print-icmp6.c revision 214478
16059Samurai/* 26059Samurai * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 36059Samurai * The Regents of the University of California. All rights reserved. 46059Samurai * 56059Samurai * Redistribution and use in source and binary forms, with or without 66059Samurai * modification, are permitted provided that: (1) source code distributions 76059Samurai * retain the above copyright notice and this paragraph in its entirety, (2) 86059Samurai * distributions including binary code include the above copyright notice and 96059Samurai * this paragraph in its entirety in the documentation or other materials 106059Samurai * provided with the distribution, and (3) all advertising materials mentioning 116059Samurai * features or use of this software display the following acknowledgement: 126059Samurai * ``This product includes software developed by the University of California, 136059Samurai * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 146059Samurai * the University nor the names of its contributors may be used to endorse 156059Samurai * or promote products derived from this software without specific prior 166059Samurai * written permission. 176059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 186059Samurai * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 198857Srgrimes * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 2032663Sbrian */ 218857Srgrimes 226059Samurai#ifndef lint 236059Samuraistatic const char rcsid[] _U_ = 2430715Sbrian "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.86 2008-02-05 19:36:13 guy Exp $"; 2530715Sbrian#endif 2630715Sbrian 2730715Sbrian#ifdef HAVE_CONFIG_H 2830715Sbrian#include "config.h" 2930715Sbrian#endif 3030715Sbrian 3131343Sbrian#ifdef INET6 3230715Sbrian 3330715Sbrian#include <tcpdump-stdinc.h> 3430715Sbrian 3530715Sbrian#include <stdio.h> 366059Samurai#include <string.h> 376059Samurai 386059Samurai#include "interface.h" 3930733Sbrian#include "addrtoname.h" 4030733Sbrian#include "extract.h" 4130733Sbrian 4230733Sbrian#include "ip6.h" 4330733Sbrian#include "icmp6.h" 446059Samurai#include "ipproto.h" 4531343Sbrian 466059Samurai#include "udp.h" 4726142Sbrian#include "ah.h" 486735Samurai 4913389Sphkstatic const char *get_rtpref(u_int); 5013389Sphkstatic const char *get_lifetime(u_int32_t); 516059Samuraistatic void print_lladdr(const u_char *, size_t); 5232663Sbrianstatic void icmp6_opt_print(const u_char *, int); 5328679Sbrianstatic void mld6_print(const u_char *); 5428679Sbrianstatic void mldv2_report_print(const u_char *, u_int); 5528679Sbrianstatic void mldv2_query_print(const u_char *, u_int); 5628679Sbrianstatic struct udphdr *get_upperlayer(u_char *, u_int *); 5728679Sbrianstatic void dnsname_print(const u_char *, const u_char *); 586059Samuraistatic void icmp6_nodeinfo_print(u_int, const u_char *, const u_char *); 5930715Sbrianstatic void icmp6_rrenum_print(const u_char *, const u_char *); 6030715Sbrian 6130715Sbrian#ifndef abs 626059Samurai#define abs(a) ((0 < (a)) ? (a) : -(a)) 6332663Sbrian#endif 646059Samurai 6531343Sbrian/* inline the various RPL definitions */ 666059Samurai#define ND_RPL_MESSAGE 0x9B 676059Samurai 6831537Sbrianstatic struct tok icmp6_type_values[] = { 6931343Sbrian { ICMP6_DST_UNREACH, "destination unreachable"}, 7031343Sbrian { ICMP6_PACKET_TOO_BIG, "packet too big"}, 7131343Sbrian { ICMP6_TIME_EXCEEDED, "time exceeded in-transit"}, 7231343Sbrian { ICMP6_PARAM_PROB, "parameter problem"}, 7331343Sbrian { ICMP6_ECHO_REQUEST, "echo request"}, 7431343Sbrian { ICMP6_ECHO_REPLY, "echo reply"}, 7531343Sbrian { MLD6_LISTENER_QUERY, "multicast listener query"}, 7631343Sbrian { MLD6_LISTENER_REPORT, "multicast listener report"}, 7731343Sbrian { MLD6_LISTENER_DONE, "multicast listener done"}, 7831343Sbrian { ND_ROUTER_SOLICIT, "router solicitation"}, 7931343Sbrian { ND_ROUTER_ADVERT, "router advertisement"}, 806059Samurai { ND_NEIGHBOR_SOLICIT, "neighbor solicitation"}, 816059Samurai { ND_NEIGHBOR_ADVERT, "neighbor advertisement"}, 8213760Sphk { ND_REDIRECT, "redirect"}, 8328679Sbrian { ICMP6_ROUTER_RENUMBERING, "router renumbering"}, 8428679Sbrian { IND_SOLICIT, "inverse neighbor solicitation"}, 8528679Sbrian { IND_ADVERT, "inverse neighbor advertisement"}, 8628679Sbrian { MLDV2_LISTENER_REPORT, "multicast listener report v2"}, 8728679Sbrian { ICMP6_HADISCOV_REQUEST, "ha discovery request"}, 8828679Sbrian { ICMP6_HADISCOV_REPLY, "ha discovery reply"}, 8928679Sbrian { ICMP6_MOBILEPREFIX_SOLICIT, "mobile router solicitation"}, 9028679Sbrian { ICMP6_MOBILEPREFIX_ADVERT, "mobile router advertisement"}, 9128679Sbrian { ICMP6_WRUREQUEST, "who-are-you request"}, 9228679Sbrian { ICMP6_WRUREPLY, "who-are-you reply"}, 9328679Sbrian { ICMP6_NI_QUERY, "node information query"}, 9428679Sbrian { ICMP6_NI_REPLY, "node information reply"}, 9528679Sbrian { MLD6_MTRACE, "mtrace message"}, 9628679Sbrian { MLD6_MTRACE_RESP, "mtrace response"}, 9728679Sbrian { ND_RPL_MESSAGE, "RPL"}, 9828679Sbrian { 0, NULL } 9928679Sbrian}; 10028679Sbrian 10128679Sbrianstatic struct tok icmp6_dst_unreach_code_values[] = { 10228679Sbrian { ICMP6_DST_UNREACH_NOROUTE, "unreachable route" }, 10328679Sbrian { ICMP6_DST_UNREACH_ADMIN, " unreachable prohibited"}, 10428679Sbrian { ICMP6_DST_UNREACH_BEYONDSCOPE, "beyond scope"}, 10528679Sbrian { ICMP6_DST_UNREACH_ADDR, "unreachable address"}, 10628679Sbrian { ICMP6_DST_UNREACH_NOPORT, "unreachable port"}, 10728679Sbrian { 0, NULL } 10828679Sbrian}; 10928679Sbrian 11028679Sbrianstatic struct tok icmp6_opt_pi_flag_values[] = { 11128679Sbrian { ND_OPT_PI_FLAG_ONLINK, "onlink" }, 11228679Sbrian { ND_OPT_PI_FLAG_AUTO, "auto" }, 11328679Sbrian { ND_OPT_PI_FLAG_ROUTER, "router" }, 11428679Sbrian { 0, NULL } 1156059Samurai}; 1166059Samurai 11728679Sbrianstatic struct tok icmp6_opt_ra_flag_values[] = { 11828679Sbrian { ND_RA_FLAG_MANAGED, "managed" }, 1196059Samurai { ND_RA_FLAG_OTHER, "other stateful"}, 1206059Samurai { ND_RA_FLAG_HOME_AGENT, "home agent"}, 1216059Samurai { 0, NULL } 12232663Sbrian}; 12332663Sbrian 1246059Samuraistatic struct tok icmp6_nd_na_flag_values[] = { 1256059Samurai { ND_NA_FLAG_ROUTER, "router" }, 1266059Samurai { ND_NA_FLAG_SOLICITED, "solicited" }, 1276059Samurai { ND_NA_FLAG_OVERRIDE, "override" }, 1286059Samurai { 0, NULL } 1296059Samurai}; 1306059Samurai 13128679Sbrian 13228679Sbrianstatic struct tok icmp6_opt_values[] = { 1336059Samurai { ND_OPT_SOURCE_LINKADDR, "source link-address"}, 1346059Samurai { ND_OPT_TARGET_LINKADDR, "destination link-address"}, 1356059Samurai { ND_OPT_PREFIX_INFORMATION, "prefix info"}, 13628679Sbrian { ND_OPT_REDIRECTED_HEADER, "redirected header"}, 1376059Samurai { ND_OPT_MTU, "mtu"}, 1386059Samurai { ND_OPT_RDNSS, "rdnss"}, 13932663Sbrian { ND_OPT_ADVINTERVAL, "advertisement interval"}, 14031514Sbrian { ND_OPT_HOMEAGENT_INFO, "homeagent information"}, 14131514Sbrian { ND_OPT_ROUTE_INFO, "route info"}, 14231514Sbrian { 0, NULL } 14331514Sbrian}; 14431514Sbrian 14531514Sbrian/* mldv2 report types */ 14631514Sbrianstatic struct tok mldv2report2str[] = { 14731514Sbrian { 1, "is_in" }, 14831514Sbrian { 2, "is_ex" }, 14931514Sbrian { 3, "to_in" }, 15031514Sbrian { 4, "to_ex" }, 15131514Sbrian { 5, "allow" }, 15231514Sbrian { 6, "block" }, 15331514Sbrian { 0, NULL } 15431514Sbrian}; 15531514Sbrian 15631514Sbrianstatic const char * 15731514Sbrianget_rtpref(u_int v) 15831514Sbrian{ 1596059Samurai static const char *rtpref_str[] = { 16028679Sbrian "medium", /* 00 */ 1616059Samurai "high", /* 01 */ 1626059Samurai "rsv", /* 10 */ 1636059Samurai "low" /* 11 */ 1646059Samurai }; 1656059Samurai 1666059Samurai return rtpref_str[((v & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff]; 1676059Samurai} 16831514Sbrian 16931514Sbrianstatic const char * 17031514Sbrianget_lifetime(u_int32_t v) 17129294Sbrian{ 17231514Sbrian static char buf[20]; 1736735Samurai 17432663Sbrian if (v == (u_int32_t)~0UL) 1756735Samurai return "infinity"; 1766735Samurai else { 17731514Sbrian snprintf(buf, sizeof(buf), "%u", v); 1786059Samurai return buf; 1796059Samurai } 1806059Samurai} 1816059Samurai 1826059Samuraistatic void 1836059Samuraiprint_lladdr(const u_int8_t *p, size_t l) 1846059Samurai{ 1856059Samurai const u_int8_t *ep, *q; 18628679Sbrian 1876059Samurai q = p; 18828679Sbrian ep = p + l; 1896059Samurai while (l > 0 && q < ep) { 1906059Samurai if (q > p) 1916059Samurai printf(":"); 1926059Samurai printf("%02x", *q++); 1936059Samurai l--; 1946059Samurai } 1956059Samurai} 1966059Samurai 1976059Samuraistatic int icmp6_cksum(const struct ip6_hdr *ip6, const struct icmp6_hdr *icp, 1986059Samurai u_int len) 19931514Sbrian{ 20031514Sbrian size_t i; 2016059Samurai register const u_int16_t *sp; 20231514Sbrian u_int32_t sum; 2036059Samurai union { 2046059Samurai struct { 2056059Samurai struct in6_addr ph_src; 2066059Samurai struct in6_addr ph_dst; 2076059Samurai u_int32_t ph_len; 2086059Samurai u_int8_t ph_zero[3]; 2096059Samurai u_int8_t ph_nxt; 2106059Samurai } ph; 2116059Samurai u_int16_t pa[20]; 2126059Samurai } phu; 2136059Samurai 2146059Samurai /* pseudo-header */ 2156059Samurai memset(&phu, 0, sizeof(phu)); 2166059Samurai phu.ph.ph_src = ip6->ip6_src; 2176059Samurai phu.ph.ph_dst = ip6->ip6_dst; 2186059Samurai phu.ph.ph_len = htonl(len); 2196059Samurai phu.ph.ph_nxt = IPPROTO_ICMPV6; 2206059Samurai 22128679Sbrian sum = 0; 2226059Samurai for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) 2236735Samurai sum += phu.pa[i]; 22432381Sbrian 22532381Sbrian sp = (const u_int16_t *)icp; 2266735Samurai 2276735Samurai for (i = 0; i < (len & ~1); i += 2) 22828679Sbrian sum += *sp++; 2296735Samurai 23032381Sbrian if (len & 1) 2316735Samurai sum += htons((*(const u_int8_t *)sp) << 8); 23226516Sbrian 2336059Samurai while (sum > 0xffff) 2346059Samurai sum = (sum & 0xffff) + (sum >> 16); 2356059Samurai sum = ~sum & 0xffff; 2366059Samurai 23731514Sbrian return (sum); 23831514Sbrian} 23931514Sbrian 2406735Samuraienum ND_RPL_CODE { 2416735Samurai ND_RPL_DAG_IS=0x01, 2426735Samurai ND_RPL_DAG_IO=0x02, 2436735Samurai ND_RPL_DAO =0x04 2446059Samurai}; 2456059Samurai 24631537Sbrianenum ND_RPL_DIO_FLAGS { 24731537Sbrian ND_RPL_DIO_GROUNDED = 0x80, 24831537Sbrian ND_RPL_DIO_DATRIG = 0x40, 24931537Sbrian ND_RPL_DIO_DASUPPORT= 0x20, 25031537Sbrian ND_RPL_DIO_RES4 = 0x10, 25131537Sbrian ND_RPL_DIO_RES3 = 0x08, 25231537Sbrian ND_RPL_DIO_PRF_MASK = 0x07, /* 3-bit preference */ 25331537Sbrian}; 25431537Sbrian 25531537Sbrianstruct nd_rpl_dio { 25631537Sbrian u_int8_t rpl_flags; 25731537Sbrian u_int8_t rpl_seq; 25831537Sbrian u_int8_t rpl_instanceid; 25931537Sbrian u_int8_t rpl_dagrank; 26031537Sbrian u_int8_t rpl_dagid[16]; 26131537Sbrian}; 26231537Sbrian 26331537Sbrianstatic void 26431537Sbrianrpl_print(netdissect_options *ndo, 26531537Sbrian const struct icmp6_hdr *hdr, 26631537Sbrian const u_char *bp, u_int length _U_) 26731537Sbrian{ 26831537Sbrian struct nd_rpl_dio *dio = (struct nd_rpl_dio *)bp; 26931537Sbrian 27031537Sbrian ND_TCHECK(dio->rpl_dagid); 27131537Sbrian 27231537Sbrian switch(hdr->icmp6_code) { 27331537Sbrian case ND_RPL_DAG_IS: 27431537Sbrian ND_PRINT((ndo, ", DAG Information Solicitation")); 27531537Sbrian if(ndo->ndo_vflag) { 27631537Sbrian } 27731537Sbrian break; 27831537Sbrian case ND_RPL_DAG_IO: 27931537Sbrian ND_PRINT((ndo, ", DAG Information Object")); 28031537Sbrian if(ndo->ndo_vflag) { 28131537Sbrian char dagid[65]; 28231537Sbrian char *d = dagid; 28331537Sbrian int i; 28431537Sbrian for(i=0;i<16;i++) { 28531537Sbrian if(isprint(dio->rpl_dagid[i])) { 28631537Sbrian *d++ = dio->rpl_dagid[i]; 28731537Sbrian } else { 28831537Sbrian int cnt=snprintf(d,4,"0x%02x", 28931537Sbrian dio->rpl_dagid[i]); 29031537Sbrian d += cnt; 29131537Sbrian } 29231537Sbrian } 29331537Sbrian *d++ = '\0'; 29431537Sbrian ND_PRINT((ndo, " [seq:%u,instance:%u,rank:%u,dagid:%s]", 29531537Sbrian dio->rpl_seq, 29631537Sbrian dio->rpl_instanceid, 29731537Sbrian dio->rpl_dagrank, 29831537Sbrian dagid)); 29931537Sbrian } 30031537Sbrian break; 30131537Sbrian case ND_RPL_DAO: 30231537Sbrian ND_PRINT((ndo, ", Destination Advertisement Object")); 30331537Sbrian if(ndo->ndo_vflag) { 30431537Sbrian } 30531537Sbrian break; 30631537Sbrian default: 30731537Sbrian ND_PRINT((ndo, ", RPL message, unknown code %u",hdr->icmp6_code)); 30831537Sbrian break; 30931537Sbrian } 31031537Sbrian return; 31131537Sbriantrunc: 31231537Sbrian ND_PRINT((ndo," [|truncated]")); 31331537Sbrian return; 31431537Sbrian 31531537Sbrian} 31631537Sbrian 31731537Sbrian 31831537Sbrianvoid 31931537Sbrianicmp6_print(netdissect_options *ndo, 32031537Sbrian const u_char *bp, u_int length, const u_char *bp2, int fragmented) 32131537Sbrian{ 32231537Sbrian const struct icmp6_hdr *dp; 32331537Sbrian const struct ip6_hdr *ip; 32431537Sbrian const struct ip6_hdr *oip; 32531537Sbrian const struct udphdr *ouh; 32631537Sbrian int dport; 32731537Sbrian const u_char *ep; 32831537Sbrian u_int prot; 32931537Sbrian 33031537Sbrian dp = (struct icmp6_hdr *)bp; 33131537Sbrian ip = (struct ip6_hdr *)bp2; 33231537Sbrian oip = (struct ip6_hdr *)(dp + 1); 33331537Sbrian /* 'ep' points to the end of available data. */ 33431537Sbrian ep = snapend; 33531537Sbrian 33631537Sbrian TCHECK(dp->icmp6_cksum); 33731537Sbrian 33831537Sbrian if (vflag && !fragmented) { 33931537Sbrian int sum = dp->icmp6_cksum; 34031537Sbrian 34131537Sbrian if (TTEST2(bp[0], length)) { 34231537Sbrian sum = icmp6_cksum(ip, dp, length); 34331537Sbrian if (sum != 0) 34431537Sbrian (void)printf("[bad icmp6 cksum %x!] ", sum); 34531537Sbrian else 34631537Sbrian (void)printf("[icmp6 sum ok] "); 34731537Sbrian } 34831537Sbrian } 34931537Sbrian 35031537Sbrian printf("ICMP6, %s", tok2str(icmp6_type_values,"unknown icmp6 type (%u)",dp->icmp6_type)); 35131537Sbrian 35231537Sbrian /* display cosmetics: print the packet length for printer that use the vflag now */ 35331537Sbrian if (vflag && (dp->icmp6_type == 35431537Sbrian ND_ROUTER_SOLICIT || 35531537Sbrian ND_ROUTER_ADVERT || 35631537Sbrian ND_NEIGHBOR_ADVERT || 35731962Sbrian ND_NEIGHBOR_SOLICIT || 35831537Sbrian ND_REDIRECT || 35931537Sbrian ICMP6_HADISCOV_REPLY || 36031537Sbrian ICMP6_MOBILEPREFIX_ADVERT )) 36131537Sbrian printf(", length %u", length); 36231537Sbrian 36331537Sbrian switch (dp->icmp6_type) { 36431537Sbrian case ICMP6_DST_UNREACH: 36531537Sbrian TCHECK(oip->ip6_dst); 36631537Sbrian printf(", %s", tok2str(icmp6_dst_unreach_code_values,"unknown unreach code (%u)",dp->icmp6_code)); 36731537Sbrian switch (dp->icmp6_code) { 36831537Sbrian 36931537Sbrian case ICMP6_DST_UNREACH_NOROUTE: /* fall through */ 37031537Sbrian case ICMP6_DST_UNREACH_ADMIN: 37131537Sbrian case ICMP6_DST_UNREACH_ADDR: 37232663Sbrian printf(" %s",ip6addr_string(&oip->ip6_dst)); 37328679Sbrian break; 3746059Samurai case ICMP6_DST_UNREACH_BEYONDSCOPE: 3759448Samurai printf(" %s, source address %s", 3769448Samurai ip6addr_string(&oip->ip6_dst), 37731514Sbrian ip6addr_string(&oip->ip6_src)); 37826516Sbrian break; 37931514Sbrian case ICMP6_DST_UNREACH_NOPORT: 38031514Sbrian if ((ouh = get_upperlayer((u_char *)oip, &prot)) 38131514Sbrian == NULL) 38231514Sbrian goto trunc; 38332381Sbrian 38432381Sbrian dport = EXTRACT_16BITS(&ouh->uh_dport); 38532381Sbrian switch (prot) { 38632381Sbrian case IPPROTO_TCP: 38732381Sbrian printf(", %s tcp port %s", 38831514Sbrian ip6addr_string(&oip->ip6_dst), 38931514Sbrian tcpport_string(dport)); 3906059Samurai break; 3916059Samurai case IPPROTO_UDP: 3926059Samurai printf(", %s udp port %s", 3936059Samurai ip6addr_string(&oip->ip6_dst), 3946059Samurai udpport_string(dport)); 3956059Samurai break; 3966059Samurai default: 3976059Samurai printf(", %s protocol %d port %d unreachable", 3986059Samurai ip6addr_string(&oip->ip6_dst), 3996059Samurai oip->ip6_nxt, dport); 4006059Samurai break; 4016059Samurai } 4026059Samurai break; 4036059Samurai default: 4046059Samurai if (vflag <= 1) { 4056059Samurai print_unknown_data(bp,"\n\t",length); 4066059Samurai return; 40732663Sbrian } 4086735Samurai break; 4096735Samurai } 4106059Samurai break; 4116059Samurai case ICMP6_PACKET_TOO_BIG: 4126059Samurai TCHECK(dp->icmp6_mtu); 4136059Samurai printf(", mtu %u", EXTRACT_32BITS(&dp->icmp6_mtu)); 4146059Samurai break; 4156059Samurai case ICMP6_TIME_EXCEEDED: 4166059Samurai TCHECK(oip->ip6_dst); 4176059Samurai switch (dp->icmp6_code) { 4186059Samurai case ICMP6_TIME_EXCEED_TRANSIT: 4196059Samurai printf(" for %s", 4206059Samurai ip6addr_string(&oip->ip6_dst)); 42131537Sbrian break; 42231537Sbrian case ICMP6_TIME_EXCEED_REASSEMBLY: 4239448Samurai printf(" (reassembly)"); 4249448Samurai break; 4259448Samurai default: 42628679Sbrian printf(", unknown code (%u)", dp->icmp6_code); 4276059Samurai break; 4286059Samurai } 4296059Samurai break; 4306059Samurai case ICMP6_PARAM_PROB: 4316059Samurai TCHECK(oip->ip6_dst); 4326059Samurai switch (dp->icmp6_code) { 4336059Samurai case ICMP6_PARAMPROB_HEADER: 4346059Samurai printf(", errorneous - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 43531343Sbrian break; 4366059Samurai case ICMP6_PARAMPROB_NEXTHEADER: 4376059Samurai printf(", next header - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 4386059Samurai break; 4396059Samurai case ICMP6_PARAMPROB_OPTION: 4406059Samurai printf(", option - octet %u", EXTRACT_32BITS(&dp->icmp6_pptr)); 4416059Samurai break; 4426059Samurai default: 44326516Sbrian printf(", code-#%d", 4446059Samurai dp->icmp6_code); 4456059Samurai break; 44626516Sbrian } 44728679Sbrian break; 4486059Samurai case ICMP6_ECHO_REQUEST: 44926516Sbrian case ICMP6_ECHO_REPLY: 4506059Samurai TCHECK(dp->icmp6_seq); 4516059Samurai printf(", seq %u", EXTRACT_16BITS(&dp->icmp6_seq)); 4526059Samurai break; 4536059Samurai case ICMP6_MEMBERSHIP_QUERY: 45428679Sbrian if (length == MLD_MINLEN) { 45532284Sbrian mld6_print((const u_char *)dp); 4566059Samurai } else if (length >= MLDV2_MINLEN) { 4576059Samurai printf("v2 "); 4586059Samurai mldv2_query_print((const u_char *)dp, length); 45931343Sbrian } else { 4606059Samurai printf(" unknown-version (len %u) ", length); 4616059Samurai } 4626059Samurai break; 46326516Sbrian case ICMP6_MEMBERSHIP_REPORT: 46426516Sbrian mld6_print((const u_char *)dp); 46526516Sbrian break; 46628679Sbrian case ICMP6_MEMBERSHIP_REDUCTION: 46726516Sbrian mld6_print((const u_char *)dp); 46826516Sbrian break; 4696059Samurai case ND_ROUTER_SOLICIT: 4706059Samurai#define RTSOLLEN 8 4716059Samurai if (vflag) { 4726059Samurai icmp6_opt_print((const u_char *)dp + RTSOLLEN, 4736059Samurai length - RTSOLLEN); 4746059Samurai } 4756059Samurai break; 4766059Samurai case ND_ROUTER_ADVERT: 4776059Samurai#define RTADVLEN 16 4786059Samurai if (vflag) { 47931962Sbrian struct nd_router_advert *p; 48026516Sbrian 48128679Sbrian p = (struct nd_router_advert *)dp; 48228679Sbrian TCHECK(p->nd_ra_retransmit); 4836059Samurai printf("\n\thop limit %u, Flags [%s]" \ 4846059Samurai ", pref %s, router lifetime %us, reachable time %us, retrans time %us", 4856059Samurai (u_int)p->nd_ra_curhoplimit, 4866059Samurai bittok2str(icmp6_opt_ra_flag_values,"none",(p->nd_ra_flags_reserved)), 4876059Samurai get_rtpref(p->nd_ra_flags_reserved), 48828679Sbrian EXTRACT_16BITS(&p->nd_ra_router_lifetime), 4896059Samurai EXTRACT_32BITS(&p->nd_ra_reachable), 4906059Samurai EXTRACT_32BITS(&p->nd_ra_retransmit)); 4916059Samurai 4926059Samurai icmp6_opt_print((const u_char *)dp + RTADVLEN, 4936059Samurai length - RTADVLEN); 49426516Sbrian } 4956735Samurai break; 4966735Samurai case ND_NEIGHBOR_SOLICIT: 4976735Samurai { 4986735Samurai struct nd_neighbor_solicit *p; 4996059Samurai p = (struct nd_neighbor_solicit *)dp; 5006059Samurai TCHECK(p->nd_ns_target); 50126516Sbrian printf(", who has %s", ip6addr_string(&p->nd_ns_target)); 50228679Sbrian if (vflag) { 5036059Samurai#define NDSOLLEN 24 5046059Samurai icmp6_opt_print((const u_char *)dp + NDSOLLEN, 50526516Sbrian length - NDSOLLEN); 5066059Samurai } 5076059Samurai } 5086059Samurai break; 5096059Samurai case ND_NEIGHBOR_ADVERT: 5106735Samurai { 5116735Samurai struct nd_neighbor_advert *p; 51225019Sphk 51325019Sphk p = (struct nd_neighbor_advert *)dp; 51428679Sbrian TCHECK(p->nd_na_target); 51528679Sbrian printf(", tgt is %s", 51625019Sphk ip6addr_string(&p->nd_na_target)); 5176059Samurai if (vflag) { 5186059Samurai printf(", Flags [%s]", 5196059Samurai bittok2str(icmp6_nd_na_flag_values, 52028679Sbrian "none", 5216059Samurai EXTRACT_32BITS(&p->nd_na_flags_reserved))); 52228679Sbrian#define NDADVLEN 24 5236059Samurai icmp6_opt_print((const u_char *)dp + NDADVLEN, 5246059Samurai length - NDADVLEN); 5256059Samurai#undef NDADVLEN 5266059Samurai } 5276059Samurai } 52826516Sbrian break; 5296059Samurai case ND_REDIRECT: 5306059Samurai#define RDR(i) ((struct nd_redirect *)(i)) 5316059Samurai TCHECK(RDR(dp)->nd_rd_dst); 5326059Samurai printf(", %s", getname6((const u_char *)&RDR(dp)->nd_rd_dst)); 5336059Samurai TCHECK(RDR(dp)->nd_rd_target); 5346059Samurai printf(" to %s", 5356059Samurai getname6((const u_char*)&RDR(dp)->nd_rd_target)); 53626516Sbrian#define REDIRECTLEN 40 5376059Samurai if (vflag) { 5386059Samurai icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 5396059Samurai length - REDIRECTLEN); 5406059Samurai } 5416059Samurai break; 5426059Samurai#undef REDIRECTLEN 54328679Sbrian#undef RDR 5446059Samurai case ICMP6_ROUTER_RENUMBERING: 54528679Sbrian icmp6_rrenum_print(bp, ep); 54628679Sbrian break; 5476059Samurai case ICMP6_NI_QUERY: 5486059Samurai case ICMP6_NI_REPLY: 5496059Samurai icmp6_nodeinfo_print(length, bp, ep); 5506059Samurai break; 5516059Samurai case IND_SOLICIT: 5526059Samurai case IND_ADVERT: 5536059Samurai break; 5546059Samurai case ICMP6_V2_MEMBERSHIP_REPORT: 5556059Samurai mldv2_report_print((const u_char *) dp, length); 55628679Sbrian break; 55728679Sbrian case ICMP6_MOBILEPREFIX_SOLICIT: /* fall through */ 55828679Sbrian case ICMP6_HADISCOV_REQUEST: 5596059Samurai TCHECK(dp->icmp6_data16[0]); 5606059Samurai printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 5616059Samurai break; 5626059Samurai case ICMP6_HADISCOV_REPLY: 5636059Samurai if (vflag) { 5646059Samurai struct in6_addr *in6; 5656059Samurai u_char *cp; 5666059Samurai 5676059Samurai TCHECK(dp->icmp6_data16[0]); 5686059Samurai printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 5696059Samurai cp = (u_char *)dp + length; 5706059Samurai in6 = (struct in6_addr *)(dp + 1); 5716059Samurai for (; (u_char *)in6 < cp; in6++) { 5726059Samurai TCHECK(*in6); 5736059Samurai printf(", %s", ip6addr_string(in6)); 5746059Samurai } 5756059Samurai } 5766059Samurai break; 577 case ICMP6_MOBILEPREFIX_ADVERT: 578 if (vflag) { 579 TCHECK(dp->icmp6_data16[0]); 580 printf(", id 0x%04x", EXTRACT_16BITS(&dp->icmp6_data16[0])); 581 if (dp->icmp6_data16[1] & 0xc0) 582 printf(" "); 583 if (dp->icmp6_data16[1] & 0x80) 584 printf("M"); 585 if (dp->icmp6_data16[1] & 0x40) 586 printf("O"); 587#define MPADVLEN 8 588 icmp6_opt_print((const u_char *)dp + MPADVLEN, 589 length - MPADVLEN); 590 } 591 break; 592 case ND_RPL_MESSAGE: 593 rpl_print(ndo, dp, &dp->icmp6_data8[0], length); 594 break; 595 default: 596 printf(", length %u", length); 597 if (vflag <= 1) 598 print_unknown_data(bp,"\n\t", length); 599 return; 600 } 601 if (!vflag) 602 printf(", length %u", length); 603 return; 604trunc: 605 fputs("[|icmp6]", stdout); 606} 607 608static struct udphdr * 609get_upperlayer(u_char *bp, u_int *prot) 610{ 611 const u_char *ep; 612 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 613 struct udphdr *uh; 614 struct ip6_hbh *hbh; 615 struct ip6_frag *fragh; 616 struct ah *ah; 617 u_int nh; 618 int hlen; 619 620 /* 'ep' points to the end of available data. */ 621 ep = snapend; 622 623 if (!TTEST(ip6->ip6_nxt)) 624 return NULL; 625 626 nh = ip6->ip6_nxt; 627 hlen = sizeof(struct ip6_hdr); 628 629 while (bp < ep) { 630 bp += hlen; 631 632 switch(nh) { 633 case IPPROTO_UDP: 634 case IPPROTO_TCP: 635 uh = (struct udphdr *)bp; 636 if (TTEST(uh->uh_dport)) { 637 *prot = nh; 638 return(uh); 639 } 640 else 641 return(NULL); 642 /* NOTREACHED */ 643 644 case IPPROTO_HOPOPTS: 645 case IPPROTO_DSTOPTS: 646 case IPPROTO_ROUTING: 647 hbh = (struct ip6_hbh *)bp; 648 if (!TTEST(hbh->ip6h_len)) 649 return(NULL); 650 nh = hbh->ip6h_nxt; 651 hlen = (hbh->ip6h_len + 1) << 3; 652 break; 653 654 case IPPROTO_FRAGMENT: /* this should be odd, but try anyway */ 655 fragh = (struct ip6_frag *)bp; 656 if (!TTEST(fragh->ip6f_offlg)) 657 return(NULL); 658 /* fragments with non-zero offset are meaningless */ 659 if ((EXTRACT_16BITS(&fragh->ip6f_offlg) & IP6F_OFF_MASK) != 0) 660 return(NULL); 661 nh = fragh->ip6f_nxt; 662 hlen = sizeof(struct ip6_frag); 663 break; 664 665 case IPPROTO_AH: 666 ah = (struct ah *)bp; 667 if (!TTEST(ah->ah_len)) 668 return(NULL); 669 nh = ah->ah_nxt; 670 hlen = (ah->ah_len + 2) << 2; 671 break; 672 673 default: /* unknown or undecodable header */ 674 *prot = nh; /* meaningless, but set here anyway */ 675 return(NULL); 676 } 677 } 678 679 return(NULL); /* should be notreached, though */ 680} 681 682static void 683icmp6_opt_print(const u_char *bp, int resid) 684{ 685 const struct nd_opt_hdr *op; 686 const struct nd_opt_hdr *opl; /* why there's no struct? */ 687 const struct nd_opt_prefix_info *opp; 688 const struct icmp6_opts_redirect *opr; 689 const struct nd_opt_mtu *opm; 690 const struct nd_opt_rdnss *oprd; 691 const struct nd_opt_advinterval *opa; 692 const struct nd_opt_homeagent_info *oph; 693 const struct nd_opt_route_info *opri; 694 const u_char *cp, *ep; 695 struct in6_addr in6, *in6p; 696 size_t l; 697 u_int i; 698 699#define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 700 701 cp = bp; 702 /* 'ep' points to the end of available data. */ 703 ep = snapend; 704 705 while (cp < ep) { 706 op = (struct nd_opt_hdr *)cp; 707 708 ECHECK(op->nd_opt_len); 709 if (resid <= 0) 710 return; 711 if (op->nd_opt_len == 0) 712 goto trunc; 713 if (cp + (op->nd_opt_len << 3) > ep) 714 goto trunc; 715 716 printf("\n\t %s option (%u), length %u (%u): ", 717 tok2str(icmp6_opt_values, "unknown", op->nd_opt_type), 718 op->nd_opt_type, 719 op->nd_opt_len << 3, 720 op->nd_opt_len); 721 722 switch (op->nd_opt_type) { 723 case ND_OPT_SOURCE_LINKADDR: 724 opl = (struct nd_opt_hdr *)op; 725 l = (op->nd_opt_len << 3) - 2; 726 print_lladdr(cp + 2, l); 727 break; 728 case ND_OPT_TARGET_LINKADDR: 729 opl = (struct nd_opt_hdr *)op; 730 l = (op->nd_opt_len << 3) - 2; 731 print_lladdr(cp + 2, l); 732 break; 733 case ND_OPT_PREFIX_INFORMATION: 734 opp = (struct nd_opt_prefix_info *)op; 735 TCHECK(opp->nd_opt_pi_prefix); 736 printf("%s/%u%s, Flags [%s], valid time %ss", 737 ip6addr_string(&opp->nd_opt_pi_prefix), 738 opp->nd_opt_pi_prefix_len, 739 (op->nd_opt_len != 4) ? "badlen" : "", 740 bittok2str(icmp6_opt_pi_flag_values, "none", opp->nd_opt_pi_flags_reserved), 741 get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_valid_time))); 742 printf(", pref. time %ss", get_lifetime(EXTRACT_32BITS(&opp->nd_opt_pi_preferred_time))); 743 break; 744 case ND_OPT_REDIRECTED_HEADER: 745 opr = (struct icmp6_opts_redirect *)op; 746 print_unknown_data(bp,"\n\t ",op->nd_opt_len<<3); 747 /* xxx */ 748 break; 749 case ND_OPT_MTU: 750 opm = (struct nd_opt_mtu *)op; 751 TCHECK(opm->nd_opt_mtu_mtu); 752 printf(" %u%s", 753 EXTRACT_32BITS(&opm->nd_opt_mtu_mtu), 754 (op->nd_opt_len != 1) ? "bad option length" : "" ); 755 break; 756 case ND_OPT_RDNSS: 757 oprd = (struct nd_opt_rdnss *)op; 758 l = (op->nd_opt_len - 1) / 2; 759 printf(" lifetime %us,", 760 EXTRACT_32BITS(&oprd->nd_opt_rdnss_lifetime)); 761 for (i = 0; i < l; i++) { 762 TCHECK(oprd->nd_opt_rdnss_addr[i]); 763 printf(" addr: %s", 764 ip6addr_string(&oprd->nd_opt_rdnss_addr[i])); 765 } 766 break; 767 case ND_OPT_ADVINTERVAL: 768 opa = (struct nd_opt_advinterval *)op; 769 TCHECK(opa->nd_opt_adv_interval); 770 printf(" %us", EXTRACT_32BITS(&opa->nd_opt_adv_interval)); 771 break; 772 case ND_OPT_HOMEAGENT_INFO: 773 oph = (struct nd_opt_homeagent_info *)op; 774 TCHECK(oph->nd_opt_hai_lifetime); 775 printf(" preference %u, lifetime %u", 776 EXTRACT_16BITS(&oph->nd_opt_hai_preference), 777 EXTRACT_16BITS(&oph->nd_opt_hai_lifetime)); 778 break; 779 case ND_OPT_ROUTE_INFO: 780 opri = (struct nd_opt_route_info *)op; 781 TCHECK(opri->nd_opt_rti_lifetime); 782 memset(&in6, 0, sizeof(in6)); 783 in6p = (struct in6_addr *)(opri + 1); 784 switch (op->nd_opt_len) { 785 case 1: 786 break; 787 case 2: 788 TCHECK2(*in6p, 8); 789 memcpy(&in6, opri + 1, 8); 790 break; 791 case 3: 792 TCHECK(*in6p); 793 memcpy(&in6, opri + 1, sizeof(in6)); 794 break; 795 default: 796 goto trunc; 797 } 798 printf(" %s/%u", ip6addr_string(&in6), 799 opri->nd_opt_rti_prefixlen); 800 printf(", pref=%s", get_rtpref(opri->nd_opt_rti_flags)); 801 printf(", lifetime=%s", 802 get_lifetime(EXTRACT_32BITS(&opri->nd_opt_rti_lifetime))); 803 break; 804 default: 805 if (vflag <= 1) { 806 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 807 return; 808 } 809 break; 810 } 811 /* do we want to see an additional hexdump ? */ 812 if (vflag> 1) 813 print_unknown_data(cp+2,"\n\t ", (op->nd_opt_len << 3) - 2); /* skip option header */ 814 815 cp += op->nd_opt_len << 3; 816 resid -= op->nd_opt_len << 3; 817 } 818 return; 819 820 trunc: 821 fputs("[ndp opt]", stdout); 822 return; 823#undef ECHECK 824} 825 826static void 827mld6_print(const u_char *bp) 828{ 829 struct mld6_hdr *mp = (struct mld6_hdr *)bp; 830 const u_char *ep; 831 832 /* 'ep' points to the end of available data. */ 833 ep = snapend; 834 835 if ((u_char *)mp + sizeof(*mp) > ep) 836 return; 837 838 printf("max resp delay: %d ", EXTRACT_16BITS(&mp->mld6_maxdelay)); 839 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 840} 841 842static void 843mldv2_report_print(const u_char *bp, u_int len) 844{ 845 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 846 u_int group, nsrcs, ngroups; 847 u_int i, j; 848 849 /* Minimum len is 8 */ 850 if (len < 8) { 851 printf(" [invalid len %d]", len); 852 return; 853 } 854 855 TCHECK(icp->icmp6_data16[1]); 856 ngroups = EXTRACT_16BITS(&icp->icmp6_data16[1]); 857 printf(", %d group record(s)", ngroups); 858 if (vflag > 0) { 859 /* Print the group records */ 860 group = 8; 861 for (i = 0; i < ngroups; i++) { 862 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 863 if (len < group + 20) { 864 printf(" [invalid number of groups]"); 865 return; 866 } 867 TCHECK2(bp[group + 4], sizeof(struct in6_addr)); 868 printf(" [gaddr %s", ip6addr_string(&bp[group + 4])); 869 printf(" %s", tok2str(mldv2report2str, " [v2-report-#%d]", 870 bp[group])); 871 nsrcs = (bp[group + 2] << 8) + bp[group + 3]; 872 /* Check the number of sources and print them */ 873 if (len < group + 20 + (nsrcs * sizeof(struct in6_addr))) { 874 printf(" [invalid number of sources %d]", nsrcs); 875 return; 876 } 877 if (vflag == 1) 878 printf(", %d source(s)", nsrcs); 879 else { 880 /* Print the sources */ 881 (void)printf(" {"); 882 for (j = 0; j < nsrcs; j++) { 883 TCHECK2(bp[group + 20 + j * sizeof(struct in6_addr)], 884 sizeof(struct in6_addr)); 885 printf(" %s", ip6addr_string(&bp[group + 20 + j * sizeof(struct in6_addr)])); 886 } 887 (void)printf(" }"); 888 } 889 /* Next group record */ 890 group += 20 + nsrcs * sizeof(struct in6_addr); 891 printf("]"); 892 } 893 } 894 return; 895trunc: 896 (void)printf("[|icmp6]"); 897 return; 898} 899 900static void 901mldv2_query_print(const u_char *bp, u_int len) 902{ 903 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 904 u_int mrc; 905 int mrt, qqi; 906 u_int nsrcs; 907 register u_int i; 908 909 /* Minimum len is 28 */ 910 if (len < 28) { 911 printf(" [invalid len %d]", len); 912 return; 913 } 914 TCHECK(icp->icmp6_data16[0]); 915 mrc = EXTRACT_16BITS(&icp->icmp6_data16[0]); 916 if (mrc < 32768) { 917 mrt = mrc; 918 } else { 919 mrt = ((mrc & 0x0fff) | 0x1000) << (((mrc & 0x7000) >> 12) + 3); 920 } 921 if (vflag) { 922 (void)printf(" [max resp delay=%d]", mrt); 923 } 924 TCHECK2(bp[8], sizeof(struct in6_addr)); 925 printf(" [gaddr %s", ip6addr_string(&bp[8])); 926 927 if (vflag) { 928 TCHECK(bp[25]); 929 if (bp[24] & 0x08) { 930 printf(" sflag"); 931 } 932 if (bp[24] & 0x07) { 933 printf(" robustness=%d", bp[24] & 0x07); 934 } 935 if (bp[25] < 128) { 936 qqi = bp[25]; 937 } else { 938 qqi = ((bp[25] & 0x0f) | 0x10) << (((bp[25] & 0x70) >> 4) + 3); 939 } 940 printf(" qqi=%d", qqi); 941 } 942 943 TCHECK2(bp[26], 2); 944 nsrcs = EXTRACT_16BITS(&bp[26]); 945 if (nsrcs > 0) { 946 if (len < 28 + nsrcs * sizeof(struct in6_addr)) 947 printf(" [invalid number of sources]"); 948 else if (vflag > 1) { 949 printf(" {"); 950 for (i = 0; i < nsrcs; i++) { 951 TCHECK2(bp[28 + i * sizeof(struct in6_addr)], 952 sizeof(struct in6_addr)); 953 printf(" %s", ip6addr_string(&bp[28 + i * sizeof(struct in6_addr)])); 954 } 955 printf(" }"); 956 } else 957 printf(", %d source(s)", nsrcs); 958 } 959 printf("]"); 960 return; 961trunc: 962 (void)printf("[|icmp6]"); 963 return; 964} 965 966static void 967dnsname_print(const u_char *cp, const u_char *ep) 968{ 969 int i; 970 971 /* DNS name decoding - no decompression */ 972 printf(", \""); 973 while (cp < ep) { 974 i = *cp++; 975 if (i) { 976 if (i > ep - cp) { 977 printf("???"); 978 break; 979 } 980 while (i-- && cp < ep) { 981 safeputchar(*cp); 982 cp++; 983 } 984 if (cp + 1 < ep && *cp) 985 printf("."); 986 } else { 987 if (cp == ep) { 988 /* FQDN */ 989 printf("."); 990 } else if (cp + 1 == ep && *cp == '\0') { 991 /* truncated */ 992 } else { 993 /* invalid */ 994 printf("???"); 995 } 996 break; 997 } 998 } 999 printf("\""); 1000} 1001 1002static void 1003icmp6_nodeinfo_print(u_int icmp6len, const u_char *bp, const u_char *ep) 1004{ 1005 struct icmp6_nodeinfo *ni6; 1006 struct icmp6_hdr *dp; 1007 const u_char *cp; 1008 size_t siz, i; 1009 int needcomma; 1010 1011 if (ep < bp) 1012 return; 1013 dp = (struct icmp6_hdr *)bp; 1014 ni6 = (struct icmp6_nodeinfo *)bp; 1015 siz = ep - bp; 1016 1017 switch (ni6->ni_type) { 1018 case ICMP6_NI_QUERY: 1019 if (siz == sizeof(*dp) + 4) { 1020 /* KAME who-are-you */ 1021 printf(" who-are-you request"); 1022 break; 1023 } 1024 printf(" node information query"); 1025 1026 TCHECK2(*dp, sizeof(*ni6)); 1027 ni6 = (struct icmp6_nodeinfo *)dp; 1028 printf(" ("); /*)*/ 1029 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1030 case NI_QTYPE_NOOP: 1031 printf("noop"); 1032 break; 1033 case NI_QTYPE_SUPTYPES: 1034 printf("supported qtypes"); 1035 i = EXTRACT_16BITS(&ni6->ni_flags); 1036 if (i) 1037 printf(" [%s]", (i & 0x01) ? "C" : ""); 1038 break; 1039 break; 1040 case NI_QTYPE_FQDN: 1041 printf("DNS name"); 1042 break; 1043 case NI_QTYPE_NODEADDR: 1044 printf("node addresses"); 1045 i = ni6->ni_flags; 1046 if (!i) 1047 break; 1048 /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ 1049 printf(" [%s%s%s%s%s%s]", 1050 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1051 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1052 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1053 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1054 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1055 (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); 1056 break; 1057 default: 1058 printf("unknown"); 1059 break; 1060 } 1061 1062 if (ni6->ni_qtype == NI_QTYPE_NOOP || 1063 ni6->ni_qtype == NI_QTYPE_SUPTYPES) { 1064 if (siz != sizeof(*ni6)) 1065 if (vflag) 1066 printf(", invalid len"); 1067 /*(*/ 1068 printf(")"); 1069 break; 1070 } 1071 1072 1073 /* XXX backward compat, icmp-name-lookup-03 */ 1074 if (siz == sizeof(*ni6)) { 1075 printf(", 03 draft"); 1076 /*(*/ 1077 printf(")"); 1078 break; 1079 } 1080 1081 switch (ni6->ni_code) { 1082 case ICMP6_NI_SUBJ_IPV6: 1083 if (!TTEST2(*dp, 1084 sizeof(*ni6) + sizeof(struct in6_addr))) 1085 break; 1086 if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { 1087 if (vflag) 1088 printf(", invalid subject len"); 1089 break; 1090 } 1091 printf(", subject=%s", 1092 getname6((const u_char *)(ni6 + 1))); 1093 break; 1094 case ICMP6_NI_SUBJ_FQDN: 1095 printf(", subject=DNS name"); 1096 cp = (const u_char *)(ni6 + 1); 1097 if (cp[0] == ep - cp - 1) { 1098 /* icmp-name-lookup-03, pascal string */ 1099 if (vflag) 1100 printf(", 03 draft"); 1101 cp++; 1102 printf(", \""); 1103 while (cp < ep) { 1104 safeputchar(*cp); 1105 cp++; 1106 } 1107 printf("\""); 1108 } else 1109 dnsname_print(cp, ep); 1110 break; 1111 case ICMP6_NI_SUBJ_IPV4: 1112 if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) 1113 break; 1114 if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { 1115 if (vflag) 1116 printf(", invalid subject len"); 1117 break; 1118 } 1119 printf(", subject=%s", 1120 getname((const u_char *)(ni6 + 1))); 1121 break; 1122 default: 1123 printf(", unknown subject"); 1124 break; 1125 } 1126 1127 /*(*/ 1128 printf(")"); 1129 break; 1130 1131 case ICMP6_NI_REPLY: 1132 if (icmp6len > siz) { 1133 printf("[|icmp6: node information reply]"); 1134 break; 1135 } 1136 1137 needcomma = 0; 1138 1139 ni6 = (struct icmp6_nodeinfo *)dp; 1140 printf(" node information reply"); 1141 printf(" ("); /*)*/ 1142 switch (ni6->ni_code) { 1143 case ICMP6_NI_SUCCESS: 1144 if (vflag) { 1145 printf("success"); 1146 needcomma++; 1147 } 1148 break; 1149 case ICMP6_NI_REFUSED: 1150 printf("refused"); 1151 needcomma++; 1152 if (siz != sizeof(*ni6)) 1153 if (vflag) 1154 printf(", invalid length"); 1155 break; 1156 case ICMP6_NI_UNKNOWN: 1157 printf("unknown"); 1158 needcomma++; 1159 if (siz != sizeof(*ni6)) 1160 if (vflag) 1161 printf(", invalid length"); 1162 break; 1163 } 1164 1165 if (ni6->ni_code != ICMP6_NI_SUCCESS) { 1166 /*(*/ 1167 printf(")"); 1168 break; 1169 } 1170 1171 switch (EXTRACT_16BITS(&ni6->ni_qtype)) { 1172 case NI_QTYPE_NOOP: 1173 if (needcomma) 1174 printf(", "); 1175 printf("noop"); 1176 if (siz != sizeof(*ni6)) 1177 if (vflag) 1178 printf(", invalid length"); 1179 break; 1180 case NI_QTYPE_SUPTYPES: 1181 if (needcomma) 1182 printf(", "); 1183 printf("supported qtypes"); 1184 i = EXTRACT_16BITS(&ni6->ni_flags); 1185 if (i) 1186 printf(" [%s]", (i & 0x01) ? "C" : ""); 1187 break; 1188 case NI_QTYPE_FQDN: 1189 if (needcomma) 1190 printf(", "); 1191 printf("DNS name"); 1192 cp = (const u_char *)(ni6 + 1) + 4; 1193 if (cp[0] == ep - cp - 1) { 1194 /* icmp-name-lookup-03, pascal string */ 1195 if (vflag) 1196 printf(", 03 draft"); 1197 cp++; 1198 printf(", \""); 1199 while (cp < ep) { 1200 safeputchar(*cp); 1201 cp++; 1202 } 1203 printf("\""); 1204 } else 1205 dnsname_print(cp, ep); 1206 if ((EXTRACT_16BITS(&ni6->ni_flags) & 0x01) != 0) 1207 printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); 1208 break; 1209 case NI_QTYPE_NODEADDR: 1210 if (needcomma) 1211 printf(", "); 1212 printf("node addresses"); 1213 i = sizeof(*ni6); 1214 while (i < siz) { 1215 if (i + sizeof(struct in6_addr) + sizeof(int32_t) > siz) 1216 break; 1217 printf(" %s", getname6(bp + i)); 1218 i += sizeof(struct in6_addr); 1219 printf("(%d)", (int32_t)EXTRACT_32BITS(bp + i)); 1220 i += sizeof(int32_t); 1221 } 1222 i = ni6->ni_flags; 1223 if (!i) 1224 break; 1225 printf(" [%s%s%s%s%s%s%s]", 1226 (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", 1227 (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", 1228 (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", 1229 (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", 1230 (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", 1231 (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", 1232 (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); 1233 break; 1234 default: 1235 if (needcomma) 1236 printf(", "); 1237 printf("unknown"); 1238 break; 1239 } 1240 1241 /*(*/ 1242 printf(")"); 1243 break; 1244 } 1245 return; 1246 1247trunc: 1248 fputs("[|icmp6]", stdout); 1249} 1250 1251static void 1252icmp6_rrenum_print(const u_char *bp, const u_char *ep) 1253{ 1254 struct icmp6_router_renum *rr6; 1255 const char *cp; 1256 struct rr_pco_match *match; 1257 struct rr_pco_use *use; 1258 char hbuf[NI_MAXHOST]; 1259 int n; 1260 1261 if (ep < bp) 1262 return; 1263 rr6 = (struct icmp6_router_renum *)bp; 1264 cp = (const char *)(rr6 + 1); 1265 1266 TCHECK(rr6->rr_reserved); 1267 switch (rr6->rr_code) { 1268 case ICMP6_ROUTER_RENUMBERING_COMMAND: 1269 printf("router renum: command"); 1270 break; 1271 case ICMP6_ROUTER_RENUMBERING_RESULT: 1272 printf("router renum: result"); 1273 break; 1274 case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET: 1275 printf("router renum: sequence number reset"); 1276 break; 1277 default: 1278 printf("router renum: code-#%d", rr6->rr_code); 1279 break; 1280 } 1281 1282 printf(", seq=%u", EXTRACT_32BITS(&rr6->rr_seqnum)); 1283 1284 if (vflag) { 1285#define F(x, y) ((rr6->rr_flags) & (x) ? (y) : "") 1286 printf("["); /*]*/ 1287 if (rr6->rr_flags) { 1288 printf("%s%s%s%s%s,", F(ICMP6_RR_FLAGS_TEST, "T"), 1289 F(ICMP6_RR_FLAGS_REQRESULT, "R"), 1290 F(ICMP6_RR_FLAGS_FORCEAPPLY, "A"), 1291 F(ICMP6_RR_FLAGS_SPECSITE, "S"), 1292 F(ICMP6_RR_FLAGS_PREVDONE, "P")); 1293 } 1294 printf("seg=%u,", rr6->rr_segnum); 1295 printf("maxdelay=%u", EXTRACT_16BITS(&rr6->rr_maxdelay)); 1296 if (rr6->rr_reserved) 1297 printf("rsvd=0x%x", EXTRACT_32BITS(&rr6->rr_reserved)); 1298 /*[*/ 1299 printf("]"); 1300#undef F 1301 } 1302 1303 if (rr6->rr_code == ICMP6_ROUTER_RENUMBERING_COMMAND) { 1304 match = (struct rr_pco_match *)cp; 1305 cp = (const char *)(match + 1); 1306 1307 TCHECK(match->rpm_prefix); 1308 1309 if (vflag > 1) 1310 printf("\n\t"); 1311 else 1312 printf(" "); 1313 printf("match("); /*)*/ 1314 switch (match->rpm_code) { 1315 case RPM_PCO_ADD: printf("add"); break; 1316 case RPM_PCO_CHANGE: printf("change"); break; 1317 case RPM_PCO_SETGLOBAL: printf("setglobal"); break; 1318 default: printf("#%u", match->rpm_code); break; 1319 } 1320 1321 if (vflag) { 1322 printf(",ord=%u", match->rpm_ordinal); 1323 printf(",min=%u", match->rpm_minlen); 1324 printf(",max=%u", match->rpm_maxlen); 1325 } 1326 if (inet_ntop(AF_INET6, &match->rpm_prefix, hbuf, sizeof(hbuf))) 1327 printf(",%s/%u", hbuf, match->rpm_matchlen); 1328 else 1329 printf(",?/%u", match->rpm_matchlen); 1330 /*(*/ 1331 printf(")"); 1332 1333 n = match->rpm_len - 3; 1334 if (n % 4) 1335 goto trunc; 1336 n /= 4; 1337 while (n-- > 0) { 1338 use = (struct rr_pco_use *)cp; 1339 cp = (const char *)(use + 1); 1340 1341 TCHECK(use->rpu_prefix); 1342 1343 if (vflag > 1) 1344 printf("\n\t"); 1345 else 1346 printf(" "); 1347 printf("use("); /*)*/ 1348 if (use->rpu_flags) { 1349#define F(x, y) ((use->rpu_flags) & (x) ? (y) : "") 1350 printf("%s%s,", 1351 F(ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME, "V"), 1352 F(ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME, "P")); 1353#undef F 1354 } 1355 if (vflag) { 1356 printf("mask=0x%x,", use->rpu_ramask); 1357 printf("raflags=0x%x,", use->rpu_raflags); 1358 if (~use->rpu_vltime == 0) 1359 printf("vltime=infty,"); 1360 else 1361 printf("vltime=%u,", 1362 EXTRACT_32BITS(&use->rpu_vltime)); 1363 if (~use->rpu_pltime == 0) 1364 printf("pltime=infty,"); 1365 else 1366 printf("pltime=%u,", 1367 EXTRACT_32BITS(&use->rpu_pltime)); 1368 } 1369 if (inet_ntop(AF_INET6, &use->rpu_prefix, hbuf, 1370 sizeof(hbuf))) 1371 printf("%s/%u/%u", hbuf, use->rpu_uselen, 1372 use->rpu_keeplen); 1373 else 1374 printf("?/%u/%u", use->rpu_uselen, 1375 use->rpu_keeplen); 1376 /*(*/ 1377 printf(")"); 1378 } 1379 } 1380 1381 return; 1382 1383trunc: 1384 fputs("[|icmp6]", stdout); 1385} 1386 1387#endif /* INET6 */ 1388