1/* 2 * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 1998-2001, 2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: mx_15.c,v 1.58 2009/12/04 22:06:37 tbox Exp $ */ 19 20/* reviewed: Wed Mar 15 18:05:46 PST 2000 by brister */ 21 22#ifndef RDATA_GENERIC_MX_15_C 23#define RDATA_GENERIC_MX_15_C 24 25#include <string.h> 26 27#include <isc/net.h> 28 29#define RRTYPE_MX_ATTRIBUTES (0) 30 31static isc_boolean_t 32check_mx(isc_token_t *token) { 33 char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")]; 34 struct in_addr addr; 35 struct in6_addr addr6; 36 37 if (strlcpy(tmp, DNS_AS_STR(*token), sizeof(tmp)) >= sizeof(tmp)) 38 return (ISC_TRUE); 39 40 if (tmp[strlen(tmp) - 1] == '.') 41 tmp[strlen(tmp) - 1] = '\0'; 42 if (inet_aton(tmp, &addr) == 1 || 43 inet_pton(AF_INET6, tmp, &addr6) == 1) 44 return (ISC_FALSE); 45 46 return (ISC_TRUE); 47} 48 49static inline isc_result_t 50fromtext_mx(ARGS_FROMTEXT) { 51 isc_token_t token; 52 dns_name_t name; 53 isc_buffer_t buffer; 54 isc_boolean_t ok; 55 56 REQUIRE(type == 15); 57 58 UNUSED(type); 59 UNUSED(rdclass); 60 UNUSED(callbacks); 61 62 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 63 ISC_FALSE)); 64 if (token.value.as_ulong > 0xffffU) 65 RETTOK(ISC_R_RANGE); 66 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 67 68 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 69 ISC_FALSE)); 70 71 ok = ISC_TRUE; 72 if ((options & DNS_RDATA_CHECKMX) != 0) 73 ok = check_mx(&token); 74 if (!ok && (options & DNS_RDATA_CHECKMXFAIL) != 0) 75 RETTOK(DNS_R_MXISADDRESS); 76 if (!ok && callbacks != NULL) 77 warn_badmx(&token, lexer, callbacks); 78 79 dns_name_init(&name, NULL); 80 buffer_fromregion(&buffer, &token.value.as_region); 81 origin = (origin != NULL) ? origin : dns_rootname; 82 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 83 ok = ISC_TRUE; 84 if ((options & DNS_RDATA_CHECKNAMES) != 0) 85 ok = dns_name_ishostname(&name, ISC_FALSE); 86 if (!ok && (options & DNS_RDATA_CHECKNAMESFAIL) != 0) 87 RETTOK(DNS_R_BADNAME); 88 if (!ok && callbacks != NULL) 89 warn_badname(&name, lexer, callbacks); 90 return (ISC_R_SUCCESS); 91} 92 93static inline isc_result_t 94totext_mx(ARGS_TOTEXT) { 95 isc_region_t region; 96 dns_name_t name; 97 dns_name_t prefix; 98 isc_boolean_t sub; 99 char buf[sizeof("64000")]; 100 unsigned short num; 101 102 REQUIRE(rdata->type == 15); 103 REQUIRE(rdata->length != 0); 104 105 dns_name_init(&name, NULL); 106 dns_name_init(&prefix, NULL); 107 108 dns_rdata_toregion(rdata, ®ion); 109 num = uint16_fromregion(®ion); 110 isc_region_consume(®ion, 2); 111 sprintf(buf, "%u", num); 112 RETERR(str_totext(buf, target)); 113 114 RETERR(str_totext(" ", target)); 115 116 dns_name_fromregion(&name, ®ion); 117 sub = name_prefix(&name, tctx->origin, &prefix); 118 return (dns_name_totext(&prefix, sub, target)); 119} 120 121static inline isc_result_t 122fromwire_mx(ARGS_FROMWIRE) { 123 dns_name_t name; 124 isc_region_t sregion; 125 126 REQUIRE(type == 15); 127 128 UNUSED(type); 129 UNUSED(rdclass); 130 131 dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14); 132 133 dns_name_init(&name, NULL); 134 135 isc_buffer_activeregion(source, &sregion); 136 if (sregion.length < 2) 137 return (ISC_R_UNEXPECTEDEND); 138 RETERR(mem_tobuffer(target, sregion.base, 2)); 139 isc_buffer_forward(source, 2); 140 return (dns_name_fromwire(&name, source, dctx, options, target)); 141} 142 143static inline isc_result_t 144towire_mx(ARGS_TOWIRE) { 145 dns_name_t name; 146 dns_offsets_t offsets; 147 isc_region_t region; 148 149 REQUIRE(rdata->type == 15); 150 REQUIRE(rdata->length != 0); 151 152 dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14); 153 154 dns_rdata_toregion(rdata, ®ion); 155 RETERR(mem_tobuffer(target, region.base, 2)); 156 isc_region_consume(®ion, 2); 157 158 dns_name_init(&name, offsets); 159 dns_name_fromregion(&name, ®ion); 160 161 return (dns_name_towire(&name, cctx, target)); 162} 163 164static inline int 165compare_mx(ARGS_COMPARE) { 166 dns_name_t name1; 167 dns_name_t name2; 168 isc_region_t region1; 169 isc_region_t region2; 170 int order; 171 172 REQUIRE(rdata1->type == rdata2->type); 173 REQUIRE(rdata1->rdclass == rdata2->rdclass); 174 REQUIRE(rdata1->type == 15); 175 REQUIRE(rdata1->length != 0); 176 REQUIRE(rdata2->length != 0); 177 178 order = memcmp(rdata1->data, rdata2->data, 2); 179 if (order != 0) 180 return (order < 0 ? -1 : 1); 181 182 dns_name_init(&name1, NULL); 183 dns_name_init(&name2, NULL); 184 185 dns_rdata_toregion(rdata1, ®ion1); 186 dns_rdata_toregion(rdata2, ®ion2); 187 188 isc_region_consume(®ion1, 2); 189 isc_region_consume(®ion2, 2); 190 191 dns_name_fromregion(&name1, ®ion1); 192 dns_name_fromregion(&name2, ®ion2); 193 194 return (dns_name_rdatacompare(&name1, &name2)); 195} 196 197static inline isc_result_t 198fromstruct_mx(ARGS_FROMSTRUCT) { 199 dns_rdata_mx_t *mx = source; 200 isc_region_t region; 201 202 REQUIRE(type == 15); 203 REQUIRE(source != NULL); 204 REQUIRE(mx->common.rdtype == type); 205 REQUIRE(mx->common.rdclass == rdclass); 206 207 UNUSED(type); 208 UNUSED(rdclass); 209 210 RETERR(uint16_tobuffer(mx->pref, target)); 211 dns_name_toregion(&mx->mx, ®ion); 212 return (isc_buffer_copyregion(target, ®ion)); 213} 214 215static inline isc_result_t 216tostruct_mx(ARGS_TOSTRUCT) { 217 isc_region_t region; 218 dns_rdata_mx_t *mx = target; 219 dns_name_t name; 220 221 REQUIRE(rdata->type == 15); 222 REQUIRE(target != NULL); 223 REQUIRE(rdata->length != 0); 224 225 mx->common.rdclass = rdata->rdclass; 226 mx->common.rdtype = rdata->type; 227 ISC_LINK_INIT(&mx->common, link); 228 229 dns_name_init(&name, NULL); 230 dns_rdata_toregion(rdata, ®ion); 231 mx->pref = uint16_fromregion(®ion); 232 isc_region_consume(®ion, 2); 233 dns_name_fromregion(&name, ®ion); 234 dns_name_init(&mx->mx, NULL); 235 RETERR(name_duporclone(&name, mctx, &mx->mx)); 236 mx->mctx = mctx; 237 return (ISC_R_SUCCESS); 238} 239 240static inline void 241freestruct_mx(ARGS_FREESTRUCT) { 242 dns_rdata_mx_t *mx = source; 243 244 REQUIRE(source != NULL); 245 REQUIRE(mx->common.rdtype == 15); 246 247 if (mx->mctx == NULL) 248 return; 249 250 dns_name_free(&mx->mx, mx->mctx); 251 mx->mctx = NULL; 252} 253 254static inline isc_result_t 255additionaldata_mx(ARGS_ADDLDATA) { 256 dns_name_t name; 257 dns_offsets_t offsets; 258 isc_region_t region; 259 260 REQUIRE(rdata->type == 15); 261 262 dns_name_init(&name, offsets); 263 dns_rdata_toregion(rdata, ®ion); 264 isc_region_consume(®ion, 2); 265 dns_name_fromregion(&name, ®ion); 266 267 return ((add)(arg, &name, dns_rdatatype_a)); 268} 269 270static inline isc_result_t 271digest_mx(ARGS_DIGEST) { 272 isc_region_t r1, r2; 273 dns_name_t name; 274 275 REQUIRE(rdata->type == 15); 276 277 dns_rdata_toregion(rdata, &r1); 278 r2 = r1; 279 isc_region_consume(&r2, 2); 280 r1.length = 2; 281 RETERR((digest)(arg, &r1)); 282 dns_name_init(&name, NULL); 283 dns_name_fromregion(&name, &r2); 284 return (dns_name_digest(&name, digest, arg)); 285} 286 287static inline isc_boolean_t 288checkowner_mx(ARGS_CHECKOWNER) { 289 290 REQUIRE(type == 15); 291 292 UNUSED(type); 293 UNUSED(rdclass); 294 295 return (dns_name_ishostname(name, wildcard)); 296} 297 298static inline isc_boolean_t 299checknames_mx(ARGS_CHECKNAMES) { 300 isc_region_t region; 301 dns_name_t name; 302 303 REQUIRE(rdata->type == 15); 304 305 UNUSED(owner); 306 307 dns_rdata_toregion(rdata, ®ion); 308 isc_region_consume(®ion, 2); 309 dns_name_init(&name, NULL); 310 dns_name_fromregion(&name, ®ion); 311 if (!dns_name_ishostname(&name, ISC_FALSE)) { 312 if (bad != NULL) 313 dns_name_clone(&name, bad); 314 return (ISC_FALSE); 315 } 316 return (ISC_TRUE); 317} 318 319static inline int 320casecompare_mx(ARGS_COMPARE) { 321 return (compare_mx(rdata1, rdata2)); 322} 323 324#endif /* RDATA_GENERIC_MX_15_C */ 325