]> The Tcpdump Group git mirrors - tcpdump/blob - print-hncp.c
Merge pull request #534 from MisterDA/hncp-20160728
[tcpdump] / print-hncp.c
1 /*
2 * Copyright (c) 2016 Antonin Décimo, Jean-Raphaël Gaglione
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the project nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <netdissect-stdinc.h>
34
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "netdissect.h"
39 #include "addrtoname.h"
40 #include "extract.h"
41
42 static void
43 hncp_print_rec(netdissect_options *ndo,
44 const u_char *cp, u_int length, int indent);
45
46 void
47 hncp_print(netdissect_options *ndo,
48 const u_char *cp, u_int length)
49 {
50 ND_PRINT((ndo, "hncp (%d)", length));
51 hncp_print_rec(ndo, cp, length, 1);
52 }
53
54 /* RFC7787 */
55 #define DNCP_REQUEST_NETWORK_STATE 1
56 #define DNCP_REQUEST_NODE_STATE 2
57 #define DNCP_NODE_ENDPOINT 3
58 #define DNCP_NETWORK_STATE 4
59 #define DNCP_NODE_STATE 5
60 #define DNCP_PEER 8
61 #define DNCP_KEEP_ALIVE_INTERVAL 9
62 #define DNCP_TRUST_VERDICT 10
63
64 /* RFC7788 */
65 #define HNCP_HNCP_VERSION 32
66 #define HNCP_EXTERNAL_CONNECTION 33
67 #define HNCP_DELEGATED_PREFIX 34
68 #define HNCP_PREFIX_POLICY 43
69 #define HNCP_DHCPV4_DATA 37
70 #define HNCP_DHCPV6_DATA 38
71 #define HNCP_ASSIGNED_PREFIX 35
72 #define HNCP_NODE_ADDRESS 36
73 #define HNCP_DNS_DELEGATED_ZONE 39
74 #define HNCP_DOMAIN_NAME 40
75 #define HNCP_NODE_NAME 41
76 #define HNCP_MANAGED_PSK 42
77
78 /* See type_mask in hncp_print_rec below */
79 #define RANGE_DNCP_RESERVED 0x10000
80 #define RANGE_HNCP_UNASSIGNED 0x10001
81 #define RANGE_DNCP_PRIVATE_USE 0x10002
82 #define RANGE_DNCP_FUTURE_USE 0x10003
83
84 static const struct tok type_values[] = {
85 { DNCP_REQUEST_NETWORK_STATE, "Request network state" },
86 { DNCP_REQUEST_NODE_STATE, "Request node state" },
87 { DNCP_NODE_ENDPOINT, "Node endpoint" },
88 { DNCP_NETWORK_STATE, "Network state" },
89 { DNCP_NODE_STATE, "Node state" },
90 { DNCP_PEER, "Peer" },
91 { DNCP_KEEP_ALIVE_INTERVAL, "Keep-alive interval" },
92 { DNCP_TRUST_VERDICT, "Trust-Verdict" },
93
94 { HNCP_HNCP_VERSION, "HNCP-Version" },
95 { HNCP_EXTERNAL_CONNECTION, "External-Connection" },
96 { HNCP_DELEGATED_PREFIX, "Delegated-Prefix" },
97 { HNCP_PREFIX_POLICY, "Prefix-Policy" },
98 { HNCP_DHCPV4_DATA, "DHCPv4-Data" },
99 { HNCP_DHCPV6_DATA, "DHCPv6-Data" },
100 { HNCP_ASSIGNED_PREFIX, "Assigned-Prefix" },
101 { HNCP_NODE_ADDRESS, "Node-Address" },
102 { HNCP_DNS_DELEGATED_ZONE, "DNS-Delegated-Zone" },
103 { HNCP_DOMAIN_NAME, "Domain-Name" },
104 { HNCP_NODE_NAME, "Node-Name" },
105 { HNCP_MANAGED_PSK, "Managed-PSK" },
106
107 { RANGE_DNCP_RESERVED, "Reserved" },
108 { RANGE_HNCP_UNASSIGNED, "Unassigned" },
109 { RANGE_DNCP_PRIVATE_USE, "Private use" },
110 { RANGE_DNCP_FUTURE_USE, "Future use" },
111
112 { 0, NULL}
113 };
114
115 #define DH4OPT_DNS_SERVERS 6 /* RFC2132 */
116 #define DH4OPT_NTP_SERVERS 42 /* RFC2132 */
117 #define DH4OPT_DOMAIN_SEARCH 119 /* RFC3397 */
118
119 static const struct tok dh4opt_str[] = {
120 { DH4OPT_DNS_SERVERS, "DNS-server" },
121 { DH4OPT_NTP_SERVERS, "NTP-server"},
122 { DH4OPT_DOMAIN_SEARCH, "DNS-search" },
123 { 0, NULL }
124 };
125
126 #define DH6OPT_DNS_SERVERS 23 /* RFC3646 */
127 #define DH6OPT_DOMAIN_LIST 24 /* RFC3646 */
128 #define DH6OPT_SNTP_SERVERS 31 /* RFC4075 */
129
130 static const struct tok dh6opt_str[] = {
131 { DH6OPT_DNS_SERVERS, "DNS-server" },
132 { DH6OPT_DOMAIN_LIST, "DNS-search-list" },
133 { DH6OPT_SNTP_SERVERS, "SNTP-servers" },
134 { 0, NULL }
135 };
136
137 static const char *
138 format_nid(const u_char *data)
139 {
140 static char buf[4][11+5];
141 static int i = 0;
142 i = (i + 1) % 4;
143 snprintf(buf[i], 16, "%02x:%02x:%02x:%02x",
144 data[0], data[1], data[2], data[3]);
145 return buf[i];
146 }
147
148 static const char *
149 format_256(const u_char *data)
150 {
151 static char buf[4][64+5];
152 static int i = 0;
153 i = (i + 1) % 4;
154 snprintf(buf[i], 28, "%016lx%016lx%016lx%016lx",
155 EXTRACT_64BITS(data),
156 EXTRACT_64BITS(data + 8),
157 EXTRACT_64BITS(data + 16),
158 EXTRACT_64BITS(data + 24)
159 );
160 return buf[i];
161 }
162
163 static const char *
164 format_interval(const uint16_t n)
165 {
166 static char buf[4][sizeof("000.00s")];
167 static int i = 0;
168 i = (i + 1) % 4;
169 if (n == 0)
170 return "0.0s (bogus)";
171 snprintf(buf[i], sizeof(buf[i]), "%u.%02us", n / 100, n % 100);
172 return buf[i];
173 }
174
175 static const char *
176 format_ip6addr(netdissect_options *ndo, const u_char *cp)
177 {
178 if (EXTRACT_64BITS(cp) == 0x0 && EXTRACT_32BITS(cp+8) == 0xffff)
179 return ipaddr_string(ndo, cp + 12);
180 else
181 return ip6addr_string(ndo, cp);
182 }
183
184 static int
185 print_prefix(netdissect_options *ndo, const u_char *prefix, u_int max_length)
186 {
187 int plenbytes;
188 static char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::/128")];
189 static u_char prefix_v4[5];
190 if (prefix[0] >= 96 && max_length >= 13 && EXTRACT_64BITS(prefix+1) == 0x0 && EXTRACT_32BITS(prefix+9) == 0xffff) {
191 prefix_v4[0] = prefix[0]-96;
192 prefix_v4[1] = prefix[13];
193 prefix_v4[2] = prefix[14];
194 prefix_v4[3] = prefix[15];
195 prefix_v4[4] = prefix[16];
196 plenbytes = 12 + decode_prefix4(ndo, (const u_char *)prefix_v4, max_length-12, buf, 45);
197 } else {
198 plenbytes = decode_prefix6(ndo, prefix, max_length, buf, 45);
199 }
200
201 safeputs(ndo, (const u_char*)buf, 45);
202 return plenbytes;
203 }
204
205 static int
206 print_dns_label(netdissect_options *ndo,
207 const u_char *cp, u_int max_length, int print)
208 {
209 u_int length = 0;
210 while (length < max_length) {
211 u_int lab_length = cp[length++];
212 if (lab_length == 0)
213 return (int)length;
214 if (length > 1 && print)
215 safeputchar(ndo, '.');
216 if (length+lab_length > max_length) {
217 if (print)
218 safeputs(ndo, cp+length, max_length-length);
219 break;
220 }
221 if (print)
222 safeputs(ndo, cp+length, lab_length);
223 length += lab_length;
224 }
225 if (print)
226 ND_PRINT((ndo, "[|DNS]"));
227 return -1;
228 }
229
230 static int
231 dhcpv4_print(netdissect_options *ndo,
232 const u_char *cp, u_int length, int indent)
233 {
234 u_int i, t;
235 const u_char *tlv, *value;
236 uint8_t type, optlen;
237
238 i = 0;
239 while (i < length) {
240 tlv = cp + i;
241 type = (uint8_t)tlv[0];
242 optlen = (uint8_t)tlv[1];
243 value = tlv + 2;
244
245 ND_PRINT((ndo, "\n"));
246 for (t = indent; t > 0; t--)
247 ND_PRINT((ndo, "\t"));
248
249 ND_PRINT((ndo, "%s", tok2str(dh4opt_str, "Unknown", type)));
250 ND_PRINT((ndo," (%u)", optlen + 2 ));
251
252 switch (type) {
253 case DH4OPT_DNS_SERVERS:
254 case DH4OPT_NTP_SERVERS: {
255 if (optlen < 4 || optlen % 4 != 0) {
256 return -1;
257 }
258 for (t = 0; t < optlen; t += 4)
259 ND_PRINT((ndo, " %s", ipaddr_string(ndo, value + t)));
260 }
261 break;
262 case DH4OPT_DOMAIN_SEARCH: {
263 const u_char *tp = value;
264 while (tp < value + optlen) {
265 ND_PRINT((ndo, " "));
266 if ((tp = ns_nprint(ndo, tp, value + optlen)) == NULL)
267 return -1;
268 }
269 }
270 break;
271 }
272
273 i += 2 + optlen;
274 }
275 return 0;
276 }
277
278 static int
279 dhcpv6_print(netdissect_options *ndo,
280 const u_char *cp, u_int length, int indent)
281 {
282 u_int i, t;
283 const u_char *tlv, *value;
284 uint16_t type, optlen;
285
286 i = 0;
287 while (i < length) {
288 tlv = cp + i;
289 type = EXTRACT_16BITS(tlv);
290 optlen = EXTRACT_16BITS(tlv + 2);
291 value = tlv + 4;
292
293 ND_PRINT((ndo, "\n"));
294 for (t = indent; t > 0; t--)
295 ND_PRINT((ndo, "\t"));
296
297 ND_PRINT((ndo, "%s", tok2str(dh6opt_str, "Unknown", type)));
298 ND_PRINT((ndo," (%u)", optlen + 4 ));
299
300 switch (type) {
301 case DH6OPT_DNS_SERVERS:
302 case DH6OPT_SNTP_SERVERS: {
303 if (optlen % 16 != 0) {
304 ND_PRINT((ndo, " %s", istr));
305 return -1;
306 }
307 for (t = 0; t < optlen; t += 16)
308 ND_PRINT((ndo, " %s", ip6addr_string(ndo, value + t)));
309 }
310 break;
311 case DH6OPT_DOMAIN_LIST: {
312 const u_char *tp = value;
313 while (tp < value + optlen) {
314 ND_PRINT((ndo, " "));
315 if ((tp = ns_nprint(ndo, tp, value + optlen)) == NULL)
316 return -1;
317 }
318 }
319 break;
320 }
321
322 i += 4 + optlen;
323 }
324 return 0;
325 }
326
327 /* Determine in-line mode */
328 static int
329 is_in_line(netdissect_options *ndo, int indent)
330 {
331 return indent - 1 >= ndo->ndo_vflag && ndo->ndo_vflag < 3;
332 }
333
334 static void
335 print_type_in_line(netdissect_options *ndo,
336 uint32_t type, int count, int indent, int *first_one)
337 {
338 if (count > 0) {
339 if (*first_one) {
340 *first_one = 0;
341 if (indent > 1) {
342 u_int t;
343 ND_PRINT((ndo, "\n"));
344 for (t = indent; t > 0; t--)
345 ND_PRINT((ndo, "\t"));
346 } else {
347 ND_PRINT((ndo, " "));
348 }
349 } else {
350 ND_PRINT((ndo, ", "));
351 }
352 ND_PRINT((ndo, "%s", tok2str(type_values, "Easter Egg", type)));
353 if (count > 1)
354 ND_PRINT((ndo, " (x%d)", count));
355 }
356 }
357
358 void
359 hncp_print_rec(netdissect_options *ndo,
360 const u_char *cp, u_int length, int indent)
361 {
362 const int in_line = is_in_line(ndo, indent);
363 int first_one = 1;
364
365 u_int i, t;
366
367 uint32_t last_type_mask = -1;
368 int last_type_count = -1;
369
370 const u_char *tlv, *value;
371 uint16_t type, bodylen;
372 uint32_t type_mask;
373
374 i = 0;
375 while (i < length) {
376 tlv = cp + i;
377
378 if (!in_line) {
379 ND_PRINT((ndo, "\n"));
380 for (t = indent; t > 0; t--)
381 ND_PRINT((ndo, "\t"));
382 }
383
384 ND_TCHECK2(*tlv, 4);
385 if (i + 4 > length)
386 goto invalid;
387
388 type = EXTRACT_16BITS(tlv);
389 bodylen = EXTRACT_16BITS(tlv + 2);
390 value = tlv + 4;
391 ND_TCHECK2(*value, bodylen);
392 if (i + bodylen + 4 > length)
393 goto invalid;
394
395 type_mask =
396 (type == 0) ? RANGE_DNCP_RESERVED:
397 (44 <= type && type <= 511) ? RANGE_HNCP_UNASSIGNED:
398 (768 <= type && type <= 1023) ? RANGE_DNCP_PRIVATE_USE:
399 RANGE_DNCP_FUTURE_USE;
400 if (type == 6 || type == 7)
401 type_mask = RANGE_DNCP_FUTURE_USE;
402
403 /* defined types */
404 {
405 t = 0;
406 while (1) {
407 u_int key = type_values[t++].v;
408 if (key > 0xffff)
409 break;
410 if (key == type) {
411 type_mask = type;
412 break;
413 }
414 }
415 }
416
417 if (in_line) {
418 if (last_type_mask == type_mask) {
419 last_type_count++;
420 } else {
421 print_type_in_line(ndo, last_type_mask, last_type_count, indent, &first_one);
422 last_type_mask = type_mask;
423 last_type_count = 1;
424 }
425
426 goto skip_multiline;
427 }
428
429 ND_PRINT((ndo,"%s", tok2str(type_values, "Easter Egg (42)", type_mask) ));
430 if (type_mask > 0xffff)
431 ND_PRINT((ndo,": type=%u", type ));
432 ND_PRINT((ndo," (%u)", bodylen + 4 ));
433
434 switch (type_mask) {
435
436 case DNCP_REQUEST_NETWORK_STATE: {
437 if (bodylen != 0)
438 ND_PRINT((ndo, " %s", istr));
439 }
440 break;
441
442 case DNCP_REQUEST_NODE_STATE: {
443 const char *node_identifier;
444 if (bodylen != 4)
445 goto invalid;
446 node_identifier = format_nid(value);
447 ND_PRINT((ndo, " NID: %s", node_identifier));
448 }
449 break;
450
451 case DNCP_NODE_ENDPOINT: {
452 const char *node_identifier;
453 uint32_t endpoint_identifier;
454 if (bodylen != 8)
455 goto invalid;
456 node_identifier = format_nid(value);
457 endpoint_identifier = EXTRACT_32BITS(value + 4);
458 ND_PRINT((ndo, " NID: %s EPID: %08x",
459 node_identifier,
460 endpoint_identifier
461 ));
462 }
463 break;
464
465 case DNCP_NETWORK_STATE: {
466 uint64_t hash;
467 if (bodylen != 8)
468 goto invalid;
469 hash = EXTRACT_64BITS(value);
470 ND_PRINT((ndo, " hash: %016lx", hash));
471 }
472 break;
473
474 case DNCP_NODE_STATE: {
475 const char *node_identifier, *time;
476 uint32_t sequence_number;
477 uint64_t hash;
478 if (bodylen < 20)
479 goto invalid;
480 node_identifier = format_nid(value);
481 sequence_number = EXTRACT_32BITS(value + 4);
482 time = format_interval(EXTRACT_32BITS(value + 8));
483 hash = EXTRACT_64BITS(value + 12);
484 ND_PRINT((ndo, " NID: %s seqno: %u %s hash: %016lx",
485 node_identifier,
486 sequence_number,
487 time,
488 hash
489 ));
490 hncp_print_rec(ndo, value+20, bodylen-20, indent+1);
491 }
492 break;
493
494 case DNCP_PEER: {
495 const char *peer_node_identifier;
496 uint32_t peer_endpoint_identifier, endpoint_identifier;
497 if (bodylen != 12)
498 goto invalid;
499 peer_node_identifier = format_nid(value);
500 peer_endpoint_identifier = EXTRACT_32BITS(value + 4);
501 endpoint_identifier = EXTRACT_32BITS(value + 8);
502 ND_PRINT((ndo, " Peer-NID: %s Peer-EPID: %08x Local-EPID: %08x",
503 peer_node_identifier,
504 peer_endpoint_identifier,
505 endpoint_identifier
506 ));
507 }
508 break;
509
510 case DNCP_KEEP_ALIVE_INTERVAL: {
511 uint32_t endpoint_identifier;
512 const char *interval;
513 if (bodylen < 8)
514 goto invalid;
515 endpoint_identifier = EXTRACT_32BITS(value);
516 interval = format_interval(EXTRACT_32BITS(value + 4));
517 ND_PRINT((ndo, " EPID: %08x Interval: %s",
518 endpoint_identifier,
519 interval
520 ));
521 }
522 break;
523
524 case DNCP_TRUST_VERDICT: {
525 if (bodylen <= 36)
526 goto invalid;
527 ND_PRINT((ndo, " Verdict: %u Fingerprint: %s Common Name: ",
528 *value,
529 format_256(value + 4)));
530 safeputs(ndo, value + 36, bodylen - 36);
531 }
532 break;
533
534 case HNCP_HNCP_VERSION: {
535 uint16_t capabilities;
536 uint8_t M, P, H, L;
537 if (bodylen < 5)
538 goto invalid;
539 capabilities = EXTRACT_16BITS(value + 2);
540 M = (uint8_t)((capabilities >> 12) & 0xf);
541 P = (uint8_t)((capabilities >> 8) & 0xf);
542 H = (uint8_t)((capabilities >> 4) & 0xf);
543 L = (uint8_t)(capabilities & 0xf);
544 ND_PRINT((ndo, " M: %u P: %u H: %u L: %u User-agent: ",
545 M, P, H, L
546 ));
547 safeputs(ndo, value + 4, bodylen - 4);
548 }
549 break;
550
551 case HNCP_EXTERNAL_CONNECTION: {
552 /* Container TLV */
553 hncp_print_rec(ndo, value, bodylen, indent+1);
554 }
555 break;
556
557 case HNCP_DELEGATED_PREFIX: {
558 int l;
559 if (bodylen < 9 || bodylen < 9 + (value[8] + 7) / 8)
560 goto invalid;
561 ND_PRINT((ndo, " VLSO: %s PLSO: %s Prefix: ",
562 format_interval(EXTRACT_32BITS(value)),
563 format_interval(EXTRACT_32BITS(value + 4))
564 ));
565 if ((l = print_prefix(ndo, value + 8, bodylen - 8)) < 0)
566 goto invalid;
567 l += 8 + (-l & 3);
568
569 if (bodylen >= l)
570 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
571 }
572 break;
573
574 case HNCP_PREFIX_POLICY: {
575 uint8_t policy;
576 if (bodylen < 1)
577 goto invalid;
578 policy = value[0];
579 ND_PRINT((ndo, " type: "));
580 if (policy == 0) {
581 if (bodylen != 1)
582 goto invalid;
583 ND_PRINT((ndo, "Internet connectivity"));
584 } else if (policy >= 1 && policy <= 128) {
585 ND_PRINT((ndo, "Dest-Prefix: "));
586 print_prefix(ndo, value, bodylen);
587 } else if (policy == 129) {
588 ND_PRINT((ndo, "DNS domain: "));
589 print_dns_label(ndo, value+1, bodylen-1, 1);
590 } else if (policy == 130) {
591 ND_PRINT((ndo, "Opaque UTF-8: "));
592 safeputs(ndo, value + 1, bodylen - 1);
593 } else if (policy == 131) {
594 if (bodylen != 1)
595 goto invalid;
596 ND_PRINT((ndo, "Restrictive assignment"));
597 } else if (policy >= 132) {
598 ND_PRINT((ndo, "Unknown (%u)", policy)); /* Reserved for future additions */
599 }
600 }
601 break;
602
603 case HNCP_DHCPV4_DATA: {
604 if (bodylen == 0)
605 goto invalid;
606 if (dhcpv4_print(ndo, value, bodylen, indent+1) != 0)
607 goto invalid;
608 }
609 break;
610
611 case HNCP_DHCPV6_DATA: {
612 if (bodylen == 0)
613 goto invalid;
614 if (dhcpv6_print(ndo, value, bodylen, indent+1) != 0)
615 goto invalid;
616 }
617 break;
618
619 case HNCP_ASSIGNED_PREFIX: {
620 uint8_t prty;
621 int l;
622 if (bodylen < 6 || bodylen < 6 + (value[5] + 7) / 8)
623 goto invalid;
624 prty = (uint8_t)(value[4] & 0xf);
625 ND_PRINT((ndo, " EPID: %08x Prty: %u",
626 EXTRACT_32BITS(value),
627 prty
628 ));
629 ND_PRINT((ndo, " Prefix: "));
630 if ((l = print_prefix(ndo, value + 5, bodylen - 5)) < 0)
631 goto invalid;
632 l += 5;
633 l += -l & 3;
634
635 if (bodylen >= l)
636 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
637 }
638 break;
639
640 case HNCP_NODE_ADDRESS: {
641 uint32_t endpoint_identifier;
642 const char *ip_address;
643 if (bodylen < 20)
644 goto invalid;
645 endpoint_identifier = EXTRACT_32BITS(value);
646 ip_address = format_ip6addr(ndo, value + 4);
647 ND_PRINT((ndo, " EPID: %08x IP Address: %s",
648 endpoint_identifier,
649 ip_address
650 ));
651
652 hncp_print_rec(ndo, value + 20, bodylen - 20, indent+1);
653 }
654 break;
655
656 case HNCP_DNS_DELEGATED_ZONE: {
657 const char *ip_address;
658 int len;
659 if (bodylen < 17)
660 goto invalid;
661 ip_address = format_ip6addr(ndo, value);
662 ND_PRINT((ndo, " IP-Address: %s %c%c%c ",
663 ip_address,
664 (value[16] & 4) ? 'l' : '-',
665 (value[16] & 2) ? 'b' : '-',
666 (value[16] & 1) ? 's' : '-'
667 ));
668 len = print_dns_label(ndo, value+17, bodylen-17, 1);
669 if (len < 0)
670 goto invalid;
671 len += 17;
672 len += -len & 3;
673 if (bodylen >= len)
674 hncp_print_rec(ndo, value+len, bodylen-len, indent+1);
675 }
676 break;
677
678 case HNCP_DOMAIN_NAME: {
679 if (bodylen == 0)
680 goto invalid;
681 ND_PRINT((ndo, " Domain: "));
682 print_dns_label(ndo, value, bodylen, 1);
683 }
684 break;
685
686 case HNCP_NODE_NAME: {
687 u_int l;
688 if (bodylen < 17)
689 goto invalid;
690 l = value[16];
691 if (bodylen < 17 + l)
692 goto invalid;
693 ND_PRINT((ndo, " IP-Address: %s Name: ",
694 format_ip6addr(ndo, value)
695 ));
696 if (l < 64) {
697 safeputchar(ndo, '"');
698 safeputs(ndo, value + 17, l);
699 safeputchar(ndo, '"');
700 } else {
701 ND_PRINT((ndo, "%s", istr));
702 }
703 l += 17;
704 l += -l & 3;
705 if (bodylen >= l)
706 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
707 }
708 break;
709
710 case HNCP_MANAGED_PSK: {
711 if (bodylen < 32)
712 goto invalid;
713 ND_PRINT((ndo, " PSK: %s", format_256(value)));
714 hncp_print_rec(ndo, value + 32, bodylen - 32, indent+1);
715 }
716 break;
717
718 case RANGE_DNCP_RESERVED:
719 case RANGE_HNCP_UNASSIGNED:
720 case RANGE_DNCP_PRIVATE_USE:
721 case RANGE_DNCP_FUTURE_USE:
722 break;
723
724 }
725 skip_multiline:
726
727 i += 4 + bodylen + (-bodylen & 3);
728 }
729 print_type_in_line(ndo, last_type_mask, last_type_count, indent, &first_one);
730
731 return;
732
733 trunc:
734 ND_PRINT((ndo, "%s", "[|hncp]"));
735 return;
736
737 invalid:
738 ND_PRINT((ndo, "%s", istr));
739 return;
740 }