1 /* $NetBSD: a_1.c,v 1.11 2025/01/26 16:25:34 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 a->common.rdclass = rdata->rdclass; 165 a->common.rdtype = rdata->type; 166 ISC_LINK_INIT(&a->common, link); 167 168 dns_rdata_toregion(rdata, ®ion); 169 n = uint32_fromregion(®ion); 170 a->in_addr.s_addr = htonl(n); 171 172 return ISC_R_SUCCESS; 173 } 174 175 static void 176 freestruct_in_a(ARGS_FREESTRUCT) { 177 dns_rdata_in_a_t *a = source; 178 179 REQUIRE(a != NULL); 180 REQUIRE(a->common.rdtype == dns_rdatatype_a); 181 REQUIRE(a->common.rdclass == dns_rdataclass_in); 182 183 UNUSED(a); 184 } 185 186 static isc_result_t 187 additionaldata_in_a(ARGS_ADDLDATA) { 188 REQUIRE(rdata->type == dns_rdatatype_a); 189 REQUIRE(rdata->rdclass == dns_rdataclass_in); 190 191 UNUSED(rdata); 192 UNUSED(owner); 193 UNUSED(add); 194 UNUSED(arg); 195 196 return ISC_R_SUCCESS; 197 } 198 199 static isc_result_t 200 digest_in_a(ARGS_DIGEST) { 201 isc_region_t r; 202 203 REQUIRE(rdata->type == dns_rdatatype_a); 204 REQUIRE(rdata->rdclass == dns_rdataclass_in); 205 206 dns_rdata_toregion(rdata, &r); 207 208 return (digest)(arg, &r); 209 } 210 211 static bool 212 checkowner_in_a(ARGS_CHECKOWNER) { 213 dns_name_t prefix, suffix; 214 unsigned int labels, i; 215 216 REQUIRE(type == dns_rdatatype_a); 217 REQUIRE(rdclass == dns_rdataclass_in); 218 219 UNUSED(type); 220 UNUSED(rdclass); 221 222 labels = dns_name_countlabels(name); 223 if (labels > 2U) { 224 /* 225 * Handle Active Directory gc._msdcs.<forest> name. 226 */ 227 dns_name_init(&prefix, NULL); 228 dns_name_init(&suffix, NULL); 229 dns_name_split(name, labels - 2, &prefix, &suffix); 230 if (dns_name_equal(&gc_msdcs, &prefix) && 231 dns_name_ishostname(&suffix, false)) 232 { 233 return true; 234 } 235 236 /* 237 * Handle SPF exists targets when the seperating label is: 238 * - "_spf" RFC7208, section 5.7 239 * - "_spf_verify" RFC7208, Appendix D1 240 * - "_spf_rate" RFC7208, Appendix D1 241 */ 242 for (i = 0; i < labels - 2; i++) { 243 dns_label_t label; 244 dns_name_getlabel(name, i, &label); 245 if ((label.length == 5 && 246 strncasecmp((char *)label.base, "\x04_spf", 5) == 247 0) || 248 (label.length == 12 && 249 strncasecmp((char *)label.base, "\x0b_spf_verify", 250 12) == 0) || 251 (label.length == 10 && 252 strncasecmp((char *)label.base, "\x09_spf_rate", 253 10) == 0)) 254 { 255 return true; 256 } 257 } 258 } 259 260 return dns_name_ishostname(name, wildcard); 261 } 262 263 static bool 264 checknames_in_a(ARGS_CHECKNAMES) { 265 REQUIRE(rdata->type == dns_rdatatype_a); 266 REQUIRE(rdata->rdclass == dns_rdataclass_in); 267 268 UNUSED(rdata); 269 UNUSED(owner); 270 UNUSED(bad); 271 272 return true; 273 } 274 275 static int 276 casecompare_in_a(ARGS_COMPARE) { 277 return compare_in_a(rdata1, rdata2); 278 } 279 280 #endif /* RDATA_IN_1_A_1_C */ 281