/* $NetBSD: amtrelay_260.c,v 1.8 2025/01/26 16:25:30 christos Exp $ */ /* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, you can obtain one at https://mozilla.org/MPL/2.0/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ #ifndef RDATA_GENERIC_AMTRELAY_260_C #define RDATA_GENERIC_AMTRELAY_260_C #include #include #define RRTYPE_AMTRELAY_ATTRIBUTES (0) static isc_result_t fromtext_amtrelay(ARGS_FROMTEXT) { isc_token_t token; dns_name_t name; isc_buffer_t buffer; unsigned int discovery; unsigned int gateway; struct in_addr addr; unsigned char addr6[16]; isc_region_t region; REQUIRE(type == dns_rdatatype_amtrelay); UNUSED(type); UNUSED(rdclass); UNUSED(callbacks); /* * Precedence. */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, false)); if (token.value.as_ulong > 0xffU) { RETTOK(ISC_R_RANGE); } RETERR(uint8_tobuffer(token.value.as_ulong, target)); /* * Discovery. */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, false)); if (token.value.as_ulong > 1U) { RETTOK(ISC_R_RANGE); } discovery = token.value.as_ulong; /* * Gateway type. */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, false)); if (token.value.as_ulong > 0x7fU) { RETTOK(ISC_R_RANGE); } RETERR(uint8_tobuffer(token.value.as_ulong | (discovery << 7), target)); gateway = token.value.as_ulong; if (gateway == 0) { return ISC_R_SUCCESS; } if (gateway > 3) { return ISC_R_NOTIMPLEMENTED; } /* * Gateway. */ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, false)); switch (gateway) { case 1: if (inet_pton(AF_INET, DNS_AS_STR(token), &addr) != 1) { RETTOK(DNS_R_BADDOTTEDQUAD); } isc_buffer_availableregion(target, ®ion); if (region.length < 4) { return ISC_R_NOSPACE; } memmove(region.base, &addr, 4); isc_buffer_add(target, 4); return ISC_R_SUCCESS; case 2: if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1) { RETTOK(DNS_R_BADAAAA); } isc_buffer_availableregion(target, ®ion); if (region.length < 16) { return ISC_R_NOSPACE; } memmove(region.base, addr6, 16); isc_buffer_add(target, 16); return ISC_R_SUCCESS; case 3: dns_name_init(&name, NULL); buffer_fromregion(&buffer, &token.value.as_region); if (origin == NULL) { origin = dns_rootname; } return dns_name_fromtext(&name, &buffer, origin, options, target); default: UNREACHABLE(); } } static isc_result_t totext_amtrelay(ARGS_TOTEXT) { isc_region_t region; dns_name_t name; char buf[sizeof("0 255 ")]; unsigned char precedence; unsigned char discovery; unsigned char gateway; const char *space; UNUSED(tctx); REQUIRE(rdata->type == dns_rdatatype_amtrelay); REQUIRE(rdata->length >= 2); if ((rdata->data[1] & 0x7f) > 3U) { return ISC_R_NOTIMPLEMENTED; } /* * Precedence. */ dns_rdata_toregion(rdata, ®ion); precedence = uint8_fromregion(®ion); isc_region_consume(®ion, 1); snprintf(buf, sizeof(buf), "%u ", precedence); RETERR(str_totext(buf, target)); /* * Discovery and Gateway type. */ gateway = uint8_fromregion(®ion); discovery = gateway >> 7; gateway &= 0x7f; space = (gateway != 0U) ? " " : ""; isc_region_consume(®ion, 1); snprintf(buf, sizeof(buf), "%u %u%s", discovery, gateway, space); RETERR(str_totext(buf, target)); /* * Gateway. */ switch (gateway) { case 0: break; case 1: return inet_totext(AF_INET, tctx->flags, ®ion, target); case 2: return inet_totext(AF_INET6, tctx->flags, ®ion, target); case 3: dns_name_init(&name, NULL); dns_name_fromregion(&name, ®ion); return dns_name_totext(&name, 0, target); default: UNREACHABLE(); } return ISC_R_SUCCESS; } static isc_result_t fromwire_amtrelay(ARGS_FROMWIRE) { dns_name_t name; isc_region_t region; REQUIRE(type == dns_rdatatype_amtrelay); UNUSED(type); UNUSED(rdclass); dctx = dns_decompress_setpermitted(dctx, false); isc_buffer_activeregion(source, ®ion); if (region.length < 2) { return ISC_R_UNEXPECTEDEND; } switch (region.base[1] & 0x7f) { case 0: if (region.length != 2) { return DNS_R_FORMERR; } isc_buffer_forward(source, region.length); return mem_tobuffer(target, region.base, region.length); case 1: if (region.length != 6) { return DNS_R_FORMERR; } isc_buffer_forward(source, region.length); return mem_tobuffer(target, region.base, region.length); case 2: if (region.length != 18) { return DNS_R_FORMERR; } isc_buffer_forward(source, region.length); return mem_tobuffer(target, region.base, region.length); case 3: RETERR(mem_tobuffer(target, region.base, 2)); isc_buffer_forward(source, 2); dns_name_init(&name, NULL); return dns_name_fromwire(&name, source, dctx, target); default: isc_buffer_forward(source, region.length); return mem_tobuffer(target, region.base, region.length); } } static isc_result_t towire_amtrelay(ARGS_TOWIRE) { isc_region_t region; REQUIRE(rdata->type == dns_rdatatype_amtrelay); REQUIRE(rdata->length != 0); UNUSED(cctx); dns_rdata_toregion(rdata, ®ion); return mem_tobuffer(target, region.base, region.length); } static int compare_amtrelay(ARGS_COMPARE) { isc_region_t region1; isc_region_t region2; REQUIRE(rdata1->type == rdata2->type); REQUIRE(rdata1->rdclass == rdata2->rdclass); REQUIRE(rdata1->type == dns_rdatatype_amtrelay); REQUIRE(rdata1->length >= 2); REQUIRE(rdata2->length >= 2); dns_rdata_toregion(rdata1, ®ion1); dns_rdata_toregion(rdata2, ®ion2); return isc_region_compare(®ion1, ®ion2); } static isc_result_t fromstruct_amtrelay(ARGS_FROMSTRUCT) { dns_rdata_amtrelay_t *amtrelay = source; isc_region_t region; uint32_t n; REQUIRE(type == dns_rdatatype_amtrelay); REQUIRE(amtrelay != NULL); REQUIRE(amtrelay->common.rdtype == type); REQUIRE(amtrelay->common.rdclass == rdclass); UNUSED(type); UNUSED(rdclass); RETERR(uint8_tobuffer(amtrelay->precedence, target)); n = (amtrelay->discovery ? 0x80 : 0) | amtrelay->gateway_type; RETERR(uint8_tobuffer(n, target)); switch (amtrelay->gateway_type) { case 0: return ISC_R_SUCCESS; case 1: n = ntohl(amtrelay->in_addr.s_addr); return uint32_tobuffer(n, target); case 2: return mem_tobuffer(target, amtrelay->in6_addr.s6_addr, 16); break; case 3: dns_name_toregion(&amtrelay->gateway, ®ion); return isc_buffer_copyregion(target, ®ion); break; default: return mem_tobuffer(target, amtrelay->data, amtrelay->length); } } static isc_result_t tostruct_amtrelay(ARGS_TOSTRUCT) { isc_region_t region; dns_rdata_amtrelay_t *amtrelay = target; dns_name_t name; uint32_t n; REQUIRE(rdata->type == dns_rdatatype_amtrelay); REQUIRE(amtrelay != NULL); REQUIRE(rdata->length >= 2); amtrelay->common.rdclass = rdata->rdclass; amtrelay->common.rdtype = rdata->type; ISC_LINK_INIT(&amtrelay->common, link); dns_name_init(&amtrelay->gateway, NULL); amtrelay->data = NULL; dns_name_init(&name, NULL); dns_rdata_toregion(rdata, ®ion); amtrelay->precedence = uint8_fromregion(®ion); isc_region_consume(®ion, 1); amtrelay->gateway_type = uint8_fromregion(®ion); amtrelay->discovery = (amtrelay->gateway_type & 0x80) != 0; amtrelay->gateway_type &= 0x7f; isc_region_consume(®ion, 1); switch (amtrelay->gateway_type) { case 0: break; case 1: n = uint32_fromregion(®ion); amtrelay->in_addr.s_addr = htonl(n); isc_region_consume(®ion, 4); break; case 2: memmove(amtrelay->in6_addr.s6_addr, region.base, 16); isc_region_consume(®ion, 16); break; case 3: dns_name_fromregion(&name, ®ion); name_duporclone(&name, mctx, &amtrelay->gateway); isc_region_consume(®ion, name_length(&name)); break; default: if (region.length != 0) { amtrelay->data = mem_maybedup(mctx, region.base, region.length); } amtrelay->length = region.length; } amtrelay->mctx = mctx; return ISC_R_SUCCESS; } static void freestruct_amtrelay(ARGS_FREESTRUCT) { dns_rdata_amtrelay_t *amtrelay = source; REQUIRE(amtrelay != NULL); REQUIRE(amtrelay->common.rdtype == dns_rdatatype_amtrelay); if (amtrelay->mctx == NULL) { return; } if (amtrelay->gateway_type == 3) { dns_name_free(&amtrelay->gateway, amtrelay->mctx); } if (amtrelay->data != NULL) { isc_mem_free(amtrelay->mctx, amtrelay->data); } amtrelay->mctx = NULL; } static isc_result_t additionaldata_amtrelay(ARGS_ADDLDATA) { REQUIRE(rdata->type == dns_rdatatype_amtrelay); UNUSED(rdata); UNUSED(owner); UNUSED(add); UNUSED(arg); return ISC_R_SUCCESS; } static isc_result_t digest_amtrelay(ARGS_DIGEST) { isc_region_t region; REQUIRE(rdata->type == dns_rdatatype_amtrelay); dns_rdata_toregion(rdata, ®ion); return (digest)(arg, ®ion); } static bool checkowner_amtrelay(ARGS_CHECKOWNER) { REQUIRE(type == dns_rdatatype_amtrelay); UNUSED(name); UNUSED(type); UNUSED(rdclass); UNUSED(wildcard); return true; } static bool checknames_amtrelay(ARGS_CHECKNAMES) { REQUIRE(rdata->type == dns_rdatatype_amtrelay); UNUSED(rdata); UNUSED(owner); UNUSED(bad); return true; } static int casecompare_amtrelay(ARGS_COMPARE) { isc_region_t region1; isc_region_t region2; dns_name_t name1; dns_name_t name2; REQUIRE(rdata1->type == rdata2->type); REQUIRE(rdata1->rdclass == rdata2->rdclass); REQUIRE(rdata1->type == dns_rdatatype_amtrelay); REQUIRE(rdata1->length >= 2); REQUIRE(rdata2->length >= 2); dns_rdata_toregion(rdata1, ®ion1); dns_rdata_toregion(rdata2, ®ion2); if (memcmp(region1.base, region2.base, 2) != 0 || (region1.base[1] & 0x7f) != 3) { return isc_region_compare(®ion1, ®ion2); } dns_name_init(&name1, NULL); dns_name_init(&name2, NULL); isc_region_consume(®ion1, 2); isc_region_consume(®ion2, 2); dns_name_fromregion(&name1, ®ion1); dns_name_fromregion(&name2, ®ion2); return dns_name_rdatacompare(&name1, &name2); } #endif /* RDATA_GENERIC_AMTRELAY_260_C */