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