./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
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 \
+++ /dev/null
-PROG= ping
-BINMODE= 4755
-MAN=
-
-.include <bsd.prog.mk>
+++ /dev/null
-/*
-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;
-{
-}
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__ */
#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,
}
}
+ {
+ 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
#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>
}
}
+ {
+ 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
#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>
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)
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);
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;
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 \
+++ /dev/null
-.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>
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");
chown \
fsck init \
mknod nologin \
+ ping \
reboot \
shutdown \
-
# support for various file systems
SUBDIR+= newfs_ext2fs fsck_ext2fs
--- /dev/null
+# $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>
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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,
+};
--- /dev/null
+/* $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,
+};
--- /dev/null
+/* $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_ */
INCS= ethertypes.h \
if_ether.h \
+ radix.h \
+ route.h \
\
\
\
in_systm.h \
\
ip.h \
+ ip_icmp.h \
+ ip_var.h \
tcp.h \
- \
+ udp.h udp_var.h \
.if !defined(__MINIX)
--- /dev/null
+/* $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_ */
\
rdate \
\
- \
+ traceroute \
\
\
unlink user \
--- /dev/null
+$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.
--- /dev/null
+# $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>
--- /dev/null
+/* $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);
+}
--- /dev/null
+/* $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 *);
--- /dev/null
+/* $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
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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);
--- /dev/null
+#!/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
+}
--- /dev/null
+#!/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
+ }
+}
--- /dev/null
+/* $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_ */
--- /dev/null
+.\" $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.
--- /dev/null
+/* $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
+
--- /dev/null
+/* $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,
+};
--- /dev/null
+/* $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,
+};
--- /dev/null
+#!/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";
+}
+
+# ©files (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");
+ }
+}
+
+# ©file (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";
+©files ("$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
--- /dev/null
+/* $NetBSD: version.c,v 1.3 2011/09/11 01:06:26 christos Exp $ */
+char version[] = "1.4a12";