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