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