| /* |
| * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 |
| * The Regents of the University of California. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that: (1) source code distributions |
| * retain the above copyright notice and this paragraph in its entirety, (2) |
| * distributions including binary code include the above copyright notice and |
| * this paragraph in its entirety in the documentation or other materials |
| * provided with the distribution, and (3) all advertising materials mentioning |
| * features or use of this software display the following acknowledgement: |
| * ``This product includes software developed by the University of California, |
| * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of |
| * the University nor the names of its contributors may be used to endorse |
| * or promote products derived from this software without specific prior |
| * written permission. |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| */ |
| |
| #ifndef lint |
| static const char rcsid[] = |
| "@(#) $Header: /tcpdump/master/tcpdump/print-icmp6.c,v 1.18 2000-07-16 05:25:16 itojun Exp $"; |
| #endif |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #ifdef INET6 |
| |
| #include <ctype.h> |
| |
| #include <sys/param.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| |
| #include <net/if.h> |
| |
| #include <netinet/in.h> |
| #include <netinet/if_ether.h> |
| #include <netinet/in_systm.h> |
| #include <netinet/ip.h> |
| #include <netinet/ip_icmp.h> |
| #include <netinet/ip_var.h> |
| #include <netinet/udp.h> |
| #include <netinet/udp_var.h> |
| #include <netinet/tcp.h> |
| |
| #include <arpa/inet.h> |
| |
| #include <stdio.h> |
| |
| #include <netinet/ip6.h> |
| #include <netinet/icmp6.h> |
| |
| #include "interface.h" |
| #include "addrtoname.h" |
| |
| void icmp6_opt_print(const u_char *, int); |
| void mld6_print(const u_char *); |
| #ifdef HAVE_STRUCT_ICMP6_NODEINFO |
| static void dnsname_print(const u_char *, const u_char *); |
| void icmp6_nodeinfo_print(int, const u_char *, const u_char *); |
| #endif |
| |
| #ifndef abs |
| #define abs(a) ((0 < (a)) ? (a) : -(a)) |
| #endif |
| |
| #ifndef HAVE_STRUCT_ICMP6_NODEINFO |
| struct icmp6_nodeinfo { |
| struct icmp6_hdr icmp6_ni_hdr; |
| u_int8_t icmp6_ni_nonce[8]; |
| /* could be followed by reply data */ |
| }; |
| |
| #define ni_type icmp6_ni_hdr.icmp6_type |
| #define ni_code icmp6_ni_hdr.icmp6_code |
| #define ni_cksum icmp6_ni_hdr.icmp6_cksum |
| #define ni_qtype icmp6_ni_hdr.icmp6_data16[0] |
| #define ni_flags icmp6_ni_hdr.icmp6_data16[1] |
| #endif |
| |
| #ifndef ICMP6_NI_SUCCESS |
| #define ICMP6_NI_SUCESS 0 /* node information successful reply */ |
| #define ICMP6_NI_REFUSED 1 /* node information request is refused */ |
| #define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */ |
| #endif |
| |
| #ifdef NI_QTYPE_NOOP |
| #define NI_QTYPE_NOOP 0 /* NOOP */ |
| #define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */ |
| #define NI_QTYPE_FQDN 2 /* FQDN */ |
| #define NI_QTYPE_NODEADDR 3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */ |
| #endif |
| |
| #ifndef ICMP6_NI_SUBJ_IPV6 |
| #define ICMP6_NI_SUBJ_IPV6 0 /* Query Subject is an IPv6 address */ |
| #define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */ |
| #define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */ |
| #endif |
| |
| void |
| icmp6_print(register const u_char *bp, register const u_char *bp2) |
| { |
| const struct icmp6_hdr *dp; |
| register const struct ip6_hdr *ip; |
| register const char *str; |
| register const struct ip6_hdr *oip; |
| register const struct udphdr *ouh; |
| register int hlen, dport; |
| register const u_char *ep; |
| char buf[256]; |
| int icmp6len; |
| |
| #if 0 |
| #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc |
| #endif |
| |
| dp = (struct icmp6_hdr *)bp; |
| ip = (struct ip6_hdr *)bp2; |
| oip = (struct ip6_hdr *)(dp + 1); |
| str = buf; |
| /* 'ep' points to the end of avaible data. */ |
| ep = snapend; |
| if (ip->ip6_plen) |
| icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) - |
| (bp - bp2)); |
| else /* XXX: jumbo payload case... */ |
| icmp6len = snapend - bp; |
| |
| #if 0 |
| (void)printf("%s > %s: ", |
| ip6addr_string(&ip->ip6_src), |
| ip6addr_string(&ip->ip6_dst)); |
| #endif |
| |
| TCHECK(dp->icmp6_code); |
| switch (dp->icmp6_type) { |
| case ICMP6_DST_UNREACH: |
| TCHECK(oip->ip6_dst); |
| switch (dp->icmp6_code) { |
| case ICMP6_DST_UNREACH_NOROUTE: |
| printf("icmp6: %s unreachable route", |
| ip6addr_string(&oip->ip6_dst)); |
| break; |
| case ICMP6_DST_UNREACH_ADMIN: |
| printf("icmp6: %s unreachable prohibited", |
| ip6addr_string(&oip->ip6_dst)); |
| break; |
| #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE |
| case ICMP6_DST_UNREACH_BEYONDSCOPE: |
| #else |
| case ICMP6_DST_UNREACH_NOTNEIGHBOR: |
| #endif |
| printf("icmp6: %s beyond scope of source address %s", |
| ip6addr_string(&oip->ip6_dst), |
| ip6addr_string(&oip->ip6_src)); |
| break; |
| case ICMP6_DST_UNREACH_ADDR: |
| printf("icmp6: %s unreachable address", |
| ip6addr_string(&oip->ip6_dst)); |
| break; |
| case ICMP6_DST_UNREACH_NOPORT: |
| TCHECK(oip->ip6_nxt); |
| hlen = sizeof(struct ip6_hdr); |
| ouh = (struct udphdr *)(((u_char *)oip) + hlen); |
| dport = ntohs(ouh->uh_dport); |
| switch (oip->ip6_nxt) { |
| case IPPROTO_TCP: |
| printf("icmp6: %s tcp port %s unreachable", |
| ip6addr_string(&oip->ip6_dst), |
| tcpport_string(dport)); |
| break; |
| case IPPROTO_UDP: |
| printf("icmp6: %s udp port %s unreachable", |
| ip6addr_string(&oip->ip6_dst), |
| udpport_string(dport)); |
| break; |
| default: |
| printf("icmp6: %s protocol %d port %d unreachable", |
| ip6addr_string(&oip->ip6_dst), |
| oip->ip6_nxt, dport); |
| break; |
| } |
| break; |
| default: |
| printf("icmp6: %s unreachable code-#%d", |
| ip6addr_string(&oip->ip6_dst), |
| dp->icmp6_code); |
| break; |
| } |
| break; |
| case ICMP6_PACKET_TOO_BIG: |
| TCHECK(dp->icmp6_mtu); |
| printf("icmp6: too big %u\n", (u_int32_t)ntohl(dp->icmp6_mtu)); |
| break; |
| case ICMP6_TIME_EXCEEDED: |
| TCHECK(oip->ip6_dst); |
| switch (dp->icmp6_code) { |
| case ICMP6_TIME_EXCEED_TRANSIT: |
| printf("icmp6: time exceeded in-transit for %s", |
| ip6addr_string(&oip->ip6_dst)); |
| break; |
| case ICMP6_TIME_EXCEED_REASSEMBLY: |
| printf("icmp6: ip6 reassembly time exceeded"); |
| break; |
| default: |
| printf("icmp6: time exceeded code-#%d", |
| dp->icmp6_code); |
| break; |
| } |
| break; |
| case ICMP6_PARAM_PROB: |
| TCHECK(oip->ip6_dst); |
| switch (dp->icmp6_code) { |
| case ICMP6_PARAMPROB_HEADER: |
| printf("icmp6: parameter problem errorneous - octet %u\n", |
| (u_int32_t)ntohl(dp->icmp6_pptr)); |
| break; |
| case ICMP6_PARAMPROB_NEXTHEADER: |
| printf("icmp6: parameter problem next header - octet %u\n", |
| (u_int32_t)ntohl(dp->icmp6_pptr)); |
| break; |
| case ICMP6_PARAMPROB_OPTION: |
| printf("icmp6: parameter problem option - octet %u\n", |
| (u_int32_t)ntohl(dp->icmp6_pptr)); |
| break; |
| default: |
| printf("icmp6: parameter problem code-#%d", |
| dp->icmp6_code); |
| break; |
| } |
| break; |
| case ICMP6_ECHO_REQUEST: |
| printf("icmp6: echo request"); |
| break; |
| case ICMP6_ECHO_REPLY: |
| printf("icmp6: echo reply"); |
| break; |
| #if defined(HAVE_STRUCT_MLD6_HDR) || defined(HAVE_STRUCT_ICMP6_MLD) |
| case ICMP6_MEMBERSHIP_QUERY: |
| printf("icmp6: multicast listener query "); |
| mld6_print((const u_char *)dp); |
| break; |
| case ICMP6_MEMBERSHIP_REPORT: |
| printf("icmp6: multicast listener report "); |
| mld6_print((const u_char *)dp); |
| break; |
| case ICMP6_MEMBERSHIP_REDUCTION: |
| printf("icmp6: multicast listener done "); |
| mld6_print((const u_char *)dp); |
| break; |
| #endif |
| case ND_ROUTER_SOLICIT: |
| printf("icmp6: router solicitation "); |
| if (vflag) { |
| #define RTSOLLEN 8 |
| icmp6_opt_print((const u_char *)dp + RTSOLLEN, |
| icmp6len - RTSOLLEN); |
| } |
| break; |
| case ND_ROUTER_ADVERT: |
| printf("icmp6: router advertisement"); |
| if (vflag) { |
| struct nd_router_advert *p; |
| |
| p = (struct nd_router_advert *)dp; |
| TCHECK(p->nd_ra_retransmit); |
| printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); |
| if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) |
| printf("M"); |
| if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) |
| printf("O"); |
| #ifndef ND_RA_FLAG_HA |
| #define ND_RA_FLAG_HA 0x20 |
| #endif |
| if (p->nd_ra_flags_reserved & ND_RA_FLAG_HA) |
| printf("H"); |
| if (p->nd_ra_flags_reserved != 0) |
| printf(" "); |
| printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); |
| printf("reachable_time=%u, ", |
| (u_int32_t)ntohl(p->nd_ra_reachable)); |
| printf("retrans_time=%u)", |
| (u_int32_t)ntohl(p->nd_ra_retransmit)); |
| #define RTADVLEN 16 |
| icmp6_opt_print((const u_char *)dp + RTADVLEN, |
| icmp6len - RTADVLEN); |
| } |
| break; |
| case ND_NEIGHBOR_SOLICIT: |
| { |
| struct nd_neighbor_solicit *p; |
| p = (struct nd_neighbor_solicit *)dp; |
| TCHECK(p->nd_ns_target); |
| printf("icmp6: neighbor sol: who has %s", |
| ip6addr_string(&p->nd_ns_target)); |
| if (vflag) { |
| #define NDSOLLEN 24 |
| icmp6_opt_print((const u_char *)dp + NDSOLLEN, |
| icmp6len - NDSOLLEN); |
| } |
| } |
| break; |
| case ND_NEIGHBOR_ADVERT: |
| { |
| struct nd_neighbor_advert *p; |
| |
| p = (struct nd_neighbor_advert *)dp; |
| TCHECK(p->nd_na_target); |
| printf("icmp6: neighbor adv: tgt is %s", |
| ip6addr_string(&p->nd_na_target)); |
| if (vflag) { |
| #define ND_NA_FLAG_ALL \ |
| (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) |
| /* we don't need ntohl() here. see advanced-api-04. */ |
| if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { |
| #undef ND_NA_FLAG_ALL |
| u_int32_t flags; |
| |
| flags = p->nd_na_flags_reserved; |
| printf("("); |
| if (flags & ND_NA_FLAG_ROUTER) |
| printf("R"); |
| if (flags & ND_NA_FLAG_SOLICITED) |
| printf("S"); |
| if (flags & ND_NA_FLAG_OVERRIDE) |
| printf("O"); |
| printf(")"); |
| } |
| #define NDADVLEN 24 |
| icmp6_opt_print((const u_char *)dp + NDADVLEN, |
| icmp6len - NDADVLEN); |
| #undef NDADVLEN |
| } |
| } |
| break; |
| case ND_REDIRECT: |
| #define RDR(i) ((struct nd_redirect *)(i)) |
| TCHECK(RDR(dp)->nd_rd_dst); |
| printf("icmp6: redirect %s", |
| getname6((const u_char *)&RDR(dp)->nd_rd_dst)); |
| printf(" to %s", |
| getname6((const u_char*)&RDR(dp)->nd_rd_target)); |
| #define REDIRECTLEN 40 |
| if (vflag) { |
| icmp6_opt_print((const u_char *)dp + REDIRECTLEN, |
| icmp6len - REDIRECTLEN); |
| } |
| break; |
| #undef REDIRECTLEN |
| #undef RDR |
| #ifndef ICMP6_ROUTER_RENUMBERING |
| #define ICMP6_ROUTER_RENUMBERING 138 /* router renumbering */ |
| #endif |
| case ICMP6_ROUTER_RENUMBERING: |
| switch (dp->icmp6_code) { |
| #ifndef ICMP6_ROUTER_RENUMBERING_COMMAND |
| #define ICMP6_ROUTER_RENUMBERING_COMMAND 0 /* rr command */ |
| #endif |
| case ICMP6_ROUTER_RENUMBERING_COMMAND: |
| printf("icmp6: router renum command"); |
| break; |
| #ifndef ICMP6_ROUTER_RENUMBERING_RESULT |
| #define ICMP6_ROUTER_RENUMBERING_RESULT 1 /* rr result */ |
| #endif |
| case ICMP6_ROUTER_RENUMBERING_RESULT: |
| printf("icmp6: router renum result"); |
| break; |
| default: |
| printf("icmp6: router renum code-#%d", dp->icmp6_code); |
| break; |
| } |
| break; |
| #ifdef HAVE_STRUCT_ICMP6_NODEINFO |
| #ifndef ICMP6_NI_QUERY |
| #define ICMP6_NI_QUERY 139 |
| #endif |
| case ICMP6_NI_QUERY: |
| icmp6_nodeinfo_print(icmp6len, bp, ep); |
| break; |
| #ifndef ICMP6_NI_REPLY |
| #define ICMP6_NI_REPLY 140 |
| #endif |
| case ICMP6_NI_REPLY: |
| icmp6_nodeinfo_print(icmp6len, bp, ep); |
| break; |
| #endif |
| default: |
| printf("icmp6: type-#%d", dp->icmp6_type); |
| break; |
| } |
| return; |
| trunc: |
| fputs("[|icmp6]", stdout); |
| #if 0 |
| #undef TCHECK |
| #endif |
| } |
| |
| void |
| icmp6_opt_print(register const u_char *bp, int resid) |
| { |
| register const struct nd_opt_hdr *op; |
| register const struct nd_opt_hdr *opl; /* why there's no struct? */ |
| register const struct nd_opt_prefix_info *opp; |
| register const struct icmp6_opts_redirect *opr; |
| register const struct nd_opt_mtu *opm; |
| register const u_char *ep; |
| int opts_len; |
| #if 0 |
| register const struct ip6_hdr *ip; |
| register const char *str; |
| register const struct ip6_hdr *oip; |
| register const struct udphdr *ouh; |
| register int hlen, dport; |
| char buf[256]; |
| #endif |
| |
| #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return |
| |
| op = (struct nd_opt_hdr *)bp; |
| #if 0 |
| ip = (struct ip6_hdr *)bp2; |
| oip = &dp->icmp6_ip6; |
| str = buf; |
| #endif |
| /* 'ep' points to the end of avaible data. */ |
| ep = snapend; |
| |
| ECHECK(op->nd_opt_len); |
| if (resid <= 0) |
| return; |
| switch (op->nd_opt_type) { |
| case ND_OPT_SOURCE_LINKADDR: |
| opl = (struct nd_opt_hdr *)op; |
| #if 1 |
| if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) |
| goto trunc; |
| #else |
| TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); |
| #endif |
| printf("(src lladdr: %s", /*)*/ |
| etheraddr_string((u_char *)(opl + 1))); |
| if (opl->nd_opt_len != 1) |
| printf("!"); |
| /*(*/ |
| printf(")"); |
| icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), |
| resid - (op->nd_opt_len << 3)); |
| break; |
| case ND_OPT_TARGET_LINKADDR: |
| opl = (struct nd_opt_hdr *)op; |
| #if 1 |
| if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) |
| goto trunc; |
| #else |
| TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); |
| #endif |
| printf("(tgt lladdr: %s", /*)*/ |
| etheraddr_string((u_char *)(opl + 1))); |
| if (opl->nd_opt_len != 1) |
| printf("!"); |
| /*(*/ |
| printf(")"); |
| icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), |
| resid - (op->nd_opt_len << 3)); |
| break; |
| case ND_OPT_PREFIX_INFORMATION: |
| opp = (struct nd_opt_prefix_info *)op; |
| TCHECK(opp->nd_opt_pi_prefix); |
| printf("(prefix info: "); /*)*/ |
| if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) |
| printf("L"); |
| if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) |
| printf("A"); |
| if (opp->nd_opt_pi_flags_reserved) |
| printf(" "); |
| printf("valid_ltime="); |
| if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) |
| printf("infinity"); |
| else { |
| printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); |
| } |
| printf(", "); |
| printf("preffered_ltime="); |
| if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) |
| printf("infinity"); |
| else { |
| printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); |
| } |
| printf(", "); |
| printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), |
| opp->nd_opt_pi_prefix_len); |
| if (opp->nd_opt_pi_len != 4) |
| printf("!"); |
| /*(*/ |
| printf(")"); |
| icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), |
| resid - (op->nd_opt_len << 3)); |
| break; |
| case ND_OPT_REDIRECTED_HEADER: |
| opr = (struct icmp6_opts_redirect *)op; |
| printf("(redirect)"); |
| /* xxx */ |
| icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), |
| resid - (op->nd_opt_len << 3)); |
| break; |
| case ND_OPT_MTU: |
| opm = (struct nd_opt_mtu *)op; |
| TCHECK(opm->nd_opt_mtu_mtu); |
| printf("(mtu: "); /*)*/ |
| printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); |
| if (opm->nd_opt_mtu_len != 1) |
| printf("!"); |
| printf(")"); |
| icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), |
| resid - (op->nd_opt_len << 3)); |
| break; |
| default: |
| opts_len = op->nd_opt_len; |
| printf("(unknwon opt_type=%d, opt_len=%d)", |
| op->nd_opt_type, opts_len); |
| if (opts_len == 0) |
| opts_len = 1; /* XXX */ |
| icmp6_opt_print((const u_char *)op + (opts_len << 3), |
| resid - (opts_len << 3)); |
| break; |
| } |
| return; |
| trunc: |
| fputs("[ndp opt]", stdout); |
| return; |
| #undef ECHECK |
| } |
| |
| #if defined(HAVE_STRUCT_MLD6_HDR) |
| void |
| mld6_print(register const u_char *bp) |
| { |
| register struct mld6_hdr *mp = (struct mld6_hdr *)bp; |
| register const u_char *ep; |
| |
| /* 'ep' points to the end of avaible data. */ |
| ep = snapend; |
| |
| if ((u_char *)mp + sizeof(*mp) > ep) |
| return; |
| |
| printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay)); |
| printf("addr: %s", ip6addr_string(&mp->mld6_addr)); |
| } |
| |
| #elif defined(HAVE_STRUCT_ICMP6_MLD) |
| |
| void |
| mld6_print(register const u_char *bp) |
| { |
| register struct icmp6_mld *mp = (struct icmp6_mld *)bp; |
| register const u_char *ep; |
| |
| /* 'ep' points to the end of avaible data. */ |
| ep = snapend; |
| |
| if ((u_char *)mp + sizeof(*mp) > ep) |
| return; |
| |
| printf("max resp delay: %d ", ntohs(mp->icmp6m_hdr.icmp6_maxdelay)); |
| printf("addr: %s", ip6addr_string(&mp->icmp6m_group)); |
| } |
| |
| #endif |
| |
| #ifdef HAVE_STRUCT_ICMP6_NODEINFO |
| static void |
| dnsname_print(const u_char *cp, const u_char *ep) |
| { |
| int i; |
| |
| /* DNS name decoding - no decompression */ |
| printf(", \""); |
| while (cp < ep) { |
| i = *cp++; |
| if (i) { |
| if (i > ep - cp) { |
| printf("???"); |
| break; |
| } |
| while (i-- && cp < ep) { |
| safeputchar(*cp); |
| cp++; |
| } |
| if (cp + 1 < ep && *cp) |
| printf("."); |
| } else { |
| if (cp == ep) { |
| /* FQDN */ |
| printf("."); |
| } else if (cp + 1 == ep && *cp == '\0') { |
| /* truncated */ |
| } else { |
| /* invalid */ |
| printf("???"); |
| } |
| break; |
| } |
| } |
| printf("\""); |
| } |
| |
| void |
| icmp6_nodeinfo_print(int icmp6len, const u_char *bp, const u_char *ep) |
| { |
| struct icmp6_nodeinfo *ni6; |
| struct icmp6_hdr *dp; |
| const u_char *cp; |
| int siz, i; |
| int needcomma; |
| |
| dp = (struct icmp6_hdr *)bp; |
| ni6 = (struct icmp6_nodeinfo *)bp; |
| siz = ep - bp; |
| |
| switch (ni6->ni_type) { |
| case ICMP6_NI_QUERY: |
| if (siz == sizeof(*dp) + 4) { |
| /* KAME who-are-you */ |
| printf("icmp6: who-are-you request"); |
| break; |
| } |
| printf("icmp6: node information query"); |
| |
| TCHECK2(*dp, sizeof(*ni6)); |
| ni6 = (struct icmp6_nodeinfo *)dp; |
| printf(" ("); /*)*/ |
| switch (ntohs(ni6->ni_qtype)) { |
| case NI_QTYPE_NOOP: |
| printf("noop"); |
| break; |
| case NI_QTYPE_SUPTYPES: |
| printf("supported qtypes"); |
| i = ntohs(ni6->ni_flags); |
| if (i) |
| printf(" [%s]", (i & 0x01) ? "C" : ""); |
| break; |
| break; |
| case NI_QTYPE_FQDN: |
| printf("DNS name"); |
| break; |
| case NI_QTYPE_NODEADDR: |
| printf("node addresses"); |
| i = ni6->ni_flags; |
| if (!i) |
| break; |
| /* NI_NODEADDR_FLAG_TRUNCATE undefined for query */ |
| printf(" [%s%s%s%s%s%s]", |
| (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", |
| (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", |
| (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", |
| (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", |
| (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", |
| (i & NI_NODEADDR_FLAG_ALL) ? "A" : ""); |
| break; |
| default: |
| printf("unknown"); |
| break; |
| } |
| |
| if (ni6->ni_qtype == NI_QTYPE_NOOP || |
| ni6->ni_qtype == NI_QTYPE_SUPTYPES) { |
| if (siz != sizeof(*ni6)) |
| if (vflag) |
| printf(", invalid len"); |
| /*(*/ |
| printf(")"); |
| break; |
| } |
| |
| |
| /* XXX backward compat, icmp-name-lookup-03 */ |
| if (siz == sizeof(*ni6)) { |
| printf(", 03 draft"); |
| /*(*/ |
| printf(")"); |
| break; |
| } |
| |
| switch (ni6->ni_code) { |
| case ICMP6_NI_SUBJ_IPV6: |
| if (!TTEST2(*dp, |
| sizeof(*ni6) + sizeof(struct in6_addr))) |
| break; |
| if (siz != sizeof(*ni6) + sizeof(struct in6_addr)) { |
| if (vflag) |
| printf(", invalid subject len"); |
| break; |
| } |
| printf(", subject=%s", |
| getname6((const u_char *)(ni6 + 1))); |
| break; |
| case ICMP6_NI_SUBJ_FQDN: |
| printf(", subject=DNS name"); |
| cp = (const u_char *)(ni6 + 1); |
| if (cp[0] == ep - cp - 1) { |
| /* icmp-name-lookup-03, pascal string */ |
| if (vflag) |
| printf(", 03 draft"); |
| cp++; |
| printf(", \""); |
| while (cp < ep) { |
| safeputchar(*cp); |
| cp++; |
| } |
| printf("\""); |
| } else |
| dnsname_print(cp, ep); |
| break; |
| case ICMP6_NI_SUBJ_IPV4: |
| if (!TTEST2(*dp, sizeof(*ni6) + sizeof(struct in_addr))) |
| break; |
| if (siz != sizeof(*ni6) + sizeof(struct in_addr)) { |
| if (vflag) |
| printf(", invalid subject len"); |
| break; |
| } |
| printf(", subject=%s", |
| getname((const u_char *)(ni6 + 1))); |
| break; |
| default: |
| printf(", unknown subject"); |
| break; |
| } |
| |
| /*(*/ |
| printf(")"); |
| break; |
| |
| case ICMP6_NI_REPLY: |
| if (icmp6len > siz) { |
| printf("[|icmp6: node information reply]"); |
| break; |
| } |
| |
| needcomma = 0; |
| |
| ni6 = (struct icmp6_nodeinfo *)dp; |
| printf("icmp6: node information query"); |
| printf(" ("); /*)*/ |
| switch (ni6->ni_code) { |
| case ICMP6_NI_SUCESS: |
| if (vflag) { |
| printf("success"); |
| needcomma++; |
| } |
| break; |
| case ICMP6_NI_REFUSED: |
| printf("refused"); |
| needcomma++; |
| if (siz != sizeof(*ni6)) |
| if (vflag) |
| printf(", invalid length"); |
| break; |
| case ICMP6_NI_UNKNOWN: |
| printf("unknown"); |
| needcomma++; |
| if (siz != sizeof(*ni6)) |
| if (vflag) |
| printf(", invalid length"); |
| break; |
| } |
| |
| if (ni6->ni_code != ICMP6_NI_SUCESS) { |
| /*(*/ |
| printf(")"); |
| break; |
| } |
| |
| switch (ntohs(ni6->ni_qtype)) { |
| case NI_QTYPE_NOOP: |
| if (needcomma) |
| printf(", "); |
| printf("noop"); |
| if (siz != sizeof(*ni6)) |
| if (vflag) |
| printf(", invalid length"); |
| break; |
| case NI_QTYPE_SUPTYPES: |
| if (needcomma) |
| printf(", "); |
| printf("supported qtypes"); |
| i = ntohs(ni6->ni_flags); |
| if (i) |
| printf(" [%s]", (i & 0x01) ? "C" : ""); |
| break; |
| case NI_QTYPE_FQDN: |
| if (needcomma) |
| printf(", "); |
| printf("DNS name"); |
| cp = (const u_char *)(ni6 + 1) + 4; |
| if (cp[0] == ep - cp - 1) { |
| /* icmp-name-lookup-03, pascal string */ |
| if (vflag) |
| printf(", 03 draft"); |
| cp++; |
| printf(", \""); |
| while (cp < ep) { |
| safeputchar(*cp); |
| cp++; |
| } |
| printf("\""); |
| } else |
| dnsname_print(cp, ep); |
| if ((ntohs(ni6->ni_flags) & 0x01) != 0) |
| printf(" [TTL=%u]", *(u_int32_t *)(ni6 + 1)); |
| break; |
| case NI_QTYPE_NODEADDR: |
| if (needcomma) |
| printf(", "); |
| printf("node addresses"); |
| for (i = sizeof(*ni6); |
| i < siz; |
| i += sizeof(struct in6_addr)) { |
| printf(" %s", getname6(bp + i)); |
| } |
| i = ni6->ni_flags; |
| if (!i) |
| break; |
| printf(" [%s%s%s%s%s%s%s]", |
| (i & NI_NODEADDR_FLAG_ANYCAST) ? "a" : "", |
| (i & NI_NODEADDR_FLAG_GLOBAL) ? "G" : "", |
| (i & NI_NODEADDR_FLAG_SITELOCAL) ? "S" : "", |
| (i & NI_NODEADDR_FLAG_LINKLOCAL) ? "L" : "", |
| (i & NI_NODEADDR_FLAG_COMPAT) ? "C" : "", |
| (i & NI_NODEADDR_FLAG_ALL) ? "A" : "", |
| (i & NI_NODEADDR_FLAG_TRUNCATE) ? "T" : ""); |
| break; |
| default: |
| if (needcomma) |
| printf(", "); |
| printf("unknown"); |
| break; |
| } |
| |
| /*(*/ |
| printf(")"); |
| break; |
| } |
| return; |
| |
| trunc: |
| fputs("[|icmp6]", stdout); |
| } |
| #endif |
| |
| #endif /* INET6 */ |