traceroute.c revision 1.36 1 /* $NetBSD: traceroute.c,v 1.36 1999/06/19 05:07:44 kim 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.36 1999/06/19 05:07:44 kim 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 + 1) / 2)))
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 outudp->uh_ulen =
1105 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1106 #ifdef _NoLongerLooksUgly_
1107 Printf("message too big, "
1108 "trying new MTU = %d\n", packlen);
1109 #endif
1110 goto again;
1111 } else
1112 Fprintf(stderr, "%s: sendto: %s\n",
1113 prog, strerror(errno));
1114 }
1115
1116 Printf("%s: wrote %s %d chars, ret=%d\n",
1117 prog, hostname, packlen, cc);
1118 (void)fflush(stdout);
1119 }
1120 }
1121
1122 double
1123 deltaT(struct timeval *t1p, struct timeval *t2p)
1124 {
1125 register double dt;
1126
1127 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
1128 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
1129 return (dt);
1130 }
1131
1132 /*
1133 * Convert an ICMP "type" field to a printable string.
1134 */
1135 char *
1136 pr_type(register u_char t)
1137 {
1138 static char *ttab[] = {
1139 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
1140 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
1141 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
1142 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
1143 "Info Reply"
1144 };
1145
1146 if (t > 16)
1147 return("OUT-OF-RANGE");
1148
1149 return(ttab[t]);
1150 }
1151
1152 int
1153 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
1154 register int seq)
1155 {
1156 register struct icmp *icp;
1157 register u_char type, code;
1158 register int hlen;
1159 #ifndef ARCHAIC
1160 register struct ip *ip;
1161
1162 ip = (struct ip *) buf;
1163 hlen = ip->ip_hl << 2;
1164 if (cc < hlen + ICMP_MINLEN) {
1165 if (verbose)
1166 Printf("packet too short (%d bytes) from %s\n", cc,
1167 inet_ntoa(from->sin_addr));
1168 return (0);
1169 }
1170 cc -= hlen;
1171 icp = (struct icmp *)(buf + hlen);
1172 #else
1173 icp = (struct icmp *)buf;
1174 #endif
1175 type = icp->icmp_type;
1176 code = icp->icmp_code;
1177 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
1178 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
1179 register struct ip *hip;
1180 register struct udphdr *up;
1181 register struct icmp *hicmp;
1182
1183 hip = &icp->icmp_ip;
1184 hlen = hip->ip_hl << 2;
1185
1186 nextmtu = ntohs(icp->icmp_nextmtu); /* for frag_err() */
1187
1188 if (useicmp) {
1189 /* XXX */
1190 if (type == ICMP_ECHOREPLY &&
1191 icp->icmp_id == htons(ident) &&
1192 icp->icmp_seq == htons(seq))
1193 return (-2);
1194
1195 hicmp = (struct icmp *)((u_char *)hip + hlen);
1196 /* XXX 8 is a magic number */
1197 if (hlen + 8 <= cc &&
1198 hip->ip_p == IPPROTO_ICMP &&
1199 hicmp->icmp_id == htons(ident) &&
1200 hicmp->icmp_seq == htons(seq))
1201 return (type == ICMP_TIMXCEED ? -1 : code + 1);
1202 } else {
1203 up = (struct udphdr *)((u_char *)hip + hlen);
1204 /* XXX 8 is a magic number */
1205 if (hlen + 12 <= cc &&
1206 hip->ip_p == IPPROTO_UDP &&
1207 up->uh_sport == htons(ident) &&
1208 up->uh_dport == htons(port + seq))
1209 return (type == ICMP_TIMXCEED ? -1 : code + 1);
1210 }
1211 }
1212 #ifndef ARCHAIC
1213 if (verbose) {
1214 register int i;
1215 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
1216
1217 Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
1218 Printf("%s: icmp type %d (%s) code %d\n",
1219 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1220 for (i = 4; i < cc ; i += sizeof(*lp))
1221 Printf("%2d: x%8.8x\n", i, *lp++);
1222 }
1223 #endif
1224 return(0);
1225 }
1226
1227
1228 void
1229 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
1230 {
1231 register struct ip *ip;
1232 register int hlen;
1233
1234 ip = (struct ip *) buf;
1235 hlen = ip->ip_hl << 2;
1236 cc -= hlen;
1237
1238 if (nflag)
1239 Printf(" %s", inet_ntoa(from->sin_addr));
1240 else
1241 Printf(" %s (%s)", inetname(from->sin_addr),
1242 inet_ntoa(from->sin_addr));
1243
1244 if (verbose)
1245 Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
1246 }
1247
1248 /*
1249 * Checksum routine for Internet Protocol family headers (C Version)
1250 */
1251 u_short
1252 in_cksum(register u_short *addr, register int len)
1253 {
1254 register int nleft = len;
1255 register u_short *w = addr;
1256 register u_short answer;
1257 register int sum = 0;
1258
1259 /*
1260 * Our algorithm is simple, using a 32 bit accumulator (sum),
1261 * we add sequential 16 bit words to it, and at the end, fold
1262 * back all the carry bits from the top 16 bits into the lower
1263 * 16 bits.
1264 */
1265 while (nleft > 1) {
1266 sum += *w++;
1267 nleft -= 2;
1268 }
1269
1270 /* mop up an odd byte, if necessary */
1271 if (nleft == 1)
1272 sum += *(u_char *)w;
1273
1274 /*
1275 * add back carry outs from top 16 bits to low 16 bits
1276 */
1277 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1278 sum += (sum >> 16); /* add carry */
1279 answer = ~sum; /* truncate to 16 bits */
1280 return (answer);
1281 }
1282
1283 /*
1284 * Subtract 2 timeval structs: out = out - in.
1285 * Out is assumed to be >= in.
1286 */
1287 void
1288 tvsub(register struct timeval *out, register struct timeval *in)
1289 {
1290
1291 if ((out->tv_usec -= in->tv_usec) < 0) {
1292 --out->tv_sec;
1293 out->tv_usec += 1000000;
1294 }
1295 out->tv_sec -= in->tv_sec;
1296 }
1297
1298 /*
1299 * Construct an Internet address representation.
1300 * If the nflag has been supplied, give
1301 * numeric value, otherwise try for symbolic name.
1302 */
1303 char *
1304 inetname(struct in_addr in)
1305 {
1306 register char *cp;
1307 register struct hostent *hp;
1308 static int first = 1;
1309 static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
1310
1311 if (first && !nflag) {
1312 int rv;
1313
1314 first = 0;
1315 rv = gethostname(domain, sizeof domain);
1316 domain[sizeof(domain) - 1] = '\0';
1317 if (rv == 0 && (cp = strchr(domain, '.')) != NULL) {
1318 (void)strncpy(domain, cp + 1, sizeof(domain) - 1);
1319 } else
1320 domain[0] = '\0';
1321 }
1322 if (!nflag && in.s_addr != INADDR_ANY) {
1323 hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1324 if (hp != NULL) {
1325 if ((cp = strchr(hp->h_name, '.')) != NULL &&
1326 strcmp(cp + 1, domain) == 0)
1327 *cp = '\0';
1328 (void)strncpy(line, hp->h_name, sizeof(line) - 1);
1329 line[sizeof(line) - 1] = '\0';
1330 return (line);
1331 }
1332 }
1333 return (inet_ntoa(in));
1334 }
1335
1336 struct hostinfo *
1337 gethostinfo(register char *hostname)
1338 {
1339 register int n;
1340 register struct hostent *hp;
1341 register struct hostinfo *hi;
1342 register char **p;
1343 register u_int32_t *ap;
1344 struct in_addr addr;
1345
1346 hi = calloc(1, sizeof(*hi));
1347 if (hi == NULL) {
1348 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1349 exit(1);
1350 }
1351 if (inet_aton(hostname, &addr) != 0) {
1352 hi->name = savestr(hostname);
1353 hi->n = 1;
1354 hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1355 if (hi->addrs == NULL) {
1356 Fprintf(stderr, "%s: calloc %s\n",
1357 prog, strerror(errno));
1358 exit(1);
1359 }
1360 hi->addrs[0] = addr.s_addr;
1361 return (hi);
1362 }
1363
1364 hp = gethostbyname(hostname);
1365 if (hp == NULL) {
1366 Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
1367 exit(1);
1368 }
1369 if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
1370 Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
1371 exit(1);
1372 }
1373 hi->name = savestr(hp->h_name);
1374 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1375 continue;
1376 hi->n = n;
1377 hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1378 if (hi->addrs == NULL) {
1379 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1380 exit(1);
1381 }
1382 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1383 memcpy(ap, *p, sizeof(*ap));
1384 return (hi);
1385 }
1386
1387 void
1388 freehostinfo(register struct hostinfo *hi)
1389 {
1390 if (hi->name != NULL) {
1391 free(hi->name);
1392 hi->name = NULL;
1393 }
1394 free((char *)hi->addrs);
1395 free((char *)hi);
1396 }
1397
1398 void
1399 getaddr(register u_int32_t *ap, register char *hostname)
1400 {
1401 register struct hostinfo *hi;
1402
1403 hi = gethostinfo(hostname);
1404 *ap = hi->addrs[0];
1405 freehostinfo(hi);
1406 }
1407
1408 void
1409 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
1410 {
1411
1412 memset(sin, 0, sizeof(*sin));
1413 #ifdef HAVE_SOCKADDR_SA_LEN
1414 sin->sin_len = sizeof(*sin);
1415 #endif
1416 sin->sin_family = AF_INET;
1417 sin->sin_addr.s_addr = addr;
1418 }
1419
1420 /* String to value with optional min and max. Handles decimal and hex. */
1421 int
1422 str2val(register const char *str, register const char *what,
1423 register int mi, register int ma)
1424 {
1425 register const char *cp;
1426 register int val;
1427 char *ep;
1428
1429 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1430 cp = str + 2;
1431 val = (int)strtol(cp, &ep, 16);
1432 } else
1433 val = (int)strtol(str, &ep, 10);
1434 if (*ep != '\0') {
1435 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1436 prog, str, what);
1437 exit(1);
1438 }
1439 if (val < mi && mi >= 0) {
1440 if (mi == 0)
1441 Fprintf(stderr, "%s: %s must be >= %d\n",
1442 prog, what, mi);
1443 else
1444 Fprintf(stderr, "%s: %s must be > %d\n",
1445 prog, what, mi - 1);
1446 exit(1);
1447 }
1448 if (val > ma && ma >= 0) {
1449 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1450 exit(1);
1451 }
1452 return (val);
1453 }
1454
1455 __dead void
1456 usage(void)
1457 {
1458 extern char version[];
1459
1460 Fprintf(stderr, "Version %s\n", version);
1461 Fprintf(stderr, "Usage: %s [-dDFPIlnrvx] [-g gateway] [-i iface] \
1462 [-f first_ttl] [-m max_ttl]\n\t[ -p port] [-q nqueries] [-s src_addr] [-t tos] \
1463 [-w waittime]\n\thost [packetlen]\n",
1464 prog);
1465 exit(1);
1466 }
1467
1468 /*
1469 * Received ICMP unreachable (fragmentation required and DF set).
1470 * If the ICMP error was from a "new" router, it'll contain the next-hop
1471 * MTU that we should use next. Otherwise we'll just keep going in the
1472 * mtus[] table, trying until we hit a valid MTU.
1473 */
1474
1475
1476 void
1477 frag_err()
1478 {
1479 int i;
1480
1481 if (nextmtu > 0 && nextmtu < packlen) {
1482 Printf("\nfragmentation required and DF set, "
1483 "next hop MTU = %d\n",
1484 nextmtu);
1485 packlen = nextmtu;
1486 for (i = 0; mtus[i] > 0; i++) {
1487 if (mtus[i] < nextmtu) {
1488 mtuptr = &mtus[i]; /* next one to try */
1489 break;
1490 }
1491 }
1492 } else {
1493 Printf("\nfragmentation required and DF set. ");
1494 if (nextmtu)
1495 Printf("\nBogus next hop MTU = %d > last MTU = %d. ",
1496 nextmtu, packlen);
1497 packlen = *mtuptr++;
1498 Printf("Trying new MTU = %d\n", packlen);
1499 }
1500 outudp->uh_ulen =
1501 htons((u_short)(packlen - (sizeof(*outip) + optlen)));
1502 }
1503
1504 int
1505 find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
1506 {
1507 int sock;
1508 struct sockaddr_in help;
1509 int help_len;
1510
1511 sock = socket(AF_INET, SOCK_DGRAM, 0);
1512 if (sock < 0) return (0);
1513
1514 help.sin_family = AF_INET;
1515 /*
1516 * At this point the port number doesn't matter
1517 * since it only has to be greater than zero.
1518 */
1519 help.sin_port = 42;
1520 help.sin_addr.s_addr = to->sin_addr.s_addr;
1521 if (connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
1522 (void)close(sock);
1523 return (0);
1524 }
1525
1526 help_len = sizeof(help);
1527 if (getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
1528 help_len != sizeof(help) ||
1529 help.sin_addr.s_addr == INADDR_ANY) {
1530 (void)close(sock);
1531 return (0);
1532 }
1533
1534 (void)close(sock);
1535 setsin(from, help.sin_addr.s_addr);
1536 return (1);
1537 }
1538