Home | History | Annotate | Line # | Download | only in traceroute
traceroute.c revision 1.28
      1 /*	$NetBSD: traceroute.c,v 1.28 1999/02/16 23:18:40 cjs 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.28 1999/02/16 23:18:40 cjs 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 #include <limits.h>
    229 #ifdef HAVE_MALLOC_H
    230 #include <malloc.h>
    231 #endif
    232 #include <memory.h>
    233 #include <netdb.h>
    234 #include <stdio.h>
    235 #include <stdlib.h>
    236 #include <string.h>
    237 #include <unistd.h>
    238 
    239 #include "gnuc.h"
    240 #ifdef HAVE_OS_PROTO_H
    241 #include "os-proto.h"
    242 #endif
    243 
    244 #include "ifaddrlist.h"
    245 #include "savestr.h"
    246 
    247 /* Maximum number of gateways (include room for one noop) */
    248 #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
    249 
    250 #ifndef MAXHOSTNAMELEN
    251 #define MAXHOSTNAMELEN	64
    252 #endif
    253 
    254 #define Fprintf (void)fprintf
    255 #define Printf (void)printf
    256 
    257 /* Host name and address list */
    258 struct hostinfo {
    259 	char *name;
    260 	int n;
    261 	u_int32_t *addrs;
    262 };
    263 
    264 /* Data section of the probe packet */
    265 struct outdata {
    266 	u_char seq;		/* sequence number of this packet */
    267 	u_char ttl;		/* ttl packet left with */
    268 	struct timeval tv;	/* time packet left */
    269 };
    270 
    271 u_char	packet[512];		/* last inbound (icmp) packet */
    272 
    273 struct ip *outip;		/* last output (udp) packet */
    274 struct udphdr *outudp;		/* last output (udp) packet */
    275 void *outmark;			/* packed location of struct outdata */
    276 struct outdata outsetup;	/* setup and copy for alignment */
    277 
    278 struct icmp *outicmp;		/* last output (icmp) packet */
    279 
    280 /* loose source route gateway list (including room for final destination) */
    281 u_int32_t gwlist[NGATEWAYS + 1];
    282 
    283 int s;				/* receive (icmp) socket file descriptor */
    284 int sndsock;			/* send (udp/icmp) socket file descriptor */
    285 
    286 struct sockaddr whereto;	/* Who to try to reach */
    287 struct sockaddr_in wherefrom;	/* Who we are */
    288 int packlen;			/* total length of packet */
    289 int minpacket;			/* min ip packet size */
    290 int maxpacket = 32 * 1024;	/* max ip packet size */
    291 
    292 char *prog;
    293 char *source;
    294 char *hostname;
    295 char *device;
    296 
    297 int nprobes = 3;
    298 int max_ttl = 30;
    299 int first_ttl = 1;
    300 u_short ident;
    301 u_short port = 32768 + 666;	/* start udp dest port # for probe packets */
    302 
    303 int options;			/* socket options */
    304 int verbose;
    305 int waittime = 5;		/* time to wait for response (in seconds) */
    306 int nflag;			/* print addresses numerically */
    307 int dump;
    308 int useicmp;			/* use icmp echo instead of udp packets */
    309 #ifdef CANT_HACK_CKSUM
    310 int docksum = 0;		/* don't calculate checksums */
    311 #else
    312 int docksum = 1;		/* calculate checksums */
    313 #endif
    314 int optlen;			/* length of ip options */
    315 
    316 int mtus[] = {
    317         17914,
    318          8166,
    319          4464,
    320          4352,
    321          2048,
    322          2002,
    323          1536,
    324          1500,
    325          1492,
    326          1006,
    327           576,
    328           552,
    329           544,
    330           512,
    331           508,
    332           296,
    333            68,
    334             0
    335 };
    336 int *mtuptr = &mtus[0];
    337 int mtudisc = 0;
    338 int nextmtu;   /* from ICMP error, set by packet_ok(), might be 0 */
    339 
    340 extern int optind;
    341 extern int opterr;
    342 extern char *optarg;
    343 
    344 /* Forwards */
    345 double	deltaT(struct timeval *, struct timeval *);
    346 void	freehostinfo(struct hostinfo *);
    347 void	getaddr(u_int32_t *, char *);
    348 struct	hostinfo *gethostinfo(char *);
    349 u_short	in_cksum(u_short *, int);
    350 char	*inetname(struct in_addr);
    351 int	main(int, char **);
    352 int	packet_ok(u_char *, int, struct sockaddr_in *, int);
    353 char	*pr_type(u_char);
    354 void	print(u_char *, int, struct sockaddr_in *);
    355 void	dump_packet(void);
    356 void	send_probe(int, int, struct timeval *);
    357 void	setsin(struct sockaddr_in *, u_int32_t);
    358 int	str2val(const char *, const char *, int, int);
    359 void	tvsub(struct timeval *, struct timeval *);
    360 __dead	void usage(void);
    361 int	wait_for_reply(int, struct sockaddr_in *, struct timeval *);
    362 void	frag_err(void);
    363 int	find_local_ip(struct sockaddr_in *, struct sockaddr_in *);
    364 
    365 int
    366 main(int argc, char **argv)
    367 {
    368 	register int op, code, n;
    369 	register char *cp;
    370 	register u_char *outp;
    371 	register u_int32_t *ap;
    372 	register struct sockaddr_in *from = &wherefrom;
    373 	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
    374 	register struct hostinfo *hi;
    375 	int on = 1;
    376 	register struct protoent *pe;
    377 	register int ttl, probe, i;
    378 	register int seq = 0;
    379 	int tos = 0, settos = 0, ttl_flag = 0;
    380 	register int lsrr = 0;
    381 	register u_short off = 0;
    382 	struct ifaddrlist *al, *al2;
    383 	char errbuf[132];
    384 
    385 	if ((cp = strrchr(argv[0], '/')) != NULL)
    386 		prog = cp + 1;
    387 	else
    388 		prog = argv[0];
    389 
    390 	opterr = 0;
    391 	while ((op = getopt(argc, argv, "dDFPInlrvxf:g:i:m:p:q:s:t:w:")) != -1)
    392 		switch (op) {
    393 
    394 		case 'd':
    395 			options |= SO_DEBUG;
    396 			break;
    397 
    398 		case 'D':
    399 			dump = 1;
    400 			break;
    401 
    402 		case 'f':
    403 			first_ttl = str2val(optarg, "first ttl", 1, 255);
    404 			break;
    405 
    406 		case 'F':
    407 			off = IP_DF;
    408 			break;
    409 
    410 		case 'g':
    411 			if (lsrr >= NGATEWAYS) {
    412 				Fprintf(stderr,
    413 				    "%s: No more than %d gateways\n",
    414 				    prog, NGATEWAYS);
    415 				exit(1);
    416 			}
    417 			getaddr(gwlist + lsrr, optarg);
    418 			++lsrr;
    419 			break;
    420 
    421 		case 'i':
    422 			device = optarg;
    423 			break;
    424 
    425 		case 'I':
    426 			++useicmp;
    427 			break;
    428 
    429 		case 'l':
    430 			++ttl_flag;
    431 			break;
    432 
    433 		case 'm':
    434 			max_ttl = str2val(optarg, "max ttl", 1, 255);
    435 			break;
    436 
    437 		case 'n':
    438 			++nflag;
    439 			break;
    440 
    441 		case 'p':
    442 			port = str2val(optarg, "port", 1, -1);
    443 			break;
    444 
    445 		case 'q':
    446 			nprobes = str2val(optarg, "nprobes", 1, -1);
    447 			break;
    448 
    449 		case 'r':
    450 			options |= SO_DONTROUTE;
    451 			break;
    452 
    453 		case 's':
    454 			/*
    455 			 * set the ip source address of the outbound
    456 			 * probe (e.g., on a multi-homed host).
    457 			 */
    458 			source = optarg;
    459 			break;
    460 
    461 		case 't':
    462 			tos = str2val(optarg, "tos", 0, 255);
    463 			++settos;
    464 			break;
    465 
    466 		case 'v':
    467 			++verbose;
    468 			break;
    469 
    470 		case 'x':
    471 			docksum = (docksum == 0);
    472 			break;
    473 
    474 		case 'w':
    475 			waittime = str2val(optarg, "wait time", 2, -1);
    476 			break;
    477 
    478 		case 'P':
    479 			off = IP_DF;
    480 			mtudisc = 1;
    481 			break;
    482 
    483 		default:
    484 			usage();
    485 		}
    486 
    487 	if (first_ttl > max_ttl) {
    488 		Fprintf(stderr,
    489 		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
    490 		    prog, first_ttl, max_ttl);
    491 		exit(1);
    492 	}
    493 
    494 	if (!docksum)
    495 		Fprintf(stderr, "%s: Warning: ckecksums disabled\n", prog);
    496 
    497 	if (lsrr > 0)
    498 		optlen = (lsrr + 1) * sizeof(gwlist[0]);
    499 	minpacket = sizeof(*outip) + sizeof(struct outdata) + optlen;
    500 	if (useicmp)
    501 		minpacket += 8;			/* XXX magic number */
    502 	else
    503 		minpacket += sizeof(*outudp);
    504 	if (packlen == 0)
    505 		packlen = minpacket;		/* minimum sized packet */
    506 	else if (minpacket > packlen || packlen > maxpacket) {
    507 		Fprintf(stderr, "%s: packet size must be %d <= s <= %d\n",
    508 		    prog, minpacket, maxpacket);
    509 		exit(1);
    510 	}
    511 
    512 	if (mtudisc)
    513 		packlen = *mtuptr++;
    514 
    515 	/* Process destination and optional packet size */
    516 	switch (argc - optind) {
    517 
    518 	case 2:
    519 		packlen = str2val(argv[optind + 1],
    520 		    "packet length", minpacket, -1);
    521 		/* Fall through */
    522 
    523 	case 1:
    524 		hostname = argv[optind];
    525 		hi = gethostinfo(hostname);
    526 		setsin(to, hi->addrs[0]);
    527 		if (hi->n > 1)
    528 			Fprintf(stderr,
    529 		    "%s: Warning: %s has multiple addresses; using %s\n",
    530 				prog, hostname, inet_ntoa(to->sin_addr));
    531 		hostname = hi->name;
    532 		hi->name = NULL;
    533 		freehostinfo(hi);
    534 		break;
    535 
    536 	default:
    537 		usage();
    538 	}
    539 
    540 #ifdef HAVE_SETLINEBUF
    541 	setlinebuf (stdout);
    542 #else
    543 	setvbuf(stdout, NULL, _IOLBF, 0);
    544 #endif
    545 
    546 	outip = (struct ip *)malloc((unsigned)packlen);
    547 	if (outip == NULL) {
    548 		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
    549 		exit(1);
    550 	}
    551 	memset((char *)outip, 0, packlen);
    552 
    553 	outip->ip_v = IPVERSION;
    554 	if (settos)
    555 		outip->ip_tos = tos;
    556 #ifdef BYTESWAP_IP_LEN
    557 	outip->ip_len = htons(packlen);
    558 #else
    559 	outip->ip_len = packlen;
    560 #endif
    561 	outip->ip_off = off;
    562 	outp = (u_char *)(outip + 1);
    563 #ifdef HAVE_RAW_OPTIONS
    564 	if (lsrr > 0) {
    565 		register u_char *optlist;
    566 
    567 		optlist = outp;
    568 		outp += optlen;
    569 
    570 		/* final hop */
    571 		gwlist[lsrr] = to->sin_addr.s_addr;
    572 
    573 		outip->ip_dst.s_addr = gwlist[0];
    574 
    575 		/* force 4 byte alignment */
    576 		optlist[0] = IPOPT_NOP;
    577 		/* loose source route option */
    578 		optlist[1] = IPOPT_LSRR;
    579 		i = lsrr * sizeof(gwlist[0]);
    580 		optlist[2] = i + 3;
    581 		/* Pointer to LSRR addresses */
    582 		optlist[3] = IPOPT_MINOFF;
    583 		memcpy(optlist + 4, gwlist + 1, i);
    584 	} else
    585 #endif
    586 		outip->ip_dst = to->sin_addr;
    587 
    588 	outip->ip_hl = (outp - (u_char *)outip) >> 2;
    589 	ident = (getpid() & 0xffff) | 0x8000;
    590 	if (useicmp) {
    591 		outip->ip_p = IPPROTO_ICMP;
    592 
    593 		outicmp = (struct icmp *)outp;
    594 		outicmp->icmp_type = ICMP_ECHO;
    595 		outicmp->icmp_id = htons(ident);
    596 
    597 		outmark = outp + 8;	/* XXX magic number */
    598 	} else {
    599 		outip->ip_p = IPPROTO_UDP;
    600 
    601 		outudp = (struct udphdr *)outp;
    602 		outudp->uh_sport = htons(ident);
    603 		outudp->uh_ulen =
    604 		    htons((u_short)(packlen - (sizeof(*outip) + optlen)));
    605 		outmark = outudp + 1;
    606 	}
    607 
    608 	cp = "icmp";
    609 	if ((pe = getprotobyname(cp)) == NULL) {
    610 		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
    611 		exit(1);
    612 	}
    613 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
    614 		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
    615 		exit(1);
    616 	}
    617 	if (options & SO_DEBUG)
    618 		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
    619 		    sizeof(on));
    620 	if (options & SO_DONTROUTE)
    621 		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    622 		    sizeof(on));
    623 
    624 #ifndef __hpux
    625 	sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    626 #else
    627 	sndsock = socket(AF_INET, SOCK_RAW,
    628 	    useicmp ? IPPROTO_ICMP : IPPROTO_UDP);
    629 #endif
    630 	if (sndsock < 0) {
    631 		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
    632 		exit(1);
    633 	}
    634 
    635 	/* Revert to non-privileged user after opening sockets */
    636 	setuid(getuid());
    637 
    638 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
    639 	if (lsrr > 0) {
    640 		u_char optlist[MAX_IPOPTLEN];
    641 
    642 		cp = "ip";
    643 		if ((pe = getprotobyname(cp)) == NULL) {
    644 			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
    645 			exit(1);
    646 		}
    647 
    648 		/* final hop */
    649 		gwlist[lsrr] = to->sin_addr.s_addr;
    650 		++lsrr;
    651 
    652 		/* force 4 byte alignment */
    653 		optlist[0] = IPOPT_NOP;
    654 		/* loose source route option */
    655 		optlist[1] = IPOPT_LSRR;
    656 		i = lsrr * sizeof(gwlist[0]);
    657 		optlist[2] = i + 3;
    658 		/* Pointer to LSRR addresses */
    659 		optlist[3] = IPOPT_MINOFF;
    660 		memcpy(optlist + 4, gwlist, i);
    661 
    662 		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist,
    663 		    i + sizeof(gwlist[0]))) < 0) {
    664 			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
    665 			    prog, strerror(errno));
    666 			exit(1);
    667 		    }
    668 	}
    669 #endif
    670 
    671 #ifdef SO_SNDBUF
    672 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
    673 	    sizeof(packlen)) < 0) {
    674 		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
    675 		exit(1);
    676 	}
    677 #endif
    678 #ifdef IP_HDRINCL
    679 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
    680 	    sizeof(on)) < 0) {
    681 		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
    682 		exit(1);
    683 	}
    684 #else
    685 #ifdef IP_TOS
    686 	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
    687 	    (char *)&tos, sizeof(tos)) < 0) {
    688 		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
    689 		    prog, tos, strerror(errno));
    690 		exit(1);
    691 	}
    692 #endif
    693 #endif
    694 	if (options & SO_DEBUG)
    695 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
    696 		    sizeof(on));
    697 	if (options & SO_DONTROUTE)
    698 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    699 		    sizeof(on));
    700 
    701 	/* Get the interface address list */
    702 	n = ifaddrlist(&al, errbuf, sizeof errbuf);
    703 	al2 = al;
    704 	if (n < 0) {
    705 		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
    706 		exit(1);
    707 	}
    708 	if (n == 0) {
    709 		Fprintf(stderr,
    710 		    "%s: Can't find any network interfaces\n", prog);
    711 		exit(1);
    712 	}
    713 
    714 	/* Look for a specific device */
    715 	if (device != NULL) {
    716 		for (i = n; i > 0; --i, ++al2)
    717 			if (strcmp(device, al2->device) == 0)
    718 				break;
    719 		if (i <= 0) {
    720 			Fprintf(stderr, "%s: Can't find interface %s\n",
    721 			    prog, device);
    722 			exit(1);
    723 		}
    724 	}
    725 
    726 	/* Determine our source address */
    727 	if (source == NULL) {
    728 		/*
    729 		 * If a device was specified, use the interface address.
    730 		 * Otherwise, use the first interface found.
    731 		 * Warn if there are more than one.
    732 		 */
    733 		setsin(from, al2->addr);
    734 		if (n > 1 && device == NULL && !find_local_ip(from, to)) {
    735 			Fprintf(stderr,
    736 		    "%s: Warning: Multiple interfaces found; using %s @ %s\n",
    737 			    prog, inet_ntoa(from->sin_addr), al2->device);
    738 		}
    739 	} else {
    740 		hi = gethostinfo(source);
    741 		source = hi->name;
    742 		hi->name = NULL;
    743 		if (device == NULL) {
    744 			/*
    745 			 * Use the first interface found.
    746 			 * Warn if there are more than one.
    747 			 */
    748 			setsin(from, hi->addrs[0]);
    749 			if (hi->n > 1)
    750 				Fprintf(stderr,
    751 			"%s: Warning: %s has multiple addresses; using %s\n",
    752 				    prog, source, inet_ntoa(from->sin_addr));
    753 		} else {
    754 			/*
    755 			 * Make sure the source specified matches the
    756 			 * interface address.
    757 			 */
    758 			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
    759 				if (*ap == al2->addr)
    760 					break;
    761 			if (i <= 0) {
    762 				Fprintf(stderr,
    763 				    "%s: %s is not on interface %s\n",
    764 				    prog, source, device);
    765 				exit(1);
    766 			}
    767 			setsin(from, *ap);
    768 		}
    769 		freehostinfo(hi);
    770 	}
    771 
    772 	/*
    773 	 * If not root, make sure source address matches a local interface.
    774 	 * (The list of addresses produced by ifaddrlist() automatically
    775 	 * excludes interfaces that are marked down and/or loopback.)
    776 	 */
    777 	if (getuid())  {
    778 		al2 = al;
    779 		for (i = n; i > 0; --i, ++al2)
    780 			if (from->sin_addr.s_addr == al2->addr)
    781 			    break;
    782 		if (i <= 0) {
    783 			Fprintf(stderr, "%s: %s is not a valid local address "
    784 			    "and you are not superuser.\n", prog,
    785 			    inet_ntoa(from->sin_addr));
    786 			exit(1);
    787 		}
    788 	}
    789 
    790 	outip->ip_src = from->sin_addr;
    791 #ifndef IP_HDRINCL
    792 	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
    793 		Fprintf(stderr, "%s: bind: %s\n",
    794 		    prog, strerror(errno));
    795 		exit (1);
    796 	}
    797 #endif
    798 
    799 	setuid(getuid());
    800 	Fprintf(stderr, "%s to %s (%s)",
    801 	    prog, hostname, inet_ntoa(to->sin_addr));
    802 	if (source)
    803 		Fprintf(stderr, " from %s", source);
    804 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
    805 	(void)fflush(stderr);
    806 
    807 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
    808 		u_int32_t lastaddr = 0;
    809 		int got_there = 0;
    810 		int unreachable = 0;
    811 
    812 again:
    813 		Printf("%2d ", ttl);
    814 		for (probe = 0; probe < nprobes; ++probe) {
    815 			register int cc;
    816 			struct timeval t1, t2;
    817 			struct timezone tz;
    818 			register struct ip *ip;
    819 			(void)gettimeofday(&t1, &tz);
    820 			send_probe(++seq, ttl, &t1);
    821 			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
    822 				(void)gettimeofday(&t2, &tz);
    823 				/*
    824 				 * Since we'll be receiving all ICMP
    825 				 * messages to this host above, we may
    826 				 * never end up with cc=0, so we need
    827 				 * an additional termination check.
    828 				 */
    829 				if (t2.tv_sec - t1.tv_sec > waittime) {
    830 					cc = 0;
    831 					break;
    832 				}
    833 				i = packet_ok(packet, cc, from, seq);
    834 				/* Skip short packet */
    835 				if (i == 0)
    836 					continue;
    837 				if (from->sin_addr.s_addr != lastaddr) {
    838 					print(packet, cc, from);
    839 					lastaddr = from->sin_addr.s_addr;
    840 				}
    841 				ip = (struct ip *)packet;
    842 				Printf("  %.3f ms", deltaT(&t1, &t2));
    843 				if (ttl_flag)
    844 					Printf(" (ttl = %d)", ip->ip_ttl);
    845 				if (i == -2) {
    846 #ifndef ARCHAIC
    847 					if (ip->ip_ttl <= 1)
    848 						Printf(" !");
    849 #endif
    850 					++got_there;
    851 					break;
    852 				}
    853 
    854 				/* time exceeded in transit */
    855 				if (i == -1)
    856 					break;
    857 				code = i - 1;
    858 				switch (code) {
    859 
    860 				case ICMP_UNREACH_PORT:
    861 #ifndef ARCHAIC
    862 					if (ip->ip_ttl <= 1)
    863 						Printf(" !");
    864 #endif
    865 					++got_there;
    866 					break;
    867 
    868 				case ICMP_UNREACH_NET:
    869 					++unreachable;
    870 					Printf(" !N");
    871 					break;
    872 
    873 				case ICMP_UNREACH_HOST:
    874 					++unreachable;
    875 					Printf(" !H");
    876 					break;
    877 
    878 				case ICMP_UNREACH_PROTOCOL:
    879 					++got_there;
    880 					Printf(" !P");
    881 					break;
    882 
    883 				case ICMP_UNREACH_NEEDFRAG:
    884 					if (mtudisc) {
    885 						frag_err();
    886 						goto again;
    887 					} else {
    888 						++unreachable;
    889 						Printf(" !F");
    890 					}
    891 					break;
    892 
    893 				case ICMP_UNREACH_SRCFAIL:
    894 					++unreachable;
    895 					Printf(" !S");
    896 					break;
    897 
    898 /* rfc1716 */
    899 #ifndef ICMP_UNREACH_FILTER_PROHIB
    900 #define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
    901 #endif
    902 				case ICMP_UNREACH_FILTER_PROHIB:
    903 					++unreachable;
    904 					Printf(" !X");
    905 					break;
    906 
    907 				default:
    908 					++unreachable;
    909 					Printf(" !<%d>", code);
    910 					break;
    911 				}
    912 				break;
    913 			}
    914 			if (cc == 0)
    915 				Printf(" *");
    916 			(void)fflush(stdout);
    917 		}
    918 		putchar('\n');
    919 		if (got_there ||
    920 		    (unreachable > 0 && unreachable >= nprobes))
    921 			break;
    922 	}
    923 	exit(0);
    924 }
    925 
    926 int
    927 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
    928     register struct timeval *tp)
    929 {
    930 	fd_set fds;
    931 	struct timeval now, wait;
    932 	struct timezone tz;
    933 	register int cc = 0;
    934 	int fromlen = sizeof(*fromp);
    935 	int retval;
    936 
    937 	FD_ZERO(&fds);
    938 	FD_SET(sock, &fds);
    939 
    940 	wait.tv_sec = tp->tv_sec + waittime;
    941 	wait.tv_usec = tp->tv_usec;
    942 	(void)gettimeofday(&now, &tz);
    943 	tvsub(&wait, &now);
    944 
    945 	retval = select(sock + 1, &fds, NULL, NULL, &wait);
    946 	if (retval < 0)  {
    947 		/* If we continue, we probably just flood the remote host. */
    948 		Fprintf(stderr, "%s: select: %s\n", prog, strerror(errno));
    949 		exit(1);
    950 	}
    951 	if (retval > 0)  {
    952 		cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
    953 			    (struct sockaddr *)fromp, &fromlen);
    954 	}
    955 
    956 	return(cc);
    957 }
    958 
    959 void
    960 dump_packet()
    961 {
    962 	u_char *p;
    963 	int i;
    964 
    965 	Fprintf(stderr, "packet data:");
    966 
    967 #ifdef __hpux
    968 	for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i <
    969 	    i < packlen - (sizeof(*outip) + optlen); i++)
    970 #else
    971 	for (p = (u_char *)outip, i = 0; i < packlen; i++)
    972 #endif
    973 	{
    974 		if ((i % 24) == 0)
    975 			Fprintf(stderr, "\n ");
    976 		Fprintf(stderr, " %02x", *p++);
    977 	}
    978 	Fprintf(stderr, "\n");
    979 }
    980 
    981 void
    982 send_probe(register int seq, int ttl, register struct timeval *tp)
    983 {
    984 	register int cc;
    985 	register struct udpiphdr * ui;
    986 	struct ip tip;
    987 
    988 again:
    989 #ifdef BYTESWAP_IP_LEN
    990 	outip->ip_len = htons(packlen);
    991 #else
    992 	outip->ip_len = packlen;
    993 #endif
    994 	outip->ip_ttl = ttl;
    995 #ifndef __hpux
    996 	outip->ip_id = htons(ident + seq);
    997 #endif
    998 
    999 	/*
   1000 	 * In most cases, the kernel will recalculate the ip checksum.
   1001 	 * But we must do it anyway so that the udp checksum comes out
   1002 	 * right.
   1003 	 */
   1004 	if (docksum) {
   1005 		outip->ip_sum =
   1006 		    in_cksum((u_short *)outip, sizeof(*outip) + optlen);
   1007 		if (outip->ip_sum == 0)
   1008 			outip->ip_sum = 0xffff;
   1009 	}
   1010 
   1011 	/* Payload */
   1012 	outsetup.seq = seq;
   1013 	outsetup.ttl = ttl;
   1014 	outsetup.tv  = *tp;
   1015 	memcpy(outmark,&outsetup,sizeof(outsetup));
   1016 
   1017 	if (useicmp)
   1018 		outicmp->icmp_seq = htons(seq);
   1019 	else
   1020 		outudp->uh_dport = htons(port + seq);
   1021 
   1022 	/* (We can only do the checksum if we know our ip address) */
   1023 	if (docksum) {
   1024 		if (useicmp) {
   1025 			outicmp->icmp_cksum = 0;
   1026 			outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
   1027 			    packlen - (sizeof(*outip) + optlen));
   1028 			if (outicmp->icmp_cksum == 0)
   1029 				outicmp->icmp_cksum = 0xffff;
   1030 		} else {
   1031 			/* Checksum (must save and restore ip header) */
   1032 			tip = *outip;
   1033 			ui = (struct udpiphdr *)outip;
   1034 #ifndef __NetBSD__
   1035 			ui->ui_next = 0;
   1036 			ui->ui_prev = 0;
   1037 			ui->ui_x1 = 0;
   1038 #else
   1039 			memset(ui->ui_x1, 0, sizeof(ui->ui_x1));
   1040 #endif
   1041 			ui->ui_len = outudp->uh_ulen;
   1042 			outudp->uh_sum = 0;
   1043 			outudp->uh_sum = in_cksum((u_short *)ui, packlen);
   1044 			if (outudp->uh_sum == 0)
   1045 				outudp->uh_sum = 0xffff;
   1046 			*outip = tip;
   1047 		}
   1048 	}
   1049 
   1050 	/* XXX undocumented debugging hack */
   1051 	if (verbose > 1) {
   1052 		register const u_short *sp;
   1053 		register int nshorts, i;
   1054 
   1055 		sp = (u_short *)outip;
   1056 		nshorts = (u_int)packlen / sizeof(u_short);
   1057 		i = 0;
   1058 		Printf("[ %d bytes", packlen);
   1059 		while (--nshorts >= 0) {
   1060 			if ((i++ % 8) == 0)
   1061 				Printf("\n\t");
   1062 			Printf(" %04x", ntohs(*sp++));
   1063 		}
   1064 		if (packlen & 1) {
   1065 			if ((i % 8) == 0)
   1066 				Printf("\n\t");
   1067 			Printf(" %02x", *(u_char *)sp);
   1068 		}
   1069 		Printf("]\n");
   1070 	}
   1071 
   1072 #if !defined(IP_HDRINCL) && defined(IP_TTL)
   1073 	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
   1074 	    (char *)&ttl, sizeof(ttl)) < 0) {
   1075 		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
   1076 		    prog, ttl, strerror(errno));
   1077 		exit(1);
   1078 	}
   1079 #endif
   1080 	if (dump)
   1081 		dump_packet();
   1082 
   1083 #ifdef __hpux
   1084 	cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
   1085 	    packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
   1086 	if (cc > 0)
   1087 		cc += sizeof(*outip) + optlen;
   1088 #else
   1089 	cc = sendto(sndsock, (char *)outip,
   1090 	    packlen, 0, &whereto, sizeof(whereto));
   1091 #endif
   1092 	if (cc < 0 || cc != packlen)  {
   1093 		if (cc < 0) {
   1094 			/*
   1095 			 * An errno of EMSGSIZE means we're writing too big a
   1096 			 * datagram for the interface.  We have to just decrease
   1097 			 * the packet size until we find one that works.
   1098 			 *
   1099 			 * XXX maybe we should try to read the outgoing if's
   1100 			 * mtu?
   1101 			 */
   1102 
   1103 			if (errno == EMSGSIZE) {
   1104 				packlen = *mtuptr++;
   1105 #ifdef _NoLongerLooksUgly_
   1106                 		Printf("\nmessage too big, "
   1107 				    "trying new MTU = %d ", packlen);
   1108 #endif
   1109 				goto again;
   1110 			} else
   1111 				Fprintf(stderr, "%s: sendto: %s\n",
   1112 				    prog, strerror(errno));
   1113 		}
   1114 
   1115 		Printf("%s: wrote %s %d chars, ret=%d\n",
   1116 		    prog, hostname, packlen, cc);
   1117 		(void)fflush(stdout);
   1118 	}
   1119 }
   1120 
   1121 double
   1122 deltaT(struct timeval *t1p, struct timeval *t2p)
   1123 {
   1124 	register double dt;
   1125 
   1126 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
   1127 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
   1128 	return (dt);
   1129 }
   1130 
   1131 /*
   1132  * Convert an ICMP "type" field to a printable string.
   1133  */
   1134 char *
   1135 pr_type(register u_char t)
   1136 {
   1137 	static char *ttab[] = {
   1138 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
   1139 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
   1140 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
   1141 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
   1142 	"Info Reply"
   1143 	};
   1144 
   1145 	if (t > 16)
   1146 		return("OUT-OF-RANGE");
   1147 
   1148 	return(ttab[t]);
   1149 }
   1150 
   1151 int
   1152 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
   1153     register int seq)
   1154 {
   1155 	register struct icmp *icp;
   1156 	register u_char type, code;
   1157 	register int hlen;
   1158 #ifndef ARCHAIC
   1159 	register struct ip *ip;
   1160 
   1161 	ip = (struct ip *) buf;
   1162 	hlen = ip->ip_hl << 2;
   1163 	if (cc < hlen + ICMP_MINLEN) {
   1164 		if (verbose)
   1165 			Printf("packet too short (%d bytes) from %s\n", cc,
   1166 				inet_ntoa(from->sin_addr));
   1167 		return (0);
   1168 	}
   1169 	cc -= hlen;
   1170 	icp = (struct icmp *)(buf + hlen);
   1171 #else
   1172 	icp = (struct icmp *)buf;
   1173 #endif
   1174 	type = icp->icmp_type;
   1175 	code = icp->icmp_code;
   1176 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
   1177 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
   1178 		register struct ip *hip;
   1179 		register struct udphdr *up;
   1180 		register struct icmp *hicmp;
   1181 
   1182 		hip = &icp->icmp_ip;
   1183 		hlen = hip->ip_hl << 2;
   1184 
   1185 		nextmtu = icp->icmp_nextmtu;	/* for frag_err() */
   1186 
   1187 		if (useicmp) {
   1188 			/* XXX */
   1189 			if (type == ICMP_ECHOREPLY &&
   1190 			    icp->icmp_id == htons(ident) &&
   1191 			    icp->icmp_seq == htons(seq))
   1192 				return (-2);
   1193 
   1194 			hicmp = (struct icmp *)((u_char *)hip + hlen);
   1195 			/* XXX 8 is a magic number */
   1196 			if (hlen + 8 <= cc &&
   1197 			    hip->ip_p == IPPROTO_ICMP &&
   1198 			    hicmp->icmp_id == htons(ident) &&
   1199 			    hicmp->icmp_seq == htons(seq))
   1200 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
   1201 		} else {
   1202 			up = (struct udphdr *)((u_char *)hip + hlen);
   1203 			/* XXX 8 is a magic number */
   1204 			if (hlen + 12 <= cc &&
   1205 			    hip->ip_p == IPPROTO_UDP &&
   1206 			    up->uh_sport == htons(ident) &&
   1207 			    up->uh_dport == htons(port + seq))
   1208 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
   1209 		}
   1210 	}
   1211 #ifndef ARCHAIC
   1212 	if (verbose) {
   1213 		register int i;
   1214 		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
   1215 
   1216 		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
   1217 		Printf("%s: icmp type %d (%s) code %d\n",
   1218 		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
   1219 		for (i = 4; i < cc ; i += sizeof(*lp))
   1220 			Printf("%2d: x%8.8x\n", i, *lp++);
   1221 	}
   1222 #endif
   1223 	return(0);
   1224 }
   1225 
   1226 
   1227 void
   1228 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
   1229 {
   1230 	register struct ip *ip;
   1231 	register int hlen;
   1232 
   1233 	ip = (struct ip *) buf;
   1234 	hlen = ip->ip_hl << 2;
   1235 	cc -= hlen;
   1236 
   1237 	if (nflag)
   1238 		Printf(" %s", inet_ntoa(from->sin_addr));
   1239 	else
   1240 		Printf(" %s (%s)", inetname(from->sin_addr),
   1241 		    inet_ntoa(from->sin_addr));
   1242 
   1243 	if (verbose)
   1244 		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
   1245 }
   1246 
   1247 /*
   1248  * Checksum routine for Internet Protocol family headers (C Version)
   1249  */
   1250 u_short
   1251 in_cksum(register u_short *addr, register int len)
   1252 {
   1253 	register int nleft = len;
   1254 	register u_short *w = addr;
   1255 	register u_short answer;
   1256 	register int sum = 0;
   1257 
   1258 	/*
   1259 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
   1260 	 *  we add sequential 16 bit words to it, and at the end, fold
   1261 	 *  back all the carry bits from the top 16 bits into the lower
   1262 	 *  16 bits.
   1263 	 */
   1264 	while (nleft > 1)  {
   1265 		sum += *w++;
   1266 		nleft -= 2;
   1267 	}
   1268 
   1269 	/* mop up an odd byte, if necessary */
   1270 	if (nleft == 1)
   1271 		sum += *(u_char *)w;
   1272 
   1273 	/*
   1274 	 * add back carry outs from top 16 bits to low 16 bits
   1275 	 */
   1276 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
   1277 	sum += (sum >> 16);			/* add carry */
   1278 	answer = ~sum;				/* truncate to 16 bits */
   1279 	return (answer);
   1280 }
   1281 
   1282 /*
   1283  * Subtract 2 timeval structs:  out = out - in.
   1284  * Out is assumed to be >= in.
   1285  */
   1286 void
   1287 tvsub(register struct timeval *out, register struct timeval *in)
   1288 {
   1289 
   1290 	if ((out->tv_usec -= in->tv_usec) < 0)   {
   1291 		--out->tv_sec;
   1292 		out->tv_usec += 1000000;
   1293 	}
   1294 	out->tv_sec -= in->tv_sec;
   1295 }
   1296 
   1297 /*
   1298  * Construct an Internet address representation.
   1299  * If the nflag has been supplied, give
   1300  * numeric value, otherwise try for symbolic name.
   1301  */
   1302 char *
   1303 inetname(struct in_addr in)
   1304 {
   1305 	register char *cp;
   1306 	register struct hostent *hp;
   1307 	static int first = 1;
   1308 	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
   1309 
   1310 	if (first && !nflag) {
   1311 		int rv;
   1312 
   1313 		first = 0;
   1314 		rv = gethostname(domain, sizeof domain);
   1315 		domain[sizeof(domain) - 1] = '\0';
   1316 		if (rv == 0 && (cp = strchr(domain, '.')) != NULL) {
   1317 			(void)strncpy(domain, cp + 1, sizeof(domain) - 1);
   1318 		} else
   1319 			domain[0] = '\0';
   1320 	}
   1321 	if (!nflag && in.s_addr != INADDR_ANY) {
   1322 		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
   1323 		if (hp != NULL) {
   1324 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
   1325 			    strcmp(cp + 1, domain) == 0)
   1326 				*cp = '\0';
   1327 			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
   1328 			line[sizeof(line) - 1] = '\0';
   1329 			return (line);
   1330 		}
   1331 	}
   1332 	return (inet_ntoa(in));
   1333 }
   1334 
   1335 struct hostinfo *
   1336 gethostinfo(register char *hostname)
   1337 {
   1338 	register int n;
   1339 	register struct hostent *hp;
   1340 	register struct hostinfo *hi;
   1341 	register char **p;
   1342 	register u_int32_t *ap;
   1343 	struct in_addr addr;
   1344 
   1345 	hi = calloc(1, sizeof(*hi));
   1346 	if (hi == NULL) {
   1347 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
   1348 		exit(1);
   1349 	}
   1350 	if (inet_aton(hostname, &addr) != 0) {
   1351 		hi->name = savestr(hostname);
   1352 		hi->n = 1;
   1353 		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
   1354 		if (hi->addrs == NULL) {
   1355 			Fprintf(stderr, "%s: calloc %s\n",
   1356 			    prog, strerror(errno));
   1357 			exit(1);
   1358 		}
   1359 		hi->addrs[0] = addr.s_addr;
   1360 		return (hi);
   1361 	}
   1362 
   1363 	hp = gethostbyname(hostname);
   1364 	if (hp == NULL) {
   1365 		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
   1366 		exit(1);
   1367 	}
   1368 	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
   1369 		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
   1370 		exit(1);
   1371 	}
   1372 	hi->name = savestr(hp->h_name);
   1373 	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
   1374 		continue;
   1375 	hi->n = n;
   1376 	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
   1377 	if (hi->addrs == NULL) {
   1378 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
   1379 		exit(1);
   1380 	}
   1381 	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
   1382 		memcpy(ap, *p, sizeof(*ap));
   1383 	return (hi);
   1384 }
   1385 
   1386 void
   1387 freehostinfo(register struct hostinfo *hi)
   1388 {
   1389 	if (hi->name != NULL) {
   1390 		free(hi->name);
   1391 		hi->name = NULL;
   1392 	}
   1393 	free((char *)hi->addrs);
   1394 	free((char *)hi);
   1395 }
   1396 
   1397 void
   1398 getaddr(register u_int32_t *ap, register char *hostname)
   1399 {
   1400 	register struct hostinfo *hi;
   1401 
   1402 	hi = gethostinfo(hostname);
   1403 	*ap = hi->addrs[0];
   1404 	freehostinfo(hi);
   1405 }
   1406 
   1407 void
   1408 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
   1409 {
   1410 
   1411 	memset(sin, 0, sizeof(*sin));
   1412 #ifdef HAVE_SOCKADDR_SA_LEN
   1413 	sin->sin_len = sizeof(*sin);
   1414 #endif
   1415 	sin->sin_family = AF_INET;
   1416 	sin->sin_addr.s_addr = addr;
   1417 }
   1418 
   1419 /* String to value with optional min and max. Handles decimal and hex. */
   1420 int
   1421 str2val(register const char *str, register const char *what,
   1422     register int mi, register int ma)
   1423 {
   1424 	register const char *cp;
   1425 	register int val;
   1426 	char *ep;
   1427 
   1428 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
   1429 		cp = str + 2;
   1430 		val = (int)strtol(cp, &ep, 16);
   1431 	} else
   1432 		val = (int)strtol(str, &ep, 10);
   1433 	if (*ep != '\0') {
   1434 		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
   1435 		    prog, str, what);
   1436 		exit(1);
   1437 	}
   1438 	if (val < mi && mi >= 0) {
   1439 		if (mi == 0)
   1440 			Fprintf(stderr, "%s: %s must be >= %d\n",
   1441 			    prog, what, mi);
   1442 		else
   1443 			Fprintf(stderr, "%s: %s must be > %d\n",
   1444 			    prog, what, mi - 1);
   1445 		exit(1);
   1446 	}
   1447 	if (val > ma && ma >= 0) {
   1448 		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
   1449 		exit(1);
   1450 	}
   1451 	return (val);
   1452 }
   1453 
   1454 __dead void
   1455 usage(void)
   1456 {
   1457 	extern char version[];
   1458 
   1459 	Fprintf(stderr, "Version %s\n", version);
   1460 	Fprintf(stderr, "Usage: %s [-dDFPIlnrvx] [-g gateway] [-i iface] \
   1461 [-f first_ttl] [-m max_ttl]\n\t[ -p port] [-q nqueries] [-s src_addr] [-t tos] \
   1462 [-w waittime]\n\thost [packetlen]\n",
   1463 	    prog);
   1464 	exit(1);
   1465 }
   1466 
   1467 /*
   1468  * Received ICMP unreachable (fragmentation required and DF set).
   1469  * If the ICMP error was from a "new" router, it'll contain the next-hop
   1470  * MTU that we should use next.  Otherwise we'll just keep going in the
   1471  * mtus[] table, trying until we hit a valid MTU.
   1472  */
   1473 
   1474 
   1475 void
   1476 frag_err()
   1477 {
   1478         int i;
   1479 
   1480         if (nextmtu > 0) {
   1481                 Printf("\nfragmentation required and DF set, next hop MTU = %d\n
   1482 ",
   1483                         nextmtu);
   1484                 packlen = nextmtu;
   1485                 for (i = 0; mtus[i] > 0; i++) {
   1486                         if (mtus[i] < nextmtu) {
   1487                                 mtuptr = &mtus[i];    /* next one to try */
   1488                                 return;
   1489                         }
   1490                 }
   1491         } else {
   1492                 packlen = *mtuptr++;
   1493                 Printf("fragmentation required and DF set, "
   1494 		    "trying new MTU = %d ", packlen);
   1495         }
   1496 }
   1497 
   1498 int
   1499 find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
   1500 {
   1501 	int sock;
   1502 	struct sockaddr_in help;
   1503 	int help_len;
   1504 
   1505 	sock = socket(AF_INET, SOCK_DGRAM, 0);
   1506 	if (sock < 0) return (0);
   1507 
   1508 	help.sin_family = AF_INET;
   1509 	/*
   1510 	 * At this point the port number doesn't matter
   1511 	 * since it only has to be greater than zero.
   1512 	 */
   1513 	help.sin_port = 42;
   1514 	help.sin_addr.s_addr = to->sin_addr.s_addr;
   1515 	if (connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
   1516 		(void)close(sock);
   1517 		return (0);
   1518 	}
   1519 
   1520 	help_len = sizeof(help);
   1521 	if (getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
   1522 	    help_len != sizeof(help) ||
   1523 	    help.sin_addr.s_addr == INADDR_ANY) {
   1524 		(void)close(sock);
   1525 		return (0);
   1526 	}
   1527 
   1528 	(void)close(sock);
   1529 	setsin(from, help.sin_addr.s_addr);
   1530 	return (1);
   1531 }
   1532