1 /* $NetBSD: mx_15.c,v 1.9 2025/01/26 16:25:32 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #ifndef RDATA_GENERIC_MX_15_C 17 #define RDATA_GENERIC_MX_15_C 18 19 #include <string.h> 20 21 #include <isc/net.h> 22 23 #include <dns/fixedname.h> 24 25 #define RRTYPE_MX_ATTRIBUTES (0) 26 27 static bool 28 check_mx(isc_token_t *token) { 29 char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")]; 30 struct in_addr addr; 31 struct in6_addr addr6; 32 33 if (strlcpy(tmp, DNS_AS_STR(*token), sizeof(tmp)) >= sizeof(tmp)) { 34 return true; 35 } 36 37 if (tmp[strlen(tmp) - 1] == '.') { 38 tmp[strlen(tmp) - 1] = '\0'; 39 } 40 if (inet_pton(AF_INET, tmp, &addr) == 1 || 41 inet_pton(AF_INET6, tmp, &addr6) == 1) 42 { 43 return false; 44 } 45 46 return true; 47 } 48 49 static isc_result_t 50 fromtext_mx(ARGS_FROMTEXT) { 51 isc_token_t token; 52 dns_name_t name; 53 isc_buffer_t buffer; 54 bool ok; 55 56 REQUIRE(type == dns_rdatatype_mx); 57 58 UNUSED(type); 59 UNUSED(rdclass); 60 61 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 62 false)); 63 if (token.value.as_ulong > 0xffffU) { 64 RETTOK(ISC_R_RANGE); 65 } 66 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 67 68 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 69 false)); 70 71 ok = true; 72 if ((options & DNS_RDATA_CHECKMX) != 0) { 73 ok = check_mx(&token); 74 } 75 if (!ok && (options & DNS_RDATA_CHECKMXFAIL) != 0) { 76 RETTOK(DNS_R_MXISADDRESS); 77 } 78 if (!ok && callbacks != NULL) { 79 warn_badmx(&token, lexer, callbacks); 80 } 81 82 dns_name_init(&name, NULL); 83 buffer_fromregion(&buffer, &token.value.as_region); 84 if (origin == NULL) { 85 origin = dns_rootname; 86 } 87 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 88 ok = true; 89 if ((options & DNS_RDATA_CHECKNAMES) != 0) { 90 ok = dns_name_ishostname(&name, false); 91 } 92 if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) { 93 RETTOK(DNS_R_BADNAME); 94 } 95 if (!ok && callbacks != NULL) { 96 warn_badname(&name, lexer, callbacks); 97 } 98 return ISC_R_SUCCESS; 99 } 100 101 static isc_result_t 102 totext_mx(ARGS_TOTEXT) { 103 isc_region_t region; 104 dns_name_t name; 105 dns_name_t prefix; 106 unsigned int opts; 107 char buf[sizeof("64000")]; 108 unsigned short num; 109 110 REQUIRE(rdata->type == dns_rdatatype_mx); 111 REQUIRE(rdata->length != 0); 112 113 dns_name_init(&name, NULL); 114 dns_name_init(&prefix, NULL); 115 116 dns_rdata_toregion(rdata, ®ion); 117 num = uint16_fromregion(®ion); 118 isc_region_consume(®ion, 2); 119 snprintf(buf, sizeof(buf), "%u", num); 120 RETERR(str_totext(buf, target)); 121 122 RETERR(str_totext(" ", target)); 123 124 dns_name_fromregion(&name, ®ion); 125 opts = name_prefix(&name, tctx->origin, &prefix) ? DNS_NAME_OMITFINALDOT 126 : 0; 127 return dns_name_totext(&prefix, opts, target); 128 } 129 130 static isc_result_t 131 fromwire_mx(ARGS_FROMWIRE) { 132 dns_name_t name; 133 isc_region_t sregion; 134 135 REQUIRE(type == dns_rdatatype_mx); 136 137 UNUSED(type); 138 UNUSED(rdclass); 139 140 dctx = dns_decompress_setpermitted(dctx, true); 141 142 dns_name_init(&name, NULL); 143 144 isc_buffer_activeregion(source, &sregion); 145 if (sregion.length < 2) { 146 return ISC_R_UNEXPECTEDEND; 147 } 148 RETERR(mem_tobuffer(target, sregion.base, 2)); 149 isc_buffer_forward(source, 2); 150 return dns_name_fromwire(&name, source, dctx, target); 151 } 152 153 static isc_result_t 154 towire_mx(ARGS_TOWIRE) { 155 dns_name_t name; 156 dns_offsets_t offsets; 157 isc_region_t region; 158 159 REQUIRE(rdata->type == dns_rdatatype_mx); 160 REQUIRE(rdata->length != 0); 161 162 dns_compress_setpermitted(cctx, true); 163 164 dns_rdata_toregion(rdata, ®ion); 165 RETERR(mem_tobuffer(target, region.base, 2)); 166 isc_region_consume(®ion, 2); 167 168 dns_name_init(&name, offsets); 169 dns_name_fromregion(&name, ®ion); 170 171 return dns_name_towire(&name, cctx, target, NULL); 172 } 173 174 static int 175 compare_mx(ARGS_COMPARE) { 176 dns_name_t name1; 177 dns_name_t name2; 178 isc_region_t region1; 179 isc_region_t region2; 180 int order; 181 182 REQUIRE(rdata1->type == rdata2->type); 183 REQUIRE(rdata1->rdclass == rdata2->rdclass); 184 REQUIRE(rdata1->type == dns_rdatatype_mx); 185 REQUIRE(rdata1->length != 0); 186 REQUIRE(rdata2->length != 0); 187 188 order = memcmp(rdata1->data, rdata2->data, 2); 189 if (order != 0) { 190 return order < 0 ? -1 : 1; 191 } 192 193 dns_name_init(&name1, NULL); 194 dns_name_init(&name2, NULL); 195 196 dns_rdata_toregion(rdata1, ®ion1); 197 dns_rdata_toregion(rdata2, ®ion2); 198 199 isc_region_consume(®ion1, 2); 200 isc_region_consume(®ion2, 2); 201 202 dns_name_fromregion(&name1, ®ion1); 203 dns_name_fromregion(&name2, ®ion2); 204 205 return dns_name_rdatacompare(&name1, &name2); 206 } 207 208 static isc_result_t 209 fromstruct_mx(ARGS_FROMSTRUCT) { 210 dns_rdata_mx_t *mx = source; 211 isc_region_t region; 212 213 REQUIRE(type == dns_rdatatype_mx); 214 REQUIRE(mx != NULL); 215 REQUIRE(mx->common.rdtype == type); 216 REQUIRE(mx->common.rdclass == rdclass); 217 218 UNUSED(type); 219 UNUSED(rdclass); 220 221 RETERR(uint16_tobuffer(mx->pref, target)); 222 dns_name_toregion(&mx->mx, ®ion); 223 return isc_buffer_copyregion(target, ®ion); 224 } 225 226 static isc_result_t 227 tostruct_mx(ARGS_TOSTRUCT) { 228 isc_region_t region; 229 dns_rdata_mx_t *mx = target; 230 dns_name_t name; 231 232 REQUIRE(rdata->type == dns_rdatatype_mx); 233 REQUIRE(mx != NULL); 234 REQUIRE(rdata->length != 0); 235 236 mx->common.rdclass = rdata->rdclass; 237 mx->common.rdtype = rdata->type; 238 ISC_LINK_INIT(&mx->common, link); 239 240 dns_name_init(&name, NULL); 241 dns_rdata_toregion(rdata, ®ion); 242 mx->pref = uint16_fromregion(®ion); 243 isc_region_consume(®ion, 2); 244 dns_name_fromregion(&name, ®ion); 245 dns_name_init(&mx->mx, NULL); 246 name_duporclone(&name, mctx, &mx->mx); 247 mx->mctx = mctx; 248 return ISC_R_SUCCESS; 249 } 250 251 static void 252 freestruct_mx(ARGS_FREESTRUCT) { 253 dns_rdata_mx_t *mx = source; 254 255 REQUIRE(mx != NULL); 256 REQUIRE(mx->common.rdtype == dns_rdatatype_mx); 257 258 if (mx->mctx == NULL) { 259 return; 260 } 261 262 dns_name_free(&mx->mx, mx->mctx); 263 mx->mctx = NULL; 264 } 265 266 static unsigned char port25_offset[] = { 0, 3 }; 267 static unsigned char port25_ndata[] = "\003_25\004_tcp"; 268 static dns_name_t port25 = DNS_NAME_INITNONABSOLUTE(port25_ndata, 269 port25_offset); 270 271 static isc_result_t 272 additionaldata_mx(ARGS_ADDLDATA) { 273 isc_result_t result; 274 dns_fixedname_t fixed; 275 dns_name_t name; 276 dns_offsets_t offsets; 277 isc_region_t region; 278 279 REQUIRE(rdata->type == dns_rdatatype_mx); 280 281 UNUSED(owner); 282 283 dns_name_init(&name, offsets); 284 dns_rdata_toregion(rdata, ®ion); 285 isc_region_consume(®ion, 2); 286 dns_name_fromregion(&name, ®ion); 287 288 if (dns_name_equal(&name, dns_rootname)) { 289 return ISC_R_SUCCESS; 290 } 291 292 result = (add)(arg, &name, dns_rdatatype_a, NULL DNS__DB_FILELINE); 293 if (result != ISC_R_SUCCESS) { 294 return result; 295 } 296 297 dns_fixedname_init(&fixed); 298 result = dns_name_concatenate(&port25, &name, 299 dns_fixedname_name(&fixed), NULL); 300 if (result != ISC_R_SUCCESS) { 301 return ISC_R_SUCCESS; 302 } 303 304 return (add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa, 305 NULL DNS__DB_FILELINE); 306 } 307 308 static isc_result_t 309 digest_mx(ARGS_DIGEST) { 310 isc_region_t r1, r2; 311 dns_name_t name; 312 313 REQUIRE(rdata->type == dns_rdatatype_mx); 314 315 dns_rdata_toregion(rdata, &r1); 316 r2 = r1; 317 isc_region_consume(&r2, 2); 318 r1.length = 2; 319 RETERR((digest)(arg, &r1)); 320 dns_name_init(&name, NULL); 321 dns_name_fromregion(&name, &r2); 322 return dns_name_digest(&name, digest, arg); 323 } 324 325 static bool 326 checkowner_mx(ARGS_CHECKOWNER) { 327 REQUIRE(type == dns_rdatatype_mx); 328 329 UNUSED(type); 330 UNUSED(rdclass); 331 332 return dns_name_ishostname(name, wildcard); 333 } 334 335 static bool 336 checknames_mx(ARGS_CHECKNAMES) { 337 isc_region_t region; 338 dns_name_t name; 339 340 REQUIRE(rdata->type == dns_rdatatype_mx); 341 342 UNUSED(owner); 343 344 dns_rdata_toregion(rdata, ®ion); 345 isc_region_consume(®ion, 2); 346 dns_name_init(&name, NULL); 347 dns_name_fromregion(&name, ®ion); 348 if (!dns_name_ishostname(&name, false)) { 349 if (bad != NULL) { 350 dns_name_clone(&name, bad); 351 } 352 return false; 353 } 354 return true; 355 } 356 357 static int 358 casecompare_mx(ARGS_COMPARE) { 359 return compare_mx(rdata1, rdata2); 360 } 361 362 #endif /* RDATA_GENERIC_MX_15_C */ 363