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