print-icmp6.c revision 147899
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_ = 24147899Ssam "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.79.2.4 2005/05/14 00:42:54 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 65146773Ssamstatic struct tok icmp6_type_values[] = { 66146773Ssam { ICMP6_DST_UNREACH, "destination unreachable"}, 67146773Ssam { ICMP6_PACKET_TOO_BIG, "packet too big"}, 68146773Ssam { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 69146773Ssam { ICMP6_PARAM_PROB, "parameter problem"}, 70146773Ssam { ICMP6_ECHO_REQUEST, "echo request"}, 71146773Ssam { ICMP6_ECHO_REPLY, "echo reply"}, 72147899Ssam { MLD6_LISTENER_QUERY, "multicast listener query"}, 73147899Ssam { MLD6_LISTENER_REPORT, "multicast listener report"}, 74147899Ssam { MLD6_LISTENER_DONE, "multicast listener done"}, 75147899Ssam { ND_ROUTER_SOLICIT, "router solicitation"}, 76146773Ssam { ND_ROUTER_ADVERT, "router advertisement"}, 77146773Ssam { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 78146773Ssam { ND_NEIGHBOR_ADVERT, "neighbor advertisment"}, 79146773Ssam { ND_REDIRECT, "redirect"}, 80146773Ssam { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 81146773Ssam { IND_SOLICIT, "inverse neighbor solicitation"}, 82146773Ssam { IND_ADVERT, "inverse neighbor advertisement"}, 83147899Ssam { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, 84146773Ssam { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 85146773Ssam { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 86146773Ssam { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 87146773Ssam { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 88146773Ssam { ICMP6_WRUREQUEST, "who-are-you request"}, 89146773Ssam { ICMP6_WRUREPLY, "who-are-you reply"}, 90146773Ssam { ICMP6_NI_QUERY, "node information query"}, 91146773Ssam { ICMP6_NI_REPLY, "node information reply"}, 92146773Ssam { MLD6_MTRACE, "mtrace message"}, 93146773Ssam { MLD6_MTRACE_RESP, "mtrace response"}, 94146773Ssam { 0, NULL } 95146773Ssam}; 96146773Ssam 97146773Ssamstatic struct tok icmp6_dst_unreach_code_values[] = { 98146773Ssam { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 99146773Ssam { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 100146773Ssam { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 101146773Ssam { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 102146773Ssam { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 103146773Ssam { 0, NULL } 104146773Ssam}; 105146773Ssam 106146773Ssamstatic struct tok icmp6_opt_pi_flag_values[] = { 107146773Ssam { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 108146773Ssam { ND_OPT_PI_FLAG_AUTO, "auto" }, 109146773Ssam { ND_OPT_PI_FLAG_ROUTER, "router" }, 110146773Ssam { 0, NULL } 111146773Ssam}; 112146773Ssam 113146773Ssamstatic struct tok icmp6_opt_ra_flag_values[] = { 114146773Ssam { ND_RA_FLAG_MANAGED, "managed" }, 115146773Ssam { ND_RA_FLAG_OTHER, "other stateful"}, 116146773Ssam { ND_RA_FLAG_HOME_AGENT, "home agent"}, 117146773Ssam { 0, NULL } 118146773Ssam}; 119146773Ssam 120146773Ssamstatic struct tok icmp6_nd_na_flag_values[] = { 121146773Ssam { ND_NA_FLAG_ROUTER, "router" }, 122146773Ssam { ND_NA_FLAG_SOLICITED, "solicited" }, 123146773Ssam { ND_NA_FLAG_OVERRIDE, "override" }, 124146773Ssam { 0, NULL } 125146773Ssam}; 126146773Ssam 127146773Ssam 128146773Ssamstatic struct tok icmp6_opt_values[] = { 129146773Ssam { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 130146773Ssam { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 131146773Ssam { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 132146773Ssam { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 133146773Ssam { ND_OPT_MTU, "mtu"}, 134146773Ssam { ND_OPT_ADVINTERVAL, "advertisment interval"}, 135146773Ssam { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 136146773Ssam { ND_OPT_ROUTE_INFO, "route info"}, 137146773Ssam { 0, NULL } 138146773Ssam}; 139146773Ssam 140146773Ssam/* mldv2 report types */ 141146773Ssamstatic struct tok mldv2report2str[] = { 142146773Ssam { 1, "is_in" }, 143146773Ssam { 2, "is_ex" }, 144146773Ssam { 3, "to_in" }, 145146773Ssam { 4, "to_ex" }, 146146773Ssam { 5, "allow" }, 147146773Ssam { 6, "block" }, 148146773Ssam { 0, NULL } 149146773Ssam}; 150146773Ssam 15198524Sfennerstatic const char * 15298524Sfennerget_rtpref(u_int v) 15398524Sfenner{ 15498524Sfenner static const char *rtpref_str[] = { 15598524Sfenner "medium", /* 00 */ 15698524Sfenner "high", /* 01 */ 15798524Sfenner "rsv", /* 10 */ 15898524Sfenner "low" /* 11 */ 15998524Sfenner }; 16098524Sfenner 16198524Sfenner return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 16298524Sfenner} 16398524Sfenner 16498524Sfennerstatic const char * 16598524Sfennerget_lifetime(u_int32_t v) 16698524Sfenner{ 16798524Sfenner static char buf[20]; 16898524Sfenner 16998524Sfenner if (v == (u_int32_t)~0UL) 17098524Sfenner return "infinity"; 17198524Sfenner else { 17298524Sfenner snprintf(buf, sizeof(buf), "%u", v); 17398524Sfenner return buf; 17498524Sfenner } 17598524Sfenner} 17698524Sfenner 17798524Sfennerstatic void 17898524Sfennerprint_lladdr(const u_int8_t *p, size_t l) 17998524Sfenner{ 18098524Sfenner const u_int8_t *ep, *q; 18198524Sfenner 18298524Sfenner q = p; 18398524Sfenner ep = p + l; 18498524Sfenner while (l > 0 && q < ep) { 18598524Sfenner if (q > p) 18698524Sfenner printf(":"); 18798524Sfenner printf("%02x", *q++); 18898524Sfenner l--; 18998524Sfenner } 19098524Sfenner} 19198524Sfenner 192127668Sbmsstatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 193127668Sbms u_int len) 194127668Sbms{ 195127668Sbms size_t i; 196127668Sbms register const u_int16_t *sp; 197127668Sbms u_int32_t sum; 198127668Sbms union { 199127668Sbms struct { 200127668Sbms struct in6_addr ph_src; 201127668Sbms struct in6_addr ph_dst; 202127668Sbms u_int32_t ph_len; 203127668Sbms u_int8_t ph_zero[3]; 204127668Sbms u_int8_t ph_nxt; 205127668Sbms } ph; 206127668Sbms u_int16_t pa[20]; 207127668Sbms } phu; 208127668Sbms 209127668Sbms /* pseudo-header */ 210127668Sbms memset(&phu, 0, sizeof(phu)); 211127668Sbms phu.ph.ph_src = ip6->ip6_src; 212127668Sbms phu.ph.ph_dst = ip6->ip6_dst; 213127668Sbms phu.ph.ph_len = htonl(len); 214127668Sbms phu.ph.ph_nxt = IPPROTO_ICMPV6; 215127668Sbms 216127668Sbms sum = 0; 217127668Sbms for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 218127668Sbms sum += phu.pa[i]; 219127668Sbms 220127668Sbms sp = (const u_int16_t *)icp; 221127668Sbms 222127668Sbms for (i = 0; i < (len & ~1); i += 2) 223127668Sbms sum += *sp++; 224127668Sbms 225127668Sbms if (len & 1) 226127668Sbms sum += htons((*(const u_int8_t *)sp) << 8); 227127668Sbms 228127668Sbms while (sum > 0xffff) 229127668Sbms sum = (sum & 0xffff) + (sum >> 16); 230127668Sbms sum = ~sum & 0xffff; 231127668Sbms 232127668Sbms return (sum); 233127668Sbms} 234127668Sbms 23556893Sfennervoid 236127668Sbmsicmp6_print(const u_char *bp, u_int length, const u_char *bp2, int fragmented) 23756893Sfenner{ 23875115Sfenner const struct icmp6_hdr *dp; 23998524Sfenner const struct ip6_hdr *ip; 24098524Sfenner const struct ip6_hdr *oip; 24198524Sfenner const struct udphdr *ouh; 24298524Sfenner int dport; 24398524Sfenner const u_char *ep; 244127668Sbms u_int prot; 24556893Sfenner 24656893Sfenner dp = (struct icmp6_hdr *)bp; 24756893Sfenner ip = (struct ip6_hdr *)bp2; 24856893Sfenner oip = (struct ip6_hdr *)(dp + 1); 24975115Sfenner /* 'ep' points to the end of available data. */ 25056893Sfenner ep = snapend; 25156893Sfenner 252127668Sbms TCHECK(dp->icmp6_cksum); 253127668Sbms 254127668Sbms if (vflag && !fragmented) { 255127668Sbms int sum = dp->icmp6_cksum; 256127668Sbms 257127668Sbms if (TTEST2(bp[0], length)) { 258127668Sbms sum = icmp6_cksum(ip, dp, length); 259127668Sbms if (sum != 0) 260127668Sbms (void)printf("[bad icmp6 cksum %x!] ", sum); 261127668Sbms else 262127668Sbms (void)printf("[icmp6 sum ok] "); 263127668Sbms } 264127668Sbms } 265127668Sbms 266146773Ssam printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 267146773Ssam 268146773Ssam /* display cosmetics: print the packet length for printer that use the vflag now */ 269146773Ssam if (vflag && (dp->icmp6_type == 270146773Ssam ND_ROUTER_SOLICIT || 271146773Ssam ND_ROUTER_ADVERT || 272146773Ssam ND_NEIGHBOR_ADVERT || 273146773Ssam ND_NEIGHBOR_SOLICIT || 274146773Ssam ND_REDIRECT || 275146773Ssam ICMP6_HADISCOV_REPLY || 276146773Ssam ICMP6_MOBILEPREFIX_ADVERT )) 277146773Ssam printf(", length %u", length); 278146773Ssam 27975115Sfenner switch (dp->icmp6_type) { 28056893Sfenner case ICMP6_DST_UNREACH: 28156893Sfenner TCHECK(oip->ip6_dst); 282146773Ssam printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 28356893Sfenner switch (dp->icmp6_code) { 284146773Ssam 285146773Ssam case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 28656893Sfenner case ICMP6_DST_UNREACH_ADMIN: 287146773Ssam case ICMP6_DST_UNREACH_ADDR: 288146773Ssam printf(" %s",ip6addr_string(&oip->ip6_dst)); 289146773Ssam break; 29056893Sfenner case ICMP6_DST_UNREACH_BEYONDSCOPE: 291146773Ssam printf(" %s, source address %s", 29256893Sfenner ip6addr_string(&oip->ip6_dst), 29356893Sfenner ip6addr_string(&oip->ip6_src)); 29456893Sfenner break; 29556893Sfenner case ICMP6_DST_UNREACH_NOPORT: 29675115Sfenner if ((ouh = get_upperlayer((u_char *)oip, &prot)) 29775115Sfenner == NULL) 29875115Sfenner goto trunc; 29975115Sfenner 300127668Sbms dport = EXTRACT_16BITS(&ouh->uh_dport); 30175115Sfenner switch (prot) { 30256893Sfenner case IPPROTO_TCP: 303146773Ssam printf(", %s tcp port %s", 30456893Sfenner ip6addr_string(&oip->ip6_dst), 30556893Sfenner tcpport_string(dport)); 30656893Sfenner break; 30756893Sfenner case IPPROTO_UDP: 308146773Ssam printf(", %s udp port %s", 30956893Sfenner ip6addr_string(&oip->ip6_dst), 31056893Sfenner udpport_string(dport)); 31156893Sfenner break; 31256893Sfenner default: 313146773Ssam printf(", %s protocol %d port %d unreachable", 31456893Sfenner ip6addr_string(&oip->ip6_dst), 31556893Sfenner oip->ip6_nxt, dport); 31656893Sfenner break; 31756893Sfenner } 31856893Sfenner break; 31956893Sfenner default: 320146773Ssam if (vflag <= 1) { 321146773Ssam print_unknown_data(bp,"\n\t",length); 322146773Ssam return; 323146773Ssam } 324146773Ssam break; 32556893Sfenner } 32656893Sfenner break; 32756893Sfenner case ICMP6_PACKET_TOO_BIG: 32856893Sfenner TCHECK(dp->icmp6_mtu); 329146773Ssam printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 33056893Sfenner break; 33156893Sfenner case ICMP6_TIME_EXCEEDED: 33256893Sfenner TCHECK(oip->ip6_dst); 33356893Sfenner switch (dp->icmp6_code) { 33456893Sfenner case ICMP6_TIME_EXCEED_TRANSIT: 335146773Ssam printf(" for %s", 33656893Sfenner ip6addr_string(&oip->ip6_dst)); 33756893Sfenner break; 33856893Sfenner case ICMP6_TIME_EXCEED_REASSEMBLY: 339146773Ssam printf(" (reassembly)"); 34056893Sfenner break; 34156893Sfenner default: 342146773Ssam printf(", unknown code (%u)", dp->icmp6_code); 34356893Sfenner break; 34456893Sfenner } 34556893Sfenner break; 34656893Sfenner case ICMP6_PARAM_PROB: 34756893Sfenner TCHECK(oip->ip6_dst); 34856893Sfenner switch (dp->icmp6_code) { 34956893Sfenner case ICMP6_PARAMPROB_HEADER: 350146773Ssam printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35156893Sfenner break; 35256893Sfenner case ICMP6_PARAMPROB_NEXTHEADER: 353146773Ssam printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35456893Sfenner break; 35556893Sfenner case ICMP6_PARAMPROB_OPTION: 356146773Ssam printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 35756893Sfenner break; 35856893Sfenner default: 359146773Ssam printf(", code-#%d", 36056893Sfenner dp->icmp6_code); 36156893Sfenner break; 36256893Sfenner } 36356893Sfenner break; 36456893Sfenner case ICMP6_ECHO_REQUEST: 36556893Sfenner case ICMP6_ECHO_REPLY: 366127668Sbms TCHECK(dp->icmp6_seq); 367146773Ssam printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 36856893Sfenner break; 36956893Sfenner case ICMP6_MEMBERSHIP_QUERY: 370146773Ssam if (length == MLD_MINLEN) { 371146773Ssam mld6_print((const u_char *)dp); 372146773Ssam } else if (length >= MLDV2_MINLEN) { 373146773Ssam printf("v2 "); 374146773Ssam mldv2_query_print((const u_char *)dp, length); 375146773Ssam } else { 376146773Ssam printf(" unknown-version (len %u) ", length); 377146773Ssam } 37856893Sfenner break; 37956893Sfenner case ICMP6_MEMBERSHIP_REPORT: 38056893Sfenner mld6_print((const u_char *)dp); 38156893Sfenner break; 38256893Sfenner case ICMP6_MEMBERSHIP_REDUCTION: 38356893Sfenner mld6_print((const u_char *)dp); 38456893Sfenner break; 38556893Sfenner case ND_ROUTER_SOLICIT: 386146773Ssam#define RTSOLLEN 8 38756893Sfenner if (vflag) { 38875115Sfenner icmp6_opt_print((const u_char *)dp + RTSOLLEN, 389127668Sbms length - RTSOLLEN); 39056893Sfenner } 39156893Sfenner break; 39256893Sfenner case ND_ROUTER_ADVERT: 393146773Ssam#define RTADVLEN 16 39456893Sfenner if (vflag) { 39556893Sfenner struct nd_router_advert *p; 39656893Sfenner 39756893Sfenner p = (struct nd_router_advert *)dp; 39856893Sfenner TCHECK(p->nd_ra_retransmit); 399146773Ssam printf("\n\thop limit %u, Flags [%s]" \ 400146773Ssam ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 401146773Ssam (u_int)p->nd_ra_curhoplimit, 402146773Ssam bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 403146773Ssam get_rtpref(p->nd_ra_flags_reserved), 404146773Ssam EXTRACT_16BITS(&p->nd_ra_router_lifetime), 405146773Ssam EXTRACT_32BITS(&p->nd_ra_reachable), 406146773Ssam EXTRACT_32BITS(&p->nd_ra_retransmit)); 40798524Sfenner 40875115Sfenner icmp6_opt_print((const u_char *)dp + RTADVLEN, 409127668Sbms length - RTADVLEN); 41056893Sfenner } 41156893Sfenner break; 41256893Sfenner case ND_NEIGHBOR_SOLICIT: 41356893Sfenner { 41456893Sfenner struct nd_neighbor_solicit *p; 41556893Sfenner p = (struct nd_neighbor_solicit *)dp; 41656893Sfenner TCHECK(p->nd_ns_target); 417146773Ssam printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 41856893Sfenner if (vflag) { 41956893Sfenner#define NDSOLLEN 24 42075115Sfenner icmp6_opt_print((const u_char *)dp + NDSOLLEN, 421127668Sbms length - NDSOLLEN); 42256893Sfenner } 42356893Sfenner } 42456893Sfenner break; 42556893Sfenner case ND_NEIGHBOR_ADVERT: 42656893Sfenner { 42756893Sfenner struct nd_neighbor_advert *p; 42856893Sfenner 42956893Sfenner p = (struct nd_neighbor_advert *)dp; 43056893Sfenner TCHECK(p->nd_na_target); 431146773Ssam printf(", tgt is %s", 43256893Sfenner ip6addr_string(&p->nd_na_target)); 43375115Sfenner if (vflag) { 434146773Ssam printf(", Flags [%s]", 435146773Ssam bittok2str(icmp6_nd_na_flag_values, 436146773Ssam "none", 437146773Ssam EXTRACT_32BITS(&p->nd_na_flags_reserved))); 43856893Sfenner#define NDADVLEN 24 43975115Sfenner icmp6_opt_print((const u_char *)dp + NDADVLEN, 440127668Sbms length - NDADVLEN); 44175115Sfenner#undef NDADVLEN 44256893Sfenner } 44356893Sfenner } 44456893Sfenner break; 44556893Sfenner case ND_REDIRECT: 44656893Sfenner#define RDR(i) ((struct nd_redirect *)(i)) 44756893Sfenner TCHECK(RDR(dp)->nd_rd_dst); 448146773Ssam printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 449127668Sbms TCHECK(RDR(dp)->nd_rd_target); 45075115Sfenner printf(" to %s", 45175115Sfenner getname6((const u_char*)&RDR(dp)->nd_rd_target)); 45256893Sfenner#define REDIRECTLEN 40 45356893Sfenner if (vflag) { 45456893Sfenner icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 455127668Sbms length - REDIRECTLEN); 45656893Sfenner } 45756893Sfenner break; 45875115Sfenner#undef REDIRECTLEN 45975115Sfenner#undef RDR 46056893Sfenner case ICMP6_ROUTER_RENUMBERING: 461127668Sbms icmp6_rrenum_print(bp, ep); 46256893Sfenner break; 46375115Sfenner case ICMP6_NI_QUERY: 46475115Sfenner case ICMP6_NI_REPLY: 465127668Sbms icmp6_nodeinfo_print(length, bp, ep); 46656893Sfenner break; 467146773Ssam case IND_SOLICIT: 468146773Ssam case IND_ADVERT: 469146773Ssam break; 470146773Ssam case ICMP6_V2_MEMBERSHIP_REPORT: 471146773Ssam mldv2_report_print((const u_char *) dp, length); 472146773Ssam break; 473146773Ssam case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 474127668Sbms case ICMP6_HADISCOV_REQUEST: 475146773Ssam TCHECK(dp->icmp6_data16[0]); 476146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 477146773Ssam break; 478127668Sbms case ICMP6_HADISCOV_REPLY: 479127668Sbms if (vflag) { 480127668Sbms struct in6_addr *in6; 481127668Sbms u_char *cp; 482127668Sbms 483127668Sbms TCHECK(dp->icmp6_data16[0]); 484146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 485127668Sbms cp = (u_char *)dp + length; 486127668Sbms in6 = (struct in6_addr *)(dp + 1); 487127668Sbms for (; (u_char *)in6 < cp; in6++) { 488127668Sbms TCHECK(*in6); 489127668Sbms printf(", %s", ip6addr_string(in6)); 490127668Sbms } 491127668Sbms } 492127668Sbms break; 493127668Sbms case ICMP6_MOBILEPREFIX_ADVERT: 494127668Sbms if (vflag) { 495127668Sbms TCHECK(dp->icmp6_data16[0]); 496146773Ssam printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 497127668Sbms if (dp->icmp6_data16[1] & 0xc0) 498127668Sbms printf(" "); 499127668Sbms if (dp->icmp6_data16[1] & 0x80) 500127668Sbms printf("M"); 501127668Sbms if (dp->icmp6_data16[1] & 0x40) 502127668Sbms printf("O"); 503127668Sbms#define MPADVLEN 8 504127668Sbms icmp6_opt_print((const u_char *)dp + MPADVLEN, 505127668Sbms length - MPADVLEN); 506127668Sbms } 507127668Sbms break; 50856893Sfenner default: 509146773Ssam printf(", length %u", length); 510146773Ssam if (vflag <= 1) 511146773Ssam print_unknown_data(bp,"\n\t", length); 512146773Ssam return; 513146773Ssam } 514146773Ssam if (!vflag) 515146773Ssam printf(", length %u", length); 51656893Sfenner return; 51756893Sfennertrunc: 51856893Sfenner fputs("[|icmp6]", stdout); 51956893Sfenner} 52056893Sfenner 52175115Sfennerstatic struct udphdr * 522127668Sbmsget_upperlayer(u_char *bp, u_int *prot) 52375115Sfenner{ 52498524Sfenner const u_char *ep; 52575115Sfenner struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 52675115Sfenner struct udphdr *uh; 52775115Sfenner struct ip6_hbh *hbh; 52875115Sfenner struct ip6_frag *fragh; 52975115Sfenner struct ah *ah; 530127668Sbms u_int nh; 531127668Sbms int hlen; 53275115Sfenner 53375115Sfenner /* 'ep' points to the end of available data. */ 53475115Sfenner ep = snapend; 53575115Sfenner 536127668Sbms if (!TTEST(ip6->ip6_nxt)) 53775115Sfenner return NULL; 53875115Sfenner 53975115Sfenner nh = ip6->ip6_nxt; 54075115Sfenner hlen = sizeof(struct ip6_hdr); 54175115Sfenner 542147899Ssam while (bp < ep) { 54375115Sfenner bp += hlen; 54475115Sfenner 54575115Sfenner switch(nh) { 54675115Sfenner case IPPROTO_UDP: 54775115Sfenner case IPPROTO_TCP: 54875115Sfenner uh = (struct udphdr *)bp; 54975115Sfenner if (TTEST(uh->uh_dport)) { 55075115Sfenner *prot = nh; 55175115Sfenner return(uh); 55275115Sfenner } 55375115Sfenner else 55475115Sfenner return(NULL); 55575115Sfenner /* NOTREACHED */ 55675115Sfenner 55775115Sfenner case IPPROTO_HOPOPTS: 55875115Sfenner case IPPROTO_DSTOPTS: 55975115Sfenner case IPPROTO_ROUTING: 56075115Sfenner hbh = (struct ip6_hbh *)bp; 561127668Sbms if (!TTEST(hbh->ip6h_len)) 56275115Sfenner return(NULL); 56375115Sfenner nh = hbh->ip6h_nxt; 56475115Sfenner hlen = (hbh->ip6h_len + 1) << 3; 56575115Sfenner break; 56675115Sfenner 56775115Sfenner case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 56875115Sfenner fragh = (struct ip6_frag *)bp; 569127668Sbms if (!TTEST(fragh->ip6f_offlg)) 57075115Sfenner return(NULL); 57175115Sfenner /* fragments with non-zero offset are meaningless */ 572127668Sbms if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 57375115Sfenner return(NULL); 57475115Sfenner nh = fragh->ip6f_nxt; 57575115Sfenner hlen = sizeof(struct ip6_frag); 57675115Sfenner break; 57775115Sfenner 57875115Sfenner case IPPROTO_AH: 57975115Sfenner ah = (struct ah *)bp; 580127668Sbms if (!TTEST(ah->ah_len)) 58175115Sfenner return(NULL); 58275115Sfenner nh = ah->ah_nxt; 58375115Sfenner hlen = (ah->ah_len + 2) << 2; 58475115Sfenner break; 58575115Sfenner 58675115Sfenner default: /* unknown or undecodable header */ 58775115Sfenner *prot = nh; /* meaningless, but set here anyway */ 58875115Sfenner return(NULL); 58975115Sfenner } 59075115Sfenner } 59175115Sfenner 59275115Sfenner return(NULL); /* should be notreached, though */ 59375115Sfenner} 59475115Sfenner 595127668Sbmsstatic void 59698524Sfennericmp6_opt_print(const u_char *bp, int resid) 59756893Sfenner{ 59898524Sfenner const struct nd_opt_hdr *op; 59998524Sfenner const struct nd_opt_hdr *opl; /* why there's no struct? */ 60098524Sfenner const struct nd_opt_prefix_info *opp; 60198524Sfenner const struct icmp6_opts_redirect *opr; 60298524Sfenner const struct nd_opt_mtu *opm; 60398524Sfenner const struct nd_opt_advinterval *opa; 604127668Sbms const struct nd_opt_homeagent_info *oph; 60598524Sfenner const struct nd_opt_route_info *opri; 60698524Sfenner const u_char *cp, *ep; 60798524Sfenner struct in6_addr in6, *in6p; 60898524Sfenner size_t l; 60956893Sfenner 61056893Sfenner#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 61156893Sfenner 61298524Sfenner cp = bp; 61375115Sfenner /* 'ep' points to the end of available data. */ 61456893Sfenner ep = snapend; 61556893Sfenner 61698524Sfenner while (cp < ep) { 61798524Sfenner op = (struct nd_opt_hdr *)cp; 61898524Sfenner 61998524Sfenner ECHECK(op->nd_opt_len); 62098524Sfenner if (resid <= 0) 62198524Sfenner return; 62298524Sfenner if (op->nd_opt_len == 0) 62356893Sfenner goto trunc; 62498524Sfenner if (cp + (op->nd_opt_len << 3) > ep) 62556893Sfenner goto trunc; 62698524Sfenner 627146773Ssam printf("\n\t %s option (%u), length %u (%u): ", 628146773Ssam tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 629146773Ssam op->nd_opt_type, 630146773Ssam op->nd_opt_len << 3, 631146773Ssam op->nd_opt_len); 632146773Ssam 63398524Sfenner switch (op->nd_opt_type) { 63498524Sfenner case ND_OPT_SOURCE_LINKADDR: 63598524Sfenner opl = (struct nd_opt_hdr *)op; 63698524Sfenner l = (op->nd_opt_len << 3) - 2; 63798524Sfenner print_lladdr(cp + 2, l); 63898524Sfenner break; 63998524Sfenner case ND_OPT_TARGET_LINKADDR: 64098524Sfenner opl = (struct nd_opt_hdr *)op; 64198524Sfenner l = (op->nd_opt_len << 3) - 2; 64298524Sfenner print_lladdr(cp + 2, l); 64398524Sfenner break; 64498524Sfenner case ND_OPT_PREFIX_INFORMATION: 64598524Sfenner opp = (struct nd_opt_prefix_info *)op; 64698524Sfenner TCHECK(opp->nd_opt_pi_prefix); 647146773Ssam printf("%s/%u%s, Flags [%s], valid time %ss", 648146773Ssam ip6addr_string(&opp->nd_opt_pi_prefix), 649146773Ssam opp->nd_opt_pi_prefix_len, 650146773Ssam (op->nd_opt_len != 4) ? "badlen" : "", 651146773Ssam bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 652146773Ssam get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 653146773Ssam printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 65498524Sfenner break; 65598524Sfenner case ND_OPT_REDIRECTED_HEADER: 65698524Sfenner opr = (struct icmp6_opts_redirect *)op; 657146773Ssam print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 65898524Sfenner /* xxx */ 65998524Sfenner break; 66098524Sfenner case ND_OPT_MTU: 66198524Sfenner opm = (struct nd_opt_mtu *)op; 66298524Sfenner TCHECK(opm->nd_opt_mtu_mtu); 663146773Ssam printf(" %u%s", 664146773Ssam EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 665146773Ssam (op->nd_opt_len != 1) ? "bad option length" : "" ); 666146773Ssam break; 66798524Sfenner case ND_OPT_ADVINTERVAL: 66898524Sfenner opa = (struct nd_opt_advinterval *)op; 66998524Sfenner TCHECK(opa->nd_opt_adv_interval); 670146773Ssam printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 671127668Sbms break; 672127668Sbms case ND_OPT_HOMEAGENT_INFO: 673127668Sbms oph = (struct nd_opt_homeagent_info *)op; 674127668Sbms TCHECK(oph->nd_opt_hai_lifetime); 675146773Ssam printf(" preference %u, lifetime %u", 676146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_preference), 677146773Ssam EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 678127668Sbms break; 67998524Sfenner case ND_OPT_ROUTE_INFO: 68098524Sfenner opri = (struct nd_opt_route_info *)op; 68198524Sfenner TCHECK(opri->nd_opt_rti_lifetime); 68298524Sfenner memset(&in6, 0, sizeof(in6)); 68398524Sfenner in6p = (struct in6_addr *)(opri + 1); 68498524Sfenner switch (op->nd_opt_len) { 68598524Sfenner case 1: 68698524Sfenner break; 68798524Sfenner case 2: 68898524Sfenner TCHECK2(*in6p, 8); 68998524Sfenner memcpy(&in6, opri + 1, 8); 69098524Sfenner break; 69198524Sfenner case 3: 69298524Sfenner TCHECK(*in6p); 69398524Sfenner memcpy(&in6, opri + 1, sizeof(in6)); 69498524Sfenner break; 69598524Sfenner default: 69698524Sfenner goto trunc; 69798524Sfenner } 69898524Sfenner printf(" %s/%u", ip6addr_string(&in6), 69998524Sfenner opri->nd_opt_rti_prefixlen); 70098524Sfenner printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 70198524Sfenner printf(", lifetime=%s", 702127668Sbms get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 70398524Sfenner break; 70498524Sfenner default: 705146773Ssam if (vflag <= 1) { 706146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 707146773Ssam return; 708146773Ssam } 709146773Ssam break; 71056893Sfenner } 711146773Ssam /* do we want to see an additional hexdump ? */ 712146773Ssam if (vflag> 1) 713146773Ssam print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 71498524Sfenner 71598524Sfenner cp += op->nd_opt_len << 3; 71698524Sfenner resid -= op->nd_opt_len << 3; 71756893Sfenner } 71856893Sfenner return; 71998524Sfenner 72056893Sfenner trunc: 72156893Sfenner fputs("[ndp opt]", stdout); 72256893Sfenner return; 72356893Sfenner#undef ECHECK 72456893Sfenner} 72556893Sfenner 726127668Sbmsstatic void 72798524Sfennermld6_print(const u_char *bp) 72856893Sfenner{ 72998524Sfenner struct mld6_hdr *mp = (struct mld6_hdr *)bp; 73098524Sfenner const u_char *ep; 73156893Sfenner 73275115Sfenner /* 'ep' points to the end of available data. */ 73356893Sfenner ep = snapend; 73456893Sfenner 73556893Sfenner if ((u_char *)mp + sizeof(*mp) > ep) 73656893Sfenner return; 73756893Sfenner 738127668Sbms printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 73956893Sfenner printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 74075115Sfenner} 74156893Sfenner 74275115Sfennerstatic void 743146773Ssammldv2_report_print(const u_char *bp, u_int len) 744146773Ssam{ 745146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 746146773Ssam u_int group, nsrcs, ngroups; 747146773Ssam u_int i, j; 748146773Ssam 749146773Ssam /* Minimum len is 8 */ 750146773Ssam if (len < 8) { 751146773Ssam printf(" [invalid len %d]", len); 752146773Ssam return; 753146773Ssam } 754146773Ssam 755146773Ssam TCHECK(icp->icmp6_data16[1]); 756146773Ssam ngroups = ntohs(icp->icmp6_data16[1]); 757146773Ssam printf(", %d group record(s)", ngroups); 758146773Ssam if (vflag > 0) { 759146773Ssam /* Print the group records */ 760146773Ssam group = 8; 761146773Ssam for (i = 0; i < ngroups; i++) { 762146773Ssam /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 763146773Ssam if (len < group + 20) { 764146773Ssam printf(" [invalid number of groups]"); 765146773Ssam return; 766146773Ssam } 767146773Ssam TCHECK2(bp[group + 4], 16); 768146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 769146773Ssam printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 770146773Ssam bp[group])); 771146773Ssam nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 772146773Ssam /* Check the number of sources and print them */ 773146773Ssam if (len < group + 20 + (nsrcs * 16)) { 774146773Ssam printf(" [invalid number of sources %d]", nsrcs); 775146773Ssam return; 776146773Ssam } 777146773Ssam if (vflag == 1) 778146773Ssam printf(", %d source(s)", nsrcs); 779146773Ssam else { 780146773Ssam /* Print the sources */ 781146773Ssam (void)printf(" {"); 782146773Ssam for (j = 0; j < nsrcs; j++) { 783146773Ssam TCHECK2(bp[group + 20 + j * 16], 16); 784146773Ssam printf(" %s", ip6addr_string(&bp[group + 20 + j * 16])); 785146773Ssam } 786146773Ssam (void)printf(" }"); 787146773Ssam } 788146773Ssam /* Next group record */ 789146773Ssam group += 20 + nsrcs * 16; 790146773Ssam printf("]"); 791146773Ssam } 792146773Ssam } 793146773Ssam return; 794146773Ssamtrunc: 795146773Ssam (void)printf("[|icmp6]"); 796146773Ssam return; 797146773Ssam} 798146773Ssam 799146773Ssamstatic void 800146773Ssammldv2_query_print(const u_char *bp, u_int len) 801146773Ssam{ 802146773Ssam struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 803146773Ssam u_int mrc; 804146773Ssam int mrt, qqi; 805146773Ssam u_int nsrcs; 806146773Ssam register u_int i; 807146773Ssam 808146773Ssam /* Minimum len is 28 */ 809146773Ssam if (len < 28) { 810146773Ssam printf(" [invalid len %d]", len); 811146773Ssam return; 812146773Ssam } 813146773Ssam TCHECK(icp->icmp6_data16[0]); 814146773Ssam mrc = ntohs(icp->icmp6_data16[0]); 815146773Ssam if (mrc < 32768) { 816146773Ssam mrt = mrc; 817146773Ssam } else { 818146773Ssam mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 819146773Ssam } 820146773Ssam if (vflag) { 821146773Ssam (void)printf(" [max resp delay=%d]", mrt); 822146773Ssam } 823146773Ssam TCHECK2(bp[8], 16); 824146773Ssam printf(" [gaddr %s", ip6addr_string(&bp[8])); 825146773Ssam 826146773Ssam if (vflag) { 827146773Ssam TCHECK(bp[25]); 828146773Ssam if (bp[24] & 0x08) { 829146773Ssam printf(" sflag"); 830146773Ssam } 831146773Ssam if (bp[24] & 0x07) { 832146773Ssam printf(" robustness=%d", bp[24] & 0x07); 833146773Ssam } 834146773Ssam if (bp[25] < 128) { 835146773Ssam qqi = bp[25]; 836146773Ssam } else { 837146773Ssam qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 838146773Ssam } 839146773Ssam printf(" qqi=%d", qqi); 840146773Ssam } 841146773Ssam 842146773Ssam TCHECK2(bp[26], 2); 843146773Ssam nsrcs = ntohs(*(u_short *)&bp[26]); 844146773Ssam if (nsrcs > 0) { 845146773Ssam if (len < 28 + nsrcs * 16) 846146773Ssam printf(" [invalid number of sources]"); 847146773Ssam else if (vflag > 1) { 848146773Ssam printf(" {"); 849146773Ssam for (i = 0; i < nsrcs; i++) { 850146773Ssam TCHECK2(bp[28 + i * 16], 16); 851146773Ssam printf(" %s", ip6addr_string(&bp[28 + i * 16])); 852146773Ssam } 853146773Ssam printf(" }"); 854146773Ssam } else 855146773Ssam printf(", %d source(s)", nsrcs); 856146773Ssam } 857146773Ssam printf("]"); 858146773Ssam return; 859146773Ssamtrunc: 860146773Ssam (void)printf("[|icmp6]"); 861146773Ssam return; 862146773Ssam} 863146773Ssam 864146773Ssamvoid 86575115Sfennerdnsname_print(const u_char *cp, const u_char *ep) 86675115Sfenner{ 86775115Sfenner int i; 86875115Sfenner 86975115Sfenner /* DNS name decoding - no decompression */ 87075115Sfenner printf(", \""); 87175115Sfenner while (cp < ep) { 87275115Sfenner i = *cp++; 87375115Sfenner if (i) { 87475115Sfenner if (i > ep - cp) { 87575115Sfenner printf("???"); 87675115Sfenner break; 87775115Sfenner } 87875115Sfenner while (i-- && cp < ep) { 87975115Sfenner safeputchar(*cp); 88075115Sfenner cp++; 88175115Sfenner } 88275115Sfenner if (cp + 1 < ep && *cp) 88375115Sfenner printf("."); 88475115Sfenner } else { 88575115Sfenner if (cp == ep) { 88675115Sfenner /* FQDN */ 88775115Sfenner printf("."); 88875115Sfenner } else if (cp + 1 == ep && *cp == '\0') { 88975115Sfenner /* truncated */ 89075115Sfenner } else { 89175115Sfenner /* invalid */ 89275115Sfenner printf("???"); 89375115Sfenner } 89475115Sfenner break; 89575115Sfenner } 89675115Sfenner } 89775115Sfenner printf("\""); 89875115Sfenner} 89975115Sfenner 900127668Sbmsstatic void 901127668Sbmsicmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 90275115Sfenner{ 90375115Sfenner struct icmp6_nodeinfo *ni6; 90475115Sfenner struct icmp6_hdr *dp; 90575115Sfenner const u_char *cp; 906127668Sbms size_t siz, i; 90775115Sfenner int needcomma; 90875115Sfenner 909127668Sbms if (ep < bp) 910127668Sbms return; 91175115Sfenner dp = (struct icmp6_hdr *)bp; 91275115Sfenner ni6 = (struct icmp6_nodeinfo *)bp; 91375115Sfenner siz = ep - bp; 91475115Sfenner 91575115Sfenner switch (ni6->ni_type) { 91675115Sfenner case ICMP6_NI_QUERY: 91775115Sfenner if (siz == sizeof(*dp) + 4) { 91875115Sfenner /* KAME who-are-you */ 919146773Ssam printf(" who-are-you request"); 92075115Sfenner break; 92175115Sfenner } 922146773Ssam printf(" node information query"); 92375115Sfenner 92475115Sfenner TCHECK2(*dp, sizeof(*ni6)); 92575115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 92675115Sfenner printf(" ("); /*)*/ 927127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 92875115Sfenner case NI_QTYPE_NOOP: 92975115Sfenner printf("noop"); 93075115Sfenner break; 93175115Sfenner case NI_QTYPE_SUPTYPES: 93275115Sfenner printf("supported qtypes"); 933127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 93475115Sfenner if (i) 93575115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 93675115Sfenner break; 93775115Sfenner break; 93875115Sfenner case NI_QTYPE_FQDN: 93975115Sfenner printf("DNS name"); 94075115Sfenner break; 94175115Sfenner case NI_QTYPE_NODEADDR: 94275115Sfenner printf("node addresses"); 94375115Sfenner i = ni6->ni_flags; 94475115Sfenner if (!i) 94575115Sfenner break; 94675115Sfenner /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 94775115Sfenner printf(" [%s%s%s%s%s%s]", 94875115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 94975115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 95075115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 95175115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 95275115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 95375115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 95475115Sfenner break; 95575115Sfenner default: 95675115Sfenner printf("unknown"); 95775115Sfenner break; 95875115Sfenner } 95975115Sfenner 96075115Sfenner if (ni6->ni_qtype == NI_QTYPE_NOOP || 96175115Sfenner ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 96275115Sfenner if (siz != sizeof(*ni6)) 96375115Sfenner if (vflag) 96475115Sfenner printf(", invalid len"); 96575115Sfenner /*(*/ 96675115Sfenner printf(")"); 96775115Sfenner break; 96875115Sfenner } 96975115Sfenner 97075115Sfenner 97175115Sfenner /* XXX backward compat, icmp-name-lookup-03 */ 97275115Sfenner if (siz == sizeof(*ni6)) { 97375115Sfenner printf(", 03 draft"); 97475115Sfenner /*(*/ 97575115Sfenner printf(")"); 97675115Sfenner break; 97775115Sfenner } 97875115Sfenner 97975115Sfenner switch (ni6->ni_code) { 98075115Sfenner case ICMP6_NI_SUBJ_IPV6: 98175115Sfenner if (!TTEST2(*dp, 98275115Sfenner sizeof(*ni6) + sizeof(struct in6_addr))) 98375115Sfenner break; 98475115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 98575115Sfenner if (vflag) 98675115Sfenner printf(", invalid subject len"); 98775115Sfenner break; 98875115Sfenner } 98975115Sfenner printf(", subject=%s", 99075115Sfenner getname6((const u_char *)(ni6 + 1))); 99175115Sfenner break; 99275115Sfenner case ICMP6_NI_SUBJ_FQDN: 99375115Sfenner printf(", subject=DNS name"); 99475115Sfenner cp = (const u_char *)(ni6 + 1); 99575115Sfenner if (cp[0] == ep - cp - 1) { 99675115Sfenner /* icmp-name-lookup-03, pascal string */ 99775115Sfenner if (vflag) 99875115Sfenner printf(", 03 draft"); 99975115Sfenner cp++; 100075115Sfenner printf(", \""); 100175115Sfenner while (cp < ep) { 100275115Sfenner safeputchar(*cp); 100375115Sfenner cp++; 100475115Sfenner } 100575115Sfenner printf("\""); 100675115Sfenner } else 100775115Sfenner dnsname_print(cp, ep); 100875115Sfenner break; 100975115Sfenner case ICMP6_NI_SUBJ_IPV4: 101075115Sfenner if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 101175115Sfenner break; 101275115Sfenner if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 101375115Sfenner if (vflag) 101475115Sfenner printf(", invalid subject len"); 101575115Sfenner break; 101675115Sfenner } 101775115Sfenner printf(", subject=%s", 101875115Sfenner getname((const u_char *)(ni6 + 1))); 101975115Sfenner break; 102075115Sfenner default: 102175115Sfenner printf(", unknown subject"); 102275115Sfenner break; 102375115Sfenner } 102475115Sfenner 102575115Sfenner /*(*/ 102675115Sfenner printf(")"); 102775115Sfenner break; 102875115Sfenner 102975115Sfenner case ICMP6_NI_REPLY: 103075115Sfenner if (icmp6len > siz) { 103175115Sfenner printf("[|icmp6: node information reply]"); 103275115Sfenner break; 103375115Sfenner } 103475115Sfenner 103575115Sfenner needcomma = 0; 103675115Sfenner 103775115Sfenner ni6 = (struct icmp6_nodeinfo *)dp; 1038146773Ssam printf(" node information reply"); 103975115Sfenner printf(" ("); /*)*/ 104075115Sfenner switch (ni6->ni_code) { 104175115Sfenner case ICMP6_NI_SUCCESS: 104275115Sfenner if (vflag) { 104375115Sfenner printf("success"); 104475115Sfenner needcomma++; 104575115Sfenner } 104675115Sfenner break; 104775115Sfenner case ICMP6_NI_REFUSED: 104875115Sfenner printf("refused"); 104975115Sfenner needcomma++; 105075115Sfenner if (siz != sizeof(*ni6)) 105175115Sfenner if (vflag) 105275115Sfenner printf(", invalid length"); 105375115Sfenner break; 105475115Sfenner case ICMP6_NI_UNKNOWN: 105575115Sfenner printf("unknown"); 105675115Sfenner needcomma++; 105775115Sfenner if (siz != sizeof(*ni6)) 105875115Sfenner if (vflag) 105975115Sfenner printf(", invalid length"); 106075115Sfenner break; 106175115Sfenner } 106275115Sfenner 106375115Sfenner if (ni6->ni_code != ICMP6_NI_SUCCESS) { 106475115Sfenner /*(*/ 106575115Sfenner printf(")"); 106675115Sfenner break; 106775115Sfenner } 106875115Sfenner 1069127668Sbms switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 107075115Sfenner case NI_QTYPE_NOOP: 107175115Sfenner if (needcomma) 107275115Sfenner printf(", "); 107375115Sfenner printf("noop"); 107475115Sfenner if (siz != sizeof(*ni6)) 107575115Sfenner if (vflag) 107675115Sfenner printf(", invalid length"); 107775115Sfenner break; 107875115Sfenner case NI_QTYPE_SUPTYPES: 107975115Sfenner if (needcomma) 108075115Sfenner printf(", "); 108175115Sfenner printf("supported qtypes"); 1082127668Sbms i = EXTRACT_16BITS(&ni6->ni_flags); 108375115Sfenner if (i) 108475115Sfenner printf(" [%s]", (i & 0x01) ? "C" : ""); 108575115Sfenner break; 108675115Sfenner case NI_QTYPE_FQDN: 108775115Sfenner if (needcomma) 108875115Sfenner printf(", "); 108975115Sfenner printf("DNS name"); 109075115Sfenner cp = (const u_char *)(ni6 + 1) + 4; 109175115Sfenner if (cp[0] == ep - cp - 1) { 109275115Sfenner /* icmp-name-lookup-03, pascal string */ 109375115Sfenner if (vflag) 109475115Sfenner printf(", 03 draft"); 109575115Sfenner cp++; 109675115Sfenner printf(", \""); 109775115Sfenner while (cp < ep) { 109875115Sfenner safeputchar(*cp); 109975115Sfenner cp++; 110075115Sfenner } 110175115Sfenner printf("\""); 110275115Sfenner } else 110375115Sfenner dnsname_print(cp, ep); 1104127668Sbms if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 110575115Sfenner printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 110675115Sfenner break; 110775115Sfenner case NI_QTYPE_NODEADDR: 110875115Sfenner if (needcomma) 110975115Sfenner printf(", "); 111075115Sfenner printf("node addresses"); 111175115Sfenner i = sizeof(*ni6); 111275115Sfenner while (i < siz) { 111375115Sfenner if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 111475115Sfenner break; 111575115Sfenner printf(" %s", getname6(bp + i)); 111675115Sfenner i += sizeof(struct in6_addr); 1117127668Sbms printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 111875115Sfenner i += sizeof(int32_t); 111975115Sfenner } 112075115Sfenner i = ni6->ni_flags; 112175115Sfenner if (!i) 112275115Sfenner break; 112375115Sfenner printf(" [%s%s%s%s%s%s%s]", 112475115Sfenner (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 112575115Sfenner (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 112675115Sfenner (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 112775115Sfenner (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 112875115Sfenner (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 112975115Sfenner (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 113075115Sfenner (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 113175115Sfenner break; 113275115Sfenner default: 113375115Sfenner if (needcomma) 113475115Sfenner printf(", "); 113575115Sfenner printf("unknown"); 113675115Sfenner break; 113775115Sfenner } 113875115Sfenner 113975115Sfenner /*(*/ 114075115Sfenner printf(")"); 114175115Sfenner break; 114275115Sfenner } 114356893Sfenner return; 114475115Sfenner 114575115Sfennertrunc: 114675115Sfenner fputs("[|icmp6]", stdout); 114756893Sfenner} 114875115Sfenner 1149127668Sbmsstatic void 1150127668Sbmsicmp6_rrenum_print(const u_char *bp, const u_char *ep) 115175115Sfenner{ 115275115Sfenner struct icmp6_router_renum *rr6; 115375115Sfenner const char *cp; 115475115Sfenner struct rr_pco_match *match; 115575115Sfenner struct rr_pco_use *use; 115675115Sfenner char hbuf[NI_MAXHOST]; 115775115Sfenner int n; 115875115Sfenner 1159127668Sbms if (ep < bp) 1160127668Sbms return; 116175115Sfenner rr6 = (struct icmp6_router_renum *)bp; 116275115Sfenner cp = (const char *)(rr6 + 1); 116375115Sfenner 116475115Sfenner TCHECK(rr6->rr_reserved); 116575115Sfenner switch (rr6->rr_code) { 116675115Sfenner case ICMP6_ROUTER_RENUMBERING_COMMAND: 116775115Sfenner printf("router renum: command"); 116875115Sfenner break; 116975115Sfenner case ICMP6_ROUTER_RENUMBERING_RESULT: 117075115Sfenner printf("router renum: result"); 117175115Sfenner break; 117275115Sfenner case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 117375115Sfenner printf("router renum: sequence number reset"); 117475115Sfenner break; 117575115Sfenner default: 117675115Sfenner printf("router renum: code-#%d", rr6->rr_code); 117775115Sfenner break; 117875115Sfenner } 117975115Sfenner 1180127668Sbms printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 118175115Sfenner 118275115Sfenner if (vflag) { 118375115Sfenner#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 118475115Sfenner printf("["); /*]*/ 118575115Sfenner if (rr6->rr_flags) { 118675115Sfenner printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 118775115Sfenner F(ICMP6_RR_FLAGS_REQRESULT, "R"), 118898524Sfenner F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 118975115Sfenner F(ICMP6_RR_FLAGS_SPECSITE, "S"), 119075115Sfenner F(ICMP6_RR_FLAGS_PREVDONE, "P")); 119175115Sfenner } 119275115Sfenner printf("seg=%u,", rr6->rr_segnum); 119375115Sfenner printf("maxdelay=%u", rr6->rr_maxdelay); 119475115Sfenner if (rr6->rr_reserved) 1195127668Sbms printf("rsvd=0x%x", EXTRACT_16BITS(&rr6->rr_reserved)); 119675115Sfenner /*[*/ 119775115Sfenner printf("]"); 119875115Sfenner#undef F 119975115Sfenner } 120075115Sfenner 120175115Sfenner if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 120275115Sfenner match = (struct rr_pco_match *)cp; 120375115Sfenner cp = (const char *)(match + 1); 120475115Sfenner 120575115Sfenner TCHECK(match->rpm_prefix); 120675115Sfenner 120798524Sfenner if (vflag > 1) 120875115Sfenner printf("\n\t"); 120975115Sfenner else 121075115Sfenner printf(" "); 121175115Sfenner printf("match("); /*)*/ 121275115Sfenner switch (match->rpm_code) { 121375115Sfenner case RPM_PCO_ADD: printf("add"); break; 121475115Sfenner case RPM_PCO_CHANGE: printf("change"); break; 121575115Sfenner case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 121675115Sfenner default: printf("#%u", match->rpm_code); break; 121775115Sfenner } 121875115Sfenner 121975115Sfenner if (vflag) { 122075115Sfenner printf(",ord=%u", match->rpm_ordinal); 122175115Sfenner printf(",min=%u", match->rpm_minlen); 122275115Sfenner printf(",max=%u", match->rpm_maxlen); 122375115Sfenner } 122475115Sfenner if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 122575115Sfenner printf(",%s/%u", hbuf, match->rpm_matchlen); 122675115Sfenner else 122775115Sfenner printf(",?/%u", match->rpm_matchlen); 122875115Sfenner /*(*/ 122975115Sfenner printf(")"); 123075115Sfenner 123175115Sfenner n = match->rpm_len - 3; 123275115Sfenner if (n % 4) 123375115Sfenner goto trunc; 123475115Sfenner n /= 4; 123575115Sfenner while (n-- > 0) { 123675115Sfenner use = (struct rr_pco_use *)cp; 123775115Sfenner cp = (const char *)(use + 1); 123875115Sfenner 123975115Sfenner TCHECK(use->rpu_prefix); 124075115Sfenner 124198524Sfenner if (vflag > 1) 124275115Sfenner printf("\n\t"); 124375115Sfenner else 124475115Sfenner printf(" "); 124575115Sfenner printf("use("); /*)*/ 124675115Sfenner if (use->rpu_flags) { 124775115Sfenner#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 124875115Sfenner printf("%s%s,", 124975115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 125075115Sfenner F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 125175115Sfenner#undef F 125275115Sfenner } 125375115Sfenner if (vflag) { 125475115Sfenner printf("mask=0x%x,", use->rpu_ramask); 125575115Sfenner printf("raflags=0x%x,", use->rpu_raflags); 125675115Sfenner if (~use->rpu_vltime == 0) 125775115Sfenner printf("vltime=infty,"); 125875115Sfenner else 125975115Sfenner printf("vltime=%u,", 1260127668Sbms EXTRACT_32BITS(&use->rpu_vltime)); 126175115Sfenner if (~use->rpu_pltime == 0) 126275115Sfenner printf("pltime=infty,"); 126375115Sfenner else 126475115Sfenner printf("pltime=%u,", 1265127668Sbms EXTRACT_32BITS(&use->rpu_pltime)); 126675115Sfenner } 126775115Sfenner if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 126875115Sfenner sizeof(hbuf))) 126975115Sfenner printf("%s/%u/%u", hbuf, use->rpu_uselen, 127075115Sfenner use->rpu_keeplen); 127175115Sfenner else 127275115Sfenner printf("?/%u/%u", use->rpu_uselen, 127375115Sfenner use->rpu_keeplen); 127475115Sfenner /*(*/ 127575115Sfenner printf(")"); 127675115Sfenner } 127775115Sfenner } 127875115Sfenner 127975115Sfenner return; 128075115Sfenner 128175115Sfennertrunc: 128275115Sfenner fputs("[|icmp6]", stdout); 128375115Sfenner} 128475115Sfenner 128556893Sfenner#endif /* INET6 */ 1286