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