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         if (i + 2 > length)
    274             return -1;
    275         tlv = cp + i;
    276         type = (uint8_t)tlv[0];
    277         optlen = (uint8_t)tlv[1];
    278         value = tlv + 2;
    279 
    280         ND_PRINT((ndo, "\n"));
    281         for (t = indent; t > 0; t--)
    282             ND_PRINT((ndo, "\t"));
    283 
    284         ND_PRINT((ndo, "%s", tok2str(dh4opt_str, "Unknown", type)));
    285         ND_PRINT((ndo," (%u)", optlen + 2 ));
    286         if (i + 2 + optlen > length)
    287             return -1;
    288 
    289         switch (type) {
    290         case DH4OPT_DNS_SERVERS:
    291         case DH4OPT_NTP_SERVERS: {
    292             if (optlen < 4 || optlen % 4 != 0) {
    293                 return -1;
    294             }
    295             for (t = 0; t < optlen; t += 4)
    296                 ND_PRINT((ndo, " %s", ipaddr_string(ndo, value + t)));
    297         }
    298             break;
    299         case DH4OPT_DOMAIN_SEARCH: {
    300             const u_char *tp = value;
    301             while (tp < value + optlen) {
    302                 ND_PRINT((ndo, " "));
    303                 if ((tp = ns_nprint(ndo, tp, value + optlen)) == NULL)
    304                     return -1;
    305             }
    306         }
    307             break;
    308         }
    309 
    310         i += 2 + optlen;
    311     }
    312     return 0;
    313 }
    314 
    315 static int
    316 dhcpv6_print(netdissect_options *ndo,
    317              const u_char *cp, u_int length, int indent)
    318 {
    319     u_int i, t;
    320     const u_char *tlv, *value;
    321     uint16_t type, optlen;
    322 
    323     i = 0;
    324     while (i < length) {
    325         if (i + 4 > length)
    326             return -1;
    327         tlv = cp + i;
    328         type = EXTRACT_16BITS(tlv);
    329         optlen = EXTRACT_16BITS(tlv + 2);
    330         value = tlv + 4;
    331 
    332         ND_PRINT((ndo, "\n"));
    333         for (t = indent; t > 0; t--)
    334             ND_PRINT((ndo, "\t"));
    335 
    336         ND_PRINT((ndo, "%s", tok2str(dh6opt_str, "Unknown", type)));
    337         ND_PRINT((ndo," (%u)", optlen + 4 ));
    338         if (i + 4 + optlen > length)
    339             return -1;
    340 
    341         switch (type) {
    342             case DH6OPT_DNS_SERVERS:
    343             case DH6OPT_SNTP_SERVERS: {
    344                 if (optlen % 16 != 0) {
    345                     ND_PRINT((ndo, " %s", istr));
    346                     return -1;
    347                 }
    348                 for (t = 0; t < optlen; t += 16)
    349                     ND_PRINT((ndo, " %s", ip6addr_string(ndo, value + t)));
    350             }
    351                 break;
    352             case DH6OPT_DOMAIN_LIST: {
    353                 const u_char *tp = value;
    354                 while (tp < value + optlen) {
    355                     ND_PRINT((ndo, " "));
    356                     if ((tp = ns_nprint(ndo, tp, value + optlen)) == NULL)
    357                         return -1;
    358                 }
    359             }
    360                 break;
    361         }
    362 
    363         i += 4 + optlen;
    364     }
    365     return 0;
    366 }
    367 
    368 /* Determine in-line mode */
    369 static int
    370 is_in_line(netdissect_options *ndo, int indent)
    371 {
    372     return indent - 1 >= ndo->ndo_vflag && ndo->ndo_vflag < 3;
    373 }
    374 
    375 static void
    376 print_type_in_line(netdissect_options *ndo,
    377                    uint32_t type, int count, int indent, int *first_one)
    378 {
    379     if (count > 0) {
    380         if (*first_one) {
    381             *first_one = 0;
    382             if (indent > 1) {
    383                 u_int t;
    384                 ND_PRINT((ndo, "\n"));
    385                 for (t = indent; t > 0; t--)
    386                     ND_PRINT((ndo, "\t"));
    387             } else {
    388                 ND_PRINT((ndo, " "));
    389             }
    390         } else {
    391             ND_PRINT((ndo, ", "));
    392         }
    393         ND_PRINT((ndo, "%s", tok2str(type_values, "Easter Egg", type)));
    394         if (count > 1)
    395             ND_PRINT((ndo, " (x%d)", count));
    396     }
    397 }
    398 
    399 void
    400 hncp_print_rec(netdissect_options *ndo,
    401                const u_char *cp, u_int length, int indent)
    402 {
    403     const int in_line = is_in_line(ndo, indent);
    404     int first_one = 1;
    405 
    406     u_int i, t;
    407 
    408     uint32_t last_type_mask = 0xffffffffU;
    409     int last_type_count = -1;
    410 
    411     const u_char *tlv, *value;
    412     uint16_t type, bodylen;
    413     uint32_t type_mask;
    414 
    415     i = 0;
    416     while (i < length) {
    417         tlv = cp + i;
    418 
    419         if (!in_line) {
    420             ND_PRINT((ndo, "\n"));
    421             for (t = indent; t > 0; t--)
    422                 ND_PRINT((ndo, "\t"));
    423         }
    424 
    425         ND_TCHECK2(*tlv, 4);
    426         if (i + 4 > length)
    427             goto invalid;
    428 
    429         type = EXTRACT_16BITS(tlv);
    430         bodylen = EXTRACT_16BITS(tlv + 2);
    431         value = tlv + 4;
    432         ND_TCHECK2(*value, bodylen);
    433         if (i + bodylen + 4 > length)
    434             goto invalid;
    435 
    436         type_mask =
    437             (type == 0)                   ? RANGE_DNCP_RESERVED:
    438             (44 <= type && type <= 511)   ? RANGE_HNCP_UNASSIGNED:
    439             (768 <= type && type <= 1023) ? RANGE_DNCP_PRIVATE_USE:
    440                                             RANGE_DNCP_FUTURE_USE;
    441         if (type == 6 || type == 7)
    442             type_mask = RANGE_DNCP_FUTURE_USE;
    443 
    444         /* defined types */
    445         {
    446             t = 0;
    447             while (1) {
    448                 u_int key = type_values[t++].v;
    449                 if (key > 0xffff)
    450                     break;
    451                 if (key == type) {
    452                     type_mask = type;
    453                     break;
    454                 }
    455             }
    456         }
    457 
    458         if (in_line) {
    459             if (last_type_mask == type_mask) {
    460                 last_type_count++;
    461             } else {
    462                 print_type_in_line(ndo, last_type_mask, last_type_count, indent, &first_one);
    463                 last_type_mask = type_mask;
    464                 last_type_count = 1;
    465             }
    466 
    467             goto skip_multiline;
    468         }
    469 
    470         ND_PRINT((ndo,"%s", tok2str(type_values, "Easter Egg (42)", type_mask) ));
    471         if (type_mask > 0xffff)
    472             ND_PRINT((ndo,": type=%u", type ));
    473         ND_PRINT((ndo," (%u)", bodylen + 4 ));
    474 
    475         switch (type_mask) {
    476 
    477         case DNCP_REQUEST_NETWORK_STATE: {
    478             if (bodylen != 0)
    479                 ND_PRINT((ndo, " %s", istr));
    480         }
    481             break;
    482 
    483         case DNCP_REQUEST_NODE_STATE: {
    484             const char *node_identifier;
    485             if (bodylen != 4) {
    486                 ND_PRINT((ndo, " %s", istr));
    487                 break;
    488             }
    489             node_identifier = format_nid(value);
    490             ND_PRINT((ndo, " NID: %s", node_identifier));
    491         }
    492             break;
    493 
    494         case DNCP_NODE_ENDPOINT: {
    495             const char *node_identifier;
    496             uint32_t endpoint_identifier;
    497             if (bodylen != 8) {
    498                 ND_PRINT((ndo, " %s", istr));
    499                 break;
    500             }
    501             node_identifier = format_nid(value);
    502             endpoint_identifier = EXTRACT_32BITS(value + 4);
    503             ND_PRINT((ndo, " NID: %s EPID: %08x",
    504                 node_identifier,
    505                 endpoint_identifier
    506             ));
    507         }
    508             break;
    509 
    510         case DNCP_NETWORK_STATE: {
    511             uint64_t hash;
    512             if (bodylen != 8) {
    513                 ND_PRINT((ndo, " %s", istr));
    514                 break;
    515             }
    516             hash = EXTRACT_64BITS(value);
    517             ND_PRINT((ndo, " hash: %016" PRIx64, hash));
    518         }
    519             break;
    520 
    521         case DNCP_NODE_STATE: {
    522             const char *node_identifier, *interval;
    523             uint32_t sequence_number;
    524             uint64_t hash;
    525             if (bodylen < 20) {
    526                 ND_PRINT((ndo, " %s", istr));
    527                 break;
    528             }
    529             node_identifier = format_nid(value);
    530             sequence_number = EXTRACT_32BITS(value + 4);
    531             interval = format_interval(EXTRACT_32BITS(value + 8));
    532             hash = EXTRACT_64BITS(value + 12);
    533             ND_PRINT((ndo, " NID: %s seqno: %u %s hash: %016" PRIx64,
    534                 node_identifier,
    535                 sequence_number,
    536                 interval,
    537                 hash
    538             ));
    539             hncp_print_rec(ndo, value+20, bodylen-20, indent+1);
    540         }
    541             break;
    542 
    543         case DNCP_PEER: {
    544             const char *peer_node_identifier;
    545             uint32_t peer_endpoint_identifier, endpoint_identifier;
    546             if (bodylen != 12) {
    547                 ND_PRINT((ndo, " %s", istr));
    548                 break;
    549             }
    550             peer_node_identifier = format_nid(value);
    551             peer_endpoint_identifier = EXTRACT_32BITS(value + 4);
    552             endpoint_identifier = EXTRACT_32BITS(value + 8);
    553             ND_PRINT((ndo, " Peer-NID: %s Peer-EPID: %08x Local-EPID: %08x",
    554                 peer_node_identifier,
    555                 peer_endpoint_identifier,
    556                 endpoint_identifier
    557             ));
    558         }
    559             break;
    560 
    561         case DNCP_KEEP_ALIVE_INTERVAL: {
    562             uint32_t endpoint_identifier;
    563             const char *interval;
    564             if (bodylen < 8) {
    565                 ND_PRINT((ndo, " %s", istr));
    566                 break;
    567             }
    568             endpoint_identifier = EXTRACT_32BITS(value);
    569             interval = format_interval(EXTRACT_32BITS(value + 4));
    570             ND_PRINT((ndo, " EPID: %08x Interval: %s",
    571                 endpoint_identifier,
    572                 interval
    573             ));
    574         }
    575             break;
    576 
    577         case DNCP_TRUST_VERDICT: {
    578             if (bodylen <= 36) {
    579                 ND_PRINT((ndo, " %s", istr));
    580                 break;
    581             }
    582             ND_PRINT((ndo, " Verdict: %u Fingerprint: %s Common Name: ",
    583                 *value,
    584                 format_256(value + 4)));
    585             safeputs(ndo, value + 36, bodylen - 36);
    586         }
    587             break;
    588 
    589         case HNCP_HNCP_VERSION: {
    590             uint16_t capabilities;
    591             uint8_t M, P, H, L;
    592             if (bodylen < 5) {
    593                 ND_PRINT((ndo, " %s", istr));
    594                 break;
    595             }
    596             capabilities = EXTRACT_16BITS(value + 2);
    597             M = (uint8_t)((capabilities >> 12) & 0xf);
    598             P = (uint8_t)((capabilities >> 8) & 0xf);
    599             H = (uint8_t)((capabilities >> 4) & 0xf);
    600             L = (uint8_t)(capabilities & 0xf);
    601             ND_PRINT((ndo, " M: %u P: %u H: %u L: %u User-agent: ",
    602                 M, P, H, L
    603             ));
    604             safeputs(ndo, value + 4, bodylen - 4);
    605         }
    606             break;
    607 
    608         case HNCP_EXTERNAL_CONNECTION: {
    609             /* Container TLV */
    610             hncp_print_rec(ndo, value, bodylen, indent+1);
    611         }
    612             break;
    613 
    614         case HNCP_DELEGATED_PREFIX: {
    615             int l;
    616             if (bodylen < 9 || bodylen < 9 + (value[8] + 7) / 8) {
    617                 ND_PRINT((ndo, " %s", istr));
    618                 break;
    619             }
    620             ND_PRINT((ndo, " VLSO: %s PLSO: %s Prefix: ",
    621                 format_interval(EXTRACT_32BITS(value)),
    622                 format_interval(EXTRACT_32BITS(value + 4))
    623             ));
    624             l = print_prefix(ndo, value + 8, bodylen - 8);
    625             if (l == -1) {
    626                 ND_PRINT((ndo, "(length is invalid)"));
    627                 break;
    628             }
    629             if (l < 0) {
    630                 /*
    631                  * We've already checked that we've captured the
    632                  * entire TLV, based on its length, so this will
    633                  * either be -1, meaning "the prefix length is
    634                  * greater than the longest possible address of
    635                  * that type" (i.e., > 32 for IPv4 or > 128 for
    636                  * IPv6", or -3, meaning "the prefix runs past
    637                  * the end of the TLV".
    638                  */
    639                 ND_PRINT((ndo, " %s", istr));
    640                 break;
    641             }
    642             l += 8 + (-l & 3);
    643 
    644             if (bodylen >= l)
    645                 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
    646         }
    647             break;
    648 
    649         case HNCP_PREFIX_POLICY: {
    650             uint8_t policy;
    651             int l;
    652             if (bodylen < 1) {
    653                 ND_PRINT((ndo, " %s", istr));
    654                 break;
    655             }
    656             policy = value[0];
    657             ND_PRINT((ndo, " type: "));
    658             if (policy == 0) {
    659                 if (bodylen != 1) {
    660                     ND_PRINT((ndo, " %s", istr));
    661                     break;
    662                 }
    663                 ND_PRINT((ndo, "Internet connectivity"));
    664             } else if (policy >= 1 && policy <= 128) {
    665                 ND_PRINT((ndo, "Dest-Prefix: "));
    666                 l = print_prefix(ndo, value, bodylen);
    667                 if (l == -1) {
    668                     ND_PRINT((ndo, "(length is invalid)"));
    669                     break;
    670                 }
    671                 if (l < 0) {
    672                     /*
    673                      * We've already checked that we've captured the
    674                      * entire TLV, based on its length, so this will
    675                      * either be -1, meaning "the prefix length is
    676                      * greater than the longest possible address of
    677                      * that type" (i.e., > 32 for IPv4 or > 128 for
    678                      * IPv6", or -3, meaning "the prefix runs past
    679                      * the end of the TLV".
    680                      */
    681                     ND_PRINT((ndo, " %s", istr));
    682                     break;
    683                 }
    684             } else if (policy == 129) {
    685                 ND_PRINT((ndo, "DNS domain: "));
    686                 print_dns_label(ndo, value+1, bodylen-1, 1);
    687             } else if (policy == 130) {
    688                 ND_PRINT((ndo, "Opaque UTF-8: "));
    689                 safeputs(ndo, value + 1, bodylen - 1);
    690             } else if (policy == 131) {
    691                 if (bodylen != 1) {
    692                     ND_PRINT((ndo, " %s", istr));
    693                     break;
    694                 }
    695                 ND_PRINT((ndo, "Restrictive assignment"));
    696             } else if (policy >= 132) {
    697                 ND_PRINT((ndo, "Unknown (%u)", policy)); /* Reserved for future additions */
    698             }
    699         }
    700             break;
    701 
    702         case HNCP_DHCPV4_DATA: {
    703             if (bodylen == 0) {
    704                 ND_PRINT((ndo, " %s", istr));
    705                 break;
    706             }
    707             if (dhcpv4_print(ndo, value, bodylen, indent+1) != 0)
    708                 goto invalid;
    709         }
    710             break;
    711 
    712         case HNCP_DHCPV6_DATA: {
    713             if (bodylen == 0) {
    714                 ND_PRINT((ndo, " %s", istr));
    715                 break;
    716             }
    717             if (dhcpv6_print(ndo, value, bodylen, indent+1) != 0) {
    718                 ND_PRINT((ndo, " %s", istr));
    719                 break;
    720             }
    721         }
    722             break;
    723 
    724         case HNCP_ASSIGNED_PREFIX: {
    725             uint8_t prty;
    726             int l;
    727             if (bodylen < 6 || bodylen < 6 + (value[5] + 7) / 8) {
    728                 ND_PRINT((ndo, " %s", istr));
    729                 break;
    730             }
    731             prty = (uint8_t)(value[4] & 0xf);
    732             ND_PRINT((ndo, " EPID: %08x Prty: %u",
    733                 EXTRACT_32BITS(value),
    734                 prty
    735             ));
    736             ND_PRINT((ndo, " Prefix: "));
    737             if ((l = print_prefix(ndo, value + 5, bodylen - 5)) < 0) {
    738                 ND_PRINT((ndo, " %s", istr));
    739                 break;
    740             }
    741             l += 5;
    742             l += -l & 3;
    743 
    744             if (bodylen >= l)
    745                 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
    746         }
    747             break;
    748 
    749         case HNCP_NODE_ADDRESS: {
    750             uint32_t endpoint_identifier;
    751             const char *ip_address;
    752             if (bodylen < 20) {
    753                 ND_PRINT((ndo, " %s", istr));
    754                 break;
    755             }
    756             endpoint_identifier = EXTRACT_32BITS(value);
    757             ip_address = format_ip6addr(ndo, value + 4);
    758             ND_PRINT((ndo, " EPID: %08x IP Address: %s",
    759                 endpoint_identifier,
    760                 ip_address
    761             ));
    762 
    763             hncp_print_rec(ndo, value + 20, bodylen - 20, indent+1);
    764         }
    765             break;
    766 
    767         case HNCP_DNS_DELEGATED_ZONE: {
    768             const char *ip_address;
    769             int len;
    770             if (bodylen < 17) {
    771                 ND_PRINT((ndo, " %s", istr));
    772                 break;
    773             }
    774             ip_address = format_ip6addr(ndo, value);
    775             ND_PRINT((ndo, " IP-Address: %s %c%c%c ",
    776                 ip_address,
    777                 (value[16] & 4) ? 'l' : '-',
    778                 (value[16] & 2) ? 'b' : '-',
    779                 (value[16] & 1) ? 's' : '-'
    780             ));
    781             len = print_dns_label(ndo, value+17, bodylen-17, 1);
    782             if (len < 0) {
    783                 ND_PRINT((ndo, " %s", istr));
    784                 break;
    785             }
    786             len += 17;
    787             len += -len & 3;
    788             if (bodylen >= len)
    789                 hncp_print_rec(ndo, value+len, bodylen-len, indent+1);
    790         }
    791             break;
    792 
    793         case HNCP_DOMAIN_NAME: {
    794             if (bodylen == 0) {
    795                 ND_PRINT((ndo, " %s", istr));
    796                 break;
    797             }
    798             ND_PRINT((ndo, " Domain: "));
    799             print_dns_label(ndo, value, bodylen, 1);
    800         }
    801             break;
    802 
    803         case HNCP_NODE_NAME: {
    804             u_int l;
    805             if (bodylen < 17) {
    806                 ND_PRINT((ndo, " %s", istr));
    807                 break;
    808             }
    809             l = value[16];
    810             if (bodylen < 17 + l) {
    811                 ND_PRINT((ndo, " %s", istr));
    812                 break;
    813             }
    814             ND_PRINT((ndo, " IP-Address: %s Name: ",
    815                 format_ip6addr(ndo, value)
    816             ));
    817             if (l < 64) {
    818                 safeputchar(ndo, '"');
    819                 safeputs(ndo, value + 17, l);
    820                 safeputchar(ndo, '"');
    821             } else {
    822                 ND_PRINT((ndo, "%s", istr));
    823             }
    824             l += 17;
    825             l += -l & 3;
    826             if (bodylen >= l)
    827                 hncp_print_rec(ndo, value + l, bodylen - l, indent+1);
    828         }
    829             break;
    830 
    831         case HNCP_MANAGED_PSK: {
    832             if (bodylen < 32) {
    833                 ND_PRINT((ndo, " %s", istr));
    834                 break;
    835             }
    836             ND_PRINT((ndo, " PSK: %s", format_256(value)));
    837             hncp_print_rec(ndo, value + 32, bodylen - 32, indent+1);
    838         }
    839             break;
    840 
    841         case RANGE_DNCP_RESERVED:
    842         case RANGE_HNCP_UNASSIGNED:
    843         case RANGE_DNCP_PRIVATE_USE:
    844         case RANGE_DNCP_FUTURE_USE:
    845             break;
    846 
    847         }
    848     skip_multiline:
    849 
    850         i += 4 + bodylen + (-bodylen & 3);
    851     }
    852     print_type_in_line(ndo, last_type_mask, last_type_count, indent, &first_one);
    853 
    854     return;
    855 
    856  trunc:
    857     ND_PRINT((ndo, "%s", "[|hncp]"));
    858     return;
    859 
    860  invalid:
    861     ND_PRINT((ndo, "%s", istr));
    862     return;
    863 }
    864