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