1/*	$NetBSD: nsec_47.c,v 1.9 2024/02/21 22:52:13 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/* RFC 3845 */
17
18#ifndef RDATA_GENERIC_NSEC_47_C
19#define RDATA_GENERIC_NSEC_47_C
20
21/*
22 * The attributes do not include DNS_RDATATYPEATTR_SINGLETON
23 * because we must be able to handle a parent/child NSEC pair.
24 */
25#define RRTYPE_NSEC_ATTRIBUTES                                      \
26	(DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \
27	 DNS_RDATATYPEATTR_ATCNAME)
28
29static isc_result_t
30fromtext_nsec(ARGS_FROMTEXT) {
31	isc_token_t token;
32	dns_name_t name;
33	isc_buffer_t buffer;
34
35	REQUIRE(type == dns_rdatatype_nsec);
36
37	UNUSED(type);
38	UNUSED(rdclass);
39	UNUSED(callbacks);
40
41	/*
42	 * Next domain.
43	 */
44	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
45				      false));
46	dns_name_init(&name, NULL);
47	buffer_fromregion(&buffer, &token.value.as_region);
48	if (origin == NULL) {
49		origin = dns_rootname;
50	}
51	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
52
53	return (typemap_fromtext(lexer, target, false));
54}
55
56static isc_result_t
57totext_nsec(ARGS_TOTEXT) {
58	isc_region_t sr;
59	dns_name_t name;
60
61	REQUIRE(rdata->type == dns_rdatatype_nsec);
62	REQUIRE(rdata->length != 0);
63
64	UNUSED(tctx);
65
66	dns_name_init(&name, NULL);
67	dns_rdata_toregion(rdata, &sr);
68	dns_name_fromregion(&name, &sr);
69	isc_region_consume(&sr, name_length(&name));
70	RETERR(dns_name_totext(&name, false, target));
71	/*
72	 * Don't leave a trailing space when there's no typemap present.
73	 */
74	if (sr.length > 0) {
75		RETERR(str_totext(" ", target));
76	}
77	return (typemap_totext(&sr, NULL, target));
78}
79
80static isc_result_t
81fromwire_nsec(ARGS_FROMWIRE) {
82	isc_region_t sr;
83	dns_name_t name;
84
85	REQUIRE(type == dns_rdatatype_nsec);
86
87	UNUSED(type);
88	UNUSED(rdclass);
89
90	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
91
92	dns_name_init(&name, NULL);
93	RETERR(dns_name_fromwire(&name, source, dctx, options, target));
94
95	isc_buffer_activeregion(source, &sr);
96	RETERR(typemap_test(&sr, false));
97	RETERR(mem_tobuffer(target, sr.base, sr.length));
98	isc_buffer_forward(source, sr.length);
99	return (ISC_R_SUCCESS);
100}
101
102static isc_result_t
103towire_nsec(ARGS_TOWIRE) {
104	isc_region_t sr;
105	dns_name_t name;
106	dns_offsets_t offsets;
107
108	REQUIRE(rdata->type == dns_rdatatype_nsec);
109	REQUIRE(rdata->length != 0);
110
111	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
112	dns_name_init(&name, offsets);
113	dns_rdata_toregion(rdata, &sr);
114	dns_name_fromregion(&name, &sr);
115	isc_region_consume(&sr, name_length(&name));
116	RETERR(dns_name_towire(&name, cctx, target));
117
118	return (mem_tobuffer(target, sr.base, sr.length));
119}
120
121static int
122compare_nsec(ARGS_COMPARE) {
123	isc_region_t r1;
124	isc_region_t r2;
125
126	REQUIRE(rdata1->type == rdata2->type);
127	REQUIRE(rdata1->rdclass == rdata2->rdclass);
128	REQUIRE(rdata1->type == dns_rdatatype_nsec);
129	REQUIRE(rdata1->length != 0);
130	REQUIRE(rdata2->length != 0);
131
132	dns_rdata_toregion(rdata1, &r1);
133	dns_rdata_toregion(rdata2, &r2);
134	return (isc_region_compare(&r1, &r2));
135}
136
137static isc_result_t
138fromstruct_nsec(ARGS_FROMSTRUCT) {
139	dns_rdata_nsec_t *nsec = source;
140	isc_region_t region;
141
142	REQUIRE(type == dns_rdatatype_nsec);
143	REQUIRE(nsec != NULL);
144	REQUIRE(nsec->common.rdtype == type);
145	REQUIRE(nsec->common.rdclass == rdclass);
146	REQUIRE(nsec->typebits != NULL || nsec->len == 0);
147
148	UNUSED(type);
149	UNUSED(rdclass);
150
151	dns_name_toregion(&nsec->next, &region);
152	RETERR(isc_buffer_copyregion(target, &region));
153
154	region.base = nsec->typebits;
155	region.length = nsec->len;
156	RETERR(typemap_test(&region, false));
157	return (mem_tobuffer(target, nsec->typebits, nsec->len));
158}
159
160static isc_result_t
161tostruct_nsec(ARGS_TOSTRUCT) {
162	isc_region_t region;
163	dns_rdata_nsec_t *nsec = target;
164	dns_name_t name;
165
166	REQUIRE(rdata->type == dns_rdatatype_nsec);
167	REQUIRE(nsec != NULL);
168	REQUIRE(rdata->length != 0);
169
170	nsec->common.rdclass = rdata->rdclass;
171	nsec->common.rdtype = rdata->type;
172	ISC_LINK_INIT(&nsec->common, link);
173
174	dns_name_init(&name, NULL);
175	dns_rdata_toregion(rdata, &region);
176	dns_name_fromregion(&name, &region);
177	isc_region_consume(&region, name_length(&name));
178	dns_name_init(&nsec->next, NULL);
179	name_duporclone(&name, mctx, &nsec->next);
180
181	nsec->len = region.length;
182	nsec->typebits = mem_maybedup(mctx, region.base, region.length);
183	if (nsec->typebits == NULL) {
184		goto cleanup;
185	}
186
187	nsec->mctx = mctx;
188	return (ISC_R_SUCCESS);
189
190cleanup:
191	if (mctx != NULL) {
192		dns_name_free(&nsec->next, mctx);
193	}
194	return (ISC_R_NOMEMORY);
195}
196
197static void
198freestruct_nsec(ARGS_FREESTRUCT) {
199	dns_rdata_nsec_t *nsec = source;
200
201	REQUIRE(nsec != NULL);
202	REQUIRE(nsec->common.rdtype == dns_rdatatype_nsec);
203
204	if (nsec->mctx == NULL) {
205		return;
206	}
207
208	dns_name_free(&nsec->next, nsec->mctx);
209	if (nsec->typebits != NULL) {
210		isc_mem_free(nsec->mctx, nsec->typebits);
211	}
212	nsec->mctx = NULL;
213}
214
215static isc_result_t
216additionaldata_nsec(ARGS_ADDLDATA) {
217	REQUIRE(rdata->type == dns_rdatatype_nsec);
218
219	UNUSED(rdata);
220	UNUSED(owner);
221	UNUSED(add);
222	UNUSED(arg);
223
224	return (ISC_R_SUCCESS);
225}
226
227static isc_result_t
228digest_nsec(ARGS_DIGEST) {
229	isc_region_t r;
230
231	REQUIRE(rdata->type == dns_rdatatype_nsec);
232
233	dns_rdata_toregion(rdata, &r);
234	return ((digest)(arg, &r));
235}
236
237static bool
238checkowner_nsec(ARGS_CHECKOWNER) {
239	REQUIRE(type == dns_rdatatype_nsec);
240
241	UNUSED(name);
242	UNUSED(type);
243	UNUSED(rdclass);
244	UNUSED(wildcard);
245
246	return (true);
247}
248
249static bool
250checknames_nsec(ARGS_CHECKNAMES) {
251	REQUIRE(rdata->type == dns_rdatatype_nsec);
252
253	UNUSED(rdata);
254	UNUSED(owner);
255	UNUSED(bad);
256
257	return (true);
258}
259
260static int
261casecompare_nsec(ARGS_COMPARE) {
262	isc_region_t region1;
263	isc_region_t region2;
264	dns_name_t name1;
265	dns_name_t name2;
266	int order;
267
268	REQUIRE(rdata1->type == rdata2->type);
269	REQUIRE(rdata1->rdclass == rdata2->rdclass);
270	REQUIRE(rdata1->type == dns_rdatatype_nsec);
271	REQUIRE(rdata1->length != 0);
272	REQUIRE(rdata2->length != 0);
273
274	dns_name_init(&name1, NULL);
275	dns_name_init(&name2, NULL);
276
277	dns_rdata_toregion(rdata1, &region1);
278	dns_rdata_toregion(rdata2, &region2);
279
280	dns_name_fromregion(&name1, &region1);
281	dns_name_fromregion(&name2, &region2);
282
283	order = dns_name_rdatacompare(&name1, &name2);
284	if (order != 0) {
285		return (order);
286	}
287
288	isc_region_consume(&region1, name_length(&name1));
289	isc_region_consume(&region2, name_length(&name2));
290
291	return (isc_region_compare(&region1, &region2));
292}
293#endif /* RDATA_GENERIC_NSEC_47_C */
294