diff options
Diffstat (limited to 'usr.sbin/traceroute')
-rw-r--r-- | usr.sbin/traceroute/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/traceroute/README | 126 | ||||
-rw-r--r-- | usr.sbin/traceroute/mean.awk | 50 | ||||
-rw-r--r-- | usr.sbin/traceroute/median.awk | 67 | ||||
-rw-r--r-- | usr.sbin/traceroute/traceroute.8 | 336 | ||||
-rw-r--r-- | usr.sbin/traceroute/traceroute.c | 835 |
6 files changed, 1422 insertions, 0 deletions
diff --git a/usr.sbin/traceroute/Makefile b/usr.sbin/traceroute/Makefile new file mode 100644 index 0000000..6f89a2c --- /dev/null +++ b/usr.sbin/traceroute/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 + +PROG= traceroute +MAN8= traceroute.0 +BINOWN= root +BINMODE=4555 + +.include <bsd.prog.mk> diff --git a/usr.sbin/traceroute/README b/usr.sbin/traceroute/README new file mode 100644 index 0000000..6d33c6c --- /dev/null +++ b/usr.sbin/traceroute/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/usr.sbin/traceroute/mean.awk b/usr.sbin/traceroute/mean.awk new file mode 100644 index 0000000..e97a56f --- /dev/null +++ b/usr.sbin/traceroute/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/usr.sbin/traceroute/median.awk b/usr.sbin/traceroute/median.awk new file mode 100644 index 0000000..1a8d81d --- /dev/null +++ b/usr.sbin/traceroute/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/usr.sbin/traceroute/traceroute.8 b/usr.sbin/traceroute/traceroute.8 new file mode 100644 index 0000000..c1e13bb --- /dev/null +++ b/usr.sbin/traceroute/traceroute.8 @@ -0,0 +1,336 @@ +.\" Copyright (c) 1990, 1991, 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. +.\" +.\" @(#)traceroute.8 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 6, 1993 +.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 m Ar max_ttl +.Op Fl n +.Op Fl p Ar port +.Op Fl q Ar nqueries +.Op Fl r +.Bk -words +.Op Fl s Ar src_addr +.Ek +.Op Fl t Ar tos +.Op Fl w Ar waittime +.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 Traceroute +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 38 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 m Ar max_ttl +Set the max time-to-live (max number of hops) used in outgoing probe +packets. The default is 30 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 port +Set the base +.Tn UDP +.Ar port +number used in probes (default is 33434). +.Nm Traceroute +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. +.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.3 tahoe +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 3 +sec.). +.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 30 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 3 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), 30 hops max, 56 byte packet +1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms +2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms +3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms +4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms +5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms +6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms +7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms +8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms +9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms +10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms +11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms + +.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), 30 hops max +1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms +2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms +3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms +4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms +5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms +6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms +7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms +8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms +9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms +10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms +11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms +12 * * * +13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms +14 * * * +15 * * * +16 * * * +17 * * * +18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms + +.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 Traceroute +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. +Other possible annotations after the time are +.Sy !H , +.Sy !N , +.Sy !P +(got a host, network or protocol unreachable, respectively), +.Sy !S +or +.Sy !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, +.Nm traceroute +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 traceroute +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 +.Sh HISTORY +The +.Nm +command +.Bt diff --git a/usr.sbin/traceroute/traceroute.c b/usr.sbin/traceroute/traceroute.c new file mode 100644 index 0000000..2ae83ba --- /dev/null +++ b/usr.sbin/traceroute/traceroute.c @@ -0,0 +1,835 @@ +/*- + * 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. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1990, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93"; +#endif /* not lint */ + +/* + * traceroute host - trace the route ip packets follow going to "host". + * + * Attempt to trace the route an ip packet would follow to some + * internet host. We find out intermediate hops by launching probe + * packets with a small ttl (time to live) then listening for an + * icmp "time exceeded" reply from a gateway. We start our probes + * with a ttl of one and increase by one until we get an icmp "port + * unreachable" (which means we got to "host") or hit a max (which + * defaults to 30 hops & can be changed with the -m flag). Three + * probes (change with -q flag) are sent at each ttl setting and a + * line is printed showing the ttl, address of the gateway and + * round trip time of each probe. If the probe answers come from + * different gateways, the address of each responding system will + * be printed. If there is no response within a 5 sec. timeout + * interval (changed with the -w flag), a "*" is printed for that + * probe. + * + * Probe packets are UDP format. We don't want the destination + * host to process them so the destination port is set to an + * unlikely value (if some clod on the destination is using that + * value, it can be changed with the -p flag). + * + * A sample use might be: + * + * [yak 71]% traceroute nis.nsf.net. + * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet + * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms + * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms + * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms + * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms + * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms + * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms + * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms + * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms + * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms + * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms + * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms + * + * Note that lines 2 & 3 are the same. This is due to a buggy + * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards + * packets with a zero ttl. + * + * A more interesting example is: + * + * [yak 72]% traceroute allspice.lcs.mit.edu. + * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max + * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms + * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms + * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms + * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms + * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms + * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms + * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms + * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms + * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms + * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms + * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms + * 12 * * * + * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms + * 14 * * * + * 15 * * * + * 16 * * * + * 17 * * * + * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms + * + * (I start to see why I'm having so much trouble with mail to + * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away + * either don't send ICMP "time exceeded" messages or send them + * with a ttl too small to reach us. 14 - 17 are running the + * MIT C Gateway code that doesn't send "time exceeded"s. God + * only knows what's going on with 12. + * + * The silent gateway 12 in the above may be the result of a bug in + * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3) + * sends an unreachable message using whatever ttl remains in the + * original datagram. Since, for gateways, the remaining ttl is + * zero, the icmp "time exceeded" is guaranteed to not make it back + * to us. The behavior of this bug is slightly more interesting + * when it appears on the destination system: + * + * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms + * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms + * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms + * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms + * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms + * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms + * 7 * * * + * 8 * * * + * 9 * * * + * 10 * * * + * 11 * * * + * 12 * * * + * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms ! + * + * Notice that there are 12 "gateways" (13 is the final + * destination) and exactly the last half of them are "missing". + * What's really happening is that rip (a Sun-3 running Sun OS3.5) + * is using the ttl from our arriving datagram as the ttl in its + * icmp reply. So, the reply will time out on the return path + * (with no notice sent to anyone since icmp's aren't sent for + * icmp's) until we probe with a ttl that's at least twice the path + * length. I.e., rip is really only 7 hops away. A reply that + * returns with a ttl of 1 is a clue this problem exists. + * Traceroute prints a "!" after the time if the ttl is <= 1. + * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or + * non-standard (HPUX) software, expect to see this problem + * frequently and/or take care picking the target host of your + * probes. + * + * Other possible annotations after the time are !H, !N, !P (got a host, + * network or protocol unreachable, respectively), !S or !F (source + * route failed or fragmentation needed -- neither of these should + * ever occur and the associated gateway is busted if you see one). If + * almost all the probes result in some kind of unreachable, traceroute + * will give up and exit. + * + * Notes + * ----- + * This program must be run by root or be setuid. (I suggest that + * you *don't* make it setuid -- casual use could result in a lot + * of unnecessary traffic on our poor, congested nets.) + * + * This program requires a kernel mod that does not appear in any + * system available from Berkeley: A raw ip socket using proto + * IPPROTO_RAW must interpret the data sent as an ip datagram (as + * opposed to data to be wrapped in a ip datagram). See the README + * file that came with the source to this program for a description + * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may + * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE + * MODIFIED TO RUN THIS PROGRAM. + * + * The udp port usage may appear bizarre (well, ok, it is bizarre). + * The problem is that an icmp message only contains 8 bytes of + * data from the original datagram. 8 bytes is the size of a udp + * header so, if we want to associate replies with the original + * datagram, the necessary information must be encoded into the + * udp header (the ip id could be used but there's no way to + * interlock with the kernel's assignment of ip id's and, anyway, + * it would have taken a lot more kernel hacking to allow this + * code to set the ip id). So, to allow two or more users to + * use traceroute simultaneously, we use this task's pid as the + * source port (the high bit is set to move the port number out + * of the "likely" range). To keep track of which probe is being + * replied to (so times and/or hop counts don't get confused by a + * reply that was delayed in transit), we increment the destination + * port number before each probe. + * + * Don't use this as a coding example. I was trying to find a + * routing problem and this code sort-of popped out after 48 hours + * without sleep. I was amazed it ever compiled, much less ran. + * + * I stole the idea for this program from Steve Deering. Since + * the first release, I've learned that had I attended the right + * IETF working group meetings, I also could have stolen it from Guy + * Almes or Matt Mathis. I don't know (or care) who came up with + * the idea first. I envy the originators' perspicacity and I'm + * glad they didn't keep the idea a secret. + * + * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or + * enhancements to the original distribution. + * + * I've hacked up a round-trip-route version of this that works by + * sending a loose-source-routed udp datagram through the destination + * back to yourself. Unfortunately, SO many gateways botch source + * routing, the thing is almost worthless. Maybe one day... + * + * -- Van Jacobson (van@helios.ee.lbl.gov) + * Tue Dec 20 03:50:13 PST 1988 + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> + +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/udp.h> + +#include <arpa/inet.h> + +#include <netdb.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define MAXPACKET 65535 /* max ip packet size */ +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#ifndef FD_SET +#define NFDBITS (8*sizeof(fd_set)) +#define FD_SETSIZE NFDBITS +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) +#endif + +#define Fprintf (void)fprintf +#define Sprintf (void)sprintf +#define Printf (void)printf + +/* + * format of a (udp) probe packet. + */ +struct opacket { + struct ip ip; + struct udphdr udp; + u_char seq; /* sequence number of this packet */ + u_char ttl; /* ttl packet left with */ + struct timeval tv; /* time packet left */ +}; + +u_char packet[512]; /* last inbound (icmp) packet */ +struct opacket *outpacket; /* last output (udp) packet */ + +int wait_for_reply __P((int, struct sockaddr_in *)); +void send_probe __P((int, int)); +double deltaT __P((struct timeval *, struct timeval *)); +int packet_ok __P((u_char *, int, struct sockaddr_in *, int)); +void print __P((u_char *, int, struct sockaddr_in *)); +void tvsub __P((struct timeval *, struct timeval *)); +char *inetname __P((struct in_addr)); +void usage __P(()); + +int s; /* receive (icmp) socket file descriptor */ +int sndsock; /* send (udp) socket file descriptor */ +struct timezone tz; /* leftover */ + +struct sockaddr whereto; /* Who to try to reach */ +int datalen; /* How much data */ + +char *source = 0; +char *hostname; + +int nprobes = 3; +int max_ttl = 30; +u_short ident; +u_short port = 32768+666; /* start udp dest port # for probe packets */ +int options; /* socket options */ +int verbose; +int waittime = 5; /* time to wait for response (in seconds) */ +int nflag; /* print addresses numerically */ + +int +main(argc, argv) + int argc; + char *argv[]; +{ + extern char *optarg; + extern int optind; + struct hostent *hp; + struct protoent *pe; + struct sockaddr_in from, *to; + int ch, i, on, probe, seq, tos, ttl; + + on = 1; + seq = tos = 0; + to = (struct sockaddr_in *)&whereto; + while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) + switch(ch) { + case 'd': + options |= SO_DEBUG; + break; + case 'm': + max_ttl = atoi(optarg); + if (max_ttl <= 1) { + Fprintf(stderr, + "traceroute: max ttl must be >1.\n"); + exit(1); + } + break; + case 'n': + nflag++; + break; + case 'p': + port = atoi(optarg); + if (port < 1) { + Fprintf(stderr, + "traceroute: port must be >0.\n"); + exit(1); + } + break; + case 'q': + nprobes = atoi(optarg); + if (nprobes < 1) { + Fprintf(stderr, + "traceroute: nprobes must be >0.\n"); + exit(1); + } + break; + case 'r': + options |= SO_DONTROUTE; + break; + case 's': + /* + * set the ip source address of the outbound + * probe (e.g., on a multi-homed host). + */ + source = optarg; + break; + case 't': + tos = atoi(optarg); + if (tos < 0 || tos > 255) { + Fprintf(stderr, + "traceroute: tos must be 0 to 255.\n"); + exit(1); + } + break; + case 'v': + verbose++; + break; + case 'w': + waittime = atoi(optarg); + if (waittime <= 1) { + Fprintf(stderr, + "traceroute: wait must be >1 sec.\n"); + exit(1); + } + break; + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 1) + usage(); + + setlinebuf (stdout); + + (void) bzero((char *)&whereto, sizeof(struct sockaddr)); + to->sin_family = AF_INET; + to->sin_addr.s_addr = inet_addr(*argv); + if (to->sin_addr.s_addr != -1) + hostname = *argv; + else { + hp = gethostbyname(*argv); + if (hp) { + to->sin_family = hp->h_addrtype; + bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); + hostname = hp->h_name; + } else { + (void)fprintf(stderr, + "traceroute: unknown host %s\n", *argv); + exit(1); + } + } + if (*++argv) + datalen = atoi(*argv); + if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) { + Fprintf(stderr, + "traceroute: packet size must be 0 <= s < %ld.\n", + MAXPACKET - sizeof(struct opacket)); + exit(1); + } + datalen += sizeof(struct opacket); + outpacket = (struct opacket *)malloc((unsigned)datalen); + if (! outpacket) { + perror("traceroute: malloc"); + exit(1); + } + (void) bzero((char *)outpacket, datalen); + outpacket->ip.ip_dst = to->sin_addr; + outpacket->ip.ip_tos = tos; + outpacket->ip.ip_v = IPVERSION; + outpacket->ip.ip_id = 0; + + ident = (getpid() & 0xffff) | 0x8000; + + if ((pe = getprotobyname("icmp")) == NULL) { + Fprintf(stderr, "icmp: unknown protocol\n"); + exit(10); + } + if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) { + perror("traceroute: icmp socket"); + exit(5); + } + 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 ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { + perror("traceroute: raw socket"); + exit(5); + } +#ifdef SO_SNDBUF + if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, + sizeof(datalen)) < 0) { + perror("traceroute: SO_SNDBUF"); + exit(6); + } +#endif SO_SNDBUF +#ifdef IP_HDRINCL + if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on, + sizeof(on)) < 0) { + perror("traceroute: IP_HDRINCL"); + exit(6); + } +#endif IP_HDRINCL + 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)); + + if (source) { + (void) bzero((char *)&from, sizeof(struct sockaddr)); + from.sin_family = AF_INET; + from.sin_addr.s_addr = inet_addr(source); + if (from.sin_addr.s_addr == -1) { + Printf("traceroute: unknown host %s\n", source); + exit(1); + } + outpacket->ip.ip_src = from.sin_addr; +#ifndef IP_HDRINCL + if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) { + perror ("traceroute: bind:"); + exit (1); + } +#endif IP_HDRINCL + } + + Fprintf(stderr, "traceroute to %s (%s)", hostname, + inet_ntoa(to->sin_addr)); + if (source) + Fprintf(stderr, " from %s", source); + Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); + (void) fflush(stderr); + + for (ttl = 1; ttl <= max_ttl; ++ttl) { + u_long lastaddr = 0; + int got_there = 0; + int unreachable = 0; + + Printf("%2d ", ttl); + for (probe = 0; probe < nprobes; ++probe) { + int cc; + struct timeval t1, t2; + struct timezone tz; + struct ip *ip; + + (void) gettimeofday(&t1, &tz); + send_probe(++seq, ttl); + while (cc = wait_for_reply(s, &from)) { + (void) gettimeofday(&t2, &tz); + if ((i = packet_ok(packet, cc, &from, seq))) { + if (from.sin_addr.s_addr != lastaddr) { + print(packet, cc, &from); + lastaddr = from.sin_addr.s_addr; + } + Printf(" %g ms", deltaT(&t1, &t2)); + switch(i - 1) { + case ICMP_UNREACH_PORT: +#ifndef ARCHAIC + ip = (struct ip *)packet; + if (ip->ip_ttl <= 1) + Printf(" !"); +#endif ARCHAIC + ++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"); + break; + case ICMP_UNREACH_SRCFAIL: + ++unreachable; + Printf(" !S"); + break; + } + break; + } + } + if (cc == 0) + Printf(" *"); + (void) fflush(stdout); + } + putchar('\n'); + if (got_there || unreachable >= nprobes-1) + exit(0); + } +} + +int +wait_for_reply(sock, from) + int sock; + struct sockaddr_in *from; +{ + fd_set fds; + struct timeval wait; + int cc = 0; + int fromlen = sizeof (*from); + + FD_ZERO(&fds); + FD_SET(sock, &fds); + wait.tv_sec = waittime; wait.tv_usec = 0; + + if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) + cc=recvfrom(s, (char *)packet, sizeof(packet), 0, + (struct sockaddr *)from, &fromlen); + + return(cc); +} + + +void +send_probe(seq, ttl) + int seq, ttl; +{ + struct opacket *op = outpacket; + struct ip *ip = &op->ip; + struct udphdr *up = &op->udp; + int i; + + ip->ip_off = 0; + ip->ip_hl = sizeof(*ip) >> 2; + ip->ip_p = IPPROTO_UDP; + ip->ip_len = datalen; + ip->ip_ttl = ttl; + ip->ip_v = IPVERSION; + ip->ip_id = htons(ident+seq); + + up->uh_sport = htons(ident); + up->uh_dport = htons(port+seq); + up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip))); + up->uh_sum = 0; + + op->seq = seq; + op->ttl = ttl; + (void) gettimeofday(&op->tv, &tz); + + i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, + sizeof(struct sockaddr)); + if (i < 0 || i != datalen) { + if (i<0) + perror("sendto"); + Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, + datalen, i); + (void) fflush(stdout); + } +} + + +double +deltaT(t1p, t2p) + struct timeval *t1p, *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(t) + 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(buf, cc, from, seq) + u_char *buf; + int cc; + struct sockaddr_in *from; + int seq; +{ + register struct icmp *icp; + u_char type, code; + int hlen; +#ifndef ARCHAIC + struct ip *ip; + + ip = (struct ip *) buf; + hlen = ip->ip_hl << 2; + if (cc < hlen + ICMP_MINLEN) { + if (verbose) + Printf("packet too short (%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 ARCHAIC + type = icp->icmp_type; code = icp->icmp_code; + if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || + type == ICMP_UNREACH) { + struct ip *hip; + struct udphdr *up; + + hip = &icp->icmp_ip; + hlen = hip->ip_hl << 2; + up = (struct udphdr *)((u_char *)hip + hlen); + if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && + up->uh_sport == htons(ident) && + up->uh_dport == htons(port+seq)) + return (type == ICMP_TIMXCEED? -1 : code+1); + } +#ifndef ARCHAIC + if (verbose) { + int i; + u_long *lp = (u_long *)&icp->icmp_ip; + + Printf("\n%d bytes from %s to %s", cc, + inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst)); + Printf(": icmp type %d (%s) code %d\n", type, pr_type(type), + icp->icmp_code); + for (i = 4; i < cc ; i += sizeof(long)) + Printf("%2d: x%8.8lx\n", i, *lp++); + } +#endif ARCHAIC + return(0); +} + + +void +print(buf, cc, from) + u_char *buf; + int cc; + struct sockaddr_in *from; +{ + struct ip *ip; + int hlen; + + ip = (struct ip *) buf; + hlen = ip->ip_hl << 2; + cc -= hlen; + + 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)); +} + + +#ifdef notyet +/* + * Checksum routine for Internet Protocol family headers (C Version) + */ +u_short +in_cksum(addr, len) + u_short *addr; + 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); +} +#endif notyet + +/* + * Subtract 2 timeval structs: out = out - in. + * Out is assumed to be >= in. + */ +void +tvsub(out, in) + register struct timeval *out, *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(in) + struct in_addr in; +{ + register char *cp; + static char line[50]; + struct hostent *hp; + static char domain[MAXHOSTNAMELEN + 1]; + static int first = 1; + + if (first && !nflag) { + first = 0; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = index(domain, '.'))) + (void) strcpy(domain, cp + 1); + else + domain[0] = 0; + } + cp = 0; + if (!nflag && in.s_addr != INADDR_ANY) { + hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); + if (hp) { + if ((cp = index(hp->h_name, '.')) && + !strcmp(cp + 1, domain)) + *cp = 0; + cp = hp->h_name; + } + } + if (cp) + (void) strcpy(line, cp); + else { + in.s_addr = ntohl(in.s_addr); +#define C(x) ((x) & 0xff) + Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24), + C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); + } + return (line); +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\ +[-s src_addr] [-t tos] [-w wait] host [data size]\n"); + exit(1); +} |