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, ®ion); 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, ®ion); 66 return inet_totext(AF_INET, tctx->flags, ®ion, 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, ®ion); 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, ®ion); 167 n = uint32_fromregion(®ion); 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