blob: 44ffdf07e34704ad3ee50abc69f29baa5f6b52fb [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.
Aaron Lehmann69d41782002-06-23 22:25:24 +000017 * 3. Neither the name of the University nor the names of its contributors
Eric Andersen5c58d282001-07-10 16:29:00 +000018 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * traceroute host - trace the route ip packets follow going to "host".
36 * Notes
37 * -----
38 * This program must be run by root or be setuid. (I suggest that
39 * you *don't* make it setuid -- casual use could result in a lot
40 * of unnecessary traffic on our poor, congested nets.)
41 *
42 * I stole the idea for this program from Steve Deering. Since
43 * the first release, I've learned that had I attended the right
44 * IETF working group meetings, I also could have stolen it from Guy
45 * Almes or Matt Mathis. I don't know (or care) who came up with
46 * the idea first. I envy the originators' perspicacity and I'm
47 * glad they didn't keep the idea a secret.
48 *
49 * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
50 * enhancements to the original distribution.
51 *
52 * I've hacked up a round-trip-route version of this that works by
53 * sending a loose-source-routed udp datagram through the destination
54 * back to yourself. Unfortunately, SO many gateways botch source
55 * routing, the thing is almost worthless. Maybe one day...
56 *
57 * -- Van Jacobson (van@helios.ee.lbl.gov)
58 * Tue Dec 20 03:50:13 PST 1988
59 */
60
Eric Andersenbdfd0d72001-10-24 05:00:29 +000061#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
62//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
63#undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
Eric Andersen7467c8d2001-07-12 20:26:32 +000064
Eric Andersen5c58d282001-07-10 16:29:00 +000065#include <stdio.h>
66#include <errno.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70#include <sys/time.h>
Eric Andersencd8c4362001-11-10 11:22:46 +000071#include "inet_common.h"
Eric Andersen5c58d282001-07-10 16:29:00 +000072#include <netdb.h>
73#include <endian.h>
Eric Andersen5c58d282001-07-10 16:29:00 +000074#include <netinet/udp.h>
75#include <netinet/ip.h>
76#include <netinet/ip_icmp.h>
77
Eric Andersenc7bda1c2004-03-15 08:29:22 +000078
Eric Andersen5c58d282001-07-10 16:29:00 +000079#define MAXPACKET 65535 /* max ip packet size */
80#ifndef MAXHOSTNAMELEN
81#define MAXHOSTNAMELEN 64
82#endif
83
84/*
85 * format of a (udp) probe packet.
86 */
87struct opacket {
88 struct ip ip;
89 struct udphdr udp;
90 u_char seq; /* sequence number of this packet */
91 u_char ttl; /* ttl packet left with */
92 struct timeval tv; /* time packet left */
93};
94
95/*
96 * Definitions for internet protocol version 4.
97 * Per RFC 791, September 1981.
98 */
99#define IPVERSION 4
100
101
102#include "busybox.h"
103
Eric Andersen5c58d282001-07-10 16:29:00 +0000104static u_char packet[512]; /* last inbound (icmp) packet */
105static struct opacket *outpacket; /* last output (udp) packet */
106
107static int s; /* receive (icmp) socket file descriptor */
108static int sndsock; /* send (udp) socket file descriptor */
109
110static struct sockaddr whereto; /* Who to try to reach */
111static int datalen; /* How much data */
112
113static char *hostname;
114
115static int max_ttl = 30;
116static u_short ident;
117static u_short port = 32768+666; /* start udp dest port # for probe packets */
118
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000119#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000120static int verbose;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000121#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000122static int waittime = 5; /* time to wait for response (in seconds) */
123static int nflag; /* print addresses numerically */
124
Eric Andersen7467c8d2001-07-12 20:26:32 +0000125/*
126 * Construct an Internet address representation.
127 * If the nflag has been supplied, give
128 * numeric value, otherwise try for symbolic name.
129 */
Eric Andersen044228d2001-07-17 01:12:36 +0000130static inline void
131inetname(struct sockaddr_in *from)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000132{
133 char *cp;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000134 static char domain[MAXHOSTNAMELEN + 1];
Eric Andersencd8c4362001-11-10 11:22:46 +0000135 char name[MAXHOSTNAMELEN + 1];
Eric Andersen7467c8d2001-07-12 20:26:32 +0000136 static int first = 1;
Eric Andersen044228d2001-07-17 01:12:36 +0000137 const char *ina;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000138
139 if (first && !nflag) {
140 first = 0;
Eric Andersenad79c0b2002-06-06 12:24:51 +0000141 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000142 domain[0] = 0;
143 }
144 cp = 0;
Eric Andersen044228d2001-07-17 01:12:36 +0000145 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
Eric Andersenad79c0b2002-06-06 12:24:51 +0000146 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
Eric Andersencd8c4362001-11-10 11:22:46 +0000147 if ((cp = strchr(name, '.')) &&
Eric Andersen7467c8d2001-07-12 20:26:32 +0000148 !strcmp(cp + 1, domain))
149 *cp = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000150 cp = (char *)name;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000151 }
152 }
Eric Andersen044228d2001-07-17 01:12:36 +0000153 ina = inet_ntoa(from->sin_addr);
154 if (nflag)
155 printf(" %s", ina);
156 else
157 printf(" %s (%s)", (cp ? cp : ina), ina);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000158}
159
160static inline void
161print(u_char *buf, int cc, struct sockaddr_in *from)
162{
163 struct ip *ip;
164 int hlen;
165
166 ip = (struct ip *) buf;
167 hlen = ip->ip_hl << 2;
168 cc -= hlen;
169
Eric Andersen044228d2001-07-17 01:12:36 +0000170 inetname(from);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000171#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000172 if (verbose)
173 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
174#endif
175}
176
177static inline double
178deltaT(struct timeval *t1p, struct timeval *t2p)
179{
180 double dt;
181
182 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
183 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
184 return (dt);
185}
186
187static inline int
188wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
189{
190 fd_set fds;
191 static struct timeval wait;
192 int cc = 0;
193 int fromlen = sizeof (*from);
194
195 FD_ZERO(&fds);
196 FD_SET(sock, &fds);
197 if (reset_timer) {
198 /*
199 * traceroute could hang if someone else has a ping
200 * running and our ICMP reply gets dropped but we don't
201 * realize it because we keep waking up to handle those
202 * other ICMP packets that keep coming in. To fix this,
203 * "reset_timer" will only be true if the last packet that
204 * came in was for us or if this is the first time we're
205 * waiting for a reply since sending out a probe. Note
206 * that this takes advantage of the select() feature on
207 * Linux where the remaining timeout is written to the
208 * struct timeval area.
209 */
210 wait.tv_sec = waittime;
211 wait.tv_usec = 0;
212 }
213
214 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
215 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
216 (struct sockaddr *)from, &fromlen);
217
218 return(cc);
219}
220
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000221#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000222/*
223 * Convert an ICMP "type" field to a printable string.
224 */
225static inline const char *
Eric Andersenad79c0b2002-06-06 12:24:51 +0000226pr_type(u_char t)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000227{
228 static const char * const ttab[] = {
229 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
230 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
231 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
232 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
233 "Info Reply"
234 };
235
236 if(t > 16)
237 return("OUT-OF-RANGE");
238
239 return(ttab[t]);
240}
241#endif
242
243static inline int
244packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
245{
246 struct icmp *icp;
247 u_char type, code;
248 int hlen;
249 struct ip *ip;
250
251 ip = (struct ip *) buf;
252 hlen = ip->ip_hl << 2;
253 if (cc < hlen + ICMP_MINLEN) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000254#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000255 if (verbose)
256 printf("packet too short (%d bytes) from %s\n", cc,
257 inet_ntoa(from->sin_addr));
258#endif
259 return (0);
260 }
261 cc -= hlen;
262 icp = (struct icmp *)(buf + hlen);
263 type = icp->icmp_type; code = icp->icmp_code;
264 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
265 type == ICMP_UNREACH) {
266 struct ip *hip;
267 struct udphdr *up;
268
269 hip = &icp->icmp_ip;
270 hlen = hip->ip_hl << 2;
271 up = (struct udphdr *)((u_char *)hip + hlen);
272 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
273 up->source == htons(ident) &&
274 up->dest == htons(port+seq))
275 return (type == ICMP_TIMXCEED? -1 : code+1);
276 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000277#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000278 if (verbose) {
279 int i;
280 u_long *lp = (u_long *)&icp->icmp_ip;
281
282 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
283 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
284 type, pr_type(type), icp->icmp_code);
285 for (i = 4; i < cc ; i += sizeof(long))
286 printf("%2d: x%8.8lx\n", i, *lp++);
287 }
288#endif
289 return(0);
290}
291
292static void /* not inline */
293send_probe(int seq, int ttl)
294{
295 struct opacket *op = outpacket;
296 struct ip *ip = &op->ip;
297 struct udphdr *up = &op->udp;
298 int i;
299 struct timezone tz;
300
301 ip->ip_off = 0;
302 ip->ip_hl = sizeof(*ip) >> 2;
303 ip->ip_p = IPPROTO_UDP;
304 ip->ip_len = datalen;
305 ip->ip_ttl = ttl;
306 ip->ip_v = IPVERSION;
307 ip->ip_id = htons(ident+seq);
308
309 up->source = htons(ident);
310 up->dest = htons(port+seq);
311 up->len = htons((u_short)(datalen - sizeof(struct ip)));
312 up->check = 0;
313
314 op->seq = seq;
315 op->ttl = ttl;
316 (void) gettimeofday(&op->tv, &tz);
317
318 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
319 sizeof(struct sockaddr));
320 if (i < 0 || i != datalen) {
321 if (i<0)
322 perror("sendto");
323 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
324 datalen, i);
325 (void) fflush(stdout);
326 }
327}
328
329
Eric Andersen5c58d282001-07-10 16:29:00 +0000330int
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000331#ifndef CONFIG_TRACEROUTE
Aaron Lehmann7dd2cec2002-08-23 07:52:58 +0000332main(int argc, char *argv[])
Eric Andersen5c58d282001-07-10 16:29:00 +0000333#else
Aaron Lehmann7dd2cec2002-08-23 07:52:58 +0000334traceroute_main(int argc, char *argv[])
Eric Andersen5c58d282001-07-10 16:29:00 +0000335#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000336{
337 extern char *optarg;
338 extern int optind;
339 struct hostent *hp;
Eric Andersen5c58d282001-07-10 16:29:00 +0000340 struct sockaddr_in from, *to;
341 int ch, i, on, probe, seq, tos, ttl;
342
343 int options = 0; /* socket options */
344 char *source = 0;
345 int nprobes = 3;
346
347 on = 1;
348 seq = tos = 0;
349 to = (struct sockaddr_in *)&whereto;
350 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
351 switch(ch) {
352 case 'd':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000353#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000354 options |= SO_DEBUG;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000355#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000356 break;
357 case 'm':
358 max_ttl = atoi(optarg);
359 if (max_ttl <= 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000360 bb_error_msg_and_die("max ttl must be >1.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000361 break;
362 case 'n':
363 nflag++;
364 break;
365 case 'p':
366 port = atoi(optarg);
367 if (port < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000368 bb_error_msg_and_die("port must be >0.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000369 break;
370 case 'q':
371 nprobes = atoi(optarg);
372 if (nprobes < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000373 bb_error_msg_and_die("nprobes must be >0.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000374 break;
375 case 'r':
376 options |= SO_DONTROUTE;
377 break;
378 case 's':
379 /*
380 * set the ip source address of the outbound
381 * probe (e.g., on a multi-homed host).
382 */
383 source = optarg;
384 break;
385 case 't':
386 tos = atoi(optarg);
387 if (tos < 0 || tos > 255)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000388 bb_error_msg_and_die("tos must be 0 to 255.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000389 break;
390 case 'v':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000391#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000392 verbose++;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000393#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000394 break;
395 case 'w':
396 waittime = atoi(optarg);
397 if (waittime <= 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000398 bb_error_msg_and_die("wait must be >1 sec.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000399 break;
400 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000401 bb_show_usage();
Eric Andersen5c58d282001-07-10 16:29:00 +0000402 }
403 argc -= optind;
404 argv += optind;
405
406 if (argc < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000407 bb_show_usage();
Eric Andersen5c58d282001-07-10 16:29:00 +0000408
409 setlinebuf (stdout);
410
Eric Andersen7467c8d2001-07-12 20:26:32 +0000411 memset(&whereto, 0, sizeof(struct sockaddr));
412 hp = xgethostbyname(*argv);
Eric Andersen5c58d282001-07-10 16:29:00 +0000413 to->sin_family = hp->h_addrtype;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000414 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
Eric Andersen5c58d282001-07-10 16:29:00 +0000415 hostname = (char *)hp->h_name;
Eric Andersen5c58d282001-07-10 16:29:00 +0000416 if (*++argv)
417 datalen = atoi(*argv);
418 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000419 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
Eric Andersen5c58d282001-07-10 16:29:00 +0000420 MAXPACKET - sizeof(struct opacket));
421 datalen += sizeof(struct opacket);
422 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000423 memset(outpacket, 0, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000424 outpacket->ip.ip_dst = to->sin_addr;
425 outpacket->ip.ip_tos = tos;
426 outpacket->ip.ip_v = IPVERSION;
427 outpacket->ip.ip_id = 0;
428
429 ident = (getpid() & 0xffff) | 0x8000;
430
Eric Andersen7467c8d2001-07-12 20:26:32 +0000431 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000432 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000433
434 s = create_icmp_socket();
435
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000436#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000437 if (options & SO_DEBUG)
438 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
439 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000440#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000441 if (options & SO_DONTROUTE)
442 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
443 (char *)&on, sizeof(on));
Eric Andersen5c58d282001-07-10 16:29:00 +0000444#ifdef SO_SNDBUF
445 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
446 sizeof(datalen)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000447 bb_perror_msg_and_die("SO_SNDBUF");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000448#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000449#ifdef IP_HDRINCL
450 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
451 sizeof(on)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000452 bb_perror_msg_and_die("IP_HDRINCL");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000453#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000454#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000455 if (options & SO_DEBUG)
456 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
457 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000458#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000459 if (options & SO_DONTROUTE)
460 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
461 (char *)&on, sizeof(on));
462
463 if (source) {
Eric Andersen7467c8d2001-07-12 20:26:32 +0000464 memset(&from, 0, sizeof(struct sockaddr));
Eric Andersen5c58d282001-07-10 16:29:00 +0000465 from.sin_family = AF_INET;
466 from.sin_addr.s_addr = inet_addr(source);
467 if (from.sin_addr.s_addr == -1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000468 bb_error_msg_and_die("unknown host %s", source);
Eric Andersen5c58d282001-07-10 16:29:00 +0000469 outpacket->ip.ip_src = from.sin_addr;
470#ifndef IP_HDRINCL
471 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000472 bb_perror_msg_and_die("bind");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000473#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000474 }
475
476 fprintf(stderr, "traceroute to %s (%s)", hostname,
477 inet_ntoa(to->sin_addr));
478 if (source)
479 fprintf(stderr, " from %s", source);
480 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000481
482 for (ttl = 1; ttl <= max_ttl; ++ttl) {
483 u_long lastaddr = 0;
484 int got_there = 0;
485 int unreachable = 0;
486
487 printf("%2d ", ttl);
488 for (probe = 0; probe < nprobes; ++probe) {
489 int cc, reset_timer;
490 struct timeval t1, t2;
491 struct timezone tz;
492 struct ip *ip;
493
494 (void) gettimeofday(&t1, &tz);
495 send_probe(++seq, ttl);
496 reset_timer = 1;
497 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
498 (void) gettimeofday(&t2, &tz);
499 if ((i = packet_ok(packet, cc, &from, seq))) {
500 reset_timer = 1;
501 if (from.sin_addr.s_addr != lastaddr) {
502 print(packet, cc, &from);
503 lastaddr = from.sin_addr.s_addr;
504 }
505 printf(" %g ms", deltaT(&t1, &t2));
506 switch(i - 1) {
507 case ICMP_UNREACH_PORT:
Eric Andersen5c58d282001-07-10 16:29:00 +0000508 ip = (struct ip *)packet;
509 if (ip->ip_ttl <= 1)
510 printf(" !");
Eric Andersen5c58d282001-07-10 16:29:00 +0000511 ++got_there;
512 break;
513 case ICMP_UNREACH_NET:
514 ++unreachable;
515 printf(" !N");
516 break;
517 case ICMP_UNREACH_HOST:
518 ++unreachable;
519 printf(" !H");
520 break;
521 case ICMP_UNREACH_PROTOCOL:
522 ++got_there;
523 printf(" !P");
524 break;
525 case ICMP_UNREACH_NEEDFRAG:
526 ++unreachable;
527 printf(" !F");
528 break;
529 case ICMP_UNREACH_SRCFAIL:
530 ++unreachable;
531 printf(" !S");
532 break;
533 }
534 break;
535 } else
536 reset_timer = 0;
537 }
538 if (cc == 0)
539 printf(" *");
540 (void) fflush(stdout);
541 }
542 putchar('\n');
543 if (got_there || unreachable >= nprobes-1)
Eric Andersencd8c4362001-11-10 11:22:46 +0000544 return 0;
Eric Andersen5c58d282001-07-10 16:29:00 +0000545 }
546
547 return 0;
548}