print-icmp6.c revision 229244
156893Sfenner/* 256893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 356893Sfenner * The Regents of the University of California. All rights reserved. 456893Sfenner * 556893Sfenner * Redistribution and use in source and binary forms, with or without 656893Sfenner * modification, are permitted provided that: (1) source code distributions 756893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2) 856893Sfenner * distributions including binary code include the above copyright notice and 956893Sfenner * this paragraph in its entirety in the documentation or other materials 1056893Sfenner * provided with the distribution, and (3) all advertising materials mentioning 1156893Sfenner * features or use of this software display the following acknowledgement: 1256893Sfenner * ``This product includes software developed by the University of California, 1356893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 1456893Sfenner * the University nor the names of its contributors may be used to endorse 1556893Sfenner * or promote products derived from this software without specific prior 1656893Sfenner * written permission. 1756893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 1856893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 1956893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2056893Sfenner */ 2156893Sfenner 2256893Sfenner#ifndef lint 23127668Sbmsstatic const char rcsid[] _U_ = 24214478Srpaulo "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp $"; 2556893Sfenner#endif 2656893Sfenner 2756893Sfenner#ifdef HAVE_CONFIG_H 2856893Sfenner#include "config.h" 2956893Sfenner#endif 3056893Sfenner 3156893Sfenner#ifdef INET6 3256893Sfenner 33127668Sbms#include <tcpdump-stdinc.h> 3456893Sfenner 3556893Sfenner#include <stdio.h> 3698524Sfenner#include <string.h> 3756893Sfenner 38147899Ssam#include "interface.h" 39147899Ssam#include "addrtoname.h" 40147899Ssam#include "extract.h" 41147899Ssam 4275115Sfenner#include "ip6.h" 4375115Sfenner#include "icmp6.h" 44127668Sbms#include "ipproto.h" 4556893Sfenner 4675115Sfenner#include "udp.h" 4775115Sfenner#include "ah.h" 4875115Sfenner 4998524Sfennerstatic const char *get_rtpref(u_int); 5098524Sfennerstatic const char *get_lifetime(u_int32_t); 5198524Sfennerstatic void print_lladdr(const u_char *, size_t); 52127668Sbmsstatic void icmp6_opt_print(const u_char *, int); 53127668Sbmsstatic void mld6_print(const u_char *); 54146773Ssamstatic void mldv2_report_print(const u_char *, u_int); 55146773Ssamstatic void mldv2_query_print(const u_char *, u_int); 56127668Sbmsstatic struct udphdr *get_upperlayer(u_char *, u_int *); 5775115Sfennerstatic void dnsname_print(const u_char *, const u_char *); 58127668Sbmsstatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 59127668Sbmsstatic void icmp6_rrenum_print(const u_char *, const u_char *); 6056893Sfenner 6175115Sfenner#ifndef abs 6275115Sfenner#define abs(a) ((0 < (a)) ? (a) : -(a)) 6375115Sfenner#endif 6475115Sfenner 65214478Srpaulo/* inline the various RPL definitions */ 66214478Srpaulo#define ND_RPL_MESSAGE 0x9B 67214478Srpaulo 68146773Ssamstatic struct tok icmp6_type_values[] = { 69146773Ssam { ICMP6_DST_UNREACH, "destination unreachable"}, 70146773Ssam { ICMP6_PACKET_TOO_BIG, "packet too big"}, 71146773Ssam { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 72146773Ssam { ICMP6_PARAM_PROB, "parameter problem"}, 73146773Ssam { ICMP6_ECHO_REQUEST, "echo request"}, 74146773Ssam { ICMP6_ECHO_REPLY, "echo reply"}, 75147899Ssam { MLD6_LISTENER_QUERY, "multicast listener query"}, 76147899Ssam { MLD6_LISTENER_REPORT, "multicast listener report"}, 77147899Ssam { MLD6_LISTENER_DONE, "multicast listener done"}, 78147899Ssam { ND_ROUTER_SOLICIT, "router solicitation"}, 79146773Ssam { ND_ROUTER_ADVERT, "router advertisement"}, 80146773Ssam { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 81162017Ssam { ND_NEIGHBOR_ADVERT, "neighbor advertisement"}, 82146773Ssam { ND_REDIRECT, "redirect"}, 83146773Ssam { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 84146773Ssam { IND_SOLICIT, "inverse neighbor solicitation"}, 85146773Ssam { IND_ADVERT, "inverse neighbor advertisement"}, 86147899Ssam { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, 87146773Ssam { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 88146773Ssam { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 89146773Ssam { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 90146773Ssam { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 91146773Ssam { ICMP6_WRUREQUEST, "who-are-you request"}, 92146773Ssam { ICMP6_WRUREPLY, "who-are-you reply"}, 93146773Ssam { ICMP6_NI_QUERY, "node information query"}, 94146773Ssam { ICMP6_NI_REPLY, "node information reply"}, 95146773Ssam { MLD6_MTRACE, "mtrace message"}, 96146773Ssam { MLD6_MTRACE_RESP, "mtrace response"}, 97214478Srpaulo { ND_RPL_MESSAGE, "RPL"}, 98146773Ssam { 0, NULL } 99146773Ssam}; 100146773Ssam 101146773Ssamstatic struct tok icmp6_dst_unreach_code_values[] = { 102146773Ssam { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 103146773Ssam { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 104146773Ssam { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 105146773Ssam { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 106146773Ssam { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 107146773Ssam { 0, NULL } 108146773Ssam}; 109146773Ssam 110146773Ssamstatic struct tok icmp6_opt_pi_flag_values[] = { 111146773Ssam { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 112146773Ssam { ND_OPT_PI_FLAG_AUTO, "auto" }, 113146773Ssam { ND_OPT_PI_FLAG_ROUTER, "router" }, 114146773Ssam { 0, NULL } 115146773Ssam}; 116146773Ssam 117146773Ssamstatic struct tok icmp6_opt_ra_flag_values[] = { 118146773Ssam { ND_RA_FLAG_MANAGED, "managed" }, 119146773Ssam { ND_RA_FLAG_OTHER, "other stateful"}, 120146773Ssam { ND_RA_FLAG_HOME_AGENT, "home agent"}, 121146773Ssam { 0, NULL } 122146773Ssam}; 123146773Ssam 124146773Ssamstatic struct tok icmp6_nd_na_flag_values[] = { 125146773Ssam { ND_NA_FLAG_ROUTER, "router" }, 126146773Ssam { ND_NA_FLAG_SOLICITED, "solicited" }, 127146773Ssam { ND_NA_FLAG_OVERRIDE, "override" }, 128146773Ssam { 0, NULL } 129146773Ssam}; 130146773Ssam 131146773Ssam 132146773Ssamstatic struct tok icmp6_opt_values[] = { 133146773Ssam { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 134146773Ssam { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 135146773Ssam { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 136146773Ssam { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 137146773Ssam { ND_OPT_MTU, "mtu"}, 138214478Srpaulo { ND_OPT_RDNSS, "rdnss"}, 139162017Ssam { ND_OPT_ADVINTERVAL, "advertisement interval"}, 140146773Ssam { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 141146773Ssam { ND_OPT_ROUTE_INFO, "route info"}, 142146773Ssam { 0, NULL } 143146773Ssam}; 144146773Ssam 145146773Ssam/* mldv2 report types */ 146146773Ssamstatic struct tok mldv2report2str[] = { 147146773Ssam { 1, "is_in" }, 148146773Ssam { 2, "is_ex" }, 149146773Ssam { 3, "to_in" }, 150146773Ssam { 4, "to_ex" }, 151146773Ssam { 5, "allow" }, 152146773Ssam { 6, "block" }, 153146773Ssam { 0, NULL } 154146773Ssam}; 155146773Ssam 15698524Sfennerstatic const char * 15798524Sfennerget_rtpref(u_int v) 15898524Sfenner{ 15998524Sfenner static const char *rtpref_str[] = { 16098524Sfenner "medium", /* 00 */ 16198524Sfenner "high", /* 01 */ 16298524Sfenner "rsv", /* 10 */ 16398524Sfenner "low" /* 11 */ 16498524Sfenner }; 16598524Sfenner 16698524Sfenner return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 16798524Sfenner} 16898524Sfenner 16998524Sfennerstatic const char * 17098524Sfennerget_lifetime(u_int32_t v) 17198524Sfenner{ 17298524Sfenner static char buf[20]; 17398524Sfenner 17498524Sfenner if (v == (u_int32_t)~0UL) 17598524Sfenner return "infinity"; 17698524Sfenner else { 17798524Sfenner snprintf(buf, sizeof(buf), "%u", v); 17898524Sfenner return buf; 17998524Sfenner } 18098524Sfenner} 18198524Sfenner 18298524Sfennerstatic void 18398524Sfennerprint_lladdr(const u_int8_t *p, size_t l) 18498524Sfenner{ 18598524Sfenner const u_int8_t *ep, *q; 18698524Sfenner 18798524Sfenner q = p; 18898524Sfenner ep = p + l; 18998524Sfenner while (l > 0 && q < ep) { 19098524Sfenner if (q > p) 19198524Sfenner printf(":"); 19298524Sfenner printf("%02x", *q++); 19398524Sfenner l--; 19498524Sfenner } 19598524Sfenner} 19698524Sfenner 197127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 198127668Sbms u_int len) 199127668Sbms{ 200127668Sbms size_t i; 201127668Sbms register const u_int16_t *sp; 202127668Sbms u_int32_t sum; 203127668Sbms union { 204127668Sbms struct { 205127668Sbms struct in6_addr ph_src; 206127668Sbms struct in6_addr ph_dst; 207127668Sbms u_int32_t ph_len; 208127668Sbms u_int8_t ph_zero[3]; 209127668Sbms u_int8_t ph_nxt; 210127668Sbms } ph; 211127668Sbms u_int16_t pa[20]; 212127668Sbms } phu; 213127668Sbms 214127668Sbms /* pseudo-header */ 215127668Sbms memset(&phu, 0, sizeof(phu)); 216127668Sbms phu.ph.ph_src = ip6->ip6_src; 217127668Sbms phu.ph.ph_dst = ip6->ip6_dst; 218127668Sbms phu.ph.ph_len = htonl(len); 219127668Sbms phu.ph.ph_nxt = IPPROTO_ICMPV6; 220127668Sbms 221127668Sbms sum = 0; 222127668Sbms for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 223127668Sbms sum += phu.pa[i]; 224127668Sbms 225127668Sbms sp = (const u_int16_t *)icp; 226127668Sbms 227127668Sbms for (i = 0; i < (len & ~1); i += 2) 228127668Sbms sum += *sp++; 229127668Sbms 230127668Sbms if (len & 1) 231127668Sbms sum += htons((*(const u_int8_t *)sp) << 8); 232127668Sbms 233127668Sbms while (sum > 0xffff) 234127668Sbms sum = (sum & 0xffff) + (sum >> 16); 235127668Sbms sum = ~sum & 0xffff; 236127668Sbms 237127668Sbms return (sum); 238127668Sbms} 239127668Sbms 240214478Srpauloenum ND_RPL_CODE { 241214478Srpaulo ND_RPL_DAG_IS=0x01, 242214478Srpaulo ND_RPL_DAG_IO=0x02, 243214478Srpaulo ND_RPL_DAO =0x04 244214478Srpaulo}; 245214478Srpaulo 246214478Srpauloenum ND_RPL_DIO_FLAGS { 247214478Srpaulo ND_RPL_DIO_GROUNDED = 0x80, 248214478Srpaulo ND_RPL_DIO_DATRIG = 0x40, 249214478Srpaulo ND_RPL_DIO_DASUPPORT= 0x20, 250214478Srpaulo ND_RPL_DIO_RES4 = 0x10, 251214478Srpaulo ND_RPL_DIO_RES3 = 0x08, 252214478Srpaulo ND_RPL_DIO_PRF_MASK = 0x07, /* 3-bit preference */ 253214478Srpaulo}; 254214478Srpaulo 255214478Srpaulostruct nd_rpl_dio { 256214478Srpaulo u_int8_t rpl_flags; 257214478Srpaulo u_int8_t rpl_seq; 258214478Srpaulo u_int8_t rpl_instanceid; 259214478Srpaulo u_int8_t rpl_dagrank; 260214478Srpaulo u_int8_t rpl_dagid[16]; 261214478Srpaulo}; 262214478Srpaulo 263214478Srpaulostatic void 264214478Srpaulorpl_print(netdissect_options *ndo, 265214478Srpaulo const struct icmp6_hdr *hdr, 266214478Srpaulo const u_char *bp, u_int length _U_) 267214478Srpaulo{ 268214478Srpaulo struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp; 269214478Srpaulo 270214478Srpaulo ND_TCHECK(dio->rpl_dagid); 271214478Srpaulo 272214478Srpaulo switch(hdr->icmp6_code) { 273214478Srpaulo case ND_RPL_DAG_IS: 274214478Srpaulo ND_PRINT((ndo, ", DAG Information Solicitation")); 275214478Srpaulo if(ndo->ndo_vflag) { 276214478Srpaulo } 277214478Srpaulo break; 278214478Srpaulo case ND_RPL_DAG_IO: 279214478Srpaulo ND_PRINT((ndo, ", DAG Information Object")); 280214478Srpaulo if(ndo->ndo_vflag) { 281214478Srpaulo char dagid[65]; 282214478Srpaulo char *d = dagid; 283214478Srpaulo int i; 284214478Srpaulo for(i=0;i<16;i++) { 285214478Srpaulo if(isprint(dio->rpl_dagid[i])) { 286214478Srpaulo *d++ = dio->rpl_dagid[i]; 287214478Srpaulo } else { 288214478Srpaulo int cnt=snprintf(d,4,"0x%02x", 289214478Srpaulo dio->rpl_dagid[i]); 290214478Srpaulo d += cnt; 291214478Srpaulo } 292214478Srpaulo } 293214478Srpaulo *d++ = '\0'; 294214478Srpaulo ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]", 295214478Srpaulo dio->rpl_seq, 296214478Srpaulo dio->rpl_instanceid, 297214478Srpaulo dio->rpl_dagrank, 298214478Srpaulo dagid)); 299214478Srpaulo } 300214478Srpaulo break; 301214478Srpaulo case ND_RPL_DAO: 302214478Srpaulo ND_PRINT((ndo, ", Destination Advertisement Object")); 303214478Srpaulo if(ndo->ndo_vflag) { 304214478Srpaulo } 305214478Srpaulo break; 306214478Srpaulo default: 307214478Srpaulo ND_PRINT((ndo, ", RPL message, unknown code %u",hdr->icmp6_code)); 308214478Srpaulo break; 309214478Srpaulo } 310214478Srpaulo return; 311214478Srpaulotrunc: 312214478Srpaulo ND_PRINT((ndo," [|truncated]")); 313214478Srpaulo return; 314214478Srpaulo 315214478Srpaulo} 316214478Srpaulo 317214478Srpaulo 31856893Sfennervoid 319214478Srpauloicmp6_print(netdissect_options *ndo, 320214478Srpaulo const u_char *bp, u_int length, const u_char *bp2, int fragmented) 32156893Sfenner{ 32275115Sfenner const struct icmp6_hdr *dp; 32398524Sfenner const struct ip6_hdr *ip; 32498524Sfenner const struct ip6_hdr *oip; 32598524Sfenner const struct udphdr *ouh; 32698524Sfenner int dport; 32798524Sfenner const u_char *ep; 328127668Sbms u_int prot; 32956893Sfenner 33056893Sfenner dp = (struct icmp6_hdr *)bp; 33156893Sfenner ip = (struct ip6_hdr *)bp2; 33256893Sfenner oip = (struct ip6_hdr *)(dp + 1); 33375115Sfenner /* 'ep' points to the end of available data. */ 33456893Sfenner ep = snapend; 33556893Sfenner 336127668Sbms TCHECK(dp->icmp6_cksum); 337127668Sbms 338127668Sbms if (vflag && !fragmented) { 339127668Sbms int sum = dp->icmp6_cksum; 340127668Sbms 341127668Sbms if (TTEST2(bp[0], length)) { 342127668Sbms sum = icmp6_cksum(ip, dp, length); 343127668Sbms if (sum != 0) 344127668Sbms (void)printf("[bad icmp6 cksum %x!] ", sum); 345127668Sbms else 346127668Sbms (void)printf("[icmp6 sum ok] "); 347127668Sbms } 348127668Sbms } 349127668Sbms 350146773Ssam printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 351146773Ssam 352146773Ssam /* display cosmetics: print the packet length for printer that use the vflag now */ 353229244Sdim if (vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT || 354229244Sdim dp->icmp6_type == ND_ROUTER_ADVERT || 355229244Sdim dp->icmp6_type == ND_NEIGHBOR_ADVERT || 356229244Sdim dp->icmp6_type == ND_NEIGHBOR_SOLICIT || 357229244Sdim dp->icmp6_type == ND_REDIRECT || 358229244Sdim dp->icmp6_type == ICMP6_HADISCOV_REPLY || 359229244Sdim dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT )) 360146773Ssam printf(", length %u", length); 361146773Ssam 36275115Sfenner switch (dp->icmp6_type) { 36356893Sfenner case ICMP6_DST_UNREACH: 36456893Sfenner TCHECK(oip->ip6_dst); 365146773Ssam printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 36656893Sfenner switch (dp->icmp6_code) { 367146773Ssam 368146773Ssam case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 36956893Sfenner case ICMP6_DST_UNREACH_ADMIN: 370146773Ssam case ICMP6_DST_UNREACH_ADDR: 371146773Ssam printf(" %s",ip6addr_string(&oip->ip6_dst)); 372146773Ssam break; 37356893Sfenner case ICMP6_DST_UNREACH_BEYONDSCOPE: 374146773Ssam printf(" %s, source address %s", 37556893Sfenner ip6addr_string(&oip->ip6_dst), 37656893Sfenner ip6addr_string(&oip->ip6_src)); 37756893Sfenner break; 37856893Sfenner case ICMP6_DST_UNREACH_NOPORT: 37975115Sfenner if ((ouh = get_upperlayer((u_char *)oip, &prot)) 38075115Sfenner == NULL) 38175115Sfenner goto trunc; 38275115Sfenner 383127668Sbms dport = EXTRACT_16BITS(&ouh->uh_dport); 38475115Sfenner switch (prot) { 38556893Sfenner case IPPROTO_TCP: 386146773Ssam printf(", %s tcp port %s", 38756893Sfenner ip6addr_string(&oip->ip6_dst), 38856893Sfenner tcpport_string(dport)); 38956893Sfenner break; 39056893Sfenner case IPPROTO_UDP: 391146773Ssam printf(", %s udp port %s", 39256893Sfenner ip6addr_string(&oip->ip6_dst), 39356893Sfenner udpport_string(dport)); 39456893Sfenner break; 39556893Sfenner default: 396146773Ssam printf(", %s protocol %d port %d unreachable", 39756893Sfenner ip6addr_string(&oip->ip6_dst), 39856893Sfenner oip->ip6_nxt, dport); 39956893Sfenner break; 40056893Sfenner } 40156893Sfenner break; 40256893Sfenner default: 403146773Ssam if (vflag <= 1) { 404146773Ssam print_unknown_data(bp,"\n\t",length); 405146773Ssam return; 406146773Ssam } 407146773Ssam break; 40856893Sfenner } 40956893Sfenner break; 41056893Sfenner case ICMP6_PACKET_TOO_BIG: 41156893Sfenner TCHECK(dp->icmp6_mtu); 412146773Ssam printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 41356893Sfenner break; 41456893Sfenner case ICMP6_TIME_EXCEEDED: 41556893Sfenner TCHECK(oip->ip6_dst); 41656893Sfenner switch (dp->icmp6_code) { 41756893Sfenner case ICMP6_TIME_EXCEED_TRANSIT: 418146773Ssam printf(" for %s", 41956893Sfenner ip6addr_string(&oip->ip6_dst)); 42056893Sfenner break; 42156893Sfenner case ICMP6_TIME_EXCEED_REASSEMBLY: 422146773Ssam printf(" (reassembly)"); 42356893Sfenner break; 42456893Sfenner default: 425146773Ssam printf(", unknown code (%u)", dp->icmp6_code); 42656893Sfenner break; 42756893Sfenner } 42856893Sfenner break; 42956893Sfenner case ICMP6_PARAM_PROB: 43056893Sfenner TCHECK(oip->ip6_dst); 43156893Sfenner switch (dp->icmp6_code) { 43256893Sfenner case ICMP6_PARAMPROB_HEADER: 433146773Ssam printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 43456893Sfenner break; 43556893Sfenner case ICMP6_PARAMPROB_NEXTHEADER: 436146773Ssam printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 43756893Sfenner break; 43856893Sfenner case ICMP6_PARAMPROB_OPTION: 439146773Ssam printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 44056893Sfenner break; 44156893Sfenner default: 442146773Ssam printf(", code-#%d", 44356893Sfenner dp->icmp6_code); 44456893Sfenner break; 44556893Sfenner } 44656893Sfenner break; 44756893Sfenner case ICMP6_ECHO_REQUEST: 44856893Sfenner case ICMP6_ECHO_REPLY: 449127668Sbms TCHECK(dp->icmp6_seq); 450146773Ssam printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 45156893Sfenner break; 45256893Sfenner case ICMP6_MEMBERSHIP_QUERY: 453146773Ssam if (length == MLD_MINLEN) { 454146773Ssam mld6_print((const u_char *)dp); 455146773Ssam } else if (length >= MLDV2_MINLEN) { 456146773Ssam printf("v2 "); 457146773Ssam mldv2_query_print((const u_char *)dp, length); 458146773Ssam } else { 459146773Ssam printf(" unknown-version (len %u) ", length); 460146773Ssam } 46156893Sfenner break; 46256893Sfenner case ICMP6_MEMBERSHIP_REPORT: 46356893Sfenner mld6_print((const u_char *)dp); 46456893Sfenner break; 46556893Sfenner case ICMP6_MEMBERSHIP_REDUCTION: 46656893Sfenner mld6_print((const u_char *)dp); 46756893Sfenner break; 46856893Sfenner case ND_ROUTER_SOLICIT: 469146773Ssam#define RTSOLLEN 8 47056893Sfenner if (vflag) { 47175115Sfenner icmp6_opt_print((const u_char *)dp + RTSOLLEN, 472127668Sbms length - RTSOLLEN); 47356893Sfenner } 47456893Sfenner break; 47556893Sfenner case ND_ROUTER_ADVERT: 476146773Ssam#define RTADVLEN 16 47756893Sfenner if (vflag) { 47856893Sfenner struct nd_router_advert *p; 47956893Sfenner 48056893Sfenner p = (struct nd_router_advert *)dp; 48156893Sfenner TCHECK(p->nd_ra_retransmit); 482146773Ssam printf("\n\thop limit %u, Flags [%s]" \ 483146773Ssam ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 484146773Ssam (u_int)p->nd_ra_curhoplimit, 485146773Ssam bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 486146773Ssam get_rtpref(p->nd_ra_flags_reserved), 487146773Ssam EXTRACT_16BITS(&p->nd_ra_router_lifetime), 488146773Ssam EXTRACT_32BITS(&p->nd_ra_reachable), 489146773Ssam EXTRACT_32BITS(&p->nd_ra_retransmit)); 49098524Sfenner 49175115Sfenner icmp6_opt_print((const u_char *)dp + RTADVLEN, 492127668Sbms length - RTADVLEN); 49356893Sfenner } 49456893Sfenner break; 49556893Sfenner case ND_NEIGHBOR_SOLICIT: 49656893Sfenner { 49756893Sfenner struct nd_neighbor_solicit *p; 49856893Sfenner p = (struct nd_neighbor_solicit *)dp; 49956893Sfenner TCHECK(p->nd_ns_target); 500146773Ssam printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 50156893Sfenner if (vflag) { 50256893Sfenner#define NDSOLLEN 24 50375115Sfenner icmp6_opt_print((const u_char *)dp + NDSOLLEN, 504127668Sbms length - NDSOLLEN); 50556893Sfenner } 50656893Sfenner } 50756893Sfenner break; 50856893Sfenner case ND_NEIGHBOR_ADVERT: 50956893Sfenner { 51056893Sfenner struct nd_neighbor_advert *p; 51156893Sfenner 51256893Sfenner p = (struct nd_neighbor_advert *)dp; 51356893Sfenner TCHECK(p->nd_na_target); 514146773Ssam printf(", tgt is %s", 51556893Sfenner ip6addr_string(&p->nd_na_target)); 51675115Sfenner if (vflag) { 517146773Ssam printf(", Flags [%s]", 518146773Ssam bittok2str(icmp6_nd_na_flag_values, 519146773Ssam "none", 520146773Ssam EXTRACT_32BITS(&p->nd_na_flags_reserved))); 52156893Sfenner#define NDADVLEN 24 52275115Sfenner icmp6_opt_print((const u_char *)dp + NDADVLEN, 523127668Sbms length - NDADVLEN); 52475115Sfenner#undef NDADVLEN 52556893Sfenner } 52656893Sfenner } 52756893Sfenner break; 52856893Sfenner case ND_REDIRECT: 52956893Sfenner#define RDR(i) ((struct nd_redirect *)(i)) 53056893Sfenner TCHECK(RDR(dp)->nd_rd_dst); 531146773Ssam printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 532127668Sbms TCHECK(RDR(dp)->nd_rd_target); 53375115Sfenner printf(" to %s", 53475115Sfenner getname6((const u_char*)&RDR(dp)->nd_rd_target)); 53556893Sfenner#define REDIRECTLEN 40 53656893Sfenner if (vflag) { 53756893Sfenner icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 538127668Sbms length - REDIRECTLEN); 53956893Sfenner } 54056893Sfenner break; 54175115Sfenner#undef REDIRECTLEN 54275115Sfenner#undef RDR 54356893Sfenner case ICMP6_ROUTER_RENUMBERING: 544127668Sbms icmp6_rrenum_print(bp, ep); 54556893Sfenner break; 54675115Sfenner case ICMP6_NI_QUERY: 54775115Sfenner case ICMP6_NI_REPLY: 548127668Sbms icmp6_nodeinfo_print(length, bp, ep); 54956893Sfenner break; 550146773Ssam case IND_SOLICIT: 551146773Ssam case IND_ADVERT: 552146773Ssam break; 553146773Ssam case ICMP6_V2_MEMBERSHIP_REPORT: 554146773Ssam mldv2_report_print((const u_char *) dp, length); 555146773Ssam break; 556146773Ssam case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 557127668Sbms case ICMP6_HADISCOV_REQUEST: 558146773Ssam TCHECK(dp->icmp6_data16[0]); 559146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 560146773Ssam break; 561127668Sbms case ICMP6_HADISCOV_REPLY: 562127668Sbms if (vflag) { 563127668Sbms struct in6_addr *in6; 564127668Sbms u_char *cp; 565127668Sbms 566127668Sbms TCHECK(dp->icmp6_data16[0]); 567146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 568127668Sbms cp = (u_char *)dp + length; 569127668Sbms in6 = (struct in6_addr *)(dp + 1); 570127668Sbms for (; (u_char *)in6 < cp; in6++) { 571127668Sbms TCHECK(*in6); 572127668Sbms printf(", %s", ip6addr_string(in6)); 573127668Sbms } 574127668Sbms } 575127668Sbms break; 576127668Sbms case ICMP6_MOBILEPREFIX_ADVERT: 577127668Sbms if (vflag) { 578127668Sbms TCHECK(dp->icmp6_data16[0]); 579146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 580127668Sbms if (dp->icmp6_data16[1] & 0xc0) 581127668Sbms printf(" "); 582127668Sbms if (dp->icmp6_data16[1] & 0x80) 583127668Sbms printf("M"); 584127668Sbms if (dp->icmp6_data16[1] & 0x40) 585127668Sbms printf("O"); 586127668Sbms#define MPADVLEN 8 587127668Sbms icmp6_opt_print((const u_char *)dp + MPADVLEN, 588127668Sbms length - MPADVLEN); 589127668Sbms } 590127668Sbms break; 591214478Srpaulo case ND_RPL_MESSAGE: 592214478Srpaulo rpl_print(ndo, dp, &dp->icmp6_data8[0], length); 593214478Srpaulo break; 59456893Sfenner default: 595146773Ssam printf(", length %u", length); 596146773Ssam if (vflag <= 1) 597146773Ssam print_unknown_data(bp,"\n\t", length); 598146773Ssam return; 599146773Ssam } 600146773Ssam if (!vflag) 601146773Ssam printf(", length %u", length); 60256893Sfenner return; 60356893Sfennertrunc: 60456893Sfenner fputs("[|icmp6]", stdout); 60556893Sfenner} 60656893Sfenner 60775115Sfennerstatic struct udphdr * 608127668Sbmsget_upperlayer(u_char *bp, u_int *prot) 60975115Sfenner{ 61098524Sfenner const u_char *ep; 61175115Sfenner struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 61275115Sfenner struct udphdr *uh; 61375115Sfenner struct ip6_hbh *hbh; 61475115Sfenner struct ip6_frag *fragh; 61575115Sfenner struct ah *ah; 616127668Sbms u_int nh; 617127668Sbms int hlen; 61875115Sfenner 61975115Sfenner /* 'ep' points to the end of available data. */ 62075115Sfenner ep = snapend; 62175115Sfenner 622127668Sbms if (!TTEST(ip6->ip6_nxt)) 62375115Sfenner return NULL; 62475115Sfenner 62575115Sfenner nh = ip6->ip6_nxt; 62675115Sfenner hlen = sizeof(struct ip6_hdr); 62775115Sfenner 628147899Ssam while (bp < ep) { 62975115Sfenner bp += hlen; 63075115Sfenner 63175115Sfenner switch(nh) { 63275115Sfenner case IPPROTO_UDP: 63375115Sfenner case IPPROTO_TCP: 63475115Sfenner uh = (struct udphdr *)bp; 63575115Sfenner if (TTEST(uh->uh_dport)) { 63675115Sfenner *prot = nh; 63775115Sfenner return(uh); 63875115Sfenner } 63975115Sfenner else 64075115Sfenner return(NULL); 64175115Sfenner /* NOTREACHED */ 64275115Sfenner 64375115Sfenner case IPPROTO_HOPOPTS: 64475115Sfenner case IPPROTO_DSTOPTS: 64575115Sfenner case IPPROTO_ROUTING: 64675115Sfenner hbh = (struct ip6_hbh *)bp; 647127668Sbms if (!TTEST(hbh->ip6h_len)) 64875115Sfenner return(NULL); 64975115Sfenner nh = hbh->ip6h_nxt; 65075115Sfenner hlen = (hbh->ip6h_len + 1) << 3; 65175115Sfenner break; 65275115Sfenner 65375115Sfenner case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 65475115Sfenner fragh = (struct ip6_frag *)bp; 655127668Sbms if (!TTEST(fragh->ip6f_offlg)) 65675115Sfenner return(NULL); 65775115Sfenner /* fragments with non-zero offset are meaningless */ 658127668Sbms if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 65975115Sfenner return(NULL); 66075115Sfenner nh = fragh->ip6f_nxt; 66175115Sfenner hlen = sizeof(struct ip6_frag); 66275115Sfenner break; 66375115Sfenner 66475115Sfenner case IPPROTO_AH: 66575115Sfenner ah = (struct ah *)bp; 666127668Sbms if (!TTEST(ah->ah_len)) 66775115Sfenner return(NULL); 66875115Sfenner nh = ah->ah_nxt; 66975115Sfenner hlen = (ah->ah_len + 2) << 2; 67075115Sfenner break; 67175115Sfenner 67275115Sfenner default: /* unknown or undecodable header */ 67375115Sfenner *prot = nh; /* meaningless, but set here anyway */ 67475115Sfenner return(NULL); 67575115Sfenner } 67675115Sfenner } 67775115Sfenner 67875115Sfenner return(NULL); /* should be notreached, though */ 67975115Sfenner} 68075115Sfenner 681127668Sbmsstatic void 68298524Sfennericmp6_opt_print(const u_char *bp, int resid) 68356893Sfenner{ 68498524Sfenner const struct nd_opt_hdr *op; 68598524Sfenner const struct nd_opt_hdr *opl; /* why there's no struct? */ 68698524Sfenner const struct nd_opt_prefix_info *opp; 68798524Sfenner const struct icmp6_opts_redirect *opr; 68898524Sfenner const struct nd_opt_mtu *opm; 689214478Srpaulo const struct nd_opt_rdnss *oprd; 69098524Sfenner const struct nd_opt_advinterval *opa; 691127668Sbms const struct nd_opt_homeagent_info *oph; 69298524Sfenner const struct nd_opt_route_info *opri; 69398524Sfenner const u_char *cp, *ep; 69498524Sfenner struct in6_addr in6, *in6p; 69598524Sfenner size_t l; 696214478Srpaulo u_int i; 69756893Sfenner 69856893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 69956893Sfenner 70098524Sfenner cp = bp; 70175115Sfenner /* 'ep' points to the end of available data. */ 70256893Sfenner ep = snapend; 70356893Sfenner 70498524Sfenner while (cp < ep) { 70598524Sfenner op = (struct nd_opt_hdr *)cp; 70698524Sfenner 70798524Sfenner ECHECK(op->nd_opt_len); 70898524Sfenner if (resid <= 0) 70998524Sfenner return; 71098524Sfenner if (op->nd_opt_len == 0) 71156893Sfenner goto trunc; 71298524Sfenner if (cp + (op->nd_opt_len << 3) > ep) 71356893Sfenner goto trunc; 71498524Sfenner 715146773Ssam printf("\n\t %s option (%u), length %u (%u): ", 716146773Ssam tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 717146773Ssam op->nd_opt_type, 718146773Ssam op->nd_opt_len << 3, 719146773Ssam op->nd_opt_len); 720146773Ssam 72198524Sfenner switch (op->nd_opt_type) { 72298524Sfenner case ND_OPT_SOURCE_LINKADDR: 72398524Sfenner opl = (struct nd_opt_hdr *)op; 72498524Sfenner l = (op->nd_opt_len << 3) - 2; 72598524Sfenner print_lladdr(cp + 2, l); 72698524Sfenner break; 72798524Sfenner case ND_OPT_TARGET_LINKADDR: 72898524Sfenner opl = (struct nd_opt_hdr *)op; 72998524Sfenner l = (op->nd_opt_len << 3) - 2; 73098524Sfenner print_lladdr(cp + 2, l); 73198524Sfenner break; 73298524Sfenner case ND_OPT_PREFIX_INFORMATION: 73398524Sfenner opp = (struct nd_opt_prefix_info *)op; 73498524Sfenner TCHECK(opp->nd_opt_pi_prefix); 735146773Ssam printf("%s/%u%s, Flags [%s], valid time %ss", 736146773Ssam ip6addr_string(&opp->nd_opt_pi_prefix), 737146773Ssam opp->nd_opt_pi_prefix_len, 738146773Ssam (op->nd_opt_len != 4) ? "badlen" : "", 739146773Ssam bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 740146773Ssam get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 741146773Ssam printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 74298524Sfenner break; 74398524Sfenner case ND_OPT_REDIRECTED_HEADER: 74498524Sfenner opr = (struct icmp6_opts_redirect *)op; 745146773Ssam print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 74698524Sfenner /* xxx */ 74798524Sfenner break; 74898524Sfenner case ND_OPT_MTU: 74998524Sfenner opm = (struct nd_opt_mtu *)op; 75098524Sfenner TCHECK(opm->nd_opt_mtu_mtu); 751146773Ssam printf(" %u%s", 752146773Ssam EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 753146773Ssam (op->nd_opt_len != 1) ? "bad option length" : "" ); 754146773Ssam break; 755214478Srpaulo case ND_OPT_RDNSS: 756214478Srpaulo oprd = (struct nd_opt_rdnss *)op; 757214478Srpaulo l = (op->nd_opt_len - 1) / 2; 758214478Srpaulo printf(" lifetime %us,", 759214478Srpaulo EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 760214478Srpaulo for (i = 0; i < l; i++) { 761214478Srpaulo TCHECK(oprd->nd_opt_rdnss_addr[i]); 762214478Srpaulo printf(" addr: %s", 763214478Srpaulo ip6addr_string(&oprd->nd_opt_rdnss_addr[i])); 764214478Srpaulo } 765214478Srpaulo break; 76698524Sfenner case ND_OPT_ADVINTERVAL: 76798524Sfenner opa = (struct nd_opt_advinterval *)op; 76898524Sfenner TCHECK(opa->nd_opt_adv_interval); 769146773Ssam printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 770127668Sbms break; 771127668Sbms case ND_OPT_HOMEAGENT_INFO: 772127668Sbms oph = (struct nd_opt_homeagent_info *)op; 773127668Sbms TCHECK(oph->nd_opt_hai_lifetime); 774146773Ssam printf(" preference %u, lifetime %u", 775146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_preference), 776146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 777127668Sbms break; 77898524Sfenner case ND_OPT_ROUTE_INFO: 77998524Sfenner opri = (struct nd_opt_route_info *)op; 78098524Sfenner TCHECK(opri->nd_opt_rti_lifetime); 78198524Sfenner memset(&in6, 0, sizeof(in6)); 78298524Sfenner in6p = (struct in6_addr *)(opri + 1); 78398524Sfenner switch (op->nd_opt_len) { 78498524Sfenner case 1: 78598524Sfenner break; 78698524Sfenner case 2: 78798524Sfenner TCHECK2(*in6p, 8); 78898524Sfenner memcpy(&in6, opri + 1, 8); 78998524Sfenner break; 79098524Sfenner case 3: 79198524Sfenner TCHECK(*in6p); 79298524Sfenner memcpy(&in6, opri + 1, sizeof(in6)); 79398524Sfenner break; 79498524Sfenner default: 79598524Sfenner goto trunc; 79698524Sfenner } 79798524Sfenner printf(" %s/%u", ip6addr_string(&in6), 79898524Sfenner opri->nd_opt_rti_prefixlen); 79998524Sfenner printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 80098524Sfenner printf(", lifetime=%s", 801127668Sbms get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 80298524Sfenner break; 80398524Sfenner default: 804146773Ssam if (vflag <= 1) { 805146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 806146773Ssam return; 807146773Ssam } 808146773Ssam break; 80956893Sfenner } 810146773Ssam /* do we want to see an additional hexdump ? */ 811146773Ssam if (vflag> 1) 812146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 81398524Sfenner 81498524Sfenner cp += op->nd_opt_len << 3; 81598524Sfenner resid -= op->nd_opt_len << 3; 81656893Sfenner } 81756893Sfenner return; 81898524Sfenner 81956893Sfenner trunc: 82056893Sfenner fputs("[ndp opt]", stdout); 82156893Sfenner return; 82256893Sfenner#undef ECHECK 82356893Sfenner} 82456893Sfenner 825127668Sbmsstatic void 82698524Sfennermld6_print(const u_char *bp) 82756893Sfenner{ 82898524Sfenner struct mld6_hdr *mp = (struct mld6_hdr *)bp; 82998524Sfenner const u_char *ep; 83056893Sfenner 83175115Sfenner /* 'ep' points to the end of available data. */ 83256893Sfenner ep = snapend; 83356893Sfenner 83456893Sfenner if ((u_char *)mp + sizeof(*mp) > ep) 83556893Sfenner return; 83656893Sfenner 837127668Sbms printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 83856893Sfenner printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 83975115Sfenner} 84056893Sfenner 84175115Sfennerstatic void 842146773Ssammldv2_report_print(const u_char *bp, u_int len) 843146773Ssam{ 844146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 845146773Ssam u_int group, nsrcs, ngroups; 846146773Ssam u_int i, j; 847146773Ssam 848146773Ssam /* Minimum len is 8 */ 849146773Ssam if (len < 8) { 850146773Ssam printf(" [invalid len %d]", len); 851146773Ssam return; 852146773Ssam } 853146773Ssam 854146773Ssam TCHECK(icp->icmp6_data16[1]); 855214478Srpaulo ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]); 856146773Ssam printf(", %d group record(s)", ngroups); 857146773Ssam if (vflag > 0) { 858146773Ssam /* Print the group records */ 859146773Ssam group = 8; 860146773Ssam for (i = 0; i < ngroups; i++) { 861146773Ssam /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 862146773Ssam if (len < group + 20) { 863146773Ssam printf(" [invalid number of groups]"); 864146773Ssam return; 865146773Ssam } 866162017Ssam TCHECK2(bp[group + 4], sizeof(struct in6_addr)); 867146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 868146773Ssam printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 869146773Ssam bp[group])); 870146773Ssam nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 871146773Ssam /* Check the number of sources and print them */ 872162017Ssam if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) { 873146773Ssam printf(" [invalid number of sources %d]", nsrcs); 874146773Ssam return; 875146773Ssam } 876146773Ssam if (vflag == 1) 877146773Ssam printf(", %d source(s)", nsrcs); 878146773Ssam else { 879146773Ssam /* Print the sources */ 880146773Ssam (void)printf(" {"); 881146773Ssam for (j = 0; j < nsrcs; j++) { 882162017Ssam TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)], 883162017Ssam sizeof(struct in6_addr)); 884162017Ssam printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 885146773Ssam } 886146773Ssam (void)printf(" }"); 887146773Ssam } 888146773Ssam /* Next group record */ 889162017Ssam group += 20 + nsrcs * sizeof(struct in6_addr); 890146773Ssam printf("]"); 891146773Ssam } 892146773Ssam } 893146773Ssam return; 894146773Ssamtrunc: 895146773Ssam (void)printf("[|icmp6]"); 896146773Ssam return; 897146773Ssam} 898146773Ssam 899146773Ssamstatic void 900146773Ssammldv2_query_print(const u_char *bp, u_int len) 901146773Ssam{ 902146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 903146773Ssam u_int mrc; 904146773Ssam int mrt, qqi; 905146773Ssam u_int nsrcs; 906146773Ssam register u_int i; 907146773Ssam 908146773Ssam /* Minimum len is 28 */ 909146773Ssam if (len < 28) { 910146773Ssam printf(" [invalid len %d]", len); 911146773Ssam return; 912146773Ssam } 913146773Ssam TCHECK(icp->icmp6_data16[0]); 914214478Srpaulo mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]); 915146773Ssam if (mrc < 32768) { 916146773Ssam mrt = mrc; 917146773Ssam } else { 918146773Ssam mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 919146773Ssam } 920146773Ssam if (vflag) { 921146773Ssam (void)printf(" [max resp delay=%d]", mrt); 922146773Ssam } 923162017Ssam TCHECK2(bp[8], sizeof(struct in6_addr)); 924146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[8])); 925146773Ssam 926146773Ssam if (vflag) { 927146773Ssam TCHECK(bp[25]); 928146773Ssam if (bp[24] & 0x08) { 929146773Ssam printf(" sflag"); 930146773Ssam } 931146773Ssam if (bp[24] & 0x07) { 932146773Ssam printf(" robustness=%d", bp[24] & 0x07); 933146773Ssam } 934146773Ssam if (bp[25] < 128) { 935146773Ssam qqi = bp[25]; 936146773Ssam } else { 937146773Ssam qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 938146773Ssam } 939146773Ssam printf(" qqi=%d", qqi); 940146773Ssam } 941146773Ssam 942146773Ssam TCHECK2(bp[26], 2); 943214478Srpaulo nsrcs = EXTRACT_16BITS(&bp[26]); 944146773Ssam if (nsrcs > 0) { 945162017Ssam if (len < 28 + nsrcs * sizeof(struct in6_addr)) 946146773Ssam printf(" [invalid number of sources]"); 947146773Ssam else if (vflag > 1) { 948146773Ssam printf(" {"); 949146773Ssam for (i = 0; i < nsrcs; i++) { 950162017Ssam TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 951162017Ssam sizeof(struct in6_addr)); 952162017Ssam printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 953146773Ssam } 954146773Ssam printf(" }"); 955146773Ssam } else 956146773Ssam printf(", %d source(s)", nsrcs); 957146773Ssam } 958146773Ssam printf("]"); 959146773Ssam return; 960146773Ssamtrunc: 961146773Ssam (void)printf("[|icmp6]"); 962146773Ssam return; 963146773Ssam} 964146773Ssam 965214478Srpaulostatic void 96675115Sfennerdnsname_print(const u_char *cp, const u_char *ep) 96775115Sfenner{ 96875115Sfenner int i; 96975115Sfenner 97075115Sfenner /* DNS name decoding - no decompression */ 97175115Sfenner printf(", \""); 97275115Sfenner while (cp < ep) { 97375115Sfenner i = *cp++; 97475115Sfenner if (i) { 97575115Sfenner if (i > ep - cp) { 97675115Sfenner printf("???"); 97775115Sfenner break; 97875115Sfenner } 97975115Sfenner while (i-- && cp < ep) { 98075115Sfenner safeputchar(*cp); 98175115Sfenner cp++; 98275115Sfenner } 98375115Sfenner if (cp + 1 < ep && *cp) 98475115Sfenner printf("."); 98575115Sfenner } else { 98675115Sfenner if (cp == ep) { 98775115Sfenner /* FQDN */ 98875115Sfenner printf("."); 98975115Sfenner } else if (cp + 1 == ep && *cp == '\0') { 99075115Sfenner /* truncated */ 99175115Sfenner } else { 99275115Sfenner /* invalid */ 99375115Sfenner printf("???"); 99475115Sfenner } 99575115Sfenner break; 99675115Sfenner } 99775115Sfenner } 99875115Sfenner printf("\""); 99975115Sfenner} 100075115Sfenner 1001127668Sbmsstatic void 1002127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 100375115Sfenner{ 100475115Sfenner struct icmp6_nodeinfo *ni6; 100575115Sfenner struct icmp6_hdr *dp; 100675115Sfenner const u_char *cp; 1007127668Sbms size_t siz, i; 100875115Sfenner int needcomma; 100975115Sfenner 1010127668Sbms if (ep < bp) 1011127668Sbms return; 101275115Sfenner dp = (struct icmp6_hdr *)bp; 101375115Sfenner ni6 = (struct icmp6_nodeinfo *)bp; 101475115Sfenner siz = ep - bp; 101575115Sfenner 101675115Sfenner switch (ni6->ni_type) { 101775115Sfenner case ICMP6_NI_QUERY: 101875115Sfenner if (siz == sizeof(*dp) + 4) { 101975115Sfenner /* KAME who-are-you */ 1020146773Ssam printf(" who-are-you request"); 102175115Sfenner break; 102275115Sfenner } 1023146773Ssam printf(" node information query"); 102475115Sfenner 102575115Sfenner TCHECK2(*dp, sizeof(*ni6)); 102675115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 102775115Sfenner printf(" ("); /*)*/ 1028127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 102975115Sfenner case NI_QTYPE_NOOP: 103075115Sfenner printf("noop"); 103175115Sfenner break; 103275115Sfenner case NI_QTYPE_SUPTYPES: 103375115Sfenner printf("supported qtypes"); 1034127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 103575115Sfenner if (i) 103675115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 103775115Sfenner break; 103875115Sfenner break; 103975115Sfenner case NI_QTYPE_FQDN: 104075115Sfenner printf("DNS name"); 104175115Sfenner break; 104275115Sfenner case NI_QTYPE_NODEADDR: 104375115Sfenner printf("node addresses"); 104475115Sfenner i = ni6->ni_flags; 104575115Sfenner if (!i) 104675115Sfenner break; 104775115Sfenner /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 104875115Sfenner printf(" [%s%s%s%s%s%s]", 104975115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 105075115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 105175115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 105275115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 105375115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 105475115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 105575115Sfenner break; 105675115Sfenner default: 105775115Sfenner printf("unknown"); 105875115Sfenner break; 105975115Sfenner } 106075115Sfenner 106175115Sfenner if (ni6->ni_qtype == NI_QTYPE_NOOP || 106275115Sfenner ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 106375115Sfenner if (siz != sizeof(*ni6)) 106475115Sfenner if (vflag) 106575115Sfenner printf(", invalid len"); 106675115Sfenner /*(*/ 106775115Sfenner printf(")"); 106875115Sfenner break; 106975115Sfenner } 107075115Sfenner 107175115Sfenner 107275115Sfenner /* XXX backward compat, icmp-name-lookup-03 */ 107375115Sfenner if (siz == sizeof(*ni6)) { 107475115Sfenner printf(", 03 draft"); 107575115Sfenner /*(*/ 107675115Sfenner printf(")"); 107775115Sfenner break; 107875115Sfenner } 107975115Sfenner 108075115Sfenner switch (ni6->ni_code) { 108175115Sfenner case ICMP6_NI_SUBJ_IPV6: 108275115Sfenner if (!TTEST2(*dp, 108375115Sfenner sizeof(*ni6) + sizeof(struct in6_addr))) 108475115Sfenner break; 108575115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 108675115Sfenner if (vflag) 108775115Sfenner printf(", invalid subject len"); 108875115Sfenner break; 108975115Sfenner } 109075115Sfenner printf(", subject=%s", 109175115Sfenner getname6((const u_char *)(ni6 + 1))); 109275115Sfenner break; 109375115Sfenner case ICMP6_NI_SUBJ_FQDN: 109475115Sfenner printf(", subject=DNS name"); 109575115Sfenner cp = (const u_char *)(ni6 + 1); 109675115Sfenner if (cp[0] == ep - cp - 1) { 109775115Sfenner /* icmp-name-lookup-03, pascal string */ 109875115Sfenner if (vflag) 109975115Sfenner printf(", 03 draft"); 110075115Sfenner cp++; 110175115Sfenner printf(", \""); 110275115Sfenner while (cp < ep) { 110375115Sfenner safeputchar(*cp); 110475115Sfenner cp++; 110575115Sfenner } 110675115Sfenner printf("\""); 110775115Sfenner } else 110875115Sfenner dnsname_print(cp, ep); 110975115Sfenner break; 111075115Sfenner case ICMP6_NI_SUBJ_IPV4: 111175115Sfenner if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 111275115Sfenner break; 111375115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 111475115Sfenner if (vflag) 111575115Sfenner printf(", invalid subject len"); 111675115Sfenner break; 111775115Sfenner } 111875115Sfenner printf(", subject=%s", 111975115Sfenner getname((const u_char *)(ni6 + 1))); 112075115Sfenner break; 112175115Sfenner default: 112275115Sfenner printf(", unknown subject"); 112375115Sfenner break; 112475115Sfenner } 112575115Sfenner 112675115Sfenner /*(*/ 112775115Sfenner printf(")"); 112875115Sfenner break; 112975115Sfenner 113075115Sfenner case ICMP6_NI_REPLY: 113175115Sfenner if (icmp6len > siz) { 113275115Sfenner printf("[|icmp6: node information reply]"); 113375115Sfenner break; 113475115Sfenner } 113575115Sfenner 113675115Sfenner needcomma = 0; 113775115Sfenner 113875115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 1139146773Ssam printf(" node information reply"); 114075115Sfenner printf(" ("); /*)*/ 114175115Sfenner switch (ni6->ni_code) { 114275115Sfenner case ICMP6_NI_SUCCESS: 114375115Sfenner if (vflag) { 114475115Sfenner printf("success"); 114575115Sfenner needcomma++; 114675115Sfenner } 114775115Sfenner break; 114875115Sfenner case ICMP6_NI_REFUSED: 114975115Sfenner printf("refused"); 115075115Sfenner needcomma++; 115175115Sfenner if (siz != sizeof(*ni6)) 115275115Sfenner if (vflag) 115375115Sfenner printf(", invalid length"); 115475115Sfenner break; 115575115Sfenner case ICMP6_NI_UNKNOWN: 115675115Sfenner printf("unknown"); 115775115Sfenner needcomma++; 115875115Sfenner if (siz != sizeof(*ni6)) 115975115Sfenner if (vflag) 116075115Sfenner printf(", invalid length"); 116175115Sfenner break; 116275115Sfenner } 116375115Sfenner 116475115Sfenner if (ni6->ni_code != ICMP6_NI_SUCCESS) { 116575115Sfenner /*(*/ 116675115Sfenner printf(")"); 116775115Sfenner break; 116875115Sfenner } 116975115Sfenner 1170127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 117175115Sfenner case NI_QTYPE_NOOP: 117275115Sfenner if (needcomma) 117375115Sfenner printf(", "); 117475115Sfenner printf("noop"); 117575115Sfenner if (siz != sizeof(*ni6)) 117675115Sfenner if (vflag) 117775115Sfenner printf(", invalid length"); 117875115Sfenner break; 117975115Sfenner case NI_QTYPE_SUPTYPES: 118075115Sfenner if (needcomma) 118175115Sfenner printf(", "); 118275115Sfenner printf("supported qtypes"); 1183127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 118475115Sfenner if (i) 118575115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 118675115Sfenner break; 118775115Sfenner case NI_QTYPE_FQDN: 118875115Sfenner if (needcomma) 118975115Sfenner printf(", "); 119075115Sfenner printf("DNS name"); 119175115Sfenner cp = (const u_char *)(ni6 + 1) + 4; 119275115Sfenner if (cp[0] == ep - cp - 1) { 119375115Sfenner /* icmp-name-lookup-03, pascal string */ 119475115Sfenner if (vflag) 119575115Sfenner printf(", 03 draft"); 119675115Sfenner cp++; 119775115Sfenner printf(", \""); 119875115Sfenner while (cp < ep) { 119975115Sfenner safeputchar(*cp); 120075115Sfenner cp++; 120175115Sfenner } 120275115Sfenner printf("\""); 120375115Sfenner } else 120475115Sfenner dnsname_print(cp, ep); 1205127668Sbms if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 120675115Sfenner printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 120775115Sfenner break; 120875115Sfenner case NI_QTYPE_NODEADDR: 120975115Sfenner if (needcomma) 121075115Sfenner printf(", "); 121175115Sfenner printf("node addresses"); 121275115Sfenner i = sizeof(*ni6); 121375115Sfenner while (i < siz) { 121475115Sfenner if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 121575115Sfenner break; 121675115Sfenner printf(" %s", getname6(bp + i)); 121775115Sfenner i += sizeof(struct in6_addr); 1218127668Sbms printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 121975115Sfenner i += sizeof(int32_t); 122075115Sfenner } 122175115Sfenner i = ni6->ni_flags; 122275115Sfenner if (!i) 122375115Sfenner break; 122475115Sfenner printf(" [%s%s%s%s%s%s%s]", 122575115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 122675115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 122775115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 122875115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 122975115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 123075115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 123175115Sfenner (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 123275115Sfenner break; 123375115Sfenner default: 123475115Sfenner if (needcomma) 123575115Sfenner printf(", "); 123675115Sfenner printf("unknown"); 123775115Sfenner break; 123875115Sfenner } 123975115Sfenner 124075115Sfenner /*(*/ 124175115Sfenner printf(")"); 124275115Sfenner break; 124375115Sfenner } 124456893Sfenner return; 124575115Sfenner 124675115Sfennertrunc: 124775115Sfenner fputs("[|icmp6]", stdout); 124856893Sfenner} 124975115Sfenner 1250127668Sbmsstatic void 1251127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep) 125275115Sfenner{ 125375115Sfenner struct icmp6_router_renum *rr6; 125475115Sfenner const char *cp; 125575115Sfenner struct rr_pco_match *match; 125675115Sfenner struct rr_pco_use *use; 125775115Sfenner char hbuf[NI_MAXHOST]; 125875115Sfenner int n; 125975115Sfenner 1260127668Sbms if (ep < bp) 1261127668Sbms return; 126275115Sfenner rr6 = (struct icmp6_router_renum *)bp; 126375115Sfenner cp = (const char *)(rr6 + 1); 126475115Sfenner 126575115Sfenner TCHECK(rr6->rr_reserved); 126675115Sfenner switch (rr6->rr_code) { 126775115Sfenner case ICMP6_ROUTER_RENUMBERING_COMMAND: 126875115Sfenner printf("router renum: command"); 126975115Sfenner break; 127075115Sfenner case ICMP6_ROUTER_RENUMBERING_RESULT: 127175115Sfenner printf("router renum: result"); 127275115Sfenner break; 127375115Sfenner case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 127475115Sfenner printf("router renum: sequence number reset"); 127575115Sfenner break; 127675115Sfenner default: 127775115Sfenner printf("router renum: code-#%d", rr6->rr_code); 127875115Sfenner break; 127975115Sfenner } 128075115Sfenner 1281127668Sbms printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 128275115Sfenner 128375115Sfenner if (vflag) { 128475115Sfenner#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 128575115Sfenner printf("["); /*]*/ 128675115Sfenner if (rr6->rr_flags) { 128775115Sfenner printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 128875115Sfenner F(ICMP6_RR_FLAGS_REQRESULT, "R"), 128998524Sfenner F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 129075115Sfenner F(ICMP6_RR_FLAGS_SPECSITE, "S"), 129175115Sfenner F(ICMP6_RR_FLAGS_PREVDONE, "P")); 129275115Sfenner } 129375115Sfenner printf("seg=%u,", rr6->rr_segnum); 1294190207Srpaulo printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)); 129575115Sfenner if (rr6->rr_reserved) 1296190207Srpaulo printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)); 129775115Sfenner /*[*/ 129875115Sfenner printf("]"); 129975115Sfenner#undef F 130075115Sfenner } 130175115Sfenner 130275115Sfenner if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 130375115Sfenner match = (struct rr_pco_match *)cp; 130475115Sfenner cp = (const char *)(match + 1); 130575115Sfenner 130675115Sfenner TCHECK(match->rpm_prefix); 130775115Sfenner 130898524Sfenner if (vflag > 1) 130975115Sfenner printf("\n\t"); 131075115Sfenner else 131175115Sfenner printf(" "); 131275115Sfenner printf("match("); /*)*/ 131375115Sfenner switch (match->rpm_code) { 131475115Sfenner case RPM_PCO_ADD: printf("add"); break; 131575115Sfenner case RPM_PCO_CHANGE: printf("change"); break; 131675115Sfenner case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 131775115Sfenner default: printf("#%u", match->rpm_code); break; 131875115Sfenner } 131975115Sfenner 132075115Sfenner if (vflag) { 132175115Sfenner printf(",ord=%u", match->rpm_ordinal); 132275115Sfenner printf(",min=%u", match->rpm_minlen); 132375115Sfenner printf(",max=%u", match->rpm_maxlen); 132475115Sfenner } 132575115Sfenner if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 132675115Sfenner printf(",%s/%u", hbuf, match->rpm_matchlen); 132775115Sfenner else 132875115Sfenner printf(",?/%u", match->rpm_matchlen); 132975115Sfenner /*(*/ 133075115Sfenner printf(")"); 133175115Sfenner 133275115Sfenner n = match->rpm_len - 3; 133375115Sfenner if (n % 4) 133475115Sfenner goto trunc; 133575115Sfenner n /= 4; 133675115Sfenner while (n-- > 0) { 133775115Sfenner use = (struct rr_pco_use *)cp; 133875115Sfenner cp = (const char *)(use + 1); 133975115Sfenner 134075115Sfenner TCHECK(use->rpu_prefix); 134175115Sfenner 134298524Sfenner if (vflag > 1) 134375115Sfenner printf("\n\t"); 134475115Sfenner else 134575115Sfenner printf(" "); 134675115Sfenner printf("use("); /*)*/ 134775115Sfenner if (use->rpu_flags) { 134875115Sfenner#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 134975115Sfenner printf("%s%s,", 135075115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 135175115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 135275115Sfenner#undef F 135375115Sfenner } 135475115Sfenner if (vflag) { 135575115Sfenner printf("mask=0x%x,", use->rpu_ramask); 135675115Sfenner printf("raflags=0x%x,", use->rpu_raflags); 135775115Sfenner if (~use->rpu_vltime == 0) 135875115Sfenner printf("vltime=infty,"); 135975115Sfenner else 136075115Sfenner printf("vltime=%u,", 1361127668Sbms EXTRACT_32BITS(&use->rpu_vltime)); 136275115Sfenner if (~use->rpu_pltime == 0) 136375115Sfenner printf("pltime=infty,"); 136475115Sfenner else 136575115Sfenner printf("pltime=%u,", 1366127668Sbms EXTRACT_32BITS(&use->rpu_pltime)); 136775115Sfenner } 136875115Sfenner if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 136975115Sfenner sizeof(hbuf))) 137075115Sfenner printf("%s/%u/%u", hbuf, use->rpu_uselen, 137175115Sfenner use->rpu_keeplen); 137275115Sfenner else 137375115Sfenner printf("?/%u/%u", use->rpu_uselen, 137475115Sfenner use->rpu_keeplen); 137575115Sfenner /*(*/ 137675115Sfenner printf(")"); 137775115Sfenner } 137875115Sfenner } 137975115Sfenner 138075115Sfenner return; 138175115Sfenner 138275115Sfennertrunc: 138375115Sfenner fputs("[|icmp6]", stdout); 138475115Sfenner} 138575115Sfenner 138656893Sfenner#endif /* INET6 */ 1387