
Fri Oct 28 13:40:27 EDT 1994

Updates to traceroute in this release:

This release of traceroute is an updated version of Van Jacobson's
1988 release of the tool.  It includes all of the original features,
plus a number of things locally added at the PSC, and several
additions suggested by people on the NANOG list:

(Note:  none of this is in the included man page; writing nroff has
never been my can of worms...)

LSRR:  (-g)  This option has been around for a while, and has started
to work its way into vendor versions of traceroute.  It allows you to
add additional points in the path, giving the ability to (for example)
traceroute to somewhere and back (so you can see the return path).  It
is particularly useful in debugging split-routing type problems.  Note
that you can put as many -g options in a traceroute as you want, up to
the limit of the IP options space in the header.

MTU Discovery:  (-M)  This option runs the algorithm in RFC1191 over
the path in question.  Every packet is send out with the Don't
Fragment bit set, and where necessary the packet size is reduced as
per RFC1191.

Statistics Collection:  (-Q)  This option reports the statistics on
delay, (min, max, avg, and std. dev) instead of reporting individual
transfer times.  It should be used with -q to send lots of packets to
each hop to get good statistics.  

Microsecond Timers:  (-u)  This option reports times to microsecond
accuracy (the default is millisecond accuracy).

A warning about timers: Many machines have clocks with relatively
large granularities.  I made no effort to do any better than what the
standard system clock does.  Thus, in many cases, printing extra
digits is of little use.  Also, some systems seem to do things like
interrupt for screen writes, (which inconveniently can occur in the
middle of timing a packet), causing further skew.  Still, on a quiet
system, this may provide useful additional information.

Loss Detection:  (-a)  Goes onto the next TTL if 10 consecutive
packets are dropped.  Control C (or whatever your interrupt character
is) will do the same thing if you want to get on to the next hop.

Owner Reporting:  (-O)  Matt wanted to know an email address for every
hop, so I added the code to do it.  The addresses are taken from DNS
SOA records, and usually have an address like
"hostmaster@foo.bar.baz".  If you are using this for trouble
reporting, it might be wise to look for an address like "noc" or
"trouble" first, but at least this give a valid mail host and an
address guaranteed to work if nothing else does.

AS Path Lookup:  (-A)  This is what prtraceroute does.  It isn't
implemented yet, though...  I'd like to put it in on the next
go-round.

Other changes:

I changed the way packet sizes get allocated.  If you specify a number
of bytes on the command line, that is how big the entire packet will
be, not just the data.  This is due to problems with the -g option
(which changes the header length) and the -M option, which requires
packets to really be the size you say they are (and not 40 bytes
bigger).  If the packet size you ask for is too small, traceroute will
silently make it the minimum size.

The -w option will now default to 3 seconds and allow you to specify
wait times of < 1 second (i.e. .5 sec).  This is for those who get
sick of waiting for the *'s to show up...

All of the changes have been tested to some degree under Ultrix and
IRIX.  I hope that most of the bugs are out of them, but if there are
bugs on other OS's I'll update the release accordingly.  Happy
tracing!

--Jamshid

Original README below:

======================================================================

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);
}
