Home | History | Annotate | Line # | Download | only in traceroute
traceroute.c revision 1.38
      1 /*	$NetBSD: traceroute.c,v 1.38 2000/01/25 16:24:32 sommerfeld Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that: (1) source code distributions
      9  * retain the above copyright notice and this paragraph in its entirety, (2)
     10  * distributions including binary code include the above copyright notice and
     11  * this paragraph in its entirety in the documentation or other materials
     12  * provided with the distribution, and (3) all advertising materials mentioning
     13  * features or use of this software display the following acknowledgement:
     14  * ``This product includes software developed by the University of California,
     15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     16  * the University nor the names of its contributors may be used to endorse
     17  * or promote products derived from this software without specific prior
     18  * written permission.
     19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     22  */
     23 
     24 #include <sys/cdefs.h>
     25 #ifndef lint
     26 #if 0
     27 static const char rcsid[] =
     28     "@(#)Header: traceroute.c,v 1.49 97/06/13 02:30:23 leres Exp  (LBL)";
     29 #else
     30 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997\n\
     31 The Regents of the University of California.  All rights reserved.\n");
     32 __RCSID("$NetBSD: traceroute.c,v 1.38 2000/01/25 16:24:32 sommerfeld Exp $");
     33 #endif
     34 #endif
     35 
     36 /*
     37  * traceroute host  - trace the route ip packets follow going to "host".
     38  *
     39  * Attempt to trace the route an ip packet would follow to some
     40  * internet host.  We find out intermediate hops by launching probe
     41  * packets with a small ttl (time to live) then listening for an
     42  * icmp "time exceeded" reply from a gateway.  We start our probes
     43  * with a ttl of one and increase by one until we get an icmp "port
     44  * unreachable" (which means we got to "host") or hit a max (which
     45  * defaults to 30 hops & can be changed with the -m flag).  Three
     46  * probes (change with -q flag) are sent at each ttl setting and a
     47  * line is printed showing the ttl, address of the gateway and
     48  * round trip time of each probe.  If the probe answers come from
     49  * different gateways, the address of each responding system will
     50  * be printed.  If there is no response within a 5 sec. timeout
     51  * interval (changed with the -w flag), a "*" is printed for that
     52  * probe.
     53  *
     54  * Probe packets are UDP format.  We don't want the destination
     55  * host to process them so the destination port is set to an
     56  * unlikely value (if some clod on the destination is using that
     57  * value, it can be changed with the -p flag).
     58  *
     59  * A sample use might be:
     60  *
     61  *     [yak 71]% traceroute nis.nsf.net.
     62  *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
     63  *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
     64  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
     65  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
     66  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
     67  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
     68  *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
     69  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
     70  *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
     71  *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
     72  *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
     73  *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
     74  *
     75  * Note that lines 2 & 3 are the same.  This is due to a buggy
     76  * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
     77  * packets with a zero ttl.
     78  *
     79  * A more interesting example is:
     80  *
     81  *     [yak 72]% traceroute allspice.lcs.mit.edu.
     82  *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
     83  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
     84  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
     85  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
     86  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
     87  *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
     88  *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
     89  *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
     90  *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
     91  *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
     92  *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
     93  *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
     94  *     12  * * *
     95  *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
     96  *     14  * * *
     97  *     15  * * *
     98  *     16  * * *
     99  *     17  * * *
    100  *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
    101  *
    102  * (I start to see why I'm having so much trouble with mail to
    103  * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
    104  * either don't send ICMP "time exceeded" messages or send them
    105  * with a ttl too small to reach us.  14 - 17 are running the
    106  * MIT C Gateway code that doesn't send "time exceeded"s.  God
    107  * only knows what's going on with 12.
    108  *
    109  * The silent gateway 12 in the above may be the result of a bug in
    110  * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
    111  * sends an unreachable message using whatever ttl remains in the
    112  * original datagram.  Since, for gateways, the remaining ttl is
    113  * zero, the icmp "time exceeded" is guaranteed to not make it back
    114  * to us.  The behavior of this bug is slightly more interesting
    115  * when it appears on the destination system:
    116  *
    117  *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
    118  *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
    119  *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
    120  *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
    121  *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
    122  *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
    123  *      7  * * *
    124  *      8  * * *
    125  *      9  * * *
    126  *     10  * * *
    127  *     11  * * *
    128  *     12  * * *
    129  *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
    130  *
    131  * Notice that there are 12 "gateways" (13 is the final
    132  * destination) and exactly the last half of them are "missing".
    133  * What's really happening is that rip (a Sun-3 running Sun OS3.5)
    134  * is using the ttl from our arriving datagram as the ttl in its
    135  * icmp reply.  So, the reply will time out on the return path
    136  * (with no notice sent to anyone since icmp's aren't sent for
    137  * icmp's) until we probe with a ttl that's at least twice the path
    138  * length.  I.e., rip is really only 7 hops away.  A reply that
    139  * returns with a ttl of 1 is a clue this problem exists.
    140  * Traceroute prints a "!" after the time if the ttl is <= 1.
    141  * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
    142  * non-standard (HPUX) software, expect to see this problem
    143  * frequently and/or take care picking the target host of your
    144  * probes.
    145  *
    146  * Other possible annotations after the time are !H, !N, !P (got a host,
    147  * network or protocol unreachable, respectively), !S or !F (source
    148  * route failed or fragmentation needed -- neither of these should
    149  * ever occur and the associated gateway is busted if you see one).  If
    150  * almost all the probes result in some kind of unreachable, traceroute
    151  * will give up and exit.
    152  *
    153  * Notes
    154  * -----
    155  * This program must be run by root or be setuid.  (I suggest that
    156  * you *don't* make it setuid -- casual use could result in a lot
    157  * of unnecessary traffic on our poor, congested nets.)
    158  *
    159  * This program requires a kernel mod that does not appear in any
    160  * system available from Berkeley:  A raw ip socket using proto
    161  * IPPROTO_RAW must interpret the data sent as an ip datagram (as
    162  * opposed to data to be wrapped in a ip datagram).  See the README
    163  * file that came with the source to this program for a description
    164  * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
    165  * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
    166  * MODIFIED TO RUN THIS PROGRAM.
    167  *
    168  * The udp port usage may appear bizarre (well, ok, it is bizarre).
    169  * The problem is that an icmp message only contains 8 bytes of
    170  * data from the original datagram.  8 bytes is the size of a udp
    171  * header so, if we want to associate replies with the original
    172  * datagram, the necessary information must be encoded into the
    173  * udp header (the ip id could be used but there's no way to
    174  * interlock with the kernel's assignment of ip id's and, anyway,
    175  * it would have taken a lot more kernel hacking to allow this
    176  * code to set the ip id).  So, to allow two or more users to
    177  * use traceroute simultaneously, we use this task's pid as the
    178  * source port (the high bit is set to move the port number out
    179  * of the "likely" range).  To keep track of which probe is being
    180  * replied to (so times and/or hop counts don't get confused by a
    181  * reply that was delayed in transit), we increment the destination
    182  * port number before each probe.
    183  *
    184  * Don't use this as a coding example.  I was trying to find a
    185  * routing problem and this code sort-of popped out after 48 hours
    186  * without sleep.  I was amazed it ever compiled, much less ran.
    187  *
    188  * I stole the idea for this program from Steve Deering.  Since
    189  * the first release, I've learned that had I attended the right
    190  * IETF working group meetings, I also could have stolen it from Guy
    191  * Almes or Matt Mathis.  I don't know (or care) who came up with
    192  * the idea first.  I envy the originators' perspicacity and I'm
    193  * glad they didn't keep the idea a secret.
    194  *
    195  * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
    196  * enhancements to the original distribution.
    197  *
    198  * I've hacked up a round-trip-route version of this that works by
    199  * sending a loose-source-routed udp datagram through the destination
    200  * back to yourself.  Unfortunately, SO many gateways botch source
    201  * routing, the thing is almost worthless.  Maybe one day...
    202  *
    203  *  -- Van Jacobson (van (at) ee.lbl.gov)
    204  *     Tue Dec 20 03:50:13 PST 1988
    205  */
    206 
    207 #include <sys/param.h>
    208 #include <sys/file.h>
    209 #include <sys/ioctl.h>
    210 #ifdef HAVE_SYS_SELECT_H
    211 #include <sys/select.h>
    212 #endif
    213 #include <sys/socket.h>
    214 #include <sys/time.h>
    215 
    216 #include <netinet/in_systm.h>
    217 #include <netinet/in.h>
    218 #include <netinet/ip.h>
    219 #include <netinet/ip_var.h>
    220 #include <netinet/ip_icmp.h>
    221 #include <netinet/udp.h>
    222 #include <netinet/udp_var.h>
    223 
    224 #include <arpa/inet.h>
    225 
    226 #include <ctype.h>
    227 #include <errno.h>
    228 #ifdef HAVE_MALLOC_H
    229 #include <malloc.h>
    230 #endif
    231 #include <memory.h>
    232 #include <netdb.h>
    233 #include <stdio.h>
    234 #include <stdlib.h>
    235 #include <string.h>
    236 #include <unistd.h>
    237 #ifdef IPSEC
    238 #include <net/route.h>
    239 #include <netinet6/ipsec.h>
    240 #endif
    241 
    242 #include "gnuc.h"
    243 #ifdef HAVE_OS_PROTO_H
    244 #include "os-proto.h"
    245 #endif
    246 
    247 #include "ifaddrlist.h"
    248 #include "savestr.h"
    249 
    250 /* Maximum number of gateways (include room for one noop) */
    251 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
    252 
    253 #ifndef MAXHOSTNAMELEN
    254 #define MAXHOSTNAMELEN	64
    255 #endif
    256 
    257 #define Fprintf (void)fprintf
    258 #define Printf (void)printf
    259 
    260 /* Host name and address list */
    261 struct hostinfo {
    262 	char *name;
    263 	int n;
    264 	u_int32_t *addrs;
    265 };
    266 
    267 /* Data section of the probe packet */
    268 struct outdata {
    269 	u_char seq;		/* sequence number of this packet */
    270 	u_char ttl;		/* ttl packet left with */
    271 	struct timeval tv;	/* time packet left */
    272 };
    273 
    274 u_char	packet[512];		/* last inbound (icmp) packet */
    275 
    276 struct ip *outip;		/* last output (udp) packet */
    277 struct udphdr *outudp;		/* last output (udp) packet */
    278 void *outmark;			/* packed location of struct outdata */
    279 struct outdata outsetup;	/* setup and copy for alignment */
    280 
    281 struct icmp *outicmp;		/* last output (icmp) packet */
    282 
    283 /* loose source route gateway list (including room for final destination) */
    284 u_int32_t gwlist[NGATEWAYS + 1];
    285 
    286 int s;				/* receive (icmp) socket file descriptor */
    287 int sndsock;			/* send (udp/icmp) socket file descriptor */
    288 
    289 struct sockaddr whereto;	/* Who to try to reach */
    290 struct sockaddr_in wherefrom;	/* Who we are */
    291 int packlen;			/* total length of packet */
    292 int minpacket;			/* min ip packet size */
    293 int maxpacket = 32 * 1024;	/* max ip packet size */
    294 int printed_ttl = 0;
    295 
    296 char *prog;
    297 char *source;
    298 char *hostname;
    299 char *device;
    300 
    301 int nprobes = 3;
    302 int max_ttl = 30;
    303 int first_ttl = 1;
    304 u_short ident;
    305 u_short port = 32768 + 666;	/* start udp dest port # for probe packets */
    306 
    307 int options;			/* socket options */
    308 int verbose;
    309 int waittime = 5;		/* time to wait for response (in seconds) */
    310 int nflag;			/* print addresses numerically */
    311 int dump;
    312 int useicmp;			/* use icmp echo instead of udp packets */
    313 #ifdef CANT_HACK_CKSUM
    314 int docksum = 0;		/* don't calculate checksums */
    315 #else
    316 int docksum = 1;		/* calculate checksums */
    317 #endif
    318 int optlen;			/* length of ip options */
    319 
    320 int mtus[] = {
    321         17914,
    322          8166,
    323          4464,
    324          4352,
    325          2048,
    326          2002,
    327          1536,
    328          1500,
    329          1492,
    330 	 1480,
    331 	 1280,
    332          1006,
    333           576,
    334           552,
    335           544,
    336           512,
    337           508,
    338           296,
    339            68,
    340             0
    341 };
    342 int *mtuptr = &mtus[0];
    343 int mtudisc = 0;
    344 int nextmtu;   /* from ICMP error, set by packet_ok(), might be 0 */
    345 
    346 extern int optind;
    347 extern int opterr;
    348 extern char *optarg;
    349 
    350 /* Forwards */
    351 double	deltaT(struct timeval *, struct timeval *);
    352 void	freehostinfo(struct hostinfo *);
    353 void	getaddr(u_int32_t *, char *);
    354 struct	hostinfo *gethostinfo(char *);
    355 u_short	in_cksum(u_short *, int);
    356 char	*inetname(struct in_addr);
    357 int	main(int, char **);
    358 int	packet_ok(u_char *, int, struct sockaddr_in *, int);
    359 char	*pr_type(u_char);
    360 void	print(u_char *, int, struct sockaddr_in *);
    361 void	resize_packet(void);
    362 void	dump_packet(void);
    363 void	send_probe(int, int, struct timeval *);
    364 void	setsin(struct sockaddr_in *, u_int32_t);
    365 int	str2val(const char *, const char *, int, int);
    366 void	tvsub(struct timeval *, struct timeval *);
    367 __dead	void usage(void);
    368 int	wait_for_reply(int, struct sockaddr_in *, struct timeval *);
    369 void	frag_err(void);
    370 int	find_local_ip(struct sockaddr_in *, struct sockaddr_in *);
    371 
    372 int
    373 main(int argc, char **argv)
    374 {
    375 	register int op, code, n;
    376 	register char *cp;
    377 	register u_char *outp;
    378 	register u_int32_t *ap;
    379 	register struct sockaddr_in *from = &wherefrom;
    380 	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
    381 	register struct hostinfo *hi;
    382 	int on = 1;
    383 	register struct protoent *pe;
    384 	register int ttl, probe, i;
    385 	register int seq = 0;
    386 	int tos = 0, settos = 0, ttl_flag = 0;
    387 	register int lsrr = 0;
    388 	register u_short off = 0;
    389 	struct ifaddrlist *al, *al2;
    390 	char errbuf[132];
    391 
    392 	if ((cp = strrchr(argv[0], '/')) != NULL)
    393 		prog = cp + 1;
    394 	else
    395 		prog = argv[0];
    396 
    397 	opterr = 0;
    398 	while ((op = getopt(argc, argv, "dDFPInlrvxf:g:i:m:p:q:s:t:w:")) != -1)
    399 		switch (op) {
    400 
    401 		case 'd':
    402 			options |= SO_DEBUG;
    403 			break;
    404 
    405 		case 'D':
    406 			dump = 1;
    407 			break;
    408 
    409 		case 'f':
    410 			first_ttl = str2val(optarg, "first ttl", 1, 255);
    411 			break;
    412 
    413 		case 'F':
    414 			off = IP_DF;
    415 			break;
    416 
    417 		case 'g':
    418 			if (lsrr >= NGATEWAYS) {
    419 				Fprintf(stderr,
    420 				    "%s: No more than %d gateways\n",
    421 				    prog, NGATEWAYS);
    422 				exit(1);
    423 			}
    424 			getaddr(gwlist + lsrr, optarg);
    425 			++lsrr;
    426 			break;
    427 
    428 		case 'i':
    429 			device = optarg;
    430 			break;
    431 
    432 		case 'I':
    433 			++useicmp;
    434 			break;
    435 
    436 		case 'l':
    437 			++ttl_flag;
    438 			break;
    439 
    440 		case 'm':
    441 			max_ttl = str2val(optarg, "max ttl", 1, 255);
    442 			break;
    443 
    444 		case 'n':
    445 			++nflag;
    446 			break;
    447 
    448 		case 'p':
    449 			port = str2val(optarg, "port", 1, -1);
    450 			break;
    451 
    452 		case 'q':
    453 			nprobes = str2val(optarg, "nprobes", 1, -1);
    454 			break;
    455 
    456 		case 'r':
    457 			options |= SO_DONTROUTE;
    458 			break;
    459 
    460 		case 's':
    461 			/*
    462 			 * set the ip source address of the outbound
    463 			 * probe (e.g., on a multi-homed host).
    464 			 */
    465 			source = optarg;
    466 			break;
    467 
    468 		case 't':
    469 			tos = str2val(optarg, "tos", 0, 255);
    470 			++settos;
    471 			break;
    472 
    473 		case 'v':
    474 			++verbose;
    475 			break;
    476 
    477 		case 'x':
    478 			docksum = (docksum == 0);
    479 			break;
    480 
    481 		case 'w':
    482 			waittime = str2val(optarg, "wait time", 2, 24 * 3600);
    483 			break;
    484 
    485 		case 'P':
    486 			off = IP_DF;
    487 			mtudisc = 1;
    488 			break;
    489 
    490 		default:
    491 			usage();
    492 		}
    493 
    494 	if (first_ttl > max_ttl) {
    495 		Fprintf(stderr,
    496 		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
    497 		    prog, first_ttl, max_ttl);
    498 		exit(1);
    499 	}
    500 
    501 	if (!docksum)
    502 		Fprintf(stderr, "%s: Warning: ckecksums disabled\n", prog);
    503 
    504 	if (lsrr > 0)
    505 		optlen = (lsrr + 1) * sizeof(gwlist[0]);
    506 	minpacket = sizeof(*outip) + sizeof(struct outdata) + optlen;
    507 	if (useicmp)
    508 		minpacket += 8;			/* XXX magic number */
    509 	else
    510 		minpacket += sizeof(*outudp);
    511 	if (packlen == 0)
    512 		packlen = minpacket;		/* minimum sized packet */
    513 	else if (minpacket > packlen || packlen > maxpacket) {
    514 		Fprintf(stderr, "%s: packet size must be %d <= s <= %d\n",
    515 		    prog, minpacket, maxpacket);
    516 		exit(1);
    517 	}
    518 
    519 	if (mtudisc)
    520 		packlen = *mtuptr++;
    521 
    522 	/* Process destination and optional packet size */
    523 	switch (argc - optind) {
    524 
    525 	case 2:
    526 		packlen = str2val(argv[optind + 1],
    527 		    "packet length", minpacket, -1);
    528 		/* Fall through */
    529 
    530 	case 1:
    531 		hostname = argv[optind];
    532 		hi = gethostinfo(hostname);
    533 		setsin(to, hi->addrs[0]);
    534 		if (hi->n > 1)
    535 			Fprintf(stderr,
    536 		    "%s: Warning: %s has multiple addresses; using %s\n",
    537 				prog, hostname, inet_ntoa(to->sin_addr));
    538 		hostname = hi->name;
    539 		hi->name = NULL;
    540 		freehostinfo(hi);
    541 		break;
    542 
    543 	default:
    544 		usage();
    545 	}
    546 
    547 #ifdef HAVE_SETLINEBUF
    548 	setlinebuf (stdout);
    549 #else
    550 	setvbuf(stdout, NULL, _IOLBF, 0);
    551 #endif
    552 
    553 	outip = (struct ip *)malloc((unsigned)packlen);
    554 	if (outip == NULL) {
    555 		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
    556 		exit(1);
    557 	}
    558 	memset((char *)outip, 0, packlen);
    559 
    560 	outip->ip_v = IPVERSION;
    561 	if (settos)
    562 		outip->ip_tos = tos;
    563 #ifdef BYTESWAP_IP_LEN
    564 	outip->ip_len = htons(packlen);
    565 #else
    566 	outip->ip_len = packlen;
    567 #endif
    568 	outip->ip_off = off;
    569 	outp = (u_char *)(outip + 1);
    570 #ifdef HAVE_RAW_OPTIONS
    571 	if (lsrr > 0) {
    572 		register u_char *optlist;
    573 
    574 		optlist = outp;
    575 		outp += optlen;
    576 
    577 		/* final hop */
    578 		gwlist[lsrr] = to->sin_addr.s_addr;
    579 
    580 		outip->ip_dst.s_addr = gwlist[0];
    581 
    582 		/* force 4 byte alignment */
    583 		optlist[0] = IPOPT_NOP;
    584 		/* loose source route option */
    585 		optlist[1] = IPOPT_LSRR;
    586 		i = lsrr * sizeof(gwlist[0]);
    587 		optlist[2] = i + 3;
    588 		/* Pointer to LSRR addresses */
    589 		optlist[3] = IPOPT_MINOFF;
    590 		memcpy(optlist + 4, gwlist + 1, i);
    591 	} else
    592 #endif
    593 		outip->ip_dst = to->sin_addr;
    594 
    595 	outip->ip_hl = (outp - (u_char *)outip) >> 2;
    596 	ident = (getpid() & 0xffff) | 0x8000;
    597 	if (useicmp) {
    598 		outip->ip_p = IPPROTO_ICMP;
    599 
    600 		outicmp = (struct icmp *)outp;
    601 		outicmp->icmp_type = ICMP_ECHO;
    602 		outicmp->icmp_id = htons(ident);
    603 
    604 		outmark = outp + 8;	/* XXX magic number */
    605 	} else {
    606 		outip->ip_p = IPPROTO_UDP;
    607 
    608 		outudp = (struct udphdr *)outp;
    609 		outudp->uh_sport = htons(ident);
    610 		outudp->uh_ulen =
    611 		    htons((u_short)(packlen - (sizeof(*outip) + optlen)));
    612 		outmark = outudp + 1;
    613 	}
    614 
    615 	cp = "icmp";
    616 	if ((pe = getprotobyname(cp)) == NULL) {
    617 		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
    618 		exit(1);
    619 	}
    620 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
    621 		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
    622 		exit(1);
    623 	}
    624 	if (options & SO_DEBUG)
    625 		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
    626 		    sizeof(on));
    627 	if (options & SO_DONTROUTE)
    628 		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    629 		    sizeof(on));
    630 #ifdef IPSEC
    631 #ifdef IPSEC_POLICY_IPSEC
    632     {
    633 	int len;
    634 	char buf[16];
    635 
    636 	/*
    637 	 * do not raise error even if setsockopt fails, kernel may have ipsec
    638 	 * turned off.
    639 	 */
    640 	if ((len = ipsec_set_policy(buf, sizeof(buf), "bypass")) < 0) {
    641 		Fprintf(stderr, "%s: %s\n", prog, ipsec_strerror());
    642 		exit(1);
    643 	}
    644 	(void)setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, buf, len);
    645     }
    646 #else
    647     {
    648 	int level = IPSEC_LEVEL_AVAIL;
    649 
    650 	(void)setsockopt(s, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &level,
    651 		sizeof(level));
    652 	(void)setsockopt(s, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, &level,
    653 		sizeof(level));
    654 #ifdef IP_AUTH_TRANS_LEVEL
    655 	(void)setsockopt(s, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &level,
    656 		sizeof(level));
    657 #else
    658 	(void)setsockopt(s, IPPROTO_IP, IP_AUTH_LEVEL, &level,
    659 		sizeof(level));
    660 #endif
    661 #ifdef IP_AUTH_NETWORK_LEVEL
    662 	(void)setsockopt(s, IPPROTO_IP, IP_AUTH_NETWORK_LEVEL, &level,
    663 		sizeof(level));
    664 #endif
    665     }
    666 #endif /*IPSEC_POLICY_IPSEC*/
    667 #endif /*IPSEC*/
    668 
    669 #ifndef __hpux
    670 	sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    671 #else
    672 	sndsock = socket(AF_INET, SOCK_RAW,
    673 	    useicmp ? IPPROTO_ICMP : IPPROTO_UDP);
    674 #endif
    675 	if (sndsock < 0) {
    676 		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
    677 		exit(1);
    678 	}
    679 
    680 #ifdef IPSEC
    681 #ifdef IPSEC_POLICY_IPSEC
    682     {
    683 	int len;
    684 	char buf[16];
    685 
    686 	/*
    687 	 * do not raise error even if setsockopt fails, kernel may have ipsec
    688 	 * turned off.
    689 	 */
    690 	if ((len = ipsec_set_policy(buf, sizeof(buf), "bypass")) < 0) {
    691 		Fprintf(stderr, "%s: %s\n", prog, ipsec_strerror());
    692 		exit(1);
    693 	}
    694 	(void)setsockopt(sndsock, IPPROTO_IP, IP_IPSEC_POLICY, buf, len);
    695     }
    696 #else
    697     {
    698 	int level = IPSEC_LEVEL_BYPASS;
    699 
    700 	(void)setsockopt(sndsock, IPPROTO_IP, IP_ESP_TRANS_LEVEL, &level,
    701 		sizeof(level));
    702 	(void)setsockopt(sndsock, IPPROTO_IP, IP_ESP_NETWORK_LEVEL, &level,
    703 		sizeof(level));
    704 #ifdef IP_AUTH_TRANS_LEVEL
    705 	(void)setsockopt(sndsock, IPPROTO_IP, IP_AUTH_TRANS_LEVEL, &level,
    706 		sizeof(level));
    707 #else
    708 	(void)setsockopt(sndsock, IPPROTO_IP, IP_AUTH_LEVEL, &level,
    709 		sizeof(level));
    710 #endif
    711 #ifdef IP_AUTH_NETWORK_LEVEL
    712 	(void)setsockopt(sndsock, IPPROTO_IP, IP_AUTH_NETWORK_LEVEL, &level,
    713 		sizeof(level));
    714 #endif
    715     }
    716 #endif /*IPSEC_POLICY_IPSEC*/
    717 #endif /*IPSEC*/
    718 
    719 	/* Revert to non-privileged user after opening sockets */
    720 	setuid(getuid());
    721 
    722 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
    723 	if (lsrr > 0) {
    724 		u_char optlist[MAX_IPOPTLEN];
    725 
    726 		cp = "ip";
    727 		if ((pe = getprotobyname(cp)) == NULL) {
    728 			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
    729 			exit(1);
    730 		}
    731 
    732 		/* final hop */
    733 		gwlist[lsrr] = to->sin_addr.s_addr;
    734 		++lsrr;
    735 
    736 		/* force 4 byte alignment */
    737 		optlist[0] = IPOPT_NOP;
    738 		/* loose source route option */
    739 		optlist[1] = IPOPT_LSRR;
    740 		i = lsrr * sizeof(gwlist[0]);
    741 		optlist[2] = i + 3;
    742 		/* Pointer to LSRR addresses */
    743 		optlist[3] = IPOPT_MINOFF;
    744 		memcpy(optlist + 4, gwlist, i);
    745 
    746 		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist,
    747 		    i + sizeof(gwlist[0]))) < 0) {
    748 			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
    749 			    prog, strerror(errno));
    750 			exit(1);
    751 		    }
    752 	}
    753 #endif
    754 
    755 #ifdef SO_SNDBUF
    756 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
    757 	    sizeof(packlen)) < 0) {
    758 		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
    759 		exit(1);
    760 	}
    761 #endif
    762 #ifdef IP_HDRINCL
    763 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
    764 	    sizeof(on)) < 0) {
    765 		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
    766 		exit(1);
    767 	}
    768 #else
    769 #ifdef IP_TOS
    770 	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
    771 	    (char *)&tos, sizeof(tos)) < 0) {
    772 		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
    773 		    prog, tos, strerror(errno));
    774 		exit(1);
    775 	}
    776 #endif
    777 #endif
    778 	if (options & SO_DEBUG)
    779 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
    780 		    sizeof(on));
    781 	if (options & SO_DONTROUTE)
    782 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    783 		    sizeof(on));
    784 
    785 	/* Get the interface address list */
    786 	n = ifaddrlist(&al, errbuf, sizeof errbuf);
    787 	al2 = al;
    788 	if (n < 0) {
    789 		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
    790 		exit(1);
    791 	}
    792 	if (n == 0) {
    793 		Fprintf(stderr,
    794 		    "%s: Can't find any network interfaces\n", prog);
    795 		exit(1);
    796 	}
    797 
    798 	/* Look for a specific device */
    799 	if (device != NULL) {
    800 		for (i = n; i > 0; --i, ++al2)
    801 			if (strcmp(device, al2->device) == 0)
    802 				break;
    803 		if (i <= 0) {
    804 			Fprintf(stderr, "%s: Can't find interface %s\n",
    805 			    prog, device);
    806 			exit(1);
    807 		}
    808 	}
    809 
    810 	/* Determine our source address */
    811 	if (source == NULL) {
    812 		/*
    813 		 * If a device was specified, use the interface address.
    814 		 * Otherwise, use the first interface found.
    815 		 * Warn if there are more than one.
    816 		 */
    817 		setsin(from, al2->addr);
    818 		if (n > 1 && device == NULL && !find_local_ip(from, to)) {
    819 			Fprintf(stderr,
    820 		    "%s: Warning: Multiple interfaces found; using %s @ %s\n",
    821 			    prog, inet_ntoa(from->sin_addr), al2->device);
    822 		}
    823 	} else {
    824 		hi = gethostinfo(source);
    825 		source = hi->name;
    826 		hi->name = NULL;
    827 		if (device == NULL) {
    828 			/*
    829 			 * Use the first interface found.
    830 			 * Warn if there are more than one.
    831 			 */
    832 			setsin(from, hi->addrs[0]);
    833 			if (hi->n > 1)
    834 				Fprintf(stderr,
    835 			"%s: Warning: %s has multiple addresses; using %s\n",
    836 				    prog, source, inet_ntoa(from->sin_addr));
    837 		} else {
    838 			/*
    839 			 * Make sure the source specified matches the
    840 			 * interface address.
    841 			 */
    842 			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
    843 				if (*ap == al2->addr)
    844 					break;
    845 			if (i <= 0) {
    846 				Fprintf(stderr,
    847 				    "%s: %s is not on interface %s\n",
    848 				    prog, source, device);
    849 				exit(1);
    850 			}
    851 			setsin(from, *ap);
    852 		}
    853 		freehostinfo(hi);
    854 	}
    855 
    856 	/*
    857 	 * If not root, make sure source address matches a local interface.
    858 	 * (The list of addresses produced by ifaddrlist() automatically
    859 	 * excludes interfaces that are marked down and/or loopback.)
    860 	 */
    861 	if (getuid())  {
    862 		al2 = al;
    863 		for (i = n; i > 0; --i, ++al2)
    864 			if (from->sin_addr.s_addr == al2->addr)
    865 			    break;
    866 		if (i <= 0) {
    867 			Fprintf(stderr, "%s: %s is not a valid local address "
    868 			    "and you are not superuser.\n", prog,
    869 			    inet_ntoa(from->sin_addr));
    870 			exit(1);
    871 		}
    872 	}
    873 
    874 	outip->ip_src = from->sin_addr;
    875 #ifndef IP_HDRINCL
    876 	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
    877 		Fprintf(stderr, "%s: bind: %s\n",
    878 		    prog, strerror(errno));
    879 		exit (1);
    880 	}
    881 #endif
    882 
    883 	setuid(getuid());
    884 	Fprintf(stderr, "%s to %s (%s)",
    885 	    prog, hostname, inet_ntoa(to->sin_addr));
    886 	if (source)
    887 		Fprintf(stderr, " from %s", source);
    888 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
    889 	(void)fflush(stderr);
    890 
    891 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
    892 		u_int32_t lastaddr = 0;
    893 		int got_there = 0;
    894 		int unreachable = 0;
    895 
    896 again:
    897 		printed_ttl = 0;
    898 		for (probe = 0; probe < nprobes; ++probe) {
    899 			register int cc;
    900 			struct timeval t1, t2;
    901 			struct timezone tz;
    902 			register struct ip *ip;
    903 			(void)gettimeofday(&t1, &tz);
    904 			send_probe(++seq, ttl, &t1);
    905 			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
    906 				(void)gettimeofday(&t2, &tz);
    907 				/*
    908 				 * Since we'll be receiving all ICMP
    909 				 * messages to this host above, we may
    910 				 * never end up with cc=0, so we need
    911 				 * an additional termination check.
    912 				 */
    913 				if (t2.tv_sec - t1.tv_sec > waittime) {
    914 					cc = 0;
    915 					break;
    916 				}
    917 				i = packet_ok(packet, cc, from, seq);
    918 				/* Skip short packet */
    919 				if (i == 0)
    920 					continue;
    921 				if (from->sin_addr.s_addr != lastaddr) {
    922 					print(packet, cc, from);
    923 					lastaddr = from->sin_addr.s_addr;
    924 				}
    925 				ip = (struct ip *)packet;
    926 				Printf("  %.3f ms", deltaT(&t1, &t2));
    927 				if (ttl_flag)
    928 					Printf(" (ttl = %d)", ip->ip_ttl);
    929 				if (i == -2) {
    930 #ifndef ARCHAIC
    931 					if (ip->ip_ttl <= 1)
    932 						Printf(" !");
    933 #endif
    934 					++got_there;
    935 					break;
    936 				}
    937 
    938 				/* time exceeded in transit */
    939 				if (i == -1)
    940 					break;
    941 				code = i - 1;
    942 				switch (code) {
    943 
    944 				case ICMP_UNREACH_PORT:
    945 #ifndef ARCHAIC
    946 					if (ip->ip_ttl <= 1)
    947 						Printf(" !");
    948 #endif
    949 					++got_there;
    950 					break;
    951 
    952 				case ICMP_UNREACH_NET:
    953 					++unreachable;
    954 					Printf(" !N");
    955 					break;
    956 
    957 				case ICMP_UNREACH_HOST:
    958 					++unreachable;
    959 					Printf(" !H");
    960 					break;
    961 
    962 				case ICMP_UNREACH_PROTOCOL:
    963 					++got_there;
    964 					Printf(" !P");
    965 					break;
    966 
    967 				case ICMP_UNREACH_NEEDFRAG:
    968 					if (mtudisc) {
    969 						frag_err();
    970 						goto again;
    971 					} else {
    972 						++unreachable;
    973 						Printf(" !F");
    974 					}
    975 					break;
    976 
    977 				case ICMP_UNREACH_SRCFAIL:
    978 					++unreachable;
    979 					Printf(" !S");
    980 					break;
    981 
    982 /* rfc1716 */
    983 #ifndef ICMP_UNREACH_FILTER_PROHIB
    984 #define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
    985 #endif
    986 				case ICMP_UNREACH_FILTER_PROHIB:
    987 					++unreachable;
    988 					Printf(" !X");
    989 					break;
    990 
    991 				default:
    992 					++unreachable;
    993 					Printf(" !<%d>", code);
    994 					break;
    995 				}
    996 				break;
    997 			}
    998 			if (cc == 0)
    999 				Printf(" *");
   1000 			(void)fflush(stdout);
   1001 		}
   1002 		putchar('\n');
   1003 		if (got_there ||
   1004 		    (unreachable > 0 && unreachable >= ((nprobes + 1) / 2)))
   1005 			break;
   1006 	}
   1007 	exit(0);
   1008 }
   1009 
   1010 int
   1011 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
   1012     register struct timeval *tp)
   1013 {
   1014 	fd_set fds;
   1015 	struct timeval now, wait;
   1016 	struct timezone tz;
   1017 	register int cc = 0;
   1018 	int fromlen = sizeof(*fromp);
   1019 	int retval;
   1020 
   1021 	FD_ZERO(&fds);
   1022 	FD_SET(sock, &fds);
   1023 
   1024 	wait.tv_sec = tp->tv_sec + waittime;
   1025 	wait.tv_usec = tp->tv_usec;
   1026 	(void)gettimeofday(&now, &tz);
   1027 	tvsub(&wait, &now);
   1028 
   1029 	retval = select(sock + 1, &fds, NULL, NULL, &wait);
   1030 	if (retval < 0)  {
   1031 		/* If we continue, we probably just flood the remote host. */
   1032 		Fprintf(stderr, "%s: select: %s\n", prog, strerror(errno));
   1033 		exit(1);
   1034 	}
   1035 	if (retval > 0)  {
   1036 		cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
   1037 			    (struct sockaddr *)fromp, &fromlen);
   1038 	}
   1039 
   1040 	return(cc);
   1041 }
   1042 
   1043 void
   1044 dump_packet()
   1045 {
   1046 	u_char *p;
   1047 	int i;
   1048 
   1049 	Fprintf(stderr, "packet data:");
   1050 
   1051 #ifdef __hpux
   1052 	for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i <
   1053 	    i < packlen - (sizeof(*outip) + optlen); i++)
   1054 #else
   1055 	for (p = (u_char *)outip, i = 0; i < packlen; i++)
   1056 #endif
   1057 	{
   1058 		if ((i % 24) == 0)
   1059 			Fprintf(stderr, "\n ");
   1060 		Fprintf(stderr, " %02x", *p++);
   1061 	}
   1062 	Fprintf(stderr, "\n");
   1063 }
   1064 
   1065 void
   1066 send_probe(register int seq, int ttl, register struct timeval *tp)
   1067 {
   1068 	register int cc;
   1069 	register struct udpiphdr * ui;
   1070 	struct ip tip;
   1071 	int oldmtu = packlen;
   1072 
   1073 again:
   1074 #ifdef BYTESWAP_IP_LEN
   1075 	outip->ip_len = htons(packlen);
   1076 #else
   1077 	outip->ip_len = packlen;
   1078 #endif
   1079 	outip->ip_ttl = ttl;
   1080 #ifndef __hpux
   1081 	outip->ip_id = htons(ident + seq);
   1082 #endif
   1083 
   1084 	/*
   1085 	 * In most cases, the kernel will recalculate the ip checksum.
   1086 	 * But we must do it anyway so that the udp checksum comes out
   1087 	 * right.
   1088 	 */
   1089 	if (docksum) {
   1090 		outip->ip_sum =
   1091 		    in_cksum((u_short *)outip, sizeof(*outip) + optlen);
   1092 		if (outip->ip_sum == 0)
   1093 			outip->ip_sum = 0xffff;
   1094 	}
   1095 
   1096 	/* Payload */
   1097 	outsetup.seq = seq;
   1098 	outsetup.ttl = ttl;
   1099 	outsetup.tv  = *tp;
   1100 	memcpy(outmark,&outsetup,sizeof(outsetup));
   1101 
   1102 	if (useicmp)
   1103 		outicmp->icmp_seq = htons(seq);
   1104 	else
   1105 		outudp->uh_dport = htons(port + seq);
   1106 
   1107 	/* (We can only do the checksum if we know our ip address) */
   1108 	if (docksum) {
   1109 		if (useicmp) {
   1110 			outicmp->icmp_cksum = 0;
   1111 			outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
   1112 			    packlen - (sizeof(*outip) + optlen));
   1113 			if (outicmp->icmp_cksum == 0)
   1114 				outicmp->icmp_cksum = 0xffff;
   1115 		} else {
   1116 			/* Checksum (must save and restore ip header) */
   1117 			tip = *outip;
   1118 			ui = (struct udpiphdr *)outip;
   1119 #ifndef __NetBSD__
   1120 			ui->ui_next = 0;
   1121 			ui->ui_prev = 0;
   1122 			ui->ui_x1 = 0;
   1123 #else
   1124 			memset(ui->ui_x1, 0, sizeof(ui->ui_x1));
   1125 #endif
   1126 			ui->ui_len = outudp->uh_ulen;
   1127 			outudp->uh_sum = 0;
   1128 			outudp->uh_sum = in_cksum((u_short *)ui, packlen);
   1129 			if (outudp->uh_sum == 0)
   1130 				outudp->uh_sum = 0xffff;
   1131 			*outip = tip;
   1132 		}
   1133 	}
   1134 
   1135 	/* XXX undocumented debugging hack */
   1136 	if (verbose > 1) {
   1137 		register const u_short *sp;
   1138 		register int nshorts, i;
   1139 
   1140 		sp = (u_short *)outip;
   1141 		nshorts = (u_int)packlen / sizeof(u_short);
   1142 		i = 0;
   1143 		Printf("[ %d bytes", packlen);
   1144 		while (--nshorts >= 0) {
   1145 			if ((i++ % 8) == 0)
   1146 				Printf("\n\t");
   1147 			Printf(" %04x", ntohs(*sp++));
   1148 		}
   1149 		if (packlen & 1) {
   1150 			if ((i % 8) == 0)
   1151 				Printf("\n\t");
   1152 			Printf(" %02x", *(u_char *)sp);
   1153 		}
   1154 		Printf("]\n");
   1155 	}
   1156 
   1157 #if !defined(IP_HDRINCL) && defined(IP_TTL)
   1158 	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
   1159 	    (char *)&ttl, sizeof(ttl)) < 0) {
   1160 		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
   1161 		    prog, ttl, strerror(errno));
   1162 		exit(1);
   1163 	}
   1164 #endif
   1165 	if (dump)
   1166 		dump_packet();
   1167 
   1168 #ifdef __hpux
   1169 	cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
   1170 	    packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
   1171 	if (cc > 0)
   1172 		cc += sizeof(*outip) + optlen;
   1173 #else
   1174 	cc = sendto(sndsock, (char *)outip,
   1175 	    packlen, 0, &whereto, sizeof(whereto));
   1176 #endif
   1177 	if (cc < 0 || cc != packlen)  {
   1178 		if (cc < 0) {
   1179 			/*
   1180 			 * An errno of EMSGSIZE means we're writing too big a
   1181 			 * datagram for the interface.  We have to just
   1182 			 * decrease the packet size until we find one that
   1183 			 * works.
   1184 			 *
   1185 			 * XXX maybe we should try to read the outgoing if's
   1186 			 * mtu?
   1187 			 */
   1188 			if (errno == EMSGSIZE) {
   1189 				packlen = *mtuptr++;
   1190 				resize_packet();
   1191 				goto again;
   1192 			} else
   1193 				Fprintf(stderr, "%s: sendto: %s\n",
   1194 				    prog, strerror(errno));
   1195 		}
   1196 
   1197 		Printf("%s: wrote %s %d chars, ret=%d\n",
   1198 		    prog, hostname, packlen, cc);
   1199 		(void)fflush(stdout);
   1200 	}
   1201 	if (oldmtu != packlen) {
   1202 		Printf("message too big, "
   1203 		    "trying new MTU = %d\n", packlen);
   1204 		printed_ttl = 0;
   1205 	}
   1206 	if (!printed_ttl) {
   1207 		Printf("%2d ", ttl);
   1208 		printed_ttl = 1;
   1209 	}
   1210 
   1211 }
   1212 
   1213 double
   1214 deltaT(struct timeval *t1p, struct timeval *t2p)
   1215 {
   1216 	register double dt;
   1217 
   1218 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
   1219 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
   1220 	return (dt);
   1221 }
   1222 
   1223 /*
   1224  * Convert an ICMP "type" field to a printable string.
   1225  */
   1226 char *
   1227 pr_type(register u_char t)
   1228 {
   1229 	static char *ttab[] = {
   1230 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
   1231 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
   1232 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
   1233 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
   1234 	"Info Reply"
   1235 	};
   1236 
   1237 	if (t > 16)
   1238 		return("OUT-OF-RANGE");
   1239 
   1240 	return(ttab[t]);
   1241 }
   1242 
   1243 int
   1244 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
   1245     register int seq)
   1246 {
   1247 	register struct icmp *icp;
   1248 	register u_char type, code;
   1249 	register int hlen;
   1250 #ifndef ARCHAIC
   1251 	register struct ip *ip;
   1252 
   1253 	ip = (struct ip *) buf;
   1254 	hlen = ip->ip_hl << 2;
   1255 	if (cc < hlen + ICMP_MINLEN) {
   1256 		if (verbose)
   1257 			Printf("packet too short (%d bytes) from %s\n", cc,
   1258 				inet_ntoa(from->sin_addr));
   1259 		return (0);
   1260 	}
   1261 	cc -= hlen;
   1262 	icp = (struct icmp *)(buf + hlen);
   1263 #else
   1264 	icp = (struct icmp *)buf;
   1265 #endif
   1266 	type = icp->icmp_type;
   1267 	code = icp->icmp_code;
   1268 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
   1269 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
   1270 		register struct ip *hip;
   1271 		register struct udphdr *up;
   1272 		register struct icmp *hicmp;
   1273 
   1274 		hip = &icp->icmp_ip;
   1275 		hlen = hip->ip_hl << 2;
   1276 
   1277 		nextmtu = ntohs(icp->icmp_nextmtu);	/* for frag_err() */
   1278 
   1279 		if (useicmp) {
   1280 			/* XXX */
   1281 			if (type == ICMP_ECHOREPLY &&
   1282 			    icp->icmp_id == htons(ident) &&
   1283 			    icp->icmp_seq == htons(seq))
   1284 				return (-2);
   1285 
   1286 			hicmp = (struct icmp *)((u_char *)hip + hlen);
   1287 			/* XXX 8 is a magic number */
   1288 			if (hlen + 8 <= cc &&
   1289 			    hip->ip_p == IPPROTO_ICMP &&
   1290 			    hicmp->icmp_id == htons(ident) &&
   1291 			    hicmp->icmp_seq == htons(seq))
   1292 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
   1293 		} else {
   1294 			up = (struct udphdr *)((u_char *)hip + hlen);
   1295 			/* XXX 8 is a magic number */
   1296 			if (hlen + 12 <= cc &&
   1297 			    hip->ip_p == IPPROTO_UDP &&
   1298 			    up->uh_sport == htons(ident) &&
   1299 			    up->uh_dport == htons(port + seq))
   1300 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
   1301 		}
   1302 	}
   1303 #ifndef ARCHAIC
   1304 	if (verbose) {
   1305 		register int i;
   1306 		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
   1307 
   1308 		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
   1309 		Printf("%s: icmp type %d (%s) code %d\n",
   1310 		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
   1311 		for (i = 4; i < cc ; i += sizeof(*lp))
   1312 			Printf("%2d: x%8.8x\n", i, *lp++);
   1313 	}
   1314 #endif
   1315 	return(0);
   1316 }
   1317 
   1318 void resize_packet(void)
   1319 {
   1320 	if (useicmp) {
   1321 		outicmp->icmp_cksum = 0;
   1322 		outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
   1323 		    packlen - (sizeof(*outip) + optlen));
   1324 		if (outicmp->icmp_cksum == 0)
   1325 			outicmp->icmp_cksum = 0xffff;
   1326 	} else {
   1327 		outudp->uh_ulen =
   1328 		    htons((u_short)(packlen - (sizeof(*outip) + optlen)));
   1329 	}
   1330 }
   1331 
   1332 void
   1333 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
   1334 {
   1335 	register struct ip *ip;
   1336 	register int hlen;
   1337 
   1338 	ip = (struct ip *) buf;
   1339 	hlen = ip->ip_hl << 2;
   1340 	cc -= hlen;
   1341 
   1342 	if (nflag)
   1343 		Printf(" %s", inet_ntoa(from->sin_addr));
   1344 	else
   1345 		Printf(" %s (%s)", inetname(from->sin_addr),
   1346 		    inet_ntoa(from->sin_addr));
   1347 
   1348 	if (verbose)
   1349 		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
   1350 }
   1351 
   1352 /*
   1353  * Checksum routine for Internet Protocol family headers (C Version)
   1354  */
   1355 u_short
   1356 in_cksum(register u_short *addr, register int len)
   1357 {
   1358 	register int nleft = len;
   1359 	register u_short *w = addr;
   1360 	register u_short answer;
   1361 	register int sum = 0;
   1362 
   1363 	/*
   1364 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
   1365 	 *  we add sequential 16 bit words to it, and at the end, fold
   1366 	 *  back all the carry bits from the top 16 bits into the lower
   1367 	 *  16 bits.
   1368 	 */
   1369 	while (nleft > 1)  {
   1370 		sum += *w++;
   1371 		nleft -= 2;
   1372 	}
   1373 
   1374 	/* mop up an odd byte, if necessary */
   1375 	if (nleft == 1)
   1376 		sum += *(u_char *)w;
   1377 
   1378 	/*
   1379 	 * add back carry outs from top 16 bits to low 16 bits
   1380 	 */
   1381 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
   1382 	sum += (sum >> 16);			/* add carry */
   1383 	answer = ~sum;				/* truncate to 16 bits */
   1384 	return (answer);
   1385 }
   1386 
   1387 /*
   1388  * Subtract 2 timeval structs:  out = out - in.
   1389  * Out is assumed to be >= in.
   1390  */
   1391 void
   1392 tvsub(register struct timeval *out, register struct timeval *in)
   1393 {
   1394 
   1395 	if ((out->tv_usec -= in->tv_usec) < 0)   {
   1396 		--out->tv_sec;
   1397 		out->tv_usec += 1000000;
   1398 	}
   1399 	out->tv_sec -= in->tv_sec;
   1400 }
   1401 
   1402 /*
   1403  * Construct an Internet address representation.
   1404  * If the nflag has been supplied, give
   1405  * numeric value, otherwise try for symbolic name.
   1406  */
   1407 char *
   1408 inetname(struct in_addr in)
   1409 {
   1410 	register char *cp;
   1411 	register struct hostent *hp;
   1412 	static int first = 1;
   1413 	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
   1414 
   1415 	if (first && !nflag) {
   1416 		int rv;
   1417 
   1418 		first = 0;
   1419 		rv = gethostname(domain, sizeof domain);
   1420 		domain[sizeof(domain) - 1] = '\0';
   1421 		if (rv == 0 && (cp = strchr(domain, '.')) != NULL) {
   1422 			(void)strncpy(domain, cp + 1, sizeof(domain) - 1);
   1423 		} else
   1424 			domain[0] = '\0';
   1425 	}
   1426 	if (!nflag && in.s_addr != INADDR_ANY) {
   1427 		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
   1428 		if (hp != NULL) {
   1429 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
   1430 			    strcmp(cp + 1, domain) == 0)
   1431 				*cp = '\0';
   1432 			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
   1433 			line[sizeof(line) - 1] = '\0';
   1434 			return (line);
   1435 		}
   1436 	}
   1437 	return (inet_ntoa(in));
   1438 }
   1439 
   1440 struct hostinfo *
   1441 gethostinfo(register char *hostname)
   1442 {
   1443 	register int n;
   1444 	register struct hostent *hp;
   1445 	register struct hostinfo *hi;
   1446 	register char **p;
   1447 	register u_int32_t *ap;
   1448 	struct in_addr addr;
   1449 
   1450 	hi = calloc(1, sizeof(*hi));
   1451 	if (hi == NULL) {
   1452 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
   1453 		exit(1);
   1454 	}
   1455 	if (inet_aton(hostname, &addr) != 0) {
   1456 		hi->name = savestr(hostname);
   1457 		hi->n = 1;
   1458 		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
   1459 		if (hi->addrs == NULL) {
   1460 			Fprintf(stderr, "%s: calloc %s\n",
   1461 			    prog, strerror(errno));
   1462 			exit(1);
   1463 		}
   1464 		hi->addrs[0] = addr.s_addr;
   1465 		return (hi);
   1466 	}
   1467 
   1468 	hp = gethostbyname(hostname);
   1469 	if (hp == NULL) {
   1470 		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
   1471 		exit(1);
   1472 	}
   1473 	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
   1474 		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
   1475 		exit(1);
   1476 	}
   1477 	hi->name = savestr(hp->h_name);
   1478 	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
   1479 		continue;
   1480 	hi->n = n;
   1481 	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
   1482 	if (hi->addrs == NULL) {
   1483 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
   1484 		exit(1);
   1485 	}
   1486 	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
   1487 		memcpy(ap, *p, sizeof(*ap));
   1488 	return (hi);
   1489 }
   1490 
   1491 void
   1492 freehostinfo(register struct hostinfo *hi)
   1493 {
   1494 	if (hi->name != NULL) {
   1495 		free(hi->name);
   1496 		hi->name = NULL;
   1497 	}
   1498 	free((char *)hi->addrs);
   1499 	free((char *)hi);
   1500 }
   1501 
   1502 void
   1503 getaddr(register u_int32_t *ap, register char *hostname)
   1504 {
   1505 	register struct hostinfo *hi;
   1506 
   1507 	hi = gethostinfo(hostname);
   1508 	*ap = hi->addrs[0];
   1509 	freehostinfo(hi);
   1510 }
   1511 
   1512 void
   1513 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
   1514 {
   1515 
   1516 	memset(sin, 0, sizeof(*sin));
   1517 #ifdef HAVE_SOCKADDR_SA_LEN
   1518 	sin->sin_len = sizeof(*sin);
   1519 #endif
   1520 	sin->sin_family = AF_INET;
   1521 	sin->sin_addr.s_addr = addr;
   1522 }
   1523 
   1524 /* String to value with optional min and max. Handles decimal and hex. */
   1525 int
   1526 str2val(register const char *str, register const char *what,
   1527     register int mi, register int ma)
   1528 {
   1529 	register const char *cp;
   1530 	register int val;
   1531 	char *ep;
   1532 
   1533 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
   1534 		cp = str + 2;
   1535 		val = (int)strtol(cp, &ep, 16);
   1536 	} else
   1537 		val = (int)strtol(str, &ep, 10);
   1538 	if (*ep != '\0') {
   1539 		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
   1540 		    prog, str, what);
   1541 		exit(1);
   1542 	}
   1543 	if (val < mi && mi >= 0) {
   1544 		if (mi == 0)
   1545 			Fprintf(stderr, "%s: %s must be >= %d\n",
   1546 			    prog, what, mi);
   1547 		else
   1548 			Fprintf(stderr, "%s: %s must be > %d\n",
   1549 			    prog, what, mi - 1);
   1550 		exit(1);
   1551 	}
   1552 	if (val > ma && ma >= 0) {
   1553 		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
   1554 		exit(1);
   1555 	}
   1556 	return (val);
   1557 }
   1558 
   1559 __dead void
   1560 usage(void)
   1561 {
   1562 	extern char version[];
   1563 
   1564 	Fprintf(stderr, "Version %s\n", version);
   1565 	Fprintf(stderr, "Usage: %s [-dDFPIlnrvx] [-g gateway] [-i iface] \
   1566 [-f first_ttl] [-m max_ttl]\n\t[ -p port] [-q nqueries] [-s src_addr] [-t tos] \
   1567 [-w waittime]\n\thost [packetlen]\n",
   1568 	    prog);
   1569 	exit(1);
   1570 }
   1571 
   1572 /*
   1573  * Received ICMP unreachable (fragmentation required and DF set).
   1574  * If the ICMP error was from a "new" router, it'll contain the next-hop
   1575  * MTU that we should use next.  Otherwise we'll just keep going in the
   1576  * mtus[] table, trying until we hit a valid MTU.
   1577  */
   1578 
   1579 
   1580 void
   1581 frag_err()
   1582 {
   1583         int i;
   1584 
   1585         if (nextmtu > 0 && nextmtu < packlen) {
   1586                 Printf("\nfragmentation required and DF set, "
   1587 		     "next hop MTU = %d\n",
   1588                         nextmtu);
   1589                 packlen = nextmtu;
   1590                 for (i = 0; mtus[i] > 0; i++) {
   1591                         if (mtus[i] < nextmtu) {
   1592                                 mtuptr = &mtus[i];    /* next one to try */
   1593                                 break;
   1594                         }
   1595                 }
   1596         } else {
   1597                 Printf("\nfragmentation required and DF set. ");
   1598 		if (nextmtu)
   1599 			Printf("\nBogus next hop MTU = %d > last MTU = %d. ",
   1600 			    nextmtu, packlen);
   1601                 packlen = *mtuptr++;
   1602 		Printf("Trying new MTU = %d\n", packlen);
   1603         }
   1604 	resize_packet();
   1605 }
   1606 
   1607 int
   1608 find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
   1609 {
   1610 	int sock;
   1611 	struct sockaddr_in help;
   1612 	int help_len;
   1613 
   1614 	sock = socket(AF_INET, SOCK_DGRAM, 0);
   1615 	if (sock < 0) return (0);
   1616 
   1617 	help.sin_family = AF_INET;
   1618 	/*
   1619 	 * At this point the port number doesn't matter
   1620 	 * since it only has to be greater than zero.
   1621 	 */
   1622 	help.sin_port = 42;
   1623 	help.sin_addr.s_addr = to->sin_addr.s_addr;
   1624 	if (connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
   1625 		(void)close(sock);
   1626 		return (0);
   1627 	}
   1628 
   1629 	help_len = sizeof(help);
   1630 	if (getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
   1631 	    help_len != sizeof(help) ||
   1632 	    help.sin_addr.s_addr == INADDR_ANY) {
   1633 		(void)close(sock);
   1634 		return (0);
   1635 	}
   1636 
   1637 	(void)close(sock);
   1638 	setsin(from, help.sin_addr.s_addr);
   1639 	return (1);
   1640 }
   1641