1/* $NetBSD: mx_15.c,v 1.1 2024/02/18 20:57:43 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 27static bool 28check_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 49static isc_result_t 50fromtext_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 101static isc_result_t 102totext_mx(ARGS_TOTEXT) { 103 isc_region_t region; 104 dns_name_t name; 105 dns_name_t prefix; 106 bool sub; 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 sub = name_prefix(&name, tctx->origin, &prefix); 126 return (dns_name_totext(&prefix, sub, target)); 127} 128 129static isc_result_t 130fromwire_mx(ARGS_FROMWIRE) { 131 dns_name_t name; 132 isc_region_t sregion; 133 134 REQUIRE(type == dns_rdatatype_mx); 135 136 UNUSED(type); 137 UNUSED(rdclass); 138 139 dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); 140 141 dns_name_init(&name, NULL); 142 143 isc_buffer_activeregion(source, &sregion); 144 if (sregion.length < 2) { 145 return (ISC_R_UNEXPECTEDEND); 146 } 147 RETERR(mem_tobuffer(target, sregion.base, 2)); 148 isc_buffer_forward(source, 2); 149 return (dns_name_fromwire(&name, source, dctx, options, target)); 150} 151 152static isc_result_t 153towire_mx(ARGS_TOWIRE) { 154 dns_name_t name; 155 dns_offsets_t offsets; 156 isc_region_t region; 157 158 REQUIRE(rdata->type == dns_rdatatype_mx); 159 REQUIRE(rdata->length != 0); 160 161 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 162 163 dns_rdata_toregion(rdata, ®ion); 164 RETERR(mem_tobuffer(target, region.base, 2)); 165 isc_region_consume(®ion, 2); 166 167 dns_name_init(&name, offsets); 168 dns_name_fromregion(&name, ®ion); 169 170 return (dns_name_towire(&name, cctx, target)); 171} 172 173static int 174compare_mx(ARGS_COMPARE) { 175 dns_name_t name1; 176 dns_name_t name2; 177 isc_region_t region1; 178 isc_region_t region2; 179 int order; 180 181 REQUIRE(rdata1->type == rdata2->type); 182 REQUIRE(rdata1->rdclass == rdata2->rdclass); 183 REQUIRE(rdata1->type == dns_rdatatype_mx); 184 REQUIRE(rdata1->length != 0); 185 REQUIRE(rdata2->length != 0); 186 187 order = memcmp(rdata1->data, rdata2->data, 2); 188 if (order != 0) { 189 return (order < 0 ? -1 : 1); 190 } 191 192 dns_name_init(&name1, NULL); 193 dns_name_init(&name2, NULL); 194 195 dns_rdata_toregion(rdata1, ®ion1); 196 dns_rdata_toregion(rdata2, ®ion2); 197 198 isc_region_consume(®ion1, 2); 199 isc_region_consume(®ion2, 2); 200 201 dns_name_fromregion(&name1, ®ion1); 202 dns_name_fromregion(&name2, ®ion2); 203 204 return (dns_name_rdatacompare(&name1, &name2)); 205} 206 207static isc_result_t 208fromstruct_mx(ARGS_FROMSTRUCT) { 209 dns_rdata_mx_t *mx = source; 210 isc_region_t region; 211 212 REQUIRE(type == dns_rdatatype_mx); 213 REQUIRE(mx != NULL); 214 REQUIRE(mx->common.rdtype == type); 215 REQUIRE(mx->common.rdclass == rdclass); 216 217 UNUSED(type); 218 UNUSED(rdclass); 219 220 RETERR(uint16_tobuffer(mx->pref, target)); 221 dns_name_toregion(&mx->mx, ®ion); 222 return (isc_buffer_copyregion(target, ®ion)); 223} 224 225static isc_result_t 226tostruct_mx(ARGS_TOSTRUCT) { 227 isc_region_t region; 228 dns_rdata_mx_t *mx = target; 229 dns_name_t name; 230 231 REQUIRE(rdata->type == dns_rdatatype_mx); 232 REQUIRE(mx != NULL); 233 REQUIRE(rdata->length != 0); 234 235 mx->common.rdclass = rdata->rdclass; 236 mx->common.rdtype = rdata->type; 237 ISC_LINK_INIT(&mx->common, link); 238 239 dns_name_init(&name, NULL); 240 dns_rdata_toregion(rdata, ®ion); 241 mx->pref = uint16_fromregion(®ion); 242 isc_region_consume(®ion, 2); 243 dns_name_fromregion(&name, ®ion); 244 dns_name_init(&mx->mx, NULL); 245 RETERR(name_duporclone(&name, mctx, &mx->mx)); 246 mx->mctx = mctx; 247 return (ISC_R_SUCCESS); 248} 249 250static void 251freestruct_mx(ARGS_FREESTRUCT) { 252 dns_rdata_mx_t *mx = source; 253 254 REQUIRE(mx != NULL); 255 REQUIRE(mx->common.rdtype == dns_rdatatype_mx); 256 257 if (mx->mctx == NULL) { 258 return; 259 } 260 261 dns_name_free(&mx->mx, mx->mctx); 262 mx->mctx = NULL; 263} 264 265static unsigned char port25_offset[] = { 0, 3 }; 266static unsigned char port25_ndata[] = "\003_25\004_tcp"; 267static dns_name_t port25 = DNS_NAME_INITNONABSOLUTE(port25_ndata, 268 port25_offset); 269 270static isc_result_t 271additionaldata_mx(ARGS_ADDLDATA) { 272 isc_result_t result; 273 dns_fixedname_t fixed; 274 dns_name_t name; 275 dns_offsets_t offsets; 276 isc_region_t region; 277 278 REQUIRE(rdata->type == dns_rdatatype_mx); 279 280 dns_name_init(&name, offsets); 281 dns_rdata_toregion(rdata, ®ion); 282 isc_region_consume(®ion, 2); 283 dns_name_fromregion(&name, ®ion); 284 285 if (dns_name_equal(&name, dns_rootname)) { 286 return (ISC_R_SUCCESS); 287 } 288 289 result = (add)(arg, &name, dns_rdatatype_a); 290 if (result != ISC_R_SUCCESS) { 291 return (result); 292 } 293 294 dns_fixedname_init(&fixed); 295 result = dns_name_concatenate(&port25, &name, 296 dns_fixedname_name(&fixed), NULL); 297 if (result != ISC_R_SUCCESS) { 298 return (ISC_R_SUCCESS); 299 } 300 301 return ((add)(arg, dns_fixedname_name(&fixed), dns_rdatatype_tlsa)); 302} 303 304static isc_result_t 305digest_mx(ARGS_DIGEST) { 306 isc_region_t r1, r2; 307 dns_name_t name; 308 309 REQUIRE(rdata->type == dns_rdatatype_mx); 310 311 dns_rdata_toregion(rdata, &r1); 312 r2 = r1; 313 isc_region_consume(&r2, 2); 314 r1.length = 2; 315 RETERR((digest)(arg, &r1)); 316 dns_name_init(&name, NULL); 317 dns_name_fromregion(&name, &r2); 318 return (dns_name_digest(&name, digest, arg)); 319} 320 321static bool 322checkowner_mx(ARGS_CHECKOWNER) { 323 REQUIRE(type == dns_rdatatype_mx); 324 325 UNUSED(type); 326 UNUSED(rdclass); 327 328 return (dns_name_ishostname(name, wildcard)); 329} 330 331static bool 332checknames_mx(ARGS_CHECKNAMES) { 333 isc_region_t region; 334 dns_name_t name; 335 336 REQUIRE(rdata->type == dns_rdatatype_mx); 337 338 UNUSED(owner); 339 340 dns_rdata_toregion(rdata, ®ion); 341 isc_region_consume(®ion, 2); 342 dns_name_init(&name, NULL); 343 dns_name_fromregion(&name, ®ion); 344 if (!dns_name_ishostname(&name, false)) { 345 if (bad != NULL) { 346 dns_name_clone(&name, bad); 347 } 348 return (false); 349 } 350 return (true); 351} 352 353static int 354casecompare_mx(ARGS_COMPARE) { 355 return (compare_mx(rdata1, rdata2)); 356} 357 358#endif /* RDATA_GENERIC_MX_15_C */ 359