xref: /netbsd-src/external/mpl/bind/dist/lib/dns/rdata/generic/amtrelay_260.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: amtrelay_260.c,v 1.8 2025/01/26 16:25:30 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_GENERIC_AMTRELAY_260_C
17 #define RDATA_GENERIC_AMTRELAY_260_C
18 
19 #include <string.h>
20 
21 #include <isc/net.h>
22 
23 #define RRTYPE_AMTRELAY_ATTRIBUTES (0)
24 
25 static isc_result_t
26 fromtext_amtrelay(ARGS_FROMTEXT) {
27 	isc_token_t token;
28 	dns_name_t name;
29 	isc_buffer_t buffer;
30 	unsigned int discovery;
31 	unsigned int gateway;
32 	struct in_addr addr;
33 	unsigned char addr6[16];
34 	isc_region_t region;
35 
36 	REQUIRE(type == dns_rdatatype_amtrelay);
37 
38 	UNUSED(type);
39 	UNUSED(rdclass);
40 	UNUSED(callbacks);
41 
42 	/*
43 	 * Precedence.
44 	 */
45 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
46 				      false));
47 	if (token.value.as_ulong > 0xffU) {
48 		RETTOK(ISC_R_RANGE);
49 	}
50 	RETERR(uint8_tobuffer(token.value.as_ulong, target));
51 
52 	/*
53 	 * Discovery.
54 	 */
55 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
56 				      false));
57 	if (token.value.as_ulong > 1U) {
58 		RETTOK(ISC_R_RANGE);
59 	}
60 	discovery = token.value.as_ulong;
61 
62 	/*
63 	 * Gateway type.
64 	 */
65 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
66 				      false));
67 	if (token.value.as_ulong > 0x7fU) {
68 		RETTOK(ISC_R_RANGE);
69 	}
70 	RETERR(uint8_tobuffer(token.value.as_ulong | (discovery << 7), target));
71 	gateway = token.value.as_ulong;
72 
73 	if (gateway == 0) {
74 		return ISC_R_SUCCESS;
75 	}
76 
77 	if (gateway > 3) {
78 		return ISC_R_NOTIMPLEMENTED;
79 	}
80 
81 	/*
82 	 * Gateway.
83 	 */
84 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
85 				      false));
86 
87 	switch (gateway) {
88 	case 1:
89 		if (inet_pton(AF_INET, DNS_AS_STR(token), &addr) != 1) {
90 			RETTOK(DNS_R_BADDOTTEDQUAD);
91 		}
92 		isc_buffer_availableregion(target, &region);
93 		if (region.length < 4) {
94 			return ISC_R_NOSPACE;
95 		}
96 		memmove(region.base, &addr, 4);
97 		isc_buffer_add(target, 4);
98 		return ISC_R_SUCCESS;
99 
100 	case 2:
101 		if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1) {
102 			RETTOK(DNS_R_BADAAAA);
103 		}
104 		isc_buffer_availableregion(target, &region);
105 		if (region.length < 16) {
106 			return ISC_R_NOSPACE;
107 		}
108 		memmove(region.base, addr6, 16);
109 		isc_buffer_add(target, 16);
110 		return ISC_R_SUCCESS;
111 
112 	case 3:
113 		dns_name_init(&name, NULL);
114 		buffer_fromregion(&buffer, &token.value.as_region);
115 		if (origin == NULL) {
116 			origin = dns_rootname;
117 		}
118 		return dns_name_fromtext(&name, &buffer, origin, options,
119 					 target);
120 	default:
121 		UNREACHABLE();
122 	}
123 }
124 
125 static isc_result_t
126 totext_amtrelay(ARGS_TOTEXT) {
127 	isc_region_t region;
128 	dns_name_t name;
129 	char buf[sizeof("0 255 ")];
130 	unsigned char precedence;
131 	unsigned char discovery;
132 	unsigned char gateway;
133 	const char *space;
134 
135 	UNUSED(tctx);
136 
137 	REQUIRE(rdata->type == dns_rdatatype_amtrelay);
138 	REQUIRE(rdata->length >= 2);
139 
140 	if ((rdata->data[1] & 0x7f) > 3U) {
141 		return ISC_R_NOTIMPLEMENTED;
142 	}
143 
144 	/*
145 	 * Precedence.
146 	 */
147 	dns_rdata_toregion(rdata, &region);
148 	precedence = uint8_fromregion(&region);
149 	isc_region_consume(&region, 1);
150 	snprintf(buf, sizeof(buf), "%u ", precedence);
151 	RETERR(str_totext(buf, target));
152 
153 	/*
154 	 * Discovery and Gateway type.
155 	 */
156 	gateway = uint8_fromregion(&region);
157 	discovery = gateway >> 7;
158 	gateway &= 0x7f;
159 	space = (gateway != 0U) ? " " : "";
160 	isc_region_consume(&region, 1);
161 	snprintf(buf, sizeof(buf), "%u %u%s", discovery, gateway, space);
162 	RETERR(str_totext(buf, target));
163 
164 	/*
165 	 * Gateway.
166 	 */
167 	switch (gateway) {
168 	case 0:
169 		break;
170 	case 1:
171 		return inet_totext(AF_INET, tctx->flags, &region, target);
172 
173 	case 2:
174 		return inet_totext(AF_INET6, tctx->flags, &region, target);
175 
176 	case 3:
177 		dns_name_init(&name, NULL);
178 		dns_name_fromregion(&name, &region);
179 		return dns_name_totext(&name, 0, target);
180 
181 	default:
182 		UNREACHABLE();
183 	}
184 	return ISC_R_SUCCESS;
185 }
186 
187 static isc_result_t
188 fromwire_amtrelay(ARGS_FROMWIRE) {
189 	dns_name_t name;
190 	isc_region_t region;
191 
192 	REQUIRE(type == dns_rdatatype_amtrelay);
193 
194 	UNUSED(type);
195 	UNUSED(rdclass);
196 
197 	dctx = dns_decompress_setpermitted(dctx, false);
198 
199 	isc_buffer_activeregion(source, &region);
200 	if (region.length < 2) {
201 		return ISC_R_UNEXPECTEDEND;
202 	}
203 
204 	switch (region.base[1] & 0x7f) {
205 	case 0:
206 		if (region.length != 2) {
207 			return DNS_R_FORMERR;
208 		}
209 		isc_buffer_forward(source, region.length);
210 		return mem_tobuffer(target, region.base, region.length);
211 
212 	case 1:
213 		if (region.length != 6) {
214 			return DNS_R_FORMERR;
215 		}
216 		isc_buffer_forward(source, region.length);
217 		return mem_tobuffer(target, region.base, region.length);
218 
219 	case 2:
220 		if (region.length != 18) {
221 			return DNS_R_FORMERR;
222 		}
223 		isc_buffer_forward(source, region.length);
224 		return mem_tobuffer(target, region.base, region.length);
225 
226 	case 3:
227 		RETERR(mem_tobuffer(target, region.base, 2));
228 		isc_buffer_forward(source, 2);
229 		dns_name_init(&name, NULL);
230 		return dns_name_fromwire(&name, source, dctx, target);
231 
232 	default:
233 		isc_buffer_forward(source, region.length);
234 		return mem_tobuffer(target, region.base, region.length);
235 	}
236 }
237 
238 static isc_result_t
239 towire_amtrelay(ARGS_TOWIRE) {
240 	isc_region_t region;
241 
242 	REQUIRE(rdata->type == dns_rdatatype_amtrelay);
243 	REQUIRE(rdata->length != 0);
244 
245 	UNUSED(cctx);
246 
247 	dns_rdata_toregion(rdata, &region);
248 	return mem_tobuffer(target, region.base, region.length);
249 }
250 
251 static int
252 compare_amtrelay(ARGS_COMPARE) {
253 	isc_region_t region1;
254 	isc_region_t region2;
255 
256 	REQUIRE(rdata1->type == rdata2->type);
257 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
258 	REQUIRE(rdata1->type == dns_rdatatype_amtrelay);
259 	REQUIRE(rdata1->length >= 2);
260 	REQUIRE(rdata2->length >= 2);
261 
262 	dns_rdata_toregion(rdata1, &region1);
263 	dns_rdata_toregion(rdata2, &region2);
264 
265 	return isc_region_compare(&region1, &region2);
266 }
267 
268 static isc_result_t
269 fromstruct_amtrelay(ARGS_FROMSTRUCT) {
270 	dns_rdata_amtrelay_t *amtrelay = source;
271 	isc_region_t region;
272 	uint32_t n;
273 
274 	REQUIRE(type == dns_rdatatype_amtrelay);
275 	REQUIRE(amtrelay != NULL);
276 	REQUIRE(amtrelay->common.rdtype == type);
277 	REQUIRE(amtrelay->common.rdclass == rdclass);
278 
279 	UNUSED(type);
280 	UNUSED(rdclass);
281 
282 	RETERR(uint8_tobuffer(amtrelay->precedence, target));
283 	n = (amtrelay->discovery ? 0x80 : 0) | amtrelay->gateway_type;
284 	RETERR(uint8_tobuffer(n, target));
285 
286 	switch (amtrelay->gateway_type) {
287 	case 0:
288 		return ISC_R_SUCCESS;
289 
290 	case 1:
291 		n = ntohl(amtrelay->in_addr.s_addr);
292 		return uint32_tobuffer(n, target);
293 
294 	case 2:
295 		return mem_tobuffer(target, amtrelay->in6_addr.s6_addr, 16);
296 		break;
297 
298 	case 3:
299 		dns_name_toregion(&amtrelay->gateway, &region);
300 		return isc_buffer_copyregion(target, &region);
301 		break;
302 
303 	default:
304 		return mem_tobuffer(target, amtrelay->data, amtrelay->length);
305 	}
306 }
307 
308 static isc_result_t
309 tostruct_amtrelay(ARGS_TOSTRUCT) {
310 	isc_region_t region;
311 	dns_rdata_amtrelay_t *amtrelay = target;
312 	dns_name_t name;
313 	uint32_t n;
314 
315 	REQUIRE(rdata->type == dns_rdatatype_amtrelay);
316 	REQUIRE(amtrelay != NULL);
317 	REQUIRE(rdata->length >= 2);
318 
319 	amtrelay->common.rdclass = rdata->rdclass;
320 	amtrelay->common.rdtype = rdata->type;
321 	ISC_LINK_INIT(&amtrelay->common, link);
322 
323 	dns_name_init(&amtrelay->gateway, NULL);
324 	amtrelay->data = NULL;
325 
326 	dns_name_init(&name, NULL);
327 	dns_rdata_toregion(rdata, &region);
328 
329 	amtrelay->precedence = uint8_fromregion(&region);
330 	isc_region_consume(&region, 1);
331 
332 	amtrelay->gateway_type = uint8_fromregion(&region);
333 	amtrelay->discovery = (amtrelay->gateway_type & 0x80) != 0;
334 	amtrelay->gateway_type &= 0x7f;
335 	isc_region_consume(&region, 1);
336 
337 	switch (amtrelay->gateway_type) {
338 	case 0:
339 		break;
340 
341 	case 1:
342 		n = uint32_fromregion(&region);
343 		amtrelay->in_addr.s_addr = htonl(n);
344 		isc_region_consume(&region, 4);
345 		break;
346 
347 	case 2:
348 		memmove(amtrelay->in6_addr.s6_addr, region.base, 16);
349 		isc_region_consume(&region, 16);
350 		break;
351 
352 	case 3:
353 		dns_name_fromregion(&name, &region);
354 		name_duporclone(&name, mctx, &amtrelay->gateway);
355 		isc_region_consume(&region, name_length(&name));
356 		break;
357 
358 	default:
359 		if (region.length != 0) {
360 			amtrelay->data = mem_maybedup(mctx, region.base,
361 						      region.length);
362 		}
363 		amtrelay->length = region.length;
364 	}
365 	amtrelay->mctx = mctx;
366 	return ISC_R_SUCCESS;
367 }
368 
369 static void
370 freestruct_amtrelay(ARGS_FREESTRUCT) {
371 	dns_rdata_amtrelay_t *amtrelay = source;
372 
373 	REQUIRE(amtrelay != NULL);
374 	REQUIRE(amtrelay->common.rdtype == dns_rdatatype_amtrelay);
375 
376 	if (amtrelay->mctx == NULL) {
377 		return;
378 	}
379 
380 	if (amtrelay->gateway_type == 3) {
381 		dns_name_free(&amtrelay->gateway, amtrelay->mctx);
382 	}
383 
384 	if (amtrelay->data != NULL) {
385 		isc_mem_free(amtrelay->mctx, amtrelay->data);
386 	}
387 
388 	amtrelay->mctx = NULL;
389 }
390 
391 static isc_result_t
392 additionaldata_amtrelay(ARGS_ADDLDATA) {
393 	REQUIRE(rdata->type == dns_rdatatype_amtrelay);
394 
395 	UNUSED(rdata);
396 	UNUSED(owner);
397 	UNUSED(add);
398 	UNUSED(arg);
399 
400 	return ISC_R_SUCCESS;
401 }
402 
403 static isc_result_t
404 digest_amtrelay(ARGS_DIGEST) {
405 	isc_region_t region;
406 
407 	REQUIRE(rdata->type == dns_rdatatype_amtrelay);
408 
409 	dns_rdata_toregion(rdata, &region);
410 	return (digest)(arg, &region);
411 }
412 
413 static bool
414 checkowner_amtrelay(ARGS_CHECKOWNER) {
415 	REQUIRE(type == dns_rdatatype_amtrelay);
416 
417 	UNUSED(name);
418 	UNUSED(type);
419 	UNUSED(rdclass);
420 	UNUSED(wildcard);
421 
422 	return true;
423 }
424 
425 static bool
426 checknames_amtrelay(ARGS_CHECKNAMES) {
427 	REQUIRE(rdata->type == dns_rdatatype_amtrelay);
428 
429 	UNUSED(rdata);
430 	UNUSED(owner);
431 	UNUSED(bad);
432 
433 	return true;
434 }
435 
436 static int
437 casecompare_amtrelay(ARGS_COMPARE) {
438 	isc_region_t region1;
439 	isc_region_t region2;
440 	dns_name_t name1;
441 	dns_name_t name2;
442 
443 	REQUIRE(rdata1->type == rdata2->type);
444 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
445 	REQUIRE(rdata1->type == dns_rdatatype_amtrelay);
446 	REQUIRE(rdata1->length >= 2);
447 	REQUIRE(rdata2->length >= 2);
448 
449 	dns_rdata_toregion(rdata1, &region1);
450 	dns_rdata_toregion(rdata2, &region2);
451 
452 	if (memcmp(region1.base, region2.base, 2) != 0 ||
453 	    (region1.base[1] & 0x7f) != 3)
454 	{
455 		return isc_region_compare(&region1, &region2);
456 	}
457 
458 	dns_name_init(&name1, NULL);
459 	dns_name_init(&name2, NULL);
460 
461 	isc_region_consume(&region1, 2);
462 	isc_region_consume(&region2, 2);
463 
464 	dns_name_fromregion(&name1, &region1);
465 	dns_name_fromregion(&name2, &region2);
466 
467 	return dns_name_rdatacompare(&name1, &name2);
468 }
469 
470 #endif /* RDATA_GENERIC_AMTRELAY_260_C */
471