1 /* $NetBSD: amtrelay_260.c,v 1.4 2021/02/19 16:42:17 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 #ifndef RDATA_GENERIC_AMTRELAY_260_C 15 #define RDATA_GENERIC_AMTRELAY_260_C 16 17 #include <string.h> 18 19 #include <isc/net.h> 20 21 #define RRTYPE_AMTRELAY_ATTRIBUTES (0) 22 23 static inline isc_result_t 24 fromtext_amtrelay(ARGS_FROMTEXT) { 25 isc_token_t token; 26 dns_name_t name; 27 isc_buffer_t buffer; 28 unsigned int discovery; 29 unsigned int gateway; 30 struct in_addr addr; 31 unsigned char addr6[16]; 32 isc_region_t region; 33 34 REQUIRE(type == dns_rdatatype_amtrelay); 35 36 UNUSED(type); 37 UNUSED(rdclass); 38 UNUSED(callbacks); 39 40 /* 41 * Precedence. 42 */ 43 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 44 false)); 45 if (token.value.as_ulong > 0xffU) { 46 RETTOK(ISC_R_RANGE); 47 } 48 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 49 50 /* 51 * Discovery. 52 */ 53 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 54 false)); 55 if (token.value.as_ulong > 1U) { 56 RETTOK(ISC_R_RANGE); 57 } 58 discovery = token.value.as_ulong; 59 60 /* 61 * Gateway type. 62 */ 63 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 64 false)); 65 if (token.value.as_ulong > 0x7fU) { 66 RETTOK(ISC_R_RANGE); 67 } 68 RETERR(uint8_tobuffer(token.value.as_ulong | (discovery << 7), target)); 69 gateway = token.value.as_ulong; 70 71 if (gateway == 0) { 72 return (ISC_R_SUCCESS); 73 } 74 75 if (gateway > 3) { 76 return (ISC_R_NOTIMPLEMENTED); 77 } 78 79 /* 80 * Gateway. 81 */ 82 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 83 false)); 84 85 switch (gateway) { 86 case 1: 87 if (inet_pton(AF_INET, DNS_AS_STR(token), &addr) != 1) { 88 RETTOK(DNS_R_BADDOTTEDQUAD); 89 } 90 isc_buffer_availableregion(target, ®ion); 91 if (region.length < 4) { 92 return (ISC_R_NOSPACE); 93 } 94 memmove(region.base, &addr, 4); 95 isc_buffer_add(target, 4); 96 return (ISC_R_SUCCESS); 97 98 case 2: 99 if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1) { 100 RETTOK(DNS_R_BADAAAA); 101 } 102 isc_buffer_availableregion(target, ®ion); 103 if (region.length < 16) { 104 return (ISC_R_NOSPACE); 105 } 106 memmove(region.base, addr6, 16); 107 isc_buffer_add(target, 16); 108 return (ISC_R_SUCCESS); 109 110 case 3: 111 dns_name_init(&name, NULL); 112 buffer_fromregion(&buffer, &token.value.as_region); 113 if (origin == NULL) { 114 origin = dns_rootname; 115 } 116 return (dns_name_fromtext(&name, &buffer, origin, options, 117 target)); 118 default: 119 INSIST(0); 120 ISC_UNREACHABLE(); 121 } 122 } 123 124 static inline isc_result_t 125 totext_amtrelay(ARGS_TOTEXT) { 126 isc_region_t region; 127 dns_name_t name; 128 char buf[sizeof("0 255 ")]; 129 unsigned char precedence; 130 unsigned char discovery; 131 unsigned char gateway; 132 const char *space; 133 134 UNUSED(tctx); 135 136 REQUIRE(rdata->type == dns_rdatatype_amtrelay); 137 REQUIRE(rdata->length >= 2); 138 139 if ((rdata->data[1] & 0x7f) > 3U) { 140 return (ISC_R_NOTIMPLEMENTED); 141 } 142 143 /* 144 * Precedence. 145 */ 146 dns_rdata_toregion(rdata, ®ion); 147 precedence = uint8_fromregion(®ion); 148 isc_region_consume(®ion, 1); 149 snprintf(buf, sizeof(buf), "%u ", precedence); 150 RETERR(str_totext(buf, target)); 151 152 /* 153 * Discovery and Gateway type. 154 */ 155 gateway = uint8_fromregion(®ion); 156 discovery = gateway >> 7; 157 gateway &= 0x7f; 158 space = (gateway != 0U) ? " " : ""; 159 isc_region_consume(®ion, 1); 160 snprintf(buf, sizeof(buf), "%u %u%s", discovery, gateway, space); 161 RETERR(str_totext(buf, target)); 162 163 /* 164 * Gateway. 165 */ 166 switch (gateway) { 167 case 0: 168 break; 169 case 1: 170 return (inet_totext(AF_INET, tctx->flags, ®ion, target)); 171 172 case 2: 173 return (inet_totext(AF_INET6, tctx->flags, ®ion, target)); 174 175 case 3: 176 dns_name_init(&name, NULL); 177 dns_name_fromregion(&name, ®ion); 178 return (dns_name_totext(&name, false, target)); 179 180 default: 181 INSIST(0); 182 ISC_UNREACHABLE(); 183 } 184 return (ISC_R_SUCCESS); 185 } 186 187 static inline isc_result_t 188 fromwire_amtrelay(ARGS_FROMWIRE) { 189 dns_name_t name; 190 isc_region_t region; 191 192 REQUIRE(type == dns_rdatatype_amtrelay); 193 194 UNUSED(type); 195 UNUSED(rdclass); 196 197 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 198 199 isc_buffer_activeregion(source, ®ion); 200 if (region.length < 2) { 201 return (ISC_R_UNEXPECTEDEND); 202 } 203 204 switch (region.base[1] & 0x7f) { 205 case 0: 206 if (region.length != 2) { 207 return (DNS_R_FORMERR); 208 } 209 isc_buffer_forward(source, region.length); 210 return (mem_tobuffer(target, region.base, region.length)); 211 212 case 1: 213 if (region.length != 6) { 214 return (DNS_R_FORMERR); 215 } 216 isc_buffer_forward(source, region.length); 217 return (mem_tobuffer(target, region.base, region.length)); 218 219 case 2: 220 if (region.length != 18) { 221 return (DNS_R_FORMERR); 222 } 223 isc_buffer_forward(source, region.length); 224 return (mem_tobuffer(target, region.base, region.length)); 225 226 case 3: 227 RETERR(mem_tobuffer(target, region.base, 2)); 228 isc_buffer_forward(source, 2); 229 dns_name_init(&name, NULL); 230 return (dns_name_fromwire(&name, source, dctx, options, 231 target)); 232 233 default: 234 isc_buffer_forward(source, region.length); 235 return (mem_tobuffer(target, region.base, region.length)); 236 } 237 } 238 239 static inline isc_result_t 240 towire_amtrelay(ARGS_TOWIRE) { 241 isc_region_t region; 242 243 REQUIRE(rdata->type == dns_rdatatype_amtrelay); 244 REQUIRE(rdata->length != 0); 245 246 UNUSED(cctx); 247 248 dns_rdata_toregion(rdata, ®ion); 249 return (mem_tobuffer(target, region.base, region.length)); 250 } 251 252 static inline int 253 compare_amtrelay(ARGS_COMPARE) { 254 isc_region_t region1; 255 isc_region_t region2; 256 257 REQUIRE(rdata1->type == rdata2->type); 258 REQUIRE(rdata1->rdclass == rdata2->rdclass); 259 REQUIRE(rdata1->type == dns_rdatatype_amtrelay); 260 REQUIRE(rdata1->length >= 2); 261 REQUIRE(rdata2->length >= 2); 262 263 dns_rdata_toregion(rdata1, ®ion1); 264 dns_rdata_toregion(rdata2, ®ion2); 265 266 return (isc_region_compare(®ion1, ®ion2)); 267 } 268 269 static inline isc_result_t 270 fromstruct_amtrelay(ARGS_FROMSTRUCT) { 271 dns_rdata_amtrelay_t *amtrelay = source; 272 isc_region_t region; 273 uint32_t n; 274 275 REQUIRE(type == dns_rdatatype_amtrelay); 276 REQUIRE(amtrelay != NULL); 277 REQUIRE(amtrelay->common.rdtype == type); 278 REQUIRE(amtrelay->common.rdclass == rdclass); 279 280 UNUSED(type); 281 UNUSED(rdclass); 282 283 RETERR(uint8_tobuffer(amtrelay->precedence, target)); 284 n = (amtrelay->discovery ? 0x80 : 0) | amtrelay->gateway_type; 285 RETERR(uint8_tobuffer(n, target)); 286 287 switch (amtrelay->gateway_type) { 288 case 0: 289 return (ISC_R_SUCCESS); 290 291 case 1: 292 n = ntohl(amtrelay->in_addr.s_addr); 293 return (uint32_tobuffer(n, target)); 294 295 case 2: 296 return (mem_tobuffer(target, amtrelay->in6_addr.s6_addr, 16)); 297 break; 298 299 case 3: 300 dns_name_toregion(&amtrelay->gateway, ®ion); 301 return (isc_buffer_copyregion(target, ®ion)); 302 break; 303 304 default: 305 return (mem_tobuffer(target, amtrelay->data, amtrelay->length)); 306 } 307 } 308 309 static inline isc_result_t 310 tostruct_amtrelay(ARGS_TOSTRUCT) { 311 isc_region_t region; 312 dns_rdata_amtrelay_t *amtrelay = target; 313 dns_name_t name; 314 uint32_t n; 315 316 REQUIRE(rdata->type == dns_rdatatype_amtrelay); 317 REQUIRE(amtrelay != NULL); 318 REQUIRE(rdata->length >= 2); 319 320 amtrelay->common.rdclass = rdata->rdclass; 321 amtrelay->common.rdtype = rdata->type; 322 ISC_LINK_INIT(&amtrelay->common, link); 323 324 dns_name_init(&amtrelay->gateway, NULL); 325 amtrelay->data = NULL; 326 327 dns_name_init(&name, NULL); 328 dns_rdata_toregion(rdata, ®ion); 329 330 amtrelay->precedence = uint8_fromregion(®ion); 331 isc_region_consume(®ion, 1); 332 333 amtrelay->gateway_type = uint8_fromregion(®ion); 334 amtrelay->discovery = (amtrelay->gateway_type & 0x80) != 0; 335 amtrelay->gateway_type &= 0x7f; 336 isc_region_consume(®ion, 1); 337 338 switch (amtrelay->gateway_type) { 339 case 0: 340 break; 341 342 case 1: 343 n = uint32_fromregion(®ion); 344 amtrelay->in_addr.s_addr = htonl(n); 345 isc_region_consume(®ion, 4); 346 break; 347 348 case 2: 349 memmove(amtrelay->in6_addr.s6_addr, region.base, 16); 350 isc_region_consume(®ion, 16); 351 break; 352 353 case 3: 354 dns_name_fromregion(&name, ®ion); 355 RETERR(name_duporclone(&name, mctx, &amtrelay->gateway)); 356 isc_region_consume(®ion, name_length(&name)); 357 break; 358 359 default: 360 if (region.length != 0) { 361 amtrelay->data = mem_maybedup(mctx, region.base, 362 region.length); 363 if (amtrelay->data == NULL) { 364 return (ISC_R_NOMEMORY); 365 } 366 } 367 amtrelay->length = region.length; 368 } 369 amtrelay->mctx = mctx; 370 return (ISC_R_SUCCESS); 371 } 372 373 static inline void 374 freestruct_amtrelay(ARGS_FREESTRUCT) { 375 dns_rdata_amtrelay_t *amtrelay = source; 376 377 REQUIRE(amtrelay != NULL); 378 REQUIRE(amtrelay->common.rdtype == dns_rdatatype_amtrelay); 379 380 if (amtrelay->mctx == NULL) { 381 return; 382 } 383 384 if (amtrelay->gateway_type == 3) { 385 dns_name_free(&amtrelay->gateway, amtrelay->mctx); 386 } 387 388 if (amtrelay->data != NULL) { 389 isc_mem_free(amtrelay->mctx, amtrelay->data); 390 } 391 392 amtrelay->mctx = NULL; 393 } 394 395 static inline isc_result_t 396 additionaldata_amtrelay(ARGS_ADDLDATA) { 397 REQUIRE(rdata->type == dns_rdatatype_amtrelay); 398 399 UNUSED(rdata); 400 UNUSED(add); 401 UNUSED(arg); 402 403 return (ISC_R_SUCCESS); 404 } 405 406 static inline isc_result_t 407 digest_amtrelay(ARGS_DIGEST) { 408 isc_region_t region; 409 410 REQUIRE(rdata->type == dns_rdatatype_amtrelay); 411 412 dns_rdata_toregion(rdata, ®ion); 413 return ((digest)(arg, ®ion)); 414 } 415 416 static inline bool 417 checkowner_amtrelay(ARGS_CHECKOWNER) { 418 REQUIRE(type == dns_rdatatype_amtrelay); 419 420 UNUSED(name); 421 UNUSED(type); 422 UNUSED(rdclass); 423 UNUSED(wildcard); 424 425 return (true); 426 } 427 428 static inline bool 429 checknames_amtrelay(ARGS_CHECKNAMES) { 430 REQUIRE(rdata->type == dns_rdatatype_amtrelay); 431 432 UNUSED(rdata); 433 UNUSED(owner); 434 UNUSED(bad); 435 436 return (true); 437 } 438 439 static inline int 440 casecompare_amtrelay(ARGS_COMPARE) { 441 isc_region_t region1; 442 isc_region_t region2; 443 dns_name_t name1; 444 dns_name_t name2; 445 446 REQUIRE(rdata1->type == rdata2->type); 447 REQUIRE(rdata1->rdclass == rdata2->rdclass); 448 REQUIRE(rdata1->type == dns_rdatatype_amtrelay); 449 REQUIRE(rdata1->length >= 2); 450 REQUIRE(rdata2->length >= 2); 451 452 dns_rdata_toregion(rdata1, ®ion1); 453 dns_rdata_toregion(rdata2, ®ion2); 454 455 if (memcmp(region1.base, region2.base, 2) != 0 || 456 (region1.base[1] & 0x7f) != 3) { 457 return (isc_region_compare(®ion1, ®ion2)); 458 } 459 460 dns_name_init(&name1, NULL); 461 dns_name_init(&name2, NULL); 462 463 isc_region_consume(®ion1, 2); 464 isc_region_consume(®ion2, 2); 465 466 dns_name_fromregion(&name1, ®ion1); 467 dns_name_fromregion(&name2, ®ion2); 468 469 return (dns_name_rdatacompare(&name1, &name2)); 470 } 471 472 #endif /* RDATA_GENERIC_AMTRELAY_260_C */ 473