summaryrefslogtreecommitdiffstats
path: root/network_cmds/traceroute.tproj
diff options
context:
space:
mode:
Diffstat (limited to 'network_cmds/traceroute.tproj')
-rw-r--r--network_cmds/traceroute.tproj/README126
-rw-r--r--network_cmds/traceroute.tproj/as.c242
-rw-r--r--network_cmds/traceroute.tproj/as.h42
-rw-r--r--network_cmds/traceroute.tproj/findsaddr-socket.c246
-rw-r--r--network_cmds/traceroute.tproj/findsaddr.h23
-rw-r--r--network_cmds/traceroute.tproj/gnuc.h43
-rw-r--r--network_cmds/traceroute.tproj/ifaddrlist.c202
-rw-r--r--network_cmds/traceroute.tproj/ifaddrlist.h57
-rw-r--r--network_cmds/traceroute.tproj/mean.awk50
-rw-r--r--network_cmds/traceroute.tproj/median.awk67
-rw-r--r--network_cmds/traceroute.tproj/traceroute.8439
-rw-r--r--network_cmds/traceroute.tproj/traceroute.c1822
-rw-r--r--network_cmds/traceroute.tproj/traceroute.h26
-rw-r--r--network_cmds/traceroute.tproj/version.c1
14 files changed, 3386 insertions, 0 deletions
diff --git a/network_cmds/traceroute.tproj/README b/network_cmds/traceroute.tproj/README
new file mode 100644
index 0000000..6d33c6c
--- /dev/null
+++ b/network_cmds/traceroute.tproj/README
@@ -0,0 +1,126 @@
+Tue Dec 27 06:24:24 PST 1988
+
+Traceroute is a system administrators utility to trace the route
+ip packets from the current system take in getting to some
+destination system. See the comments at the front of the
+program for a description of its use.
+
+This program
+
+ a) can only be run by root (it uses raw ip sockets).
+
+ b) REQUIRES A KERNEL MOD to the raw ip output code to run.
+
+If you want to hack on your kernel, my modified version of the
+routine rip_output (in file /sys/netinet/raw_ip.c) is attached.
+This code may or may not resemble the code in your kernel.
+It may offer you a place to start but I make no promises.
+If you do hack your kernel, remember to test everything that uses
+raw ip sockets (e.g., ping and egpup/gated) & make sure they still
+work. I wish you the best of luck and you're on your own.
+
+If your system has the ttl bug mentioned in the source, you
+might want to fix it while you're in the kernel. (This bug
+appears in all releases of BSD up to but not including 4.3tahoe.
+If your version of netinet/ip_icmp.c is any earlier than 7.3
+(April, '87), it has the bug.) The fix is just to add the line
+ ip->ip_ttl = MAXTTL;
+after the line
+ ip->ip_src = t;
+(or anywhere before the call to icmp_send) in routine icmp_reflect.
+
+If you're running this on a pre-4.3bsd system (e.g., Sun 3.x,
+Ultrix) that strips ip headers from icmp messages, add -DARCHAIC
+to CFLAGS in the Makefile. Also note that rip_output contains
+a conditional for a 4.2/4.3 change in the location of a raw
+socket's protocol number. I've checked this under 4.3 & Sun OS
+3.5 but you should double-check your system to make sure the
+appropriate branch of the #if is taken (check the line that
+assigned to ip->ip_p in your system's original rip_output).
+
+A couple of awk programs to massage the traceroute output are
+included. "mean.awk" and "median.awk" compute the mean and median
+time to each hop, respectively. I've found that something like
+
+ traceroute -q 7 foo.somewhere >t
+ awk -f median.awk t | graph
+
+can give you a quick picture of the bad spots on a long
+path (median is usually a better noise filter than mean).
+
+Enjoy.
+
+ - Van Jacobson (van@helios.ee.lbl.gov)
+
+-------------------- rip_output from /sys/netinet/raw_ip.c
+rip_output(m, so)
+ register struct mbuf *m;
+ struct socket *so;
+{
+ register struct ip *ip;
+ int error;
+ struct rawcb *rp = sotorawcb(so);
+ struct sockaddr_in *sin;
+#if BSD>=43
+ short proto = rp->rcb_proto.sp_protocol;
+#else
+ short proto = so->so_proto->pr_protocol;
+#endif
+ /*
+ * if the protocol is IPPROTO_RAW, the user handed us a
+ * complete IP packet. Otherwise, allocate an mbuf for a
+ * header and fill it in as needed.
+ */
+ if (proto != IPPROTO_RAW) {
+ /*
+ * Calculate data length and get an mbuf
+ * for IP header.
+ */
+ int len = 0;
+ struct mbuf *m0;
+
+ for (m0 = m; m; m = m->m_next)
+ len += m->m_len;
+
+ m = m_get(M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ m = m0;
+ error = ENOBUFS;
+ goto bad;
+ }
+ m->m_off = MMAXOFF - sizeof(struct ip);
+ m->m_len = sizeof(struct ip);
+ m->m_next = m0;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = proto;
+ ip->ip_len = sizeof(struct ip) + len;
+ ip->ip_ttl = MAXTTL;
+ } else
+ ip = mtod(m, struct ip *);
+
+ if (rp->rcb_flags & RAW_LADDR) {
+ sin = (struct sockaddr_in *)&rp->rcb_laddr;
+ if (sin->sin_family != AF_INET) {
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+ ip->ip_src.s_addr = sin->sin_addr.s_addr;
+ } else
+ ip->ip_src.s_addr = 0;
+
+ ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr;
+
+#if BSD>=43
+ return (ip_output(m, rp->rcb_options, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#else
+ return (ip_output(m, (struct mbuf *)0, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#endif
+bad:
+ m_freem(m);
+ return (error);
+}
diff --git a/network_cmds/traceroute.tproj/as.c b/network_cmds/traceroute.tproj/as.c
new file mode 100644
index 0000000..eb96851
--- /dev/null
+++ b/network_cmds/traceroute.tproj/as.c
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/contrib/traceroute/as.c,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
+/* $NetBSD: as.c,v 1.1 2001/11/04 23:14:36 atatat 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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(server)
+ char *server;
+{
+ struct aslookup *asn;
+ struct hostent *he = NULL;
+ struct servent *se;
+ struct sockaddr_in in;
+ FILE *f;
+ int s;
+
+ if (server == NULL)
+ server = DEFAULT_AS_SERVER;
+
+ (void)memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ in.sin_len = sizeof(in);
+ if ((se = getservbyname("whois", "tcp")) == NULL) {
+ warnx("warning: whois/tcp service not found");
+ in.sin_port = ntohs(43);
+ } else
+ in.sin_port = se->s_port;
+
+ if (inet_aton(server, &in.sin_addr) == 0 &&
+ ((he = gethostbyname(server)) == NULL ||
+ he->h_addr == NULL)) {
+ warnx("%s: %s", server, hstrerror(h_errno));
+ return (NULL);
+ }
+
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+ warn("socket");
+ return (NULL);
+ }
+
+ do {
+ if (he != NULL) {
+ memcpy(&in.sin_addr, he->h_addr, he->h_length);
+ he->h_addr_list++;
+ }
+ if (connect(s, (struct sockaddr *)&in, sizeof(in)) == 0)
+ break;
+ if (he == NULL || he->h_addr == NULL) {
+ close(s);
+ s = -1;
+ break;
+ }
+ } while (1);
+
+ if (s == -1) {
+ 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
+ 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);
+}
+
+int
+as_lookup(_asn, addr)
+ void *_asn;
+ struct in_addr *addr;
+{
+ struct aslookup *asn = _asn;
+ char buf[1024];
+ int as, rc, dlen;
+
+ as = rc = dlen = 0;
+ (void)fprintf(asn->as_f, "!r%s/32,l\n", inet_ntoa(*addr));
+ (void)fflush(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !r%s/32,l\n",
+ inet_ntoa(*addr));
+ (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%d", &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(_asn)
+ void *_asn;
+{
+ struct aslookup *asn = _asn;
+
+ (void)fprintf(asn->as_f, "!q\n");
+ (void)fclose(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !q\n");
+ (void)fclose(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ free(asn);
+}
diff --git a/network_cmds/traceroute.tproj/as.h b/network_cmds/traceroute.tproj/as.h
new file mode 100644
index 0000000..a4c6f47
--- /dev/null
+++ b/network_cmds/traceroute.tproj/as.h
@@ -0,0 +1,42 @@
+/* $FreeBSD: src/contrib/traceroute/as.h,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
+/* $NetBSD: as.h,v 1.1 2001/11/04 23:14:36 atatat 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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 __P((char *));
+int as_lookup __P((void *, struct in_addr *));
+void as_shutdown __P((void *));
diff --git a/network_cmds/traceroute.tproj/findsaddr-socket.c b/network_cmds/traceroute.tproj/findsaddr-socket.c
new file mode 100644
index 0000000..01dcef1
--- /dev/null
+++ b/network_cmds/traceroute.tproj/findsaddr-socket.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 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.
+ *
+ * $FreeBSD: src/contrib/traceroute/findsaddr-socket.c,v 1.2 2002/07/30 04:49:13 fenner Exp $
+ */
+
+/* XXX Yes this is WAY too complicated */
+
+#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 */
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "findsaddr.h"
+
+#ifdef HAVE_SOCKADDR_SA_LEN
+#define SALEN(sa) ((sa)->sa_len)
+#else
+#define SALEN(sa) salen(sa)
+#endif
+
+#ifndef roundup
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
+#endif
+
+struct rtmsg {
+ struct rt_msghdr rtmsg;
+ u_char data[512];
+};
+
+static struct rtmsg rtmsg = {
+ { 0, RTM_VERSION, RTM_GET, 0,
+ RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC,
+ RTA_DST | RTA_IFA, 0, 0, 0, 0, 0, { 0 } },
+ { 0 }
+};
+
+#ifndef HAVE_SOCKADDR_SA_LEN
+static int salen(struct sockaddr *);
+#endif
+
+/*
+ * Return the source address for the given destination address
+ */
+const char *
+findsaddr(register const struct sockaddr_in *to,
+ register struct sockaddr_in *from)
+{
+ register struct rt_msghdr *rp;
+ register u_char *cp;
+
+ register struct sockaddr_in *sp, *ifa;
+ register struct sockaddr *sa;
+ register int s, size, cc, seq, i;
+ register pid_t pid;
+ static char errbuf[512];
+
+ s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
+ if (s < 0) {
+ snprintf(errbuf, sizeof(errbuf), "socket: %.128s", strerror(errno));
+ return (errbuf);
+ }
+
+ seq = 0;
+ pid = getpid();
+
+ rp = &rtmsg.rtmsg;
+ rp->rtm_seq = ++seq;
+ cp = (u_char *)(rp + 1);
+
+ sp = (struct sockaddr_in *)cp;
+ *sp = *to;
+ cp += roundup(SALEN((struct sockaddr *)sp), sizeof(u_int32_t));
+
+ size = cp - (u_char *)rp;
+ rp->rtm_msglen = size;
+
+ cc = write(s, (char *)rp, size);
+ if (cc < 0) {
+ snprintf(errbuf, sizeof(errbuf), "write: %.128s", strerror(errno));
+ close(s);
+ return (errbuf);
+ }
+ if (cc != size) {
+ snprintf(errbuf, sizeof(errbuf), "short write (%d != %d)", cc, size);
+ close(s);
+ return (errbuf);
+ }
+
+ size = sizeof(rtmsg);
+ do {
+ memset(rp, 0, size);
+ cc = read(s, (char *)rp, size);
+ if (cc < 0) {
+ snprintf(errbuf, sizeof(errbuf), "read: %.128s", strerror(errno));
+ close(s);
+ return (errbuf);
+ }
+
+ } while (rp->rtm_seq != seq || rp->rtm_pid != pid);
+ close(s);
+
+
+ if (rp->rtm_version != RTM_VERSION) {
+ snprintf(errbuf, sizeof(errbuf), "bad version %d", rp->rtm_version);
+ return (errbuf);
+ }
+ if (rp->rtm_msglen > cc) {
+ snprintf(errbuf, sizeof(errbuf), "bad msglen %d > %d", rp->rtm_msglen, cc);
+ return (errbuf);
+ }
+ if (rp->rtm_errno != 0) {
+ snprintf(errbuf, sizeof(errbuf), "rtm_errno: %.128s", strerror(rp->rtm_errno));
+ return (errbuf);
+ }
+
+ /* Find the interface sockaddr */
+ cp = (u_char *)(rp + 1);
+ for (i = 1; i != 0; i <<= 1)
+ if ((i & rp->rtm_addrs) != 0) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+
+ case RTA_IFA:
+ if (sa->sa_family == AF_INET) {
+ ifa = (struct sockaddr_in *)cp;
+ if (ifa->sin_addr.s_addr != 0) {
+ *from = *ifa;
+ return (NULL);
+ }
+ }
+ break;
+
+ default:
+ break;
+ /* empty */
+ }
+
+ if (SALEN(sa) == 0)
+ cp += sizeof (u_int32_t);
+ else
+ cp += roundup(SALEN(sa), sizeof (u_int32_t));
+ }
+
+ return ("failed!");
+}
+
+#ifndef HAVE_SOCKADDR_SA_LEN
+static int
+salen(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ return (sizeof(struct sockaddr_in));
+
+ case AF_LINK:
+ return (sizeof(struct sockaddr_dl));
+
+ default:
+ return (sizeof(struct sockaddr));
+ }
+}
+#endif
diff --git a/network_cmds/traceroute.tproj/findsaddr.h b/network_cmds/traceroute.tproj/findsaddr.h
new file mode 100644
index 0000000..49ed9e1
--- /dev/null
+++ b/network_cmds/traceroute.tproj/findsaddr.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 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.
+ *
+ * @(#) $Id: findsaddr.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+const char *findsaddr(const struct sockaddr_in *, struct sockaddr_in *);
diff --git a/network_cmds/traceroute.tproj/gnuc.h b/network_cmds/traceroute.tproj/gnuc.h
new file mode 100644
index 0000000..f13c0be
--- /dev/null
+++ b/network_cmds/traceroute.tproj/gnuc.h
@@ -0,0 +1,43 @@
+/* @(#) $Header: /Volumes/george/fs-svn/network_cmds/traceroute.tproj/gnuc.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL) */
+
+/* Define __P() macro, if necessary */
+#ifndef __P
+#if __STDC__
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+
+/* inline foo */
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+
+/*
+ * Handle new and old "dead" routine prototypes
+ *
+ * For example:
+ *
+ * __dead void foo(void) __attribute__((volatile));
+ *
+ */
+#ifdef __GNUC__
+#ifndef __dead
+#define __dead volatile
+#endif
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
+#else
+#ifndef __dead
+#define __dead
+#endif
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
diff --git a/network_cmds/traceroute.tproj/ifaddrlist.c b/network_cmds/traceroute.tproj/ifaddrlist.c
new file mode 100644
index 0000000..17b1026
--- /dev/null
+++ b/network_cmds/traceroute.tproj/ifaddrlist.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * 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/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 */
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "ifaddrlist.h"
+
+/*
+ * Return the interface list
+ */
+int
+ifaddrlist(register struct ifaddrlist **ipaddrp, register char *errbuf, size_t errbuflen)
+{
+ register int fd, nipaddr;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ register int n;
+#endif
+ register struct ifreq *ifrp, *ifend, *ifnext, *mp;
+ register struct sockaddr_in *sin;
+ register struct ifaddrlist *al;
+ struct ifconf ifc;
+ struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
+#define MAX_IPADDR (sizeof(ibuf) / sizeof(ibuf[0]))
+ static struct ifaddrlist ifaddrlist[MAX_IPADDR];
+ char device[sizeof(ifr.ifr_name) + 1];
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ (void)snprintf(errbuf, errbuflen, "socket: %s", strerror(errno));
+ return (-1);
+ }
+ ifc.ifc_len = sizeof(ibuf);
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ if (errno == EINVAL)
+ (void)snprintf(errbuf, sizeof(errbuf),
+ "SIOCGIFCONF: ifreq struct too small (%d bytes)",
+ (int)sizeof(ibuf));
+ else
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFCONF: %s",
+ strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ al = ifaddrlist;
+ mp = NULL;
+ nipaddr = 0;
+ for (; ifrp < ifend; ifrp = ifnext) {
+#ifdef HAVE_SOCKADDR_SA_LEN
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ifnext = ifrp + 1;
+ else
+ ifnext = (struct ifreq *)((char *)ifrp + n);
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+#else
+ ifnext = ifrp + 1;
+#endif
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ strlcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ if (errno == ENXIO)
+ continue;
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFFLAGS: %.*s: %s",
+ (int)sizeof(ifr.ifr_name), ifr.ifr_name,
+ strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+
+ /* Must be up */
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ continue;
+
+
+ (void)strlcpy(device, ifr.ifr_name, sizeof(device));
+#ifdef sun
+ /* Ignore sun virtual interfaces */
+ if (strchr(device, ':') != NULL)
+ continue;
+#endif
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFADDR: %s: %s",
+ device, strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+
+ if (nipaddr >= MAX_IPADDR) {
+ (void)snprintf(errbuf, errbuflen, "Too many interfaces (%d)",
+ (int)MAX_IPADDR);
+ (void)close(fd);
+ return (-1);
+ }
+ sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ al->addr = sin->sin_addr.s_addr;
+ al->device = strdup(device);
+ ++al;
+ ++nipaddr;
+ }
+ (void)close(fd);
+
+ *ipaddrp = ifaddrlist;
+ return (nipaddr);
+}
diff --git a/network_cmds/traceroute.tproj/ifaddrlist.h b/network_cmds/traceroute.tproj/ifaddrlist.h
new file mode 100644
index 0000000..53d91d9
--- /dev/null
+++ b/network_cmds/traceroute.tproj/ifaddrlist.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * 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: /Volumes/george/fs-svn/network_cmds/traceroute.tproj/ifaddrlist.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+
+struct ifaddrlist {
+ u_int32_t addr;
+ char *device;
+};
+
+int ifaddrlist(struct ifaddrlist **, char *, size_t );
diff --git a/network_cmds/traceroute.tproj/mean.awk b/network_cmds/traceroute.tproj/mean.awk
new file mode 100644
index 0000000..e97a56f
--- /dev/null
+++ b/network_cmds/traceroute.tproj/mean.awk
@@ -0,0 +1,50 @@
+#!/bin/awk -f
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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 University of
+# California, Berkeley and its contributors.
+# 4. 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.
+#
+# @(#)mean.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the average time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ tottime += $(f - 1)
+ ++n
+ }
+ }
+ if (n > 0)
+ print $1, tottime/n, median
+}
diff --git a/network_cmds/traceroute.tproj/median.awk b/network_cmds/traceroute.tproj/median.awk
new file mode 100644
index 0000000..1a8d81d
--- /dev/null
+++ b/network_cmds/traceroute.tproj/median.awk
@@ -0,0 +1,67 @@
+#!/bin/awk -f
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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 University of
+# California, Berkeley and its contributors.
+# 4. 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.
+#
+# @(#)median.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the median time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ ++n
+ time[n] = $(f - 1)
+ }
+ }
+ if (n > 0) {
+ # insertion sort the times to find the median
+ for (i = 2; i <= n; ++i) {
+ v = time[i]; j = i - 1;
+ while (time[j] > v) {
+ time[j+1] = time[j];
+ j = j - 1;
+ if (j < 0)
+ break;
+ }
+ time[j+1] = v;
+ }
+ if (n > 1 && (n % 2) == 0)
+ median = (time[n/2] + time[(n/2) + 1]) / 2
+ else
+ median = time[(n+1)/2]
+
+ print $1, median
+ }
+}
diff --git a/network_cmds/traceroute.tproj/traceroute.8 b/network_cmds/traceroute.tproj/traceroute.8
new file mode 100644
index 0000000..c726d7a
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.8
@@ -0,0 +1,439 @@
+.\" Copyright (c) 1989, 1995, 1996, 1997, 1999, 2000
+.\" 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.Dd May 29, 2008
+.Dt TRACEROUTE 8
+.Os BSD 4.3
+.Sh NAME
+.Nm traceroute
+.Nd print the route packets take to network host
+.Sh SYNOPSIS
+.Nm traceroute
+.Op Fl adeFISdNnrvx
+.Op Fl A Ar as_server
+.Op Fl f Ar first_ttl
+.Op Fl g Ar gateway
+.Op Fl i Ar iface
+.Op Fl M Ar first_ttl
+.Op Fl m Ar max_ttl
+.Op Fl P Ar proto
+.Op Fl p Ar port
+.Op Fl q Ar nqueries
+.Op Fl s Ar src_addr
+.Op Fl t Ar tos
+.Op Fl w Ar waittime
+.Op Fl z Ar pausemsecs
+.Ar host
+.Op Ar packetsize
+.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.
+.Nm
+utilizes the IP protocol `time to live' field and attempts to elicit an
+.Tn ICMP
+.Dv 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 size (in bytes) after the destination host
+name.
+.Pp
+Other options are:
+.Bl -tag -width Ds
+.It Fl a
+Turn on AS# lookups for each hop encountered.
+.It Fl A Ar as_server
+Turn on AS# lookups and use the given server instead of the
+default.
+.It Fl d
+Enable socket level debugging.
+.It Fl D
+When an ICMP response to our probe datagram is received,
+print the differences between the transmitted packet and
+the packet quoted by the ICMP response.
+A key showing the location of fields within the transmitted packet is printed,
+followed by the original packet in hex,
+followed by the quoted packet in hex.
+Bytes that are unchanged in the quoted packet are shown as underscores.
+Note,
+the IP checksum and the TTL of the quoted packet are not expected to match.
+By default, only one probe per hop is sent with this option.
+.It Fl e
+Firewall evasion mode.
+Use fixed destination ports for UDP and TCP probes.
+The destination port does NOT increment with each packet sent.
+.It Fl f Ar first_ttl
+Set the initial time-to-live used in the first outgoing probe packet.
+.It Fl F
+Set the "don't fragment" bit.
+.It Fl g Ar gateway
+Specify a loose source route gateway (8 maximum).
+.It Fl i Ar iface
+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
+.Fl s
+flag for another way to do this.)
+.It Fl I
+Use
+.Tn ICMP
+ECHO instead of
+.Tn UDP
+datagrams. (A synonym for "-P icmp").
+.It Fl M Ar first_ttl
+Set the initial time-to-live value used in outgoing probe packets.
+The default is 1, i.e., start with the first hop.
+.It Fl m Ar max_ttl
+Set the max time-to-live (max number of hops) used in outgoing probe
+packets. The default is
+.Em net.inet.ip.ttl
+hops (the same default used for
+.Tn TCP
+connections).
+.It Fl n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each gateway found on the
+path).
+.It Fl P Ar proto
+Send packets of specified IP protocol. The currently supported protocols
+are:
+.Tn UDP
+,
+.Tn TCP
+,
+.Tn GRE
+and
+.Tn ICMP
+Other protocols may also be specified (either by name or by number), though
+.Nm
+does not implement any special knowledge of their packet formats. This
+option is useful for determining which router along a path may be
+blocking packets based on IP protocol number. But see BUGS below.
+.It Fl p Ar port
+Protocol specific. For
+.Tn UDP
+and
+.Tn TCP,
+sets the base
+.Ar port
+number used in probes (default is 33434).
+.Nm
+hopes that nothing is listening on
+.Tn UDP
+ports
+.Em base
+to
+.Em base+nhops-1
+at the destination host (so an
+.Tn ICMP
+.Dv 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.
+.It Fl q Ar nqueries
+Set the number of probes per ``ttl'' to
+.Ar nqueries
+(default is three probes).
+.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 src_addr
+Use the following IP address
+(which must be given as an IP number, not
+a hostname) as the source address in outgoing probe packets. On
+hosts 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
+.Fl i
+flag for another way to do this.)
+.It Fl S
+Print a summary of how many probes were not answered for each hop.
+.It Fl t Ar tos
+Set the
+.Em 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 a
+.Bx 4.4
+or later system, this may be academic since the normal network
+services like telnet and ftp don't let you control the
+.Dv TOS ) .
+Not all values of
+.Dv TOS
+are legal or
+meaningful \- see the IP spec for definitions. Useful values are
+probably
+.Ql \-t 16
+(low delay) and
+.Ql \-t 8
+(high throughput).
+.It Fl v
+Verbose output. Received
+.Tn ICMP
+packets other than
+.Dv TIME_EXCEEDED
+and
+.Dv UNREACHABLE Ns s
+are listed.
+.It Fl w
+Set the time (in seconds) to wait for a response to a probe (default 5 sec.).
+.It Fl x
+Toggle IP checksums. Normally, this prevents
+.Nm
+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
+.Fl x
+causes them to be calculated). Note that checksums are usually required
+for the last hop when using
+.Tn ICMP
+ECHO probes (
+.Fl I
+). So they are always calculated when using ICMP.
+.It Fl z Ar pausemsecs
+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).
+.El
+.Pp
+This program attempts to trace the route an IP packet would follow to some
+internet host by launching
+.Tn UDP
+probe
+packets with a small ttl (time to live) then listening for an
+.Tn ICMP
+"time exceeded" reply from a gateway. We start our probes
+with a ttl of one and increase by one until we get an
+.Tn ICMP
+"port unreachable"
+(which means we got to "host") or hit a max (which
+defaults to
+.Em net.inet.ip.ttl
+hops & can be changed with the
+.Fl m
+flag). Three
+probes (changed with
+.Fl 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
+.Fl w
+flag), a "*" is printed for that
+probe.
+.Pp
+We don't want the destination
+host to process the
+.Tn 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
+.Fl p
+flag).
+.Pp
+A sample use and output might be:
+.Bd -literal
+[yak 71]% traceroute nis.nsf.net.
+traceroute to nis.nsf.net (35.1.1.48), 64 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
+
+.Ed
+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 bug in the distributed version
+of 4.3
+.Tn BSD ) .
+Note that you have to guess what path
+the packets are taking cross-country since the
+.Tn NSFNet
+(129.140)
+doesn't supply address-to-name translations for its
+.Tn NSS Ns es .
+.Pp
+A more interesting example is:
+.Bd -literal
+[yak 72]% traceroute allspice.lcs.mit.edu.
+traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 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
+
+.Ed
+Note that the gateways 12, 14, 15, 16 & 17 hops away
+either don't send
+.Tn ICMP
+"time exceeded" messages or send them
+with a ttl too small to reach us. 14 \- 17 are running the
+.Tn 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]
+.Tn 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
+.Tn 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:
+.Bd -literal
+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 !
+
+.Ed
+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
+.Tn ICMP
+reply. So, the reply will time out on the return path
+(with no notice sent to anyone since
+.Tn ICMP's
+aren't sent for
+.Tn 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.
+.Nm
+prints a "!" after the time if the ttl is <= 1.
+Since vendors ship a lot of obsolete
+.Pf ( Tn DEC Ns \'s
+Ultrix, Sun 3.x) or
+non-standard
+.Pq Tn HPUX
+software, expect to see this problem
+frequently and/or take care picking the target host of your
+probes.
+.Pp
+Other possible annotations after the time are
+.Sy !H ,
+.Sy !N ,
+or
+.Sy !P
+(host, network or protocol unreachable),
+.Sy !S
+(source route failed),
+.B !F\-<pmtu>
+(fragmentation needed \- the RFC1191 Path MTU Discovery value is displayed),
+.Sy !U
+or
+.Sy !W
+(destination network/host unknown),
+.Sy !I
+(source host is isolated),
+.Sy !A
+(communication with destination network administratively prohibited),
+.Sy !Z
+(communication with destination host administratively prohibited),
+.Sy !Q
+(for this ToS the destination network is unreachable),
+.Sy !T
+(for this ToS the destination host is unreachable),
+.Sy !X
+(communication administratively prohibited),
+.Sy !V
+(host precedence violation),
+.Sy !C
+(precedence cutoff in effect), or
+.Sy !<num>
+(ICMP unreachable code <num>).
+These are defined by RFC1812 (which supersedes RFC1716).
+If almost all the probes result in some kind of unreachable,
+.Nm
+will give up and exit.
+.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
+.Nm
+during normal operations or from automated scripts.
+.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.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ping 8 ,
+.Xr traceroute6 8
+.Sh BUGS
+When using protocols other than UDP, functionality is reduced.
+In particular, the last packet will often appear to be lost, because
+even though it reaches the destination host, there's no way to know
+that because no ICMP message is sent back.
+In the TCP case,
+.Nm
+should listen for a RST from the destination host (or an intermediate
+router that's filtering packets), but this is not implemented yet.
+.Pp
+The AS number capability reports information that may sometimes be
+inaccurate due to discrepancies between the contents of the
+routing database server and the current state of the Internet.
diff --git a/network_cmds/traceroute.tproj/traceroute.c b/network_cmds/traceroute.tproj/traceroute.c
new file mode 100644
index 0000000..a411d0a
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * 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
+__unused static const char copyright[] =
+ "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
+The Regents of the University of California. All rights reserved.\n";
+#endif
+
+/*
+ * 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 net.inet.ip.ttl 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), 64 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), 64 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>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#include <sys/time.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 <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <arpa/inet.h>
+
+#ifdef IPSEC
+#include <net/route.h>
+#include <netinet6/ipsec.h> /* XXX */
+#endif /* IPSEC */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.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 "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 "findsaddr.h"
+#include "ifaddrlist.h"
+#include "as.h"
+#include "traceroute.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
+
+/* What a GRE packet header looks like */
+struct grehdr {
+ u_int16_t flags;
+ u_int16_t proto;
+ u_int16_t length; /* PPTP version of these fields */
+ u_int16_t callId;
+};
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+/* For GRE, we prepare what looks like a PPTP packet */
+#define GRE_PPTP_PROTO 0x880b
+
+/* 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 timeval tv; /* time packet left */
+};
+
+#ifndef HAVE_ICMP_NEXTMTU
+/* Path MTU Discovery (RFC1191) */
+struct my_pmtu {
+ u_short ipm_void;
+ u_short ipm_nextmtu;
+};
+#endif
+
+u_char packet[512]; /* last inbound (icmp) packet */
+
+struct ip *outip; /* last output ip packet */
+u_char *outp; /* last output inner protocol packet */
+
+struct ip *hip = NULL; /* Quoted IP header */
+int hiplen = 0;
+
+/* loose source route gateway list (including room for final destination) */
+u_int32_t gwlist[NGATEWAYS + 1];
+
+int s; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+
+struct sockaddr whereto; /* Who to try to reach */
+struct sockaddr wherefrom; /* Who we are */
+int packlen; /* total length of packet */
+int protlen; /* length of protocol part of packet */
+int minpacket; /* min ip packet size */
+int maxpacket = 32 * 1024; /* max ip packet size */
+int pmtu; /* Path MTU Discovery (RFC1191) */
+u_int pausemsecs;
+
+char *prog;
+char *source;
+char *hostname;
+char *device;
+static const char devnull[] = "/dev/null";
+
+int nprobes = -1;
+int max_ttl;
+int first_ttl = 1;
+u_short ident;
+u_short port; /* protocol specific base "port" */
+
+int options; /* socket options */
+int verbose;
+int waittime = 5; /* time to wait for response (in seconds) */
+int nflag; /* print addresses numerically */
+int as_path; /* print as numbers for each hop */
+char *as_server = NULL;
+void *asn;
+#ifdef CANT_HACK_IPCKSUM
+int doipcksum = 0; /* don't calculate ip checksums by default */
+#else
+int doipcksum = 1; /* calculate ip checksums by default */
+#endif
+int optlen; /* length of ip options */
+int fixedPort = 0; /* Use fixed destination port for TCP and UDP */
+int printdiff = 0; /* Print the difference between sent and quoted */
+
+extern int optind;
+extern int opterr;
+extern char *optarg;
+
+/* Forwards */
+double deltaT(struct timeval *, struct timeval *);
+void freehostinfo(struct hostinfo *);
+void getaddr(u_int32_t *, char *);
+struct hostinfo *gethostinfo(char *);
+u_short in_cksum(u_short *, int);
+char *inetname(struct in_addr);
+int main(int, char **);
+u_short p_cksum(struct ip *, u_short *, int);
+int packet_ok(u_char *, int, struct sockaddr_in *, int);
+char *pr_type(u_char);
+void print(u_char *, int, struct sockaddr_in *);
+#ifdef IPSEC
+int setpolicy __P((int so, char *policy));
+#endif
+void send_probe(int, int);
+struct outproto *setproto(char *);
+int str2val(const char *, const char *, int, int);
+void tvsub(struct timeval *, struct timeval *);
+void usage(void);
+int wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
+void pkt_compare(const u_char *, int, const u_char *, int);
+#ifndef HAVE_USLEEP
+int usleep(u_int);
+#endif
+
+void udp_prep(struct outdata *);
+int udp_check(const u_char *, int);
+void tcp_prep(struct outdata *);
+int tcp_check(const u_char *, int);
+void gre_prep(struct outdata *);
+int gre_check(const u_char *, int);
+void gen_prep(struct outdata *);
+int gen_check(const u_char *, int);
+void icmp_prep(struct outdata *);
+int icmp_check(const u_char *, int);
+
+/* Descriptor structure for each outgoing protocol we support */
+struct outproto {
+ char *name; /* name of protocol */
+ const char *key; /* An ascii key for the bytes of the header */
+ u_char num; /* IP protocol number */
+ u_short hdrlen; /* max size of protocol header */
+ u_short port; /* default base protocol-specific "port" */
+ void (*prepare)(struct outdata *);
+ /* finish preparing an outgoing packet */
+ int (*check)(const u_char *, int);
+ /* check an incoming packet */
+};
+
+/* List of supported protocols. The first one is the default. The last
+ one is the handler for generic protocols not explicitly listed. */
+struct outproto protos[] = {
+ {
+ "udp",
+ "spt dpt len sum",
+ IPPROTO_UDP,
+ sizeof(struct udphdr),
+ 32768 + 666,
+ udp_prep,
+ udp_check
+ },
+ {
+ "tcp",
+ "spt dpt seq ack xxflwin sum urp",
+ IPPROTO_TCP,
+ sizeof(struct tcphdr),
+ 32768 + 666,
+ tcp_prep,
+ tcp_check
+ },
+ {
+ "gre",
+ "flg pro len clid",
+ IPPROTO_GRE,
+ sizeof(struct grehdr),
+ GRE_PPTP_PROTO,
+ gre_prep,
+ gre_check
+ },
+ {
+ "icmp",
+ "typ cod sum ",
+ IPPROTO_ICMP,
+ sizeof(struct icmp),
+ 0,
+ icmp_prep,
+ icmp_check
+ },
+ {
+ NULL,
+ NULL,
+ 0,
+ 2 * sizeof(u_short),
+ 0,
+ gen_prep,
+ gen_check
+ },
+};
+struct outproto *proto = &protos[0];
+
+const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts";
+
+int
+main(int argc, char **argv)
+{
+ register int op, code, n;
+ register char *cp;
+ register const char *err;
+ register u_int32_t *ap;
+ register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
+ register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
+ register struct hostinfo *hi;
+ int on = 1;
+ register struct protoent *pe;
+ register int ttl, probe, i;
+ register int seq = 0;
+ int tos = 0, settos = 0;
+ register int lsrr = 0;
+ register u_short off = 0;
+ struct ifaddrlist *al;
+ char errbuf[132];
+ int requestPort = -1;
+ int sump = 0;
+ int sockerrno = 0;
+
+ if (argv[0] == NULL)
+ prog = "traceroute";
+ else if ((cp = strrchr(argv[0], '/')) != NULL)
+ prog = cp + 1;
+ else
+ prog = argv[0];
+
+ /* 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) {
+ Fprintf(stderr, "%s: open \"%s\": %s\n",
+ prog, devnull, strerror(errno));
+ exit(1);
+ }
+ /*
+ * Do the setuid-required stuff first, then lose priveleges ASAP.
+ * Do error checking for these two calls where they appeared in
+ * the original code.
+ */
+ cp = "icmp";
+ pe = getprotobyname(cp);
+ if (pe) {
+ if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
+ sockerrno = errno;
+ else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+ sockerrno = errno;
+ }
+
+ setuid(getuid());
+
+#ifdef IPCTL_DEFTTL
+ {
+ int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+ size_t sz = sizeof(max_ttl);
+
+ if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
+ perror("sysctl(net.inet.ip.ttl)");
+ exit(1);
+ }
+ }
+#else
+ max_ttl = 30;
+#endif
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+ 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':
+ printdiff = 1;
+ break;
+
+ case 'e':
+ fixedPort = 1;
+ break;
+
+ case 'f':
+ case 'M': /* FreeBSD compat. */
+ first_ttl = str2val(optarg, "first ttl", 1, 255);
+ break;
+
+ case 'F':
+ off = IP_DF;
+ break;
+
+ case 'g':
+ if (lsrr >= NGATEWAYS) {
+ Fprintf(stderr,
+ "%s: No more than %d gateways\n",
+ prog, NGATEWAYS);
+ exit(1);
+ }
+ getaddr(gwlist + lsrr, optarg);
+ ++lsrr;
+ break;
+
+ case 'i':
+ device = optarg;
+ break;
+
+ case 'I':
+ proto = setproto("icmp");
+ break;
+
+ case 'm':
+ max_ttl = str2val(optarg, "max ttl", 1, 255);
+ break;
+
+ case 'n':
+ ++nflag;
+ break;
+
+ case 'P':
+ proto = setproto(optarg);
+ break;
+
+ case 'p':
+ requestPort = (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 'S':
+ sump = 1;
+ 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",
+ 1, 24 * 60 * 60);
+ break;
+
+ case 'z':
+ pausemsecs = str2val(optarg, "pause msecs",
+ 0, 60 * 60 * 1000);
+ break;
+
+ default:
+ usage();
+ }
+
+ /* Set requested port, if any, else default for this protocol */
+ port = (requestPort != -1) ? requestPort : proto->port;
+
+ if (nprobes == -1)
+ nprobes = printdiff ? 1 : 3;
+
+ if (first_ttl > max_ttl) {
+ Fprintf(stderr,
+ "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
+ prog, first_ttl, max_ttl);
+ exit(1);
+ }
+
+ if (!doipcksum)
+ Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
+
+ if (lsrr > 0)
+ optlen = (lsrr + 1) * sizeof(gwlist[0]);
+ minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
+ packlen = minpacket; /* minimum sized packet */
+
+ /* 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)
+ Fprintf(stderr,
+ "%s: Warning: %s has multiple addresses; using %s\n",
+ prog, 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
+
+ protlen = packlen - sizeof(*outip) - optlen;
+
+ outip = (struct ip *)malloc((unsigned)packlen);
+ if (outip == NULL) {
+ Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ memset((char *)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
+ outip->ip_p = proto->num;
+ outp = (u_char *)(outip + 1);
+#ifdef HAVE_RAW_OPTIONS
+ if (lsrr > 0) {
+ register 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 = (getpid() & 0xffff) | 0x8000;
+
+ if (pe == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+ if (s < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&on,
+ sizeof(on));
+ if (options & SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(s, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(s, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ if (sndsock < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+
+#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
+ if (lsrr > 0) {
+ u_char optlist[MAX_IPOPTLEN];
+
+ cp = "ip";
+ if ((pe = getprotobyname(cp)) == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+
+ /* 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 ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
+ (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
+ Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+ }
+#endif
+
+#ifdef SO_SNDBUF
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
+ sizeof(packlen)) < 0) {
+ Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+#endif
+#ifdef IP_HDRINCL
+ if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+ sizeof(on)) < 0) {
+ Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+#else
+#ifdef IP_TOS
+ if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(tos)) < 0) {
+ Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
+ prog, tos, strerror(errno));
+ exit(1);
+ }
+#endif
+#endif
+ if (options & SO_DEBUG)
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+ /* Get the interface address list */
+ n = ifaddrlist(&al, errbuf, sizeof(errbuf));
+ if (n < 0) {
+ Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
+ exit(1);
+ }
+ if (n == 0) {
+ Fprintf(stderr,
+ "%s: Can't find any network interfaces\n", prog);
+ exit(1);
+ }
+
+ /* Look for a specific device */
+ if (device != NULL) {
+ for (i = n; i > 0; --i, ++al)
+ if (strcmp(device, al->device) == 0)
+ break;
+ if (i <= 0) {
+ Fprintf(stderr, "%s: Can't find interface %.32s\n",
+ prog, device);
+ exit(1);
+ }
+ }
+
+ /* Determine our source address */
+ if (source == NULL) {
+ /*
+ * If a device was specified, use the interface address.
+ * Otherwise, try to determine our source address.
+ */
+ if (device != NULL)
+ setsin(from, al->addr);
+ else if ((err = findsaddr(to, from)) != NULL) {
+ Fprintf(stderr, "%s: findsaddr: %s\n",
+ prog, err);
+ exit(1);
+ }
+ } else {
+ hi = gethostinfo(source);
+ source = hi->name;
+ hi->name = NULL;
+ /*
+ * If the device was specified make sure it
+ * corresponds to the source address specified.
+ * Otherwise, use the first address (and warn if
+ * there are more than one).
+ */
+ if (device != NULL) {
+ for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
+ if (*ap == al->addr)
+ break;
+ if (i <= 0) {
+ Fprintf(stderr,
+ "%s: %s is not on interface %.32s\n",
+ prog, source, device);
+ exit(1);
+ }
+ setsin(from, *ap);
+ } else {
+ setsin(from, hi->addrs[0]);
+ if (hi->n > 1)
+ Fprintf(stderr,
+ "%s: Warning: %s has multiple addresses; using %s\n",
+ prog, source, inet_ntoa(from->sin_addr));
+ }
+ freehostinfo(hi);
+ }
+
+ outip->ip_src = from->sin_addr;
+
+ /* Check the source address (-s), if any, is valid */
+ if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
+ Fprintf(stderr, "%s: bind: %s\n",
+ prog, strerror(errno));
+ exit (1);
+ }
+
+ if (as_path) {
+ asn = as_setup(as_server);
+ if (asn == NULL) {
+ Fprintf(stderr, "%s: as_setup failed, AS# lookups"
+ " disabled\n", prog);
+ (void)fflush(stderr);
+ as_path = 0;
+ }
+ }
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(sndsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(sndsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ 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;
+ int loss;
+
+ Printf("%2d ", ttl);
+ for (probe = 0, loss = 0; probe < nprobes; ++probe) {
+ register int cc;
+ struct timeval t1, t2;
+ struct timezone tz;
+ register struct ip *ip;
+ struct outdata outdata;
+
+ if (sentfirst && pausemsecs > 0)
+ usleep(pausemsecs * 1000);
+ /* Prepare outgoing data */
+ outdata.seq = ++seq;
+ outdata.ttl = ttl;
+
+ /* Avoid alignment problems by copying bytewise: */
+ (void)gettimeofday(&t1, &tz);
+ memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
+
+ /* Finalize and send packet */
+ (*proto->prepare)(&outdata);
+ send_probe(seq, ttl);
+ ++sentfirst;
+
+ /* Wait for a reply */
+ while ((cc = wait_for_reply(s, from, &t1)) != 0) {
+ double T;
+ int precis;
+
+ (void)gettimeofday(&t2, &tz);
+ 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;
+ }
+ T = deltaT(&t1, &t2);
+#ifdef SANE_PRECISION
+ if (T >= 1000.0)
+ precis = 0;
+ else if (T >= 100.0)
+ precis = 1;
+ else if (T >= 10.0)
+ precis = 2;
+ else
+#endif
+ precis = 3;
+ Printf(" %.*f ms", precis, T);
+ if (printdiff) {
+ Printf("\n");
+ Printf("%*.*s%s\n",
+ -(outip->ip_hl << 3),
+ outip->ip_hl << 3,
+ ip_hdr_key,
+ proto->key);
+ pkt_compare((void *)outip, packlen,
+ (void *)hip, hiplen);
+ }
+ if (i == -2) {
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ 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
+ ip = (struct ip *)packet;
+ 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:
+ ++unreachable;
+ Printf(" !F-%d", pmtu);
+ break;
+
+ case ICMP_UNREACH_SRCFAIL:
+ ++unreachable;
+ Printf(" !S");
+ break;
+
+ case ICMP_UNREACH_NET_UNKNOWN:
+ ++unreachable;
+ Printf(" !U");
+ break;
+
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ ++unreachable;
+ Printf(" !W");
+ break;
+
+ case ICMP_UNREACH_ISOLATED:
+ ++unreachable;
+ Printf(" !I");
+ break;
+
+ case ICMP_UNREACH_NET_PROHIB:
+ ++unreachable;
+ Printf(" !A");
+ break;
+
+ case ICMP_UNREACH_HOST_PROHIB:
+ ++unreachable;
+ Printf(" !Z");
+ break;
+
+ case ICMP_UNREACH_TOSNET:
+ ++unreachable;
+ Printf(" !Q");
+ break;
+
+ case ICMP_UNREACH_TOSHOST:
+ ++unreachable;
+ Printf(" !T");
+ 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) {
+ loss++;
+ Printf(" *");
+ }
+ (void)fflush(stdout);
+ }
+ if (sump) {
+ Printf(" (%d%% loss)", (loss * 100) / nprobes);
+ }
+ putchar('\n');
+ if (got_there ||
+ (unreachable > 0 && unreachable >= nprobes - 1))
+ break;
+ }
+ if (as_path)
+ as_shutdown(asn);
+ exit(0);
+}
+
+int
+wait_for_reply(register int sock, register struct sockaddr_in *fromp,
+ register const struct timeval *tp)
+{
+ fd_set *fdsp;
+ size_t nfds;
+ struct timeval now, wait;
+ struct timezone tz;
+ register int cc = 0;
+ register int error;
+ socklen_t fromlen = sizeof(*fromp);
+
+ nfds = howmany(sock + 1, NFDBITS);
+ if ((fdsp = malloc(nfds * sizeof(fd_set))) == NULL)
+ err(1, "malloc");
+ memset(fdsp, 0, nfds * sizeof(fd_set));
+ FD_SET(sock, fdsp);
+
+ wait.tv_sec = tp->tv_sec + waittime;
+ wait.tv_usec = tp->tv_usec;
+ (void)gettimeofday(&now, &tz);
+ tvsub(&wait, &now);
+ if (wait.tv_sec < 0) {
+ wait.tv_sec = 0;
+ wait.tv_usec = 1;
+ }
+
+ error = select(sock + 1, fdsp, NULL, NULL, &wait);
+ if (error == -1 && errno == EINVAL) {
+ Fprintf(stderr, "%s: botched select() args\n", prog);
+ exit(1);
+ }
+ if (error > 0)
+ cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
+ (struct sockaddr *)fromp, &fromlen);
+
+ free(fdsp);
+ return(cc);
+}
+
+void
+send_probe(int seq, int ttl)
+{
+ register int cc;
+
+ outip->ip_ttl = ttl;
+ outip->ip_id = htons(ident + seq);
+
+ /* XXX undocumented debugging hack */
+ if (verbose > 1) {
+ register const u_short *sp;
+ register int nshorts, i;
+
+ sp = (u_short *)outip;
+ nshorts = (u_int)packlen / sizeof(u_short);
+ 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", *(u_char *)sp);
+ }
+ Printf("]\n");
+ }
+
+#if !defined(IP_HDRINCL) && defined(IP_TTL)
+ if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0) {
+ Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
+ prog, ttl, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ cc = sendto(sndsock, (char *)outip,
+ packlen, 0, &whereto, sizeof(whereto));
+ if (cc < 0 || cc != packlen) {
+ if (cc < 0)
+ Fprintf(stderr, "%s: sendto: %s\n",
+ prog, strerror(errno));
+ Printf("%s: wrote %s %d chars, ret=%d\n",
+ prog, hostname, packlen, cc);
+ (void)fflush(stdout);
+ }
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+int
+setpolicy(so, policy)
+ int so;
+ char *policy;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ warnx("%s", ipsec_strerror());
+ return -1;
+ }
+ (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf));
+
+ free(buf);
+
+ return 0;
+}
+#endif
+
+double
+deltaT(struct timeval *t1p, struct timeval *t2p)
+{
+ register 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.
+ */
+char *
+pr_type(register u_char t)
+{
+ static 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]);
+}
+
+int
+packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
+ register int seq)
+{
+ register struct icmp *icp;
+ register u_char type, code;
+ register int hlen;
+#ifndef ARCHAIC
+ register struct ip *ip;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ if (cc < hlen + ICMP_MINLEN) {
+ if (verbose)
+ Printf("packet too short (%d 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_ECHOREPLY
+ && proto->num == IPPROTO_ICMP
+ && (*proto->check)((u_char *)icp, (u_char)seq))
+ return -2;
+ if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
+ type == ICMP_UNREACH) {
+ u_char *inner;
+
+ hip = &icp->icmp_ip;
+ hiplen = ((u_char *)icp + cc) - (u_char *)hip;
+ hlen = hip->ip_hl << 2;
+ inner = (u_char *)((u_char *)hip + hlen);
+ if (hlen + 12 <= cc
+ && hip->ip_p == proto->num
+ && (*proto->check)(inner, (u_char)seq))
+ return (type == ICMP_TIMXCEED ? -1 : code + 1);
+ }
+#ifndef ARCHAIC
+ if (verbose) {
+ register int i;
+ u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
+
+ Printf("\n%d 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);
+}
+
+void
+icmp_prep(struct outdata *outdata)
+{
+ struct icmp *const icmpheader = (struct icmp *) outp;
+
+ icmpheader->icmp_type = ICMP_ECHO;
+ icmpheader->icmp_id = htons(ident);
+ icmpheader->icmp_seq = htons(outdata->seq);
+ icmpheader->icmp_cksum = 0;
+ icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
+ if (icmpheader->icmp_cksum == 0)
+ icmpheader->icmp_cksum = 0xffff;
+}
+
+int
+icmp_check(const u_char *data, int seq)
+{
+ struct icmp *const icmpheader = (struct icmp *) data;
+
+ return (icmpheader->icmp_id == htons(ident)
+ && icmpheader->icmp_seq == htons(seq));
+}
+
+void
+udp_prep(struct outdata *outdata)
+{
+ struct udphdr *const outudp = (struct udphdr *) outp;
+
+ outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
+ outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ outudp->uh_ulen = htons((u_short)protlen);
+ outudp->uh_sum = 0;
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
+ outudp->uh_sum = (sum) ? sum : 0xffff;
+ }
+
+ return;
+}
+
+int
+udp_check(const u_char *data, int seq)
+{
+ struct udphdr *const udp = (struct udphdr *) data;
+
+ return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
+ ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
+}
+
+void
+tcp_prep(struct outdata *outdata)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) outp;
+
+ tcp->th_sport = htons(ident);
+ tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
+ (fixedPort ? outdata->seq : 0));
+ tcp->th_ack = 0;
+ tcp->th_off = 5;
+ tcp->th_flags = TH_SYN;
+ tcp->th_sum = 0;
+
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
+ tcp->th_sum = (sum) ? sum : 0xffff;
+ }
+}
+
+int
+tcp_check(const u_char *data, int seq)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) data;
+
+ return (ntohs(tcp->th_sport) == ident
+ && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+ && tcp->th_seq == ((ident << 16) | (port + seq));
+}
+
+void
+gre_prep(struct outdata *outdata)
+{
+ struct grehdr *const gre = (struct grehdr *) outp;
+
+ gre->flags = htons(0x2001);
+ gre->proto = htons(port);
+ gre->length = 0;
+ gre->callId = htons(ident + outdata->seq);
+}
+
+int
+gre_check(const u_char *data, int seq)
+{
+ struct grehdr *const gre = (struct grehdr *) data;
+
+ return(ntohs(gre->proto) == port
+ && ntohs(gre->callId) == ident + seq);
+}
+
+void
+gen_prep(struct outdata *outdata)
+{
+ u_int16_t *const ptr = (u_int16_t *) outp;
+
+ ptr[0] = htons(ident);
+ ptr[1] = htons(port + outdata->seq);
+}
+
+int
+gen_check(const u_char *data, int seq)
+{
+ u_int16_t *const ptr = (u_int16_t *) data;
+
+ return(ntohs(ptr[0]) == ident
+ && ntohs(ptr[1]) == port + seq);
+}
+
+void
+print(register u_char *buf, register int cc, register struct sockaddr_in *from)
+{
+ register struct ip *ip;
+ register int hlen;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ cc -= hlen;
+
+ if (as_path)
+ Printf(" [AS%d]", as_lookup(asn, &from->sin_addr));
+
+ if (nflag)
+ Printf(" %s", inet_ntoa(from->sin_addr));
+ else
+ Printf(" %s (%s)", inetname(from->sin_addr),
+ inet_ntoa(from->sin_addr));
+
+ if (verbose)
+ Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+}
+
+/*
+ * Checksum routine for UDP and TCP headers.
+ */
+u_short
+p_cksum(struct ip *ip, u_short *data, int len)
+{
+ static struct ipovly ipo;
+ u_short sumh, sumd;
+ u_int32_t sumt;
+
+ ipo.ih_pr = ip->ip_p;
+ ipo.ih_len = htons(len);
+ ipo.ih_src = ip->ip_src;
+ ipo.ih_dst = ip->ip_dst;
+
+ sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
+ sumd = in_cksum((u_short*)data, len); /* payload data cksum */
+ sumt = (sumh << 16) | (sumd);
+
+ return ~in_cksum((u_short*)&sumt, sizeof(sumt));
+}
+
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+u_short
+in_cksum(register u_short *addr, register int len)
+{
+ register int nleft = len;
+ register u_short *w = addr;
+ register u_short answer;
+ register int sum = 0;
+
+ /*
+ * 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)
+ sum += *(u_char *)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 = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
+
+/*
+ * Subtract 2 timeval structs: out = out - in.
+ * Out is assumed to be within about LONG_MAX seconds of in.
+ */
+void
+tvsub(register struct timeval *out, register 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.
+ */
+char *
+inetname(struct in_addr in)
+{
+ register char *cp;
+ register 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;
+ memmove(domain, cp, strlen(cp) + 1);
+ }
+ }
+ }
+ 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));
+}
+
+struct hostinfo *
+gethostinfo(register char *hostname)
+{
+ register int n;
+ register struct hostent *hp;
+ register struct hostinfo *hi;
+ register char **p;
+ register u_int32_t addr, *ap;
+
+ if (strlen(hostname) > 64) {
+ Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
+ prog, hostname);
+ exit(1);
+ }
+ hi = calloc(1, sizeof(*hi));
+ if (hi == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ addr = inet_addr(hostname);
+ if ((int32_t)addr != -1) {
+ hi->name = strdup(hostname);
+ hi->n = 1;
+ hi->addrs = calloc(1, sizeof(hi->addrs[0]));
+ if (hi->addrs == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+ hi->addrs[0] = addr;
+ return (hi);
+ }
+
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+ Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
+ exit(1);
+ }
+ if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
+ Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
+ exit(1);
+ }
+ hi->name = strdup(hp->h_name);
+ 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) {
+ Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
+ memcpy(ap, *p, sizeof(*ap));
+ return (hi);
+}
+
+void
+freehostinfo(register struct hostinfo *hi)
+{
+ if (hi->name != NULL) {
+ free(hi->name);
+ hi->name = NULL;
+ }
+ free((char *)hi->addrs);
+ free((char *)hi);
+}
+
+void
+getaddr(register u_int32_t *ap, register char *hostname)
+{
+ register struct hostinfo *hi;
+
+ hi = gethostinfo(hostname);
+ *ap = hi->addrs[0];
+ freehostinfo(hi);
+}
+
+void
+setsin(register struct sockaddr_in *sin, register 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. */
+int
+str2val(register const char *str, register const char *what,
+ register int mi, register int ma)
+{
+ register const char *cp;
+ register int val;
+ char *ep;
+
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ cp = str + 2;
+ val = (int)strtol(cp, &ep, 16);
+ } else
+ val = (int)strtol(str, &ep, 10);
+ if (*ep != '\0') {
+ Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
+ prog, str, what);
+ exit(1);
+ }
+ if (val < mi && mi >= 0) {
+ if (mi == 0)
+ Fprintf(stderr, "%s: %s must be >= %d\n",
+ prog, what, mi);
+ else
+ Fprintf(stderr, "%s: %s must be > %d\n",
+ prog, what, mi - 1);
+ exit(1);
+ }
+ if (val > ma && ma >= 0) {
+ Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
+ exit(1);
+ }
+ return (val);
+}
+
+struct outproto *
+setproto(char *pname)
+{
+ struct outproto *proto;
+ int i;
+
+ for (i = 0; protos[i].name != NULL; i++) {
+ if (strcasecmp(protos[i].name, pname) == 0) {
+ break;
+ }
+ }
+ proto = &protos[i];
+ if (proto->name == NULL) { /* generic handler */
+ struct protoent *pe;
+ u_int32_t pnum;
+
+ /* Determine the IP protocol number */
+ if ((pe = getprotobyname(pname)) != NULL)
+ pnum = pe->p_proto;
+ else
+ pnum = str2val(optarg, "proto number", 1, 255);
+ proto->num = pnum;
+ }
+ return proto;
+}
+
+void
+pkt_compare(const u_char *a, int la, const u_char *b, int lb) {
+ int l;
+ int i;
+
+ for (i = 0; i < la; i++)
+ Printf("%02x", (unsigned int)a[i]);
+ Printf("\n");
+ l = (la <= lb) ? la : lb;
+ for (i = 0; i < l; i++)
+ if (a[i] == b[i])
+ Printf("__");
+ else
+ Printf("%02x", (unsigned int)b[i]);
+ for (; i < lb; i++)
+ Printf("%02x", (unsigned int)b[i]);
+ Printf("\n");
+}
+
+
+void
+usage(void)
+{
+ extern char version[];
+
+ Fprintf(stderr, "Version %s\n", version);
+ Fprintf(stderr,
+ "Usage: %s [-adDeFInrSvx] [-A as_server] [-f first_ttl] [-g gateway] [-i iface]\n"
+ "\t[-M first_ttl] [-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
+ "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog);
+ exit(1);
+}
diff --git a/network_cmds/traceroute.tproj/traceroute.h b/network_cmds/traceroute.tproj/traceroute.h
new file mode 100644
index 0000000..31154d8
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 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.
+ *
+ * @(#) $Id: traceroute.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+
+extern char *prog;
+
+void setsin(struct sockaddr_in *, u_int32_t);
diff --git a/network_cmds/traceroute.tproj/version.c b/network_cmds/traceroute.tproj/version.c
new file mode 100644
index 0000000..680dcd4
--- /dev/null
+++ b/network_cmds/traceroute.tproj/version.c
@@ -0,0 +1 @@
+char version[] = "1.4a12+Darwin";