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