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