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"}, 139252283Sdelphij { ND_OPT_DNSSL, "dnssl"}, 140162017Ssam { ND_OPT_ADVINTERVAL, "advertisement interval"}, 141146773Ssam { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 142146773Ssam { ND_OPT_ROUTE_INFO, "route info"}, 143146773Ssam { 0, NULL } 144146773Ssam}; 145146773Ssam 146146773Ssam/* mldv2 report types */ 147146773Ssamstatic struct tok mldv2report2str[] = { 148146773Ssam { 1, "is_in" }, 149146773Ssam { 2, "is_ex" }, 150146773Ssam { 3, "to_in" }, 151146773Ssam { 4, "to_ex" }, 152146773Ssam { 5, "allow" }, 153146773Ssam { 6, "block" }, 154146773Ssam { 0, NULL } 155146773Ssam}; 156146773Ssam 15798524Sfennerstatic const char * 15898524Sfennerget_rtpref(u_int v) 15998524Sfenner{ 16098524Sfenner static const char *rtpref_str[] = { 16198524Sfenner "medium", /* 00 */ 16298524Sfenner "high", /* 01 */ 16398524Sfenner "rsv", /* 10 */ 16498524Sfenner "low" /* 11 */ 16598524Sfenner }; 16698524Sfenner 16798524Sfenner return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 16898524Sfenner} 16998524Sfenner 17098524Sfennerstatic const char * 17198524Sfennerget_lifetime(u_int32_t v) 17298524Sfenner{ 17398524Sfenner static char buf[20]; 17498524Sfenner 17598524Sfenner if (v == (u_int32_t)~0UL) 17698524Sfenner return "infinity"; 17798524Sfenner else { 178252283Sdelphij snprintf(buf, sizeof(buf), "%us", v); 17998524Sfenner return buf; 18098524Sfenner } 18198524Sfenner} 18298524Sfenner 18398524Sfennerstatic void 18498524Sfennerprint_lladdr(const u_int8_t *p, size_t l) 18598524Sfenner{ 18698524Sfenner const u_int8_t *ep, *q; 18798524Sfenner 18898524Sfenner q = p; 18998524Sfenner ep = p + l; 19098524Sfenner while (l > 0 && q < ep) { 19198524Sfenner if (q > p) 19298524Sfenner printf(":"); 19398524Sfenner printf("%02x", *q++); 19498524Sfenner l--; 19598524Sfenner } 19698524Sfenner} 19798524Sfenner 198127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 199127668Sbms u_int len) 200127668Sbms{ 201236192Sdelphij return (nextproto6_cksum(ip6, (const u_int8_t *)(void *)icp, len, 202236192Sdelphij IPPROTO_ICMPV6)); 203127668Sbms} 204127668Sbms 205214478Srpauloenum ND_RPL_CODE { 206236192Sdelphij ND_RPL_DIS =0x00, 207236192Sdelphij ND_RPL_DIO =0x01, 208236192Sdelphij ND_RPL_DAO =0x02, 209236192Sdelphij ND_RPL_DAO_ACK=0x03, 210236192Sdelphij ND_RPL_SDIS =0x80, 211236192Sdelphij ND_RPL_SDIO =0x81, 212236192Sdelphij ND_RPL_SDAO =0x82, 213236192Sdelphij ND_RPL_SDAO_ACK=0x83, 214236192Sdelphij ND_RPL_SCC =0x8A, 215214478Srpaulo}; 216214478Srpaulo 217214478Srpauloenum ND_RPL_DIO_FLAGS { 218214478Srpaulo ND_RPL_DIO_GROUNDED = 0x80, 219214478Srpaulo ND_RPL_DIO_DATRIG = 0x40, 220214478Srpaulo ND_RPL_DIO_DASUPPORT= 0x20, 221214478Srpaulo ND_RPL_DIO_RES4 = 0x10, 222214478Srpaulo ND_RPL_DIO_RES3 = 0x08, 223214478Srpaulo ND_RPL_DIO_PRF_MASK = 0x07, /* 3-bit preference */ 224214478Srpaulo}; 225214478Srpaulo 226214478Srpaulostruct nd_rpl_dio { 227214478Srpaulo u_int8_t rpl_flags; 228214478Srpaulo u_int8_t rpl_seq; 229214478Srpaulo u_int8_t rpl_instanceid; 230214478Srpaulo u_int8_t rpl_dagrank; 231214478Srpaulo u_int8_t rpl_dagid[16]; 232214478Srpaulo}; 233214478Srpaulo 234214478Srpaulostatic void 235214478Srpaulorpl_print(netdissect_options *ndo, 236214478Srpaulo const struct icmp6_hdr *hdr, 237214478Srpaulo const u_char *bp, u_int length _U_) 238214478Srpaulo{ 239214478Srpaulo struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp; 240236192Sdelphij int secured = hdr->icmp6_code & 0x80; 241236192Sdelphij int basecode= hdr->icmp6_code & 0x7f; 242214478Srpaulo 243214478Srpaulo ND_TCHECK(dio->rpl_dagid); 244214478Srpaulo 245236192Sdelphij if(secured) { 246236192Sdelphij ND_PRINT((ndo, ", (SEC)")); 247236192Sdelphij } else { 248236192Sdelphij ND_PRINT((ndo, ", (CLR)")); 249236192Sdelphij } 250236192Sdelphij 251236192Sdelphij switch(basecode) { 252236192Sdelphij case ND_RPL_DIS: 253236192Sdelphij ND_PRINT((ndo, "DODAG Information Solicitation")); 254214478Srpaulo if(ndo->ndo_vflag) { 255214478Srpaulo } 256214478Srpaulo break; 257236192Sdelphij case ND_RPL_DIO: 258236192Sdelphij ND_PRINT((ndo, "DODAG Information Object")); 259214478Srpaulo if(ndo->ndo_vflag) { 260214478Srpaulo char dagid[65]; 261214478Srpaulo char *d = dagid; 262214478Srpaulo int i; 263214478Srpaulo for(i=0;i<16;i++) { 264214478Srpaulo if(isprint(dio->rpl_dagid[i])) { 265214478Srpaulo *d++ = dio->rpl_dagid[i]; 266214478Srpaulo } else { 267214478Srpaulo int cnt=snprintf(d,4,"0x%02x", 268214478Srpaulo dio->rpl_dagid[i]); 269214478Srpaulo d += cnt; 270214478Srpaulo } 271214478Srpaulo } 272214478Srpaulo *d++ = '\0'; 273214478Srpaulo ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]", 274214478Srpaulo dio->rpl_seq, 275214478Srpaulo dio->rpl_instanceid, 276214478Srpaulo dio->rpl_dagrank, 277214478Srpaulo dagid)); 278214478Srpaulo } 279214478Srpaulo break; 280214478Srpaulo case ND_RPL_DAO: 281236192Sdelphij ND_PRINT((ndo, "Destination Advertisement Object")); 282214478Srpaulo if(ndo->ndo_vflag) { 283214478Srpaulo } 284214478Srpaulo break; 285236192Sdelphij case ND_RPL_DAO_ACK: 286236192Sdelphij ND_PRINT((ndo, "Destination Advertisement Object Ack")); 287236192Sdelphij if(ndo->ndo_vflag) { 288236192Sdelphij } 289236192Sdelphij break; 290214478Srpaulo default: 291236192Sdelphij ND_PRINT((ndo, "RPL message, unknown code %u",hdr->icmp6_code)); 292214478Srpaulo break; 293214478Srpaulo } 294214478Srpaulo return; 295214478Srpaulotrunc: 296214478Srpaulo ND_PRINT((ndo," [|truncated]")); 297214478Srpaulo return; 298214478Srpaulo 299214478Srpaulo} 300214478Srpaulo 301214478Srpaulo 30256893Sfennervoid 303214478Srpauloicmp6_print(netdissect_options *ndo, 304214478Srpaulo const u_char *bp, u_int length, const u_char *bp2, int fragmented) 30556893Sfenner{ 30675115Sfenner const struct icmp6_hdr *dp; 30798524Sfenner const struct ip6_hdr *ip; 30898524Sfenner const struct ip6_hdr *oip; 30998524Sfenner const struct udphdr *ouh; 31098524Sfenner int dport; 31198524Sfenner const u_char *ep; 312127668Sbms u_int prot; 31356893Sfenner 31456893Sfenner dp = (struct icmp6_hdr *)bp; 31556893Sfenner ip = (struct ip6_hdr *)bp2; 31656893Sfenner oip = (struct ip6_hdr *)(dp + 1); 31775115Sfenner /* 'ep' points to the end of available data. */ 31856893Sfenner ep = snapend; 31956893Sfenner 320127668Sbms TCHECK(dp->icmp6_cksum); 321127668Sbms 322127668Sbms if (vflag && !fragmented) { 323236192Sdelphij u_int16_t sum, udp_sum; 324127668Sbms 325127668Sbms if (TTEST2(bp[0], length)) { 326236192Sdelphij udp_sum = EXTRACT_16BITS(&dp->icmp6_cksum); 327127668Sbms sum = icmp6_cksum(ip, dp, length); 328127668Sbms if (sum != 0) 329236192Sdelphij (void)printf("[bad icmp6 cksum 0x%04x -> 0x%04x!] ", 330236192Sdelphij udp_sum, 331236192Sdelphij in_cksum_shouldbe(udp_sum, sum)); 332127668Sbms else 333127668Sbms (void)printf("[icmp6 sum ok] "); 334127668Sbms } 335127668Sbms } 336127668Sbms 337146773Ssam printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 338146773Ssam 339146773Ssam /* display cosmetics: print the packet length for printer that use the vflag now */ 340229244Sdim if (vflag && (dp->icmp6_type == ND_ROUTER_SOLICIT || 341229244Sdim dp->icmp6_type == ND_ROUTER_ADVERT || 342229244Sdim dp->icmp6_type == ND_NEIGHBOR_ADVERT || 343229244Sdim dp->icmp6_type == ND_NEIGHBOR_SOLICIT || 344229244Sdim dp->icmp6_type == ND_REDIRECT || 345229244Sdim dp->icmp6_type == ICMP6_HADISCOV_REPLY || 346229244Sdim dp->icmp6_type == ICMP6_MOBILEPREFIX_ADVERT )) 347146773Ssam printf(", length %u", length); 348146773Ssam 34975115Sfenner switch (dp->icmp6_type) { 35056893Sfenner case ICMP6_DST_UNREACH: 35156893Sfenner TCHECK(oip->ip6_dst); 352146773Ssam printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 35356893Sfenner switch (dp->icmp6_code) { 354146773Ssam 355146773Ssam case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 35656893Sfenner case ICMP6_DST_UNREACH_ADMIN: 357146773Ssam case ICMP6_DST_UNREACH_ADDR: 358146773Ssam printf(" %s",ip6addr_string(&oip->ip6_dst)); 359146773Ssam break; 36056893Sfenner case ICMP6_DST_UNREACH_BEYONDSCOPE: 361146773Ssam printf(" %s, source address %s", 36256893Sfenner ip6addr_string(&oip->ip6_dst), 36356893Sfenner ip6addr_string(&oip->ip6_src)); 36456893Sfenner break; 36556893Sfenner case ICMP6_DST_UNREACH_NOPORT: 36675115Sfenner if ((ouh = get_upperlayer((u_char *)oip, &prot)) 36775115Sfenner == NULL) 36875115Sfenner goto trunc; 36975115Sfenner 370127668Sbms dport = EXTRACT_16BITS(&ouh->uh_dport); 37175115Sfenner switch (prot) { 37256893Sfenner case IPPROTO_TCP: 373146773Ssam printf(", %s tcp port %s", 37456893Sfenner ip6addr_string(&oip->ip6_dst), 37556893Sfenner tcpport_string(dport)); 37656893Sfenner break; 37756893Sfenner case IPPROTO_UDP: 378146773Ssam printf(", %s udp port %s", 37956893Sfenner ip6addr_string(&oip->ip6_dst), 38056893Sfenner udpport_string(dport)); 38156893Sfenner break; 38256893Sfenner default: 383146773Ssam printf(", %s protocol %d port %d unreachable", 38456893Sfenner ip6addr_string(&oip->ip6_dst), 38556893Sfenner oip->ip6_nxt, dport); 38656893Sfenner break; 38756893Sfenner } 38856893Sfenner break; 38956893Sfenner default: 390146773Ssam if (vflag <= 1) { 391146773Ssam print_unknown_data(bp,"\n\t",length); 392146773Ssam return; 393146773Ssam } 394146773Ssam break; 39556893Sfenner } 39656893Sfenner break; 39756893Sfenner case ICMP6_PACKET_TOO_BIG: 39856893Sfenner TCHECK(dp->icmp6_mtu); 399146773Ssam printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 40056893Sfenner break; 40156893Sfenner case ICMP6_TIME_EXCEEDED: 40256893Sfenner TCHECK(oip->ip6_dst); 40356893Sfenner switch (dp->icmp6_code) { 40456893Sfenner case ICMP6_TIME_EXCEED_TRANSIT: 405146773Ssam printf(" for %s", 40656893Sfenner ip6addr_string(&oip->ip6_dst)); 40756893Sfenner break; 40856893Sfenner case ICMP6_TIME_EXCEED_REASSEMBLY: 409146773Ssam printf(" (reassembly)"); 41056893Sfenner break; 41156893Sfenner default: 412146773Ssam printf(", unknown code (%u)", dp->icmp6_code); 41356893Sfenner break; 41456893Sfenner } 41556893Sfenner break; 41656893Sfenner case ICMP6_PARAM_PROB: 41756893Sfenner TCHECK(oip->ip6_dst); 41856893Sfenner switch (dp->icmp6_code) { 41956893Sfenner case ICMP6_PARAMPROB_HEADER: 420146773Ssam printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 42156893Sfenner break; 42256893Sfenner case ICMP6_PARAMPROB_NEXTHEADER: 423146773Ssam printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 42456893Sfenner break; 42556893Sfenner case ICMP6_PARAMPROB_OPTION: 426146773Ssam printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 42756893Sfenner break; 42856893Sfenner default: 429146773Ssam printf(", code-#%d", 43056893Sfenner dp->icmp6_code); 43156893Sfenner break; 43256893Sfenner } 43356893Sfenner break; 43456893Sfenner case ICMP6_ECHO_REQUEST: 43556893Sfenner case ICMP6_ECHO_REPLY: 436127668Sbms TCHECK(dp->icmp6_seq); 437146773Ssam printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 43856893Sfenner break; 43956893Sfenner case ICMP6_MEMBERSHIP_QUERY: 440146773Ssam if (length == MLD_MINLEN) { 441146773Ssam mld6_print((const u_char *)dp); 442146773Ssam } else if (length >= MLDV2_MINLEN) { 443252283Sdelphij printf(" v2"); 444146773Ssam mldv2_query_print((const u_char *)dp, length); 445146773Ssam } else { 446146773Ssam printf(" unknown-version (len %u) ", length); 447146773Ssam } 44856893Sfenner break; 44956893Sfenner case ICMP6_MEMBERSHIP_REPORT: 45056893Sfenner mld6_print((const u_char *)dp); 45156893Sfenner break; 45256893Sfenner case ICMP6_MEMBERSHIP_REDUCTION: 45356893Sfenner mld6_print((const u_char *)dp); 45456893Sfenner break; 45556893Sfenner case ND_ROUTER_SOLICIT: 456146773Ssam#define RTSOLLEN 8 45756893Sfenner if (vflag) { 45875115Sfenner icmp6_opt_print((const u_char *)dp + RTSOLLEN, 459127668Sbms length - RTSOLLEN); 46056893Sfenner } 46156893Sfenner break; 46256893Sfenner case ND_ROUTER_ADVERT: 463146773Ssam#define RTADVLEN 16 46456893Sfenner if (vflag) { 46556893Sfenner struct nd_router_advert *p; 46656893Sfenner 46756893Sfenner p = (struct nd_router_advert *)dp; 46856893Sfenner TCHECK(p->nd_ra_retransmit); 469146773Ssam printf("\n\thop limit %u, Flags [%s]" \ 470146773Ssam ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 471146773Ssam (u_int)p->nd_ra_curhoplimit, 472146773Ssam bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 473146773Ssam get_rtpref(p->nd_ra_flags_reserved), 474146773Ssam EXTRACT_16BITS(&p->nd_ra_router_lifetime), 475146773Ssam EXTRACT_32BITS(&p->nd_ra_reachable), 476146773Ssam EXTRACT_32BITS(&p->nd_ra_retransmit)); 47798524Sfenner 47875115Sfenner icmp6_opt_print((const u_char *)dp + RTADVLEN, 479127668Sbms length - RTADVLEN); 48056893Sfenner } 48156893Sfenner break; 48256893Sfenner case ND_NEIGHBOR_SOLICIT: 48356893Sfenner { 48456893Sfenner struct nd_neighbor_solicit *p; 48556893Sfenner p = (struct nd_neighbor_solicit *)dp; 48656893Sfenner TCHECK(p->nd_ns_target); 487146773Ssam printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 48856893Sfenner if (vflag) { 48956893Sfenner#define NDSOLLEN 24 49075115Sfenner icmp6_opt_print((const u_char *)dp + NDSOLLEN, 491127668Sbms length - NDSOLLEN); 49256893Sfenner } 49356893Sfenner } 49456893Sfenner break; 49556893Sfenner case ND_NEIGHBOR_ADVERT: 49656893Sfenner { 49756893Sfenner struct nd_neighbor_advert *p; 49856893Sfenner 49956893Sfenner p = (struct nd_neighbor_advert *)dp; 50056893Sfenner TCHECK(p->nd_na_target); 501146773Ssam printf(", tgt is %s", 50256893Sfenner ip6addr_string(&p->nd_na_target)); 50375115Sfenner if (vflag) { 504146773Ssam printf(", Flags [%s]", 505146773Ssam bittok2str(icmp6_nd_na_flag_values, 506146773Ssam "none", 507146773Ssam EXTRACT_32BITS(&p->nd_na_flags_reserved))); 50856893Sfenner#define NDADVLEN 24 50975115Sfenner icmp6_opt_print((const u_char *)dp + NDADVLEN, 510127668Sbms length - NDADVLEN); 51175115Sfenner#undef NDADVLEN 51256893Sfenner } 51356893Sfenner } 51456893Sfenner break; 51556893Sfenner case ND_REDIRECT: 51656893Sfenner#define RDR(i) ((struct nd_redirect *)(i)) 51756893Sfenner TCHECK(RDR(dp)->nd_rd_dst); 518146773Ssam printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 519127668Sbms TCHECK(RDR(dp)->nd_rd_target); 52075115Sfenner printf(" to %s", 52175115Sfenner getname6((const u_char*)&RDR(dp)->nd_rd_target)); 52256893Sfenner#define REDIRECTLEN 40 52356893Sfenner if (vflag) { 52456893Sfenner icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 525127668Sbms length - REDIRECTLEN); 52656893Sfenner } 52756893Sfenner break; 52875115Sfenner#undef REDIRECTLEN 52975115Sfenner#undef RDR 53056893Sfenner case ICMP6_ROUTER_RENUMBERING: 531127668Sbms icmp6_rrenum_print(bp, ep); 53256893Sfenner break; 53375115Sfenner case ICMP6_NI_QUERY: 53475115Sfenner case ICMP6_NI_REPLY: 535127668Sbms icmp6_nodeinfo_print(length, bp, ep); 53656893Sfenner break; 537146773Ssam case IND_SOLICIT: 538146773Ssam case IND_ADVERT: 539146773Ssam break; 540146773Ssam case ICMP6_V2_MEMBERSHIP_REPORT: 541146773Ssam mldv2_report_print((const u_char *) dp, length); 542146773Ssam break; 543146773Ssam case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 544127668Sbms case ICMP6_HADISCOV_REQUEST: 545146773Ssam TCHECK(dp->icmp6_data16[0]); 546146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 547146773Ssam break; 548127668Sbms case ICMP6_HADISCOV_REPLY: 549127668Sbms if (vflag) { 550127668Sbms struct in6_addr *in6; 551127668Sbms u_char *cp; 552127668Sbms 553127668Sbms TCHECK(dp->icmp6_data16[0]); 554146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 555127668Sbms cp = (u_char *)dp + length; 556127668Sbms in6 = (struct in6_addr *)(dp + 1); 557127668Sbms for (; (u_char *)in6 < cp; in6++) { 558127668Sbms TCHECK(*in6); 559127668Sbms printf(", %s", ip6addr_string(in6)); 560127668Sbms } 561127668Sbms } 562127668Sbms break; 563127668Sbms case ICMP6_MOBILEPREFIX_ADVERT: 564127668Sbms if (vflag) { 565127668Sbms TCHECK(dp->icmp6_data16[0]); 566146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 567127668Sbms if (dp->icmp6_data16[1] & 0xc0) 568127668Sbms printf(" "); 569127668Sbms if (dp->icmp6_data16[1] & 0x80) 570127668Sbms printf("M"); 571127668Sbms if (dp->icmp6_data16[1] & 0x40) 572127668Sbms printf("O"); 573127668Sbms#define MPADVLEN 8 574127668Sbms icmp6_opt_print((const u_char *)dp + MPADVLEN, 575127668Sbms length - MPADVLEN); 576127668Sbms } 577127668Sbms break; 578214478Srpaulo case ND_RPL_MESSAGE: 579214478Srpaulo rpl_print(ndo, dp, &dp->icmp6_data8[0], length); 580214478Srpaulo break; 58156893Sfenner default: 582146773Ssam printf(", length %u", length); 583146773Ssam if (vflag <= 1) 584146773Ssam print_unknown_data(bp,"\n\t", length); 585146773Ssam return; 586146773Ssam } 587146773Ssam if (!vflag) 588146773Ssam printf(", length %u", length); 58956893Sfenner return; 59056893Sfennertrunc: 59156893Sfenner fputs("[|icmp6]", stdout); 59256893Sfenner} 59356893Sfenner 59475115Sfennerstatic struct udphdr * 595127668Sbmsget_upperlayer(u_char *bp, u_int *prot) 59675115Sfenner{ 59798524Sfenner const u_char *ep; 59875115Sfenner struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 59975115Sfenner struct udphdr *uh; 60075115Sfenner struct ip6_hbh *hbh; 60175115Sfenner struct ip6_frag *fragh; 60275115Sfenner struct ah *ah; 603127668Sbms u_int nh; 604127668Sbms int hlen; 60575115Sfenner 60675115Sfenner /* 'ep' points to the end of available data. */ 60775115Sfenner ep = snapend; 60875115Sfenner 609127668Sbms if (!TTEST(ip6->ip6_nxt)) 61075115Sfenner return NULL; 61175115Sfenner 61275115Sfenner nh = ip6->ip6_nxt; 61375115Sfenner hlen = sizeof(struct ip6_hdr); 61475115Sfenner 615147899Ssam while (bp < ep) { 61675115Sfenner bp += hlen; 61775115Sfenner 61875115Sfenner switch(nh) { 61975115Sfenner case IPPROTO_UDP: 62075115Sfenner case IPPROTO_TCP: 62175115Sfenner uh = (struct udphdr *)bp; 62275115Sfenner if (TTEST(uh->uh_dport)) { 62375115Sfenner *prot = nh; 62475115Sfenner return(uh); 62575115Sfenner } 62675115Sfenner else 62775115Sfenner return(NULL); 62875115Sfenner /* NOTREACHED */ 62975115Sfenner 63075115Sfenner case IPPROTO_HOPOPTS: 63175115Sfenner case IPPROTO_DSTOPTS: 63275115Sfenner case IPPROTO_ROUTING: 63375115Sfenner hbh = (struct ip6_hbh *)bp; 634127668Sbms if (!TTEST(hbh->ip6h_len)) 63575115Sfenner return(NULL); 63675115Sfenner nh = hbh->ip6h_nxt; 63775115Sfenner hlen = (hbh->ip6h_len + 1) << 3; 63875115Sfenner break; 63975115Sfenner 64075115Sfenner case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 64175115Sfenner fragh = (struct ip6_frag *)bp; 642127668Sbms if (!TTEST(fragh->ip6f_offlg)) 64375115Sfenner return(NULL); 64475115Sfenner /* fragments with non-zero offset are meaningless */ 645127668Sbms if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 64675115Sfenner return(NULL); 64775115Sfenner nh = fragh->ip6f_nxt; 64875115Sfenner hlen = sizeof(struct ip6_frag); 64975115Sfenner break; 65075115Sfenner 65175115Sfenner case IPPROTO_AH: 65275115Sfenner ah = (struct ah *)bp; 653127668Sbms if (!TTEST(ah->ah_len)) 65475115Sfenner return(NULL); 65575115Sfenner nh = ah->ah_nxt; 65675115Sfenner hlen = (ah->ah_len + 2) << 2; 65775115Sfenner break; 65875115Sfenner 65975115Sfenner default: /* unknown or undecodable header */ 66075115Sfenner *prot = nh; /* meaningless, but set here anyway */ 66175115Sfenner return(NULL); 66275115Sfenner } 66375115Sfenner } 66475115Sfenner 66575115Sfenner return(NULL); /* should be notreached, though */ 66675115Sfenner} 66775115Sfenner 668127668Sbmsstatic void 66998524Sfennericmp6_opt_print(const u_char *bp, int resid) 67056893Sfenner{ 67198524Sfenner const struct nd_opt_hdr *op; 67298524Sfenner const struct nd_opt_hdr *opl; /* why there's no struct? */ 67398524Sfenner const struct nd_opt_prefix_info *opp; 67498524Sfenner const struct icmp6_opts_redirect *opr; 67598524Sfenner const struct nd_opt_mtu *opm; 676214478Srpaulo const struct nd_opt_rdnss *oprd; 677252283Sdelphij const struct nd_opt_dnssl *opds; 67898524Sfenner const struct nd_opt_advinterval *opa; 679127668Sbms const struct nd_opt_homeagent_info *oph; 68098524Sfenner const struct nd_opt_route_info *opri; 681252283Sdelphij const u_char *cp, *ep, *domp; 68298524Sfenner struct in6_addr in6, *in6p; 68398524Sfenner size_t l; 684214478Srpaulo u_int i; 68556893Sfenner 68656893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 68756893Sfenner 68898524Sfenner cp = bp; 68975115Sfenner /* 'ep' points to the end of available data. */ 69056893Sfenner ep = snapend; 69156893Sfenner 69298524Sfenner while (cp < ep) { 69398524Sfenner op = (struct nd_opt_hdr *)cp; 69498524Sfenner 69598524Sfenner ECHECK(op->nd_opt_len); 69698524Sfenner if (resid <= 0) 69798524Sfenner return; 69898524Sfenner if (op->nd_opt_len == 0) 69956893Sfenner goto trunc; 70098524Sfenner if (cp + (op->nd_opt_len << 3) > ep) 70156893Sfenner goto trunc; 70298524Sfenner 703146773Ssam printf("\n\t %s option (%u), length %u (%u): ", 704146773Ssam tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 705146773Ssam op->nd_opt_type, 706146773Ssam op->nd_opt_len << 3, 707146773Ssam op->nd_opt_len); 708146773Ssam 70998524Sfenner switch (op->nd_opt_type) { 71098524Sfenner case ND_OPT_SOURCE_LINKADDR: 71198524Sfenner opl = (struct nd_opt_hdr *)op; 71298524Sfenner l = (op->nd_opt_len << 3) - 2; 71398524Sfenner print_lladdr(cp + 2, l); 71498524Sfenner break; 71598524Sfenner case ND_OPT_TARGET_LINKADDR: 71698524Sfenner opl = (struct nd_opt_hdr *)op; 71798524Sfenner l = (op->nd_opt_len << 3) - 2; 71898524Sfenner print_lladdr(cp + 2, l); 71998524Sfenner break; 72098524Sfenner case ND_OPT_PREFIX_INFORMATION: 72198524Sfenner opp = (struct nd_opt_prefix_info *)op; 72298524Sfenner TCHECK(opp->nd_opt_pi_prefix); 723252283Sdelphij printf("%s/%u%s, Flags [%s], valid time %s", 724146773Ssam ip6addr_string(&opp->nd_opt_pi_prefix), 725146773Ssam opp->nd_opt_pi_prefix_len, 726146773Ssam (op->nd_opt_len != 4) ? "badlen" : "", 727146773Ssam bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 728146773Ssam get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 729252283Sdelphij printf(", pref. time %s", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 73098524Sfenner break; 73198524Sfenner case ND_OPT_REDIRECTED_HEADER: 73298524Sfenner opr = (struct icmp6_opts_redirect *)op; 733146773Ssam print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 73498524Sfenner /* xxx */ 73598524Sfenner break; 73698524Sfenner case ND_OPT_MTU: 73798524Sfenner opm = (struct nd_opt_mtu *)op; 73898524Sfenner TCHECK(opm->nd_opt_mtu_mtu); 739146773Ssam printf(" %u%s", 740146773Ssam EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 741146773Ssam (op->nd_opt_len != 1) ? "bad option length" : "" ); 742146773Ssam break; 743214478Srpaulo case ND_OPT_RDNSS: 744214478Srpaulo oprd = (struct nd_opt_rdnss *)op; 745214478Srpaulo l = (op->nd_opt_len - 1) / 2; 746214478Srpaulo printf(" lifetime %us,", 747214478Srpaulo EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 748214478Srpaulo for (i = 0; i < l; i++) { 749214478Srpaulo TCHECK(oprd->nd_opt_rdnss_addr[i]); 750214478Srpaulo printf(" addr: %s", 751214478Srpaulo ip6addr_string(&oprd->nd_opt_rdnss_addr[i])); 752214478Srpaulo } 753214478Srpaulo break; 754252283Sdelphij case ND_OPT_DNSSL: 755252283Sdelphij opds = (struct nd_opt_dnssl *)op; 756252283Sdelphij printf(" lifetime %us, domain(s):", 757252283Sdelphij EXTRACT_32BITS(&opds->nd_opt_dnssl_lifetime)); 758252283Sdelphij domp = cp + 8; /* domain names, variable-sized, RFC1035-encoded */ 759252283Sdelphij while (domp < cp + (op->nd_opt_len << 3) && *domp != '\0') 760252283Sdelphij { 761252283Sdelphij printf (" "); 762252283Sdelphij if ((domp = ns_nprint (domp, bp)) == NULL) 763252283Sdelphij goto trunc; 764252283Sdelphij } 765252283Sdelphij break; 76698524Sfenner case ND_OPT_ADVINTERVAL: 76798524Sfenner opa = (struct nd_opt_advinterval *)op; 76898524Sfenner TCHECK(opa->nd_opt_adv_interval); 769242485Sdelphij printf(" %ums", 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