blob: a3abd0a00761bc2ec6885bf9cd421a072345c478 [file] [log] [blame]
Eric Andersen5c58d282001-07-10 16:29:00 +00001/*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Van Jacobson.
7 *
Eric Andersen7467c8d2001-07-12 20:26:32 +00008 * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
Eric Andersen5c58d282001-07-10 16:29:00 +00009 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38/*
39 * traceroute host - trace the route ip packets follow going to "host".
40 * Notes
41 * -----
42 * This program must be run by root or be setuid. (I suggest that
43 * you *don't* make it setuid -- casual use could result in a lot
44 * of unnecessary traffic on our poor, congested nets.)
45 *
46 * I stole the idea for this program from Steve Deering. Since
47 * the first release, I've learned that had I attended the right
48 * IETF working group meetings, I also could have stolen it from Guy
49 * Almes or Matt Mathis. I don't know (or care) who came up with
50 * the idea first. I envy the originators' perspicacity and I'm
51 * glad they didn't keep the idea a secret.
52 *
53 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
54 * enhancements to the original distribution.
55 *
56 * I've hacked up a round-trip-route version of this that works by
57 * sending a loose-source-routed udp datagram through the destination
58 * back to yourself. Unfortunately, SO many gateways botch source
59 * routing, the thing is almost worthless. Maybe one day...
60 *
61 * -- Van Jacobson (van@helios.ee.lbl.gov)
62 * Tue Dec 20 03:50:13 PST 1988
63 */
64
Eric Andersen7467c8d2001-07-12 20:26:32 +000065#undef BB_FEATURE_TRACEROUTE_VERBOSE
66//#define BB_FEATURE_TRACEROUTE_VERBOSE
67#undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
68
Eric Andersen5c58d282001-07-10 16:29:00 +000069#include <stdio.h>
70#include <errno.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74#include <sys/time.h>
Eric Andersenaf6b40a2001-07-31 22:53:36 +000075#include <sys/types.h>
76#include <sys/socket.h>
Eric Andersen5c58d282001-07-10 16:29:00 +000077#include <netdb.h>
78#include <endian.h>
79#include <arpa/inet.h>
80#include <netinet/udp.h>
81#include <netinet/ip.h>
82#include <netinet/ip_icmp.h>
83
Eric Andersenbe0c3602001-08-02 10:55:32 +000084
85 /* It turns out that libc5 doesn't have proper icmp support
86 * built into it header files, so we have to supplement it */
87#if __GNU_LIBRARY__ < 5
88static const int ICMP_MINLEN = 8; /* abs minimum */
89
90struct icmp_ra_addr
91{
92 u_int32_t ira_addr;
93 u_int32_t ira_preference;
94};
95
96
97struct icmp
98{
99 u_int8_t icmp_type; /* type of message, see below */
100 u_int8_t icmp_code; /* type sub code */
101 u_int16_t icmp_cksum; /* ones complement checksum of struct */
102 union
103 {
104 u_char ih_pptr; /* ICMP_PARAMPROB */
105 struct in_addr ih_gwaddr; /* gateway address */
106 struct ih_idseq /* echo datagram */
107 {
108 u_int16_t icd_id;
109 u_int16_t icd_seq;
110 } ih_idseq;
111 u_int32_t ih_void;
112
113 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
114 struct ih_pmtu
115 {
116 u_int16_t ipm_void;
117 u_int16_t ipm_nextmtu;
118 } ih_pmtu;
119
120 struct ih_rtradv
121 {
122 u_int8_t irt_num_addrs;
123 u_int8_t irt_wpa;
124 u_int16_t irt_lifetime;
125 } ih_rtradv;
126 } icmp_hun;
127#define icmp_pptr icmp_hun.ih_pptr
128#define icmp_gwaddr icmp_hun.ih_gwaddr
129#define icmp_id icmp_hun.ih_idseq.icd_id
130#define icmp_seq icmp_hun.ih_idseq.icd_seq
131#define icmp_void icmp_hun.ih_void
132#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
133#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
134#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
135#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
136#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
137 union
138 {
139 struct
140 {
141 u_int32_t its_otime;
142 u_int32_t its_rtime;
143 u_int32_t its_ttime;
144 } id_ts;
145 struct
146 {
147 struct ip idi_ip;
148 /* options and then 64 bits of data */
149 } id_ip;
150 struct icmp_ra_addr id_radv;
151 u_int32_t id_mask;
152 u_int8_t id_data[1];
153 } icmp_dun;
154#define icmp_otime icmp_dun.id_ts.its_otime
155#define icmp_rtime icmp_dun.id_ts.its_rtime
156#define icmp_ttime icmp_dun.id_ts.its_ttime
157#define icmp_ip icmp_dun.id_ip.idi_ip
158#define icmp_radv icmp_dun.id_radv
159#define icmp_mask icmp_dun.id_mask
160#define icmp_data icmp_dun.id_data
161};
162
163#define ICMP_MINLEN 8 /* abs minimum */
164#define ICMP_UNREACH 3 /* dest unreachable, codes: */
165#define ICMP_TIMXCEED 11 /* time exceeded, code: */
166#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
167#define ICMP_UNREACH_NET 0 /* bad net */
168#define ICMP_UNREACH_HOST 1 /* bad host */
169#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
170#define ICMP_UNREACH_PORT 3 /* bad port */
171#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
172#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
173#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000174
Eric Andersenaf6b40a2001-07-31 22:53:36 +0000175
Eric Andersen5c58d282001-07-10 16:29:00 +0000176#define MAXPACKET 65535 /* max ip packet size */
177#ifndef MAXHOSTNAMELEN
178#define MAXHOSTNAMELEN 64
179#endif
180
181/*
182 * format of a (udp) probe packet.
183 */
184struct opacket {
185 struct ip ip;
186 struct udphdr udp;
187 u_char seq; /* sequence number of this packet */
188 u_char ttl; /* ttl packet left with */
189 struct timeval tv; /* time packet left */
190};
191
192/*
193 * Definitions for internet protocol version 4.
194 * Per RFC 791, September 1981.
195 */
196#define IPVERSION 4
197
198
199#include "busybox.h"
200
Eric Andersen5c58d282001-07-10 16:29:00 +0000201static u_char packet[512]; /* last inbound (icmp) packet */
202static struct opacket *outpacket; /* last output (udp) packet */
203
204static int s; /* receive (icmp) socket file descriptor */
205static int sndsock; /* send (udp) socket file descriptor */
206
207static struct sockaddr whereto; /* Who to try to reach */
208static int datalen; /* How much data */
209
210static char *hostname;
211
212static int max_ttl = 30;
213static u_short ident;
214static u_short port = 32768+666; /* start udp dest port # for probe packets */
215
Eric Andersen7467c8d2001-07-12 20:26:32 +0000216#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000217static int verbose;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000218#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000219static int waittime = 5; /* time to wait for response (in seconds) */
220static int nflag; /* print addresses numerically */
221
Eric Andersen7467c8d2001-07-12 20:26:32 +0000222/*
223 * Construct an Internet address representation.
224 * If the nflag has been supplied, give
225 * numeric value, otherwise try for symbolic name.
226 */
Eric Andersen044228d2001-07-17 01:12:36 +0000227static inline void
228inetname(struct sockaddr_in *from)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000229{
230 char *cp;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000231 struct hostent *hp;
232 static char domain[MAXHOSTNAMELEN + 1];
233 static int first = 1;
Eric Andersen044228d2001-07-17 01:12:36 +0000234 const char *ina;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000235
236 if (first && !nflag) {
237 first = 0;
238 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
Eric Andersen044228d2001-07-17 01:12:36 +0000239 (cp = strchr(domain, '.')))
Eric Andersen7467c8d2001-07-12 20:26:32 +0000240 (void) strcpy(domain, cp + 1);
241 else
242 domain[0] = 0;
243 }
244 cp = 0;
Eric Andersen044228d2001-07-17 01:12:36 +0000245 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
246 hp = gethostbyaddr((char *)&(from->sin_addr), sizeof (from->sin_addr), AF_INET);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000247 if (hp) {
Eric Andersen044228d2001-07-17 01:12:36 +0000248 if ((cp = strchr(hp->h_name, '.')) &&
Eric Andersen7467c8d2001-07-12 20:26:32 +0000249 !strcmp(cp + 1, domain))
250 *cp = 0;
251 cp = (char *)hp->h_name;
252 }
253 }
Eric Andersen044228d2001-07-17 01:12:36 +0000254 ina = inet_ntoa(from->sin_addr);
255 if (nflag)
256 printf(" %s", ina);
257 else
258 printf(" %s (%s)", (cp ? cp : ina), ina);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000259}
260
261static inline void
262print(u_char *buf, int cc, struct sockaddr_in *from)
263{
264 struct ip *ip;
265 int hlen;
266
267 ip = (struct ip *) buf;
268 hlen = ip->ip_hl << 2;
269 cc -= hlen;
270
Eric Andersen044228d2001-07-17 01:12:36 +0000271 inetname(from);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000272#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
273 if (verbose)
274 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
275#endif
276}
277
278static inline double
279deltaT(struct timeval *t1p, struct timeval *t2p)
280{
281 double dt;
282
283 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
284 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
285 return (dt);
286}
287
288static inline int
289wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
290{
291 fd_set fds;
292 static struct timeval wait;
293 int cc = 0;
294 int fromlen = sizeof (*from);
295
296 FD_ZERO(&fds);
297 FD_SET(sock, &fds);
298 if (reset_timer) {
299 /*
300 * traceroute could hang if someone else has a ping
301 * running and our ICMP reply gets dropped but we don't
302 * realize it because we keep waking up to handle those
303 * other ICMP packets that keep coming in. To fix this,
304 * "reset_timer" will only be true if the last packet that
305 * came in was for us or if this is the first time we're
306 * waiting for a reply since sending out a probe. Note
307 * that this takes advantage of the select() feature on
308 * Linux where the remaining timeout is written to the
309 * struct timeval area.
310 */
311 wait.tv_sec = waittime;
312 wait.tv_usec = 0;
313 }
314
315 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
316 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
317 (struct sockaddr *)from, &fromlen);
318
319 return(cc);
320}
321
322#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
323/*
324 * Convert an ICMP "type" field to a printable string.
325 */
326static inline const char *
327pr_type(t)
328 u_char t;
329{
330 static const char * const ttab[] = {
331 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
332 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
333 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
334 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
335 "Info Reply"
336 };
337
338 if(t > 16)
339 return("OUT-OF-RANGE");
340
341 return(ttab[t]);
342}
343#endif
344
345static inline int
346packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
347{
348 struct icmp *icp;
349 u_char type, code;
350 int hlen;
351 struct ip *ip;
352
353 ip = (struct ip *) buf;
354 hlen = ip->ip_hl << 2;
355 if (cc < hlen + ICMP_MINLEN) {
356#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
357 if (verbose)
358 printf("packet too short (%d bytes) from %s\n", cc,
359 inet_ntoa(from->sin_addr));
360#endif
361 return (0);
362 }
363 cc -= hlen;
364 icp = (struct icmp *)(buf + hlen);
365 type = icp->icmp_type; code = icp->icmp_code;
366 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
367 type == ICMP_UNREACH) {
368 struct ip *hip;
369 struct udphdr *up;
370
371 hip = &icp->icmp_ip;
372 hlen = hip->ip_hl << 2;
373 up = (struct udphdr *)((u_char *)hip + hlen);
374 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
375 up->source == htons(ident) &&
376 up->dest == htons(port+seq))
377 return (type == ICMP_TIMXCEED? -1 : code+1);
378 }
379#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
380 if (verbose) {
381 int i;
382 u_long *lp = (u_long *)&icp->icmp_ip;
383
384 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
385 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
386 type, pr_type(type), icp->icmp_code);
387 for (i = 4; i < cc ; i += sizeof(long))
388 printf("%2d: x%8.8lx\n", i, *lp++);
389 }
390#endif
391 return(0);
392}
393
394static void /* not inline */
395send_probe(int seq, int ttl)
396{
397 struct opacket *op = outpacket;
398 struct ip *ip = &op->ip;
399 struct udphdr *up = &op->udp;
400 int i;
401 struct timezone tz;
402
403 ip->ip_off = 0;
404 ip->ip_hl = sizeof(*ip) >> 2;
405 ip->ip_p = IPPROTO_UDP;
406 ip->ip_len = datalen;
407 ip->ip_ttl = ttl;
408 ip->ip_v = IPVERSION;
409 ip->ip_id = htons(ident+seq);
410
411 up->source = htons(ident);
412 up->dest = htons(port+seq);
413 up->len = htons((u_short)(datalen - sizeof(struct ip)));
414 up->check = 0;
415
416 op->seq = seq;
417 op->ttl = ttl;
418 (void) gettimeofday(&op->tv, &tz);
419
420 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
421 sizeof(struct sockaddr));
422 if (i < 0 || i != datalen) {
423 if (i<0)
424 perror("sendto");
425 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
426 datalen, i);
427 (void) fflush(stdout);
428 }
429}
430
431
Eric Andersen5c58d282001-07-10 16:29:00 +0000432int
433#ifndef BB_TRACEROUTE
434main(argc, argv)
435#else
436traceroute_main(argc, argv)
437#endif
438 int argc;
439 char *argv[];
440{
441 extern char *optarg;
442 extern int optind;
443 struct hostent *hp;
Eric Andersen5c58d282001-07-10 16:29:00 +0000444 struct sockaddr_in from, *to;
445 int ch, i, on, probe, seq, tos, ttl;
446
447 int options = 0; /* socket options */
448 char *source = 0;
449 int nprobes = 3;
450
451 on = 1;
452 seq = tos = 0;
453 to = (struct sockaddr_in *)&whereto;
454 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
455 switch(ch) {
456 case 'd':
Eric Andersen7467c8d2001-07-12 20:26:32 +0000457#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000458 options |= SO_DEBUG;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000459#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000460 break;
461 case 'm':
462 max_ttl = atoi(optarg);
463 if (max_ttl <= 1)
464 error_msg_and_die("max ttl must be >1.");
465 break;
466 case 'n':
467 nflag++;
468 break;
469 case 'p':
470 port = atoi(optarg);
471 if (port < 1)
472 error_msg_and_die("port must be >0.");
473 break;
474 case 'q':
475 nprobes = atoi(optarg);
476 if (nprobes < 1)
477 error_msg_and_die("nprobes must be >0.");
478 break;
479 case 'r':
480 options |= SO_DONTROUTE;
481 break;
482 case 's':
483 /*
484 * set the ip source address of the outbound
485 * probe (e.g., on a multi-homed host).
486 */
487 source = optarg;
488 break;
489 case 't':
490 tos = atoi(optarg);
491 if (tos < 0 || tos > 255)
492 error_msg_and_die("tos must be 0 to 255.");
493 break;
494 case 'v':
Eric Andersen7467c8d2001-07-12 20:26:32 +0000495#ifdef BB_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000496 verbose++;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000497#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000498 break;
499 case 'w':
500 waittime = atoi(optarg);
501 if (waittime <= 1)
502 error_msg_and_die("wait must be >1 sec.");
503 break;
504 default:
505 show_usage();
506 }
507 argc -= optind;
508 argv += optind;
509
510 if (argc < 1)
511 show_usage();
512
513 setlinebuf (stdout);
514
Eric Andersen7467c8d2001-07-12 20:26:32 +0000515 memset(&whereto, 0, sizeof(struct sockaddr));
516 hp = xgethostbyname(*argv);
Eric Andersen5c58d282001-07-10 16:29:00 +0000517 to->sin_family = hp->h_addrtype;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000518 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
Eric Andersen5c58d282001-07-10 16:29:00 +0000519 hostname = (char *)hp->h_name;
Eric Andersen5c58d282001-07-10 16:29:00 +0000520 if (*++argv)
521 datalen = atoi(*argv);
522 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
523 error_msg_and_die("packet size must be 0 <= s < %d.",
524 MAXPACKET - sizeof(struct opacket));
525 datalen += sizeof(struct opacket);
526 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000527 memset(outpacket, 0, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000528 outpacket->ip.ip_dst = to->sin_addr;
529 outpacket->ip.ip_tos = tos;
530 outpacket->ip.ip_v = IPVERSION;
531 outpacket->ip.ip_id = 0;
532
533 ident = (getpid() & 0xffff) | 0x8000;
534
Eric Andersen7467c8d2001-07-12 20:26:32 +0000535 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
536 perror_msg_and_die(can_not_create_raw_socket);
537
538 s = create_icmp_socket();
539
540#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000541 if (options & SO_DEBUG)
542 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
543 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000544#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000545 if (options & SO_DONTROUTE)
546 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
547 (char *)&on, sizeof(on));
Eric Andersen5c58d282001-07-10 16:29:00 +0000548#ifdef SO_SNDBUF
549 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
550 sizeof(datalen)) < 0)
551 perror_msg_and_die("SO_SNDBUF");
552#endif SO_SNDBUF
553#ifdef IP_HDRINCL
554 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
555 sizeof(on)) < 0)
556 perror_msg_and_die("IP_HDRINCL");
557#endif IP_HDRINCL
Eric Andersen7467c8d2001-07-12 20:26:32 +0000558#ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000559 if (options & SO_DEBUG)
560 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
561 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000562#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000563 if (options & SO_DONTROUTE)
564 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
565 (char *)&on, sizeof(on));
566
567 if (source) {
Eric Andersen7467c8d2001-07-12 20:26:32 +0000568 memset(&from, 0, sizeof(struct sockaddr));
Eric Andersen5c58d282001-07-10 16:29:00 +0000569 from.sin_family = AF_INET;
570 from.sin_addr.s_addr = inet_addr(source);
571 if (from.sin_addr.s_addr == -1)
572 error_msg_and_die("unknown host %s", source);
573 outpacket->ip.ip_src = from.sin_addr;
574#ifndef IP_HDRINCL
575 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
576 perror_msg_and_die("bind");
577#endif IP_HDRINCL
578 }
579
580 fprintf(stderr, "traceroute to %s (%s)", hostname,
581 inet_ntoa(to->sin_addr));
582 if (source)
583 fprintf(stderr, " from %s", source);
584 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000585
586 for (ttl = 1; ttl <= max_ttl; ++ttl) {
587 u_long lastaddr = 0;
588 int got_there = 0;
589 int unreachable = 0;
590
591 printf("%2d ", ttl);
592 for (probe = 0; probe < nprobes; ++probe) {
593 int cc, reset_timer;
594 struct timeval t1, t2;
595 struct timezone tz;
596 struct ip *ip;
597
598 (void) gettimeofday(&t1, &tz);
599 send_probe(++seq, ttl);
600 reset_timer = 1;
601 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
602 (void) gettimeofday(&t2, &tz);
603 if ((i = packet_ok(packet, cc, &from, seq))) {
604 reset_timer = 1;
605 if (from.sin_addr.s_addr != lastaddr) {
606 print(packet, cc, &from);
607 lastaddr = from.sin_addr.s_addr;
608 }
609 printf(" %g ms", deltaT(&t1, &t2));
610 switch(i - 1) {
611 case ICMP_UNREACH_PORT:
Eric Andersen5c58d282001-07-10 16:29:00 +0000612 ip = (struct ip *)packet;
613 if (ip->ip_ttl <= 1)
614 printf(" !");
Eric Andersen5c58d282001-07-10 16:29:00 +0000615 ++got_there;
616 break;
617 case ICMP_UNREACH_NET:
618 ++unreachable;
619 printf(" !N");
620 break;
621 case ICMP_UNREACH_HOST:
622 ++unreachable;
623 printf(" !H");
624 break;
625 case ICMP_UNREACH_PROTOCOL:
626 ++got_there;
627 printf(" !P");
628 break;
629 case ICMP_UNREACH_NEEDFRAG:
630 ++unreachable;
631 printf(" !F");
632 break;
633 case ICMP_UNREACH_SRCFAIL:
634 ++unreachable;
635 printf(" !S");
636 break;
637 }
638 break;
639 } else
640 reset_timer = 0;
641 }
642 if (cc == 0)
643 printf(" *");
644 (void) fflush(stdout);
645 }
646 putchar('\n');
647 if (got_there || unreachable >= nprobes-1)
648 exit(0);
649 }
650
651 return 0;
652}