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