]> Zhao Yanbai Git Server - minix.git/commitdiff
netbsd ping & traceroute 13/2713/6
authorBen Gras <ben@minix3.org>
Mon, 3 Jun 2013 10:54:08 +0000 (10:54 +0000)
committerGerrit Code Review <gerrit@localhost>
Thu, 21 Aug 2014 12:07:39 +0000 (08:07 -0400)
. remove minix ping
. add support for socket(AF_INET, SOCK_RAW, {IPPROTO_ICMP,IPPROTO_UDP})
. gives test48 a better chance of detecting network connectivity

Change-Id: Ia678546d27ac378642f1160a141e1fc33458cce2

38 files changed:
distrib/sets/lists/minix/mi
minix/commands/Makefile
minix/commands/ping/Makefile [deleted file]
minix/commands/ping/ping.c [deleted file]
minix/include/net/gen/inet.h
minix/lib/libc/sys/recvfrom.c
minix/lib/libc/sys/sendto.c
minix/lib/libc/sys/socket.c
minix/man/man1/Makefile
minix/man/man1/ping.1 [deleted file]
minix/tests/test48.c
sbin/Makefile
sbin/ping/Makefile [new file with mode: 0644]
sbin/ping/ping.8 [new file with mode: 0644]
sbin/ping/ping.c [new file with mode: 0644]
sbin/ping/ping_hostops.c [new file with mode: 0644]
sbin/ping/ping_rumpops.c [new file with mode: 0644]
sbin/ping/prog_ops.h [new file with mode: 0644]
sys/net/Makefile
sys/netinet/Makefile
sys/netinet/ip_icmp.h [new file with mode: 0644]
usr.sbin/Makefile
usr.sbin/traceroute/CHANGES [new file with mode: 0644]
usr.sbin/traceroute/Makefile [new file with mode: 0644]
usr.sbin/traceroute/as.c [new file with mode: 0644]
usr.sbin/traceroute/as.h [new file with mode: 0644]
usr.sbin/traceroute/gnuc.h [new file with mode: 0644]
usr.sbin/traceroute/ifaddrlist.c [new file with mode: 0644]
usr.sbin/traceroute/ifaddrlist.h [new file with mode: 0644]
usr.sbin/traceroute/mean.awk [new file with mode: 0644]
usr.sbin/traceroute/median.awk [new file with mode: 0644]
usr.sbin/traceroute/prog_ops.h [new file with mode: 0644]
usr.sbin/traceroute/traceroute.8 [new file with mode: 0644]
usr.sbin/traceroute/traceroute.c [new file with mode: 0644]
usr.sbin/traceroute/traceroute_hostops.c [new file with mode: 0644]
usr.sbin/traceroute/traceroute_rumpops.c [new file with mode: 0644]
usr.sbin/traceroute/trrt2netbsd [new file with mode: 0755]
usr.sbin/traceroute/version.c [new file with mode: 0644]

index d79bc793b24bde1680b298f9ec9f6ff256b8f103..611f7d5d99715e11492dff25a96814514c2c28d8 100644 (file)
 ./sbin/mknod                           minix-sys
 ./sbin/newfs_ext2fs                    minix-sys
 ./sbin/nologin                         minix-sys
+./sbin/ping                            minix-sys
 ./sbin/poweroff                                minix-sys
 ./sbin/reboot                          minix-sys
 ./sbin/shutdown                                minix-sys
 ./usr/bin/paste                                minix-sys
 ./usr/bin/patch                                minix-sys
 ./usr/bin/pathchk                      minix-sys
-./usr/bin/ping                         minix-sys
+./usr/bin/ping                          minix-sys      obsolete
 ./usr/bin/pkgin_all                    minix-sys
 ./usr/bin/pkgin_cd                     minix-sys
 ./usr/bin/pkgin_sets                   minix-sys
 ./usr/include/net/if_ether.h           minix-sys
 ./usr/include/net/if.h                 minix-sys
 ./usr/include/net/netlib.h             minix-sys
+./usr/include/net/radix.h              minix-sys
+./usr/include/net/route.h              minix-sys
 ./usr/include/netconfig.h              minix-sys
 ./usr/include/netdb.h                  minix-sys
 ./usr/include/netgroup.h               minix-sys
 ./usr/include/netinet/in.h             minix-sys
 ./usr/include/netinet/in_systm.h       minix-sys
 ./usr/include/netinet/ip.h             minix-sys
+./usr/include/netinet/ip_icmp.h                minix-sys
+./usr/include/netinet/ip_var.h         minix-sys
 ./usr/include/netinet/tcp.h            minix-sys
+./usr/include/netinet/udp.h                    minix-sys
+./usr/include/netinet/udp_var.h                        minix-sys
 ./usr/include/netinet6                 minix-sys
 ./usr/include/netinet6/in6.h           minix-sys
 ./usr/include/nlist.h                  minix-sys
 ./usr/man/man1/patch.1                 minix-sys
 ./usr/man/man1/pathchk.1               minix-sys
 ./usr/man/man1/pax.1                   minix-sys
-./usr/man/man1/ping.1                  minix-sys
+./usr/man/man1/ping.1                   minix-sys      obsolete
 ./usr/man/man1/pkg_view.1              minix-sys
 ./usr/man/man1/playwave.1              minix-sys
 ./usr/man/man1/pr.1                    minix-sys
 ./usr/man/man8/ossdevlinks.8                   minix-sys
 ./usr/man/man8/part.8                          minix-sys
 ./usr/man/man8/partition.8                     minix-sys
+./usr/man/man8/ping.8                  minix-sys
 ./usr/man/man8/postinstall.8                   minix-sys
 ./usr/man/man8/poweroff.8                      minix-sys
 ./usr/man/man8/printroot.8                     minix-sys
 ./usr/man/man8/sync.8                          minix-sys
 ./usr/man/man8/syslogd.8                       minix-sys
 ./usr/man/man8/tcpd.8                          minix-sys
+./usr/man/man8/traceroute.8                    minix-sys
 ./usr/man/man8/unix.8                          minix-sys
 ./usr/man/man8/unlink.8                                minix-sys
 ./usr/man/man8/unstr.8                         minix-sys
 ./usr/sbin/postinstall                 minix-sys
 ./usr/sbin/pwd_mkdb                    minix-sys
 ./usr/sbin/rdate                       minix-sys
+./usr/sbin/traceroute                  minix-sys
 ./usr/sbin/unlink                      minix-sys
 ./usr/sbin/user                                minix-sys
 ./usr/sbin/useradd                     minix-sys
index 11b275914d18d50646db8d63cbbc7f3219d0a933..cd7e1da4266a969e8a6b1af75955d732e1847bbf 100644 (file)
@@ -18,7 +18,7 @@ SUBDIR=       add_route arp ash at backup btrace \
        mined \
        mount mt netconf \
        nonamed \
-       ping postinstall prep printroot \
+       postinstall prep printroot \
        profile progressbar pr_routes ps pwdauth \
        ramdisk rarpd rawspeed rcp readclock \
        remsync rget rlogin \
diff --git a/minix/commands/ping/Makefile b/minix/commands/ping/Makefile
deleted file mode 100644 (file)
index 9fb8d1f..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-PROG=  ping
-BINMODE= 4755
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/minix/commands/ping/ping.c b/minix/commands/ping/ping.c
deleted file mode 100644 (file)
index de6c66c..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-ping.c
-*/
-
-#define DEBUG  1
-
-#include <sys/types.h>
-#include <errno.h>
-#include <signal.h>
-#include <net/gen/netdb.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <net/gen/oneCsum.h>
-#include <fcntl.h>
-#include <net/gen/in.h>
-#include <net/gen/inet.h>
-#include <net/gen/ip_hdr.h>
-#include <net/gen/icmp_hdr.h>
-#include <net/gen/ip_io.h>
-
-#define WRITE_SIZE 30
-char buffer[16*1024];
-
-int main(int argc, char *argv[]);
-
-#if DEBUG
-#define where() fprintf(stderr, "%s %d:", __FILE__, __LINE__);
-#endif
-
-#if __STDC__
-#define PROTO(x,y) x y
-#else
-#define PROTO(x,y) X ()
-#endif
-
-PROTO (int main, (int argc, char *argv[]) );
-static PROTO (void sig_hand, (int signal) );
-
-main(argc, argv)
-int argc;
-char *argv[];
-{
-       int fd, i;
-       int result, result1;
-       nwio_ipopt_t ipopt;
-       ip_hdr_t *ip_hdr;
-       int ihl;
-       icmp_hdr_t *icmp_hdr;
-       ipaddr_t dst_addr;
-       struct hostent *hostent;
-       int length;
-
-       if (argc<2 || argc>3)
-       {
-               fprintf(stderr, "Usage: %s hostname [length]\n", argv[0]);
-               exit(1);
-       }
-       hostent= gethostbyname(argv[1]);
-       if (!hostent)
-       {
-               dst_addr= inet_addr(argv[1]);
-               if (dst_addr == -1)
-               {
-                       fprintf(stderr, "%s: unknown host (%s)\n",
-                               argv[0], argv[1]);
-                       exit(1);
-               }
-       }
-       else
-               dst_addr= *(ipaddr_t *)(hostent->h_addr);
-       if (argc == 3)
-       {
-               length= strtol (argv[2], (char **)0, 0);
-               if (length< sizeof(icmp_hdr_t) + IP_MIN_HDR_SIZE)
-               {
-                       fprintf(stderr, "%s: length too small (%s)\n",
-                               argv[0], argv[2]);
-                       exit(1);
-               }
-       }
-       else
-               length= WRITE_SIZE;
-
-       fd= open ("/dev/ip", O_RDWR);
-       if (fd<0)
-               perror("open"), exit(1);
-
-       ipopt.nwio_flags= NWIO_COPY | NWIO_PROTOSPEC;
-       ipopt.nwio_proto= 1;
-
-       result= ioctl (fd, NWIOSIPOPT, &ipopt);
-       if (result<0)
-               perror("ioctl (NWIOSIPOPT)"), exit(1);
-
-       result= ioctl (fd, NWIOGIPOPT, &ipopt);
-       if (result<0)
-               perror("ioctl (NWIOGIPOPT)"), exit(1);
-
-       for (i= 0; i< 20; i++)
-       {
-               ip_hdr= (ip_hdr_t *)buffer;
-               ip_hdr->ih_dst= dst_addr;
-
-               icmp_hdr= (icmp_hdr_t *)(buffer+20);
-               icmp_hdr->ih_type= 8;
-               icmp_hdr->ih_code= 0;
-               icmp_hdr->ih_chksum= 0;
-               icmp_hdr->ih_chksum= ~oneC_sum(0, (u16_t *)icmp_hdr,
-                       WRITE_SIZE-20);
-               result= write(fd, buffer, length);
-               if (result<0)
-               {
-                       perror("write");
-                       exit(1);
-               }
-               if (result != length)
-               {
-                       where();
-                       fprintf(stderr, "result= %d\n", result);
-                       exit(1);
-               }
-
-               alarm(0);
-               signal (SIGALRM, sig_hand);
-               alarm(1);
-
-               result= read(fd, buffer, sizeof(buffer));
-               if (result>= 0 || errno != EINTR)
-                       break;
-       }
-       if (i >= 20)
-       {
-               printf("no answer from %s\n", argv[1]);
-               exit(1);
-       }
-       if (result<0)
-       {
-               perror ("read");
-               exit(1);
-       }
-       printf("%s is alive\n", argv[1]);
-       exit(0);
-}
-
-static void sig_hand(signal)
-int signal;
-{
-}
index 527ba686046c79cb955cb282f10274aab8baa6c8..e70c5aa8f3d173cce10f53fa09bdf13510b26d25 100644 (file)
@@ -9,7 +9,5 @@ server/ip/gen/inet.h
 
 ipaddr_t inet_addr( const char *addr );
 ipaddr_t inet_network( const char *addr );
-char *inet_ntoa( ipaddr_t addr );
-int inet_aton( const char *cp, ipaddr_t *pin );
 
 #endif /* __SERVER__IP__GEN__INET_H__ */
index 5f5a19b9eb20afad0b402d17ab639b9117dbd5c3..01d3e48c9ea5e3e6a035966f633ec1c5dac9876f 100644 (file)
@@ -20,6 +20,9 @@
 #include <net/gen/udp_hdr.h>
 #include <net/gen/udp_io.h>
 
+#include <net/gen/ip_hdr.h>
+#include <net/gen/icmp_hdr.h>
+
 #define DEBUG 0
 
 static ssize_t _tcp_recvfrom(int sock, void *__restrict buffer, size_t length,
@@ -85,6 +88,37 @@ ssize_t recvfrom(int sock, void *__restrict buffer, size_t length,
                }
        }
 
+       {
+               ip_hdr_t *ip_hdr;
+                       int ihl, rd;
+               icmp_hdr_t *icmp_hdr;
+               struct sockaddr_in sin;
+
+               rd = read(sock, buffer, length);
+
+               if(rd < 0) return rd;
+
+               assert(rd >= sizeof(*ip_hdr));
+
+               ip_hdr= buffer;
+
+               if (address != NULL)
+               {
+                       int len;
+                       memset(&sin, 0, sizeof(sin));
+                       sin.sin_family= AF_INET;
+                       sin.sin_addr.s_addr= ip_hdr->ih_src;
+                       sin.sin_len= sizeof(sin);
+                       len= *address_len;
+                       if (len > sizeof(sin))
+                               len= sizeof(sin);
+                       memcpy(address, &sin, len);
+                       *address_len= sizeof(sin);
+               }
+
+               return rd;
+       }
+
 #if DEBUG
        fprintf(stderr, "recvfrom: not implemented for fd %d\n", sock);
 #endif
index 4f174bba2338342cde5649d1d4a88e96e4bdc46a..f0d6a2811fa6b62446ae695123022cbca2687cbf 100644 (file)
@@ -14,6 +14,8 @@
 #include <netinet/in.h>
 
 #include <net/gen/in.h>
+#include <net/gen/ip_hdr.h>
+#include <net/gen/icmp_hdr.h>
 #include <net/gen/tcp.h>
 #include <net/gen/tcp_io.h>
 #include <net/gen/udp.h>
@@ -76,6 +78,26 @@ ssize_t sendto(int sock, const void *message, size_t length, int flags,
                }
        }
 
+       {
+               ip_hdr_t *ip_hdr;
+               int ihl;
+               icmp_hdr_t *icmp_hdr;
+               struct sockaddr_in *sinp;
+
+               sinp = (struct sockaddr_in *) __UNCONST(dest_addr);
+               if (sinp->sin_family != AF_INET)
+               {
+                       errno= EAFNOSUPPORT;
+                       return -1;
+               }
+
+               /* raw */
+               ip_hdr= (ip_hdr_t *)message;
+               ip_hdr->ih_dst= sinp->sin_addr.s_addr;
+
+               return write(sock, message, length);
+       }
+
 #if DEBUG
        fprintf(stderr, "sendto: not implemented for fd %d\n", sock);
 #endif
index 9f18838478ddaa6561b75a1a56e98b2811e9bacc..f73828a0187ad41838c860975d2d0d2c3b3b4640 100644 (file)
@@ -11,7 +11,19 @@ __weak_alias(socket, __socket30)
 #include <stdio.h>
 #include <unistd.h>
 #include <sys/socket.h>
+
 #include <sys/ioc_net.h>
+#include <net/hton.h>
+#include <net/gen/in.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_hdr.h>
+#include <net/gen/eth_io.h>
+#include <net/gen/ip_hdr.h>
+#include <net/gen/ip_io.h>
+#include <net/gen/udp.h>
+#include <net/gen/udp_hdr.h>
+#include <net/gen/udp_io.h>
+#include <net/gen/dhcp.h>
 
 #include <net/netlib.h>
 #include <netinet/in.h>
@@ -21,6 +33,7 @@ __weak_alias(socket, __socket30)
 static int _tcp_socket(int type, int protocol);
 static int _udp_socket(int type, int protocol);
 static int _uds_socket(int type, int protocol);
+static int _raw_socket(int type, int protocol);
 static void _socket_flags(int type, int *result);
 
 int socket(int domain, int type, int protocol)
@@ -53,6 +66,12 @@ int socket(int domain, int type, int protocol)
        if (domain == AF_INET && sock_type == SOCK_DGRAM)
                return _udp_socket(type, protocol);
 
+       if (domain == AF_INET && sock_type == SOCK_RAW && protocol == IPPROTO_ICMP)
+               return _raw_socket(type, protocol);
+
+       if (domain == AF_INET && sock_type == SOCK_RAW && protocol == IPPROTO_UDP)
+               return _raw_socket(type, protocol);
+
 #if DEBUG
        fprintf(stderr, "socket: nothing for domain %d, type %d, protocol %d\n",
                domain, type, protocol);
@@ -127,6 +146,50 @@ static int _udp_socket(int type, int protocol)
        return fd;
 }
 
+static int _raw_socket(int type, int protocol)
+{
+       int r, fd, t_errno, flags = O_RDWR;
+       struct sockaddr_in sin;
+       nwio_ipopt_t ipopt;
+       int result;
+
+       if (protocol != IPPROTO_ICMP && protocol != IPPROTO_UDP && protocol != 0)
+       {
+#if DEBUG
+               fprintf(stderr, "socket(icmp): bad protocol %d\n", protocol);
+#endif
+               errno= EPROTONOSUPPORT;
+               return -1;
+       }
+       _socket_flags(type, &flags);
+       fd= open(IP_DEVICE, flags);
+       if (fd == -1)
+               return fd;
+
+       memset(&ipopt, 0, sizeof(ipopt));
+
+        ipopt.nwio_flags= NWIO_COPY;
+
+       if(protocol) {
+               ipopt.nwio_flags |= NWIO_PROTOSPEC;
+               ipopt.nwio_proto = protocol;
+       }
+
+        result = ioctl (fd, NWIOSIPOPT, &ipopt);
+        if (result<0) {
+               close(fd);
+               return -1;
+       }
+
+        result = ioctl (fd, NWIOGIPOPT, &ipopt);
+        if (result<0) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
 static int _uds_socket(int type, int protocol)
 {
        int fd, r, flags = O_RDWR, sock_type;
index 9c6f462378fc563453028b6d18e6df8e427aa11d..8f8b8e14c011729560dfbc5fdb330800b9b39c43 100644 (file)
@@ -11,7 +11,7 @@ MAN=  ash.1 at.1 \
        look.1 lp.1 lspci.1 mail.1  \
        mixer.1 \
        mkproto.1 mount.1 mt.1 \
-       ping.1 playwave.1 prep.1 \
+       playwave.1 prep.1 \
        profile.1 ps.1 rcp.1 recwave.1 \
        remsync.1 rget.1 rlogin.1 rsh.1 rz.1 \
        spell.1 svc.1 svrctl.1 \
diff --git a/minix/man/man1/ping.1 b/minix/man/man1/ping.1
deleted file mode 100644 (file)
index 7a85db2..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-.TH PING 1
-.SH NAME
-ping \- send ICMP ECHO_REQUEST packets to network hosts 
-.SH SYNOPSIS
-.B /usr/bin/ping hostname [length]
-.de EX
-.TP 20
-\\fB\$1\\fR
-# \\$2
-..
-.SH EXAMPLES
-.TP 20
-.B ping 192.168.1.1
-# Ping host 192.168.1.1
-.TP 20
-.B ping www.minix3.org 500
-# Ping www.minix3.org with 500 byte IP packets
-.SH DESCRIPTION
-.PP
-Sends ICMP ECHO_REQUEST packets to the specified host and waits for a ECHO_REPLY.
-Optionally, the length (size) of the IP packet can be specified.  The default is
-30 bytes.  (Note, the 14 byte Ethernet header will make this a 44 byte packet.)
-.SH OPTIONS
-.IP length 
-Size (in bytes) of the transmitted ICMP packet.  The default length of the IP
-packet is 30 bytes.  (Adding the ethernet header will result in a 44 byte 
-packet being transmitted.)
-.SH "SEE ALSO"
-ifconfig(8)
-.SH AUTHOR
-Leith Brandeland <lb.minix@gmail.com>
index 33f565c664b390e45622f7cf82ed51bde022f595..fa8dba57fb101e814956aac8ebf8a17d8e27aa76 100644 (file)
@@ -580,7 +580,7 @@ static int can_use_network(void)
        int status;
 
        /* try to ping minix3.org */
-       status = system("ping www.minix3.org > /dev/null 2>&1");
+       status = system("ping -w 5 www.minix3.org > /dev/null 2>&1");
        if (status == 127)
        {
                printf("cannot execute ping\n");
index ee3735542e544df0ddc613e282c1fd47561140ee..ed2ae4306ced0404b55998009dd18202208f83aa 100644 (file)
@@ -10,9 +10,9 @@ SUBDIR= \
        chown \
        fsck init \
        mknod nologin \
+       ping \
        reboot \
        shutdown \
-       
 
 # support for various file systems
 SUBDIR+= newfs_ext2fs fsck_ext2fs
diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile
new file mode 100644 (file)
index 0000000..466f7a9
--- /dev/null
@@ -0,0 +1,22 @@
+#      $NetBSD: Makefile,v 1.17 2013/11/09 21:39:27 christos Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/5/93
+
+USE_FORT?= yes # setuid
+RUMPPRG=ping
+MAN=   ping.8
+BINOWN=        root
+BINMODE=4555
+LDADD= -lm
+DPADD= ${LIBM}
+
+# BJG - no ipsec
+#CPPFLAGS+=    -DIPSEC
+
+#LDADD+= -lipsec
+#DPADD+= ${LIBIPSEC}
+
+.if ${MACHINE_ARCH} == "vax"
+COPTS.ping.c=-O0
+.endif
+
+.include <bsd.prog.mk>
diff --git a/sbin/ping/ping.8 b/sbin/ping/ping.8
new file mode 100644 (file)
index 0000000..b74b740
--- /dev/null
@@ -0,0 +1,478 @@
+.\"    $NetBSD: ping.8,v 1.50 2011/09/10 20:47:33 wiz Exp $
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\"    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 the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)ping.8     8.2 (Berkeley) 12/11/93
+.\"
+.Dd September 10, 2011
+.Dt PING 8
+.Os
+.Sh NAME
+.Nm ping
+.Nd send
+.Tn ICMP ECHO_REQUEST
+packets to network hosts
+.Sh SYNOPSIS
+.Nm
+.Op Fl aCDdfLnoPQqRrv
+.Op Fl c Ar count
+.Op Fl E Ar policy
+.Op Fl g Ar gateway
+.Op Fl h Ar host
+.Op Fl I Ar srcaddr
+.Op Fl i Ar interval
+.Op Fl l Ar preload
+.Op Fl p Ar pattern
+.Op Fl s Ar packetsize
+.Op Fl T Ar ttl
+.Op Fl t Ar tos
+.Op Fl w Ar deadline
+.Ar host
+.Sh DESCRIPTION
+.Nm
+uses the
+.Tn ICMP
+protocol's mandatory
+.Tn ECHO_REQUEST
+datagram to elicit an
+.Tn ICMP ECHO_RESPONSE
+from a host or gateway.
+.Tn ECHO_REQUEST
+datagrams (``pings'') have an IP and
+.Tn ICMP
+header,
+followed by a
+.Dq struct timespec
+and then an arbitrary number of ``pad'' bytes used to fill out the
+packet.
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Emit an audible beep (by sending an ascii BEL character to the
+standard error output) after each non-duplicate response is received.
+This is disabled for flood pings as it would probably cause temporary
+insanity.
+.It Fl C
+Send timestamps in compat format; two 32 bit words in little endian format,
+the first one representing seconds, and the second one representing
+microseconds.
+.It Fl c Ar count
+Stop after sending (and waiting the specified delay to receive)
+.Ar count
+.Tn ECHO_RESPONSE
+packets.
+.It Fl D
+Set the
+.Dv Don't Fragment
+bit in the IP header.
+This can be used to determine the path MTU.
+.It Fl d
+Set the
+.Dv SO_DEBUG
+option on the socket being used.
+.It Fl E Ar policy
+Use IPsec policy specification string
+.Ar policy
+for packets.
+For the format of specification string, please refer
+.Xr ipsec_set_policy 3 .
+Please note that this option is same as
+.Fl P
+in KAME/FreeBSD and KAME/BSDI
+(as
+.Fl P
+was already occupied in
+.Nx ) .
+.It Fl f
+Flood ping.
+Outputs packets as fast as they come back or one hundred times per second,
+whichever is more.
+For every
+.Tn ECHO_REQUEST
+sent a period ``.'' is printed, while for every
+.Tn ECHO_REPLY
+received a backspace is printed.
+This provides a rapid display of how many packets are being dropped.
+Only the super-user may use this option.
+.Bf -emphasis
+This can be very hard on a network and should be used with caution.
+.Ef
+.It Fl g Ar gateway
+Use Loose Source Routing to send the ECHO_REQUEST packets via
+.Ar gateway .
+.It Fl h Ar host
+is an alternate way of specifying the target host instead of as the
+last argument.
+.It Fl I Ar srcaddr
+Set the source IP address to
+.Ar srcaddr
+which can be a hostname or an IP number.
+For multicast datagrams, it also specifies the outgoing interface.
+.It Fl i Ar interval
+Wait
+.Ar interval
+seconds
+.Em between sending each packet .
+The default is to wait for one second between each packet,
+except when the -f option is used the wait interval is 0.01 seconds.
+.It Fl L
+Disable loopback when sending to multicast destinations,
+so the transmitting host doesn't see the ICMP requests.
+.It Fl l Ar preload
+If
+.Ar preload
+is specified,
+.Nm
+sends that many packets as fast as possible before falling into its normal
+mode of behavior.
+Only the super-user may use this option.
+.It Fl n
+Numeric output only.
+No attempt will be made to look up symbolic names for host addresses.
+.It Fl o
+Exit successfully after receiving one reply packet.
+.It Fl P
+Use a pseudo-random sequence for the data instead of the default,
+fixed sequence of incrementing 8-bit integers.
+This is useful to foil compression on PPP and other links.
+.It Fl p Ar pattern
+You may specify up to 16 ``pad'' bytes to fill out the packet you send.
+This is useful for diagnosing data-dependent problems in a network.
+For example,
+.Dq Li \-p ff
+will cause the sent packet to be filled with all
+ones.
+.It Fl Q
+Do not display responses such as Network Unreachable ICMP messages
+concerning the ECHO_REQUESTs sent.
+.It Fl q
+Quiet output.
+Nothing is displayed except the summary lines at startup time and
+when finished.
+.It Fl R
+Record Route.
+Includes the
+.Tn RECORD_ROUTE
+option in the
+.Tn ECHO_REQUEST
+packet and displays the route buffer on returned packets.
+This should show the path to the target host and back, which is
+especially useful in the case of asymmetric routing.
+Note that the IP header is only large enough for nine such addresses,
+and only seven when using the
+.Fl g
+option.
+This is why it was necessary to invent
+.Xr traceroute 8 .
+Many hosts ignore or discard this option.
+.It Fl r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network, an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it (e.g., after the interface was dropped by
+.Xr routed 8 ) .
+.It Fl s Ar packetsize
+Specifies the number of data bytes to be sent.
+The default is 56, which translates into 64
+.Tn ICMP
+data bytes when combined
+with the 8 bytes of
+.Tn ICMP
+header data.
+The maximum allowed value is 65467 bytes.
+.It Fl T Ar ttl
+Use the specified time-to-live.
+.It Fl t Ar tos
+Use the specified hexadecimal type of service.
+.It Fl v
+Verbose output.
+.Tn ICMP
+packets other than
+.Tn ECHO_RESPONSE
+that are received are listed.
+.It Fl w Ar deadline
+Specifies a timeout, in seconds, before ping exits regardless of
+how many packets have been sent or received.
+.El
+.Pp
+When using
+.Nm
+for fault isolation, it should first be run on the local host, to verify
+that the local network interface is up and running.
+Then, hosts and gateways further and further away should be ``pinged''.
+.Pp
+Round-trip times and packet loss statistics are computed.
+If duplicate packets are received, they are not included in the packet
+loss calculation, although the round trip time of these packets is used
+in calculating the minimum/average/maximum round-trip time numbers.
+.Pp
+When the specified number of packets have been sent (and received) or
+if the program is terminated with a
+.Dv SIGINT ,
+a brief summary is displayed.
+The summary information can be displayed while
+.Nm
+is running by sending it a
+.Dv SIGINFO
+signal (see the
+.Dq status
+argument for
+.Xr stty 1
+for more information).
+.Pp
+.Nm
+continually sends one datagram per second, and prints one line of
+output for every ECHO_RESPONSE returned.
+On a trusted system with IP
+Security Options enabled, if the network idiom is not MONO,
+.Nm
+also prints a second line containing the hexadecimal representation
+of the IP security option in the ECHO_RESPONSE.
+If the
+.Fl c
+count option is given, only that number of requests is sent.
+No output is produced if there is no response.
+Round-trip times and packet loss statistics are computed.
+If duplicate packets are received,
+they are not included in the packet loss calculation,
+although the round trip time of these packets is used in calculating
+the minimum/average/maximum round-trip time numbers.
+When the specified number of packets have been sent (and received) or if
+the program is terminated with an interrupt (SIGINT), a brief
+summary is displayed.
+When not using the
+.Fl f
+(flood) option, the first interrupt, usually generated by control-C or DEL,
+causes
+.Nm
+to wait for its outstanding requests to return.
+It will wait no longer than the longest round trip time
+encountered by previous, successful pings.
+The second interrupt stops ping immediately.
+.Pp
+This program is intended for use in network testing, measurement and
+management.
+Because of the load it can impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.Sh ICMP PACKET DETAILS
+An IP header without options is 20 bytes.
+An
+.Tn ICMP
+.Tn ECHO_REQUEST
+packet contains an additional 8 bytes worth of
+.Tn ICMP
+header followed by an arbitrary amount of data.
+When a
+.Ar packetsize
+is given, this indicated the size of this extra piece of data (the
+default is 56).
+Thus the amount of data received inside of an IP packet of type
+.Tn ICMP
+.Tn ECHO_REPLY
+will always be 8 bytes more than the requested data space (the
+.Tn ICMP
+header).
+.Pp
+If the data space is at least 
+.Dv sizeof(struct timespec)
+(16) large,
+.Nm
+uses the first
+.Dv sizeof(struct timespec)
+bytes to include a timestamp to compute round trip times.
+Otherwise if the data space is at least eight bytes large (or the
+.Fl C
+flag is specified),
+.Nm
+uses the first eight bytes of this space to include a timestamp to compute
+round trip times.
+If there are not enough bytes of pad no round trip times are given.
+.Sh DUPLICATE AND DAMAGED PACKETS
+.Nm
+will report duplicate and damaged packets.
+Duplicate packets should never occur, and seem to be caused by
+inappropriate link-level retransmissions.
+Duplicates may occur in many situations and are rarely (if ever) a
+good sign, although the presence of low levels of duplicates may not
+always be cause for alarm.
+.Pp
+Damaged packets are obviously serious cause for alarm and often
+indicate broken hardware somewhere in the
+.Nm
+packet's path (in the network or in the hosts).
+.Sh TRYING DIFFERENT DATA PATTERNS
+The (inter)network layer should never treat packets differently depending
+on the data contained in the data portion.
+Unfortunately, data-dependent problems have been known to sneak into
+networks and remain undetected for long periods of time.
+In many cases the particular pattern that will have problems is something
+that doesn't have sufficient ``transitions'', such as all ones or all
+zeros, or a pattern right at the edge, such as almost all zeros.
+It isn't necessarily enough to specify a data pattern of all zeros (for
+example) on the command line because the pattern that is of interest is
+at the data link level, and the relationship between what you type and
+what the controllers transmit can be complicated.
+.Pp
+This means that if you have a data-dependent problem you will probably
+have to do a lot of testing to find it.
+If you are lucky, you may manage to find a file that either can't be sent
+across your network or that takes much longer to transfer than other
+similar length files.
+You can then examine this file for repeated patterns that you can test
+using the
+.Fl p
+option of
+.Nm .
+.Sh TTL DETAILS
+The
+.Tn TTL
+value of an IP packet represents the maximum number of IP routers
+that the packet can go through before being thrown away.
+In current practice you can expect each router in the Internet to decrement
+the
+.Tn TTL
+field by exactly one.
+.Pp
+The
+.Tn TCP/IP
+specification states that the
+.Tn TTL
+field for
+.Tn TCP
+packets should
+be set to 60, but many systems use smaller values
+.Po
+.Bx 4.3
+uses 30,
+.Bx 4.2
+used 15
+.Pc .
+.Pp
+The maximum possible value of this field is 255, and most
+.Ux
+systems set the
+.Tn TTL
+field of
+.Tn ICMP ECHO_REQUEST
+packets to 255.
+This is why you will find you can ``ping'' some hosts, but not reach them
+with
+.Xr telnet 1
+or
+.Xr ftp 1 .
+.Pp
+In normal operation ping prints the ttl value from the packet it receives.
+When a remote system receives a ping packet, it can do one of three things
+with the
+.Tn TTL
+field in its response:
+.Bl -bullet
+.It
+Not change it; this is what Berkeley
+.Ux
+systems did before the
+.Bx 4.3 tahoe
+release.
+In this case the
+.Tn TTL
+value in the received packet will be 255 minus the
+number of routers in the round-trip path.
+.It
+Set it to 255; this is what current Berkeley
+.Ux
+systems do.
+In this case the
+.Tn TTL
+value in the received packet will be 255 minus the
+number of routers in the path
+.Em from
+the remote system
+.Em to
+the
+.Nm Ns Em ing
+host.
+.It
+Set it to some other value.
+Some machines use the same value for
+.Tn ICMP
+packets that they use for
+.Tn TCP
+packets, for example either 30 or 60.
+Others may use completely wild values.
+.El
+.Sh EXIT STATUS
+.Nm
+returns 0 on success (the host is alive),
+and non-zero if the arguments are incorrect or the host is not responding.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr icmp 4 ,
+.Xr inet 4 ,
+.Xr ip 4 ,
+.Xr ifconfig 8 ,
+.Xr routed 8 ,
+.Xr spray 8 ,
+.Xr traceroute 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
+IPsec support was added by WIDE/KAME project.
+.Sh BUGS
+Flood pinging is not recommended in general, and flood pinging a broadcast
+or multicast address should only be done under very controlled conditions.
+.Pp
+The
+.Nm
+program has evolved differently under different operating systems,
+and in some cases the same flag performs a different function
+under different operating systems.
+The
+.Fl t
+flag conflicts with
+.Fx .
+The
+.Fl a , c , I , i ,
+.Fl l , P , p , s ,
+and
+.Fl t
+flags conflict with
+.Sy Solaris .
+.Pp
+Some hosts and gateways ignore the
+.Tn RECORD_ROUTE
+option.
+.Pp
+The maximum IP header length is too small for options like
+.Tn RECORD_ROUTE
+to
+be completely useful.
+There's not much that that can be done about this, however.
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
new file mode 100644 (file)
index 0000000..f3d47e0
--- /dev/null
@@ -0,0 +1,1923 @@
+/*     $NetBSD: ping.c,v 1.107 2013/10/19 01:08:25 christos Exp $      */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ *                     P I N G . C
+ *
+ * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ *     Mike Muuss
+ *     U. S. Army Ballistic Research Laboratory
+ *     December, 1983
+ * Modified at Uc Berkeley
+ * Record Route and verbose headers - Phil Dykstra, BRL, March 1988.
+ * Multicast options (ttl, if, loop) - Steve Deering, Stanford, August 1988.
+ * ttl, duplicate detection - Cliff Frost, UCB, April 1989
+ * Pad pattern - Cliff Frost (from Tom Ferrin, UCSF), April 1989
+ *
+ * Status -
+ *     Public Domain.  Distribution Unlimited.
+ *
+ * Bugs -
+ *     More statistics could always be gathered.
+ *     This program has to run SUID to ROOT to access the ICMP socket.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ping.c,v 1.107 2013/10/19 01:08:25 christos Exp $");
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <termios.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <poll.h>
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+#include <err.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <netdb.h>
+
+#ifdef IPSEC
+#include <netipsec/ipsec.h>
+#endif /*IPSEC*/
+
+#include "prog_ops.h"
+
+#define FLOOD_INTVL    0.01            /* default flood output interval */
+#define        MAXPACKET       (IP_MAXPACKET-60-8)     /* max packet size */
+
+#define F_VERBOSE      0x0001
+#define F_QUIET                0x0002          /* minimize all output */
+#define F_SEMI_QUIET   0x0004          /* ignore our ICMP errors */
+#define F_FLOOD                0x0008          /* flood-ping */
+#define        F_RECORD_ROUTE  0x0010          /* record route */
+#define F_SOURCE_ROUTE 0x0020          /* loose source route */
+#define F_PING_FILLED  0x0040          /* is buffer filled with user data? */
+#define F_PING_RANDOM  0x0080          /* use random data */
+#define        F_NUMERIC       0x0100          /* do not do gethostbyaddr() calls */
+#define F_TIMING       0x0200          /* room for a timestamp */
+#define F_DF           0x0400          /* set IP DF bit */
+#define F_SOURCE_ADDR  0x0800          /* set source IP address/interface */
+#define F_ONCE         0x1000          /* exit(0) after receiving 1 reply */
+#define F_MCAST                0x2000          /* multicast target */
+#define F_MCAST_NOLOOP 0x4000          /* no multicast loopback */
+#define F_AUDIBLE      0x8000          /* audible output */
+#define F_TIMING64     0x10000         /* 64 bit time, nanoseconds */
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define F_POLICY       0x20000
+#else
+#define        F_AUTHHDR       0x20000
+#define        F_ENCRYPT       0x40000
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+
+/* MAX_DUP_CHK is the number of bits in received table, the
+ *     maximum number of received sequence numbers we can track to check
+ *     for duplicates.
+ */
+#define MAX_DUP_CHK     (8 * 2048)
+static u_char  rcvd_tbl[MAX_DUP_CHK/8];
+static int     nrepeats = 0;
+#define A(seq) rcvd_tbl[(seq/8)%sizeof(rcvd_tbl)]  /* byte in array */
+#define B(seq) (1 << (seq & 0x07))     /* bit in byte */
+#define SET(seq) (A(seq) |= B(seq))
+#define CLR(seq) (A(seq) &= (~B(seq)))
+#define TST(seq) (A(seq) & B(seq))
+
+struct tv32 {
+       int32_t tv32_sec;
+       int32_t tv32_usec;
+};
+
+
+static u_char  *packet;
+static int     packlen;
+static int     pingflags = 0, options;
+static int     pongflags = 0;
+static char    *fill_pat;
+
+static int s;                                  /* Socket file descriptor */
+static int sloop;                              /* Socket file descriptor/loopback */
+
+#define PHDR_LEN sizeof(struct tv32)           /* size of timestamp header */
+#define PHDR64_LEN sizeof(struct timespec)     /* size of timestamp header */
+static struct sockaddr_in whereto, send_addr;  /* Who to ping */
+static struct sockaddr_in src_addr;            /* from where */
+static struct sockaddr_in loc_addr;            /* 127.1 */
+static int datalen;                            /* How much data */
+static int phdrlen;
+
+#ifndef __NetBSD__
+static char *progname;
+#define        getprogname()           (progname)
+#define        setprogname(name)       ((void)(progname = (name)))
+#endif
+
+static char hostname[MAXHOSTNAMELEN];
+
+static struct {
+       struct ip       o_ip;
+       char            o_opt[MAX_IPOPTLEN];
+       union {
+               u_char      u_buf[MAXPACKET+offsetof(struct icmp, icmp_data)];
+               struct icmp u_icmp;
+       } o_u;
+} out_pack;
+#define        opack_icmp      out_pack.o_u.u_icmp
+static struct ip *opack_ip;
+
+static char optspace[MAX_IPOPTLEN];            /* record route space */
+static int optlen;
+
+static int npackets;                           /* total packets to send */
+static int preload;                            /* number of packets to "preload" */
+static int ntransmitted;                       /* output sequence # = #sent */
+static int ident;                              /* our ID, in network byte order */
+
+static int nreceived;                          /* # of packets we got back */
+
+static double interval;                        /* interval between packets */
+static struct timespec interval_tv;
+static double tmin = 999999999.0;
+static double tmax = 0.0;
+static double tsum = 0.0;                      /* sum of all times */
+static double tsumsq = 0.0;
+static double maxwait = 0.0;
+
+#ifndef __minix
+static int bufspace = IP_MAXPACKET;
+#endif
+
+static struct timespec now, clear_cache, last_tx, next_tx, first_tx;
+static struct timespec last_rx, first_rx;
+static int lastrcvd = 1;                       /* last ping sent has been received */
+
+static struct timespec jiggle_time;
+static int jiggle_cnt, total_jiggled, jiggle_direction = -1;
+
+__dead static void doit(void);
+static void prefinish(int);
+static void prtsig(int);
+__dead static void finish(int);
+static void summary(int);
+static void pinger(void);
+static void fill(void);
+static void rnd_fill(void);
+static double diffsec(struct timespec *, struct timespec *);
+#if 0
+static void timespecadd(struct timespec *, struct timespec *);
+#endif
+static void sec_to_timespec(const double, struct timespec *);
+static double timespec_to_sec(const struct timespec *);
+static void pr_pack(u_char *, int, struct sockaddr_in *);
+static u_int16_t in_cksum(u_int16_t *, u_int);
+static void pr_saddr(u_char *);
+static char *pr_addr(struct in_addr *);
+static void pr_iph(struct icmp *, int);
+static void pr_retip(struct icmp *, int);
+static int pr_icmph(struct icmp *, struct sockaddr_in *, int);
+static void jiggle(int), jiggle_flush(int);
+static void gethost(const char *, const char *,
+                   struct sockaddr_in *, char *, int);
+__dead static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+       int c, i, on = 1, hostind = 0;
+       long l;
+       int len = -1, compat = 0;
+       u_char ttl = 0;
+       u_long tos = 0;
+       char *p;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+       char *policy_in = NULL;
+       char *policy_out = NULL;
+#endif
+#endif
+#ifdef SIGINFO
+       struct sigaction sa;
+#endif
+
+       if (prog_init && prog_init() == -1)
+               err(1, "init failed");
+
+       if ((s = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
+               err(1, "Cannot create socket");
+       if ((sloop = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
+               err(1, "Cannot create socket");
+
+#ifndef __minix
+       /*
+        * sloop is never read on.  This prevents packets from
+        * queueing in its recv buffer.
+        */
+       if (prog_shutdown(sloop, SHUT_RD) == -1)
+               warn("Cannot shutdown for read");
+#endif
+
+       if (prog_setuid(prog_getuid()) == -1)
+               err(1, "setuid");
+
+       setprogname(argv[0]);
+
+#ifndef IPSEC
+#define IPSECOPT
+#else
+#ifdef IPSEC_POLICY_IPSEC
+#define IPSECOPT       "E:"
+#else
+#define IPSECOPT       "AE"
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif
+       while ((c = getopt(argc, argv,
+                          "ac:CdDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) {
+#undef IPSECOPT
+               switch (c) {
+               case 'a':
+                       pingflags |= F_AUDIBLE;
+                       break;
+               case 'C':
+                       compat = 1;
+                       break;
+               case 'c':
+                       npackets = strtol(optarg, &p, 0);
+                       if (*p != '\0' || npackets <= 0)
+                               errx(1, "Bad/invalid number of packets");
+                       break;
+               case 'D':
+                       pingflags |= F_DF;
+                       break;
+               case 'd':
+                       options |= SO_DEBUG;
+                       break;
+               case 'f':
+                       pingflags |= F_FLOOD;
+                       break;
+               case 'h':
+                       hostind = optind-1;
+                       break;
+               case 'i':               /* wait between sending packets */
+                       interval = strtod(optarg, &p);
+                       if (*p != '\0' || interval <= 0)
+                               errx(1, "Bad/invalid interval %s", optarg);
+                       break;
+               case 'l':
+                       preload = strtol(optarg, &p, 0);
+                       if (*p != '\0' || preload < 0)
+                               errx(1, "Bad/invalid preload value %s",
+                                    optarg);
+                       break;
+               case 'n':
+                       pingflags |= F_NUMERIC;
+                       break;
+               case 'o':
+                       pingflags |= F_ONCE;
+                       break;
+               case 'p':               /* fill buffer with user pattern */
+                       if (pingflags & F_PING_RANDOM)
+                               errx(1, "Only one of -P and -p allowed");
+                       pingflags |= F_PING_FILLED;
+                       fill_pat = optarg;
+                       break;
+               case 'P':
+                       if (pingflags & F_PING_FILLED)
+                               errx(1, "Only one of -P and -p allowed");
+                       pingflags |= F_PING_RANDOM;
+                       break;
+               case 'q':
+                       pingflags |= F_QUIET;
+                       break;
+               case 'Q':
+                       pingflags |= F_SEMI_QUIET;
+                       break;
+               case 'r':
+                       options |= SO_DONTROUTE;
+                       break;
+               case 's':               /* size of packet to send */
+                       l = strtol(optarg, &p, 0);
+                       if (*p != '\0' || l < 0)
+                               errx(1, "Bad/invalid packet size %s", optarg);
+                       if (l > MAXPACKET)
+                               errx(1, "packet size is too large");
+                       len = (int)l;
+                       break;
+               case 'v':
+                       pingflags |= F_VERBOSE;
+                       break;
+               case 'R':
+                       pingflags |= F_RECORD_ROUTE;
+                       break;
+               case 'L':
+                       pingflags |= F_MCAST_NOLOOP;
+                       break;
+               case 't':
+                       tos = strtoul(optarg, &p, 0);
+                       if (*p != '\0' ||  tos > 0xFF)
+                               errx(1, "bad tos value: %s", optarg);
+                       break;
+               case 'T':
+                       l = strtol(optarg, &p, 0);
+                       if (*p != '\0' || l > 255 || l <= 0)
+                               errx(1, "ttl out of range");
+                       ttl = (u_char)l;    /* cannot check >255 otherwise */
+                       break;
+               case 'I':
+                       pingflags |= F_SOURCE_ADDR;
+                       gethost("-I", optarg, &src_addr, 0, 0);
+                       break;
+               case 'g':
+                       pingflags |= F_SOURCE_ROUTE;
+                       gethost("-g", optarg, &send_addr, 0, 0);
+                       break;
+               case 'w':
+                       maxwait = strtod(optarg, &p);
+                       if (*p != '\0' || maxwait <= 0)
+                               errx(1, "Bad/invalid maxwait time %s", optarg);
+                       break;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+               case 'E':
+                       pingflags |= F_POLICY;
+                       if (!strncmp("in", optarg, 2)) {
+                               policy_in = strdup(optarg);
+                               if (!policy_in)
+                                       err(1, "strdup");
+                       } else if (!strncmp("out", optarg, 3)) {
+                               policy_out = strdup(optarg);
+                               if (!policy_out)
+                                       err(1, "strdup");
+                       } else
+                               errx(1, "invalid security policy");
+                       break;
+#else
+               case 'A':
+                       pingflags |= F_AUTHHDR;
+                       break;
+               case 'E':
+                       pingflags |= F_ENCRYPT;
+                       break;
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       if (interval == 0)
+               interval = (pingflags & F_FLOOD) ? FLOOD_INTVL : 1.0;
+#ifndef sgi
+       if (pingflags & F_FLOOD && prog_getuid())
+               errx(1, "Must be superuser to use -f");
+       if (interval < 1.0 && prog_getuid())
+               errx(1, "Must be superuser to use < 1 sec ping interval");
+       if (preload > 0 && prog_getuid())
+               errx(1, "Must be superuser to use -l");
+#endif
+       sec_to_timespec(interval, &interval_tv);
+
+       if ((pingflags & (F_AUDIBLE|F_FLOOD)) == (F_AUDIBLE|F_FLOOD))
+               warnx("Sorry, no audible output for flood pings");
+
+       if (npackets != 0) {
+               npackets += preload;
+       } else {
+               npackets = INT_MAX;
+       }
+
+       if (hostind == 0) {
+               if (optind != argc-1)
+                       usage();
+               else
+                       hostind = optind;
+       }
+       else if (hostind >= argc - 1)
+               usage();
+
+       gethost("", argv[hostind], &whereto, hostname, sizeof(hostname));
+       if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)))
+               pingflags |= F_MCAST;
+       if (!(pingflags & F_SOURCE_ROUTE))
+               (void) memcpy(&send_addr, &whereto, sizeof(send_addr));
+
+       loc_addr.sin_family = AF_INET;
+       loc_addr.sin_len = sizeof(struct sockaddr_in);
+       loc_addr.sin_addr.s_addr = htonl((127 << 24) + 1);
+
+       if (len != -1)
+               datalen = len;
+       else
+               datalen = 64;
+       if (!compat && datalen >= (int)PHDR64_LEN) { /* can we time them? */
+               pingflags |= F_TIMING64;
+               phdrlen = PHDR64_LEN;
+       } else if (datalen >= (int)PHDR_LEN) {  /* can we time them? */
+               pingflags |= F_TIMING;
+               phdrlen = PHDR_LEN;
+       } else
+               phdrlen = 0;
+
+       packlen = datalen + 60 + 76;    /* MAXIP + MAXICMP */
+       datalen -= phdrlen;
+       if ((packet = malloc(packlen)) == NULL)
+               err(1, "Out of memory");
+
+       if (pingflags & F_PING_FILLED) {
+               fill();
+       } else if (pingflags & F_PING_RANDOM) {
+               rnd_fill();
+       } else {
+               for (i = phdrlen; i < datalen; i++)
+                       opack_icmp.icmp_data[i] = i;
+       }
+
+       ident = arc4random() & 0xFFFF;
+
+       if (options & SO_DEBUG) {
+               if (prog_setsockopt(s, SOL_SOCKET, SO_DEBUG,
+                              (char *)&on, sizeof(on)) == -1)
+                       warn("Can't turn on socket debugging");
+       }
+       if (options & SO_DONTROUTE) {
+               if (prog_setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
+                              (char *)&on, sizeof(on)) == -1)
+                       warn("SO_DONTROUTE");
+       }
+
+       if (options & SO_DEBUG) {
+               if (prog_setsockopt(sloop, SOL_SOCKET, SO_DEBUG,
+                              (char *)&on, sizeof(on)) == -1)
+                       warn("Can't turn on socket debugging");
+       }
+       if (options & SO_DONTROUTE) {
+               if (prog_setsockopt(sloop, SOL_SOCKET, SO_DONTROUTE,
+                              (char *)&on, sizeof(on)) == -1)
+                       warn("SO_DONTROUTE");
+       }
+
+       if (pingflags & F_SOURCE_ROUTE) {
+               optspace[IPOPT_OPTVAL] = IPOPT_LSRR;
+               optspace[IPOPT_OLEN] = optlen = 7;
+               optspace[IPOPT_OFFSET] = IPOPT_MINOFF;
+               (void)memcpy(&optspace[IPOPT_MINOFF-1], &whereto.sin_addr,
+                            sizeof(whereto.sin_addr));
+               optspace[optlen++] = IPOPT_NOP;
+       }
+       if (pingflags & F_RECORD_ROUTE) {
+               optspace[optlen+IPOPT_OPTVAL] = IPOPT_RR;
+               optspace[optlen+IPOPT_OLEN] = (MAX_IPOPTLEN -1-optlen);
+               optspace[optlen+IPOPT_OFFSET] = IPOPT_MINOFF;
+               optlen = MAX_IPOPTLEN;
+       }
+       /* this leaves opack_ip 0(mod 4) aligned */
+       opack_ip = (struct ip *)((char *)&out_pack.o_ip
+                                + sizeof(out_pack.o_opt)
+                                - optlen);
+       (void) memcpy(opack_ip + 1, optspace, optlen);
+
+#ifndef __minix
+       if (prog_setsockopt(s,IPPROTO_IP,IP_HDRINCL,
+           (char *) &on, sizeof(on)) < 0)
+               err(1, "Can't set special IP header");
+#endif
+
+       opack_ip->ip_v = IPVERSION;
+       opack_ip->ip_hl = (sizeof(struct ip)+optlen) >> 2;
+       opack_ip->ip_tos = tos;
+       opack_ip->ip_off = (pingflags & F_DF) ? IP_DF : 0;
+       opack_ip->ip_ttl = ttl ? ttl : MAXTTL;
+       opack_ip->ip_p = IPPROTO_ICMP;
+       opack_ip->ip_src = src_addr.sin_addr;
+       opack_ip->ip_dst = send_addr.sin_addr;
+
+       if (pingflags & F_MCAST) {
+               if (pingflags & F_MCAST_NOLOOP) {
+                       u_char loop = 0;
+                       if (prog_setsockopt(s, IPPROTO_IP,
+                           IP_MULTICAST_LOOP,
+                           (char *) &loop, 1) < 0)
+                               err(1, "Can't disable multicast loopback");
+               }
+
+               if (ttl != 0
+                   && prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
+                   (char *) &ttl, 1) < 0)
+                       err(1, "Can't set multicast time-to-live");
+
+               if ((pingflags & F_SOURCE_ADDR)
+                   && prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
+                                 (char *) &src_addr.sin_addr,
+                                 sizeof(src_addr.sin_addr)) < 0)
+                       err(1, "Can't set multicast source interface");
+
+       } else if (pingflags & F_SOURCE_ADDR) {
+               if (prog_setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
+                              (char *) &src_addr.sin_addr,
+                              sizeof(src_addr.sin_addr)) < 0)
+                       err(1, "Can't set source interface/address");
+       }
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+    {
+       char *buf;
+       if (pingflags & F_POLICY) {
+               if (policy_in != NULL) {
+                       buf = ipsec_set_policy(policy_in, strlen(policy_in));
+                       if (buf == NULL)
+                               errx(1, "%s", ipsec_strerror());
+                       if (prog_setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+                                       buf, ipsec_get_policylen(buf)) < 0) {
+                               err(1, "ipsec policy cannot be configured");
+                       }
+                       free(buf);
+               }
+               if (policy_out != NULL) {
+                       buf = ipsec_set_policy(policy_out, strlen(policy_out));
+                       if (buf == NULL)
+                               errx(1, "%s", ipsec_strerror());
+                       if (prog_setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+                                       buf, ipsec_get_policylen(buf)) < 0) {
+                               err(1, "ipsec policy cannot be configured");
+                       }
+                       free(buf);
+               }
+       }
+       buf = ipsec_set_policy("out bypass", strlen("out bypass"));
+       if (buf == NULL)
+               errx(1, "%s", ipsec_strerror());
+       if (prog_setsockopt(sloop, IPPROTO_IP, IP_IPSEC_POLICY,
+                       buf, ipsec_get_policylen(buf)) < 0) {
+#if 0
+               warnx("ipsec is not configured");
+#else
+               /* ignore it, should be okay */
+#endif
+       }
+       free(buf);
+    }
+#else
+    {
+       int optval;
+       if (pingflags & F_AUTHHDR) {
+               optval = IPSEC_LEVEL_REQUIRE;
+#ifdef IP_AUTH_TRANS_LEVEL
+               (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_TRANS_LEVEL,
+                       (char *)&optval, sizeof(optval));
+#else
+               (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_LEVEL,
+                       (char *)&optval, sizeof(optval));
+#endif
+       }
+       if (pingflags & F_ENCRYPT) {
+               optval = IPSEC_LEVEL_REQUIRE;
+               (void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_TRANS_LEVEL,
+                       (char *)&optval, sizeof(optval));
+       }
+       optval = IPSEC_LEVEL_BYPASS;
+#ifdef IP_AUTH_TRANS_LEVEL
+       (void)prog_setsockopt(sloop, IPPROTO_IP, IP_AUTH_TRANS_LEVEL,
+               (char *)&optval, sizeof(optval));
+#else
+       (void)prog_setsockopt(sloop, IPPROTO_IP, IP_AUTH_LEVEL,
+               (char *)&optval, sizeof(optval));
+#endif
+       (void)prog_setsockopt(sloop, IPPROTO_IP, IP_ESP_TRANS_LEVEL,
+               (char *)&optval, sizeof(optval));
+    }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+       (void)printf("PING %s (%s): %d data bytes\n", hostname,
+                    inet_ntoa(whereto.sin_addr), datalen + phdrlen);
+
+#ifndef __minix
+       /* When pinging the broadcast address, you can get a lot
+        * of answers.  Doing something so evil is useful if you
+        * are trying to stress the ethernet, or just want to
+        * fill the arp cache to get some stuff for /etc/ethers.
+        */
+       while (0 > prog_setsockopt(s, SOL_SOCKET, SO_RCVBUF,
+                             (char*)&bufspace, sizeof(bufspace))) {
+               if ((bufspace -= 4096) <= 0)
+                       err(1, "Cannot set the receive buffer size");
+       }
+
+       /* make it possible to send giant probes, but do not worry now
+        * if it fails, since we probably won't send giant probes.
+        */
+       (void)prog_setsockopt(s, SOL_SOCKET, SO_SNDBUF,
+                        (char*)&bufspace, sizeof(bufspace));
+#endif
+
+       (void)signal(SIGINT, prefinish);
+
+#ifdef SIGINFO
+       sa.sa_handler = prtsig;
+       sa.sa_flags = SA_NOKERNINFO;
+       sigemptyset(&sa.sa_mask);
+       (void)sigaction(SIGINFO, &sa, NULL);
+#else
+       (void)signal(SIGQUIT, prtsig);
+#endif
+       (void)signal(SIGCONT, prtsig);
+
+       /* fire off them quickies */
+       for (i = 0; i < preload; i++) {
+               clock_gettime(CLOCK_MONOTONIC, &now);
+               pinger();
+       }
+
+       doit();
+       return 0;
+}
+
+
+static void
+doit(void)
+{
+       int cc;
+       struct sockaddr_in from;
+       socklen_t fromlen;
+       double sec, last, d_last;
+       struct pollfd fdmaskp[1];
+
+       (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
+       if (maxwait != 0) {
+               last = timespec_to_sec(&clear_cache) + maxwait;
+               d_last = 0;
+       } else {
+               last = 0;
+               d_last = 365*24*60*60;
+       }
+
+       do {
+               clock_gettime(CLOCK_MONOTONIC, &now);
+
+               if (last != 0)
+                       d_last = last - timespec_to_sec(&now);
+
+               if (ntransmitted < npackets && d_last > 0) {
+                       /* send if within 100 usec or late for next packet */
+                       sec = diffsec(&next_tx, &now);
+                       if (sec <= 0.0001 ||
+                           (lastrcvd && (pingflags & F_FLOOD))) {
+                               pinger();
+                               sec = diffsec(&next_tx, &now);
+                       }
+                       if (sec < 0.0)
+                               sec = 0.0;
+                       if (d_last < sec)
+                               sec = d_last;
+
+               } else {
+                       /* For the last response, wait twice as long as the
+                        * worst case seen, or 10 times as long as the
+                        * maximum interpacket interval, whichever is longer.
+                        */
+                       sec = MAX(2 * tmax, 10 * interval) -
+                           diffsec(&now, &last_tx);
+                       if (d_last < sec)
+                               sec = d_last;
+                       if (sec <= 0)
+                               break;
+               }
+
+               fdmaskp[0].fd = s;
+               fdmaskp[0].events = POLLIN;
+               cc = prog_poll(fdmaskp, 1, (int)(sec * 1000));
+               if (cc <= 0) {
+                       if (cc < 0) {
+                               if (errno == EINTR)
+                                       continue;
+                               jiggle_flush(1);
+                               err(1, "poll");
+                       }
+                       continue;
+               }
+
+               fromlen  = sizeof(from);
+               cc = prog_recvfrom(s, (char *) packet, packlen,
+                             0, (struct sockaddr *)&from,
+                             &fromlen);
+               if (cc < 0) {
+                       perror("recvfrom failed");
+                       if (errno != EINTR) {
+                               jiggle_flush(1);
+                               warn("recvfrom");
+                               (void)fflush(stderr);
+                       }
+                       continue;
+               }
+               clock_gettime(CLOCK_MONOTONIC, &now);
+               pr_pack(packet, cc, &from);
+
+       } while (nreceived < npackets
+                && (nreceived == 0 || !(pingflags & F_ONCE)));
+
+       finish(0);
+}
+
+
+static void
+jiggle_flush(int nl)                   /* new line if there are dots */
+{
+       int serrno = errno;
+
+       if (jiggle_cnt > 0) {
+               total_jiggled += jiggle_cnt;
+               jiggle_direction = 1;
+               do {
+                       (void)putchar('.');
+               } while (--jiggle_cnt > 0);
+
+       } else if (jiggle_cnt < 0) {
+               total_jiggled -= jiggle_cnt;
+               jiggle_direction = -1;
+               do {
+                       (void)putchar('\b');
+               } while (++jiggle_cnt < 0);
+       }
+
+       if (nl) {
+               if (total_jiggled != 0)
+                       (void)putchar('\n');
+               total_jiggled = 0;
+               jiggle_direction = -1;
+       }
+
+       (void)fflush(stdout);
+       (void)fflush(stderr);
+       jiggle_time = now;
+       errno = serrno;
+}
+
+
+/* jiggle the cursor for flood-ping
+ */
+static void
+jiggle(int delta)
+{
+       double dt;
+
+       if (pingflags & F_QUIET)
+               return;
+
+       /* do not back up into messages */
+       if (total_jiggled+jiggle_cnt+delta < 0)
+               return;
+
+       jiggle_cnt += delta;
+
+       /* flush the FLOOD dots when things are quiet
+        * or occassionally to make the cursor jiggle.
+        */
+       dt = diffsec(&last_tx, &jiggle_time);
+       if (dt > 0.2 || (dt >= 0.15 && delta*jiggle_direction < 0))
+               jiggle_flush(0);
+}
+
+
+/*
+ * Compose and transmit an ICMP ECHO REQUEST packet.  The IP packet
+ * will be added on by the kernel.  The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer.  The first phdrlen bytes
+ * of the data portion are used to hold a UNIX "timeval" struct in VAX
+ * byte-order, to compute the round-trip time, or a UNIX "timespec" in native
+ * format.
+ */
+static void
+pinger(void)
+{
+       struct tv32 tv32;
+#ifndef __minix
+       int i, cc, sw;
+#else
+       int i, cc;
+#endif
+
+       opack_icmp.icmp_code = 0;
+       opack_icmp.icmp_seq = htons((u_int16_t)(ntransmitted));
+
+#ifndef __minix
+       /* clear the cached route in the kernel after an ICMP
+        * response such as a Redirect is seen to stop causing
+        * more such packets.  Also clear the cached route
+        * periodically in case of routing changes that make
+        * black holes come and go.
+        */
+       if (clear_cache.tv_sec != now.tv_sec) {
+               opack_icmp.icmp_type = ICMP_ECHOREPLY;
+               opack_icmp.icmp_id = ~ident;
+               opack_icmp.icmp_cksum = 0;
+               opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp,
+                   phdrlen);
+               sw = 0;
+               if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
+                              (char *)&sw,sizeof(sw)) < 0)
+                       err(1, "Can't turn off special IP header");
+               if (prog_sendto(sloop, (char *) &opack_icmp,
+                          ICMP_MINLEN, MSG_DONTROUTE,
+                          (struct sockaddr *)&loc_addr,
+                          sizeof(struct sockaddr_in)) < 0) {
+                       /*
+                        * XXX: we only report this as a warning in verbose
+                        * mode because people get confused when they see
+                        * this error when they are running in single user
+                        * mode and they have not configured lo0
+                        */
+                       if (pingflags & F_VERBOSE)
+                               warn("failed to clear cached route");
+               }
+               sw = 1;
+               if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
+                              (char *)&sw, sizeof(sw)) < 0)
+                       err(1, "Can't set special IP header");
+               
+               (void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
+       }
+#endif
+
+       opack_icmp.icmp_type = ICMP_ECHO;
+       opack_icmp.icmp_id = ident;
+
+       if (pingflags & F_TIMING) {
+               tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
+               tv32.tv32_usec = htonl(now.tv_nsec / 1000);
+               (void) memcpy(&opack_icmp.icmp_data[0], &tv32, sizeof(tv32));
+       } else if (pingflags & F_TIMING64)
+               (void) memcpy(&opack_icmp.icmp_data[0], &now, sizeof(now));
+
+       cc = MAX(datalen, ICMP_MINLEN) + phdrlen;
+       opack_icmp.icmp_cksum = 0;
+       opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp, cc);
+
+       cc += opack_ip->ip_hl<<2;
+       opack_ip->ip_len = cc;
+       i = prog_sendto(s, (char *) opack_ip, cc, 0,
+                  (struct sockaddr *)&send_addr, sizeof(struct sockaddr_in));
+
+       if (i != cc) {
+               jiggle_flush(1);
+               if (i < 0)
+                       warn("sendto");
+               else
+                       warnx("wrote %s %d chars, ret=%d", hostname, cc, i);
+               (void)fflush(stderr);
+       }
+       lastrcvd = 0;
+
+       CLR(ntransmitted);
+       ntransmitted++;
+
+       last_tx = now;
+       if (next_tx.tv_sec == 0) {
+               first_tx = now;
+               next_tx = now;
+       }
+
+       /* Transmit regularly, at always the same microsecond in the
+        * second when going at one packet per second.
+        * If we are at most 100 ms behind, send extras to get caught up.
+        * Otherwise, skip packets we were too slow to send.
+        */
+       if (diffsec(&next_tx, &now) <= interval) {
+               do {
+                       timespecadd(&next_tx, &interval_tv, &next_tx);
+               } while (diffsec(&next_tx, &now) < -0.1);
+       }
+
+       if (pingflags & F_FLOOD)
+               jiggle(1);
+
+       /* While the packet is going out, ready buffer for the next
+        * packet. Use a fast but not very good random number generator.
+        */
+       if (pingflags & F_PING_RANDOM)
+               rnd_fill();
+}
+
+
+static void
+pr_pack_sub(int cc,
+           char *addr,
+           int seqno,
+           int dupflag,
+           int ttl,
+           double triptime)
+{
+       jiggle_flush(1);
+
+       if (pingflags & F_FLOOD)
+               return;
+
+       (void)printf("%d bytes from %s: icmp_seq=%u", cc, addr, seqno);
+       if (dupflag)
+               (void)printf(" DUP!");
+       (void)printf(" ttl=%d", ttl);
+       if (pingflags & (F_TIMING|F_TIMING64)) {
+               const unsigned int prec = (pingflags & F_TIMING64) != 0 ? 6 : 3;
+
+               (void)printf(" time=%.*f ms", prec, triptime*1000.0);
+       }
+
+       /*
+        * Send beep to stderr, since that's more likely than stdout
+        * to go to a terminal..
+        */
+       if (pingflags & F_AUDIBLE && !dupflag)
+               (void)fprintf(stderr,"\a");
+}
+
+
+/*
+ * Print out the packet, if it came from us.  This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair).  This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+static void
+pr_pack(u_char *buf,
+       int tot_len,
+       struct sockaddr_in *from)
+{
+       struct ip *ip;
+       struct icmp *icp;
+       int i, j, net_len;
+       u_char *cp;
+       static int old_rrlen;
+       static char old_rr[MAX_IPOPTLEN];
+       int hlen, dupflag = 0, dumped;
+       double triptime = 0.0;
+#define PR_PACK_SUB() {if (!dumped) {                  \
+       dumped = 1;                                     \
+       pr_pack_sub(net_len, inet_ntoa(from->sin_addr), \
+                   ntohs((u_int16_t)icp->icmp_seq),    \
+                   dupflag, ip->ip_ttl, triptime);}}
+
+       /* Check the IP header */
+       ip = (struct ip *) buf;
+       hlen = ip->ip_hl << 2;
+       if (tot_len < hlen + ICMP_MINLEN) {
+               if (pingflags & F_VERBOSE) {
+                       jiggle_flush(1);
+                       (void)printf("packet too short (%d bytes) from %s\n",
+                                    tot_len, inet_ntoa(from->sin_addr));
+               }
+               return;
+       }
+
+       /* Now the ICMP part */
+       dumped = 0;
+       net_len = tot_len - hlen;
+       icp = (struct icmp *)(buf + hlen);
+       if (icp->icmp_type == ICMP_ECHOREPLY
+           && icp->icmp_id == ident) {
+
+               if (icp->icmp_seq == htons((u_int16_t)(ntransmitted-1)))
+                       lastrcvd = 1;
+               last_rx = now;
+               if (first_rx.tv_sec == 0)
+                       first_rx = last_rx;
+               nreceived++;
+               if (pingflags & (F_TIMING|F_TIMING64)) {
+                       struct timespec tv;
+
+                       if (pingflags & F_TIMING) {
+                               struct tv32 tv32;
+
+                               (void)memcpy(&tv32, icp->icmp_data, sizeof(tv32));
+                               tv.tv_sec = (uint32_t)ntohl(tv32.tv32_sec);
+                               tv.tv_nsec = ntohl(tv32.tv32_usec) * 1000;
+                       } else if (pingflags & F_TIMING64) 
+                               (void)memcpy(&tv, icp->icmp_data, sizeof(tv));
+                       else
+                               memset(&tv, 0, sizeof(tv));     /* XXX: gcc */
+
+                       triptime = diffsec(&last_rx, &tv);
+                       tsum += triptime;
+                       tsumsq += triptime * triptime;
+                       if (triptime < tmin)
+                               tmin = triptime;
+                       if (triptime > tmax)
+                               tmax = triptime;
+               }
+
+               if (TST(ntohs((u_int16_t)icp->icmp_seq))) {
+                       nrepeats++, nreceived--;
+                       dupflag=1;
+               } else {
+                       SET(ntohs((u_int16_t)icp->icmp_seq));
+               }
+
+               if (tot_len != opack_ip->ip_len) {
+                       PR_PACK_SUB();
+                       switch (opack_ip->ip_len - tot_len) {
+                       case MAX_IPOPTLEN:
+                               if ((pongflags & F_RECORD_ROUTE) != 0)
+                                       break;
+                               if ((pingflags & F_RECORD_ROUTE) == 0)
+                                       goto out;
+                               pongflags |= F_RECORD_ROUTE;
+                               (void)printf("\nremote host does not "
+                                   "support record route");
+                               break;
+                       case 8:
+                               if ((pongflags & F_SOURCE_ROUTE) != 0)
+                                       break;
+                               if ((pingflags & F_SOURCE_ROUTE) == 0)
+                                       goto out;
+                               pongflags |= F_SOURCE_ROUTE;
+                               (void)printf("\nremote host does not "
+                                   "support source route");
+                               break;
+                       default:
+                       out:
+                               (void)printf("\nwrong total length %d "
+                                   "instead of %d", tot_len, opack_ip->ip_len);
+                               break;
+                       }
+               }
+
+               if (!dupflag) {
+                       static u_int16_t last_seqno = 0xffff;
+                       u_int16_t seqno = ntohs((u_int16_t)icp->icmp_seq);
+                       u_int16_t gap = seqno - (last_seqno + 1);
+                       if (gap > 0 && gap < 0x8000 &&
+                           (pingflags & F_VERBOSE)) {
+                               (void)printf("[*** sequence gap of %u "
+                                   "packets from %u ... %u ***]\n", gap,
+                                   (u_int16_t) (last_seqno + 1),
+                                   (u_int16_t) (seqno - 1));
+                               if (pingflags & F_QUIET)
+                                       summary(0);
+                       }
+
+                       if (gap < 0x8000)
+                               last_seqno = seqno;
+               }
+
+               if (pingflags & F_QUIET)
+                       return;
+
+               if (!(pingflags & F_FLOOD))
+                       PR_PACK_SUB();
+
+               /* check the data */
+               if ((size_t)(tot_len - hlen) >
+                   offsetof(struct icmp, icmp_data) + datalen
+                   && !(pingflags & F_PING_RANDOM)
+                   && memcmp(icp->icmp_data + phdrlen,
+                           opack_icmp.icmp_data + phdrlen,
+                           datalen - phdrlen)) {
+                       for (i = phdrlen; i < datalen; i++) {
+                               if (icp->icmp_data[i] !=
+                                   opack_icmp.icmp_data[i])
+                                       break;
+                       }
+                       PR_PACK_SUB();
+                       (void)printf("\nwrong data byte #%d should have been"
+                                    " %#x but was %#x", i,
+                                    (u_char)opack_icmp.icmp_data[i],
+                                    (u_char)icp->icmp_data[i]);
+                       for (i = phdrlen; i < datalen; i++) {
+                               if ((i % 16) == 0)
+                                       (void)printf("\n\t");
+                               (void)printf("%2x ",(u_char)icp->icmp_data[i]);
+                       }
+               }
+
+       } else {
+               if (!pr_icmph(icp, from, net_len))
+                       return;
+               dumped = 2;
+       }
+
+       /* Display any IP options */
+       cp = buf + sizeof(struct ip);
+       while (hlen > (int)sizeof(struct ip)) {
+               switch (*cp) {
+               case IPOPT_EOL:
+                       hlen = 0;
+                       break;
+               case IPOPT_LSRR:
+                       hlen -= 2;
+                       j = *++cp;
+                       ++cp;
+                       j -= IPOPT_MINOFF;
+                       if (j <= 0)
+                               continue;
+                       if (dumped <= 1) {
+                               j = ((j+3)/4)*4;
+                               hlen -= j;
+                               cp += j;
+                               break;
+                       }
+                       PR_PACK_SUB();
+                       (void)printf("\nLSRR: ");
+                       for (;;) {
+                               pr_saddr(cp);
+                               cp += 4;
+                               hlen -= 4;
+                               j -= 4;
+                               if (j <= 0)
+                                       break;
+                               (void)putchar('\n');
+                       }
+                       break;
+               case IPOPT_RR:
+                       j = *++cp;      /* get length */
+                       i = *++cp;      /* and pointer */
+                       hlen -= 2;
+                       if (i > j)
+                               i = j;
+                       i -= IPOPT_MINOFF;
+                       if (i <= 0)
+                               continue;
+                       if (dumped <= 1) {
+                               if (i == old_rrlen
+                                   && !memcmp(cp, old_rr, i)) {
+                                       if (dumped)
+                                           (void)printf("\t(same route)");
+                                       j = ((i+3)/4)*4;
+                                       hlen -= j;
+                                       cp += j;
+                                       break;
+                               }
+                               old_rrlen = i;
+                               (void) memcpy(old_rr, cp, i);
+                       }
+                       if (!dumped) {
+                               jiggle_flush(1);
+                               (void)printf("RR: ");
+                               dumped = 1;
+                       } else {
+                               (void)printf("\nRR: ");
+                       }
+                       for (;;) {
+                               pr_saddr(cp);
+                               cp += 4;
+                               hlen -= 4;
+                               i -= 4;
+                               if (i <= 0)
+                                       break;
+                               (void)putchar('\n');
+                       }
+                       break;
+               case IPOPT_NOP:
+                       if (dumped <= 1)
+                               break;
+                       PR_PACK_SUB();
+                       (void)printf("\nNOP");
+                       break;
+#ifdef sgi
+               case IPOPT_SECURITY:    /* RFC 1108 RIPSO BSO */
+               case IPOPT_ESO:         /* RFC 1108 RIPSO ESO */
+               case IPOPT_CIPSO:       /* Commercial IPSO */
+                       if ((sysconf(_SC_IP_SECOPTS)) > 0) {
+                               i = (unsigned)cp[1];
+                               hlen -= i - 1;
+                               PR_PACK_SUB();
+                               (void)printf("\nSEC:");
+                               while (i--) {
+                                       (void)printf(" %02x", *cp++);
+                               }
+                               cp--;
+                               break;
+                       }
+#endif
+               default:
+                       PR_PACK_SUB();
+                       (void)printf("\nunknown option 0x%x", *cp);
+                       break;
+               }
+               hlen--;
+               cp++;
+       }
+
+       if (dumped) {
+               (void)putchar('\n');
+               (void)fflush(stdout);
+       } else {
+               jiggle(-1);
+       }
+}
+
+
+/* Compute the IP checksum
+ *     This assumes the packet is less than 32K long.
+ */
+static u_int16_t
+in_cksum(u_int16_t *p, u_int len)
+{
+       u_int32_t sum = 0;
+       int nwords = len >> 1;
+
+       while (nwords-- != 0)
+               sum += *p++;
+
+       if (len & 1) {
+               union {
+                       u_int16_t w;
+                       u_int8_t c[2];
+               } u;
+               u.c[0] = *(u_char *)p;
+               u.c[1] = 0;
+               sum += u.w;
+       }
+
+       /* end-around-carry */
+       sum = (sum >> 16) + (sum & 0xffff);
+       sum += (sum >> 16);
+       return (~sum);
+}
+
+
+/*
+ * compute the difference of two timespecs in seconds
+ */
+static double
+diffsec(struct timespec *timenow,
+       struct timespec *then)
+{
+       if (timenow->tv_sec == 0)
+               return -1;
+       return (timenow->tv_sec - then->tv_sec)
+           * 1.0 + (timenow->tv_nsec - then->tv_nsec) / 1000000000.0;
+}
+
+
+#if 0
+static void
+timespecadd(struct timespec *t1,
+          struct timespec *t2)
+{
+
+       t1->tv_sec += t2->tv_sec;
+       if ((t1->tv_nsec += t2->tv_nsec) >= 1000000000) {
+               t1->tv_sec++;
+               t1->tv_nsec -= 1000000000;
+       }
+}
+#endif
+
+
+static void
+sec_to_timespec(const double sec, struct timespec *tp)
+{
+       tp->tv_sec = sec;
+       tp->tv_nsec = (sec - tp->tv_sec) * 1000000000.0;
+}
+
+
+static double
+timespec_to_sec(const struct timespec *tp)
+{
+       return tp->tv_sec + tp->tv_nsec / 1000000000.0;
+}
+
+
+/*
+ * Print statistics.
+ * Heavily buffered STDIO is used here, so that all the statistics
+ * will be written with 1 sys-write call.  This is nice when more
+ * than one copy of the program is running on a terminal;  it prevents
+ * the statistics output from becomming intermingled.
+ */
+static void
+summary(int header)
+{
+       jiggle_flush(1);
+
+       if (header)
+               (void)printf("\n----%s PING Statistics----\n", hostname);
+       (void)printf("%d packets transmitted, ", ntransmitted);
+       (void)printf("%d packets received, ", nreceived);
+       if (nrepeats)
+               (void)printf("+%d duplicates, ", nrepeats);
+       if (ntransmitted) {
+               if (nreceived > ntransmitted)
+                       (void)printf("-- somebody's duplicating packets!");
+               else
+                       (void)printf("%.1f%% packet loss",
+                                    (((ntransmitted-nreceived)*100.0) /
+                                           ntransmitted));
+       }
+       (void)printf("\n");
+       if (nreceived && (pingflags & (F_TIMING|F_TIMING64))) {
+               double n = nreceived + nrepeats;
+               double avg = (tsum / n);
+               double variance = 0.0;
+               const unsigned int prec = (pingflags & F_TIMING64) != 0 ? 6 : 3;
+               if (n>1)
+                       variance = (tsumsq - n*avg*avg) /(n-1);
+
+               printf("round-trip min/avg/max/stddev = "
+                       "%.*f/%.*f/%.*f/%.*f ms\n",
+                       prec, tmin * 1000.0,
+                       prec, avg * 1000.0,
+                       prec, tmax * 1000.0,
+                       prec, sqrt(variance) * 1000.0);
+               if (pingflags & F_FLOOD) {
+                       double r = diffsec(&last_rx, &first_rx);
+                       double t = diffsec(&last_tx, &first_tx);
+                       if (r == 0)
+                               r = 0.0001;
+                       if (t == 0)
+                               t = 0.0001;
+                       (void)printf("  %.1f packets/sec sent, "
+                                    " %.1f packets/sec received\n",
+                                    ntransmitted/t, nreceived/r);
+               }
+       }
+}
+
+
+/*
+ * Print statistics when SIGINFO is received.
+ */
+/* ARGSUSED */
+static void
+prtsig(int dummy)
+{
+
+       summary(0);
+#ifndef SIGINFO
+       (void)signal(SIGQUIT, prtsig);
+#endif
+}
+
+
+/*
+ * On the first SIGINT, allow any outstanding packets to dribble in
+ */
+static void
+prefinish(int dummy)
+{
+       if (lastrcvd                    /* quit now if caught up */
+           || nreceived == 0)          /* or if remote is dead */
+               finish(0);
+
+       (void)signal(dummy, finish);    /* do this only the 1st time */
+
+       if (npackets > ntransmitted)    /* let the normal limit work */
+               npackets = ntransmitted;
+}
+
+/*
+ * Print statistics and give up.
+ */
+/* ARGSUSED */
+static void
+finish(int dummy)
+{
+#ifdef SIGINFO
+       (void)signal(SIGINFO, SIG_DFL);
+#else
+       (void)signal(SIGQUIT, SIG_DFL);
+#endif
+
+       summary(1);
+       exit(nreceived > 0 ? 0 : 2);
+}
+
+
+static int                             /* 0=do not print it */
+ck_pr_icmph(struct icmp *icp,
+           struct sockaddr_in *from,
+           int cc,
+           int override)               /* 1=override VERBOSE if interesting */
+{
+       int     hlen;
+       struct ip ipb, *ip = &ipb;
+       struct icmp icp2b, *icp2 = &icp2b;
+       int res;
+
+       if (pingflags & F_VERBOSE) {
+               res = 1;
+               jiggle_flush(1);
+       } else {
+               res = 0;
+       }
+
+       (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
+       hlen = ip->ip_hl << 2;
+       if (ip->ip_p == IPPROTO_ICMP
+           && hlen + 6 <= cc) {
+               (void) memcpy(icp2, &icp->icmp_data[hlen], sizeof(*icp2));
+               if (icp2->icmp_id == ident) {
+                       /* remember to clear route cached in kernel
+                        * if this non-Echo-Reply ICMP message was for one
+                        * of our packets.
+                        */
+                       clear_cache.tv_sec = 0;
+
+                       if (!res && override
+                           && (pingflags & (F_QUIET|F_SEMI_QUIET)) == 0) {
+                               jiggle_flush(1);
+                               (void)printf("%d bytes from %s: ",
+                                            cc, pr_addr(&from->sin_addr));
+                               res = 1;
+                       }
+               }
+       }
+
+       return res;
+}
+
+
+/*
+ *  Print a descriptive string about an ICMP header other than an echo reply.
+ */
+static int                             /* 0=printed nothing */
+pr_icmph(struct icmp *icp,
+        struct sockaddr_in *from,
+        int cc)
+{
+       switch (icp->icmp_type ) {
+       case ICMP_UNREACH:
+               if (!ck_pr_icmph(icp, from, cc, 1))
+                       return 0;
+               switch (icp->icmp_code) {
+               case ICMP_UNREACH_NET:
+                       (void)printf("Destination Net Unreachable");
+                       break;
+               case ICMP_UNREACH_HOST:
+                       (void)printf("Destination Host Unreachable");
+                       break;
+               case ICMP_UNREACH_PROTOCOL:
+                       (void)printf("Destination Protocol Unreachable");
+                       break;
+               case ICMP_UNREACH_PORT:
+                       (void)printf("Destination Port Unreachable");
+                       break;
+               case ICMP_UNREACH_NEEDFRAG:
+                       (void)printf("frag needed and DF set.  Next MTU=%d",
+                              ntohs(icp->icmp_nextmtu));
+                       break;
+               case ICMP_UNREACH_SRCFAIL:
+                       (void)printf("Source Route Failed");
+                       break;
+               case ICMP_UNREACH_NET_UNKNOWN:
+                       (void)printf("Unreachable unknown net");
+                       break;
+               case ICMP_UNREACH_HOST_UNKNOWN:
+                       (void)printf("Unreachable unknown host");
+                       break;
+               case ICMP_UNREACH_ISOLATED:
+                       (void)printf("Unreachable host isolated");
+                       break;
+               case ICMP_UNREACH_NET_PROHIB:
+                       (void)printf("Net prohibited access");
+                       break;
+               case ICMP_UNREACH_HOST_PROHIB:
+                       (void)printf("Host prohibited access");
+                       break;
+               case ICMP_UNREACH_TOSNET:
+                       (void)printf("Bad TOS for net");
+                       break;
+               case ICMP_UNREACH_TOSHOST:
+                       (void)printf("Bad TOS for host");
+                       break;
+               case 13:
+                       (void)printf("Communication prohibited");
+                       break;
+               case 14:
+                       (void)printf("Host precedence violation");
+                       break;
+               case 15:
+                       (void)printf("Precedence cutoff");
+                       break;
+               default:
+                       (void)printf("Bad Destination Unreachable Code: %d",
+                                    icp->icmp_code);
+                       break;
+               }
+               /* Print returned IP header information */
+               pr_retip(icp, cc);
+               break;
+
+       case ICMP_SOURCEQUENCH:
+               if (!ck_pr_icmph(icp, from, cc, 1))
+                       return 0;
+               (void)printf("Source Quench");
+               pr_retip(icp, cc);
+               break;
+
+       case ICMP_REDIRECT:
+               if (!ck_pr_icmph(icp, from, cc, 1))
+                       return 0;
+               switch (icp->icmp_code) {
+               case ICMP_REDIRECT_NET:
+                       (void)printf("Redirect Network");
+                       break;
+               case ICMP_REDIRECT_HOST:
+                       (void)printf("Redirect Host");
+                       break;
+               case ICMP_REDIRECT_TOSNET:
+                       (void)printf("Redirect Type of Service and Network");
+                       break;
+               case ICMP_REDIRECT_TOSHOST:
+                       (void)printf("Redirect Type of Service and Host");
+                       break;
+               default:
+                       (void)printf("Redirect--Bad Code: %d", icp->icmp_code);
+                       break;
+               }
+               (void)printf(" New router addr: %s",
+                            pr_addr(&icp->icmp_hun.ih_gwaddr));
+               pr_retip(icp, cc);
+               break;
+
+       case ICMP_ECHO:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Echo Request: ID=%d seq=%d",
+                            ntohs(icp->icmp_id), ntohs(icp->icmp_seq));
+               break;
+
+       case ICMP_ECHOREPLY:
+               /* displaying other's pings is too noisey */
+#if 0
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Echo Reply: ID=%d seq=%d",
+                            ntohs(icp->icmp_id), ntohs(icp->icmp_seq));
+               break;
+#else
+               return 0;
+#endif
+
+       case ICMP_ROUTERADVERT:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Router Discovery Advert");
+               break;
+
+       case ICMP_ROUTERSOLICIT:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Router Discovery Solicit");
+               break;
+
+       case ICMP_TIMXCEED:
+               if (!ck_pr_icmph(icp, from, cc, 1))
+                       return 0;
+               switch (icp->icmp_code ) {
+               case ICMP_TIMXCEED_INTRANS:
+                       (void)printf("Time To Live exceeded");
+                       break;
+               case ICMP_TIMXCEED_REASS:
+                       (void)printf("Frag reassembly time exceeded");
+                       break;
+               default:
+                       (void)printf("Time exceeded, Bad Code: %d",
+                                    icp->icmp_code);
+                       break;
+               }
+               pr_retip(icp, cc);
+               break;
+
+       case ICMP_PARAMPROB:
+               if (!ck_pr_icmph(icp, from, cc, 1))
+                       return 0;
+               (void)printf("Parameter problem: pointer = 0x%02x",
+                            icp->icmp_hun.ih_pptr);
+               pr_retip(icp, cc);
+               break;
+
+       case ICMP_TSTAMP:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Timestamp");
+               break;
+
+       case ICMP_TSTAMPREPLY:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Timestamp Reply");
+               break;
+
+       case ICMP_IREQ:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Information Request");
+               break;
+
+       case ICMP_IREQREPLY:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Information Reply");
+               break;
+
+       case ICMP_MASKREQ:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Address Mask Request");
+               break;
+
+       case ICMP_MASKREPLY:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Address Mask Reply");
+               break;
+
+       default:
+               if (!ck_pr_icmph(icp, from, cc, 0))
+                       return 0;
+               (void)printf("Bad ICMP type: %d", icp->icmp_type);
+               if (pingflags & F_VERBOSE)
+                       pr_iph(icp, cc);
+       }
+
+       return 1;
+}
+
+
+/*
+ *  Print an IP header with options.
+ */
+static void
+pr_iph(struct icmp *icp,
+       int cc)
+{
+       int     hlen;
+       u_char  *cp;
+       struct ip ipb, *ip = &ipb;
+
+       (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
+
+       hlen = ip->ip_hl << 2;
+       cp = (u_char *) &icp->icmp_data[20];    /* point to options */
+
+       (void)printf("\n Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src          Dst\n");
+       (void)printf("  %1x  %1x  %02x %04x %04x",
+                    ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
+       (void)printf("   %1x %04x",
+                    ((ip->ip_off)&0xe000)>>13, (ip->ip_off)&0x1fff);
+       (void)printf("  %02x  %02x %04x",
+                    ip->ip_ttl, ip->ip_p, ip->ip_sum);
+       (void)printf(" %15s ",
+                    inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
+       (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
+       /* dump any option bytes */
+       while (hlen-- > 20 && cp < (u_char*)icp+cc) {
+               (void)printf("%02x", *cp++);
+       }
+}
+
+/*
+ * Print an ASCII host address starting from a string of bytes.
+ */
+static void
+pr_saddr(u_char *cp)
+{
+       n_long l;
+       struct in_addr addr;
+
+       l = (u_char)*++cp;
+       l = (l<<8) + (u_char)*++cp;
+       l = (l<<8) + (u_char)*++cp;
+       l = (l<<8) + (u_char)*++cp;
+       addr.s_addr = htonl(l);
+       (void)printf("\t%s", (l == 0) ? "0.0.0.0" : pr_addr(&addr));
+}
+
+
+/*
+ *  Return an ASCII host address
+ *  as a dotted quad and optionally with a hostname
+ */
+static char *
+pr_addr(struct in_addr *addr)          /* in network order */
+{
+       struct  hostent *hp;
+       static  char buf[MAXHOSTNAMELEN+4+16+1];
+
+       if ((pingflags & F_NUMERIC)
+           || !(hp = gethostbyaddr((char *)addr, sizeof(*addr), AF_INET))) {
+               (void)snprintf(buf, sizeof(buf), "%s", inet_ntoa(*addr));
+       } else {
+               (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
+                   inet_ntoa(*addr));
+       }
+
+       return buf;
+}
+
+/*
+ *  Dump some info on a returned (via ICMP) IP packet.
+ */
+static void
+pr_retip(struct icmp *icp,
+        int cc)
+{
+       int     hlen;
+       u_char  *cp;
+       struct ip ipb, *ip = &ipb;
+
+       (void) memcpy(ip, icp->icmp_data, sizeof(*ip));
+
+       if (pingflags & F_VERBOSE)
+               pr_iph(icp, cc);
+
+       hlen = ip->ip_hl << 2;
+       cp = (u_char *) &icp->icmp_data[hlen];
+
+       if (ip->ip_p == IPPROTO_TCP) {
+               if (pingflags & F_VERBOSE)
+                       (void)printf("\n  TCP: from port %u, to port %u",
+                                    (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)));
+       } else if (ip->ip_p == IPPROTO_UDP) {
+               if (pingflags & F_VERBOSE)
+                       (void)printf("\n  UDP: from port %u, to port %u",
+                                    (*cp*256+*(cp+1)), (*(cp+2)*256+*(cp+3)));
+       } else if (ip->ip_p == IPPROTO_ICMP) {
+               struct icmp icp2;
+               (void) memcpy(&icp2, cp, sizeof(icp2));
+               if (icp2.icmp_type == ICMP_ECHO) {
+                       if (pingflags & F_VERBOSE)
+                               (void)printf("\n  ID=%u icmp_seq=%u",
+                                            ntohs((u_int16_t)icp2.icmp_id),
+                                            ntohs((u_int16_t)icp2.icmp_seq));
+                       else
+                               (void)printf(" for icmp_seq=%u",
+                                            ntohs((u_int16_t)icp2.icmp_seq));
+               }
+       }
+}
+
+static void
+fill(void)
+{
+       int i, j, k;
+       char *cp;
+       int pat[16];
+
+       for (cp = fill_pat; *cp != '\0'; cp++) {
+               if (!isxdigit((unsigned char)*cp))
+                       break;
+       }
+       if (cp == fill_pat || *cp != '\0' || (cp-fill_pat) > 16*2) {
+               (void)fflush(stdout);
+               errx(1, "\"-p %s\": patterns must be specified with"
+                    " 1-32 hex digits\n",
+                    fill_pat);
+       }
+
+       i = sscanf(fill_pat,
+                  "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+                   &pat[0], &pat[1], &pat[2], &pat[3],
+                   &pat[4], &pat[5], &pat[6], &pat[7],
+                   &pat[8], &pat[9], &pat[10], &pat[11],
+                   &pat[12], &pat[13], &pat[14], &pat[15]);
+
+       for (k = phdrlen, j = 0; k <= datalen; k++) {
+               opack_icmp.icmp_data[k] = pat[j];
+               if (++j >= i)
+                       j = 0;
+       }
+
+       if (!(pingflags & F_QUIET)) {
+               (void)printf("PATTERN: 0x");
+               for (j=0; j<i; j++)
+                       (void)printf("%02x",
+                                    (u_char)opack_icmp.icmp_data[phdrlen + j]);
+               (void)printf("\n");
+       }
+
+}
+
+
+static void
+rnd_fill(void)
+{
+       static u_int32_t rnd;
+       int i;
+
+       for (i = phdrlen; i < datalen; i++) {
+               rnd = (3141592621U * rnd + 663896637U);
+               opack_icmp.icmp_data[i] = rnd>>24;
+       }
+}
+
+
+static void
+gethost(const char *arg,
+       const char *name,
+       struct sockaddr_in *sa,
+       char *realname,
+       int realname_len)
+{
+       struct hostent *hp;
+
+       (void)memset(sa, 0, sizeof(*sa));
+       sa->sin_family = AF_INET;
+       sa->sin_len = sizeof(struct sockaddr_in);
+
+       /* If it is an IP address, try to convert it to a name to
+        * have something nice to display.
+        */
+       if (inet_aton(name, &sa->sin_addr) != 0) {
+               if (realname) {
+                       if (pingflags & F_NUMERIC)
+                               hp = 0;
+                       else
+                               hp = gethostbyaddr((char *)&sa->sin_addr,
+                                                  sizeof(sa->sin_addr),
+                                                  AF_INET);
+                       (void)strlcpy(realname, hp ? hp->h_name : name,
+                           realname_len);
+               }
+               return;
+       }
+       
+       hp = gethostbyname(name);
+       if (!hp)
+               errx(1, "Cannot resolve \"%s\" (%s)",name,hstrerror(h_errno));
+
+       if (hp->h_addrtype != AF_INET)
+               errx(1, "%s only supported with IP", arg);
+
+       (void)memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
+
+       if (realname)
+               (void)strlcpy(realname, hp->h_name, realname_len);
+}
+
+
+static void
+usage(void)
+{
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define IPSECOPT       "\n     [-E policy] "
+#else
+#define IPSECOPT       "\n     [-AE] "
+#endif /*IPSEC_POLICY_IPSEC*/
+#else
+#define IPSECOPT       ""
+#endif /*IPSEC*/
+
+       (void)fprintf(stderr, "usage: \n"
+           "%s [-aCDdfLnoPQqRrv] [-c count] [-g gateway] [-h host]"
+           " [-I addr] [-i interval]\n"
+           "     [-l preload] [-p pattern] [-s size] [-T ttl] [-t tos]"
+           " [-w maxwait] " IPSECOPT "host\n",
+           getprogname());
+       exit(1);
+}
diff --git a/sbin/ping/ping_hostops.c b/sbin/ping/ping_hostops.c
new file mode 100644 (file)
index 0000000..72b1f82
--- /dev/null
@@ -0,0 +1,53 @@
+/*     $NetBSD: ping_hostops.c,v 1.2 2011/03/11 09:59:56 pooka Exp $   */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ping_hostops.c,v 1.2 2011/03/11 09:59:56 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <poll.h>
+#include <unistd.h>
+
+#include "prog_ops.h"
+
+const struct prog_ops prog_ops = {
+       .op_socket = socket,
+       .op_setsockopt = setsockopt,
+       .op_shutdown = shutdown,
+       .op_poll = poll,
+       .op_recvfrom = recvfrom,
+       .op_sendto = sendto,
+       .op_close = close,
+       .op_getuid = getuid,
+       .op_setuid = setuid,
+};
diff --git a/sbin/ping/ping_rumpops.c b/sbin/ping/ping_rumpops.c
new file mode 100644 (file)
index 0000000..7e2f211
--- /dev/null
@@ -0,0 +1,58 @@
+/*     $NetBSD: ping_rumpops.c,v 1.2 2011/03/11 09:59:56 pooka Exp $   */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: ping_rumpops.c,v 1.2 2011/03/11 09:59:56 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <poll.h>
+#include <unistd.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/rumpclient.h>
+
+#include "prog_ops.h"
+
+const struct prog_ops prog_ops = {
+       .op_init =      rumpclient_init,
+
+       .op_socket =    rump_sys_socket,
+       .op_setsockopt= rump_sys_setsockopt,
+       .op_shutdown =  rump_sys_shutdown,
+       .op_poll =      rump_sys_poll,
+       .op_sendto =    rump_sys_sendto,
+       .op_recvfrom =  rump_sys_recvfrom,
+       .op_close =     rump_sys_close,
+       .op_getuid =    rump_sys_getuid,
+       .op_setuid =    rump_sys_setuid,
+};
diff --git a/sbin/ping/prog_ops.h b/sbin/ping/prog_ops.h
new file mode 100644 (file)
index 0000000..ccc5a70
--- /dev/null
@@ -0,0 +1,79 @@
+/*      $NetBSD: prog_ops.h,v 1.3 2011/03/11 09:59:56 pooka Exp $      */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROG_OPS_H_
+#define _PROG_OPS_H_
+
+#include <sys/types.h>
+
+#ifndef CRUNCHOPS
+struct prog_ops {
+       int (*op_init)(void);
+
+       int (*op_socket)(int, int, int);
+       int (*op_setsockopt)(int, int, int, const void *, socklen_t);
+       int (*op_shutdown)(int, int);
+
+       int (*op_poll)(struct pollfd *, nfds_t, int);
+
+       ssize_t (*op_recvfrom)(int, void *, size_t, int,
+                              struct sockaddr *, socklen_t *);
+       ssize_t (*op_sendto)(int, const void *, size_t, int,
+                              const struct sockaddr *, socklen_t);
+
+       int (*op_close)(int);
+
+       uid_t (*op_getuid)(void);
+       int (*op_setuid)(uid_t);
+};
+extern const struct prog_ops prog_ops;
+
+#define prog_init prog_ops.op_init
+#define prog_socket prog_ops.op_socket
+#define prog_setsockopt prog_ops.op_setsockopt
+#define prog_shutdown prog_ops.op_shutdown
+#define prog_poll prog_ops.op_poll
+#define prog_recvfrom prog_ops.op_recvfrom
+#define prog_sendto prog_ops.op_sendto
+#define prog_close prog_ops.op_close
+#define prog_getuid prog_ops.op_getuid
+#define prog_setuid prog_ops.op_setuid
+#else
+#define prog_init ((int (*)(void))NULL)
+#define prog_socket socket
+#define prog_setsockopt setsockopt
+#define prog_shutdown shutdown
+#define prog_poll poll
+#define prog_recvfrom recvfrom
+#define prog_sendto sendto
+#define prog_close close
+#define prog_getuid getuid
+#define prog_setuid setuid
+#endif
+
+#endif /* _PROG_OPS_H_ */
index 751f0734cefd6ec9384fb7f67b7292aa16f88a67..3870aabcaeebc406d3a49c6520bf902685448db9 100644 (file)
@@ -6,6 +6,8 @@ INCSDIR= /usr/include/net
 
 INCS=  ethertypes.h \
        if_ether.h \
+       radix.h \
+       route.h \
        \
        \
        \
index 26e610888c2be1ac2f0cda385421d08c001dba2d..d8bf7e6a664454e795dfb73eb189ac2d94f65fb9 100644 (file)
@@ -7,8 +7,10 @@ INCS=  \
        in_systm.h \
        \
        ip.h \
+       ip_icmp.h \
+       ip_var.h \
        tcp.h \
-       \
+       udp.h udp_var.h \
        
 
 .if !defined(__MINIX)
diff --git a/sys/netinet/ip_icmp.h b/sys/netinet/ip_icmp.h
new file mode 100644 (file)
index 0000000..2cdfdbb
--- /dev/null
@@ -0,0 +1,253 @@
+/*     $NetBSD: ip_icmp.h,v 1.33 2011/12/24 20:18:54 christos Exp $    */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ *     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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ip_icmp.h   8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef _NETINET_IP_ICMP_H_
+#define _NETINET_IP_ICMP_H_
+
+
+/*
+ * Interface Control Message Protocol Definitions.
+ * Per RFC 792, September 1981.
+ */
+
+/*
+ * Internal of an ICMP Router Advertisement
+ */
+struct icmp_ra_addr {
+       u_int32_t ira_addr;
+       u_int32_t ira_preference;
+} __packed;
+
+/*
+ * Structure of an icmp header.
+ */
+struct icmp {
+       u_int8_t  icmp_type;            /* type of message, see below */
+       u_int8_t  icmp_code;            /* type sub code */
+       u_int16_t icmp_cksum;           /* ones complement cksum of struct */
+       union {
+               u_int8_t  ih_pptr;              /* ICMP_PARAMPROB */
+               struct in_addr ih_gwaddr;       /* ICMP_REDIRECT */
+               struct ih_idseq {
+                         n_short icd_id;
+                         n_short icd_seq;
+               } ih_idseq __packed;
+               int32_t   ih_void;
+
+               /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
+               struct ih_pmtu {
+                         n_short ipm_void;
+                         n_short ipm_nextmtu;
+               } ih_pmtu __packed;
+               struct ih_rtradv {
+                       u_int8_t irt_num_addrs;
+                       u_int8_t irt_wpa;
+                       u_int16_t irt_lifetime;
+               } ih_rtradv __packed;
+       } icmp_hun /* XXX __packed ??? */;
+#define icmp_pptr        icmp_hun.ih_pptr
+#define icmp_gwaddr      icmp_hun.ih_gwaddr
+#define icmp_id                  icmp_hun.ih_idseq.icd_id
+#define icmp_seq         icmp_hun.ih_idseq.icd_seq
+#define icmp_void        icmp_hun.ih_void
+#define icmp_pmvoid      icmp_hun.ih_pmtu.ipm_void
+#define icmp_nextmtu     icmp_hun.ih_pmtu.ipm_nextmtu
+#define icmp_num_addrs   icmp_hun.ih_rtradv.irt_num_addrs
+#define icmp_wpa         icmp_hun.ih_rtradv.irt_wpa
+#define icmp_lifetime    icmp_hun.ih_rtradv.irt_lifetime
+       union {
+               struct id_ts {
+                         n_time its_otime;
+                         n_time its_rtime;
+                         n_time its_ttime;
+               } id_ts __packed;
+               struct id_ip  {
+                         struct ip idi_ip;
+                         /* options and then 64 bits of data */
+               } id_ip /* XXX: __packed ??? */;
+               struct icmp_ra_addr id_radv;
+               u_int32_t id_mask;
+               int8_t    id_data[1];
+       } icmp_dun /* XXX __packed ??? */;
+#define icmp_otime       icmp_dun.id_ts.its_otime
+#define icmp_rtime       icmp_dun.id_ts.its_rtime
+#define icmp_ttime       icmp_dun.id_ts.its_ttime
+#define icmp_ip                  icmp_dun.id_ip.idi_ip
+#define icmp_radv        icmp_dun.id_mask
+#define icmp_mask        icmp_dun.id_mask
+#define icmp_data        icmp_dun.id_data
+};
+
+/*
+ * Lower bounds on packet lengths for various types.
+ * For the error advice packets must first insure that the
+ * packet is large enought to contain the returned ip header.
+ * Only then can we do the check to see if 64 bits of packet
+ * data have been returned, since we need to check the returned
+ * ip header length.
+ */
+#define ICMP_MINLEN    8                               /* abs minimum */
+#define ICMP_TSLEN     (8 + 3 * sizeof (n_time))       /* timestamp */
+#define ICMP_MASKLEN   12                              /* address mask */
+#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8)    /* min */
+#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
+       /* N.B.: must separately check that ip_hl >= 5 */
+
+/*
+ * Definition of type and code field values.
+ */
+#define ICMP_ECHOREPLY         0               /* echo reply */
+#define ICMP_UNREACH           3               /* dest unreachable, codes: */
+#define                ICMP_UNREACH_NET        0               /* bad net */
+#define                ICMP_UNREACH_HOST       1               /* bad host */
+#define                ICMP_UNREACH_PROTOCOL   2               /* bad protocol */
+#define                ICMP_UNREACH_PORT       3               /* bad port */
+#define                ICMP_UNREACH_NEEDFRAG   4               /* IP_DF caused drop */
+#define                ICMP_UNREACH_SRCFAIL    5               /* src route failed */
+#define                ICMP_UNREACH_NET_UNKNOWN 6              /* unknown net */
+#define                ICMP_UNREACH_HOST_UNKNOWN 7             /* unknown host */
+#define                ICMP_UNREACH_ISOLATED   8               /* src host isolated */
+#define                ICMP_UNREACH_NET_PROHIB 9               /* prohibited access */
+#define                ICMP_UNREACH_HOST_PROHIB 10             /* ditto */
+#define                ICMP_UNREACH_TOSNET     11              /* bad tos for net */
+#define                ICMP_UNREACH_TOSHOST    12              /* bad tos for host */
+#define                ICMP_UNREACH_ADMIN_PROHIBIT 13          /* communication
+                                                          administratively
+                                                          prohibited */
+#define                ICMP_UNREACH_HOST_PREC  14              /* host precedence
+                                                          violation */
+#define                ICMP_UNREACH_PREC_CUTOFF 15             /* precedence cutoff */
+#define ICMP_SOURCEQUENCH      4               /* packet lost, slow down */
+#define ICMP_REDIRECT          5               /* shorter route, codes: */
+#define                ICMP_REDIRECT_NET       0               /* for network */
+#define                ICMP_REDIRECT_HOST      1               /* for host */
+#define                ICMP_REDIRECT_TOSNET    2               /* for tos and net */
+#define                ICMP_REDIRECT_TOSHOST   3               /* for tos and host */
+#define ICMP_ALTHOSTADDR       6               /* alternative host address */
+#define ICMP_ECHO              8               /* echo service */
+#define ICMP_ROUTERADVERT      9               /* router advertisement */
+#define                ICMP_ROUTERADVERT_NORMAL 0
+#define                ICMP_ROUTERADVERT_NOROUTE 16
+#define ICMP_ROUTERSOLICIT     10              /* router solicitation */
+#define ICMP_TIMXCEED          11              /* time exceeded, code: */
+#define                ICMP_TIMXCEED_INTRANS   0               /* ttl==0 in transit */
+#define                ICMP_TIMXCEED_REASS     1               /* ttl==0 in reass */
+#define ICMP_PARAMPROB         12              /* ip header bad */
+#define                ICMP_PARAMPROB_ERRATPTR 0
+#define                ICMP_PARAMPROB_OPTABSENT 1
+#define                ICMP_PARAMPROB_LENGTH   2
+#define ICMP_TSTAMP            13              /* timestamp request */
+#define ICMP_TSTAMPREPLY       14              /* timestamp reply */
+#define ICMP_IREQ              15              /* information request */
+#define ICMP_IREQREPLY         16              /* information reply */
+#define ICMP_MASKREQ           17              /* address mask request */
+#define ICMP_MASKREPLY         18              /* address mask reply */
+#define ICMP_TRACEROUTE                30              /* traceroute */
+#define ICMP_DATACONVERR       31              /* data conversion error */
+#define ICMP_MOBILE_REDIRECT   32              /* mobile redirect */
+#define ICMP_IPV6_WHEREAREYOU  33              /* ipv6 where are you */
+#define ICMP_IPV6_IAMHERE      34              /* ipv6 i am here */
+#define ICMP_MOBILE_REGREQUEST 35              /* mobile registration req */
+#define ICMP_MOBILE_REGREPLY   36              /* mobile registration reply */
+#define ICMP_SKIP              39              /* SKIP */
+#define ICMP_PHOTURIS          40              /* security */
+#define                ICMP_PHOTURIS_UNKNOWN_INDEX     0       /* unknown sec index */
+#define                ICMP_PHOTURIS_AUTH_FAILED       1       /* auth failed */
+#define                ICMP_PHOTURIS_DECOMPRESS_FAILED 2       /* decompress failed */
+#define                ICMP_PHOTURIS_DECRYPT_FAILED    3       /* decrypt failed */
+#define                ICMP_PHOTURIS_NEED_AUTHN        4       /* no authentication */
+#define                ICMP_PHOTURIS_NEED_AUTHZ        5       /* no authorization */
+
+#define ICMP_MAXTYPE           40
+
+#ifdef ICMP_STRINGS
+static const char *icmp_type[] = {
+       "echoreply", "unassigned_1", "unassigned_2", "unreach",
+       "sourcequench", "redirect", "althostaddr", "unassigned_7",
+       "echo", "routeradvert", "routersolicit", "timxceed",
+       "paramprob", "tstamp", "tstampreply", "ireq",
+       "ireqreply", "maskreq", "maskreply", "reserved_19",
+       "reserved_20", "reserved_21", "reserved_22", "reserved_23",
+       "reserved_24", "reserved_25", "reserved_26", "reserved_27",
+       "reserved_28", "reserved_29", "traceroute", "dataconverr",
+       "mobile_redirect", "ipv6_whereareyou", "ipv6_iamhere",
+       "mobile_regrequest", "mobile_regreply", "reserved_37",
+       "reserved_38", "skip", "photuris", NULL
+};
+static const char *icmp_code_none[] = { "none", NULL };
+static const char *icmp_code_unreach[] = {
+       "net", "host", "oprt", "needfrag", "srcfail", "net_unknown",
+       "host_unknown", "isolated", "net_prohib", "host_prohib",
+       "tosnet", "toshost", "admin_prohibit", "host_prec", "prec_cutoff", NULL
+};
+static const char *icmp_code_redirect[] = {
+       "net", "host", "tosnet", "toshost", NULL
+};
+static const char *icmp_code_routeradvert[] = {
+       "normal", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+       "noroute", NULL
+};
+static const char *icmp_code_timxceed[] = {
+       "intrans", "reass", NULL
+};
+static const char *icmp_code_paramprob[] = {
+       "erratptr", "optabsent", "length", NULL
+};
+static const char *icmp_code_photuris[] = {
+       "unknown_index", "auth_failed", "decompress_failed",
+       "decrypt_failed", "need_authn", "need_authz", NULL
+};
+#endif
+
+#define ICMP_INFOTYPE(type) \
+       ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
+       (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
+       (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
+       (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
+       (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
+
+#ifdef _KERNEL
+void   icmp_error(struct mbuf *, int, int, n_long, int);
+void   icmp_mtudisc(struct icmp *, struct in_addr);
+void   icmp_input(struct mbuf *, ...);
+void   icmp_init(void);
+void   icmp_reflect(struct mbuf *);
+void   icmp_send(struct mbuf *, struct mbuf *);
+int    icmp_sysctl(int *, u_int, void *, size_t *, void *, size_t);
+
+void   icmp_mtudisc_callback_register(void (*)(struct in_addr));
+int    icmp_ratelimit(const struct in_addr *, const int, const int);
+#endif
+
+
+#endif /* !_NETINET_IP_ICMP_H_ */
index 68e48faacc45f6d392f0ee2c5a30a814f7da3288..93e7e707a808dd803453ca60ef71d2946c76e612 100644 (file)
@@ -24,7 +24,7 @@ SUBDIR= \
        \
        rdate \
        \
-       \
+       traceroute \
        \
        \
        unlink user \
diff --git a/usr.sbin/traceroute/CHANGES b/usr.sbin/traceroute/CHANGES
new file mode 100644 (file)
index 0000000..0fadff0
--- /dev/null
@@ -0,0 +1,149 @@
+$NetBSD: CHANGES,v 1.2 2011/09/11 01:06:26 christos Exp $
+@(#) Id: CHANGES,v 1.23 2000/12/14 06:53:11 leres Exp  (LBL)
+
+v1.4 Wed Dec 13 22:50:35 PST 2000
+
+- Add an option to use icmp echo instead of udp datagrams.
+
+- Add HPUX and Linux support.
+
+- Handle hex argument values as suggested by John Hawkinson
+  (jhawk@mit.edu)
+
+- Added flags to set the first ttl and to set the don't fragment bit.
+
+- Add a local autoconf macro to check for routines in libraries; the
+  autoconf version is broken (it only puts the library name in the
+  cache variable name). Thanks to John Hawkinson.
+
+- Add a local autoconf macro to check for types; the autoconf version
+  is broken (it uses grep instead of actually compiling a code fragment).
+
+- Attempt to detect "egcs" versions of gcc.
+
+- Fix problems caused by savestr().
+
+- Detect when there are more interfaces than we can deal with. Thanks
+  to Guy Harris guy@netapp.com.
+
+- Accommodate changes made to FreeBSD 3.2-RELEASE network headers files.
+
+- The ip header offset needs to be byte swapped under Solaris on the
+  intel as well. Reported by John McDermott (jjm@jkintl.com) Also byte
+  ip length and offset for linux.
+
+- In wait_for_reply(), use passed socket instead of global one. Thanks
+  to Richard Kettlewell (richard.kettlewell@kewill.com)
+
+- Check for IFF_LOOPBACK as a define or an enum (concession to linux).
+  Reported by Robert Bihlmeyer (robbe@orcus.priv.at)
+
+- Increase size of SIOCGIFCONF buffer to accommodate systems with lots
+  of virtual interfaces. Ignore sun virtual interfaces. Suggested by
+  Ian Donaldson (iand@aone.com.au)
+
+- Always calculate icmp checksums when using -I. Reported by Soumen
+  (sbiswas@novell.com)
+
+- Documentation fix for description of -p. Thanks to Jeffrey C Honig
+  (jch@bsdi.com)
+
+- Enable ip checksums for Solaris 2.6 and higher (since they seem to
+  work correctly now).
+
+- Avoid problems when broken routers return 0.0.0.0 as their source
+  address. Thanks to John Hawkinson (jhawk@bbnplanet.com)
+
+- Canonicalize hostname if gethostname() doesn't return a domain.
+
+- Add -z flag (pause msecs) to allow optional pause between probes.
+  Suggested by Dave Morrison (drmorris@uplanet.com)
+
+- Fix max packet length test.
+
+- Use "/dev/null" instead of "." for file descriptor fodder.
+  Suggested by Tim Robbins (fyre@box3n.gumbynet.org)
+
+- Watch for a NULL argv[0]. Suggested by Tim Robbins.
+
+- Be careful with hostname legnths.
+
+- Print RFC1191 Path MTU Discovery value on "needfrag" unreachables.
+
+- Limit port size to 16 bits. Suggested by Tim Robbins.
+
+- Limit wait time to 24 hours.
+
+- Modified linux specific struct ipovly definition to avoid problems
+  with 64 bit systems. Problem reported by Uros Prestor
+  (uros@turbolinux.com)
+
+- Use kernel routing tables to determine correct source address.
+  Three styles are supported: bsd/socket, solaris/mib and linux.
+
+- Fix configure to recognize older versions of Solaris.
+
+v1.3.2 Thu Sep 26 18:06:16 PDT 1996
+
+- Rewrite source routing code to eliminate a number of problems on
+  systems using raw ip options. Also pad options with a noop so gateway
+  addresses are aligned.
+
+- Don't call inet_ntoa() twice in the same printf(). Thanks to NetBSD
+  via Bill Fenner (fenner@parc.xerox.com)
+
+- Decode "administratively prohibited filter" icmp code and print
+  numeric value for unknown codes. Thanks to Bill Fenner.
+
+v1.3.1 Wed Sep 18 21:08:16 PDT 1996
+
+- Some systems (e.g. AIX) need sys/select.h. Thanks to Brett Hogden
+  (hogden@rge.com)
+
+- Byte swap ip header length under Solaris. (This has no effect on the
+  sparc but is required on the i386.)
+
+- Made optional packet length control total size of packet.
+
+v1.3 Mon Sep 16 14:55:44 PDT 1996
+
+- Overrun buffer security fixes. Thanks to Bill Fenner
+  (fenner@parc.xerox.com)
+
+- Wait for response packet relative to start of probe. Thanks to Bill
+  Fenner.
+
+- Fix bug that prevented changing the packet size. Thanks to Gregory
+  Decker (gdecker@nate.dcrt.nih.gov)
+
+- Add support for RAW_OPTIONS (e.g. 4.4 BSD systems such as BSD/OS and
+  FreeBSD) thanks to Jeffrey C Honig (jch@bsdi.com)
+
+- Remove ip header byte swap fix from v1.2; most kernels swap the ip
+  header length in the kernel (and it causes OSF3 to crash).
+
+- Fix to not exit when the number of probes is set to 1 (i.e. "-q 1")
+
+- Improve autoconf configuration.
+
+v1.2 Tue Oct 17 23:50:05 PDT 1995
+
+- Convert to autoconf and ansify.
+
+- Byte swap ip header length for little endian machines. Fix thanks to
+  Y Badri (yb@greybox.demon.co.uk).
+
+v1.1 Thu Jun 15 02:32:55 PDT 1995
+
+- Check for too many arguments.
+
+- Recode to make timing of packet's round trip more obvious and to
+  tighten up code.
+
+- Ifdef IP_OPTIONS code.
+
+- Display time in microseconds.
+
+v1.0 Tue Feb 28 23:50:05 PDT 1989
+
+- Initial public release.
diff --git a/usr.sbin/traceroute/Makefile b/usr.sbin/traceroute/Makefile
new file mode 100644 (file)
index 0000000..4685ef6
--- /dev/null
@@ -0,0 +1,29 @@
+#      $NetBSD: Makefile,v 1.19 2011/09/11 01:06:26 christos Exp $     
+
+USE_FORT?= yes # network client
+
+RUMPPRG=traceroute
+MAN=   traceroute.8 
+
+CPPFLAGS+=-DHAVE_MALLOC_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SOCKIO_H=1
+CPPFLAGS+=-DHAVE_STRERROR=1 -DHAVE_SETLINEBUF=1 -DHAVE_SOCKADDR_SA_LEN=1 
+CPPFLAGS+=-DHAVE_RAW_OPTIONS=1
+CPPFLAGS+=-DHAVE_ICMP_NEXTMTU=1
+
+#CPPFLAGS+=-DIPSEC
+#LDADD+=       -lipsec
+#DPADD+=       ${LIBIPSEC}
+
+BINOWN= root
+BINMODE=4555
+
+SRCS=  traceroute.c ifaddrlist.c 
+SRCS+= version.c as.c
+
+.PATH: ${.CURDIR}/../../lib/libc/net
+RUMPSRCS= getifaddrs.c
+CPPFLAGS+= -DRUMP_ACTION
+
+AWKS=  median.awk mean.awk 
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/traceroute/as.c b/usr.sbin/traceroute/as.c
new file mode 100644 (file)
index 0000000..3808372
--- /dev/null
@@ -0,0 +1,224 @@
+/*     $NetBSD: as.c,v 1.4 2011/05/10 01:52:49 christos Exp $  */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "as.h"
+
+#define DEFAULT_AS_SERVER "whois.radb.net"
+#undef AS_DEBUG_FILE
+
+struct aslookup {
+       FILE *as_f;
+#ifdef AS_DEBUG_FILE
+       FILE *as_debug;
+#endif /* AS_DEBUG_FILE */
+};
+
+void *
+as_setup(const char *server)
+{
+       struct aslookup *asn;
+       struct addrinfo hints, *res0, *res;
+       FILE *f;
+       int s, error;
+
+       s = -1;
+       if (server == NULL)
+               server = getenv("RA_SERVER");
+       if (server == NULL)
+               server = DEFAULT_AS_SERVER;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+       error = getaddrinfo(server, "whois", &hints, &res0);
+       if (error == EAI_SERVICE) {
+               warnx("warning: whois/tcp service not found");
+               error = getaddrinfo(server, "43", &hints, &res0);
+       }
+
+       if (error != 0) {
+               warnx("%s: %s", server, gai_strerror(error));
+               return (NULL);
+       }
+
+       for (res = res0; res; res = res->ai_next) {
+               s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+               if (s < 0)
+                       continue;
+               if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
+                       break;
+               close(s);
+               s = -1;
+       }
+       freeaddrinfo(res0);
+       if (s < 0) {
+               warn("connect");
+               return (NULL);
+       }
+
+       f = fdopen(s, "r+");
+       (void)fprintf(f, "!!\n");
+       (void)fflush(f);
+
+       asn = malloc(sizeof(struct aslookup));
+       if (asn == NULL)
+               (void)fclose(f);
+       else
+               asn->as_f = f;
+
+#ifdef AS_DEBUG_FILE
+       if (asn) {
+               asn->as_debug = fopen(AS_DEBUG_FILE, "w");
+               if (asn->as_debug) {
+                       (void)fprintf(asn->as_debug, ">> !!\n");
+                       (void)fflush(asn->as_debug);
+               }
+       }
+#endif /* AS_DEBUG_FILE */
+
+       return (asn);
+}
+
+unsigned int
+as_lookup(void *_asn, char *addr, sa_family_t family)
+{
+       struct aslookup *asn = _asn;
+       char buf[1024];
+       unsigned int as;
+       int rc, dlen, plen;
+
+       as = 0;
+       rc = dlen = 0;
+       plen = (family == AF_INET6) ? 128 : 32;
+       (void)fprintf(asn->as_f, "!r%s/%d,l\n", addr, plen);
+       (void)fflush(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+       if (asn->as_debug) {
+               (void)fprintf(asn->as_debug, ">> !r%s/%d,l\n", addr, plen);
+               (void)fflush(asn->as_debug);
+       }
+#endif /* AS_DEBUG_FILE */
+
+       while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
+               buf[sizeof(buf) - 1] = '\0';
+
+#ifdef AS_DEBUG_FILE
+               if (asn->as_debug) {
+                       (void)fprintf(asn->as_debug, "<< %s", buf);
+                       (void)fflush(asn->as_debug);
+               }
+#endif /* AS_DEBUG_FILE */
+
+               if (rc == 0) {
+                       rc = buf[0];
+                       switch (rc) {
+                           case 'A':
+                               /* A - followed by # bytes of answer */
+                               sscanf(buf, "A%d\n", &dlen);
+#ifdef AS_DEBUG_FILE
+                               if (asn->as_debug) {
+                                       (void)fprintf(asn->as_debug,
+                                            "dlen: %d\n", dlen);
+                                       (void)fflush(asn->as_debug);
+                               }
+#endif /* AS_DEBUG_FILE */
+                               break;
+                           case 'C':   
+                           case 'D':
+                           case 'E':
+                           case 'F':
+                               /* C - no data returned */
+                               /* D - key not found */
+                               /* E - multiple copies of key */
+                               /* F - some other error */
+                               break;
+                       }
+                       if (rc == 'A')
+                               /* skip to next input line */
+                               continue;
+               }
+
+               if (dlen == 0)
+                       /* out of data, next char read is end code */
+                       rc = buf[0];
+               if (rc != 'A')
+                       /* either an error off the bat, or a done code */
+                       break;
+
+               /* data received, thank you */
+               dlen -= strlen(buf);
+
+               /* origin line is the interesting bit */
+               if (as == 0 && strncasecmp(buf, "origin:", 7) == 0) {
+                       sscanf(buf + 7, " AS%u", &as);
+#ifdef AS_DEBUG_FILE
+                       if (asn->as_debug) {
+                               (void)fprintf(asn->as_debug, "as: %d\n", as);
+                               (void)fflush(asn->as_debug);
+                       }
+#endif /* AS_DEBUG_FILE */
+               }
+       }
+
+       return (as);
+}
+
+void
+as_shutdown(void *_asn)
+{
+       struct aslookup *asn = _asn;
+
+       (void)fprintf(asn->as_f, "!q\n");
+       (void)fclose(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+       if (asn->as_debug) {
+               (void)fprintf(asn->as_debug, ">> !q\n");
+               (void)fclose(asn->as_debug);
+       }
+#endif /* AS_DEBUG_FILE */
+
+       free(asn);
+}
diff --git a/usr.sbin/traceroute/as.h b/usr.sbin/traceroute/as.h
new file mode 100644 (file)
index 0000000..324b89f
--- /dev/null
@@ -0,0 +1,34 @@
+/*     $NetBSD: as.h,v 1.4 2011/05/10 01:52:49 christos Exp $  */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+void   *as_setup(const char *);
+unsigned int as_lookup(void *, char *, sa_family_t);
+void   as_shutdown(void *);
diff --git a/usr.sbin/traceroute/gnuc.h b/usr.sbin/traceroute/gnuc.h
new file mode 100644 (file)
index 0000000..aadb5fa
--- /dev/null
@@ -0,0 +1,36 @@
+/*     $NetBSD: gnuc.h,v 1.2 2002/07/06 21:51:49 wiz Exp $     */
+
+/* @(#) Header: gnuc.h,v 1.3 95/10/09 02:47:01 leres Exp  (LBL) */
+
+/* inline foo */
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+
+/*
+ * Handle new and old "dead" routine prototypes
+ *
+ * For example:
+ *
+ *     __dead void foo(void) __attribute__((volatile));
+ *
+ */
+#ifdef __GNUC__
+#ifndef __dead
+#define __dead volatile
+#endif
+#if __GNUC__ < 2  || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
+#else
+#ifndef __dead
+#define __dead
+#endif
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
diff --git a/usr.sbin/traceroute/ifaddrlist.c b/usr.sbin/traceroute/ifaddrlist.c
new file mode 100644 (file)
index 0000000..170f397
--- /dev/null
@@ -0,0 +1,146 @@
+/*     $NetBSD: ifaddrlist.c,v 1.10 2011/09/11 01:06:26 christos Exp $ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ *     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 the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the Computer Systems
+ *     Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char rcsid[] =
+    "@(#) Header: ifaddrlist.c,v 1.2 97/04/22 13:31:05 leres Exp  (LBL)";
+    "@(#) Id: ifaddrlist.c,v 1.9 2000/11/23 20:01:55 leres Exp  (LBL)";
+#else
+__RCSID("$NetBSD: ifaddrlist.c,v 1.10 2011/09/11 01:06:26 christos Exp $");
+#endif
+#endif
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h>                          /* concession to AIX */
+
+struct mbuf;
+struct rtentry;
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "ifaddrlist.h"
+
+/* Not all systems have IFF_LOOPBACK */
+#ifdef IFF_LOOPBACK
+#define ISLOOPBACK(p) ((p)->ifa_flags & IFF_LOOPBACK)
+#else
+#define ISLOOPBACK(p) (strcmp((p)->ifa_name, "lo0") == 0)
+#endif
+
+/*
+ * Return the interface list
+ */
+ssize_t
+ifaddrlist(struct ifaddrlist **ipaddrp, char *errbuf, size_t buflen)
+{
+       struct sockaddr_in *sin;
+       struct ifaddrs *ifap = NULL, *ifa;
+       struct ifaddrlist *al = NULL, *nal;
+       size_t i = 0, maxal = 10;
+
+       if (getifaddrs(&ifap) != 0)
+               goto out;
+
+       if ((al = malloc(maxal * sizeof(*al))) == NULL)
+               goto out;
+               
+       for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+               if (ifa->ifa_addr->sa_family != AF_INET)
+                       continue;
+
+               /* Must be up */
+               if ((ifa->ifa_flags & IFF_UP) == 0)
+                       continue;
+
+               /*
+                * Must not be a loopback address (127/8)
+                */
+               sin = (struct sockaddr_in *)ifa->ifa_addr;
+               if (ISLOOPBACK(ifa))
+                       if (ntohl(sin->sin_addr.s_addr) == INADDR_LOOPBACK)
+                               continue;
+
+               if (i == maxal) {
+                       maxal <<= 1;
+                       if ((nal = realloc(al, maxal * sizeof(*al))) == NULL)
+                               goto out;
+                       al = nal;
+               }
+
+               al[i].addr = sin->sin_addr.s_addr;
+               if ((al[i].device = strdup(ifa->ifa_name)) == NULL)
+                       goto out;
+               i++;
+       }
+       if ((nal = realloc(al, i * sizeof(*al))) == NULL)
+               goto out;
+       freeifaddrs(ifap);
+       *ipaddrp = nal;
+       return (ssize_t)i;
+out:
+       if (ifap)
+               freeifaddrs(ifap);
+       if (al) {
+               while (i > 0)
+                       free(al[--i].device);
+               free(al);
+       }
+       (void)snprintf(errbuf, buflen, "%s: %s", __func__, strerror(errno));
+       return -1;
+}
diff --git a/usr.sbin/traceroute/ifaddrlist.h b/usr.sbin/traceroute/ifaddrlist.h
new file mode 100644 (file)
index 0000000..7e54279
--- /dev/null
@@ -0,0 +1,31 @@
+/*     $NetBSD: ifaddrlist.h,v 1.3 2011/05/11 00:38:28 christos Exp $  */
+
+/*
+ * Copyright (c) 1997
+ *     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.
+ *
+ * @(#) Header: traceroute.h,v 1.1 97/01/04 19:33:33 leres Locked  (LBL)
+ */
+
+struct ifaddrlist {
+       uint32_t addr;
+       char *device;
+};
+
+ssize_t        ifaddrlist(struct ifaddrlist **, char *, size_t);
diff --git a/usr.sbin/traceroute/mean.awk b/usr.sbin/traceroute/mean.awk
new file mode 100644 (file)
index 0000000..75cc421
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/awk -f
+#      $NetBSD: mean.awk,v 1.5 1997/10/04 16:31:29 christos Exp $
+/^ *[0-9]/     {
+       # print out the average time to each hop along a route.
+       tottime = 0; n = 0;
+       for (f = 5; f <= NF; ++f) {
+               if ($f == "ms") {
+                       tottime += $(f - 1)
+                       ++n
+               }
+       }
+       if (n > 0)
+               print $1, tottime/n, median
+}
diff --git a/usr.sbin/traceroute/median.awk b/usr.sbin/traceroute/median.awk
new file mode 100644 (file)
index 0000000..672e115
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/awk -f
+#      $NetBSD: median.awk,v 1.5 1997/10/04 16:31:32 christos Exp $
+/^ *[0-9]/     {
+       # print out the median time to each hop along a route.
+       tottime = 0; n = 0;
+       for (f = 5; f <= NF; ++f) {
+               if ($f == "ms") {
+                       ++n
+                       time[n] = $(f - 1)
+               }
+       }
+       if (n > 0) {
+               # insertion sort the times to find the median
+               for (i = 2; i <= n; ++i) {
+                       v = time[i]; j = i - 1;
+                       while (time[j] > v) {
+                               time[j+1] = time[j];
+                               j = j - 1;
+                               if (j < 0)
+                                       break;
+                       }
+                       time[j+1] = v;
+               }
+               if (n > 1 && (n % 2) == 0)
+                       median = (time[n/2] + time[(n/2) + 1]) / 2
+               else
+                       median = time[(n+1)/2]
+
+               print $1, median
+       }
+}
diff --git a/usr.sbin/traceroute/prog_ops.h b/usr.sbin/traceroute/prog_ops.h
new file mode 100644 (file)
index 0000000..9811d6f
--- /dev/null
@@ -0,0 +1,72 @@
+/*      $NetBSD: prog_ops.h,v 1.1 2010/12/15 00:09:41 pooka Exp $      */
+
+/*
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROG_OPS_H_
+#define _PROG_OPS_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <poll.h>
+
+struct prog_ops {
+       int (*op_init)(void);
+
+       int (*op_socket)(int, int, int);
+       int (*op_setsockopt)(int, int, int, const void *, socklen_t);
+       int (*op_shutdown)(int, int);
+
+       int (*op_poll)(struct pollfd *, nfds_t, int);
+
+       ssize_t (*op_recvfrom)(int, void *, size_t, int,
+                              struct sockaddr *, socklen_t *);
+       ssize_t (*op_sendto)(int, const void *, size_t, int,
+                              const struct sockaddr *, socklen_t);
+
+       int (*op_close)(int);
+
+       int (*op_connect)(int, const struct sockaddr *, socklen_t);
+       int (*op_getsockname)(int, struct sockaddr *, socklen_t *);
+
+       int (*op_sysctl)(const int *, u_int, void *, size_t *,
+                        const void *, size_t);
+};
+extern const struct prog_ops prog_ops;
+
+#define prog_init prog_ops.op_init
+#define prog_socket prog_ops.op_socket
+#define prog_setsockopt prog_ops.op_setsockopt
+#define prog_shutdown prog_ops.op_shutdown
+#define prog_poll prog_ops.op_poll
+#define prog_recvfrom prog_ops.op_recvfrom
+#define prog_sendto prog_ops.op_sendto
+#define prog_close prog_ops.op_close
+#define prog_connect prog_ops.op_connect
+#define prog_getsockname prog_ops.op_getsockname
+#define prog_sysctl prog_ops.op_sysctl
+
+#endif /* _PROG_OPS_H_ */
diff --git a/usr.sbin/traceroute/traceroute.8 b/usr.sbin/traceroute/traceroute.8
new file mode 100644 (file)
index 0000000..0ed6f2b
--- /dev/null
@@ -0,0 +1,419 @@
+.\" $NetBSD: traceroute.8,v 1.29 2011/09/11 01:06:26 christos Exp $
+.\"
+.\" Copyright (c) 1989, 1995, 1996, 1997
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not 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.
+.\"
+.\"    Id: traceroute.8,v 1.19 2000/09/21 08:44:19 leres Exp
+.\"
+.TH TRACEROUTE 8 "21 September 2000"
+.UC 6
+.SH NAME
+traceroute \- print the route packets take to network host
+.SH SYNOPSIS
+.na
+.B traceroute
+[
+.B \-aDFPIdlMnrvx
+] [
+.B \-f
+.I first_ttl
+]
+.br
+.ti +8
+[
+.B \-g
+.I gateway
+] [
+.B \-i
+.I iface
+] [
+.B \-m
+max_ttl
+]
+.br
+.ti +8
+[
+.B \-p
+.I port
+] [
+.B \-q
+.I nqueries
+] [
+.B \-s
+.I src_addr
+]
+.br
+.ti +8
+[
+.B \-t
+.I tos
+] [
+.B \-w
+.I waittime
+] [
+.B \-z
+.I pausemsecs
+ ]
+] [
+.B \-A
+.I as_server
+]
+.br
+.ti +8
+.I host
+[
+.I packetlen
+]
+.ad
+.SH DESCRIPTION
+The Internet is a large and complex aggregation of
+network hardware, connected together by gateways.
+Tracking the route one's packets follow (or finding the miscreant
+gateway that's discarding your packets) can be difficult.
+.I Traceroute
+uses the IP protocol `time to live' field and attempts to elicit an
+ICMP TIME_EXCEEDED response from each gateway along the path to some
+host.
+.PP
+The only mandatory parameter is the destination host name or IP number.
+The default probe datagram length is 40 bytes, but this may be increased
+by specifying a packet length (in bytes) after the destination host
+name.
+.PP
+Other options are:
+.TP
+.B \-a
+Turn on AS# lookups for each hop encountered.
+.TP
+.B \-A
+Turn on AS# lookups and use the given server instead of the default.
+.TP
+.B \-d
+Turn on socket-level debugging.
+.TP
+.B \-D
+Dump the packet data to standard error before transmitting it.
+.TP
+.B \-f
+Set the initial time-to-live used in the first outgoing probe packet.
+.TP
+.B \-F
+Set the "don't fragment" bit.
+.TP
+.B \-g
+Specify a loose source route gateway (8 maximum).
+.TP
+.B \-i
+Specify a network interface to obtain the source IP address for
+outgoing probe packets. This is normally only useful on a multi-homed
+host. (See the
+.B \-s
+flag for another way to do this.)
+.TP
+.B \-I
+Use ICMP ECHO instead of UDP datagrams.
+.TP
+.B \-l
+Display the ttl value of the returned packet.  This is useful for
+checking for asymmetric routing.
+.TP
+.B \-m
+Set the max time-to-live (max number of hops) used in outgoing probe
+packets.  The default value is taken from the
+.I net.inet.ip.ttl
+sysctl(3) variable.
+.TP
+.B \-M
+If found, show the MPLS Label and the Experimental (EXP) bit for the hop.
+.TP
+.B \-n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each gateway found on the
+path).
+.TP
+.B \-p
+Set the base UDP port number used in probes (default is 33434).
+Traceroute hopes that nothing is listening on UDP ports
+.I base
+to
+.I base + nhops \- 1
+at the destination host (so an ICMP PORT_UNREACHABLE message will
+be returned to terminate the route tracing).  If something is
+listening on a port in the default range, this option can be used
+to pick an unused port range.
+.TP
+.B \-P
+Set the "don't fragment" bit, and use the next hop mtu each time we get
+the "need fragmentation" error, thus probing the path MTU.
+.TP
+.B \-q
+Set the number of probe packets sent for each hop.  By default, traceroute
+sends three probe packets.
+.TP
+.B \-r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network,
+an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it (e.g., after the interface was dropped by
+.IR routed (8)).
+.TP
+.B \-s
+Use the following IP address (which usually is given as an IP number, not
+a hostname) as the source address in outgoing probe packets.  On
+multi-homed hosts (those with more than one IP
+address), this option can be used to
+force the source address to be something other than the IP address
+of the interface the probe packet is sent on.  If the IP address
+is not one of this machine's interface addresses, an error is
+returned and nothing is sent. (See the
+.B \-i
+flag for another way to do this.)
+.TP
+.B \-t
+Set the
+.I type-of-service
+in probe packets to the following value (default zero).  The value must be
+a decimal integer in the range 0 to 255.  This option can be used to
+see if different types-of-service result in different paths.  (If you
+are not running 4.4BSD, this may be academic since the normal network
+services like telnet and ftp don't let you control the TOS).
+Not all values of TOS are legal or
+meaningful \- see the IP spec for definitions.  Useful values are
+probably
+.RB ` -t
+.IR 16 '
+(low delay) and
+.RB ` -t
+.IR 8 '
+(high throughput).
+.TP
+.B \-v
+Verbose output.  Received ICMP packets other than TIME_EXCEEDED and
+UNREACHABLEs are listed.
+.TP
+.B \-w
+Set the time (in seconds) to wait for a response to a probe (default 5
+sec.).
+.TP
+.B \-x
+Toggle ip checksums. Normally, this prevents traceroute from calculating
+ip checksums. In some cases, the operating system can overwrite parts of
+the outgoing packet but not recalculate the checksum (so in some cases
+the default is to not calculate checksums and using
+.B \-x
+causes them to be calculated). Note that checksums are usually required
+for the last hop when using ICMP ECHO probes
+.RB ( \-I ).
+So they are always calculated when using ICMP.
+.TP
+.B \-z
+Set the time (in milliseconds) to pause between probes (default 0).
+Some systems such as Solaris and routers such as Ciscos rate limit
+icmp messages. A good value to use with this this is 500 (e.g. 1/2 second).
+.PP
+This program attempts to trace the route an IP packet would follow to some
+internet host by launching UDP probe
+packets with a small ttl (time to live) then listening for an
+ICMP "time exceeded" reply from a gateway.  We start our probes
+with a ttl of one and increase by one until we get an ICMP "port
+unreachable" (which means we got to "host") or hit a max (which
+defaults to 30 hops \*[Am] can be changed with the
+.B \-m
+flag).  Three
+probes (change with
+.B \-q
+flag) are sent at each ttl setting and a
+line is printed showing the ttl, address of the gateway and
+round trip time of each probe.  If the probe answers come from
+different gateways, the address of each responding system will
+be printed.  If there is no response within a 5 sec. timeout
+interval (changed with the
+.B \-w
+flag), a "*" is printed for that
+probe.
+.PP
+We don't want the destination
+host to process the UDP probe packets so the destination port is set to an
+unlikely value (if some clod on the destination is using that
+value, it can be changed with the
+.B \-p
+flag).
+.PP
+A sample use and output might be:
+
+.RS
+.nf
+[yak 71]% traceroute nis.nsf.net.
+traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 38 byte packet
+ 1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
+ 2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
+ 3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
+ 4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
+ 5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
+ 6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
+ 7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
+ 8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
+ 9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
+10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
+11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
+.fi
+.RE
+
+Note that lines 2 \*[Am] 3 are the same.  This is due to a buggy
+kernel on the 2nd hop system \- lilac-dmc.Berkeley.EDU \- that forwards
+packets with a zero ttl (a bug in the distributed version
+of 4.3BSD).  Note that you have to guess what path
+the packets are taking cross-country since the NSFNET (129.140)
+doesn't supply address-to-name translations for its NSSes.
+.PP
+A more interesting example is:
+
+.RS
+.nf
+[yak 72]% traceroute allspice.lcs.mit.edu.
+traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ 1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
+ 2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
+ 3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
+ 4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
+ 5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
+ 6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
+ 7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
+ 8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
+ 9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
+10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
+11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
+12  * * *
+13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
+14  * * *
+15  * * *
+16  * * *
+17  * * *
+18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
+.fi
+.RE
+
+Note that the gateways 12, 14, 15, 16 \*[Am] 17 hops away
+either don't send ICMP "time exceeded" messages or send them
+with a ttl too small to reach us.  14 \- 17 are running the
+MIT C Gateway code that doesn't send "time exceeded"s.  God
+only knows what's going on with 12.
+.PP
+The silent gateway 12 in the above may be the result of a bug in
+the 4.[23]BSD network code (and its derivatives):  4.x (x \(<= 3)
+sends an unreachable message using whatever ttl remains in the
+original datagram.  Since, for gateways, the remaining ttl is
+zero, the ICMP "time exceeded" is guaranteed to not make it back
+to us.  The behavior of this bug is slightly more interesting
+when it appears on the destination system:
+
+.RS
+.nf
+ 1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
+ 2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
+ 3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
+ 4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
+ 5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
+ 6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
+ 7  * * *
+ 8  * * *
+ 9  * * *
+10  * * *
+11  * * *
+12  * * *
+13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
+.fi
+.RE
+
+Notice that there are 12 "gateways" (13 is the final
+destination) and exactly the last half of them are "missing".
+What's really happening is that rip (a Sun-3 running Sun OS3.5)
+is using the ttl from our arriving datagram as the ttl in its
+ICMP reply.  So, the reply will time out on the return path
+(with no notice sent to anyone since ICMP's aren't sent for
+ICMP's) until we probe with a ttl that's at least twice the path
+length.  I.e., rip is really only 7 hops away.  A reply that
+returns with a ttl of 1 is a clue this problem exists.
+Traceroute prints a "!" after the time if the ttl is \(<= 1.
+Since vendors ship a lot of obsolete (DEC's ULTRIX, Sun 3.x) or
+non-standard (HP-UX) software, expect to see this problem
+frequently and/or take care picking the target host of your
+probes.
+
+Other possible annotations after the time are
+.BR !H ,
+.BR !N ,
+or
+.B !P
+(host, network or protocol unreachable),
+.B !S
+(source route failed),
+.B !F\-<pmtu>
+(fragmentation needed \- the RFC1191 Path MTU Discovery value is displayed),
+.B !X
+(communication administratively prohibited),
+.B !V
+(host precedence violation),
+.B !C
+(precedence cutoff in effect), or
+.B !\*[Lt]N\*[Gt]
+(ICMP unreachable code \*[Lt]num\*[Gt]).
+These are defined by RFC1812 (which supersedes RFC1716).
+If almost all the probes result in some kind of unreachable, traceroute
+will give up and exit.
+
+.RS
+.nf
+traceroute \-g 10.3.0.5 128.182.0.0
+.fi
+.RE
+
+will show the path from the Cambridge Mailbridge to PSC, while
+
+.RS
+.nf
+traceroute \-g 192.5.146.4 \-g 10.3.0.5 35.0.0.0
+.fi
+.RE
+
+will show the path from the Cambridge Mailbridge to Merit, using PSC to
+reach the Mailbridge.
+.PP
+This program is intended for use in network testing, measurement
+and management.
+It should be used primarily for manual fault isolation.
+Because of the load it could impose on the network, it is unwise to use
+.I traceroute
+during normal operations or from automated scripts.
+.SH SEE ALSO
+netstat(1), ping(8)
+.SH AUTHOR
+Implemented by Van Jacobson from a suggestion by Steve Deering.  Debugged
+by a cast of thousands with particularly cogent suggestions or fixes from
+C. Philip Wood, Tim Seaver and Ken Adelman.
+.LP
+The current version is available via anonymous ftp:
+.LP
+.RS
+.I ftp://ftp.ee.lbl.gov/traceroute.tar.gz
+.RE
+.SH BUGS
+Please send bug reports to traceroute@ee.lbl.gov.
+.PP
+The AS number capability reports information that may sometimes be
+inaccurate due to discrepancies between the contents of the routing
+database server and the current state of the Internet.
diff --git a/usr.sbin/traceroute/traceroute.c b/usr.sbin/traceroute/traceroute.c
new file mode 100644 (file)
index 0000000..a4b10f9
--- /dev/null
@@ -0,0 +1,1905 @@
+/*     $NetBSD: traceroute.c,v 1.81 2012/08/16 00:40:28 zafer Exp $    */
+
+/*
+ * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ *     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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char rcsid[] =
+    "@(#)Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp  (LBL)";
+#else
+__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997,\
+ 1998, 1999, 2000\
+ The Regents of the University of California.  All rights reserved.");
+__RCSID("$NetBSD: traceroute.c,v 1.81 2012/08/16 00:40:28 zafer Exp $");
+#endif
+#endif
+
+
+#include <net/hton.h>
+#include <net/gen/in.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <net/gen/ether.h>
+#include <net/gen/eth_hdr.h>
+#include <net/gen/eth_io.h>
+#include <net/gen/ip_hdr.h>
+#include <net/gen/ip_io.h>
+#include <net/gen/udp.h>
+#include <net/gen/udp_hdr.h>
+#include <net/gen/udp_io.h>
+
+/*
+ * traceroute host  - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host.  We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway.  We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to 30 hops & can be changed with the -m flag).  Three
+ * probes (change with -q flag) are sent at each ttl setting and a
+ * line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe.  If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed.  If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format.  We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ *     [yak 71]% traceroute nis.nsf.net.
+ *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+ *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
+ *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
+ *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
+ *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
+ *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
+ *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
+ *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
+ *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
+ *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
+ *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
+ *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
+ *
+ * Note that lines 2 & 3 are the same.  This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ *     [yak 72]% traceroute allspice.lcs.mit.edu.
+ *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
+ *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
+ *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
+ *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
+ *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
+ *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
+ *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
+ *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
+ *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
+ *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
+ *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
+ *     12  * * *
+ *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
+ *     14  * * *
+ *     15  * * *
+ *     16  * * *
+ *     17  * * *
+ *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us.  14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s.  God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram.  Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us.  The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
+ *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
+ *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
+ *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
+ *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
+ *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
+ *      7  * * *
+ *      8  * * *
+ *      9  * * *
+ *     10  * * *
+ *     11  * * *
+ *     12  * * *
+ *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply.  So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length.  I.e., rip is really only 7 hops away.  A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one).  If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid.  (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley:  A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in a ip datagram).  See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
+ * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram.  8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id).  So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range).  To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example.  I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep.  I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering.  Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis.  I don't know (or care) who came up with
+ * the idea first.  I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself.  Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless.  Maybe one day...
+ *
+ *  -- Van Jacobson (van@ee.lbl.gov)
+ *     Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <memory.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <poll.h>
+#ifdef IPSEC
+#include <net/route.h>
+#include <netipsec/ipsec.h>
+#endif
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+/* rfc1716 */
+#ifndef ICMP_UNREACH_FILTER_PROHIB
+#define ICMP_UNREACH_FILTER_PROHIB     13      /* admin prohibited filter */
+#endif
+#ifndef ICMP_UNREACH_HOST_PRECEDENCE
+#define ICMP_UNREACH_HOST_PRECEDENCE   14      /* host precedence violation */
+#endif
+#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
+#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15      /* precedence cutoff */
+#endif
+
+#include "ifaddrlist.h"
+#include "as.h"
+#include "prog_ops.h"
+
+/* Maximum number of gateways (include room for one noop) */
+#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define Fprintf (void)fprintf
+#define Printf (void)printf
+
+/* Host name and address list */
+struct hostinfo {
+       char *name;
+       int n;
+       u_int32_t *addrs;
+};
+
+/* Data section of the probe packet */
+struct outdata {
+       u_char seq;             /* sequence number of this packet */
+       u_char ttl;             /* ttl packet left with */
+       struct tv32 {
+               int32_t tv32_sec;
+               int32_t tv32_usec;
+       } tv;                   /* time packet left */
+};
+
+/*
+ * Support for ICMP extensions
+ *
+ * http://www.ietf.org/proceedings/01aug/I-D/draft-ietf-mpls-icmp-02.txt
+ */
+#define ICMP_EXT_OFFSET    8 /* ICMP type, code, checksum, unused */ + \
+                         128 /* original datagram */
+#define ICMP_EXT_VERSION 2
+/*
+ * ICMP extensions, common header
+ */
+struct icmp_ext_cmn_hdr {
+#if BYTE_ORDER == BIG_ENDIAN
+       unsigned char   version:4;
+       unsigned char   reserved1:4;
+#else
+       unsigned char   reserved1:4;
+       unsigned char   version:4;
+#endif
+       unsigned char   reserved2;
+       unsigned short  checksum;
+};
+
+/*
+ * ICMP extensions, object header
+ */
+struct icmp_ext_obj_hdr {
+    u_short length;
+    u_char  class_num;
+#define MPLS_STACK_ENTRY_CLASS 1
+    u_char  c_type;
+#define MPLS_STACK_ENTRY_C_TYPE 1
+};
+
+struct mpls_header {
+#if BYTE_ORDER == BIG_ENDIAN
+        uint32_t       label:20;
+        unsigned char  exp:3;
+        unsigned char  s:1;
+        unsigned char  ttl:8;
+#else
+        unsigned char  ttl:8;
+        unsigned char  s:1;
+        unsigned char  exp:3;
+        uint32_t       label:20;
+#endif
+};
+
+#ifndef HAVE_ICMP_NEXTMTU
+/* Path MTU Discovery (RFC1191) */
+struct my_pmtu {
+       u_short ipm_void;
+       u_short ipm_nextmtu;
+};
+#endif
+
+static u_char  packet[512];            /* last inbound (icmp) packet */
+
+static struct ip *outip;               /* last output (udp) packet */
+static struct udphdr *outudp;          /* last output (udp) packet */
+static void *outmark;                  /* packed location of struct outdata */
+static struct outdata outsetup;        /* setup and copy for alignment */
+
+static struct icmp *outicmp;           /* last output (icmp) packet */
+
+/* loose source route gateway list (including room for final destination) */
+static u_int32_t gwlist[NGATEWAYS + 1];
+
+static int s;                          /* receive (icmp) socket file descriptor */
+static int sndsock;                    /* send (udp/icmp) socket file descriptor */
+
+static struct sockaddr whereto;                /* Who to try to reach */
+static struct sockaddr wherefrom;      /* Who we are */
+static int packlen;                    /* total length of packet */
+static int minpacket;                  /* min ip packet size */
+static int maxpacket = 32 * 1024;      /* max ip packet size */
+static int printed_ttl = 0;
+static int pmtu;                       /* Path MTU Discovery (RFC1191) */
+static u_int pausemsecs;
+
+static const char *prog;
+static char *source;
+static char *hostname;
+static char *device;
+#ifdef notdef
+static const char devnull[] = "/dev/null";
+#endif
+
+static int nprobes = 3;
+static int max_ttl = 30;
+static int first_ttl = 1;
+static u_int16_t ident;
+static in_port_t port = 32768 + 666;   /* start udp dest port # for probe packets */
+
+static int options;                    /* socket options */
+static int verbose;
+static int waittime = 5;               /* time to wait for response (in seconds) */
+static int nflag;                      /* print addresses numerically */
+static int dump;
+static int Mflag;                      /* show MPLS labels if any */
+static int as_path;                    /* print as numbers for each hop */
+static char *as_server = NULL;
+static void *asn;
+static int useicmp = 0;                /* use icmp echo instead of udp packets */
+#ifdef CANT_HACK_CKSUM
+static int doipcksum = 0;              /* don't calculate checksums */
+#else
+static int doipcksum = 1;              /* calculate checksums */
+#endif
+static int optlen;                     /* length of ip options */
+
+static int mtus[] = {
+        17914,
+         8166,
+         4464,
+         4352,
+         2048,
+         2002,
+         1536,
+         1500,
+         1492,
+         1480,
+         1280,
+         1006,
+          576,
+          552,
+          544,
+          512,
+          508,
+          296,
+           68,
+            0
+};
+static int *mtuptr = &mtus[0];
+static int mtudisc = 0;
+static int nextmtu;   /* from ICMP error, set by packet_ok(), might be 0 */
+
+/* Forwards */
+static double deltaT(struct timeval *, struct timeval *);
+static void freehostinfo(struct hostinfo *);
+static void getaddr(u_int32_t *, char *);
+static struct hostinfo *gethostinfo(char *);
+static u_int16_t in_cksum(u_int16_t *, int);
+static u_int16_t in_cksum2(u_int16_t, u_int16_t *, int);
+static char *inetname(struct in_addr);
+static int packet_ok(u_char *, ssize_t, struct sockaddr_in *, int);
+static const char *pr_type(u_char);
+static void print(u_char *, int, struct sockaddr_in *);
+static void resize_packet(void);
+static void dump_packet(void);
+static void send_probe(int, int, struct timeval *);
+static void setsin(struct sockaddr_in *, u_int32_t);
+static int str2val(const char *, const char *, int, int);
+static void tvsub(struct timeval *, struct timeval *);
+static void usage(void) __attribute__((__noreturn__));
+static ssize_t wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
+static void decode_extensions(unsigned char *buf, int ip_len);
+static void frag_err(void);
+static int find_local_ip(struct sockaddr_in *, struct sockaddr_in *);
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+static int setpolicy(int, const char *);
+#endif
+#endif
+
+int
+main(int argc, char **argv)
+{
+       int op, code, n;
+       u_char *outp;
+       u_int32_t *ap;
+       struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
+       struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
+       struct hostinfo *hi;
+       int on = 1;
+       int ttl, probe, i;
+       int seq = 0;
+       int tos = 0, settos = 0, ttl_flag = 0;
+       int lsrr = 0;
+       u_int16_t off = 0;
+       struct ifaddrlist *al, *al2;
+       char errbuf[132];
+       int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+       size_t size = sizeof(max_ttl);
+
+       setprogname(argv[0]);
+       prog = getprogname();
+
+       if (prog_init && prog_init() == -1)
+               err(1, "init failed");
+
+#ifdef notdef
+       /* Kernel takes care of it */
+       /* Insure the socket fds won't be 0, 1 or 2 */
+       if (open(devnull, O_RDONLY) < 0 ||
+           open(devnull, O_RDONLY) < 0 ||
+           open(devnull, O_RDONLY) < 0)
+               err(1, "Cannot open `%s'", devnull);
+#endif
+       if ((s = prog_socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
+               err(1, "icmp socket");
+
+       /*
+        * XXX 'useicmp' will always be zero here. I think the HP-UX users
+        * running our traceroute code will forgive us.
+        */
+#ifndef __hpux
+#ifdef __minix
+       sndsock = prog_socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
+#else
+       sndsock = prog_socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+#endif
+#else
+       sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW
+           useicmp ? IPPROTO_ICMP : IPPROTO_UDP);
+#endif
+       if (sndsock < 0)
+               err(1, "raw socket");
+
+       (void) prog_sysctl(mib, sizeof(mib)/sizeof(mib[0]), &max_ttl, &size,
+           NULL, 0);
+
+       opterr = 0;
+       while ((op = getopt(argc, argv, "aA:dDFPIMnlrvxf:g:i:m:p:q:s:t:w:z:")) != -1)
+               switch (op) {
+
+               case 'a':
+                       as_path = 1;
+                       break;
+
+               case 'A':
+                       as_path = 1;
+                       as_server = optarg;
+                       break;
+
+               case 'd':
+                       options |= SO_DEBUG;
+                       break;
+
+               case 'D':
+                       dump = 1;
+                       break;
+
+               case 'f':
+                       first_ttl = str2val(optarg, "first ttl", 1, 255);
+                       break;
+
+               case 'F':
+                       off = IP_DF;
+                       break;
+
+               case 'g':
+                       if (lsrr >= NGATEWAYS)
+                               errx(1, "more than %d gateways", NGATEWAYS);
+                       getaddr(gwlist + lsrr, optarg);
+                       ++lsrr;
+                       break;
+
+               case 'i':
+                       device = optarg;
+                       break;
+
+               case 'I':
+                       ++useicmp;
+                       break;
+
+               case 'l':
+                       ++ttl_flag;
+                       break;
+
+               case 'm':
+                       max_ttl = str2val(optarg, "max ttl", 1, 255);
+                       break;
+
+               case 'M':
+                       Mflag = 1;
+                       break;
+
+               case 'n':
+                       ++nflag;
+                       break;
+
+               case 'p':
+                       port = (u_short)str2val(optarg, "port",
+                           1, (1 << 16) - 1);
+                       break;
+
+               case 'q':
+                       nprobes = str2val(optarg, "nprobes", 1, -1);
+                       break;
+
+               case 'r':
+                       options |= SO_DONTROUTE;
+                       break;
+
+               case 's':
+                       /*
+                        * set the ip source address of the outbound
+                        * probe (e.g., on a multi-homed host).
+                        */
+                       source = optarg;
+                       break;
+
+               case 't':
+                       tos = str2val(optarg, "tos", 0, 255);
+                       ++settos;
+                       break;
+
+               case 'v':
+                       ++verbose;
+                       break;
+
+               case 'x':
+                       doipcksum = (doipcksum == 0);
+                       break;
+
+               case 'w':
+                       waittime = str2val(optarg, "wait time",
+                           2, 24 * 60 * 60);
+                       break;
+
+               case 'z':
+                       pausemsecs = str2val(optarg, "pause msecs",
+                           0, 60 * 60 * 1000);
+
+               case 'P':
+                       off = IP_DF;
+                       mtudisc = 1;
+                       break;
+
+               default:
+                       usage();
+               }
+
+       if (first_ttl > max_ttl)
+               errx(1, "first ttl (%d) may not be greater than max ttl (%d)",
+                   first_ttl, max_ttl);
+
+       if (!doipcksum)
+               warnx("ip checksums disabled");
+
+       if (lsrr > 0)
+               optlen = (lsrr + 1) * sizeof(gwlist[0]);
+       minpacket = sizeof(*outip) + sizeof(struct outdata) + optlen;
+       if (useicmp)
+               minpacket += 8;                 /* XXX magic number */
+       else
+               minpacket += sizeof(*outudp);
+       packlen = minpacket;            /* minimum sized packet */
+
+       if (mtudisc)
+               packlen = *mtuptr++;
+
+       /* Process destination and optional packet size */
+       switch (argc - optind) {
+
+       case 2:
+               packlen = str2val(argv[optind + 1],
+                   "packet length", minpacket, maxpacket);
+               /* Fall through */
+
+       case 1:
+               hostname = argv[optind];
+               hi = gethostinfo(hostname);
+               setsin(to, hi->addrs[0]);
+               if (hi->n > 1)
+                       warnx("%s has multiple addresses; using %s",
+                           hostname, inet_ntoa(to->sin_addr));
+               hostname = hi->name;
+               hi->name = NULL;
+               freehostinfo(hi);
+               break;
+
+       default:
+               usage();
+       }
+
+#ifdef HAVE_SETLINEBUF
+       setlinebuf (stdout);
+#else
+       setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
+
+       outip = malloc((unsigned)packlen);
+       if (outip == NULL)
+               err(1, "malloc");
+       memset(outip, 0, packlen);
+
+       outip->ip_v = IPVERSION;
+       if (settos)
+               outip->ip_tos = tos;
+#ifdef BYTESWAP_IP_HDR
+       outip->ip_len = htons(packlen);
+       outip->ip_off = htons(off);
+#else
+       outip->ip_len = packlen;
+       outip->ip_off = off;
+#endif
+       outp = (u_char *)(outip + 1);
+#ifdef HAVE_RAW_OPTIONS
+       if (lsrr > 0) {
+               u_char *optlist;
+
+               optlist = outp;
+               outp += optlen;
+
+               /* final hop */
+               gwlist[lsrr] = to->sin_addr.s_addr;
+
+               outip->ip_dst.s_addr = gwlist[0];
+
+               /* force 4 byte alignment */
+               optlist[0] = IPOPT_NOP;
+               /* loose source route option */
+               optlist[1] = IPOPT_LSRR;
+               i = lsrr * sizeof(gwlist[0]);
+               optlist[2] = i + 3;
+               /* Pointer to LSRR addresses */
+               optlist[3] = IPOPT_MINOFF;
+               memcpy(optlist + 4, gwlist + 1, i);
+       } else
+#endif
+               outip->ip_dst = to->sin_addr;
+
+       outip->ip_hl = (outp - (u_char *)outip) >> 2;
+       ident = htons(arc4random() & 0xffff) | 0x8000;
+       if (useicmp) {
+               outip->ip_p = IPPROTO_ICMP;
+
+               outicmp = (struct icmp *)outp;
+               outicmp->icmp_type = ICMP_ECHO;
+               outicmp->icmp_id = htons(ident);
+
+               outmark = outp + 8;     /* XXX magic number */
+       } else {
+               outip->ip_p = IPPROTO_UDP;
+
+               outudp = (struct udphdr *)outp;
+               outudp->uh_sport = htons(ident);
+               outudp->uh_ulen =
+                   htons((u_int16_t)(packlen - (sizeof(*outip) + optlen)));
+               outmark = outudp + 1;
+       }
+
+       if (options & SO_DEBUG)
+               (void)prog_setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
+                   sizeof(on));
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+       /*
+        * do not raise error even if setsockopt fails, kernel may have ipsec
+        * turned off.
+        */
+       if (setpolicy(s, "in bypass") < 0)
+               exit(1);
+       if (setpolicy(s, "out bypass") < 0)
+               exit(1);
+#else
+    {
+       int level = IPSEC_LEVEL_AVAIL;
+
+       (void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &level,
+               sizeof(level));
+       (void)prog_setsockopt(s, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, &level,
+               sizeof(level));
+#ifdef IP_AUTH_TRANS_LEVEL
+       (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &level,
+               sizeof(level));
+#else
+       (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_LEVEL, &level,
+               sizeof(level));
+#endif
+#ifdef IP_AUTH_NETWORK_LEVEL
+       (void)prog_setsockopt(s, IPPROTO_IP, IP_AUTH_NETWORK_LEVEL, &level,
+               sizeof(level));
+#endif
+    }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+       /*
+        * do not raise error even if setsockopt fails, kernel may have ipsec
+        * turned off.
+        */
+       if (setpolicy(sndsock, "in bypass") < 0)
+               exit(1);
+       if (setpolicy(sndsock, "out bypass") < 0)
+               exit(1);
+#else
+    {
+       int level = IPSEC_LEVEL_BYPASS;
+
+       (void)prog_setsockopt(sndsock, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &level,
+               sizeof(level));
+       (void)prog_setsockopt(sndsock, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, &level,
+               sizeof(level));
+#ifdef IP_AUTH_TRANS_LEVEL
+       (void)prog_setsockopt(sndsock, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &level,
+               sizeof(level));
+#else
+       (void)prog_setsockopt(sndsock, IPPROTO_IP, IP_AUTH_LEVEL, &level,
+               sizeof(level));
+#endif
+#ifdef IP_AUTH_NETWORK_LEVEL
+       (void)prog_setsockopt(sndsock, IPPROTO_IP, IP_AUTH_NETWORK_LEVEL, &level,
+               sizeof(level));
+#endif
+    }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
+       if (lsrr > 0) {
+               u_char optlist[MAX_IPOPTLEN];
+
+               /* final hop */
+               gwlist[lsrr] = to->sin_addr.s_addr;
+               ++lsrr;
+
+               /* force 4 byte alignment */
+               optlist[0] = IPOPT_NOP;
+               /* loose source route option */
+               optlist[1] = IPOPT_LSRR;
+               i = lsrr * sizeof(gwlist[0]);
+               optlist[2] = i + 3;
+               /* Pointer to LSRR addresses */
+               optlist[3] = IPOPT_MINOFF;
+               memcpy(optlist + 4, gwlist, i);
+
+               if ((prog_setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, optlist,
+                   i + sizeof(gwlist[0]))) < 0)
+                       err(1, "IP_OPTIONS");
+       }
+#endif
+
+#ifndef __minix
+#ifdef SO_SNDBUF
+       if (prog_setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
+           sizeof(packlen)) < 0)
+               err(1, "SO_SNDBUF");
+#endif
+#ifdef IP_HDRINCL
+       if (prog_setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+           sizeof(on)) < 0)
+               err(1, "IP_HDRINCL");
+#else
+#ifdef IP_TOS
+       if (settos && prog_setsockopt(sndsock, IPPROTO_IP, IP_TOS,
+           &tos, sizeof(tos)) < 0)
+               err(1, "setsockopt tos %d", tos);
+#endif
+#endif
+       if (options & SO_DEBUG)
+               if (prog_setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, &on,
+                   sizeof(on)) < 0)
+                       err(1, "setsockopt debug %d", tos);
+       if (options & SO_DONTROUTE)
+               if (prog_setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, &on,
+                   sizeof(on)) < 0)
+                       err(1, "setsockopt dontroute %d", tos);
+#endif
+
+       /* Get the interface address list */
+       n = ifaddrlist(&al, errbuf, sizeof errbuf);
+       al2 = al;
+       if (n < 0)
+               errx(1, "ifaddrlist (%s)", errbuf);
+       if (n == 0)
+               errx(1, "Can't find any network interfaces");
+
+       /* Look for a specific device */
+       if (device != NULL) {
+               for (i = n; i > 0; --i, ++al2)
+                       if (strcmp(device, al2->device) == 0)
+                               break;
+               if (i <= 0)
+                       errx(1, "Can't find interface %.32s", device);
+       }
+
+       /* Determine our source address */
+       if (source == NULL) {
+               /*
+                * If a device was specified, use the interface address.
+                * Otherwise, try to determine our source address.
+                * Warn if there are more than one.
+                */
+               setsin(from, al2->addr);
+               if (n > 1 && device == NULL && !find_local_ip(from, to)) {
+                       warnx("Multiple interfaces found; using %s @ %s",
+                           inet_ntoa(from->sin_addr), al2->device);
+               }
+       } else {
+               hi = gethostinfo(source);
+               source = hi->name;
+               hi->name = NULL;
+               if (device == NULL) {
+                       /*
+                        * Use the first interface found.
+                        * Warn if there are more than one.
+                        */
+                       setsin(from, hi->addrs[0]);
+                       if (hi->n > 1)
+                               warnx("%s has multiple addresses; using %s",
+                                   source, inet_ntoa(from->sin_addr));
+               } else {
+                       /*
+                        * Make sure the source specified matches the
+                        * interface address.
+                        */
+                       for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
+                               if (*ap == al2->addr)
+                                       break;
+                       if (i <= 0)
+                               errx(1, "%s is not on interface %s",
+                                   source, device);
+                       setsin(from, *ap);
+               }
+               freehostinfo(hi);
+       }
+
+       /* Revert to non-privileged user after opening sockets */
+       setgid(getgid());
+       setuid(getuid());
+
+       /* 
+        * If not root, make sure source address matches a local interface.
+        * (The list of addresses produced by ifaddrlist() automatically
+        * excludes interfaces that are marked down and/or loopback.)
+        */
+       if (getuid())  {
+               al2 = al;
+               for (i = n; i > 0; --i, ++al2)
+                       if (from->sin_addr.s_addr == al2->addr)
+                           break;
+               if (i <= 0)
+                       errx(1, "%s is not a valid local address "
+                           "and you are not superuser.",
+                           inet_ntoa(from->sin_addr));
+       }
+
+       outip->ip_src = from->sin_addr;
+#ifndef IP_HDRINCL
+       if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0)
+               err(1, "bind");
+#endif
+
+       if (as_path) {
+               asn = as_setup(as_server);
+               if (asn == NULL) {
+                       warnx("as_setup failed, AS# lookups disabled");
+                       (void)fflush(stderr);
+                       as_path = 0;
+               }
+       }
+
+       setuid(getuid());
+       Fprintf(stderr, "%s to %s (%s)",
+           prog, hostname, inet_ntoa(to->sin_addr));
+       if (source)
+               Fprintf(stderr, " from %s", source);
+       Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
+       (void)fflush(stderr);
+
+       for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
+               u_int32_t lastaddr = 0;
+               int gotlastaddr = 0;
+               int got_there = 0;
+               int unreachable = 0;
+               int sentfirst = 0;
+
+again:
+               printed_ttl = 0;
+               for (probe = 0; probe < nprobes; ++probe) {
+                       int cc;
+                       struct timeval t1, t2;
+                       struct ip *ip;
+                       if (sentfirst && pausemsecs > 0)
+                               usleep(pausemsecs * 1000);
+                       (void)gettimeofday(&t1, NULL);
+                       if (!useicmp && htons(port + seq + 1) == 0)
+                               seq++;
+                       send_probe(++seq, ttl, &t1);
+                       ++sentfirst;
+                       while ((cc = wait_for_reply(s, from, &t1)) != 0) {
+                               (void)gettimeofday(&t2, NULL);
+                               /*
+                                * Since we'll be receiving all ICMP
+                                * messages to this host above, we may
+                                * never end up with cc=0, so we need
+                                * an additional termination check.
+                                */
+                               if (t2.tv_sec - t1.tv_sec > waittime) {
+                                       cc = 0;
+                                       break;
+                               }
+                               i = packet_ok(packet, cc, from, seq);
+                               /* Skip short packet */
+                               if (i == 0)
+                                       continue;
+                               if (!gotlastaddr ||
+                                   from->sin_addr.s_addr != lastaddr) {
+                                       if (gotlastaddr) printf("\n   ");
+                                       print(packet, cc, from);
+                                       lastaddr = from->sin_addr.s_addr;
+                                       ++gotlastaddr;
+                               }
+                               ip = (struct ip *)packet;
+                               Printf("  %.3f ms", deltaT(&t1, &t2));
+                               if (ttl_flag)
+                                       Printf(" (ttl = %d)", ip->ip_ttl);
+                               if (i == -2) {
+#ifndef ARCHAIC
+                                       if (ip->ip_ttl <= 1)
+                                               Printf(" !");
+#endif
+                                       ++got_there;
+                                       break;
+                               }
+
+                               /* time exceeded in transit */
+                               if (i == -1)
+                                       break;
+                               code = i - 1;
+                               switch (code) {
+
+                               case ICMP_UNREACH_PORT:
+#ifndef ARCHAIC
+                                       if (ip->ip_ttl <= 1)
+                                               Printf(" !");
+#endif
+                                       ++got_there;
+                                       break;
+
+                               case ICMP_UNREACH_NET:
+                                       ++unreachable;
+                                       Printf(" !N");
+                                       break;
+
+                               case ICMP_UNREACH_HOST:
+                                       ++unreachable;
+                                       Printf(" !H");
+                                       break;
+
+                               case ICMP_UNREACH_PROTOCOL:
+                                       ++got_there;
+                                       Printf(" !P");
+                                       break;
+
+                               case ICMP_UNREACH_NEEDFRAG:
+                                       if (mtudisc) {
+                                               frag_err();
+                                               goto again;
+                                       } else {
+                                               ++unreachable;
+                                               Printf(" !F-%d", pmtu);
+                                       }
+                                       break;
+
+                               case ICMP_UNREACH_SRCFAIL:
+                                       ++unreachable;
+                                       Printf(" !S");
+                                       break;
+
+                               case ICMP_UNREACH_FILTER_PROHIB:
+                                       ++unreachable;
+                                       Printf(" !X");
+                                       break;
+
+                               case ICMP_UNREACH_HOST_PRECEDENCE:
+                                       ++unreachable;
+                                       Printf(" !V");
+                                       break;
+
+                               case ICMP_UNREACH_PRECEDENCE_CUTOFF:
+                                       ++unreachable;
+                                       Printf(" !C");
+                                       break;
+
+                               default:
+                                       ++unreachable;
+                                       Printf(" !<%d>", code);
+                                       break;
+                               }
+                               break;
+                       }
+                       if (cc == 0)
+                               Printf(" *");
+                       else if (cc && probe == nprobes - 1 && Mflag)
+                               decode_extensions(packet, cc);
+                       (void)fflush(stdout);
+               }
+               putchar('\n');
+               if (got_there ||
+                   (unreachable > 0 && unreachable >= ((nprobes + 1) / 2)))
+                       break;
+       }
+
+       if (as_path)
+               as_shutdown(asn);
+
+       exit(0);
+}
+
+static ssize_t
+wait_for_reply(int sock, struct sockaddr_in *fromp, const struct timeval *tp)
+{
+       struct pollfd set[1];
+       struct timeval now, wait;
+       ssize_t cc = 0;
+       socklen_t fromlen = sizeof(*fromp);
+       int retval;
+
+       set[0].fd = sock;
+       set[0].events = POLLIN;
+
+       wait.tv_sec = tp->tv_sec + waittime;
+       wait.tv_usec = tp->tv_usec;
+       (void)gettimeofday(&now, NULL);
+       tvsub(&wait, &now);
+
+       if (wait.tv_sec < 0) {
+               wait.tv_sec = 0;
+               wait.tv_usec = 0;
+       }
+
+       retval = prog_poll(set, 1, wait.tv_sec * 1000 + wait.tv_usec / 1000);
+       if (retval < 0) 
+               /* If we continue, we probably just flood the remote host. */
+               err(1, "poll");
+       if (retval > 0)  {
+               cc = prog_recvfrom(sock, (char *)packet, sizeof(packet), 0,
+                           (struct sockaddr *)fromp, &fromlen);
+       }
+
+       return cc;
+}
+
+static void
+decode_extensions(unsigned char *buf, int ip_len)
+{
+        struct icmp_ext_cmn_hdr *cmn_hdr;
+        struct icmp_ext_obj_hdr *obj_hdr;
+        union {
+                struct mpls_header mpls;
+                uint32_t mpls_h;
+        } mpls;
+        size_t datalen, obj_len;
+        struct ip *ip;
+
+        ip = (struct ip *)buf;
+
+        if (ip_len < (int)((ip->ip_hl << 2) + ICMP_EXT_OFFSET +
+           sizeof(struct icmp_ext_cmn_hdr))) {
+               /*
+                * No support for ICMP extensions on this host
+                */
+               return;
+        }
+
+        /*
+         * Move forward to the start of the ICMP extensions, if present
+         */
+        buf += (ip->ip_hl << 2) + ICMP_EXT_OFFSET;
+        cmn_hdr = (struct icmp_ext_cmn_hdr *)buf;
+
+        if (cmn_hdr->version != ICMP_EXT_VERSION) {
+               /*
+                * Unknown version
+                */
+               return;
+        }
+
+        datalen = ip_len - ((u_char *)cmn_hdr - (u_char *)ip);
+
+        /*
+         * Check the checksum, cmn_hdr->checksum == 0 means no checksum'ing
+         * done by sender.
+         *
+        * If the checksum is ok, we'll get 0, as the checksum is calculated
+         * with the checksum field being 0'd.
+         */
+        if (ntohs(cmn_hdr->checksum) &&
+            in_cksum((u_short *)cmn_hdr, datalen)) {
+            return;
+        }
+        buf += sizeof(*cmn_hdr);
+        datalen -= sizeof(*cmn_hdr);
+        while (datalen >= sizeof(struct icmp_ext_obj_hdr)) {
+               obj_hdr = (struct icmp_ext_obj_hdr *)buf;
+               obj_len = ntohs(obj_hdr->length);
+
+               /*
+                * Sanity check the length field
+                */
+               if (obj_len > datalen)
+                       return;
+
+               datalen -= obj_len;
+               /*
+                * Move past the object header
+                */
+               buf += sizeof(struct icmp_ext_obj_hdr);
+               obj_len -= sizeof(struct icmp_ext_obj_hdr);
+               switch (obj_hdr->class_num) {
+               case MPLS_STACK_ENTRY_CLASS:
+                       switch (obj_hdr->c_type) {
+                       case MPLS_STACK_ENTRY_C_TYPE:
+                               while (obj_len >= sizeof(uint32_t)) {
+                                       mpls.mpls_h = ntohl(*(uint32_t *)buf);
+                                       buf += sizeof(uint32_t);
+                                       obj_len -= sizeof(uint32_t);
+                                       printf(" [MPLS: Label %d Exp %d]",
+                                           mpls.mpls.label, mpls.mpls.exp);
+                               }
+                               if (obj_len > 0) {
+                                       /*
+                                        * Something went wrong, and we're at
+                                        * a unknown offset into the packet,
+                                        * ditch the rest of it.
+                                        */
+                                       return;
+                               }
+                               break;
+                       default:
+                               /*
+                                * Unknown object, skip past it
+                                */
+                               buf += ntohs(obj_hdr->length) -
+                                   sizeof(struct icmp_ext_obj_hdr);
+                               break;
+                       }
+                       break;
+               default:
+                       /*
+                        * Unknown object, skip past it
+                        */
+                       buf += ntohs(obj_hdr->length) -
+                           sizeof(struct icmp_ext_obj_hdr);
+                       break;
+               }
+       }
+}
+
+static void
+dump_packet(void)
+{
+       u_char *p;
+       int i;
+
+       Fprintf(stderr, "packet data:");
+
+#ifdef __hpux
+       for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i < 
+           i < packlen - (sizeof(*outip) + optlen); i++)
+#else
+       for (p = (u_char *)outip, i = 0; i < packlen; i++)
+#endif
+       {
+               if ((i % 24) == 0)
+                       Fprintf(stderr, "\n ");
+               Fprintf(stderr, " %02x", *p++);
+       }
+       Fprintf(stderr, "\n");
+}
+
+void
+send_probe(int seq, int ttl, struct timeval *tp)
+{
+       int cc;
+       struct udpiphdr * ui, *oui;
+       int oldmtu = packlen;
+       struct ip tip;
+
+again:
+#ifdef BYTESWAP_IP_LEN
+       outip->ip_len = htons(packlen);
+#else
+       outip->ip_len = packlen;
+#endif
+       outip->ip_ttl = ttl;
+#ifndef __hpux
+       outip->ip_id = htons(ident + seq);
+#endif
+
+       /*
+        * In most cases, the kernel will recalculate the ip checksum.
+        * But we must do it anyway so that the udp checksum comes out
+        * right.
+        */
+       if (doipcksum) {
+               outip->ip_sum =
+                   in_cksum((u_int16_t *)outip, sizeof(*outip) + optlen);
+               if (outip->ip_sum == 0)
+                       outip->ip_sum = 0xffff;
+       }
+
+       /* Payload */
+       outsetup.seq = seq;
+       outsetup.ttl = ttl;
+       outsetup.tv.tv32_sec = htonl(tp->tv_sec);
+       outsetup.tv.tv32_usec = htonl(tp->tv_usec);
+       memcpy(outmark,&outsetup,sizeof(outsetup));
+
+       if (useicmp)
+               outicmp->icmp_seq = htons(seq);
+       else
+               outudp->uh_dport = htons(port + seq);
+
+       if (useicmp) {
+               /* Always calculate checksum for icmp packets */
+               outicmp->icmp_cksum = 0;
+               outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
+                   packlen - (sizeof(*outip) + optlen));
+               if (outicmp->icmp_cksum == 0)
+                       outicmp->icmp_cksum = 0xffff;
+       } else if (doipcksum) {
+               /* Checksum (we must save and restore ip header) */
+               tip = *outip;
+               ui = (struct udpiphdr *)outip;
+               oui = (struct udpiphdr *)&tip;
+               /* Easier to zero and put back things that are ok */
+               memset(ui, 0, sizeof(ui->ui_i));
+               ui->ui_src = oui->ui_src;
+               ui->ui_dst = oui->ui_dst;
+               ui->ui_pr = oui->ui_pr;
+               ui->ui_len = outudp->uh_ulen;
+               outudp->uh_sum = 0;
+               outudp->uh_sum = in_cksum((u_short *)ui, packlen);
+               if (outudp->uh_sum == 0)
+                       outudp->uh_sum = 0xffff;
+               *outip = tip;
+       }
+
+       /* XXX undocumented debugging hack */
+       if (verbose > 1) {
+               const u_int16_t *sp;
+               int nshorts, i;
+
+               sp = (u_int16_t *)outip;
+               nshorts = (u_int)packlen / sizeof(u_int16_t);
+               i = 0;
+               Printf("[ %d bytes", packlen);
+               while (--nshorts >= 0) {
+                       if ((i++ % 8) == 0)
+                               Printf("\n\t");
+                       Printf(" %04x", ntohs(*sp++));
+               }
+               if (packlen & 1) {
+                       if ((i % 8) == 0)
+                               Printf("\n\t");
+                       Printf(" %02x", *(const u_char *)sp);
+               }
+               Printf("]\n");
+       }
+
+#ifndef __minix
+#if !defined(IP_HDRINCL) && defined(IP_TTL)
+       if (prog_setsockopt(sndsock, IPPROTO_IP, IP_TTL,
+           (char *)&ttl, sizeof(ttl)) < 0)
+               err(1, "setsockopt ttl %d", ttl);
+#endif
+#else
+       {
+               nwio_ipopt_t ipopts; 
+               memset(&ipopts, 0, sizeof(ipopts));
+               ipopts.nwio_flags = NWIO_HDR_O_SPEC;
+               ipopts.nwio_ttl = ttl;
+               if(ioctl(sndsock, NWIOSIPOPT, &ipopts) < 0) {
+                       err(1, "ttl ioctl");
+               }
+       }
+#endif
+       if (dump)
+               dump_packet();
+
+#ifdef __hpux
+       cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
+           packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
+       if (cc > 0)
+               cc += sizeof(*outip) + optlen;
+#else
+       cc = prog_sendto(sndsock, (char *)outip,
+           packlen, 0, &whereto, sizeof(whereto));
+#endif
+       if (cc < 0 || cc != packlen)  {
+               if (cc < 0) {
+                       /*
+                        * An errno of EMSGSIZE means we're writing too big a
+                        * datagram for the interface.  We have to just
+                        * decrease the packet size until we find one that
+                        * works.
+                        *
+                        * XXX maybe we should try to read the outgoing if's 
+                        * mtu?
+                        */
+                       if (errno == EMSGSIZE) {
+                               packlen = *mtuptr++;
+                               resize_packet();
+                               goto again;
+                       } else
+                               warn("sendto..");
+               }
+               
+               Printf("%s: wrote %s %d chars, ret=%d\n",
+                   prog, hostname, packlen, cc);
+               (void)fflush(stdout);
+       }
+       if (oldmtu != packlen) {
+               Printf("message too big, "
+                   "trying new MTU = %d\n", packlen);
+               printed_ttl = 0;
+       }
+       if (!printed_ttl) {
+               Printf("%2d ", ttl);
+               printed_ttl = 1;
+       }
+       
+}
+
+static double
+deltaT(struct timeval *t1p, struct timeval *t2p)
+{
+       double dt;
+
+       dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+            (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+       return dt;
+}
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+static const char *
+pr_type(u_char t)
+{
+       static const char *ttab[] = {
+       "Echo Reply",   "ICMP 1",       "ICMP 2",       "Dest Unreachable",
+       "Source Quench", "Redirect",    "ICMP 6",       "ICMP 7",
+       "Echo",         "ICMP 9",       "ICMP 10",      "Time Exceeded",
+       "Param Problem", "Timestamp",   "Timestamp Reply", "Info Request",
+       "Info Reply"
+       };
+
+       if (t > 16)
+               return "OUT-OF-RANGE";
+
+       return ttab[t];
+}
+
+static int
+packet_ok(u_char *buf, ssize_t cc, struct sockaddr_in *from, int seq)
+{
+       struct icmp *icp;
+       u_char type, code;
+       int hlen;
+#ifndef ARCHAIC
+       struct ip *ip;
+
+       ip = (struct ip *) buf;
+       hlen = ip->ip_hl << 2;
+       if (cc < hlen + ICMP_MINLEN) {
+               if (verbose)
+                       Printf("packet too short (%zd bytes) from %s\n", cc,
+                               inet_ntoa(from->sin_addr));
+               return 0;
+       }
+       cc -= hlen;
+       icp = (struct icmp *)(buf + hlen);
+#else
+       icp = (struct icmp *)buf;
+#endif
+       type = icp->icmp_type;
+       code = icp->icmp_code;
+       /* Path MTU Discovery (RFC1191) */
+       if (code != ICMP_UNREACH_NEEDFRAG)
+               pmtu = 0;
+       else {
+#ifdef HAVE_ICMP_NEXTMTU
+               pmtu = ntohs(icp->icmp_nextmtu);
+#else
+               pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
+#endif
+       }
+       if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
+           type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
+               struct ip *hip;
+               struct udphdr *up;
+               struct icmp *hicmp;
+
+               hip = &icp->icmp_ip;
+               hlen = hip->ip_hl << 2;
+
+               nextmtu = ntohs(icp->icmp_nextmtu);     /* for frag_err() */
+                       
+               if (useicmp) {
+                       /* XXX */
+                       if (type == ICMP_ECHOREPLY &&
+                           icp->icmp_id == htons(ident) &&
+                           icp->icmp_seq == htons(seq))
+                               return -2;
+
+                       hicmp = (struct icmp *)((u_char *)hip + hlen);
+                       /* XXX 8 is a magic number */
+                       if (hlen + 8 <= cc &&
+                           hip->ip_p == IPPROTO_ICMP &&
+                           hicmp->icmp_id == htons(ident) &&
+                           hicmp->icmp_seq == htons(seq))
+                               return type == ICMP_TIMXCEED ? -1 : code + 1;
+               } else {
+                       up = (struct udphdr *)((u_char *)hip + hlen);
+                       /* XXX 8 is a magic number */
+                       if (hlen + 12 <= cc &&
+                           hip->ip_p == IPPROTO_UDP &&
+                           up->uh_sport == htons(ident) &&
+                           up->uh_dport == htons(port + seq))
+                               return type == ICMP_TIMXCEED ? -1 : code + 1;
+               }
+       }
+#ifndef ARCHAIC
+       if (verbose) {
+               int i;
+               u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
+
+               Printf("\n%zd bytes from %s to ", cc, inet_ntoa(from->sin_addr));
+               Printf("%s: icmp type %d (%s) code %d\n",
+                   inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
+               for (i = 4; i < cc ; i += sizeof(*lp))
+                       Printf("%2d: x%8.8x\n", i, *lp++);
+       }
+#endif
+       return(0);
+}
+
+static void
+resize_packet(void)
+{
+       if (useicmp) {
+               outicmp->icmp_cksum = 0;
+               outicmp->icmp_cksum = in_cksum((u_int16_t *)outicmp,
+                   packlen - (sizeof(*outip) + optlen));
+               if (outicmp->icmp_cksum == 0)
+                       outicmp->icmp_cksum = 0xffff;
+       } else {
+               outudp->uh_ulen =
+                   htons((u_int16_t)(packlen - (sizeof(*outip) + optlen)));
+       }
+}
+
+static void
+print(u_char *buf, int cc, struct sockaddr_in *from)
+{
+       struct ip *ip;
+       int hlen;
+       char addr[INET_ADDRSTRLEN];
+
+       ip = (struct ip *) buf;
+       hlen = ip->ip_hl << 2;
+       cc -= hlen;
+
+       strlcpy(addr, inet_ntoa(from->sin_addr), sizeof(addr));
+
+       if (as_path)
+               Printf(" [AS%u]", as_lookup(asn, addr, AF_INET));
+
+       if (nflag)
+               Printf(" %s", addr);
+       else
+               Printf(" %s (%s)", inetname(from->sin_addr), addr);
+
+       if (verbose)
+               Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+}
+
+static u_int16_t
+in_cksum(u_int16_t *addr, int len)
+{
+
+       return ~in_cksum2(0, addr, len);
+}
+
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+static u_int16_t
+in_cksum2(u_int16_t seed, u_int16_t *addr, int len)
+{
+       int nleft = len;
+       u_int16_t *w = addr;
+       union {
+               u_int16_t w;
+               u_int8_t b[2];
+       } answer;
+       int32_t sum = seed;
+
+       /*
+        *  Our algorithm is simple, using a 32 bit accumulator (sum),
+        *  we add sequential 16 bit words to it, and at the end, fold
+        *  back all the carry bits from the top 16 bits into the lower
+        *  16 bits.
+        */
+       while (nleft > 1)  {
+               sum += *w++;
+               nleft -= 2;
+       }
+
+       /* mop up an odd byte, if necessary */
+       if (nleft == 1) {
+               answer.b[0] = *(u_char *)w;
+               answer.b[1] = 0;
+               sum += answer.w;
+       }
+
+       /*
+        * add back carry outs from top 16 bits to low 16 bits
+        */
+       sum = (sum >> 16) + (sum & 0xffff);     /* add hi 16 to low 16 */
+       sum += (sum >> 16);                     /* add carry */
+       answer.w = sum;                         /* truncate to 16 bits */
+       return answer.w;
+}
+
+/*
+ * Subtract 2 timeval structs:  out = out - in.
+ * Out is assumed to be >= in.
+ */
+static void
+tvsub(struct timeval *out, struct timeval *in)
+{
+
+       if ((out->tv_usec -= in->tv_usec) < 0)   {
+               --out->tv_sec;
+               out->tv_usec += 1000000;
+       }
+       out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+static char *
+inetname(struct in_addr in)
+{
+       char *cp;
+       struct hostent *hp;
+       static int first = 1;
+       static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
+
+       if (first && !nflag) {
+
+               first = 0;
+               if (gethostname(domain, sizeof(domain) - 1) < 0)
+                       domain[0] = '\0';
+               else {
+                       cp = strchr(domain, '.');
+                       if (cp == NULL) {
+                               hp = gethostbyname(domain);
+                               if (hp != NULL)
+                                       cp = strchr(hp->h_name, '.');
+                       }
+                       if (cp == NULL)
+                               domain[0] = '\0';
+                       else {
+                               ++cp;
+                               (void)strlcpy(domain, cp, sizeof(domain));
+                       }
+               }
+       }
+       if (!nflag && in.s_addr != INADDR_ANY) {
+               hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
+               if (hp != NULL) {
+                       if ((cp = strchr(hp->h_name, '.')) != NULL &&
+                           strcmp(cp + 1, domain) == 0)
+                               *cp = '\0';
+                       (void)strlcpy(line, hp->h_name, sizeof(line));
+                       return line;
+               }
+       }
+       return inet_ntoa(in);
+}
+
+static struct hostinfo *
+gethostinfo(char *hname)
+{
+       int n;
+       struct hostent *hp;
+       struct hostinfo *hi;
+       char **p;
+       u_int32_t *ap;
+       struct in_addr addr;
+
+       hi = calloc(1, sizeof(*hi));
+       if (hi == NULL)
+               err(1, "calloc");
+       if (inet_aton(hname, &addr) != 0) {
+               hi->name = strdup(hname);
+               if (!hi->name)
+                       err(1, "strdup");
+               hi->n = 1;
+               hi->addrs = calloc(1, sizeof(hi->addrs[0]));
+               if (hi->addrs == NULL)
+                       err(1, "calloc");
+               hi->addrs[0] = addr.s_addr;
+               return hi;
+       }
+
+       hp = gethostbyname(hname);
+       if (hp == NULL)
+               errx(1, "unknown host %s", hname);
+       if (hp->h_addrtype != AF_INET || hp->h_length != 4)
+               errx(1, "bad host %s", hname);
+       hi->name = strdup(hp->h_name);
+       if (!hi->name)
+               err(1, "strdup");
+       for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
+               continue;
+       hi->n = n;
+       hi->addrs = calloc(n, sizeof(hi->addrs[0]));
+       if (hi->addrs == NULL)
+               err(1, "calloc");
+       for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
+               memcpy(ap, *p, sizeof(*ap));
+       return hi;
+}
+
+static void
+freehostinfo(struct hostinfo *hi)
+{
+       if (hi->name != NULL) {
+               free(hi->name);
+               hi->name = NULL;
+       }
+       free(hi->addrs);
+       free(hi);
+}
+
+static void
+getaddr(u_int32_t *ap, char *hname)
+{
+       struct hostinfo *hi;
+
+       hi = gethostinfo(hname);
+       *ap = hi->addrs[0];
+       freehostinfo(hi);
+}
+
+static void
+setsin(struct sockaddr_in *sin, u_int32_t addr)
+{
+
+       memset(sin, 0, sizeof(*sin));
+#ifdef HAVE_SOCKADDR_SA_LEN
+       sin->sin_len = sizeof(*sin);
+#endif
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = addr;
+}
+
+/* String to value with optional min and max. Handles decimal and hex. */
+static int
+str2val(const char *str, const char *what, int mi, int ma)
+{
+       const char *cp;
+       long val;
+       char *ep;
+
+       errno = 0;
+       ep = NULL;
+       if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+               cp = str + 2;
+               val = strtol(cp, &ep, 16);
+       } else
+               val = strtol(str, &ep, 10);
+       if (errno || str[0] == '\0' || *ep != '\0')
+               errx(1, "\"%s\" bad value for %s", str, what);
+       if (val < mi && mi >= 0) {
+               if (mi == 0)
+                       errx(1, "%s must be >= %d", what, mi);
+               else
+                       errx(1, "%s must be > %d", what, mi - 1);
+       }
+       if (val > ma && ma >= 0)
+               errx(1, "%s must be <= %d", what, ma);
+       return (int)val;
+}
+
+__dead void
+usage(void)
+{
+       extern char version[];
+
+       Fprintf(stderr, "Version %s\n", version);
+       Fprintf(stderr, "Usage: %s [-adDFPIlMnrvx] [-g gateway] [-i iface] \
+[-f first_ttl]\n\t[-m max_ttl] [-p port] [-q nqueries] [-s src_addr] [-t tos]\n\t\
+[-w waittime] [-z pausemsecs] [-A as_server] host [packetlen]\n",
+           getprogname());
+       exit(1);
+}
+
+/*
+ * Received ICMP unreachable (fragmentation required and DF set).
+ * If the ICMP error was from a "new" router, it'll contain the next-hop
+ * MTU that we should use next.  Otherwise we'll just keep going in the
+ * mtus[] table, trying until we hit a valid MTU.
+ */
+
+
+void
+frag_err()
+{
+        int i;
+
+        if (nextmtu > 0 && nextmtu < packlen) {
+                Printf("\nfragmentation required and DF set, "
+                    "next hop MTU = %d\n",
+                        nextmtu);
+                packlen = nextmtu;
+                for (i = 0; mtus[i] > 0; i++) {
+                        if (mtus[i] < nextmtu) {
+                                mtuptr = &mtus[i];    /* next one to try */
+                                break;
+                        }
+                }
+        } else {
+                Printf("\nfragmentation required and DF set. ");
+               if (nextmtu)
+                       Printf("\nBogus next hop MTU = %d > last MTU = %d. ",
+                           nextmtu, packlen);
+                packlen = *mtuptr++;
+               Printf("Trying new MTU = %d\n", packlen);
+        }
+       resize_packet();
+}
+
+int
+find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
+{
+       int sock;
+       struct sockaddr_in help;
+       socklen_t help_len;
+
+       sock = prog_socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock < 0) return 0;
+
+       help.sin_family = AF_INET;
+       /*
+        * At this point the port number doesn't matter
+        * since it only has to be greater than zero.
+        */
+       help.sin_port = 42;
+       help.sin_addr.s_addr = to->sin_addr.s_addr;
+       if (prog_connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
+               (void)prog_close(sock);
+               return 0;
+       }
+
+       help_len = sizeof(help);
+       if (prog_getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
+           help_len != sizeof(help) ||
+           help.sin_addr.s_addr == INADDR_ANY) {
+               (void)prog_close(sock);
+               return 0;
+       }
+
+       (void)prog_close(sock);
+       setsin(from, help.sin_addr.s_addr);
+       return 1;
+}
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+static int
+setpolicy(int so, const char *policy)
+{
+       char *buf;
+
+       buf = ipsec_set_policy(policy, strlen(policy));
+       if (buf == NULL) {
+               warnx("%s", ipsec_strerror());
+               return -1;
+       }
+       (void)prog_setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
+               buf, ipsec_get_policylen(buf));
+
+       free(buf);
+
+       return 0;
+}
+#endif
+#endif
+
diff --git a/usr.sbin/traceroute/traceroute_hostops.c b/usr.sbin/traceroute/traceroute_hostops.c
new file mode 100644 (file)
index 0000000..98016b8
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $NetBSD: traceroute_hostops.c,v 1.1 2010/12/15 00:09:41 pooka Exp $     */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: traceroute_hostops.c,v 1.1 2010/12/15 00:09:41 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <poll.h>
+#include <unistd.h>
+
+#include "prog_ops.h"
+
+const struct prog_ops prog_ops = {
+       .op_socket = socket,
+       .op_setsockopt = setsockopt,
+       .op_shutdown = shutdown,
+       .op_poll = poll,
+       .op_recvfrom = recvfrom,
+       .op_sendto = sendto,
+       .op_close = close,
+       .op_connect = connect,
+       .op_getsockname = getsockname,
+       .op_sysctl = sysctl,
+};
diff --git a/usr.sbin/traceroute/traceroute_rumpops.c b/usr.sbin/traceroute/traceroute_rumpops.c
new file mode 100644 (file)
index 0000000..f90cd17
--- /dev/null
@@ -0,0 +1,59 @@
+/*     $NetBSD: traceroute_rumpops.c,v 1.1 2010/12/15 00:09:42 pooka Exp $     */
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: traceroute_rumpops.c,v 1.1 2010/12/15 00:09:42 pooka Exp $");
+#endif /* !lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <poll.h>
+#include <unistd.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/rumpclient.h>
+
+#include "prog_ops.h"
+
+const struct prog_ops prog_ops = {
+       .op_init =      rumpclient_init,
+
+       .op_socket =    rump_sys_socket,
+       .op_setsockopt= rump_sys_setsockopt,
+       .op_shutdown =  rump_sys_shutdown,
+       .op_poll =      rump_sys_poll,
+       .op_recvfrom =  rump_sys_recvfrom,
+       .op_sendto =    rump_sys_sendto,
+       .op_close =     rump_sys_close,
+       .op_connect =   rump_sys_connect,
+       .op_getsockname=rump_sys_getsockname,
+       .op_sysctl =    rump_sys___sysctl,
+};
diff --git a/usr.sbin/traceroute/trrt2netbsd b/usr.sbin/traceroute/trrt2netbsd
new file mode 100755 (executable)
index 0000000..bfe88f9
--- /dev/null
@@ -0,0 +1,272 @@
+#!/usr/local/bin/perl
+#
+#      $NetBSD: trrt2netbsd,v 1.4 1999/06/16 20:47:57 is Exp $
+#
+#  Perl script to convert a standard distribution directory for traceroute into
+#      a NetBSD source tree.
+#
+#  This is done as a script so that as each distribution is released,
+#      only changes from the previous one need to be dealt with as
+#      modifications to this script and related files.  This should
+#      reduce the cost of updating from a new release of traceroute by an
+#      order of magnitude (or more?)
+#
+#  This script requires two environment variables set:
+#      SRCDIR - traceroute source directory
+#      TARGETDIR - name of the high level directory to make
+#
+#  Written by Christos Zoulas Oct 2nd, 1997 for traceroute-1.4a5
+#
+
+$version = "1.4a5";
+
+# definitions ...
+
+@subdirs = ("usr.sbin/traceroute");
+
+@trrtf = ("ifaddrlist.c", "savestr.c", "traceroute.c");
+
+@trrthf = ("gnuc.h", "ifaddrlist.h", "savestr.h");
+
+@trrtmf = ("traceroute.8");
+@trrtdf = ("CHANGES", "README");
+@trrtaf = ("mean.awk", "median.awk");
+
+
+# sed edit list: file, sed-program
+%sedlist = ();
+
+#
+# Utility Subroutines
+#
+
+sub makedir {
+    system("mkdir -p @_");
+}
+
+# &fixrcs (fromfile, tofile);
+sub fixrcs
+{
+    my ($f, $t) = @_;
+    my @keywords = ("Author", "Date", "Header", "Id", "Locker", "Log",
+                   "Name", "RCSfile", "Revision", "Source", "State");
+    my $state = 0;
+    my $hdr = 0;
+
+    open(IFILE, "<$f") || die "Cannot open $f";
+    open(OFILE, ">$t") || die "Cannot create $t";
+
+    if ($t =~ /.*\.[0-9]/) {
+       print OFILE '.\\" $', 'NetBSD',  '$', "\n.\\\"", "\n";
+    }
+    elsif ($t =~ /.*\.[ch]/) {
+       print OFILE "/*\t", '$', 'NetBSD', '$', "\t*/\n\n";
+    }
+    elsif ($t =~ /.*\.[yl]/) {
+       $hdr = 1;
+    }
+    else {
+       print OFILE '$', 'NetBSD', '$', "\n";
+    }
+    while (<IFILE>) {
+       if ($hdr == 1) {
+           if (/%{/) {
+               print OFILE "%{\n/*\t", '$', 'NetBSD', '$', "\t*/\n\n";
+               $hdr = 0;
+               next;
+           }
+       }
+       if ($state == 2) {
+           if (/#endif/) {
+               print OFILE "#else\n__RCSID(", '"$', 'NetBSD', '$"',
+                   ");\n#endif\n";
+               $state = 0;
+           }
+       }
+       if ($state == 1) {
+           print OFILE "#if 0\n";
+           $state = 2;
+       }
+       if (/#ifndef lint/) {
+           print OFILE "#include <sys/cdefs.h>\n";
+           $state = 1;
+       }
+       foreach $key (@keywords) {
+           s/\$$key\$/$key/g;
+           s/\$$key:(.*)\$/$key:$1/g;
+       }
+       print OFILE $_;
+    }
+    close(IFILE) || die "closing input file";
+    close(OFILE) || die "closing output file";
+}
+
+# &copyfiles (fromdir, todir, list of files);
+sub copyfiles {
+    local ($fdir, $tdir, @list) = @_;
+    local ($f);
+
+    foreach $f (@list) {
+       print "  $fdir/$f --> $tdir/$f\n";
+       &fixrcs("$fdir/$f", "$tdir/$f");
+    }
+}
+
+# &copyfile (fromfile, tofile);
+sub copyfile {
+    local ($f, $t) = @_;
+
+    print "  $f --> $t\n";
+    system ("cp $f $t");
+}
+
+sub uniq {
+    local (@inlist) = @_;
+    local (@outlist);
+
+    @outlist = ($inlist[0]);
+    for ( $i=1; $i < @inlist; $i++ ) {
+       if ($inlist[$i] ne $inlist[$i-1]) {
+           push (@outlist, $inlist[$i]);
+       }
+    }
+
+    @outlist;
+}
+
+sub dumpsrcs {
+    local (@names) = @_;
+    local ($count);
+
+    $count = 0;
+    while ($f = pop(@names)) {
+        print ODATA "$f ";
+       if ($count == 5 && @names > 0) {
+           print ODATA "\\\n";
+           $count = 0;
+       } else {
+           $count += 1;
+       }
+    }
+    if ($count != 0) {
+       print ODATA "\n";
+    }
+}
+
+#
+# Main program.
+# 
+
+$srcdir = $ENV{'SRCDIR'};
+$targetdir = $ENV{'TARGETDIR'};
+$incdirs = "-I. -I$srcdir/config -I$srcdir";
+
+if (!$srcdir | !targetdir) {
+    die "You must define the environment variables SRCDIR and TARGETDIR.\n"
+} 
+print "Making the NetBSD directory tree.\n";
+foreach $f (@subdirs) { 
+    print "   -->$f\n";
+    makedir ("$targetdir/$f");
+}
+
+print "Populating the usr.sbin/traceroute directory.\n";
+&copyfiles ("$srcdir", "$targetdir/usr.sbin/traceroute", @trrtf, @trrthf, @trrtdf,
+           @trrtmf, @trrtaf);
+
+#
+# Build makefiles
+#
+
+$first = "True";
+while ($line = <DATA>) {
+    chop ($line);
+    if (substr($line,0,2) eq "%%") {
+       @cmd = split (/ /,$line);
+       if ($cmd[1] eq "file") {
+           print "Building $targetdir/$cmd[2]\n";
+           if ($first eq "") {
+               close (ODATA);
+           } else {
+               $first = "";
+           }
+           open (ODATA, ">$targetdir/$cmd[2]") ||
+               die "Could not create $targetdir/$cmd[2]";
+       } elsif ($cmd[1] eq "awks") {
+           print "  Defining AWKS\n";
+           if ($first) {
+               die "Data file must start with a %% file!";
+           }
+           print ODATA "AWKS=\t";
+           &dumpsrcs (@trrtaf);
+       } elsif ($cmd[1] eq "srcs") {
+           print "  Defining SRCS\n";
+           if ($first) {
+               die "Data file must start with a %% file!";
+           }
+           print ODATA "SRCS=\t";
+           &dumpsrcs (@trrtf);
+       } elsif ($cmd[1] eq "man") {
+           print "  Defining MAN\n";
+           if ($first) {
+               die "Data file must start with a %% file!";
+           }
+           print ODATA "MAN=\t";
+           &dumpsrcs (@trrtmf);
+       } elsif ($cmd[1] eq "version") {
+           print "  Defining VERSION\n";
+           print ODATA "char version[] = \"$version\";";
+       } elsif ($cmd[1] eq "NetBSD") {
+           if ($first) {
+               die "Data section must start with a %% file!";
+           }
+           print ODATA "$cmd[2]        \$"."NetBSD".": \$      $cmd[3]\n";
+       }
+    } else {
+       if ($first) {
+           die "Data file must start with a %% file!";
+       }
+       print ODATA "$line\n";
+    }
+}    
+close (ODATA);
+
+#
+# Sed transformations of files
+#
+foreach $n (keys(%sedlist)) {
+    print "Modifying $n\n";
+    system ("cd $targetdir; sed $sedlist{$n} $n > tmp;  mv -f tmp $n");
+}
+
+#
+# end of the script
+#
+
+# what follows is the data for makefiles and other special files
+# that need to be created.
+
+__END__
+%% file usr.sbin/traceroute/Makefile
+%% NetBSD #
+
+WARNS?=        1
+PROG=  traceroute
+%% man
+
+CPPFLAGS+=-DHAVE_MALLOC_H=1 -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SOCKIO_H=1
+CPPFLAGS+=-DHAVE_STRERROR=1 -DHAVE_SETLINEBUF=1 -DHAVE_SOCKADDR_SA_LEN=1 
+CPPFLAGS+=-DHAVE_RAW_OPTIONS=1
+
+BINOWN= root
+BINMODE=4555
+
+%% srcs
+SRCS+= version.c
+
+%% awks 
+
+.include <bsd.prog.mk>
+%% file usr.sbin/traceroute/version.c
+%% NetBSD /* */
+%% version
diff --git a/usr.sbin/traceroute/version.c b/usr.sbin/traceroute/version.c
new file mode 100644 (file)
index 0000000..8f987c1
--- /dev/null
@@ -0,0 +1,2 @@
+/*     $NetBSD: version.c,v 1.3 2011/09/11 01:06:26 christos Exp $     */
+char version[] = "1.4a12";