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