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