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