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