apl_42.c revision 1.6
1/*	$NetBSD: apl_42.c,v 1.6 2020/08/03 17:23:42 christos Exp $	*/
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14/* RFC3123 */
15
16#ifndef RDATA_IN_1_APL_42_C
17#define RDATA_IN_1_APL_42_C
18
19#define RRTYPE_APL_ATTRIBUTES (0)
20
21static inline isc_result_t
22fromtext_in_apl(ARGS_FROMTEXT) {
23	isc_token_t token;
24	unsigned char addr[16];
25	unsigned long afi;
26	uint8_t prefix;
27	uint8_t len;
28	bool neg;
29	char *cp, *ap, *slash;
30	int n;
31
32	REQUIRE(type == dns_rdatatype_apl);
33	REQUIRE(rdclass == dns_rdataclass_in);
34
35	UNUSED(type);
36	UNUSED(rdclass);
37	UNUSED(origin);
38	UNUSED(options);
39	UNUSED(callbacks);
40
41	do {
42		RETERR(isc_lex_getmastertoken(lexer, &token,
43					      isc_tokentype_string, true));
44		if (token.type != isc_tokentype_string) {
45			break;
46		}
47
48		cp = DNS_AS_STR(token);
49		neg = (*cp == '!');
50		if (neg) {
51			cp++;
52		}
53		afi = strtoul(cp, &ap, 10);
54		if (*ap++ != ':' || cp == ap) {
55			RETTOK(DNS_R_SYNTAX);
56		}
57		if (afi > 0xffffU) {
58			RETTOK(ISC_R_RANGE);
59		}
60		slash = strchr(ap, '/');
61		if (slash == NULL || slash == ap) {
62			RETTOK(DNS_R_SYNTAX);
63		}
64		RETTOK(isc_parse_uint8(&prefix, slash + 1, 10));
65		switch (afi) {
66		case 1:
67			*slash = '\0';
68			n = inet_pton(AF_INET, ap, addr);
69			*slash = '/';
70			if (n != 1) {
71				RETTOK(DNS_R_BADDOTTEDQUAD);
72			}
73			if (prefix > 32) {
74				RETTOK(ISC_R_RANGE);
75			}
76			for (len = 4; len > 0; len--) {
77				if (addr[len - 1] != 0) {
78					break;
79				}
80			}
81			break;
82
83		case 2:
84			*slash = '\0';
85			n = inet_pton(AF_INET6, ap, addr);
86			*slash = '/';
87			if (n != 1) {
88				RETTOK(DNS_R_BADAAAA);
89			}
90			if (prefix > 128) {
91				RETTOK(ISC_R_RANGE);
92			}
93			for (len = 16; len > 0; len--) {
94				if (addr[len - 1] != 0) {
95					break;
96				}
97			}
98			break;
99
100		default:
101			RETTOK(ISC_R_NOTIMPLEMENTED);
102		}
103		RETERR(uint16_tobuffer(afi, target));
104		RETERR(uint8_tobuffer(prefix, target));
105		RETERR(uint8_tobuffer(len | ((neg) ? 0x80 : 0), target));
106		RETERR(mem_tobuffer(target, addr, len));
107	} while (1);
108
109	/*
110	 * Let upper layer handle eol/eof.
111	 */
112	isc_lex_ungettoken(lexer, &token);
113
114	return (ISC_R_SUCCESS);
115}
116
117static inline isc_result_t
118totext_in_apl(ARGS_TOTEXT) {
119	isc_region_t sr;
120	isc_region_t ir;
121	uint16_t afi;
122	uint8_t prefix;
123	uint8_t len;
124	bool neg;
125	unsigned char buf[16];
126	char txt[sizeof(" !64000:")];
127	const char *sep = "";
128	int n;
129
130	REQUIRE(rdata->type == dns_rdatatype_apl);
131	REQUIRE(rdata->rdclass == dns_rdataclass_in);
132
133	UNUSED(tctx);
134
135	dns_rdata_toregion(rdata, &sr);
136	ir.base = buf;
137	ir.length = sizeof(buf);
138
139	while (sr.length > 0) {
140		INSIST(sr.length >= 4);
141		afi = uint16_fromregion(&sr);
142		isc_region_consume(&sr, 2);
143		prefix = *sr.base;
144		isc_region_consume(&sr, 1);
145		len = (*sr.base & 0x7f);
146		neg = (*sr.base & 0x80);
147		isc_region_consume(&sr, 1);
148		INSIST(len <= sr.length);
149		n = snprintf(txt, sizeof(txt), "%s%s%u:", sep, neg ? "!" : "",
150			     afi);
151		INSIST(n < (int)sizeof(txt));
152		RETERR(str_totext(txt, target));
153		switch (afi) {
154		case 1:
155			INSIST(len <= 4);
156			INSIST(prefix <= 32);
157			memset(buf, 0, sizeof(buf));
158			memmove(buf, sr.base, len);
159			RETERR(inet_totext(AF_INET, tctx->flags, &ir, target));
160			break;
161
162		case 2:
163			INSIST(len <= 16);
164			INSIST(prefix <= 128);
165			memset(buf, 0, sizeof(buf));
166			memmove(buf, sr.base, len);
167			RETERR(inet_totext(AF_INET6, tctx->flags, &ir, target));
168			break;
169
170		default:
171			return (ISC_R_NOTIMPLEMENTED);
172		}
173		n = snprintf(txt, sizeof(txt), "/%u", prefix);
174		INSIST(n < (int)sizeof(txt));
175		RETERR(str_totext(txt, target));
176		isc_region_consume(&sr, len);
177		sep = " ";
178	}
179	return (ISC_R_SUCCESS);
180}
181
182static inline isc_result_t
183fromwire_in_apl(ARGS_FROMWIRE) {
184	isc_region_t sr, sr2;
185	isc_region_t tr;
186	uint16_t afi;
187	uint8_t prefix;
188	uint8_t len;
189
190	REQUIRE(type == dns_rdatatype_apl);
191	REQUIRE(rdclass == dns_rdataclass_in);
192
193	UNUSED(type);
194	UNUSED(dctx);
195	UNUSED(rdclass);
196	UNUSED(options);
197
198	isc_buffer_activeregion(source, &sr);
199	isc_buffer_availableregion(target, &tr);
200	if (sr.length > tr.length) {
201		return (ISC_R_NOSPACE);
202	}
203	sr2 = sr;
204
205	/* Zero or more items */
206	while (sr.length > 0) {
207		if (sr.length < 4) {
208			return (ISC_R_UNEXPECTEDEND);
209		}
210		afi = uint16_fromregion(&sr);
211		isc_region_consume(&sr, 2);
212		prefix = *sr.base;
213		isc_region_consume(&sr, 1);
214		len = (*sr.base & 0x7f);
215		isc_region_consume(&sr, 1);
216		if (len > sr.length) {
217			return (ISC_R_UNEXPECTEDEND);
218		}
219		switch (afi) {
220		case 1:
221			if (prefix > 32 || len > 4) {
222				return (ISC_R_RANGE);
223			}
224			break;
225		case 2:
226			if (prefix > 128 || len > 16) {
227				return (ISC_R_RANGE);
228			}
229		}
230		if (len > 0 && sr.base[len - 1] == 0) {
231			return (DNS_R_FORMERR);
232		}
233		isc_region_consume(&sr, len);
234	}
235	isc_buffer_forward(source, sr2.length);
236	return (mem_tobuffer(target, sr2.base, sr2.length));
237}
238
239static inline isc_result_t
240towire_in_apl(ARGS_TOWIRE) {
241	UNUSED(cctx);
242
243	REQUIRE(rdata->type == dns_rdatatype_apl);
244	REQUIRE(rdata->rdclass == dns_rdataclass_in);
245
246	return (mem_tobuffer(target, rdata->data, rdata->length));
247}
248
249static inline int
250compare_in_apl(ARGS_COMPARE) {
251	isc_region_t r1;
252	isc_region_t r2;
253
254	REQUIRE(rdata1->type == rdata2->type);
255	REQUIRE(rdata1->rdclass == rdata2->rdclass);
256	REQUIRE(rdata1->type == dns_rdatatype_apl);
257	REQUIRE(rdata1->rdclass == dns_rdataclass_in);
258
259	dns_rdata_toregion(rdata1, &r1);
260	dns_rdata_toregion(rdata2, &r2);
261	return (isc_region_compare(&r1, &r2));
262}
263
264static inline isc_result_t
265fromstruct_in_apl(ARGS_FROMSTRUCT) {
266	dns_rdata_in_apl_t *apl = source;
267	isc_buffer_t b;
268
269	REQUIRE(type == dns_rdatatype_apl);
270	REQUIRE(rdclass == dns_rdataclass_in);
271	REQUIRE(apl != NULL);
272	REQUIRE(apl->common.rdtype == type);
273	REQUIRE(apl->common.rdclass == rdclass);
274	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
275
276	isc_buffer_init(&b, apl->apl, apl->apl_len);
277	isc_buffer_add(&b, apl->apl_len);
278	isc_buffer_setactive(&b, apl->apl_len);
279	return (fromwire_in_apl(rdclass, type, &b, NULL, false, target));
280}
281
282static inline isc_result_t
283tostruct_in_apl(ARGS_TOSTRUCT) {
284	dns_rdata_in_apl_t *apl = target;
285	isc_region_t r;
286
287	REQUIRE(apl != NULL);
288	REQUIRE(rdata->type == dns_rdatatype_apl);
289	REQUIRE(rdata->rdclass == dns_rdataclass_in);
290
291	apl->common.rdclass = rdata->rdclass;
292	apl->common.rdtype = rdata->type;
293	ISC_LINK_INIT(&apl->common, link);
294
295	dns_rdata_toregion(rdata, &r);
296	apl->apl_len = r.length;
297	apl->apl = mem_maybedup(mctx, r.base, r.length);
298	if (apl->apl == NULL) {
299		return (ISC_R_NOMEMORY);
300	}
301
302	apl->offset = 0;
303	apl->mctx = mctx;
304	return (ISC_R_SUCCESS);
305}
306
307static inline void
308freestruct_in_apl(ARGS_FREESTRUCT) {
309	dns_rdata_in_apl_t *apl = source;
310
311	REQUIRE(apl != NULL);
312	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
313	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
314
315	if (apl->mctx == NULL) {
316		return;
317	}
318	if (apl->apl != NULL) {
319		isc_mem_free(apl->mctx, apl->apl);
320	}
321	apl->mctx = NULL;
322}
323
324isc_result_t
325dns_rdata_apl_first(dns_rdata_in_apl_t *apl) {
326	uint32_t length;
327
328	REQUIRE(apl != NULL);
329	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
330	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
331	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
332
333	/*
334	 * If no APL return ISC_R_NOMORE.
335	 */
336	if (apl->apl == NULL) {
337		return (ISC_R_NOMORE);
338	}
339
340	/*
341	 * Sanity check data.
342	 */
343	INSIST(apl->apl_len > 3U);
344	length = apl->apl[apl->offset + 3] & 0x7f;
345	INSIST(4 + length <= apl->apl_len);
346
347	apl->offset = 0;
348	return (ISC_R_SUCCESS);
349}
350
351isc_result_t
352dns_rdata_apl_next(dns_rdata_in_apl_t *apl) {
353	uint32_t length;
354
355	REQUIRE(apl != NULL);
356	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
357	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
358	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
359
360	/*
361	 * No APL or have already reached the end return ISC_R_NOMORE.
362	 */
363	if (apl->apl == NULL || apl->offset == apl->apl_len) {
364		return (ISC_R_NOMORE);
365	}
366
367	/*
368	 * Sanity check data.
369	 */
370	INSIST(apl->offset < apl->apl_len);
371	INSIST(apl->apl_len > 3U);
372	INSIST(apl->offset <= apl->apl_len - 4U);
373	length = apl->apl[apl->offset + 3] & 0x7f;
374	/*
375	 * 16 to 32 bits promotion as 'length' is 32 bits so there is
376	 * no overflow problems.
377	 */
378	INSIST(4 + length + apl->offset <= apl->apl_len);
379
380	apl->offset += 4 + length;
381	return ((apl->offset < apl->apl_len) ? ISC_R_SUCCESS : ISC_R_NOMORE);
382}
383
384isc_result_t
385dns_rdata_apl_current(dns_rdata_in_apl_t *apl, dns_rdata_apl_ent_t *ent) {
386	uint32_t length;
387
388	REQUIRE(apl != NULL);
389	REQUIRE(apl->common.rdtype == dns_rdatatype_apl);
390	REQUIRE(apl->common.rdclass == dns_rdataclass_in);
391	REQUIRE(ent != NULL);
392	REQUIRE(apl->apl != NULL || apl->apl_len == 0);
393	REQUIRE(apl->offset <= apl->apl_len);
394
395	if (apl->offset == apl->apl_len) {
396		return (ISC_R_NOMORE);
397	}
398
399	/*
400	 * Sanity check data.
401	 */
402	INSIST(apl->apl_len > 3U);
403	INSIST(apl->offset <= apl->apl_len - 4U);
404	length = (apl->apl[apl->offset + 3] & 0x7f);
405	/*
406	 * 16 to 32 bits promotion as 'length' is 32 bits so there is
407	 * no overflow problems.
408	 */
409	INSIST(4 + length + apl->offset <= apl->apl_len);
410
411	ent->family = (apl->apl[apl->offset] << 8) + apl->apl[apl->offset + 1];
412	ent->prefix = apl->apl[apl->offset + 2];
413	ent->length = length;
414	ent->negative = (apl->apl[apl->offset + 3] & 0x80);
415	if (ent->length != 0) {
416		ent->data = &apl->apl[apl->offset + 4];
417	} else {
418		ent->data = NULL;
419	}
420	return (ISC_R_SUCCESS);
421}
422
423unsigned int
424dns_rdata_apl_count(const dns_rdata_in_apl_t *apl) {
425	return (apl->apl_len);
426}
427
428static inline isc_result_t
429additionaldata_in_apl(ARGS_ADDLDATA) {
430	REQUIRE(rdata->type == dns_rdatatype_apl);
431	REQUIRE(rdata->rdclass == dns_rdataclass_in);
432
433	(void)add;
434	(void)arg;
435
436	return (ISC_R_SUCCESS);
437}
438
439static inline isc_result_t
440digest_in_apl(ARGS_DIGEST) {
441	isc_region_t r;
442
443	REQUIRE(rdata->type == dns_rdatatype_apl);
444	REQUIRE(rdata->rdclass == dns_rdataclass_in);
445
446	dns_rdata_toregion(rdata, &r);
447
448	return ((digest)(arg, &r));
449}
450
451static inline bool
452checkowner_in_apl(ARGS_CHECKOWNER) {
453	REQUIRE(type == dns_rdatatype_apl);
454	REQUIRE(rdclass == dns_rdataclass_in);
455
456	UNUSED(name);
457	UNUSED(type);
458	UNUSED(rdclass);
459	UNUSED(wildcard);
460
461	return (true);
462}
463
464static inline bool
465checknames_in_apl(ARGS_CHECKNAMES) {
466	REQUIRE(rdata->type == dns_rdatatype_apl);
467	REQUIRE(rdata->rdclass == dns_rdataclass_in);
468
469	UNUSED(rdata);
470	UNUSED(owner);
471	UNUSED(bad);
472
473	return (true);
474}
475
476static inline int
477casecompare_in_apl(ARGS_COMPARE) {
478	return (compare_in_apl(rdata1, rdata2));
479}
480
481#endif /* RDATA_IN_1_APL_42_C */
482