Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2016 Antonin Dcimo, Jean-Raphal 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 /* \summary: Home Networking Control Protocol (HNCP) printer */
     30 
     31 #ifdef HAVE_CONFIG_H
     32 #include "config.h"
     33 #endif
     34 
     35 #include <netdissect-stdinc.h>
     36 
     37 #include <stdlib.h>
     38 #include <string.h>
     39 
     40 #include "netdissect.h"
     41 #include "addrtoname.h"
     42 #include "extract.h"
     43 
     44 static void
     45 hncp_print_rec(netdissect_options *ndo,
     46                const u_char *cp, u_int length, int indent);
     47 
     48 void
     49 hncp_print(netdissect_options *ndo,
     50            const u_char *cp, u_int length)
     51 {
     52     ND_PRINT((ndo, "hncp (%d)", length));
     53     hncp_print_rec(ndo, cp, length, 1);
     54 }
     55 
     56 /* RFC7787 */
     57 #define DNCP_REQUEST_NETWORK_STATE  1
     58 #define DNCP_REQUEST_NODE_STATE     2
     59 #define DNCP_NODE_ENDPOINT          3
     60 #define DNCP_NETWORK_STATE          4
     61 #define DNCP_NODE_STATE             5
     62 #define DNCP_PEER                   8
     63 #define DNCP_KEEP_ALIVE_INTERVAL    9
     64 #define DNCP_TRUST_VERDICT         10
     65 
     66 /* RFC7788 */
     67 #define HNCP_HNCP_VERSION          32
     68 #define HNCP_EXTERNAL_CONNECTION   33
     69 #define HNCP_DELEGATED_PREFIX      34
     70 #define HNCP_PREFIX_POLICY         43
     71 #define HNCP_DHCPV4_DATA           37
     72 #define HNCP_DHCPV6_DATA           38
     73 #define HNCP_ASSIGNED_PREFIX       35
     74 #define HNCP_NODE_ADDRESS          36
     75 #define HNCP_DNS_DELEGATED_ZONE    39
     76 #define HNCP_DOMAIN_NAME           40
     77 #define HNCP_NODE_NAME             41
     78 #define HNCP_MANAGED_PSK           42
     79 
     80 /* See type_mask in hncp_print_rec below */
     81 #define RANGE_DNCP_RESERVED    0x10000
     82 #define RANGE_HNCP_UNASSIGNED  0x10001
     83 #define RANGE_DNCP_PRIVATE_USE 0x10002
     84 #define RANGE_DNCP_FUTURE_USE  0x10003
     85 
     86 static const struct tok type_values[] = {
     87     { DNCP_REQUEST_NETWORK_STATE, "Request network state" },
     88     { DNCP_REQUEST_NODE_STATE,    "Request node state" },
     89     { DNCP_NODE_ENDPOINT,         "Node endpoint" },
     90     { DNCP_NETWORK_STATE,         "Network state" },
     91     { DNCP_NODE_STATE,            "Node state" },
     92     { DNCP_PEER,                  "Peer" },
     93     { DNCP_KEEP_ALIVE_INTERVAL,   "Keep-alive interval" },
     94     { DNCP_TRUST_VERDICT,         "Trust-Verdict" },
     95 
     96     { HNCP_HNCP_VERSION,        "HNCP-Version" },
     97     { HNCP_EXTERNAL_CONNECTION, "External-Connection" },
     98     { HNCP_DELEGATED_PREFIX,    "Delegated-Prefix" },
     99     { HNCP_PREFIX_POLICY,       "Prefix-Policy" },
    100     { HNCP_DHCPV4_DATA,         "DHCPv4-Data" },
    101     { HNCP_DHCPV6_DATA,         "DHCPv6-Data" },
    102     { HNCP_ASSIGNED_PREFIX,     "Assigned-Prefix" },
    103     { HNCP_NODE_ADDRESS,        "Node-Address" },
    104     { HNCP_DNS_DELEGATED_ZONE,  "DNS-Delegated-Zone" },
    105     { HNCP_DOMAIN_NAME,         "Domain-Name" },
    106     { HNCP_NODE_NAME,           "Node-Name" },
    107     { HNCP_MANAGED_PSK,         "Managed-PSK" },
    108 
    109     { RANGE_DNCP_RESERVED,    "Reserved" },
    110     { RANGE_HNCP_UNASSIGNED,  "Unassigned" },
    111     { RANGE_DNCP_PRIVATE_USE, "Private use" },
    112     { RANGE_DNCP_FUTURE_USE,  "Future use" },
    113 
    114     { 0, NULL}
    115 };
    116 
    117 #define DH4OPT_DNS_SERVERS 6     /* RFC2132 */
    118 #define DH4OPT_NTP_SERVERS 42    /* RFC2132 */
    119 #define DH4OPT_DOMAIN_SEARCH 119 /* RFC3397 */
    120 
    121 static const struct tok dh4opt_str[] = {
    122     { DH4OPT_DNS_SERVERS, "DNS-server" },
    123     { DH4OPT_NTP_SERVERS, "NTP-server"},
    124     { DH4OPT_DOMAIN_SEARCH, "DNS-search" },
    125     { 0, NULL }
    126 };
    127 
    128 #define DH6OPT_DNS_SERVERS 23   /* RFC3646 */
    129 #define DH6OPT_DOMAIN_LIST 24   /* RFC3646 */
    130 #define DH6OPT_SNTP_SERVERS 31  /* RFC4075 */
    131 
    132 static const struct tok dh6opt_str[] = {
    133     { DH6OPT_DNS_SERVERS,  "DNS-server" },
    134     { DH6OPT_DOMAIN_LIST,  "DNS-search-list" },
    135     { DH6OPT_SNTP_SERVERS, "SNTP-servers" },
    136     { 0, NULL }
    137 };
    138 
    139 /*
    140  * For IPv4-mapped IPv6 addresses, length of the prefix that precedes
    141  * the 4 bytes of IPv4 address at the end of the IPv6 address.
    142  */
    143 #define IPV4_MAPPED_HEADING_LEN    12
    144 
    145 /*
    146  * Is an IPv6 address an IPv4-mapped address?
    147  */
    148 static inline int
    149 is_ipv4_mapped_address(const u_char *addr)
    150 {
    151     /* The value of the prefix */
    152     static const u_char ipv4_mapped_heading[IPV4_MAPPED_HEADING_LEN] =
    153         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
    154 
    155     return memcmp(addr, ipv4_mapped_heading, IPV4_MAPPED_HEADING_LEN) == 0;
    156 }
    157 
    158 static const char *
    159 format_nid(const u_char *data)
    160 {
    161     static char buf[4][11+5];
    162     static int i = 0;
    163     i = (i + 1) % 4;
    164     snprintf(buf[i], 16, "%02x:%02x:%02x:%02x",
    165              data[0], data[1], data[2], data[3]);
    166     return buf[i];
    167 }
    168 
    169 static const char *
    170 format_256(const u_char *data)
    171 {
    172     static char buf[4][64+5];
    173     static int i = 0;
    174     i = (i + 1) % 4;
    175     snprintf(buf[i], 28, "%016" PRIx64 "%016" PRIx64 "%016" PRIx64 "%016" PRIx64,
    176          EXTRACT_64BITS(data),
    177          EXTRACT_64BITS(data + 8),
    178          EXTRACT_64BITS(data + 16),
    179          EXTRACT_64BITS(data + 24)
    180     );
    181     return buf[i];
    182 }
    183 
    184 static const char *
    185 format_interval(const uint32_t n)
    186 {
    187     static char buf[4][sizeof("0000000.000s")];
    188     static int i = 0;
    189     i = (i + 1) % 4;
    190     snprintf(buf[i], sizeof(buf[i]), "%u.%03us", n / 1000, n % 1000);
    191     return buf[i];
    192 }
    193 
    194 static const char *
    195 format_ip6addr(netdissect_options *ndo, const u_char *cp)
    196 {
    197     if (is_ipv4_mapped_address(cp))
    198         return ipaddr_string(ndo, cp + IPV4_MAPPED_HEADING_LEN);
    199     else
    200         return ip6addr_string(ndo, cp);
    201 }
    202 
    203 static int
    204 print_prefix(netdissect_options *ndo, const u_char *prefix, u_int max_length)
    205 {
    206     int plenbytes;
    207     char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::/128")];
    208 
    209     if (prefix[0] >= 96 && max_length >= IPV4_MAPPED_HEADING_LEN + 1 &&
    210         is_ipv4_mapped_address(&prefix[1])) {
    211         struct in_addr addr;
    212         u_int plen;
    213 
    214         plen = prefix[0]-96;
    215         if (32 < plen)
    216             return -1;
    217         max_length -= 1;
    218 
    219         memset(&addr, 0, sizeof(addr));
    220         plenbytes = (plen + 7) / 8;
    221         if (max_length < (u_int)plenbytes + IPV4_MAPPED_HEADING_LEN)
    222             return -3;
    223         memcpy(&addr, &prefix[1 + IPV4_MAPPED_HEADING_LEN], plenbytes);
    224         if (plen % 8) {
    225 		((u_char *)&addr)[plenbytes - 1] &=
    226 			((0xff00 >> (plen % 8)) & 0xff);
    227 	}
    228 	snprintf(buf, sizeof(buf), "%s/%d", ipaddr_string(ndo, &addr), plen);
    229         plenbytes += 1 + IPV4_MAPPED_HEADING_LEN;
    230     } else {
    231         plenbytes = decode_prefix6(ndo, prefix, max_length, buf, sizeof(buf));
    232     }
    233 
    234     ND_PRINT((ndo, "%s", buf));
    235     return plenbytes;
    236 }
    237 
    238 static int
    239 print_dns_label(netdissect_options *ndo,
    240                 const u_char *cp, u_int max_length, int print)
    241 {
    242     u_int length = 0;
    243     while (length < max_length) {
    244         u_int lab_length = cp[length++];
    245         if (lab_length == 0)
    246             return (int)length;
    247         if (length > 1 && print)
    248             safeputchar(ndo, '.');
    249         if (length+lab_length > max_length) {
    250             if (print)
    251                 safeputs(ndo, cp+length, max_length-length);
    252             break;
    253         }
    254         if (print)
    255             safeputs(ndo, cp+length, lab_length);
    256         length += lab_length;
    257     }
    258     if (print)
    259         ND_PRINT((ndo, "[|DNS]"));
    260     return -1;
    261 }
    262 
    263 static int
    264 dhcpv4_print(netdissect_options *ndo,
    265              const u_char *cp, u_int length, int indent)
    266 {
    267     u_int i, t;
    268     const u_char *tlv, *value;
    269     uint8_t type, optlen;
    270 
    271     i = 0;
    272     while (i < length) {
    273         tlv = cp + i;
    274         type = (uint8_t)tlv[0];
    275         optlen = (uint8_t)tlv[1];
    276         value = tlv + 2;
    277 
    278         ND_PRINT((ndo, "\n"));
    279         for (t = indent; t > 0; t--)
    280             ND_PRINT((ndo, "\t"));
    281 
    282         ND_PRINT((ndo, "%s", tok2str(dh4opt_str, "Unknown", type)));
    283         ND_PRINT((ndo," (%u)", optlen + 2 ));
    284 
    285         switch (type) {
    286         case DH4OPT_DNS_SERVERS:
    287         case DH4OPT_NTP_SERVERS: {
    288             if (optlen < 4 || optlen % 4 != 0) {
    289                 return -1;
    290             }
    291             for (t = 0; t < optlen; t += 4)
    292                 ND_PRINT((ndo, " %s", ipaddr_string(ndo, value + t)));
    293         }
    294             break;
    295         case DH4OPT_DOMAIN_SEARCH: {
    296             const u_char *tp = value;
    297             while (tp < value + optlen) {
    298                 ND_PRINT((ndo, " "));
    299                 if ((tp = ns_nprint(ndo, tp, value + optlen)) == NULL)
    300                     return -1;
    301             }
    302         }
    303             break;
    304         }
    305 
    306         i += 2 + optlen;
    307     }
    308     return 0;
    309 }
    310 
    311 static int
    312 dhcpv6_print(netdissect_options *ndo,
    313              const u_char *cp, u_int length, int indent)
    314 {
    315     u_int i, t;
    316     const u_char *tlv, *value;
    317     uint16_t type, optlen;
    318 
    319     i = 0;
    320     while (i < length) {
    321         tlv = cp + i;
    322         type = EXTRACT_16BITS(tlv);
    323         optlen = EXTRACT_16BITS(tlv + 2);
    324         value = tlv + 4;
    325 
    326         ND_PRINT((ndo, "\n"));
    327         for (t = indent; t > 0; t--)
    328             ND_PRINT((ndo, "\t"));
    329 
    330         ND_PRINT((ndo, "%s", tok2str(dh6opt_str, "Unknown", type)));
    331         ND_PRINT((ndo," (%u)", optlen + 4 ));
    332 
    333         switch (type) {
    334             case DH6OPT_DNS_SERVERS:
    335             case DH6OPT_SNTP_SERVERS: {
    336                 if (optlen % 16 != 0) {
    337                     ND_PRINT((ndo, " %s", istr));
    338                     return -1;
    339                 }
    340                 for (t = 0; t < optlen; t += 16)
    341                     ND_PRINT((ndo, " %s", ip6addr_string(ndo, value + t)));
    342             }
    343                 break;
    344             case DH6OPT_DOMAIN_LIST: {
    345                 const u_char *tp = value;
    346                 while (tp < value + optlen) {
    347                     ND_PRINT((ndo, " "));
    348                     if ((tp = ns_nprint(ndo, tp, value + optlen)) == NULL)
    349                         return -1;
    350                 }
    351             }
    352                 break;
    353         }
    354 
    355         i += 4 + optlen;
    356     }
    357     return 0;
    358 }
    359 
    360 /* Determine in-line mode */
    361 static int
    362 is_in_line(netdissect_options *ndo, int indent)
    363 {
    364     return indent - 1 >= ndo->ndo_vflag && ndo->ndo_vflag < 3;
    365 }
    366 
    367 static void
    368 print_type_in_line(netdissect_options *ndo,
    369                    uint32_t type, int count, int indent, int *first_one)
    370 {
    371     if (count > 0) {
    372         if (*first_one) {
    373             *first_one = 0;
    374             if (indent > 1) {
    375                 u_int t;
    376                 ND_PRINT((ndo, "\n"));
    377                 for (t = indent; t > 0; t--)
    378                     ND_PRINT((ndo, "\t"));
    379             } else {
    380                 ND_PRINT((ndo, " "));
    381             }
    382         } else {
    383             ND_PRINT((ndo, ", "));
    384         }
    385         ND_PRINT((ndo, "%s", tok2str(type_values, "Easter Egg", type)));
    386         if (count > 1)
    387             ND_PRINT((ndo, " (x%d)", count));
    388     }
    389 }
    390 
    391 void
    392 hncp_print_rec(netdissect_options *ndo,
    393                const u_char *cp, u_int length, int indent)
    394 {
    395     const int in_line = is_in_line(ndo, indent);
    396     int first_one = 1;
    397 
    398     u_int i, t;
    399 
    400     uint32_t last_type_mask = 0xffffffffU;
    401     int last_type_count = -1;
    402 
    403     const u_char *tlv, *value;
    404     uint16_t type, bodylen;
    405     uint32_t type_mask;
    406 
    407     i = 0;
    408     while (i < length) {
    409         tlv = cp + i;
    410 
    411         if (!in_line) {
    412             ND_PRINT((ndo, "\n"));
    413             for (t = indent; t > 0; t--)
    414                 ND_PRINT((ndo, "\t"));
    415         }
    416 
    417         ND_TCHECK2(*tlv, 4);
    418         if (i + 4 > length)
    419             goto invalid;
    420 
    421         type = EXTRACT_16BITS(tlv);
    422         bodylen = EXTRACT_16BITS(tlv + 2);
    423         value = tlv + 4;
    424         ND_TCHECK2(*value, bodylen);
    425         if (i + bodylen + 4 > length)
    426             goto invalid;
    427 
    428         type_mask =
    429             (type == 0)                   ? RANGE_DNCP_RESERVED:
    430             (44 <= type && type <= 511)   ? RANGE_HNCP_UNASSIGNED:
    431             (768 <= type && type <= 1023) ? RANGE_DNCP_PRIVATE_USE:
    432                                             RANGE_DNCP_FUTURE_USE;
    433         if (type == 6 || type == 7)
    434             type_mask = RANGE_DNCP_FUTURE_USE;
    435 
    436         /* defined types */
    437         {
    438             t = 0;
    439             while (1) {
    440                 u_int key = type_values[t++].v;
    441                 if (key > 0xffff)
    442                     break;
    443                 if (key == type) {
    444                     type_mask = type;
    445                     break;
    446                 }
    447             }
    448         }
    449 
    450         if (in_line) {
    451             if (last_type_mask == type_mask) {
    452                 last_type_count++;
    453             } else {
    454                 print_type_in_line(ndo, last_type_mask, last_type_count, indent, &first_one);
    455                 last_type_mask = type_mask;
    456                 last_type_count = 1;
    457             }
    458 
    459             goto skip_multiline;
    460         }
    461 
    462         ND_PRINT((ndo,"%s", tok2str(type_values, "Easter Egg (42)", type_mask) ));
    463         if (type_mask > 0xffff)
    464             ND_PRINT((ndo,": type=%u", type ));
    465         ND_PRINT((ndo," (%u)", bodylen + 4 ));
    466 
    467         switch (type_mask) {
    468 
    469         case DNCP_REQUEST_NETWORK_STATE: {
    470             if (bodylen != 0)
    471                 ND_PRINT((ndo, " %s", istr));
    472         }
    473             break;
    474 
    475         case DNCP_REQUEST_NODE_STATE: {
    476             const char *node_identifier;
    477             if (bodylen != 4) {
    478                 ND_PRINT((ndo, " %s", istr));
    479                 break;
    480             }
    481             node_identifier = format_nid(value);
    482             ND_PRINT((ndo, " NID: %s", node_identifier));
    483         }
    484             break;
    485 
    486         case DNCP_NODE_ENDPOINT: {
    487             const char *node_identifier;
    488             uint32_t endpoint_identifier;
    489             if (bodylen != 8) {
    490                 ND_PRINT((ndo, " %s", istr));
    491                 break;
    492             }
    493             node_identifier = format_nid(value);
    494             endpoint_identifier = EXTRACT_32BITS(value + 4);
    495             ND_PRINT((ndo, " NID: %s EPID: %08x",
    496                 node_identifier,
    497                 endpoint_identifier
    498             ));
    499         }
    500             break;
    501 
    502         case DNCP_NETWORK_STATE: {
    503             uint64_t hash;
    504             if (bodylen != 8) {
    505                 ND_PRINT((ndo, " %s", istr));
    506                 break;
    507             }
    508             hash = EXTRACT_64BITS(value);
    509             ND_PRINT((ndo, " hash: %016" PRIx64, hash));
    510         }
    511             break;
    512 
    513         case DNCP_NODE_STATE: {
    514             const char *node_identifier, *interval;
    515             uint32_t sequence_number;
    516             uint64_t hash;
    517             if (bodylen < 20) {
    518                 ND_PRINT((ndo, " %s", istr));
    519                 break;
    520             }
    521             node_identifier = format_nid(value);
    522             sequence_number = EXTRACT_32BITS(value + 4);
    523             interval = format_interval(EXTRACT_32BITS(value + 8));
    524             hash = EXTRACT_64BITS(value + 12);
    525             ND_PRINT((ndo, " NID: %s seqno: %u %s hash: %016" PRIx64,
    526                 node_identifier,
    527                 sequence_number,
    528                 interval,
    529                 hash
    530             ));
    531             hncp_print_rec(ndo, value+20, bodylen-20, indent+1);
    532         }
    533             break;
    534 
    535         case DNCP_PEER: {
    536             const char *peer_node_identifier;
    537             uint32_t peer_endpoint_identifier, endpoint_identifier;
    538             if (bodylen != 12) {
    539                 ND_PRINT((ndo, " %s", istr));
    540                 break;
    541             }
    542             peer_node_identifier = format_nid(value);
    543             peer_endpoint_identifier = EXTRACT_32BITS(value + 4);
    544             endpoint_identifier = EXTRACT_32BITS(value + 8);
    545             ND_PRINT((ndo, " Peer-NID: %s Peer-EPID: %08x Local-EPID: %08x",
    546                 peer_node_identifier,
    547                 peer_endpoint_identifier,
    548                 endpoint_identifier
    549             ));
    550         }
    551             break;
    552 
    553         case DNCP_KEEP_ALIVE_INTERVAL: {
    554             uint32_t endpoint_identifier;
    555             const char *interval;
    556             if (bodylen < 8) {
    557                 ND_PRINT((ndo, " %s", istr));
    558                 break;
    559             }
    560             endpoint_identifier = EXTRACT_32BITS(value);
    561             interval = format_interval(EXTRACT_32BITS(value + 4));
    562             ND_PRINT((ndo, " EPID: %08x Interval: %s",
    563                 endpoint_identifier,
    564                 interval
    565             ));
    566         }
    567             break;
    568 
    569         case DNCP_TRUST_VERDICT: {
    570             if (bodylen <= 36) {
    571                 ND_PRINT((ndo, " %s", istr));
    572                 break;
    573             }
    574             ND_PRINT((ndo, " Verdict: %u Fingerprint: %s Common Name: ",
    575                 *value,
    576                 format_256(value + 4)));
    577             safeputs(ndo, value + 36, bodylen - 36);
    578         }
    579             break;
    580 
    581         case HNCP_HNCP_VERSION: {
    582             uint16_t capabilities;
    583             uint8_t M, P, H, L;
    584             if (bodylen < 5) {
    585                 ND_PRINT((ndo, " %s", istr));
    586                 break;
    587             }
    588             capabilities = EXTRACT_16BITS(value + 2);
    589             M = (uint8_t)((capabilities >> 12) & 0xf);
    590             P = (uint8_t)((capabilities >> 8) & 0xf);
    591             H = (uint8_t)((capabilities >> 4) & 0xf);
    592             L = (uint8_t)(capabilities & 0xf);
    593             ND_PRINT((ndo, " M: %u P: %u H: %u L: %u User-agent: ",
    594                 M, P, H, L
    595             ));
    596             safeputs(ndo, value + 4, bodylen - 4);
    597         }
    598             break;
    599 
    600         case HNCP_EXTERNAL_CONNECTION: {
    601             /* Container TLV */
    602             hncp_print_rec(ndo, value, bodylen, indent+1);
    603         }
    604             break;
    605 
    606         case HNCP_DELEGATED_PREFIX: {
    607             int l;
    608             if (bodylen < 9 || bodylen < 9 + (value[8] + 7) / 8) {
    609                 ND_PRINT((ndo, " %s", istr));
    610                 break;
    611             }
    612             ND_PRINT((ndo, " VLSO: %s PLSO: %s Prefix: ",
    613                 format_interval(EXTRACT_32BITS(value)),
    614                 format_interval(EXTRACT_32BITS(value + 4))
    615             ));
    616             l = print_prefix(ndo, value + 8, bodylen - 8);
    617             if (l == -1) {
    618                 ND_PRINT((ndo, "(length is invalid)"));
    619                 break;
    620             }
    621             if (l < 0) {
    622                 /*
    623                  * We've already checked that we've captured the
    624                  * entire TLV, based on its length, so this will
    625                  * either be -1, meaning "the prefix length is
    626                  * greater than the longest possible address of
    627                  * that type" (i.e., > 32 for IPv4 or > 128 for
    628                  * IPv6", or -3, meaning "the prefix runs past
    629                  * the end of the TLV".
    630                  */
    631                 ND_PRINT((ndo, " %s", istr));
    632                 break;
    633             }
    634             l += 8 + (-l & 3);
    635 
    636             if (bodylen >= l)
    637                 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
    638         }
    639             break;
    640 
    641         case HNCP_PREFIX_POLICY: {
    642             uint8_t policy;
    643             int l;
    644             if (bodylen < 1) {
    645                 ND_PRINT((ndo, " %s", istr));
    646                 break;
    647             }
    648             policy = value[0];
    649             ND_PRINT((ndo, " type: "));
    650             if (policy == 0) {
    651                 if (bodylen != 1) {
    652                     ND_PRINT((ndo, " %s", istr));
    653                     break;
    654                 }
    655                 ND_PRINT((ndo, "Internet connectivity"));
    656             } else if (policy >= 1 && policy <= 128) {
    657                 ND_PRINT((ndo, "Dest-Prefix: "));
    658                 l = print_prefix(ndo, value, bodylen);
    659                 if (l == -1) {
    660                     ND_PRINT((ndo, "(length is invalid)"));
    661                     break;
    662                 }
    663                 if (l < 0) {
    664                     /*
    665                      * We've already checked that we've captured the
    666                      * entire TLV, based on its length, so this will
    667                      * either be -1, meaning "the prefix length is
    668                      * greater than the longest possible address of
    669                      * that type" (i.e., > 32 for IPv4 or > 128 for
    670                      * IPv6", or -3, meaning "the prefix runs past
    671                      * the end of the TLV".
    672                      */
    673                     ND_PRINT((ndo, " %s", istr));
    674                     break;
    675                 }
    676             } else if (policy == 129) {
    677                 ND_PRINT((ndo, "DNS domain: "));
    678                 print_dns_label(ndo, value+1, bodylen-1, 1);
    679             } else if (policy == 130) {
    680                 ND_PRINT((ndo, "Opaque UTF-8: "));
    681                 safeputs(ndo, value + 1, bodylen - 1);
    682             } else if (policy == 131) {
    683                 if (bodylen != 1) {
    684                     ND_PRINT((ndo, " %s", istr));
    685                     break;
    686                 }
    687                 ND_PRINT((ndo, "Restrictive assignment"));
    688             } else if (policy >= 132) {
    689                 ND_PRINT((ndo, "Unknown (%u)", policy)); /* Reserved for future additions */
    690             }
    691         }
    692             break;
    693 
    694         case HNCP_DHCPV4_DATA: {
    695             if (bodylen == 0) {
    696                 ND_PRINT((ndo, " %s", istr));
    697                 break;
    698             }
    699             if (dhcpv4_print(ndo, value, bodylen, indent+1) != 0)
    700                 goto invalid;
    701         }
    702             break;
    703 
    704         case HNCP_DHCPV6_DATA: {
    705             if (bodylen == 0) {
    706                 ND_PRINT((ndo, " %s", istr));
    707                 break;
    708             }
    709             if (dhcpv6_print(ndo, value, bodylen, indent+1) != 0) {
    710                 ND_PRINT((ndo, " %s", istr));
    711                 break;
    712             }
    713         }
    714             break;
    715 
    716         case HNCP_ASSIGNED_PREFIX: {
    717             uint8_t prty;
    718             int l;
    719             if (bodylen < 6 || bodylen < 6 + (value[5] + 7) / 8) {
    720                 ND_PRINT((ndo, " %s", istr));
    721                 break;
    722             }
    723             prty = (uint8_t)(value[4] & 0xf);
    724             ND_PRINT((ndo, " EPID: %08x Prty: %u",
    725                 EXTRACT_32BITS(value),
    726                 prty
    727             ));
    728             ND_PRINT((ndo, " Prefix: "));
    729             if ((l = print_prefix(ndo, value + 5, bodylen - 5)) < 0) {
    730                 ND_PRINT((ndo, " %s", istr));
    731                 break;
    732             }
    733             l += 5;
    734             l += -l & 3;
    735 
    736             if (bodylen >= l)
    737                 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
    738         }
    739             break;
    740 
    741         case HNCP_NODE_ADDRESS: {
    742             uint32_t endpoint_identifier;
    743             const char *ip_address;
    744             if (bodylen < 20) {
    745                 ND_PRINT((ndo, " %s", istr));
    746                 break;
    747             }
    748             endpoint_identifier = EXTRACT_32BITS(value);
    749             ip_address = format_ip6addr(ndo, value + 4);
    750             ND_PRINT((ndo, " EPID: %08x IP Address: %s",
    751                 endpoint_identifier,
    752                 ip_address
    753             ));
    754 
    755             hncp_print_rec(ndo, value + 20, bodylen - 20, indent+1);
    756         }
    757             break;
    758 
    759         case HNCP_DNS_DELEGATED_ZONE: {
    760             const char *ip_address;
    761             int len;
    762             if (bodylen < 17) {
    763                 ND_PRINT((ndo, " %s", istr));
    764                 break;
    765             }
    766             ip_address = format_ip6addr(ndo, value);
    767             ND_PRINT((ndo, " IP-Address: %s %c%c%c ",
    768                 ip_address,
    769                 (value[16] & 4) ? 'l' : '-',
    770                 (value[16] & 2) ? 'b' : '-',
    771                 (value[16] & 1) ? 's' : '-'
    772             ));
    773             len = print_dns_label(ndo, value+17, bodylen-17, 1);
    774             if (len < 0) {
    775                 ND_PRINT((ndo, " %s", istr));
    776                 break;
    777             }
    778             len += 17;
    779             len += -len & 3;
    780             if (bodylen >= len)
    781                 hncp_print_rec(ndo, value+len, bodylen-len, indent+1);
    782         }
    783             break;
    784 
    785         case HNCP_DOMAIN_NAME: {
    786             if (bodylen == 0) {
    787                 ND_PRINT((ndo, " %s", istr));
    788                 break;
    789             }
    790             ND_PRINT((ndo, " Domain: "));
    791             print_dns_label(ndo, value, bodylen, 1);
    792         }
    793             break;
    794 
    795         case HNCP_NODE_NAME: {
    796             u_int l;
    797             if (bodylen < 17) {
    798                 ND_PRINT((ndo, " %s", istr));
    799                 break;
    800             }
    801             l = value[16];
    802             if (bodylen < 17 + l) {
    803                 ND_PRINT((ndo, " %s", istr));
    804                 break;
    805             }
    806             ND_PRINT((ndo, " IP-Address: %s Name: ",
    807                 format_ip6addr(ndo, value)
    808             ));
    809             if (l < 64) {
    810                 safeputchar(ndo, '"');
    811                 safeputs(ndo, value + 17, l);
    812                 safeputchar(ndo, '"');
    813             } else {
    814                 ND_PRINT((ndo, "%s", istr));
    815             }
    816             l += 17;
    817             l += -l & 3;
    818             if (bodylen >= l)
    819                 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
    820         }
    821             break;
    822 
    823         case HNCP_MANAGED_PSK: {
    824             if (bodylen < 32) {
    825                 ND_PRINT((ndo, " %s", istr));
    826                 break;
    827             }
    828             ND_PRINT((ndo, " PSK: %s", format_256(value)));
    829             hncp_print_rec(ndo, value + 32, bodylen - 32, indent+1);
    830         }
    831             break;
    832 
    833         case RANGE_DNCP_RESERVED:
    834         case RANGE_HNCP_UNASSIGNED:
    835         case RANGE_DNCP_PRIVATE_USE:
    836         case RANGE_DNCP_FUTURE_USE:
    837             break;
    838 
    839         }
    840     skip_multiline:
    841 
    842         i += 4 + bodylen + (-bodylen & 3);
    843     }
    844     print_type_in_line(ndo, last_type_mask, last_type_count, indent, &first_one);
    845 
    846     return;
    847 
    848  trunc:
    849     ND_PRINT((ndo, "%s", "[|hncp]"));
    850     return;
    851 
    852  invalid:
    853     ND_PRINT((ndo, "%s", istr));
    854     return;
    855 }
    856