Home | History | Annotate | Line # | Download | only in traceroute
traceroute.c revision 1.23
      1 /*	$NetBSD: traceroute.c,v 1.23 1998/07/06 06:59:06 mrg 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.23 1998/07/06 06:59:06 mrg 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 void *outmark;			/* packed location of struct outdata */
    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 
    338 int
    339 main(int argc, char **argv)
    340 {
    341 	register int op, code, n;
    342 	register char *cp;
    343 	register u_char *outp;
    344 	register u_int32_t *ap;
    345 	register struct sockaddr_in *from = &wherefrom;
    346 	register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
    347 	register struct hostinfo *hi;
    348 	int on = 1;
    349 	register struct protoent *pe;
    350 	register int ttl, probe, i;
    351 	register int seq = 0;
    352 	int tos = 0, settos = 0, ttl_flag = 0;
    353 	register int lsrr = 0;
    354 	register u_short off = 0;
    355 	struct ifaddrlist *al;
    356 	char errbuf[132];
    357 
    358 	if ((cp = strrchr(argv[0], '/')) != NULL)
    359 		prog = cp + 1;
    360 	else
    361 		prog = argv[0];
    362 
    363 	opterr = 0;
    364 	while ((op = getopt(argc, argv, "dDFInlrvxf:g:i:m:p:q:s:t:w:")) != -1)
    365 		switch (op) {
    366 
    367 		case 'd':
    368 			options |= SO_DEBUG;
    369 			break;
    370 
    371 		case 'D':
    372 			dump = 1;
    373 			break;
    374 
    375 		case 'f':
    376 			first_ttl = str2val(optarg, "first ttl", 1, 255);
    377 			break;
    378 
    379 		case 'F':
    380 			off = IP_DF;
    381 			break;
    382 
    383 		case 'g':
    384 			if (lsrr >= NGATEWAYS) {
    385 				Fprintf(stderr,
    386 				    "%s: No more than %d gateways\n",
    387 				    prog, NGATEWAYS);
    388 				exit(1);
    389 			}
    390 			getaddr(gwlist + lsrr, optarg);
    391 			++lsrr;
    392 			break;
    393 
    394 		case 'i':
    395 			device = optarg;
    396 			break;
    397 
    398 		case 'I':
    399 			++useicmp;
    400 			break;
    401 
    402 		case 'l':
    403 			++ttl_flag;
    404 			break;
    405 
    406 		case 'm':
    407 			max_ttl = str2val(optarg, "max ttl", 1, 255);
    408 			break;
    409 
    410 		case 'n':
    411 			++nflag;
    412 			break;
    413 
    414 		case 'p':
    415 			port = str2val(optarg, "port", 1, -1);
    416 			break;
    417 
    418 		case 'q':
    419 			nprobes = str2val(optarg, "nprobes", 1, -1);
    420 			break;
    421 
    422 		case 'r':
    423 			options |= SO_DONTROUTE;
    424 			break;
    425 
    426 		case 's':
    427 			/*
    428 			 * set the ip source address of the outbound
    429 			 * probe (e.g., on a multi-homed host).
    430 			 */
    431 			source = optarg;
    432 			break;
    433 
    434 		case 't':
    435 			tos = str2val(optarg, "tos", 0, 255);
    436 			++settos;
    437 			break;
    438 
    439 		case 'v':
    440 			++verbose;
    441 			break;
    442 
    443 		case 'x':
    444 			docksum = (docksum == 0);
    445 			break;
    446 
    447 		case 'w':
    448 			waittime = str2val(optarg, "wait time", 2, -1);
    449 			break;
    450 
    451 		default:
    452 			usage();
    453 		}
    454 
    455 	if (first_ttl > max_ttl) {
    456 		Fprintf(stderr,
    457 		    "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
    458 		    prog, first_ttl, max_ttl);
    459 		exit(1);
    460 	}
    461 
    462 	if (!docksum)
    463 		Fprintf(stderr, "%s: Warning: ckecksums disabled\n", prog);
    464 
    465 	if (lsrr > 0)
    466 		optlen = (lsrr + 1) * sizeof(gwlist[0]);
    467 	minpacket = sizeof(*outip) + sizeof(struct outdata) + optlen;
    468 	if (useicmp)
    469 		minpacket += 8;			/* XXX magic number */
    470 	else
    471 		minpacket += sizeof(*outudp);
    472 	if (packlen == 0)
    473 		packlen = minpacket;		/* minimum sized packet */
    474 	else if (minpacket > packlen || packlen > maxpacket) {
    475 		Fprintf(stderr, "%s: packet size must be %d <= s <= %d\n",
    476 		    prog, minpacket, maxpacket);
    477 		exit(1);
    478 	}
    479 
    480 	/* Process destination and optional packet size */
    481 	switch (argc - optind) {
    482 
    483 	case 2:
    484 		packlen = str2val(argv[optind + 1],
    485 		    "packet length", minpacket, -1);
    486 		/* Fall through */
    487 
    488 	case 1:
    489 		hostname = argv[optind];
    490 		hi = gethostinfo(hostname);
    491 		setsin(to, hi->addrs[0]);
    492 		if (hi->n > 1)
    493 			Fprintf(stderr,
    494 		    "%s: Warning: %s has multiple addresses; using %s\n",
    495 				prog, hostname, inet_ntoa(to->sin_addr));
    496 		hostname = hi->name;
    497 		hi->name = NULL;
    498 		freehostinfo(hi);
    499 		break;
    500 
    501 	default:
    502 		usage();
    503 	}
    504 
    505 #ifdef HAVE_SETLINEBUF
    506 	setlinebuf (stdout);
    507 #else
    508 	setvbuf(stdout, NULL, _IOLBF, 0);
    509 #endif
    510 
    511 	outip = (struct ip *)malloc((unsigned)packlen);
    512 	if (outip == NULL) {
    513 		Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
    514 		exit(1);
    515 	}
    516 	memset((char *)outip, 0, packlen);
    517 
    518 	outip->ip_v = IPVERSION;
    519 	if (settos)
    520 		outip->ip_tos = tos;
    521 #ifdef BYTESWAP_IP_LEN
    522 	outip->ip_len = htons(packlen);
    523 #else
    524 	outip->ip_len = packlen;
    525 #endif
    526 	outip->ip_off = off;
    527 	outp = (u_char *)(outip + 1);
    528 #ifdef HAVE_RAW_OPTIONS
    529 	if (lsrr > 0) {
    530 		register u_char *optlist;
    531 
    532 		optlist = outp;
    533 		outp += optlen;
    534 
    535 		/* final hop */
    536 		gwlist[lsrr] = to->sin_addr.s_addr;
    537 
    538 		outip->ip_dst.s_addr = gwlist[0];
    539 
    540 		/* force 4 byte alignment */
    541 		optlist[0] = IPOPT_NOP;
    542 		/* loose source route option */
    543 		optlist[1] = IPOPT_LSRR;
    544 		i = lsrr * sizeof(gwlist[0]);
    545 		optlist[2] = i + 3;
    546 		/* Pointer to LSRR addresses */
    547 		optlist[3] = IPOPT_MINOFF;
    548 		memcpy(optlist + 4, gwlist + 1, i);
    549 	} else
    550 #endif
    551 		outip->ip_dst = to->sin_addr;
    552 
    553 	outip->ip_hl = (outp - (u_char *)outip) >> 2;
    554 	ident = (getpid() & 0xffff) | 0x8000;
    555 	if (useicmp) {
    556 		outip->ip_p = IPPROTO_ICMP;
    557 
    558 		outicmp = (struct icmp *)outp;
    559 		outicmp->icmp_type = ICMP_ECHO;
    560 		outicmp->icmp_id = htons(ident);
    561 
    562 		outmark = outp + 8;	/* XXX magic number */
    563 	} else {
    564 		outip->ip_p = IPPROTO_UDP;
    565 
    566 		outudp = (struct udphdr *)outp;
    567 		outudp->uh_sport = htons(ident);
    568 		outudp->uh_ulen =
    569 		    htons((u_short)(packlen - (sizeof(*outip) + optlen)));
    570 		outmark = outudp + 1;
    571 	}
    572 
    573 	cp = "icmp";
    574 	if ((pe = getprotobyname(cp)) == NULL) {
    575 		Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
    576 		exit(1);
    577 	}
    578 	if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
    579 		Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
    580 		exit(1);
    581 	}
    582 	if (options & SO_DEBUG)
    583 		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
    584 		    sizeof(on));
    585 	if (options & SO_DONTROUTE)
    586 		(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    587 		    sizeof(on));
    588 
    589 #ifndef __hpux
    590 	sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    591 #else
    592 	sndsock = socket(AF_INET, SOCK_RAW,
    593 	    useicmp ? IPPROTO_ICMP : IPPROTO_UDP);
    594 #endif
    595 	if (sndsock < 0) {
    596 		Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
    597 		exit(1);
    598 	}
    599 
    600 	/* Revert to non-privileged user after opening sockets */
    601 	setuid(getuid());
    602 
    603 #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
    604 	if (lsrr > 0) {
    605 		u_char optlist[MAX_IPOPTLEN];
    606 
    607 		cp = "ip";
    608 		if ((pe = getprotobyname(cp)) == NULL) {
    609 			Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
    610 			exit(1);
    611 		}
    612 
    613 		/* final hop */
    614 		gwlist[lsrr] = to->sin_addr.s_addr;
    615 		++lsrr;
    616 
    617 		/* force 4 byte alignment */
    618 		optlist[0] = IPOPT_NOP;
    619 		/* loose source route option */
    620 		optlist[1] = IPOPT_LSRR;
    621 		i = lsrr * sizeof(gwlist[0]);
    622 		optlist[2] = i + 3;
    623 		/* Pointer to LSRR addresses */
    624 		optlist[3] = IPOPT_MINOFF;
    625 		memcpy(optlist + 4, gwlist, i);
    626 
    627 		if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist,
    628 		    i + sizeof(gwlist[0]))) < 0) {
    629 			Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
    630 			    prog, strerror(errno));
    631 			exit(1);
    632 		    }
    633 	}
    634 #endif
    635 
    636 #ifdef SO_SNDBUF
    637 	if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
    638 	    sizeof(packlen)) < 0) {
    639 		Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
    640 		exit(1);
    641 	}
    642 #endif
    643 #ifdef IP_HDRINCL
    644 	if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
    645 	    sizeof(on)) < 0) {
    646 		Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
    647 		exit(1);
    648 	}
    649 #else
    650 #ifdef IP_TOS
    651 	if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
    652 	    (char *)&tos, sizeof(tos)) < 0) {
    653 		Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
    654 		    prog, tos, strerror(errno));
    655 		exit(1);
    656 	}
    657 #endif
    658 #endif
    659 	if (options & SO_DEBUG)
    660 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
    661 		    sizeof(on));
    662 	if (options & SO_DONTROUTE)
    663 		(void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
    664 		    sizeof(on));
    665 
    666 	/* Get the interface address list */
    667 	n = ifaddrlist(&al, errbuf, sizeof errbuf);
    668 	if (n < 0) {
    669 		Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
    670 		exit(1);
    671 	}
    672 	if (n == 0) {
    673 		Fprintf(stderr,
    674 		    "%s: Can't find any network interfaces\n", prog);
    675 		exit(1);
    676 	}
    677 
    678 	/* Look for a specific device */
    679 	if (device != NULL) {
    680 		for (i = n; i > 0; --i, ++al)
    681 			if (strcmp(device, al->device) == 0)
    682 				break;
    683 		if (i <= 0) {
    684 			Fprintf(stderr, "%s: Can't find interface %s\n",
    685 			    prog, device);
    686 			exit(1);
    687 		}
    688 	}
    689 
    690 	/* Determine our source address */
    691 	if (source == NULL) {
    692 		/*
    693 		 * If a device was specified, use the interface address.
    694 		 * Otherwise, use the first interface found.
    695 		 * Warn if there are more than one.
    696 		 */
    697 		setsin(from, al->addr);
    698 		if (n > 1 && device == NULL) {
    699 			Fprintf(stderr,
    700 		    "%s: Warning: Multiple interfaces found; using %s @ %s\n",
    701 			    prog, inet_ntoa(from->sin_addr), al->device);
    702 		}
    703 	} else {
    704 		hi = gethostinfo(source);
    705 		source = hi->name;
    706 		hi->name = NULL;
    707 		if (device == NULL) {
    708 			/*
    709 			 * Use the first interface found.
    710 			 * Warn if there are more than one.
    711 			 */
    712 			setsin(from, hi->addrs[0]);
    713 			if (hi->n > 1)
    714 				Fprintf(stderr,
    715 			"%s: Warning: %s has multiple addresses; using %s\n",
    716 				    prog, source, inet_ntoa(from->sin_addr));
    717 		} else {
    718 			/*
    719 			 * Make sure the source specified matches the
    720 			 * interface address.
    721 			 */
    722 			for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
    723 				if (*ap == al->addr)
    724 					break;
    725 			if (i <= 0) {
    726 				Fprintf(stderr,
    727 				    "%s: %s is not on interface %s\n",
    728 				    prog, source, device);
    729 				exit(1);
    730 			}
    731 			setsin(from, *ap);
    732 		}
    733 		freehostinfo(hi);
    734 	}
    735 	outip->ip_src = from->sin_addr;
    736 #ifndef IP_HDRINCL
    737 	if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
    738 		Fprintf(stderr, "%s: bind: %s\n",
    739 		    prog, strerror(errno));
    740 		exit (1);
    741 	}
    742 #endif
    743 
    744 	setuid(getuid());
    745 	Fprintf(stderr, "%s to %s (%s)",
    746 	    prog, hostname, inet_ntoa(to->sin_addr));
    747 	if (source)
    748 		Fprintf(stderr, " from %s", source);
    749 	Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
    750 	(void)fflush(stderr);
    751 
    752 	for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
    753 		u_int32_t lastaddr = 0;
    754 		int got_there = 0;
    755 		int unreachable = 0;
    756 
    757 		Printf("%2d ", ttl);
    758 		for (probe = 0; probe < nprobes; ++probe) {
    759 			register int cc;
    760 			struct timeval t1, t2;
    761 			struct timezone tz;
    762 			register struct ip *ip;
    763 
    764 			(void)gettimeofday(&t1, &tz);
    765 			send_probe(++seq, ttl, &t1);
    766 			while ((cc = wait_for_reply(s, from, &t1)) != 0) {
    767 				(void)gettimeofday(&t2, &tz);
    768 				/*
    769 				 * Since we'll be receiving all ICMP
    770 				 * messages to this host above, we may
    771 				 * never end up with cc=0, so we need
    772 				 * an additional termination check.
    773 				 */
    774 				if (t2.tv_sec - t1.tv_sec > waittime) {
    775 					cc = 0;
    776 					break;
    777 				}
    778 				i = packet_ok(packet, cc, from, seq);
    779 				/* Skip short packet */
    780 				if (i == 0)
    781 					continue;
    782 				if (from->sin_addr.s_addr != lastaddr) {
    783 					print(packet, cc, from);
    784 					lastaddr = from->sin_addr.s_addr;
    785 				}
    786 				ip = (struct ip *)packet;
    787 				Printf("  %.3f ms", deltaT(&t1, &t2));
    788 				if (ttl_flag)
    789 					Printf(" (ttl = %d)", ip->ip_ttl);
    790 				if (i == -2) {
    791 #ifndef ARCHAIC
    792 					if (ip->ip_ttl <= 1)
    793 						Printf(" !");
    794 #endif
    795 					++got_there;
    796 					break;
    797 				}
    798 				/* time exceeded in transit */
    799 				if (i == -1)
    800 					break;
    801 				code = i - 1;
    802 				switch (code) {
    803 
    804 				case ICMP_UNREACH_PORT:
    805 #ifndef ARCHAIC
    806 					if (ip->ip_ttl <= 1)
    807 						Printf(" !");
    808 #endif
    809 					++got_there;
    810 					break;
    811 
    812 				case ICMP_UNREACH_NET:
    813 					++unreachable;
    814 					Printf(" !N");
    815 					break;
    816 
    817 				case ICMP_UNREACH_HOST:
    818 					++unreachable;
    819 					Printf(" !H");
    820 					break;
    821 
    822 				case ICMP_UNREACH_PROTOCOL:
    823 					++got_there;
    824 					Printf(" !P");
    825 					break;
    826 
    827 				case ICMP_UNREACH_NEEDFRAG:
    828 					++unreachable;
    829 					Printf(" !F");
    830 					break;
    831 
    832 				case ICMP_UNREACH_SRCFAIL:
    833 					++unreachable;
    834 					Printf(" !S");
    835 					break;
    836 
    837 /* rfc1716 */
    838 #ifndef ICMP_UNREACH_FILTER_PROHIB
    839 #define ICMP_UNREACH_FILTER_PROHIB	13	/* admin prohibited filter */
    840 #endif
    841 				case ICMP_UNREACH_FILTER_PROHIB:
    842 					++unreachable;
    843 					Printf(" !X");
    844 					break;
    845 
    846 				default:
    847 					++unreachable;
    848 					Printf(" !<%d>", code);
    849 					break;
    850 				}
    851 				break;
    852 			}
    853 			if (cc == 0)
    854 				Printf(" *");
    855 			(void)fflush(stdout);
    856 		}
    857 		putchar('\n');
    858 		if (got_there ||
    859 		    (unreachable > 0 && unreachable >= nprobes))
    860 			break;
    861 	}
    862 	exit(0);
    863 }
    864 
    865 int
    866 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
    867     register struct timeval *tp)
    868 {
    869 	fd_set fds;
    870 	struct timeval now, wait;
    871 	struct timezone tz;
    872 	register int cc = 0;
    873 	int fromlen = sizeof(*fromp);
    874 
    875 	FD_ZERO(&fds);
    876 	FD_SET(sock, &fds);
    877 
    878 	wait.tv_sec = tp->tv_sec + waittime;
    879 	wait.tv_usec = tp->tv_usec;
    880 	(void)gettimeofday(&now, &tz);
    881 	tvsub(&wait, &now);
    882 
    883 	if (select(sock + 1, &fds, NULL, NULL, &wait) > 0)
    884 		cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
    885 			    (struct sockaddr *)fromp, &fromlen);
    886 
    887 	return(cc);
    888 }
    889 
    890 void
    891 dump_packet()
    892 {
    893 	u_char *p;
    894 	int i;
    895 
    896 	Fprintf(stderr, "packet data:");
    897 
    898 #ifdef __hpux
    899 	for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i <
    900 	    i < packlen - (sizeof(*outip) + optlen); i++)
    901 #else
    902 	for (p = (u_char *)outip, i = 0; i < packlen; i++)
    903 #endif
    904 	{
    905 		if ((i % 24) == 0)
    906 			Fprintf(stderr, "\n ");
    907 		Fprintf(stderr, " %02x", *p++);
    908 	}
    909 	Fprintf(stderr, "\n");
    910 }
    911 
    912 void
    913 send_probe(register int seq, int ttl, register struct timeval *tp)
    914 {
    915 	register int cc;
    916 	register struct udpiphdr * ui;
    917 	struct ip tip;
    918 
    919 	outip->ip_ttl = ttl;
    920 #ifndef __hpux
    921 	outip->ip_id = htons(ident + seq);
    922 #endif
    923 
    924 	/*
    925 	 * In most cases, the kernel will recalculate the ip checksum.
    926 	 * But we must do it anyway so that the udp checksum comes out
    927 	 * right.
    928 	 */
    929 	if (docksum) {
    930 		outip->ip_sum =
    931 		    in_cksum((u_short *)outip, sizeof(*outip) + optlen);
    932 		if (outip->ip_sum == 0)
    933 			outip->ip_sum = 0xffff;
    934 	}
    935 
    936 	/* Payload */
    937 	outsetup.seq = seq;
    938 	outsetup.ttl = ttl;
    939 	outsetup.tv  = *tp;
    940 	memcpy(outmark,&outsetup,sizeof(outsetup));
    941 
    942 	if (useicmp)
    943 		outicmp->icmp_seq = htons(seq);
    944 	else
    945 		outudp->uh_dport = htons(port + seq);
    946 
    947 	/* (We can only do the checksum if we know our ip address) */
    948 	if (docksum) {
    949 		if (useicmp) {
    950 			outicmp->icmp_cksum = 0;
    951 			outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
    952 			    packlen - (sizeof(*outip) + optlen));
    953 			if (outicmp->icmp_cksum == 0)
    954 				outicmp->icmp_cksum = 0xffff;
    955 		} else {
    956 			/* Checksum (must save and restore ip header) */
    957 			tip = *outip;
    958 			ui = (struct udpiphdr *)outip;
    959 #ifndef __NetBSD__
    960 			ui->ui_next = 0;
    961 			ui->ui_prev = 0;
    962 			ui->ui_x1 = 0;
    963 #else
    964 			memset(ui->ui_x1, 0, sizeof(ui->ui_x1));
    965 #endif
    966 			ui->ui_len = outudp->uh_ulen;
    967 			outudp->uh_sum = 0;
    968 			outudp->uh_sum = in_cksum((u_short *)ui, packlen);
    969 			if (outudp->uh_sum == 0)
    970 				outudp->uh_sum = 0xffff;
    971 			*outip = tip;
    972 		}
    973 	}
    974 
    975 	/* XXX undocumented debugging hack */
    976 	if (verbose > 1) {
    977 		register const u_short *sp;
    978 		register int nshorts, i;
    979 
    980 		sp = (u_short *)outip;
    981 		nshorts = (u_int)packlen / sizeof(u_short);
    982 		i = 0;
    983 		Printf("[ %d bytes", packlen);
    984 		while (--nshorts >= 0) {
    985 			if ((i++ % 8) == 0)
    986 				Printf("\n\t");
    987 			Printf(" %04x", ntohs(*sp++));
    988 		}
    989 		if (packlen & 1) {
    990 			if ((i % 8) == 0)
    991 				Printf("\n\t");
    992 			Printf(" %02x", *(u_char *)sp);
    993 		}
    994 		Printf("]\n");
    995 	}
    996 
    997 #if !defined(IP_HDRINCL) && defined(IP_TTL)
    998 	if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
    999 	    (char *)&ttl, sizeof(ttl)) < 0) {
   1000 		Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
   1001 		    prog, ttl, strerror(errno));
   1002 		exit(1);
   1003 	}
   1004 #endif
   1005 	if (dump)
   1006 		dump_packet();
   1007 
   1008 #ifdef __hpux
   1009 	cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
   1010 	    packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
   1011 	if (cc > 0)
   1012 		cc += sizeof(*outip) + optlen;
   1013 #else
   1014 	cc = sendto(sndsock, (char *)outip,
   1015 	    packlen, 0, &whereto, sizeof(whereto));
   1016 #endif
   1017 	if (cc < 0 || cc != packlen)  {
   1018 		if (cc < 0)
   1019 			Fprintf(stderr, "%s: sendto: %s\n",
   1020 			    prog, strerror(errno));
   1021 		Printf("%s: wrote %s %d chars, ret=%d\n",
   1022 		    prog, hostname, packlen, cc);
   1023 		(void)fflush(stdout);
   1024 	}
   1025 }
   1026 
   1027 double
   1028 deltaT(struct timeval *t1p, struct timeval *t2p)
   1029 {
   1030 	register double dt;
   1031 
   1032 	dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
   1033 	     (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
   1034 	return (dt);
   1035 }
   1036 
   1037 /*
   1038  * Convert an ICMP "type" field to a printable string.
   1039  */
   1040 char *
   1041 pr_type(register u_char t)
   1042 {
   1043 	static char *ttab[] = {
   1044 	"Echo Reply",	"ICMP 1",	"ICMP 2",	"Dest Unreachable",
   1045 	"Source Quench", "Redirect",	"ICMP 6",	"ICMP 7",
   1046 	"Echo",		"ICMP 9",	"ICMP 10",	"Time Exceeded",
   1047 	"Param Problem", "Timestamp",	"Timestamp Reply", "Info Request",
   1048 	"Info Reply"
   1049 	};
   1050 
   1051 	if (t > 16)
   1052 		return("OUT-OF-RANGE");
   1053 
   1054 	return(ttab[t]);
   1055 }
   1056 
   1057 int
   1058 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
   1059     register int seq)
   1060 {
   1061 	register struct icmp *icp;
   1062 	register u_char type, code;
   1063 	register int hlen;
   1064 #ifndef ARCHAIC
   1065 	register struct ip *ip;
   1066 
   1067 	ip = (struct ip *) buf;
   1068 	hlen = ip->ip_hl << 2;
   1069 	if (cc < hlen + ICMP_MINLEN) {
   1070 		if (verbose)
   1071 			Printf("packet too short (%d bytes) from %s\n", cc,
   1072 				inet_ntoa(from->sin_addr));
   1073 		return (0);
   1074 	}
   1075 	cc -= hlen;
   1076 	icp = (struct icmp *)(buf + hlen);
   1077 #else
   1078 	icp = (struct icmp *)buf;
   1079 #endif
   1080 	type = icp->icmp_type;
   1081 	code = icp->icmp_code;
   1082 	if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
   1083 	    type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
   1084 		register struct ip *hip;
   1085 		register struct udphdr *up;
   1086 		register struct icmp *hicmp;
   1087 
   1088 		hip = &icp->icmp_ip;
   1089 		hlen = hip->ip_hl << 2;
   1090 		if (useicmp) {
   1091 			/* XXX */
   1092 			if (type == ICMP_ECHOREPLY &&
   1093 			    icp->icmp_id == htons(ident) &&
   1094 			    icp->icmp_seq == htons(seq))
   1095 				return (-2);
   1096 
   1097 			hicmp = (struct icmp *)((u_char *)hip + hlen);
   1098 			/* XXX 8 is a magic number */
   1099 			if (hlen + 8 <= cc &&
   1100 			    hip->ip_p == IPPROTO_ICMP &&
   1101 			    hicmp->icmp_id == htons(ident) &&
   1102 			    hicmp->icmp_seq == htons(seq))
   1103 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
   1104 		} else {
   1105 			up = (struct udphdr *)((u_char *)hip + hlen);
   1106 			/* XXX 8 is a magic number */
   1107 			if (hlen + 12 <= cc &&
   1108 			    hip->ip_p == IPPROTO_UDP &&
   1109 			    up->uh_sport == htons(ident) &&
   1110 			    up->uh_dport == htons(port + seq))
   1111 				return (type == ICMP_TIMXCEED ? -1 : code + 1);
   1112 		}
   1113 	}
   1114 #ifndef ARCHAIC
   1115 	if (verbose) {
   1116 		register int i;
   1117 		u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
   1118 
   1119 		Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
   1120 		Printf("%s: icmp type %d (%s) code %d\n",
   1121 		    inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
   1122 		for (i = 4; i < cc ; i += sizeof(*lp))
   1123 			Printf("%2d: x%8.8x\n", i, *lp++);
   1124 	}
   1125 #endif
   1126 	return(0);
   1127 }
   1128 
   1129 
   1130 void
   1131 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
   1132 {
   1133 	register struct ip *ip;
   1134 	register int hlen;
   1135 
   1136 	ip = (struct ip *) buf;
   1137 	hlen = ip->ip_hl << 2;
   1138 	cc -= hlen;
   1139 
   1140 	if (nflag)
   1141 		Printf(" %s", inet_ntoa(from->sin_addr));
   1142 	else
   1143 		Printf(" %s (%s)", inetname(from->sin_addr),
   1144 		    inet_ntoa(from->sin_addr));
   1145 
   1146 	if (verbose)
   1147 		Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
   1148 }
   1149 
   1150 /*
   1151  * Checksum routine for Internet Protocol family headers (C Version)
   1152  */
   1153 u_short
   1154 in_cksum(register u_short *addr, register int len)
   1155 {
   1156 	register int nleft = len;
   1157 	register u_short *w = addr;
   1158 	register u_short answer;
   1159 	register int sum = 0;
   1160 
   1161 	/*
   1162 	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
   1163 	 *  we add sequential 16 bit words to it, and at the end, fold
   1164 	 *  back all the carry bits from the top 16 bits into the lower
   1165 	 *  16 bits.
   1166 	 */
   1167 	while (nleft > 1)  {
   1168 		sum += *w++;
   1169 		nleft -= 2;
   1170 	}
   1171 
   1172 	/* mop up an odd byte, if necessary */
   1173 	if (nleft == 1)
   1174 		sum += *(u_char *)w;
   1175 
   1176 	/*
   1177 	 * add back carry outs from top 16 bits to low 16 bits
   1178 	 */
   1179 	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
   1180 	sum += (sum >> 16);			/* add carry */
   1181 	answer = ~sum;				/* truncate to 16 bits */
   1182 	return (answer);
   1183 }
   1184 
   1185 /*
   1186  * Subtract 2 timeval structs:  out = out - in.
   1187  * Out is assumed to be >= in.
   1188  */
   1189 void
   1190 tvsub(register struct timeval *out, register struct timeval *in)
   1191 {
   1192 
   1193 	if ((out->tv_usec -= in->tv_usec) < 0)   {
   1194 		--out->tv_sec;
   1195 		out->tv_usec += 1000000;
   1196 	}
   1197 	out->tv_sec -= in->tv_sec;
   1198 }
   1199 
   1200 /*
   1201  * Construct an Internet address representation.
   1202  * If the nflag has been supplied, give
   1203  * numeric value, otherwise try for symbolic name.
   1204  */
   1205 char *
   1206 inetname(struct in_addr in)
   1207 {
   1208 	register char *cp;
   1209 	register struct hostent *hp;
   1210 	static int first = 1;
   1211 	static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
   1212 
   1213 	if (first && !nflag) {
   1214 		int rv;
   1215 
   1216 		first = 0;
   1217 		rv = gethostname(domain, sizeof domain);
   1218 		domain[sizeof(domain) - 1] = '\0';
   1219 		if (rv == 0 && (cp = strchr(domain, '.')) != NULL) {
   1220 			(void)strncpy(domain, cp + 1, sizeof(domain) - 1);
   1221 		} else
   1222 			domain[0] = '\0';
   1223 	}
   1224 	if (!nflag && in.s_addr != INADDR_ANY) {
   1225 		hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
   1226 		if (hp != NULL) {
   1227 			if ((cp = strchr(hp->h_name, '.')) != NULL &&
   1228 			    strcmp(cp + 1, domain) == 0)
   1229 				*cp = '\0';
   1230 			(void)strncpy(line, hp->h_name, sizeof(line) - 1);
   1231 			line[sizeof(line) - 1] = '\0';
   1232 			return (line);
   1233 		}
   1234 	}
   1235 	return (inet_ntoa(in));
   1236 }
   1237 
   1238 struct hostinfo *
   1239 gethostinfo(register char *hostname)
   1240 {
   1241 	register int n;
   1242 	register struct hostent *hp;
   1243 	register struct hostinfo *hi;
   1244 	register char **p;
   1245 	register u_int32_t *ap;
   1246 	struct in_addr addr;
   1247 
   1248 	hi = calloc(1, sizeof(*hi));
   1249 	if (hi == NULL) {
   1250 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
   1251 		exit(1);
   1252 	}
   1253 	if (inet_aton(hostname, &addr) != 0) {
   1254 		hi->name = savestr(hostname);
   1255 		hi->n = 1;
   1256 		hi->addrs = calloc(1, sizeof(hi->addrs[0]));
   1257 		if (hi->addrs == NULL) {
   1258 			Fprintf(stderr, "%s: calloc %s\n",
   1259 			    prog, strerror(errno));
   1260 			exit(1);
   1261 		}
   1262 		hi->addrs[0] = addr.s_addr;
   1263 		return (hi);
   1264 	}
   1265 
   1266 	hp = gethostbyname(hostname);
   1267 	if (hp == NULL) {
   1268 		Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
   1269 		exit(1);
   1270 	}
   1271 	if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
   1272 		Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
   1273 		exit(1);
   1274 	}
   1275 	hi->name = savestr(hp->h_name);
   1276 	for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
   1277 		continue;
   1278 	hi->n = n;
   1279 	hi->addrs = calloc(n, sizeof(hi->addrs[0]));
   1280 	if (hi->addrs == NULL) {
   1281 		Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
   1282 		exit(1);
   1283 	}
   1284 	for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
   1285 		memcpy(ap, *p, sizeof(*ap));
   1286 	return (hi);
   1287 }
   1288 
   1289 void
   1290 freehostinfo(register struct hostinfo *hi)
   1291 {
   1292 	if (hi->name != NULL) {
   1293 		free(hi->name);
   1294 		hi->name = NULL;
   1295 	}
   1296 	free((char *)hi->addrs);
   1297 	free((char *)hi);
   1298 }
   1299 
   1300 void
   1301 getaddr(register u_int32_t *ap, register char *hostname)
   1302 {
   1303 	register struct hostinfo *hi;
   1304 
   1305 	hi = gethostinfo(hostname);
   1306 	*ap = hi->addrs[0];
   1307 	freehostinfo(hi);
   1308 }
   1309 
   1310 void
   1311 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
   1312 {
   1313 
   1314 	memset(sin, 0, sizeof(*sin));
   1315 #ifdef HAVE_SOCKADDR_SA_LEN
   1316 	sin->sin_len = sizeof(*sin);
   1317 #endif
   1318 	sin->sin_family = AF_INET;
   1319 	sin->sin_addr.s_addr = addr;
   1320 }
   1321 
   1322 /* String to value with optional min and max. Handles decimal and hex. */
   1323 int
   1324 str2val(register const char *str, register const char *what,
   1325     register int mi, register int ma)
   1326 {
   1327 	register const char *cp;
   1328 	register int val;
   1329 	char *ep;
   1330 
   1331 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
   1332 		cp = str + 2;
   1333 		val = (int)strtol(cp, &ep, 16);
   1334 	} else
   1335 		val = (int)strtol(str, &ep, 10);
   1336 	if (*ep != '\0') {
   1337 		Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
   1338 		    prog, str, what);
   1339 		exit(1);
   1340 	}
   1341 	if (val < mi && mi >= 0) {
   1342 		if (mi == 0)
   1343 			Fprintf(stderr, "%s: %s must be >= %d\n",
   1344 			    prog, what, mi);
   1345 		else
   1346 			Fprintf(stderr, "%s: %s must be > %d\n",
   1347 			    prog, what, mi - 1);
   1348 		exit(1);
   1349 	}
   1350 	if (val > ma && ma >= 0) {
   1351 		Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
   1352 		exit(1);
   1353 	}
   1354 	return (val);
   1355 }
   1356 
   1357 __dead void
   1358 usage(void)
   1359 {
   1360 	extern char version[];
   1361 
   1362 	Fprintf(stderr, "Version %s\n", version);
   1363 	Fprintf(stderr, "Usage: %s [-dDFIlnrvx] [-g gateway] [-i iface] \
   1364 [-f first_ttl] [-m max_ttl]\n\t[ -p port] [-q nqueries] [-s src_addr] [-t tos] \
   1365 [-w waittime]\n\thost [packetlen]\n",
   1366 	    prog);
   1367 	exit(1);
   1368 }
   1369