Home | History | Annotate | Line # | Download | only in in_1
      1 /*	$NetBSD: a_1.c,v 1.12 2026/01/29 18:37:54 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_IN_1_A_1_C
     17 #define RDATA_IN_1_A_1_C
     18 
     19 #include <string.h>
     20 
     21 #include <isc/net.h>
     22 
     23 #define RRTYPE_A_ATTRIBUTES (0)
     24 
     25 static isc_result_t
     26 fromtext_in_a(ARGS_FROMTEXT) {
     27 	isc_token_t token;
     28 	struct in_addr addr;
     29 	isc_region_t region;
     30 
     31 	REQUIRE(type == dns_rdatatype_a);
     32 	REQUIRE(rdclass == dns_rdataclass_in);
     33 
     34 	UNUSED(type);
     35 	UNUSED(origin);
     36 	UNUSED(options);
     37 	UNUSED(rdclass);
     38 	UNUSED(callbacks);
     39 
     40 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
     41 				      false));
     42 
     43 	if (inet_pton(AF_INET, DNS_AS_STR(token), &addr) != 1) {
     44 		RETTOK(DNS_R_BADDOTTEDQUAD);
     45 	}
     46 	isc_buffer_availableregion(target, &region);
     47 	if (region.length < 4) {
     48 		return ISC_R_NOSPACE;
     49 	}
     50 	memmove(region.base, &addr, 4);
     51 	isc_buffer_add(target, 4);
     52 	return ISC_R_SUCCESS;
     53 }
     54 
     55 static isc_result_t
     56 totext_in_a(ARGS_TOTEXT) {
     57 	isc_region_t region;
     58 
     59 	REQUIRE(rdata->type == dns_rdatatype_a);
     60 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
     61 	REQUIRE(rdata->length == 4);
     62 
     63 	UNUSED(tctx);
     64 
     65 	dns_rdata_toregion(rdata, &region);
     66 	return inet_totext(AF_INET, tctx->flags, &region, target);
     67 }
     68 
     69 static isc_result_t
     70 fromwire_in_a(ARGS_FROMWIRE) {
     71 	isc_region_t sregion;
     72 	isc_region_t tregion;
     73 
     74 	REQUIRE(type == dns_rdatatype_a);
     75 	REQUIRE(rdclass == dns_rdataclass_in);
     76 
     77 	UNUSED(type);
     78 	UNUSED(dctx);
     79 	UNUSED(rdclass);
     80 
     81 	isc_buffer_activeregion(source, &sregion);
     82 	isc_buffer_availableregion(target, &tregion);
     83 	if (sregion.length < 4) {
     84 		return ISC_R_UNEXPECTEDEND;
     85 	}
     86 	if (tregion.length < 4) {
     87 		return ISC_R_NOSPACE;
     88 	}
     89 
     90 	memmove(tregion.base, sregion.base, 4);
     91 	isc_buffer_forward(source, 4);
     92 	isc_buffer_add(target, 4);
     93 	return ISC_R_SUCCESS;
     94 }
     95 
     96 static isc_result_t
     97 towire_in_a(ARGS_TOWIRE) {
     98 	isc_region_t region;
     99 
    100 	REQUIRE(rdata->type == dns_rdatatype_a);
    101 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
    102 	REQUIRE(rdata->length == 4);
    103 
    104 	UNUSED(cctx);
    105 
    106 	isc_buffer_availableregion(target, &region);
    107 	if (region.length < rdata->length) {
    108 		return ISC_R_NOSPACE;
    109 	}
    110 	memmove(region.base, rdata->data, rdata->length);
    111 	isc_buffer_add(target, 4);
    112 	return ISC_R_SUCCESS;
    113 }
    114 
    115 static int
    116 compare_in_a(ARGS_COMPARE) {
    117 	isc_region_t r1;
    118 	isc_region_t r2;
    119 
    120 	REQUIRE(rdata1->type == rdata2->type);
    121 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
    122 	REQUIRE(rdata1->type == dns_rdatatype_a);
    123 	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
    124 	REQUIRE(rdata1->length == 4);
    125 	REQUIRE(rdata2->length == 4);
    126 
    127 	dns_rdata_toregion(rdata1, &r1);
    128 	dns_rdata_toregion(rdata2, &r2);
    129 	return isc_region_compare(&r1, &r2);
    130 }
    131 
    132 static isc_result_t
    133 fromstruct_in_a(ARGS_FROMSTRUCT) {
    134 	dns_rdata_in_a_t *a = source;
    135 	uint32_t n;
    136 
    137 	REQUIRE(type == dns_rdatatype_a);
    138 	REQUIRE(rdclass == dns_rdataclass_in);
    139 	REQUIRE(a != NULL);
    140 	REQUIRE(a->common.rdtype == type);
    141 	REQUIRE(a->common.rdclass == rdclass);
    142 
    143 	UNUSED(type);
    144 	UNUSED(rdclass);
    145 
    146 	n = ntohl(a->in_addr.s_addr);
    147 
    148 	return uint32_tobuffer(n, target);
    149 }
    150 
    151 static isc_result_t
    152 tostruct_in_a(ARGS_TOSTRUCT) {
    153 	dns_rdata_in_a_t *a = target;
    154 	uint32_t n;
    155 	isc_region_t region;
    156 
    157 	REQUIRE(a != NULL);
    158 	REQUIRE(rdata->type == dns_rdatatype_a);
    159 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
    160 	REQUIRE(rdata->length == 4);
    161 
    162 	UNUSED(mctx);
    163 
    164 	DNS_RDATACOMMON_INIT(a, rdata->type, rdata->rdclass);
    165 
    166 	dns_rdata_toregion(rdata, &region);
    167 	n = uint32_fromregion(&region);
    168 	a->in_addr.s_addr = htonl(n);
    169 
    170 	return ISC_R_SUCCESS;
    171 }
    172 
    173 static void
    174 freestruct_in_a(ARGS_FREESTRUCT) {
    175 	dns_rdata_in_a_t *a = source;
    176 
    177 	REQUIRE(a != NULL);
    178 	REQUIRE(a->common.rdtype == dns_rdatatype_a);
    179 	REQUIRE(a->common.rdclass == dns_rdataclass_in);
    180 
    181 	UNUSED(a);
    182 }
    183 
    184 static isc_result_t
    185 additionaldata_in_a(ARGS_ADDLDATA) {
    186 	REQUIRE(rdata->type == dns_rdatatype_a);
    187 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
    188 
    189 	UNUSED(rdata);
    190 	UNUSED(owner);
    191 	UNUSED(add);
    192 	UNUSED(arg);
    193 
    194 	return ISC_R_SUCCESS;
    195 }
    196 
    197 static isc_result_t
    198 digest_in_a(ARGS_DIGEST) {
    199 	isc_region_t r;
    200 
    201 	REQUIRE(rdata->type == dns_rdatatype_a);
    202 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
    203 
    204 	dns_rdata_toregion(rdata, &r);
    205 
    206 	return (digest)(arg, &r);
    207 }
    208 
    209 static bool
    210 checkowner_in_a(ARGS_CHECKOWNER) {
    211 	dns_name_t prefix, suffix;
    212 	unsigned int labels, i;
    213 
    214 	REQUIRE(type == dns_rdatatype_a);
    215 	REQUIRE(rdclass == dns_rdataclass_in);
    216 
    217 	UNUSED(type);
    218 	UNUSED(rdclass);
    219 
    220 	labels = dns_name_countlabels(name);
    221 	if (labels > 2U) {
    222 		/*
    223 		 * Handle Active Directory gc._msdcs.<forest> name.
    224 		 */
    225 		dns_name_init(&prefix, NULL);
    226 		dns_name_init(&suffix, NULL);
    227 		dns_name_split(name, labels - 2, &prefix, &suffix);
    228 		if (dns_name_equal(&gc_msdcs, &prefix) &&
    229 		    dns_name_ishostname(&suffix, false))
    230 		{
    231 			return true;
    232 		}
    233 
    234 		/*
    235 		 * Handle SPF exists targets when the seperating label is:
    236 		 * - "_spf" RFC7208, section 5.7
    237 		 * - "_spf_verify" RFC7208, Appendix D1
    238 		 * - "_spf_rate" RFC7208, Appendix D1
    239 		 */
    240 		for (i = 0; i < labels - 2; i++) {
    241 			dns_label_t label;
    242 			dns_name_getlabel(name, i, &label);
    243 			if ((label.length == 5 &&
    244 			     strncasecmp((char *)label.base, "\x04_spf", 5) ==
    245 				     0) ||
    246 			    (label.length == 12 &&
    247 			     strncasecmp((char *)label.base, "\x0b_spf_verify",
    248 					 12) == 0) ||
    249 			    (label.length == 10 &&
    250 			     strncasecmp((char *)label.base, "\x09_spf_rate",
    251 					 10) == 0))
    252 			{
    253 				return true;
    254 			}
    255 		}
    256 	}
    257 
    258 	return dns_name_ishostname(name, wildcard);
    259 }
    260 
    261 static bool
    262 checknames_in_a(ARGS_CHECKNAMES) {
    263 	REQUIRE(rdata->type == dns_rdatatype_a);
    264 	REQUIRE(rdata->rdclass == dns_rdataclass_in);
    265 
    266 	UNUSED(rdata);
    267 	UNUSED(owner);
    268 	UNUSED(bad);
    269 
    270 	return true;
    271 }
    272 
    273 static int
    274 casecompare_in_a(ARGS_COMPARE) {
    275 	return compare_in_a(rdata1, rdata2);
    276 }
    277 
    278 #endif /* RDATA_IN_1_A_1_C */
    279