1 /* $NetBSD: amtrelay_260.c,v 1.6 2023/01/25 21:43: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
fromtext_amtrelay(ARGS_FROMTEXT)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, ®ion);
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, ®ion);
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
totext_amtrelay(ARGS_TOTEXT)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, ®ion);
148 precedence = uint8_fromregion(®ion);
149 isc_region_consume(®ion, 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(®ion);
157 discovery = gateway >> 7;
158 gateway &= 0x7f;
159 space = (gateway != 0U) ? " " : "";
160 isc_region_consume(®ion, 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, ®ion, target));
172
173 case 2:
174 return (inet_totext(AF_INET6, tctx->flags, ®ion, target));
175
176 case 3:
177 dns_name_init(&name, NULL);
178 dns_name_fromregion(&name, ®ion);
179 return (dns_name_totext(&name, false, target));
180
181 default:
182 UNREACHABLE();
183 }
184 return (ISC_R_SUCCESS);
185 }
186
187 static isc_result_t
fromwire_amtrelay(ARGS_FROMWIRE)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 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
198
199 isc_buffer_activeregion(source, ®ion);
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, options,
231 target));
232
233 default:
234 isc_buffer_forward(source, region.length);
235 return (mem_tobuffer(target, region.base, region.length));
236 }
237 }
238
239 static isc_result_t
towire_amtrelay(ARGS_TOWIRE)240 towire_amtrelay(ARGS_TOWIRE) {
241 isc_region_t region;
242
243 REQUIRE(rdata->type == dns_rdatatype_amtrelay);
244 REQUIRE(rdata->length != 0);
245
246 UNUSED(cctx);
247
248 dns_rdata_toregion(rdata, ®ion);
249 return (mem_tobuffer(target, region.base, region.length));
250 }
251
252 static int
compare_amtrelay(ARGS_COMPARE)253 compare_amtrelay(ARGS_COMPARE) {
254 isc_region_t region1;
255 isc_region_t region2;
256
257 REQUIRE(rdata1->type == rdata2->type);
258 REQUIRE(rdata1->rdclass == rdata2->rdclass);
259 REQUIRE(rdata1->type == dns_rdatatype_amtrelay);
260 REQUIRE(rdata1->length >= 2);
261 REQUIRE(rdata2->length >= 2);
262
263 dns_rdata_toregion(rdata1, ®ion1);
264 dns_rdata_toregion(rdata2, ®ion2);
265
266 return (isc_region_compare(®ion1, ®ion2));
267 }
268
269 static isc_result_t
fromstruct_amtrelay(ARGS_FROMSTRUCT)270 fromstruct_amtrelay(ARGS_FROMSTRUCT) {
271 dns_rdata_amtrelay_t *amtrelay = source;
272 isc_region_t region;
273 uint32_t n;
274
275 REQUIRE(type == dns_rdatatype_amtrelay);
276 REQUIRE(amtrelay != NULL);
277 REQUIRE(amtrelay->common.rdtype == type);
278 REQUIRE(amtrelay->common.rdclass == rdclass);
279
280 UNUSED(type);
281 UNUSED(rdclass);
282
283 RETERR(uint8_tobuffer(amtrelay->precedence, target));
284 n = (amtrelay->discovery ? 0x80 : 0) | amtrelay->gateway_type;
285 RETERR(uint8_tobuffer(n, target));
286
287 switch (amtrelay->gateway_type) {
288 case 0:
289 return (ISC_R_SUCCESS);
290
291 case 1:
292 n = ntohl(amtrelay->in_addr.s_addr);
293 return (uint32_tobuffer(n, target));
294
295 case 2:
296 return (mem_tobuffer(target, amtrelay->in6_addr.s6_addr, 16));
297 break;
298
299 case 3:
300 dns_name_toregion(&amtrelay->gateway, ®ion);
301 return (isc_buffer_copyregion(target, ®ion));
302 break;
303
304 default:
305 return (mem_tobuffer(target, amtrelay->data, amtrelay->length));
306 }
307 }
308
309 static isc_result_t
tostruct_amtrelay(ARGS_TOSTRUCT)310 tostruct_amtrelay(ARGS_TOSTRUCT) {
311 isc_region_t region;
312 dns_rdata_amtrelay_t *amtrelay = target;
313 dns_name_t name;
314 uint32_t n;
315
316 REQUIRE(rdata->type == dns_rdatatype_amtrelay);
317 REQUIRE(amtrelay != NULL);
318 REQUIRE(rdata->length >= 2);
319
320 amtrelay->common.rdclass = rdata->rdclass;
321 amtrelay->common.rdtype = rdata->type;
322 ISC_LINK_INIT(&amtrelay->common, link);
323
324 dns_name_init(&amtrelay->gateway, NULL);
325 amtrelay->data = NULL;
326
327 dns_name_init(&name, NULL);
328 dns_rdata_toregion(rdata, ®ion);
329
330 amtrelay->precedence = uint8_fromregion(®ion);
331 isc_region_consume(®ion, 1);
332
333 amtrelay->gateway_type = uint8_fromregion(®ion);
334 amtrelay->discovery = (amtrelay->gateway_type & 0x80) != 0;
335 amtrelay->gateway_type &= 0x7f;
336 isc_region_consume(®ion, 1);
337
338 switch (amtrelay->gateway_type) {
339 case 0:
340 break;
341
342 case 1:
343 n = uint32_fromregion(®ion);
344 amtrelay->in_addr.s_addr = htonl(n);
345 isc_region_consume(®ion, 4);
346 break;
347
348 case 2:
349 memmove(amtrelay->in6_addr.s6_addr, region.base, 16);
350 isc_region_consume(®ion, 16);
351 break;
352
353 case 3:
354 dns_name_fromregion(&name, ®ion);
355 RETERR(name_duporclone(&name, mctx, &amtrelay->gateway));
356 isc_region_consume(®ion, name_length(&name));
357 break;
358
359 default:
360 if (region.length != 0) {
361 amtrelay->data = mem_maybedup(mctx, region.base,
362 region.length);
363 if (amtrelay->data == NULL) {
364 return (ISC_R_NOMEMORY);
365 }
366 }
367 amtrelay->length = region.length;
368 }
369 amtrelay->mctx = mctx;
370 return (ISC_R_SUCCESS);
371 }
372
373 static void
freestruct_amtrelay(ARGS_FREESTRUCT)374 freestruct_amtrelay(ARGS_FREESTRUCT) {
375 dns_rdata_amtrelay_t *amtrelay = source;
376
377 REQUIRE(amtrelay != NULL);
378 REQUIRE(amtrelay->common.rdtype == dns_rdatatype_amtrelay);
379
380 if (amtrelay->mctx == NULL) {
381 return;
382 }
383
384 if (amtrelay->gateway_type == 3) {
385 dns_name_free(&amtrelay->gateway, amtrelay->mctx);
386 }
387
388 if (amtrelay->data != NULL) {
389 isc_mem_free(amtrelay->mctx, amtrelay->data);
390 }
391
392 amtrelay->mctx = NULL;
393 }
394
395 static isc_result_t
additionaldata_amtrelay(ARGS_ADDLDATA)396 additionaldata_amtrelay(ARGS_ADDLDATA) {
397 REQUIRE(rdata->type == dns_rdatatype_amtrelay);
398
399 UNUSED(rdata);
400 UNUSED(add);
401 UNUSED(arg);
402
403 return (ISC_R_SUCCESS);
404 }
405
406 static isc_result_t
digest_amtrelay(ARGS_DIGEST)407 digest_amtrelay(ARGS_DIGEST) {
408 isc_region_t region;
409
410 REQUIRE(rdata->type == dns_rdatatype_amtrelay);
411
412 dns_rdata_toregion(rdata, ®ion);
413 return ((digest)(arg, ®ion));
414 }
415
416 static bool
checkowner_amtrelay(ARGS_CHECKOWNER)417 checkowner_amtrelay(ARGS_CHECKOWNER) {
418 REQUIRE(type == dns_rdatatype_amtrelay);
419
420 UNUSED(name);
421 UNUSED(type);
422 UNUSED(rdclass);
423 UNUSED(wildcard);
424
425 return (true);
426 }
427
428 static bool
checknames_amtrelay(ARGS_CHECKNAMES)429 checknames_amtrelay(ARGS_CHECKNAMES) {
430 REQUIRE(rdata->type == dns_rdatatype_amtrelay);
431
432 UNUSED(rdata);
433 UNUSED(owner);
434 UNUSED(bad);
435
436 return (true);
437 }
438
439 static int
casecompare_amtrelay(ARGS_COMPARE)440 casecompare_amtrelay(ARGS_COMPARE) {
441 isc_region_t region1;
442 isc_region_t region2;
443 dns_name_t name1;
444 dns_name_t name2;
445
446 REQUIRE(rdata1->type == rdata2->type);
447 REQUIRE(rdata1->rdclass == rdata2->rdclass);
448 REQUIRE(rdata1->type == dns_rdatatype_amtrelay);
449 REQUIRE(rdata1->length >= 2);
450 REQUIRE(rdata2->length >= 2);
451
452 dns_rdata_toregion(rdata1, ®ion1);
453 dns_rdata_toregion(rdata2, ®ion2);
454
455 if (memcmp(region1.base, region2.base, 2) != 0 ||
456 (region1.base[1] & 0x7f) != 3)
457 {
458 return (isc_region_compare(®ion1, ®ion2));
459 }
460
461 dns_name_init(&name1, NULL);
462 dns_name_init(&name2, NULL);
463
464 isc_region_consume(®ion1, 2);
465 isc_region_consume(®ion2, 2);
466
467 dns_name_fromregion(&name1, ®ion1);
468 dns_name_fromregion(&name2, ®ion2);
469
470 return (dns_name_rdatacompare(&name1, &name2));
471 }
472
473 #endif /* RDATA_GENERIC_AMTRELAY_260_C */
474