1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Van Jacobson.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1990 The Regents of the University of California.\n\
40  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 static char sccsid[] = "@(#)traceroute.c	5.4 (Berkeley) 5/15/90";
45 #endif /* not lint */
46 
47 /*
48  * traceroute host  - trace the route ip packets follow going to "host".
49  *
50  * Attempt to trace the route an ip packet would follow to some
51  * internet host.  We find out intermediate hops by launching probe
52  * packets with a small ttl (time to live) then listening for an
53  * icmp "time exceeded" reply from a gateway.  We start our probes
54  * with a ttl of one and increase by one until we get an icmp "port
55  * unreachable" (which means we got to "host") or hit a max (which
56  * defaults to 30 hops & can be changed with the -m flag).  Three
57  * probes (change with -q flag) are sent at each ttl setting and a
58  * line is printed showing the ttl, address of the gateway and
59  * round trip time of each probe.  If the probe answers come from
60  * different gateways, the address of each responding system will
61  * be printed.  If there is no response within a 5 sec. timeout
62  * interval (changed with the -w flag), a "*" is printed for that
63  * probe.
64  *
65  * Probe packets are UDP format.  We don't want the destination
66  * host to process them so the destination port is set to an
67  * unlikely value (if some clod on the destination is using that
68  * value, it can be changed with the -p flag).
69  *
70  * A sample use might be:
71  *
72  *     [yak 71]% traceroute nis.nsf.net.
73  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
74  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
75  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
76  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
77  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
78  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
79  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
80  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
81  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
82  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
83  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
84  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
85  *
86  * Note that lines 2 & 3 are the same.  This is due to a buggy
87  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
88  * packets with a zero ttl.
89  *
90  * A more interesting example is:
91  *
92  *     [yak 72]% traceroute allspice.lcs.mit.edu.
93  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
94  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
95  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
96  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
97  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
98  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
99  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
100  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
101  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
102  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
103  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
104  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
105  *     12  * * *
106  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
107  *     14  * * *
108  *     15  * * *
109  *     16  * * *
110  *     17  * * *
111  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
112  *
113  * (I start to see why I'm having so much trouble with mail to
114  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
115  * either don't send ICMP "time exceeded" messages or send them
116  * with a ttl too small to reach us.  14 - 17 are running the
117  * MIT C Gateway code that doesn't send "time exceeded"s.  God
118  * only knows what's going on with 12.
119  *
120  * The silent gateway 12 in the above may be the result of a bug in
121  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
122  * sends an unreachable message using whatever ttl remains in the
123  * original datagram.  Since, for gateways, the remaining ttl is
124  * zero, the icmp "time exceeded" is guaranteed to not make it back
125  * to us.  The behavior of this bug is slightly more interesting
126  * when it appears on the destination system:
127  *
128  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
129  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
130  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
131  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
132  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
133  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
134  *      7  * * *
135  *      8  * * *
136  *      9  * * *
137  *     10  * * *
138  *     11  * * *
139  *     12  * * *
140  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
141  *
142  * Notice that there are 12 "gateways" (13 is the final
143  * destination) and exactly the last half of them are "missing".
144  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
145  * is using the ttl from our arriving datagram as the ttl in its
146  * icmp reply.  So, the reply will time out on the return path
147  * (with no notice sent to anyone since icmp's aren't sent for
148  * icmp's) until we probe with a ttl that's at least twice the path
149  * length.  I.e., rip is really only 7 hops away.  A reply that
150  * returns with a ttl of 1 is a clue this problem exists.
151  * Traceroute prints a "!" after the time if the ttl is <= 1.
152  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
153  * non-standard (HPUX) software, expect to see this problem
154  * frequently and/or take care picking the target host of your
155  * probes.
156  *
157  * Other possible annotations after the time are !H, !N, !P (got a host,
158  * network or protocol unreachable, respectively), !S or !F (source
159  * route failed or fragmentation needed -- neither of these should
160  * ever occur and the associated gateway is busted if you see one).  If
161  * almost all the probes result in some kind of unreachable, traceroute
162  * will give up and exit.
163  *
164  * Notes
165  * -----
166  * This program must be run by root or be setuid.  (I suggest that
167  * you *don't* make it setuid -- casual use could result in a lot
168  * of unnecessary traffic on our poor, congested nets.)
169  *
170  * This program requires a kernel mod that does not appear in any
171  * system available from Berkeley:  A raw ip socket using proto
172  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
173  * opposed to data to be wrapped in a ip datagram).  See the README
174  * file that came with the source to this program for a description
175  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
176  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
177  * MODIFIED TO RUN THIS PROGRAM.
178  *
179  * The udp port usage may appear bizarre (well, ok, it is bizarre).
180  * The problem is that an icmp message only contains 8 bytes of
181  * data from the original datagram.  8 bytes is the size of a udp
182  * header so, if we want to associate replies with the original
183  * datagram, the necessary information must be encoded into the
184  * udp header (the ip id could be used but there's no way to
185  * interlock with the kernel's assignment of ip id's and, anyway,
186  * it would have taken a lot more kernel hacking to allow this
187  * code to set the ip id).  So, to allow two or more users to
188  * use traceroute simultaneously, we use this task's pid as the
189  * source port (the high bit is set to move the port number out
190  * of the "likely" range).  To keep track of which probe is being
191  * replied to (so times and/or hop counts don't get confused by a
192  * reply that was delayed in transit), we increment the destination
193  * port number before each probe.
194  *
195  * Don't use this as a coding example.  I was trying to find a
196  * routing problem and this code sort-of popped out after 48 hours
197  * without sleep.  I was amazed it ever compiled, much less ran.
198  *
199  * I stole the idea for this program from Steve Deering.  Since
200  * the first release, I've learned that had I attended the right
201  * IETF working group meetings, I also could have stolen it from Guy
202  * Almes or Matt Mathis.  I don't know (or care) who came up with
203  * the idea first.  I envy the originators' perspicacity and I'm
204  * glad they didn't keep the idea a secret.
205  *
206  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
207  * enhancements to the original distribution.
208  *
209  * I've hacked up a round-trip-route version of this that works by
210  * sending a loose-source-routed udp datagram through the destination
211  * back to yourself.  Unfortunately, SO many gateways botch source
212  * routing, the thing is almost worthless.  Maybe one day...
213  *
214  *  -- Van Jacobson (van@helios.ee.lbl.gov)
215  *     Tue Dec 20 03:50:13 PST 1988
216  */
217 
218 #include <sys/param.h>
219 #include <sys/time.h>
220 #include <sys/socket.h>
221 #include <sys/file.h>
222 #include <sys/ioctl.h>
223 
224 #include <netinet/in_systm.h>
225 #include <netinet/in.h>
226 #include <netinet/ip.h>
227 #include <netinet/ip_icmp.h>
228 #include <netinet/udp.h>
229 #include <netdb.h>
230 
231 #include <stdio.h>
232 #include <errno.h>
233 #include <string.h>
234 
235 #define	MAXPACKET	65535	/* max ip packet size */
236 #ifndef MAXHOSTNAMELEN
237 #define MAXHOSTNAMELEN	64
238 #endif
239 
240 #ifndef FD_SET
241 #define NFDBITS         (8*sizeof(fd_set))
242 #define FD_SETSIZE      NFDBITS
243 #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
244 #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
245 #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
246 #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
247 #endif
248 
249 #define Fprintf (void)fprintf
250 #define Sprintf (void)sprintf
251 #define Printf (void)printf
252 extern	int errno;
253 extern  char *malloc();
254 extern  char *inet_ntoa();
255 extern  u_long inet_addr();
256 
257 /*
258  * format of a (udp) probe packet.
259  */
260 struct opacket {
261 	struct ip ip;
262 	struct udphdr udp;
263 	u_char seq;		/* sequence number of this packet */
264 	u_char ttl;		/* ttl packet left with */
265 	struct timeval tv;	/* time packet left */
266 };
267 
268 u_char	packet[512];		/* last inbound (icmp) packet */
269 struct opacket	*outpacket;	/* last output (udp) packet */
270 char *inetname();
271 
272 int s;				/* receive (icmp) socket file descriptor */
273 int sndsock;			/* send (udp) socket file descriptor */
274 struct timezone tz;		/* leftover */
275 
276 struct sockaddr whereto;	/* Who to try to reach */
277 int datalen;			/* How much data */
278 
279 char *source = 0;
280 char *hostname;
281 
282 int nprobes = 3;
283 int max_ttl = 30;
284 u_short ident;
285 u_short port = 32768+666;	/* start udp dest port # for probe packets */
286 int options;			/* socket options */
287 int verbose;
288 int waittime = 5;		/* time to wait for response (in seconds) */
289 int nflag;			/* print addresses numerically */
290 
main(argc,argv)291 main(argc, argv)
292 	char *argv[];
293 {
294 	extern char *optarg;
295 	extern int optind;
296 	struct hostent *hp;
297 	struct protoent *pe;
298 	struct sockaddr_in from, *to;
299 	int ch, i, on, probe, seq, tos, ttl;
300 
301 	on = 1;
302 	seq = tos = 0;
303 	to = (struct sockaddr_in *)&whereto;
304 	while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
305 		switch(ch) {
306 		case 'd':
307 			options |= SO_DEBUG;
308 			break;
309 		case 'm':
310 			max_ttl = atoi(optarg);
311 			if (max_ttl <= 1) {
312 				Fprintf(stderr,
313 				    "traceroute: max ttl must be >1.\n");
314 				exit(1);
315 			}
316 			break;
317 		case 'n':
318 			nflag++;
319 			break;
320 		case 'p':
321 			port = atoi(optarg);
322 			if (port < 1) {
323 				Fprintf(stderr,
324 				    "traceroute: port must be >0.\n");
325 				exit(1);
326 			}
327 			break;
328 		case 'q':
329 			nprobes = atoi(optarg);
330 			if (nprobes < 1) {
331 				Fprintf(stderr,
332 				    "traceroute: nprobes must be >0.\n");
333 				exit(1);
334 			}
335 			break;
336 		case 'r':
337 			options |= SO_DONTROUTE;
338 			break;
339 		case 's':
340 			/*
341 			 * set the ip source address of the outbound
342 			 * probe (e.g., on a multi-homed host).
343 			 */
344 			source = optarg;
345 			break;
346 		case 't':
347 			tos = atoi(optarg);
348 			if (tos < 0 || tos > 255) {
349 				Fprintf(stderr,
350 				    "traceroute: tos must be 0 to 255.\n");
351 				exit(1);
352 			}
353 			break;
354 		case 'v':
355 			verbose++;
356 			break;
357 		case 'w':
358 			waittime = atoi(optarg);
359 			if (waittime <= 1) {
360 				Fprintf(stderr,
361 				    "traceroute: wait must be >1 sec.\n");
362 				exit(1);
363 			}
364 			break;
365 		default:
366 			usage();
367 		}
368 	argc -= optind;
369 	argv += optind;
370 
371 	if (argc < 1)
372 		usage();
373 
374 	setlinebuf (stdout);
375 
376 	(void) bzero((char *)&whereto, sizeof(struct sockaddr));
377 	to->sin_family = AF_INET;
378 	to->sin_addr.s_addr = inet_addr(*argv);
379 	if (to->sin_addr.s_addr != -1)
380 		hostname = *argv;
381 	else {
382 		hp = gethostbyname(*argv);
383 		if (hp) {
384 			to->sin_family = hp->h_addrtype;
385 			bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
386 			hostname = hp->h_name;
387 		} else {
388 			(void)fprintf(stderr,
389 			    "traceroute: unknown host %s\n", *argv);
390 			exit(1);
391 		}
392 	}
393 	if (*++argv)
394 		datalen = atoi(*argv);
395 	if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
396 		Fprintf(stderr,
397 		    "traceroute: packet size must be 0 <= s < %ld.\n",
398 		    MAXPACKET - sizeof(struct opacket));
399 		exit(1);
400 	}
401 	datalen += sizeof(struct opacket);
402 	outpacket = (struct opacket *)malloc((unsigned)datalen);
403 	if (! outpacket) {
404 		perror("traceroute: malloc");
405 		exit(1);
406 	}
407 	(void) bzero((char *)outpacket, datalen);
408 	outpacket->ip.ip_dst = to->sin_addr;
409 	outpacket->ip.ip_tos = tos;
410 
411 	ident = (getpid() & 0xffff) | 0x8000;
412 
413 	if ((pe = getprotobyname("icmp")) == NULL) {
414 		Fprintf(stderr, "icmp: unknown protocol\n");
415 		exit(10);
416 	}
417 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
418 		perror("traceroute: icmp socket");
419 		exit(5);
420 	}
421 	if (options & SO_DEBUG)
422 		(void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
423 				  (char *)&on, sizeof(on));
424 	if (options & SO_DONTROUTE)
425 		(void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
426 				  (char *)&on, sizeof(on));
427 
428 	if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
429 		perror("traceroute: raw socket");
430 		exit(5);
431 	}
432 #ifdef SO_SNDBUF
433 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
434 		       sizeof(datalen)) < 0) {
435 		perror("traceroute: SO_SNDBUF");
436 		exit(6);
437 	}
438 #endif SO_SNDBUF
439 #ifdef IP_HDRINCL
440 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
441 		       sizeof(on)) < 0) {
442 		perror("traceroute: IP_HDRINCL");
443 		exit(6);
444 	}
445 #endif IP_HDRINCL
446 	if (options & SO_DEBUG)
447 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
448 				  (char *)&on, sizeof(on));
449 	if (options & SO_DONTROUTE)
450 		(void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
451 				  (char *)&on, sizeof(on));
452 
453 	if (source) {
454 		(void) bzero((char *)&from, sizeof(struct sockaddr));
455 		from.sin_family = AF_INET;
456 		from.sin_addr.s_addr = inet_addr(source);
457 		if (from.sin_addr.s_addr == -1) {
458 			Printf("traceroute: unknown host %s\n", source);
459 			exit(1);
460 		}
461 		outpacket->ip.ip_src = from.sin_addr;
462 #ifndef IP_HDRINCL
463 		if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
464 			perror ("traceroute: bind:");
465 			exit (1);
466 		}
467 #endif IP_HDRINCL
468 	}
469 
470 	Fprintf(stderr, "traceroute to %s (%s)", hostname,
471 		inet_ntoa(to->sin_addr));
472 	if (source)
473 		Fprintf(stderr, " from %s", source);
474 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
475 	(void) fflush(stderr);
476 
477 	for (ttl = 1; ttl <= max_ttl; ++ttl) {
478 		u_long lastaddr = 0;
479 		int got_there = 0;
480 		int unreachable = 0;
481 
482 		Printf("%2d ", ttl);
483 		for (probe = 0; probe < nprobes; ++probe) {
484 			int cc;
485 			struct timeval tv;
486 			struct ip *ip;
487 
488 			(void) gettimeofday(&tv, &tz);
489 			send_probe(++seq, ttl);
490 			while (cc = wait_for_reply(s, &from)) {
491 				if ((i = packet_ok(packet, cc, &from, seq))) {
492 					int dt = deltaT(&tv);
493 					if (from.sin_addr.s_addr != lastaddr) {
494 						print(packet, cc, &from);
495 						lastaddr = from.sin_addr.s_addr;
496 					}
497 					Printf("  %d ms", dt);
498 					switch(i - 1) {
499 					case ICMP_UNREACH_PORT:
500 #ifndef ARCHAIC
501 						ip = (struct ip *)packet;
502 						if (ip->ip_ttl <= 1)
503 							Printf(" !");
504 #endif ARCHAIC
505 						++got_there;
506 						break;
507 					case ICMP_UNREACH_NET:
508 						++unreachable;
509 						Printf(" !N");
510 						break;
511 					case ICMP_UNREACH_HOST:
512 						++unreachable;
513 						Printf(" !H");
514 						break;
515 					case ICMP_UNREACH_PROTOCOL:
516 						++got_there;
517 						Printf(" !P");
518 						break;
519 					case ICMP_UNREACH_NEEDFRAG:
520 						++unreachable;
521 						Printf(" !F");
522 						break;
523 					case ICMP_UNREACH_SRCFAIL:
524 						++unreachable;
525 						Printf(" !S");
526 						break;
527 					}
528 					break;
529 				}
530 			}
531 			if (cc == 0)
532 				Printf(" *");
533 			(void) fflush(stdout);
534 		}
535 		putchar('\n');
536 		if (got_there || unreachable >= nprobes-1)
537 			exit(0);
538 	}
539 }
540 
wait_for_reply(sock,from)541 wait_for_reply(sock, from)
542 	int sock;
543 	struct sockaddr_in *from;
544 {
545 	fd_set fds;
546 	struct timeval wait;
547 	int cc = 0;
548 	int fromlen = sizeof (*from);
549 
550 	FD_ZERO(&fds);
551 	FD_SET(sock, &fds);
552 	wait.tv_sec = waittime; wait.tv_usec = 0;
553 
554 	if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
555 		cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
556 			    (struct sockaddr *)from, &fromlen);
557 
558 	return(cc);
559 }
560 
561 
send_probe(seq,ttl)562 send_probe(seq, ttl)
563 {
564 	struct opacket *op = outpacket;
565 	struct ip *ip = &op->ip;
566 	struct udphdr *up = &op->udp;
567 	int i;
568 
569 	ip->ip_off = 0;
570 	ip->ip_p = IPPROTO_UDP;
571 	ip->ip_len = datalen;
572 	ip->ip_ttl = ttl;
573 
574 	up->uh_sport = htons(ident);
575 	up->uh_dport = htons(port+seq);
576 	up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
577 	up->uh_sum = 0;
578 
579 	op->seq = seq;
580 	op->ttl = ttl;
581 	(void) gettimeofday(&op->tv, &tz);
582 
583 	i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
584 		   sizeof(struct sockaddr));
585 	if (i < 0 || i != datalen)  {
586 		if (i<0)
587 			perror("sendto");
588 		Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
589 			datalen, i);
590 		(void) fflush(stdout);
591 	}
592 }
593 
594 
595 deltaT(tp)
596 	struct timeval *tp;
597 {
598 	struct timeval tv;
599 
600 	(void) gettimeofday(&tv, &tz);
601 	tvsub(&tv, tp);
602 	return (tv.tv_sec*1000 + (tv.tv_usec + 500)/1000);
603 }
604 
605 
606 /*
607  * Convert an ICMP "type" field to a printable string.
608  */
609 char *
pr_type(t)610 pr_type(t)
611 	u_char t;
612 {
613 	static char *ttab[] = {
614 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
615 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
616 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
617 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
618 	"Info Reply"
619 	};
620 
621 	if(t > 16)
622 		return("OUT-OF-RANGE");
623 
624 	return(ttab[t]);
625 }
626 
627 
packet_ok(buf,cc,from,seq)628 packet_ok(buf, cc, from, seq)
629 	u_char *buf;
630 	int cc;
631 	struct sockaddr_in *from;
632 	int seq;
633 {
634 	register struct icmp *icp;
635 	u_char type, code;
636 	int hlen;
637 #ifndef ARCHAIC
638 	struct ip *ip;
639 
640 	ip = (struct ip *) buf;
641 	hlen = ip->ip_hl << 2;
642 	if (cc < hlen + ICMP_MINLEN) {
643 		if (verbose)
644 			Printf("packet too short (%d bytes) from %s\n", cc,
645 				inet_ntoa(from->sin_addr));
646 		return (0);
647 	}
648 	cc -= hlen;
649 	icp = (struct icmp *)(buf + hlen);
650 #else
651 	icp = (struct icmp *)buf;
652 #endif ARCHAIC
653 	type = icp->icmp_type; code = icp->icmp_code;
654 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
655 	    type == ICMP_UNREACH) {
656 		struct ip *hip;
657 		struct udphdr *up;
658 
659 		hip = &icp->icmp_ip;
660 		hlen = hip->ip_hl << 2;
661 		up = (struct udphdr *)((u_char *)hip + hlen);
662 		if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
663 		    up->uh_sport == htons(ident) &&
664 		    up->uh_dport == htons(port+seq))
665 			return (type == ICMP_TIMXCEED? -1 : code+1);
666 	}
667 #ifndef ARCHAIC
668 	if (verbose) {
669 		int i;
670 		u_long *lp = (u_long *)&icp->icmp_ip;
671 
672 		Printf("\n%d bytes from %s to %s", cc,
673 			inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
674 		Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
675 		       icp->icmp_code);
676 		for (i = 4; i < cc ; i += sizeof(long))
677 			Printf("%2d: x%8.8lx\n", i, *lp++);
678 	}
679 #endif ARCHAIC
680 	return(0);
681 }
682 
683 
print(buf,cc,from)684 print(buf, cc, from)
685 	u_char *buf;
686 	int cc;
687 	struct sockaddr_in *from;
688 {
689 	struct ip *ip;
690 	int hlen;
691 
692 	ip = (struct ip *) buf;
693 	hlen = ip->ip_hl << 2;
694 	cc -= hlen;
695 
696 	if (nflag)
697 		Printf(" %s", inet_ntoa(from->sin_addr));
698 	else
699 		Printf(" %s (%s)", inetname(from->sin_addr),
700 		       inet_ntoa(from->sin_addr));
701 
702 	if (verbose)
703 		Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
704 }
705 
706 
707 #ifdef notyet
708 /*
709  * Checksum routine for Internet Protocol family headers (C Version)
710  */
in_cksum(addr,len)711 in_cksum(addr, len)
712 u_short *addr;
713 int len;
714 {
715 	register int nleft = len;
716 	register u_short *w = addr;
717 	register u_short answer;
718 	register int sum = 0;
719 
720 	/*
721 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
722 	 *  we add sequential 16 bit words to it, and at the end, fold
723 	 *  back all the carry bits from the top 16 bits into the lower
724 	 *  16 bits.
725 	 */
726 	while (nleft > 1)  {
727 		sum += *w++;
728 		nleft -= 2;
729 	}
730 
731 	/* mop up an odd byte, if necessary */
732 	if (nleft == 1)
733 		sum += *(u_char *)w;
734 
735 	/*
736 	 * add back carry outs from top 16 bits to low 16 bits
737 	 */
738 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
739 	sum += (sum >> 16);			/* add carry */
740 	answer = ~sum;				/* truncate to 16 bits */
741 	return (answer);
742 }
743 #endif notyet
744 
745 /*
746  * Subtract 2 timeval structs:  out = out - in.
747  * Out is assumed to be >= in.
748  */
tvsub(out,in)749 tvsub(out, in)
750 register struct timeval *out, *in;
751 {
752 	if ((out->tv_usec -= in->tv_usec) < 0)   {
753 		out->tv_sec--;
754 		out->tv_usec += 1000000;
755 	}
756 	out->tv_sec -= in->tv_sec;
757 }
758 
759 
760 /*
761  * Construct an Internet address representation.
762  * If the nflag has been supplied, give
763  * numeric value, otherwise try for symbolic name.
764  */
765 char *
inetname(in)766 inetname(in)
767 	struct in_addr in;
768 {
769 	register char *cp;
770 	static char line[50];
771 	struct hostent *hp;
772 	static char domain[MAXHOSTNAMELEN + 1];
773 	static int first = 1;
774 
775 	if (first && !nflag) {
776 		first = 0;
777 		if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
778 		    (cp = index(domain, '.')))
779 			(void) strcpy(domain, cp + 1);
780 		else
781 			domain[0] = 0;
782 	}
783 	cp = 0;
784 	if (!nflag && in.s_addr != INADDR_ANY) {
785 		hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
786 		if (hp) {
787 			if ((cp = index(hp->h_name, '.')) &&
788 			    !strcmp(cp + 1, domain))
789 				*cp = 0;
790 			cp = hp->h_name;
791 		}
792 	}
793 	if (cp)
794 		(void) strcpy(line, cp);
795 	else {
796 		in.s_addr = ntohl(in.s_addr);
797 #define C(x)	((x) & 0xff)
798 		Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
799 			C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
800 	}
801 	return (line);
802 }
803 
usage()804 usage()
805 {
806 	(void)fprintf(stderr,
807 "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
808 [-s src_addr] [-t tos] [-w wait] host [data size]\n");
809 	exit(1);
810 }
811