traceroute.c revision 1.28 1 /* $NetBSD: traceroute.c,v 1.28 1999/02/16 23:18:40 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.28 1999/02/16 23:18:40 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, *al2;
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 al2 = al;
704 if (n < 0) {
705 Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
706 exit(1);
707 }
708 if (n == 0) {
709 Fprintf(stderr,
710 "%s: Can't find any network interfaces\n", prog);
711 exit(1);
712 }
713
714 /* Look for a specific device */
715 if (device != NULL) {
716 for (i = n; i > 0; --i, ++al2)
717 if (strcmp(device, al2->device) == 0)
718 break;
719 if (i <= 0) {
720 Fprintf(stderr, "%s: Can't find interface %s\n",
721 prog, device);
722 exit(1);
723 }
724 }
725
726 /* Determine our source address */
727 if (source == NULL) {
728 /*
729 * If a device was specified, use the interface address.
730 * Otherwise, use the first interface found.
731 * Warn if there are more than one.
732 */
733 setsin(from, al2->addr);
734 if (n > 1 && device == NULL && !find_local_ip(from, to)) {
735 Fprintf(stderr,
736 "%s: Warning: Multiple interfaces found; using %s @ %s\n",
737 prog, inet_ntoa(from->sin_addr), al2->device);
738 }
739 } else {
740 hi = gethostinfo(source);
741 source = hi->name;
742 hi->name = NULL;
743 if (device == NULL) {
744 /*
745 * Use the first interface found.
746 * Warn if there are more than one.
747 */
748 setsin(from, hi->addrs[0]);
749 if (hi->n > 1)
750 Fprintf(stderr,
751 "%s: Warning: %s has multiple addresses; using %s\n",
752 prog, source, inet_ntoa(from->sin_addr));
753 } else {
754 /*
755 * Make sure the source specified matches the
756 * interface address.
757 */
758 for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
759 if (*ap == al2->addr)
760 break;
761 if (i <= 0) {
762 Fprintf(stderr,
763 "%s: %s is not on interface %s\n",
764 prog, source, device);
765 exit(1);
766 }
767 setsin(from, *ap);
768 }
769 freehostinfo(hi);
770 }
771
772 /*
773 * If not root, make sure source address matches a local interface.
774 * (The list of addresses produced by ifaddrlist() automatically
775 * excludes interfaces that are marked down and/or loopback.)
776 */
777 if (getuid()) {
778 al2 = al;
779 for (i = n; i > 0; --i, ++al2)
780 if (from->sin_addr.s_addr == al2->addr)
781 break;
782 if (i <= 0) {
783 Fprintf(stderr, "%s: %s is not a valid local address "
784 "and you are not superuser.\n", prog,
785 inet_ntoa(from->sin_addr));
786 exit(1);
787 }
788 }
789
790 outip->ip_src = from->sin_addr;
791 #ifndef IP_HDRINCL
792 if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
793 Fprintf(stderr, "%s: bind: %s\n",
794 prog, strerror(errno));
795 exit (1);
796 }
797 #endif
798
799 setuid(getuid());
800 Fprintf(stderr, "%s to %s (%s)",
801 prog, hostname, inet_ntoa(to->sin_addr));
802 if (source)
803 Fprintf(stderr, " from %s", source);
804 Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
805 (void)fflush(stderr);
806
807 for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
808 u_int32_t lastaddr = 0;
809 int got_there = 0;
810 int unreachable = 0;
811
812 again:
813 Printf("%2d ", ttl);
814 for (probe = 0; probe < nprobes; ++probe) {
815 register int cc;
816 struct timeval t1, t2;
817 struct timezone tz;
818 register struct ip *ip;
819 (void)gettimeofday(&t1, &tz);
820 send_probe(++seq, ttl, &t1);
821 while ((cc = wait_for_reply(s, from, &t1)) != 0) {
822 (void)gettimeofday(&t2, &tz);
823 /*
824 * Since we'll be receiving all ICMP
825 * messages to this host above, we may
826 * never end up with cc=0, so we need
827 * an additional termination check.
828 */
829 if (t2.tv_sec - t1.tv_sec > waittime) {
830 cc = 0;
831 break;
832 }
833 i = packet_ok(packet, cc, from, seq);
834 /* Skip short packet */
835 if (i == 0)
836 continue;
837 if (from->sin_addr.s_addr != lastaddr) {
838 print(packet, cc, from);
839 lastaddr = from->sin_addr.s_addr;
840 }
841 ip = (struct ip *)packet;
842 Printf(" %.3f ms", deltaT(&t1, &t2));
843 if (ttl_flag)
844 Printf(" (ttl = %d)", ip->ip_ttl);
845 if (i == -2) {
846 #ifndef ARCHAIC
847 if (ip->ip_ttl <= 1)
848 Printf(" !");
849 #endif
850 ++got_there;
851 break;
852 }
853
854 /* time exceeded in transit */
855 if (i == -1)
856 break;
857 code = i - 1;
858 switch (code) {
859
860 case ICMP_UNREACH_PORT:
861 #ifndef ARCHAIC
862 if (ip->ip_ttl <= 1)
863 Printf(" !");
864 #endif
865 ++got_there;
866 break;
867
868 case ICMP_UNREACH_NET:
869 ++unreachable;
870 Printf(" !N");
871 break;
872
873 case ICMP_UNREACH_HOST:
874 ++unreachable;
875 Printf(" !H");
876 break;
877
878 case ICMP_UNREACH_PROTOCOL:
879 ++got_there;
880 Printf(" !P");
881 break;
882
883 case ICMP_UNREACH_NEEDFRAG:
884 if (mtudisc) {
885 frag_err();
886 goto again;
887 } else {
888 ++unreachable;
889 Printf(" !F");
890 }
891 break;
892
893 case ICMP_UNREACH_SRCFAIL:
894 ++unreachable;
895 Printf(" !S");
896 break;
897
898 /* rfc1716 */
899 #ifndef ICMP_UNREACH_FILTER_PROHIB
900 #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */
901 #endif
902 case ICMP_UNREACH_FILTER_PROHIB:
903 ++unreachable;
904 Printf(" !X");
905 break;
906
907 default:
908 ++unreachable;
909 Printf(" !<%d>", code);
910 break;
911 }
912 break;
913 }
914 if (cc == 0)
915 Printf(" *");
916 (void)fflush(stdout);
917 }
918 putchar('\n');
919 if (got_there ||
920 (unreachable > 0 && unreachable >= nprobes))
921 break;
922 }
923 exit(0);
924 }
925
926 int
927 wait_for_reply(register int sock, register struct sockaddr_in *fromp,
928 register struct timeval *tp)
929 {
930 fd_set fds;
931 struct timeval now, wait;
932 struct timezone tz;
933 register int cc = 0;
934 int fromlen = sizeof(*fromp);
935 int retval;
936
937 FD_ZERO(&fds);
938 FD_SET(sock, &fds);
939
940 wait.tv_sec = tp->tv_sec + waittime;
941 wait.tv_usec = tp->tv_usec;
942 (void)gettimeofday(&now, &tz);
943 tvsub(&wait, &now);
944
945 retval = select(sock + 1, &fds, NULL, NULL, &wait);
946 if (retval < 0) {
947 /* If we continue, we probably just flood the remote host. */
948 Fprintf(stderr, "%s: select: %s\n", prog, strerror(errno));
949 exit(1);
950 }
951 if (retval > 0) {
952 cc = recvfrom(s, (char *)packet, sizeof(packet), 0,
953 (struct sockaddr *)fromp, &fromlen);
954 }
955
956 return(cc);
957 }
958
959 void
960 dump_packet()
961 {
962 u_char *p;
963 int i;
964
965 Fprintf(stderr, "packet data:");
966
967 #ifdef __hpux
968 for (p = useicmp ? (u_char *)outicmp : (u_char *)outudp, i = 0; i <
969 i < packlen - (sizeof(*outip) + optlen); i++)
970 #else
971 for (p = (u_char *)outip, i = 0; i < packlen; i++)
972 #endif
973 {
974 if ((i % 24) == 0)
975 Fprintf(stderr, "\n ");
976 Fprintf(stderr, " %02x", *p++);
977 }
978 Fprintf(stderr, "\n");
979 }
980
981 void
982 send_probe(register int seq, int ttl, register struct timeval *tp)
983 {
984 register int cc;
985 register struct udpiphdr * ui;
986 struct ip tip;
987
988 again:
989 #ifdef BYTESWAP_IP_LEN
990 outip->ip_len = htons(packlen);
991 #else
992 outip->ip_len = packlen;
993 #endif
994 outip->ip_ttl = ttl;
995 #ifndef __hpux
996 outip->ip_id = htons(ident + seq);
997 #endif
998
999 /*
1000 * In most cases, the kernel will recalculate the ip checksum.
1001 * But we must do it anyway so that the udp checksum comes out
1002 * right.
1003 */
1004 if (docksum) {
1005 outip->ip_sum =
1006 in_cksum((u_short *)outip, sizeof(*outip) + optlen);
1007 if (outip->ip_sum == 0)
1008 outip->ip_sum = 0xffff;
1009 }
1010
1011 /* Payload */
1012 outsetup.seq = seq;
1013 outsetup.ttl = ttl;
1014 outsetup.tv = *tp;
1015 memcpy(outmark,&outsetup,sizeof(outsetup));
1016
1017 if (useicmp)
1018 outicmp->icmp_seq = htons(seq);
1019 else
1020 outudp->uh_dport = htons(port + seq);
1021
1022 /* (We can only do the checksum if we know our ip address) */
1023 if (docksum) {
1024 if (useicmp) {
1025 outicmp->icmp_cksum = 0;
1026 outicmp->icmp_cksum = in_cksum((u_short *)outicmp,
1027 packlen - (sizeof(*outip) + optlen));
1028 if (outicmp->icmp_cksum == 0)
1029 outicmp->icmp_cksum = 0xffff;
1030 } else {
1031 /* Checksum (must save and restore ip header) */
1032 tip = *outip;
1033 ui = (struct udpiphdr *)outip;
1034 #ifndef __NetBSD__
1035 ui->ui_next = 0;
1036 ui->ui_prev = 0;
1037 ui->ui_x1 = 0;
1038 #else
1039 memset(ui->ui_x1, 0, sizeof(ui->ui_x1));
1040 #endif
1041 ui->ui_len = outudp->uh_ulen;
1042 outudp->uh_sum = 0;
1043 outudp->uh_sum = in_cksum((u_short *)ui, packlen);
1044 if (outudp->uh_sum == 0)
1045 outudp->uh_sum = 0xffff;
1046 *outip = tip;
1047 }
1048 }
1049
1050 /* XXX undocumented debugging hack */
1051 if (verbose > 1) {
1052 register const u_short *sp;
1053 register int nshorts, i;
1054
1055 sp = (u_short *)outip;
1056 nshorts = (u_int)packlen / sizeof(u_short);
1057 i = 0;
1058 Printf("[ %d bytes", packlen);
1059 while (--nshorts >= 0) {
1060 if ((i++ % 8) == 0)
1061 Printf("\n\t");
1062 Printf(" %04x", ntohs(*sp++));
1063 }
1064 if (packlen & 1) {
1065 if ((i % 8) == 0)
1066 Printf("\n\t");
1067 Printf(" %02x", *(u_char *)sp);
1068 }
1069 Printf("]\n");
1070 }
1071
1072 #if !defined(IP_HDRINCL) && defined(IP_TTL)
1073 if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
1074 (char *)&ttl, sizeof(ttl)) < 0) {
1075 Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
1076 prog, ttl, strerror(errno));
1077 exit(1);
1078 }
1079 #endif
1080 if (dump)
1081 dump_packet();
1082
1083 #ifdef __hpux
1084 cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp,
1085 packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto));
1086 if (cc > 0)
1087 cc += sizeof(*outip) + optlen;
1088 #else
1089 cc = sendto(sndsock, (char *)outip,
1090 packlen, 0, &whereto, sizeof(whereto));
1091 #endif
1092 if (cc < 0 || cc != packlen) {
1093 if (cc < 0) {
1094 /*
1095 * An errno of EMSGSIZE means we're writing too big a
1096 * datagram for the interface. We have to just decrease
1097 * the packet size until we find one that works.
1098 *
1099 * XXX maybe we should try to read the outgoing if's
1100 * mtu?
1101 */
1102
1103 if (errno == EMSGSIZE) {
1104 packlen = *mtuptr++;
1105 #ifdef _NoLongerLooksUgly_
1106 Printf("\nmessage too big, "
1107 "trying new MTU = %d ", packlen);
1108 #endif
1109 goto again;
1110 } else
1111 Fprintf(stderr, "%s: sendto: %s\n",
1112 prog, strerror(errno));
1113 }
1114
1115 Printf("%s: wrote %s %d chars, ret=%d\n",
1116 prog, hostname, packlen, cc);
1117 (void)fflush(stdout);
1118 }
1119 }
1120
1121 double
1122 deltaT(struct timeval *t1p, struct timeval *t2p)
1123 {
1124 register double dt;
1125
1126 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
1127 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
1128 return (dt);
1129 }
1130
1131 /*
1132 * Convert an ICMP "type" field to a printable string.
1133 */
1134 char *
1135 pr_type(register u_char t)
1136 {
1137 static char *ttab[] = {
1138 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
1139 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
1140 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
1141 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
1142 "Info Reply"
1143 };
1144
1145 if (t > 16)
1146 return("OUT-OF-RANGE");
1147
1148 return(ttab[t]);
1149 }
1150
1151 int
1152 packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
1153 register int seq)
1154 {
1155 register struct icmp *icp;
1156 register u_char type, code;
1157 register int hlen;
1158 #ifndef ARCHAIC
1159 register struct ip *ip;
1160
1161 ip = (struct ip *) buf;
1162 hlen = ip->ip_hl << 2;
1163 if (cc < hlen + ICMP_MINLEN) {
1164 if (verbose)
1165 Printf("packet too short (%d bytes) from %s\n", cc,
1166 inet_ntoa(from->sin_addr));
1167 return (0);
1168 }
1169 cc -= hlen;
1170 icp = (struct icmp *)(buf + hlen);
1171 #else
1172 icp = (struct icmp *)buf;
1173 #endif
1174 type = icp->icmp_type;
1175 code = icp->icmp_code;
1176 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
1177 type == ICMP_UNREACH || type == ICMP_ECHOREPLY) {
1178 register struct ip *hip;
1179 register struct udphdr *up;
1180 register struct icmp *hicmp;
1181
1182 hip = &icp->icmp_ip;
1183 hlen = hip->ip_hl << 2;
1184
1185 nextmtu = icp->icmp_nextmtu; /* for frag_err() */
1186
1187 if (useicmp) {
1188 /* XXX */
1189 if (type == ICMP_ECHOREPLY &&
1190 icp->icmp_id == htons(ident) &&
1191 icp->icmp_seq == htons(seq))
1192 return (-2);
1193
1194 hicmp = (struct icmp *)((u_char *)hip + hlen);
1195 /* XXX 8 is a magic number */
1196 if (hlen + 8 <= cc &&
1197 hip->ip_p == IPPROTO_ICMP &&
1198 hicmp->icmp_id == htons(ident) &&
1199 hicmp->icmp_seq == htons(seq))
1200 return (type == ICMP_TIMXCEED ? -1 : code + 1);
1201 } else {
1202 up = (struct udphdr *)((u_char *)hip + hlen);
1203 /* XXX 8 is a magic number */
1204 if (hlen + 12 <= cc &&
1205 hip->ip_p == IPPROTO_UDP &&
1206 up->uh_sport == htons(ident) &&
1207 up->uh_dport == htons(port + seq))
1208 return (type == ICMP_TIMXCEED ? -1 : code + 1);
1209 }
1210 }
1211 #ifndef ARCHAIC
1212 if (verbose) {
1213 register int i;
1214 u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
1215
1216 Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
1217 Printf("%s: icmp type %d (%s) code %d\n",
1218 inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
1219 for (i = 4; i < cc ; i += sizeof(*lp))
1220 Printf("%2d: x%8.8x\n", i, *lp++);
1221 }
1222 #endif
1223 return(0);
1224 }
1225
1226
1227 void
1228 print(register u_char *buf, register int cc, register struct sockaddr_in *from)
1229 {
1230 register struct ip *ip;
1231 register int hlen;
1232
1233 ip = (struct ip *) buf;
1234 hlen = ip->ip_hl << 2;
1235 cc -= hlen;
1236
1237 if (nflag)
1238 Printf(" %s", inet_ntoa(from->sin_addr));
1239 else
1240 Printf(" %s (%s)", inetname(from->sin_addr),
1241 inet_ntoa(from->sin_addr));
1242
1243 if (verbose)
1244 Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
1245 }
1246
1247 /*
1248 * Checksum routine for Internet Protocol family headers (C Version)
1249 */
1250 u_short
1251 in_cksum(register u_short *addr, register int len)
1252 {
1253 register int nleft = len;
1254 register u_short *w = addr;
1255 register u_short answer;
1256 register int sum = 0;
1257
1258 /*
1259 * Our algorithm is simple, using a 32 bit accumulator (sum),
1260 * we add sequential 16 bit words to it, and at the end, fold
1261 * back all the carry bits from the top 16 bits into the lower
1262 * 16 bits.
1263 */
1264 while (nleft > 1) {
1265 sum += *w++;
1266 nleft -= 2;
1267 }
1268
1269 /* mop up an odd byte, if necessary */
1270 if (nleft == 1)
1271 sum += *(u_char *)w;
1272
1273 /*
1274 * add back carry outs from top 16 bits to low 16 bits
1275 */
1276 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
1277 sum += (sum >> 16); /* add carry */
1278 answer = ~sum; /* truncate to 16 bits */
1279 return (answer);
1280 }
1281
1282 /*
1283 * Subtract 2 timeval structs: out = out - in.
1284 * Out is assumed to be >= in.
1285 */
1286 void
1287 tvsub(register struct timeval *out, register struct timeval *in)
1288 {
1289
1290 if ((out->tv_usec -= in->tv_usec) < 0) {
1291 --out->tv_sec;
1292 out->tv_usec += 1000000;
1293 }
1294 out->tv_sec -= in->tv_sec;
1295 }
1296
1297 /*
1298 * Construct an Internet address representation.
1299 * If the nflag has been supplied, give
1300 * numeric value, otherwise try for symbolic name.
1301 */
1302 char *
1303 inetname(struct in_addr in)
1304 {
1305 register char *cp;
1306 register struct hostent *hp;
1307 static int first = 1;
1308 static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
1309
1310 if (first && !nflag) {
1311 int rv;
1312
1313 first = 0;
1314 rv = gethostname(domain, sizeof domain);
1315 domain[sizeof(domain) - 1] = '\0';
1316 if (rv == 0 && (cp = strchr(domain, '.')) != NULL) {
1317 (void)strncpy(domain, cp + 1, sizeof(domain) - 1);
1318 } else
1319 domain[0] = '\0';
1320 }
1321 if (!nflag && in.s_addr != INADDR_ANY) {
1322 hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
1323 if (hp != NULL) {
1324 if ((cp = strchr(hp->h_name, '.')) != NULL &&
1325 strcmp(cp + 1, domain) == 0)
1326 *cp = '\0';
1327 (void)strncpy(line, hp->h_name, sizeof(line) - 1);
1328 line[sizeof(line) - 1] = '\0';
1329 return (line);
1330 }
1331 }
1332 return (inet_ntoa(in));
1333 }
1334
1335 struct hostinfo *
1336 gethostinfo(register char *hostname)
1337 {
1338 register int n;
1339 register struct hostent *hp;
1340 register struct hostinfo *hi;
1341 register char **p;
1342 register u_int32_t *ap;
1343 struct in_addr addr;
1344
1345 hi = calloc(1, sizeof(*hi));
1346 if (hi == NULL) {
1347 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1348 exit(1);
1349 }
1350 if (inet_aton(hostname, &addr) != 0) {
1351 hi->name = savestr(hostname);
1352 hi->n = 1;
1353 hi->addrs = calloc(1, sizeof(hi->addrs[0]));
1354 if (hi->addrs == NULL) {
1355 Fprintf(stderr, "%s: calloc %s\n",
1356 prog, strerror(errno));
1357 exit(1);
1358 }
1359 hi->addrs[0] = addr.s_addr;
1360 return (hi);
1361 }
1362
1363 hp = gethostbyname(hostname);
1364 if (hp == NULL) {
1365 Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
1366 exit(1);
1367 }
1368 if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
1369 Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
1370 exit(1);
1371 }
1372 hi->name = savestr(hp->h_name);
1373 for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
1374 continue;
1375 hi->n = n;
1376 hi->addrs = calloc(n, sizeof(hi->addrs[0]));
1377 if (hi->addrs == NULL) {
1378 Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
1379 exit(1);
1380 }
1381 for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
1382 memcpy(ap, *p, sizeof(*ap));
1383 return (hi);
1384 }
1385
1386 void
1387 freehostinfo(register struct hostinfo *hi)
1388 {
1389 if (hi->name != NULL) {
1390 free(hi->name);
1391 hi->name = NULL;
1392 }
1393 free((char *)hi->addrs);
1394 free((char *)hi);
1395 }
1396
1397 void
1398 getaddr(register u_int32_t *ap, register char *hostname)
1399 {
1400 register struct hostinfo *hi;
1401
1402 hi = gethostinfo(hostname);
1403 *ap = hi->addrs[0];
1404 freehostinfo(hi);
1405 }
1406
1407 void
1408 setsin(register struct sockaddr_in *sin, register u_int32_t addr)
1409 {
1410
1411 memset(sin, 0, sizeof(*sin));
1412 #ifdef HAVE_SOCKADDR_SA_LEN
1413 sin->sin_len = sizeof(*sin);
1414 #endif
1415 sin->sin_family = AF_INET;
1416 sin->sin_addr.s_addr = addr;
1417 }
1418
1419 /* String to value with optional min and max. Handles decimal and hex. */
1420 int
1421 str2val(register const char *str, register const char *what,
1422 register int mi, register int ma)
1423 {
1424 register const char *cp;
1425 register int val;
1426 char *ep;
1427
1428 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
1429 cp = str + 2;
1430 val = (int)strtol(cp, &ep, 16);
1431 } else
1432 val = (int)strtol(str, &ep, 10);
1433 if (*ep != '\0') {
1434 Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
1435 prog, str, what);
1436 exit(1);
1437 }
1438 if (val < mi && mi >= 0) {
1439 if (mi == 0)
1440 Fprintf(stderr, "%s: %s must be >= %d\n",
1441 prog, what, mi);
1442 else
1443 Fprintf(stderr, "%s: %s must be > %d\n",
1444 prog, what, mi - 1);
1445 exit(1);
1446 }
1447 if (val > ma && ma >= 0) {
1448 Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
1449 exit(1);
1450 }
1451 return (val);
1452 }
1453
1454 __dead void
1455 usage(void)
1456 {
1457 extern char version[];
1458
1459 Fprintf(stderr, "Version %s\n", version);
1460 Fprintf(stderr, "Usage: %s [-dDFPIlnrvx] [-g gateway] [-i iface] \
1461 [-f first_ttl] [-m max_ttl]\n\t[ -p port] [-q nqueries] [-s src_addr] [-t tos] \
1462 [-w waittime]\n\thost [packetlen]\n",
1463 prog);
1464 exit(1);
1465 }
1466
1467 /*
1468 * Received ICMP unreachable (fragmentation required and DF set).
1469 * If the ICMP error was from a "new" router, it'll contain the next-hop
1470 * MTU that we should use next. Otherwise we'll just keep going in the
1471 * mtus[] table, trying until we hit a valid MTU.
1472 */
1473
1474
1475 void
1476 frag_err()
1477 {
1478 int i;
1479
1480 if (nextmtu > 0) {
1481 Printf("\nfragmentation required and DF set, next hop MTU = %d\n
1482 ",
1483 nextmtu);
1484 packlen = nextmtu;
1485 for (i = 0; mtus[i] > 0; i++) {
1486 if (mtus[i] < nextmtu) {
1487 mtuptr = &mtus[i]; /* next one to try */
1488 return;
1489 }
1490 }
1491 } else {
1492 packlen = *mtuptr++;
1493 Printf("fragmentation required and DF set, "
1494 "trying new MTU = %d ", packlen);
1495 }
1496 }
1497
1498 int
1499 find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
1500 {
1501 int sock;
1502 struct sockaddr_in help;
1503 int help_len;
1504
1505 sock = socket(AF_INET, SOCK_DGRAM, 0);
1506 if (sock < 0) return (0);
1507
1508 help.sin_family = AF_INET;
1509 /*
1510 * At this point the port number doesn't matter
1511 * since it only has to be greater than zero.
1512 */
1513 help.sin_port = 42;
1514 help.sin_addr.s_addr = to->sin_addr.s_addr;
1515 if (connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
1516 (void)close(sock);
1517 return (0);
1518 }
1519
1520 help_len = sizeof(help);
1521 if (getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
1522 help_len != sizeof(help) ||
1523 help.sin_addr.s_addr == INADDR_ANY) {
1524 (void)close(sock);
1525 return (0);
1526 }
1527
1528 (void)close(sock);
1529 setsin(from, help.sin_addr.s_addr);
1530 return (1);
1531 }
1532