1/*	$NetBSD: a_1.c,v 1.1 2024/02/18 20:57:46 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
25static isc_result_t
26fromtext_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
55static isc_result_t
56totext_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
69static isc_result_t
70fromwire_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(options);
80	UNUSED(rdclass);
81
82	isc_buffer_activeregion(source, &sregion);
83	isc_buffer_availableregion(target, &tregion);
84	if (sregion.length < 4) {
85		return (ISC_R_UNEXPECTEDEND);
86	}
87	if (tregion.length < 4) {
88		return (ISC_R_NOSPACE);
89	}
90
91	memmove(tregion.base, sregion.base, 4);
92	isc_buffer_forward(source, 4);
93	isc_buffer_add(target, 4);
94	return (ISC_R_SUCCESS);
95}
96
97static isc_result_t
98towire_in_a(ARGS_TOWIRE) {
99	isc_region_t region;
100
101	REQUIRE(rdata->type == dns_rdatatype_a);
102	REQUIRE(rdata->rdclass == dns_rdataclass_in);
103	REQUIRE(rdata->length == 4);
104
105	UNUSED(cctx);
106
107	isc_buffer_availableregion(target, &region);
108	if (region.length < rdata->length) {
109		return (ISC_R_NOSPACE);
110	}
111	memmove(region.base, rdata->data, rdata->length);
112	isc_buffer_add(target, 4);
113	return (ISC_R_SUCCESS);
114}
115
116static int
117compare_in_a(ARGS_COMPARE) {
118	isc_region_t r1;
119	isc_region_t r2;
120
121	REQUIRE(rdata1->type == rdata2->type);
122	REQUIRE(rdata1->rdclass == rdata2->rdclass);
123	REQUIRE(rdata1->type == dns_rdatatype_a);
124	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
125	REQUIRE(rdata1->length == 4);
126	REQUIRE(rdata2->length == 4);
127
128	dns_rdata_toregion(rdata1, &r1);
129	dns_rdata_toregion(rdata2, &r2);
130	return (isc_region_compare(&r1, &r2));
131}
132
133static isc_result_t
134fromstruct_in_a(ARGS_FROMSTRUCT) {
135	dns_rdata_in_a_t *a = source;
136	uint32_t n;
137
138	REQUIRE(type == dns_rdatatype_a);
139	REQUIRE(rdclass == dns_rdataclass_in);
140	REQUIRE(a != NULL);
141	REQUIRE(a->common.rdtype == type);
142	REQUIRE(a->common.rdclass == rdclass);
143
144	UNUSED(type);
145	UNUSED(rdclass);
146
147	n = ntohl(a->in_addr.s_addr);
148
149	return (uint32_tobuffer(n, target));
150}
151
152static isc_result_t
153tostruct_in_a(ARGS_TOSTRUCT) {
154	dns_rdata_in_a_t *a = target;
155	uint32_t n;
156	isc_region_t region;
157
158	REQUIRE(a != NULL);
159	REQUIRE(rdata->type == dns_rdatatype_a);
160	REQUIRE(rdata->rdclass == dns_rdataclass_in);
161	REQUIRE(rdata->length == 4);
162
163	UNUSED(mctx);
164
165	a->common.rdclass = rdata->rdclass;
166	a->common.rdtype = rdata->type;
167	ISC_LINK_INIT(&a->common, link);
168
169	dns_rdata_toregion(rdata, &region);
170	n = uint32_fromregion(&region);
171	a->in_addr.s_addr = htonl(n);
172
173	return (ISC_R_SUCCESS);
174}
175
176static void
177freestruct_in_a(ARGS_FREESTRUCT) {
178	dns_rdata_in_a_t *a = source;
179
180	REQUIRE(a != NULL);
181	REQUIRE(a->common.rdtype == dns_rdatatype_a);
182	REQUIRE(a->common.rdclass == dns_rdataclass_in);
183
184	UNUSED(a);
185}
186
187static isc_result_t
188additionaldata_in_a(ARGS_ADDLDATA) {
189	REQUIRE(rdata->type == dns_rdatatype_a);
190	REQUIRE(rdata->rdclass == dns_rdataclass_in);
191
192	UNUSED(rdata);
193	UNUSED(add);
194	UNUSED(arg);
195
196	return (ISC_R_SUCCESS);
197}
198
199static isc_result_t
200digest_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
211static bool
212checkowner_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
263static bool
264checknames_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
275static int
276casecompare_in_a(ARGS_COMPARE) {
277	return (compare_in_a(rdata1, rdata2));
278}
279
280#endif /* RDATA_IN_1_A_1_C */
281