summaryrefslogtreecommitdiff
path: root/sbin/ping6/ping6.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/ping6/ping6.c')
-rw-r--r--sbin/ping6/ping6.c801
1 files changed, 542 insertions, 259 deletions
diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c
index c1b0edf3075..19c86ce154a 100644
--- a/sbin/ping6/ping6.c
+++ b/sbin/ping6/ping6.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ping6.c,v 1.9 2000/06/30 16:00:10 millert Exp $ */
-/* $KAME: ping6.c,v 1.55 2000/06/12 16:18:32 itojun Exp $ */
+/* $OpenBSD: ping6.c,v 1.10 2000/08/13 20:17:00 itojun Exp $ */
+/* $KAME: ping6.c,v 1.72 2000/08/13 20:12:48 itojun Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -116,13 +116,16 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
+#include <arpa/nameser.h>
#include <netdb.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#ifdef __OpenBSD__
#include <math.h>
+#endif
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -134,14 +137,19 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
#include <netinet6/ipsec.h>
#endif
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <md5.h>
+#else
+#include "md5.h"
+#endif
#define MAXPACKETLEN 131072
#define IP6LEN 40
#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */
#define ICMP6ECHOTMLEN sizeof(struct timeval)
#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8)
-#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12) /* 64 bits of nonce + 32 bits ttl */
+/* FQDN case, 64 bits of nonce + 32 bits ttl */
+#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12)
#define EXTRA 256 /* for AH and various other headers. weird. */
#define DEFDATALEN ICMP6ECHOTMLEN
#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
@@ -179,6 +187,8 @@ static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
#define F_HOSTNAME 0x10000
#define F_FQDNOLD 0x20000
#define F_NIGROUP 0x40000
+#define F_SUPTYPES 0x80000
+#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
u_int options;
#define IN6LEN sizeof(struct in6_addr)
@@ -206,6 +216,7 @@ char BSPACE = '\b'; /* characters written for flood */
char DOT = '.';
char *hostname;
int ident; /* process id to identify our packets */
+u_int8_t nonce[8]; /* nonce field for node information */
struct in6_addr srcaddr;
/* counters */
@@ -213,7 +224,7 @@ long npackets; /* max packets to transmit */
long nreceived; /* # of packets we got back */
long nrepeats; /* number of duplicates */
long ntransmitted; /* sequence # for outbound packets = #sent */
-double interval = 1; /* interval between packets */
+struct timeval interval = {1, 0}; /* interval between packets */
int hoplimit = -1; /* hoplimit */
/* timing */
@@ -221,7 +232,9 @@ int timing; /* flag to do timing */
double tmin = 999999999.0; /* minimum round trip time */
double tmax = 0.0; /* maximum round trip time */
double tsum = 0.0; /* sum of all times, for doing average */
+#ifdef __OpenBSD__
double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+#endif
/* for node addresses */
u_short naflags;
@@ -243,6 +256,10 @@ const char *pr_addr __P((struct sockaddr_in6 *));
void pr_icmph __P((struct icmp6_hdr *, u_char *));
void pr_iph __P((struct ip6_hdr *));
void pr_nodeaddr __P((struct icmp6_nodeinfo *, int));
+int myechoreply __P((const struct icmp6_hdr *));
+int mynireply __P((const struct icmp6_nodeinfo *));
+char *dnsdecode __P((const u_char **, const u_char *, const u_char *,
+ u_char *, size_t));
void pr_pack __P((u_char *, int, struct msghdr *));
void pr_exthdrs __P((struct msghdr *));
void pr_ip6opt __P((void *));
@@ -259,10 +276,6 @@ main(argc, argv)
int argc;
char *argv[];
{
-#if defined(__FreeBSD__) && __FreeBSD__ < 3
- extern int optind;
- extern char *optarg;
-#endif
struct itimerval itimer;
struct sockaddr_in6 from;
struct timeval timeout;
@@ -280,10 +293,14 @@ main(argc, argv)
#ifdef USE_RFC2292BIS
struct ip6_rthdr *rthdr = NULL;
#endif
+#ifndef __OpenBSD__
+ struct timeval tv;
+#endif
#ifdef IPSEC_POLICY_IPSEC
char *policy_in = NULL;
char *policy_out = NULL;
#endif
+ double intval;
/* just to be sure */
memset(&smsghdr, 0, sizeof(&smsghdr));
@@ -292,54 +309,54 @@ main(argc, argv)
preload = 0;
datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
#ifndef IPSEC
- while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwW")) != -1)
+ while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwW")) != EOF)
#else
#ifdef IPSEC_POLICY_IPSEC
- while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWP:")) != -1)
+ while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwWP:")) != EOF)
#else
- while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:vwWAE")) != -1)
+ while ((ch = getopt(argc, argv, "a:b:c:dfHh:I:i:l:nNp:qRS:s:tvwWAE")) != EOF)
#endif /*IPSEC_POLICY_IPSEC*/
#endif
{
- switch(ch) {
- case 'a':
- {
- char *cp;
-
- options |= F_NODEADDR;
- datalen = 2048; /* XXX: enough? */
- for (cp = optarg; *cp != '\0'; cp++) {
- switch(*cp) {
- case 'a':
- naflags |= NI_NODEADDR_FLAG_ALL;
- break;
- case 'c':
- case 'C':
- naflags |= NI_NODEADDR_FLAG_COMPAT;
- break;
- case 'l':
- case 'L':
- naflags |= NI_NODEADDR_FLAG_LINKLOCAL;
- break;
- case 's':
- case 'S':
- naflags |= NI_NODEADDR_FLAG_SITELOCAL;
- break;
- case 'g':
- case 'G':
- naflags |= NI_NODEADDR_FLAG_GLOBAL;
- break;
- case 'A': /* experimental. not in the spec */
- naflags |= NI_NODEADDR_FLAG_ANYCAST;
- break;
- default:
- usage();
- /*NOTREACHED*/
- }
- }
- break;
- }
- case 'b':
+ switch (ch) {
+ case 'a':
+ {
+ char *cp;
+
+ options &= ~F_NOUSERDATA;
+ options |= F_NODEADDR;
+ for (cp = optarg; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case 'a':
+ naflags |= NI_NODEADDR_FLAG_ALL;
+ break;
+ case 'c':
+ case 'C':
+ naflags |= NI_NODEADDR_FLAG_COMPAT;
+ break;
+ case 'l':
+ case 'L':
+ naflags |= NI_NODEADDR_FLAG_LINKLOCAL;
+ break;
+ case 's':
+ case 'S':
+ naflags |= NI_NODEADDR_FLAG_SITELOCAL;
+ break;
+ case 'g':
+ case 'G':
+ naflags |= NI_NODEADDR_FLAG_GLOBAL;
+ break;
+ case 'A': /* experimental. not in the spec */
+ naflags |= NI_NODEADDR_FLAG_ANYCAST;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ break;
+ }
+ case 'b':
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
sockbufsize = atoi(optarg);
#else
@@ -381,18 +398,23 @@ main(argc, argv)
#endif
break;
case 'i': /* wait between sending packets */
- interval = strtod(optarg, NULL);
-
- if (interval <= 0 || interval >= INT_MAX)
- errx(1, "bad timing interval: %s", optarg);
-
- if (interval < 1)
- if (getuid())
- errx(1, "%s: only root may use interval < 1s", strerror(EPERM));
-
- if (interval < 0.01)
- interval = 0.01;
-
+ intval = strtod(optarg, &e);
+ if (*optarg == '\0' || *e != '\0')
+ errx(1, "illegal timing interval %s", optarg);
+ if (intval < 1 && getuid()) {
+ errx(1, "%s: only root may use interval < 1s",
+ strerror(EPERM));
+ }
+ interval.tv_sec = (long)intval;
+ interval.tv_usec =
+ (long)((intval - interval.tv_sec) * 1000000);
+ if (interval.tv_sec < 0)
+ errx(1, "illegal timing interval %s", optarg);
+ /* less than 1/hz does not make sense */
+ if (interval.tv_sec == 0 && interval.tv_usec < 10000) {
+ warnx("too small interval, raised to 0.01");
+ interval.tv_usec = 10000;
+ }
options |= F_INTERVAL;
break;
case 'l':
@@ -435,18 +457,25 @@ main(argc, argv)
datalen = strtol(optarg, &e, 10);
if (datalen <= 0 || *optarg == '\0' || *e != '\0')
errx(1, "illegal datalen value -- %s", optarg);
- if (datalen > MAXDATALEN)
+ if (datalen > MAXDATALEN) {
errx(1,
"datalen value too large, maximum is %d",
MAXDATALEN);
+ }
+ break;
+ case 't':
+ options &= ~F_NOUSERDATA;
+ options |= F_SUPTYPES;
break;
case 'v':
options |= F_VERBOSE;
break;
case 'w':
+ options &= ~F_NOUSERDATA;
options |= F_FQDN;
break;
case 'W':
+ options &= ~F_NOUSERDATA;
options |= F_FQDNOLD;
break;
#ifdef IPSEC
@@ -483,9 +512,10 @@ main(argc, argv)
}
if (argc > 1) {
-#ifdef USE_SIN6_SCOPE_ID
- ip6optlen += CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1));
-#else /* old advanced API */
+#ifdef IPV6_RECVRTHDR /* 2292bis */
+ ip6optlen += CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0,
+ argc - 1));
+#else /* RFC2292 */
ip6optlen += inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1);
#endif
}
@@ -525,19 +555,37 @@ main(argc, argv)
if (options & F_FLOOD && options & F_INTERVAL)
errx(1, "-f and -i incompatible options");
- if (datalen >= sizeof(struct timeval)) /* can we time transfer */
+ if ((options & F_NOUSERDATA) == 0 &&
+ datalen >= sizeof(struct timeval)) {
+ /* can we time transfer */
timing = 1;
+ } else {
+ /* suppress timing for node information query */
+ timing = 0;
+ datalen = 2048;
+ }
packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA;
if (!(packet = (u_char *)malloc((u_int)packlen)))
err(1, "Unable to allocate packet");
if (!(options & F_PINGFILLED))
- for (i = 8; i < datalen; ++i)
+ for (i = ICMP6ECHOLEN; i < packlen; ++i)
*datap++ = i;
ident = getpid() & 0xFFFF;
+#ifndef __OpenBSD__
+ gettimeofday(&tv, NULL);
+ srand((unsigned int)(tv.tv_sec ^ tv.tv_usec ^ (long)ident));
+ memset(nonce, 0, sizeof(nonce));
+ for (i = 0; i < sizeof(nonce); i += sizeof(int))
+ *((int *)&nonce[i]) = rand();
+#else
+ memset(nonce, 0, sizeof(nonce));
+ for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t))
+ *((u_int32_t *)&nonce[i]) = arc4random();
+#endif
if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
- err(1, "socket");
+ err(1, "socket");
hold = 1;
@@ -586,7 +634,7 @@ main(argc, argv)
if (!(options & F_VERBOSE)) {
ICMP6_FILTER_SETBLOCKALL(&filt);
if ((options & F_FQDN) || (options & F_FQDNOLD) ||
- (options & F_NODEADDR))
+ (options & F_NODEADDR) || (options & F_SUPTYPES))
ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
else
ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
@@ -734,7 +782,7 @@ main(argc, argv)
struct addrinfo *iaip;
if ((error = getaddrinfo(argv[hops], NULL, &hints, &iaip)))
- errx(1, "%s", gai_strerror(error));
+ errx(1, gai_strerror(error));
if (SIN6(res->ai_addr)->sin6_family != AF_INET6)
errx(1,
"bad addr family of an intermediate addr");
@@ -870,8 +918,7 @@ main(argc, argv)
if ((options & F_FLOOD) == 0) {
(void)signal(SIGALRM, onalrm);
- itimer.it_interval.tv_sec = interval;
- itimer.it_interval.tv_usec = 0;
+ itimer.it_interval = interval;
itimer.it_value.tv_sec = 0;
itimer.it_value.tv_usec = 1;
(void)setitimer(ITIMER_REAL, &itimer, NULL);
@@ -970,26 +1017,25 @@ pinger()
struct icmp6_hdr *icp;
struct iovec iov[2];
int i, cc;
+ struct icmp6_nodeinfo *nip;
+ int seq;
icp = (struct icmp6_hdr *)outpack;
+ nip = (struct icmp6_nodeinfo *)outpack;
memset(icp, 0, sizeof(*icp));
- icp->icmp6_code = 0;
icp->icmp6_cksum = 0;
- icp->icmp6_seq = ntransmitted++; /* htons later */
- icp->icmp6_id = htons(ident); /* ID */
-
- CLR(icp->icmp6_seq % mx_dup_ck);
- icp->icmp6_seq = htons(icp->icmp6_seq);
+ seq = ntransmitted++;
+ CLR(seq % mx_dup_ck);
if (options & F_FQDN) {
icp->icmp6_type = ICMP6_NI_QUERY;
icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
- /* XXX: overwrite icmp6_id */
- ((struct icmp6_nodeinfo *)icp)->ni_qtype = htons(NI_QTYPE_FQDN);
- ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0);
- if (timing)
- (void)gettimeofday((struct timeval *)
- &outpack[ICMP6ECHOLEN], NULL);
+ nip->ni_qtype = htons(NI_QTYPE_FQDN);
+ nip->ni_flags = htons(0);
+
+ memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
sizeof(dst.sin6_addr));
cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
@@ -997,33 +1043,43 @@ pinger()
} else if (options & F_FQDNOLD) {
/* packet format in 03 draft - no Subject data on queries */
icp->icmp6_type = ICMP6_NI_QUERY;
- /* code field is always 0 */
- /* XXX: overwrite icmp6_id */
- ((struct icmp6_nodeinfo *)icp)->ni_qtype = htons(NI_QTYPE_FQDN);
- ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0);
- if (timing)
- (void)gettimeofday((struct timeval *)
- &outpack[ICMP6ECHOLEN], NULL);
+ icp->icmp6_code = 0; /* code field is always 0 */
+ nip->ni_qtype = htons(NI_QTYPE_FQDN);
+ nip->ni_flags = htons(0);
+
+ memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
cc = ICMP6_NIQLEN;
datalen = 0;
} else if (options & F_NODEADDR) {
icp->icmp6_type = ICMP6_NI_QUERY;
icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
- /* XXX: overwrite icmp6_id */
- ((struct icmp6_nodeinfo *)icp)->ni_qtype =
- htons(NI_QTYPE_NODEADDR);
- ((struct icmp6_nodeinfo *)icp)->ni_flags = htons(0);
- if (timing)
- (void)gettimeofday((struct timeval *)
- &outpack[ICMP6ECHOLEN], NULL);
+ nip->ni_qtype = htons(NI_QTYPE_NODEADDR);
+ nip->ni_flags = naflags;
+
+ memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
sizeof(dst.sin6_addr));
cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
datalen = 0;
- ((struct icmp6_nodeinfo *)icp)->ni_flags = naflags;
- }
- else {
+ } else if (options & F_SUPTYPES) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/
+ nip->ni_qtype = htons(NI_QTYPE_SUPTYPES);
+ nip->ni_flags = 0; /* do not support compressed bitmap */
+
+ memcpy(nip->icmp6_ni_nonce, nonce, sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+ cc = ICMP6_NIQLEN;
+ datalen = 0;
+ } else {
icp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icp->icmp6_code = 0;
+ icp->icmp6_id = htons(ident);
+ icp->icmp6_seq = ntohs(seq);
if (timing)
(void)gettimeofday((struct timeval *)
&outpack[ICMP6ECHOLEN], NULL);
@@ -1050,6 +1106,98 @@ pinger()
(void)write(STDOUT_FILENO, &DOT, 1);
}
+int
+myechoreply(icp)
+ const struct icmp6_hdr *icp;
+{
+ if (ntohs(icp->icmp6_id) == ident)
+ return 1;
+ else
+ return 0;
+}
+
+int
+mynireply(nip)
+ const struct icmp6_nodeinfo *nip;
+{
+ if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
+ nonce + sizeof(u_int16_t),
+ sizeof(nonce) - sizeof(u_int16_t)) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+char *
+dnsdecode(sp, ep, base, buf, bufsiz)
+ const u_char **sp;
+ const u_char *ep;
+ const u_char *base; /*base for compressed name*/
+ u_char *buf;
+ size_t bufsiz;
+{
+ int i, l;
+ const u_char *cp;
+ char *q;
+ const char *eq;
+ char cresult[MAXDNAME + 1];
+ const u_char *comp;
+
+ cp = *sp;
+ q = buf;
+ eq = buf + bufsiz;
+
+ if (cp >= ep)
+ return NULL;
+ while (cp < ep) {
+ i = *cp;
+ if (i == 0 || cp != *sp) {
+ if (q >= eq - 1)
+ return NULL; /*result overrun*/
+ *q++ = '.';
+ }
+ if (i == 0)
+ break;
+ cp++;
+
+ if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) {
+ /* DNS compression */
+ if (!base)
+ return NULL;
+
+ comp = base + (i & 0x3f);
+ if (dnsdecode(&comp, cp, base, cresult,
+ sizeof(cresult)) == NULL)
+ return NULL;
+ if (eq - q < strlen(cresult) + 1)
+ return NULL; /*result overrun*/
+ strcpy(q, cresult); /*XXX should be strlcpy*/
+ q += strlen(q);
+ break;
+ } else if ((i & 0x3f) == i) {
+ if (i > ep - cp)
+ return NULL; /*source overrun*/
+ while (i-- > 0 && cp < ep) {
+ if (eq - q < (isprint(*cp) ? 2 : 5))
+ return NULL; /*result overrun*/
+ l = snprintf(q, eq - q,
+ isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
+ cp++;
+ q += l;
+ }
+ } else
+ return NULL; /*invalid label*/
+ }
+ if (q >= eq)
+ return NULL; /*result overrun*/
+ if (i != 0)
+ return NULL; /*not terminated*/
+ cp++;
+ *q = '\0';
+ *sp = cp;
+ return buf;
+}
+
/*
* pr_pack --
* Print out the packet, if it came from us. This logic is necessary
@@ -1065,6 +1213,7 @@ pr_pack(buf, cc, mhdr)
{
#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
struct icmp6_hdr *icp;
+ struct icmp6_nodeinfo *ni;
int i;
int hoplim;
struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
@@ -1075,6 +1224,8 @@ pr_pack(buf, cc, mhdr)
int dupflag;
size_t off;
int oldfqdn;
+ u_int16_t seq;
+ char dnsname[MAXDNAME + 1];
(void)gettimeofday(&tv, NULL);
@@ -1085,6 +1236,7 @@ pr_pack(buf, cc, mhdr)
return;
}
icp = (struct icmp6_hdr *)buf;
+ ni = (struct icmp6_nodeinfo *)buf;
off = 0;
if ((hoplim = get_hoplim(mhdr)) == -1) {
@@ -1096,11 +1248,8 @@ pr_pack(buf, cc, mhdr)
return;
}
- if (icp->icmp6_type == ICMP6_ECHO_REPLY) {
- /* XXX the following line overwrites the original packet */
- icp->icmp6_seq = ntohs(icp->icmp6_seq);
- if (ntohs(icp->icmp6_id) != ident)
- return; /* It was not our ECHO */
+ if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) {
+ seq = ntohs(icp->icmp6_seq);
++nreceived;
if (timing) {
tp = (struct timeval *)(icp + 1);
@@ -1108,19 +1257,21 @@ pr_pack(buf, cc, mhdr)
triptime = ((double)tv.tv_sec) * 1000.0 +
((double)tv.tv_usec) / 1000.0;
tsum += triptime;
+#ifdef __OpenBSD__
tsumsq += triptime * triptime;
+#endif
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
tmax = triptime;
}
- if (TST(icp->icmp6_seq % mx_dup_ck)) {
+ if (TST(seq % mx_dup_ck)) {
++nrepeats;
--nreceived;
dupflag = 1;
} else {
- SET(icp->icmp6_seq % mx_dup_ck);
+ SET(seq % mx_dup_ck);
dupflag = 0;
}
@@ -1131,8 +1282,7 @@ pr_pack(buf, cc, mhdr)
(void)write(STDOUT_FILENO, &BSPACE, 1);
else {
(void)printf("%d bytes from %s, icmp_seq=%u", cc,
- pr_addr(from),
- icp->icmp6_seq);
+ pr_addr(from), seq);
(void)printf(" hlim=%d", hoplim);
if ((options & F_VERBOSE) != 0) {
struct sockaddr_in6 dstsa;
@@ -1158,24 +1308,70 @@ pr_pack(buf, cc, mhdr)
}
}
}
- } else if (icp->icmp6_type == ICMP6_NI_REPLY) { /* ICMP6_NI_REPLY */
- struct icmp6_nodeinfo *ni = (struct icmp6_nodeinfo *)(buf + off);
-
- (void)printf("%d bytes from %s: ", cc,
- pr_addr(from));
-
- switch(ntohs(ni->ni_qtype)) {
- case NI_QTYPE_NOOP:
- printf("NodeInfo NOOP");
- break;
- case NI_QTYPE_SUPTYPES:
- printf("NodeInfo Supported Qtypes");
- break;
- case NI_QTYPE_NODEADDR:
- pr_nodeaddr(ni, end - (u_char *)ni);
- break;
- case NI_QTYPE_FQDN:
- default: /* XXX: for backward compatibility */
+ } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) {
+ seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce);
+ ++nreceived;
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ (void)printf("%d bytes from %s: ", cc, pr_addr(from));
+
+ switch (ntohs(ni->ni_code)) {
+ case ICMP6_NI_SUCCESS:
+ break;
+ case ICMP6_NI_REFUSED:
+ printf("refused, type 0x%x", ntohs(ni->ni_type));
+ goto fqdnend;
+ case ICMP6_NI_UNKNOWN:
+ printf("unknown, type 0x%x", ntohs(ni->ni_type));
+ goto fqdnend;
+ default:
+ printf("unknown code 0x%x, type 0x%x",
+ ntohs(ni->ni_code), ntohs(ni->ni_type));
+ goto fqdnend;
+ }
+
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ printf("NodeInfo NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ printf("NodeInfo Supported Qtypes");
+ if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0) {
+ printf(", compressed bitmap");
+ break;
+ } else {
+ size_t clen;
+ u_int32_t v;
+ cp = (u_char *)(ni + 1);
+ clen = (size_t)(end - cp);
+ if (clen == 0 || clen > 8192 || clen % 4) {
+ printf(", invalid length(%lu)",
+ (u_long)clen);
+ break;
+ }
+ printf(", bitmap = 0x");
+ for (dp = end - 4; dp >= cp; dp -= 4) {
+ memcpy(&v, dp, sizeof(v));
+ v = (u_int32_t)ntohl(v);
+ printf("%08x", v);
+ }
+ }
+ break;
+ case NI_QTYPE_NODEADDR:
+ pr_nodeaddr(ni, end - (u_char *)ni);
+ break;
+ case NI_QTYPE_FQDN:
+ default: /* XXX: for backward compatibility */
cp = (u_char *)ni + ICMP6_NIRLEN;
if (buf[off + ICMP6_NIRLEN] ==
cc - off - ICMP6_NIRLEN - 1)
@@ -1183,38 +1379,31 @@ pr_pack(buf, cc, mhdr)
else
oldfqdn = 0;
if (oldfqdn) {
- cp++;
+ cp++; /* skip length */
while (cp < end) {
safeputc(*cp & 0xff);
cp++;
}
} else {
+ i = 0;
while (cp < end) {
- i = *cp++;
- if (i) {
- if (i > end - cp) {
- printf("???");
- break;
- }
- while (i-- && cp < end) {
- safeputc(*cp & 0xff);
- cp++;
- }
- if (cp + 1 < end && *cp)
- printf(".");
- } else {
- if (cp == end) {
- /* FQDN */
- printf(".");
- } else if (cp + 1 == end &&
- *cp == '\0') {
- /* truncated */
- } else {
- /* invalid */
- printf("???");
- }
+ if (dnsdecode((const u_char **)&cp, end,
+ (const u_char *)(ni + 1), dnsname,
+ sizeof(dnsname)) == NULL) {
+ printf("???");
break;
}
+ /*
+ * name-lookup special handling for
+ * truncated name
+ */
+ if (cp + 1 < end && !*cp &&
+ strlen(dnsname) > 0) {
+ dnsname[strlen(dnsname) - 1] = '\0';
+ cp++;
+ }
+ printf("%s%s", i > 0 ? "," : "",
+ dnsname);
}
}
if (options & F_VERBOSE) {
@@ -1223,7 +1412,7 @@ pr_pack(buf, cc, mhdr)
(void)printf(" ("); /*)*/
- switch(ni->ni_code) {
+ switch (ni->ni_code) {
case ICMP6_NI_REFUSED:
(void)printf("refused");
comma++;
@@ -1241,13 +1430,13 @@ pr_pack(buf, cc, mhdr)
ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]);
if (comma)
printf(",");
- if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL))
+ if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) {
(void)printf("TTL=%d:meaningless",
- (int)ttl);
- else {
+ (int)ttl);
+ } else {
if (ttl < 0) {
(void)printf("TTL=%d:invalid",
- ttl);
+ ttl);
} else
(void)printf("TTL=%d", ttl);
}
@@ -1273,22 +1462,21 @@ pr_pack(buf, cc, mhdr)
if (comma)
printf(",");
(void)printf("invalid namelen:%d/%lu",
- buf[off + ICMP6_NIRLEN],
- (u_long)cc - off - ICMP6_NIRLEN - 1);
+ buf[off + ICMP6_NIRLEN],
+ (u_long)cc - off - ICMP6_NIRLEN - 1);
comma++;
}
/*(*/
putchar(')');
}
- fqdnend:
+ fqdnend:
;
}
} else {
/* We've got something other than an ECHOREPLY */
if (!(options & F_VERBOSE))
return;
- (void)printf("%d bytes from %s: ", cc,
- pr_addr(from));
+ (void)printf("%d bytes from %s: ", cc, pr_addr(from));
pr_icmph(icp, end);
}
@@ -1312,7 +1500,7 @@ pr_exthdrs(mhdr)
if (cm->cmsg_level != IPPROTO_IPV6)
continue;
- switch(cm->cmsg_type) {
+ switch (cm->cmsg_type) {
case IPV6_HOPOPTS:
printf(" HbH Options: ");
pr_ip6opt(CMSG_DATA(cm));
@@ -1445,13 +1633,13 @@ pr_nodeaddr(ni, nilen)
nilen -= sizeof(struct icmp6_nodeinfo);
if (options & F_VERBOSE) {
- switch(ni->ni_code) {
- case ICMP6_NI_REFUSED:
- (void)printf("refused");
- break;
- case ICMP6_NI_UNKNOWN:
- (void)printf("unknown qtype");
- break;
+ switch (ni->ni_code) {
+ case ICMP6_NI_REFUSED:
+ (void)printf("refused");
+ break;
+ case ICMP6_NI_UNKNOWN:
+ (void)printf("unknown qtype");
+ break;
}
if (ni->ni_flags & NI_NODEADDR_FLAG_ALL)
(void)printf(" truncated");
@@ -1572,29 +1760,32 @@ summary()
/* Only display average to microseconds */
double num = nreceived + nrepeats;
double avg = tsum / num;
+#ifdef __OpenBSD__
double dev = sqrt(tsumsq / num - avg * avg);
(void)printf(
"round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
tmin, avg, tmax, dev);
+#else
+ (void)printf(
+ "round-trip min/avg/max = %.3f/%.3f/%.3f ms\n",
+ tmin, avg, tmax);
+#endif
(void)fflush(stdout);
}
}
-#ifdef notdef
-static char *ttab[] = {
- "Echo Reply", /* ip + seq + udata */
- "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
- "Source Quench", /* IP */
- "Redirect", /* redirect type, gateway, + IP */
- "Echo",
- "Time Exceeded", /* transit, frag reassem + IP */
- "Parameter Problem", /* pointer + IP */
- "Timestamp", /* id + seq + three timestamps */
- "Timestamp Reply", /* " */
- "Info Request", /* id + sq */
- "Info Reply" /* " */
+/*subject type*/
+static char *niqcode[] = {
+ "IPv6 address",
+ "DNS label", /*or empty*/
+ "IPv4 address",
};
-#endif
+
+/*result code*/
+static char *nircode[] = {
+ "Success", "Refused", "Unknown",
+};
+
/*
* pr_icmph --
@@ -1606,10 +1797,15 @@ pr_icmph(icp, end)
u_char *end;
{
char ntop_buf[INET6_ADDRSTRLEN];
+ struct nd_redirect *red;
+ struct icmp6_nodeinfo *ni;
+ char dnsname[MAXDNAME + 1];
+ const u_char *cp;
+ size_t l;
- switch(icp->icmp6_type) {
+ switch (icp->icmp6_type) {
case ICMP6_DST_UNREACH:
- switch(icp->icmp6_code) {
+ switch (icp->icmp6_code) {
case ICMP6_DST_UNREACH_NOROUTE:
(void)printf("No Route to Destination\n");
break;
@@ -1640,7 +1836,7 @@ pr_icmph(icp, end)
pr_retip((struct ip6_hdr *)(icp + 1), end);
break;
case ICMP6_TIME_EXCEEDED:
- switch(icp->icmp6_code) {
+ switch (icp->icmp6_code) {
case ICMP6_TIME_EXCEED_TRANSIT:
(void)printf("Time to live exceeded\n");
break;
@@ -1656,19 +1852,19 @@ pr_icmph(icp, end)
break;
case ICMP6_PARAM_PROB:
(void)printf("Parameter problem: ");
- switch(icp->icmp6_code) {
- case ICMP6_PARAMPROB_HEADER:
- (void)printf("Erroneous Header ");
- break;
- case ICMP6_PARAMPROB_NEXTHEADER:
- (void)printf("Unknown Nextheader ");
- break;
- case ICMP6_PARAMPROB_OPTION:
- (void)printf("Unrecognized Option ");
- break;
- default:
- (void)printf("Bad code(%d) ", icp->icmp6_code);
- break;
+ switch (icp->icmp6_code) {
+ case ICMP6_PARAMPROB_HEADER:
+ (void)printf("Erroneous Header ");
+ break;
+ case ICMP6_PARAMPROB_NEXTHEADER:
+ (void)printf("Unknown Nextheader ");
+ break;
+ case ICMP6_PARAMPROB_OPTION:
+ (void)printf("Unrecognized Option ");
+ break;
+ default:
+ (void)printf("Bad code(%d) ", icp->icmp6_code);
+ break;
}
(void)printf("pointer = 0x%02x\n",
(int)ntohl(icp->icmp6_pptr));
@@ -1704,9 +1900,7 @@ pr_icmph(icp, end)
(void)printf("Neighbor Advertisement");
break;
case ND_REDIRECT:
- {
- struct nd_redirect *red = (struct nd_redirect *)icp;
-
+ red = (struct nd_redirect *)icp;
(void)printf("Redirect\n");
(void)printf("Destination: %s",
inet_ntop(AF_INET6, &red->nd_rd_dst,
@@ -1715,14 +1909,105 @@ pr_icmph(icp, end)
inet_ntop(AF_INET6, &red->nd_rd_target,
ntop_buf, sizeof(ntop_buf)));
break;
- }
case ICMP6_NI_QUERY:
(void)printf("Node Information Query");
/* XXX ID + Seq + Data */
+ ni = (struct icmp6_nodeinfo *)icp;
+ l = end - (u_char *)(ni + 1);
+ printf(", ");
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ (void)printf("NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ (void)printf("Supported qtypes");
+ break;
+ case NI_QTYPE_FQDN:
+ (void)printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ (void)printf("nodeaddr");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ (void)printf("IPv4 nodeaddr");
+ break;
+ default:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (options & F_VERBOSE) {
+ switch (ni->ni_code) {
+ case ICMP6_NI_SUBJ_IPV6:
+ if (l == sizeof(struct in6_addr) &&
+ inet_ntop(AF_INET6, ni + 1, ntop_buf, sizeof(ntop_buf)) != NULL) {
+ (void)printf(", subject=%s(%s)",
+ niqcode[ni->ni_code], ntop_buf);
+ } else {
+#if 1
+ /* backward compat to -W */
+ (void)printf(", oldfqdn");
+#else
+ (void)printf(", invalid");
+#endif
+ }
+ break;
+ case ICMP6_NI_SUBJ_FQDN:
+ if (end == (u_char *)(ni + 1)) {
+ (void)printf(", no subject");
+ break;
+ }
+ printf(", subject=%s", niqcode[ni->ni_code]);
+ cp = (const u_char *)(ni + 1);
+ if (dnsdecode(&cp, end, NULL, dnsname, sizeof(dnsname)) != NULL)
+ printf("(%s)", dnsname);
+ else
+ printf("(invalid)");
+ break;
+ case ICMP6_NI_SUBJ_IPV4:
+ if (l == sizeof(struct in_addr) &&
+ inet_ntop(AF_INET, ni + 1, ntop_buf, sizeof(ntop_buf)) != NULL) {
+ (void)printf(", subject=%s(%s)",
+ niqcode[ni->ni_code], ntop_buf);
+ } else
+ (void)printf(", invalid");
+ break;
+ default:
+ (void)printf(", invalid");
+ break;
+ }
+ }
break;
case ICMP6_NI_REPLY:
(void)printf("Node Information Reply");
/* XXX ID + Seq + Data */
+ ni = (struct icmp6_nodeinfo *)icp;
+ printf(", ");
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ (void)printf("NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ (void)printf("Supported qtypes");
+ break;
+ case NI_QTYPE_FQDN:
+ (void)printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ (void)printf("nodeaddr");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ (void)printf("IPv4 nodeaddr");
+ break;
+ default:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (options & F_VERBOSE) {
+ if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0]))
+ printf(", invalid");
+ else
+ printf(", %s", nircode[ni->ni_code]);
+ }
break;
default:
(void)printf("Bad ICMP type: %d", icp->icmp6_type);
@@ -1770,14 +2055,15 @@ pr_addr(addr)
if ((options & F_HOSTNAME) == 0)
flag |= NI_NUMERICHOST;
-#ifdef KAME_SCOPEID
+#ifdef NI_WITHSCOPEID
flag |= NI_WITHSCOPEID;
#endif
- getnameinfo((struct sockaddr *)addr, addr->sin6_len, buf, sizeof(buf),
- NULL, 0, flag);
-
- return (buf);
+ if (getnameinfo((struct sockaddr *)addr, addr->sin6_len,
+ buf, sizeof(buf), NULL, 0, flag) == 0)
+ return (buf);
+ else
+ return "?";
}
/*
@@ -1803,53 +2089,52 @@ pr_retip(ip6, end)
cp += hlen;
while (end - cp >= 8) {
switch (nh) {
- case IPPROTO_HOPOPTS:
- printf("HBH ");
- hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
- nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
- break;
- case IPPROTO_DSTOPTS:
- printf("DSTOPT ");
- hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
- nh = ((struct ip6_dest *)cp)->ip6d_nxt;
- break;
- case IPPROTO_FRAGMENT:
- printf("FRAG ");
- hlen = sizeof(struct ip6_frag);
- nh = ((struct ip6_frag *)cp)->ip6f_nxt;
- break;
- case IPPROTO_ROUTING:
- printf("RTHDR ");
- hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
- nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
- break;
+ case IPPROTO_HOPOPTS:
+ printf("HBH ");
+ hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
+ nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
+ break;
+ case IPPROTO_DSTOPTS:
+ printf("DSTOPT ");
+ hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
+ nh = ((struct ip6_dest *)cp)->ip6d_nxt;
+ break;
+ case IPPROTO_FRAGMENT:
+ printf("FRAG ");
+ hlen = sizeof(struct ip6_frag);
+ nh = ((struct ip6_frag *)cp)->ip6f_nxt;
+ break;
+ case IPPROTO_ROUTING:
+ printf("RTHDR ");
+ hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
+ nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
+ break;
#ifdef IPSEC
- case IPPROTO_AH:
- printf("AH ");
- hlen = (((struct ah *)cp)->ah_len+2) << 2;
- nh = ((struct ah *)cp)->ah_nxt;
- break;
+ case IPPROTO_AH:
+ printf("AH ");
+ hlen = (((struct ah *)cp)->ah_len+2) << 2;
+ nh = ((struct ah *)cp)->ah_nxt;
+ break;
#endif
- case IPPROTO_ICMPV6:
- printf("ICMP6: type = %d, code = %d\n",
- *cp, *(cp + 1));
- return;
- case IPPROTO_ESP:
- printf("ESP\n");
- return;
- case IPPROTO_TCP:
- printf("TCP: from port %u, to port %u (decimal)\n",
- (*cp * 256 + *(cp + 1)),
- (*(cp + 2) * 256 + *(cp + 3)));
- return;
- case IPPROTO_UDP:
- printf("UDP: from port %u, to port %u (decimal)\n",
- (*cp * 256 + *(cp + 1)),
- (*(cp + 2) * 256 + *(cp + 3)));
- return;
- default:
- printf("Unknown Header(%d)\n", nh);
- return;
+ case IPPROTO_ICMPV6:
+ printf("ICMP6: type = %d, code = %d\n", *cp, *(cp + 1));
+ return;
+ case IPPROTO_ESP:
+ printf("ESP\n");
+ return;
+ case IPPROTO_TCP:
+ printf("TCP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)),
+ (*(cp + 2) * 256 + *(cp + 3)));
+ return;
+ case IPPROTO_UDP:
+ printf("UDP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)),
+ (*(cp + 2) * 256 + *(cp + 3)));
+ return;
+ default:
+ printf("Unknown Header(%d)\n", nh);
+ return;
}
if ((cp += hlen) >= end)
@@ -1948,10 +2233,8 @@ nigroup(name)
MD5Update(&ctxt, name, p - name);
MD5Final(digest, &ctxt);
- bzero(&in6, sizeof(in6));
- in6.s6_addr[0] = 0xff;
- in6.s6_addr[1] = 0x02;
- in6.s6_addr[11] = 0x02;
+ if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1)
+ return NULL; /*XXX*/
bcopy(digest, &in6.s6_addr[12], 4);
if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL)