blob: 628b13492b30ba3c429301204f60fd0d6078ed8c [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
Paul Fox28069402005-07-20 11:55:08 +0000104 /* last inbound (icmp) packet */
105static u_char packet[512] __attribute__ ((aligned));
Eric Andersen5c58d282001-07-10 16:29:00 +0000106static struct opacket *outpacket; /* last output (udp) packet */
107
108static int s; /* receive (icmp) socket file descriptor */
109static int sndsock; /* send (udp) socket file descriptor */
110
111static struct sockaddr whereto; /* Who to try to reach */
112static int datalen; /* How much data */
113
114static char *hostname;
115
116static int max_ttl = 30;
117static u_short ident;
118static u_short port = 32768+666; /* start udp dest port # for probe packets */
119
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000120#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000121static int verbose;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000122#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000123static int waittime = 5; /* time to wait for response (in seconds) */
124static int nflag; /* print addresses numerically */
125
Eric Andersen7467c8d2001-07-12 20:26:32 +0000126/*
127 * Construct an Internet address representation.
128 * If the nflag has been supplied, give
129 * numeric value, otherwise try for symbolic name.
130 */
Eric Andersen044228d2001-07-17 01:12:36 +0000131static inline void
132inetname(struct sockaddr_in *from)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000133{
134 char *cp;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000135 static char domain[MAXHOSTNAMELEN + 1];
Eric Andersencd8c4362001-11-10 11:22:46 +0000136 char name[MAXHOSTNAMELEN + 1];
Eric Andersen7467c8d2001-07-12 20:26:32 +0000137 static int first = 1;
Eric Andersen044228d2001-07-17 01:12:36 +0000138 const char *ina;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000139
140 if (first && !nflag) {
141 first = 0;
Eric Andersenad79c0b2002-06-06 12:24:51 +0000142 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000143 domain[0] = 0;
144 }
145 cp = 0;
Eric Andersen044228d2001-07-17 01:12:36 +0000146 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
Eric Andersenad79c0b2002-06-06 12:24:51 +0000147 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
Eric Andersencd8c4362001-11-10 11:22:46 +0000148 if ((cp = strchr(name, '.')) &&
Eric Andersen7467c8d2001-07-12 20:26:32 +0000149 !strcmp(cp + 1, domain))
150 *cp = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000151 cp = (char *)name;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000152 }
153 }
Eric Andersen044228d2001-07-17 01:12:36 +0000154 ina = inet_ntoa(from->sin_addr);
155 if (nflag)
156 printf(" %s", ina);
157 else
158 printf(" %s (%s)", (cp ? cp : ina), ina);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000159}
160
161static inline void
162print(u_char *buf, int cc, struct sockaddr_in *from)
163{
164 struct ip *ip;
165 int hlen;
166
167 ip = (struct ip *) buf;
168 hlen = ip->ip_hl << 2;
169 cc -= hlen;
170
Eric Andersen044228d2001-07-17 01:12:36 +0000171 inetname(from);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000172#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000173 if (verbose)
174 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
175#endif
176}
177
178static inline double
179deltaT(struct timeval *t1p, struct timeval *t2p)
180{
181 double dt;
182
183 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
184 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
185 return (dt);
186}
187
188static inline int
Paul Fox28069402005-07-20 11:55:08 +0000189wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000190{
191 fd_set fds;
192 static struct timeval wait;
193 int cc = 0;
194 int fromlen = sizeof (*from);
195
196 FD_ZERO(&fds);
197 FD_SET(sock, &fds);
198 if (reset_timer) {
199 /*
200 * traceroute could hang if someone else has a ping
201 * running and our ICMP reply gets dropped but we don't
202 * realize it because we keep waking up to handle those
203 * other ICMP packets that keep coming in. To fix this,
204 * "reset_timer" will only be true if the last packet that
205 * came in was for us or if this is the first time we're
206 * waiting for a reply since sending out a probe. Note
207 * that this takes advantage of the select() feature on
208 * Linux where the remaining timeout is written to the
209 * struct timeval area.
210 */
211 wait.tv_sec = waittime;
212 wait.tv_usec = 0;
213 }
214
215 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
Paul Fox28069402005-07-20 11:55:08 +0000216 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
Eric Andersen7467c8d2001-07-12 20:26:32 +0000217 (struct sockaddr *)from, &fromlen);
218
219 return(cc);
220}
221
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000222#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000223/*
224 * Convert an ICMP "type" field to a printable string.
225 */
226static inline const char *
Eric Andersenad79c0b2002-06-06 12:24:51 +0000227pr_type(u_char t)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000228{
229 static const char * const ttab[] = {
230 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
231 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
232 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
233 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
234 "Info Reply"
235 };
236
237 if(t > 16)
238 return("OUT-OF-RANGE");
239
240 return(ttab[t]);
241}
242#endif
243
244static inline int
245packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
246{
247 struct icmp *icp;
248 u_char type, code;
249 int hlen;
250 struct ip *ip;
251
252 ip = (struct ip *) buf;
253 hlen = ip->ip_hl << 2;
254 if (cc < hlen + ICMP_MINLEN) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000255#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000256 if (verbose)
257 printf("packet too short (%d bytes) from %s\n", cc,
258 inet_ntoa(from->sin_addr));
259#endif
260 return (0);
261 }
262 cc -= hlen;
263 icp = (struct icmp *)(buf + hlen);
264 type = icp->icmp_type; code = icp->icmp_code;
265 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
266 type == ICMP_UNREACH) {
267 struct ip *hip;
268 struct udphdr *up;
269
270 hip = &icp->icmp_ip;
271 hlen = hip->ip_hl << 2;
272 up = (struct udphdr *)((u_char *)hip + hlen);
273 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
274 up->source == htons(ident) &&
275 up->dest == htons(port+seq))
276 return (type == ICMP_TIMXCEED? -1 : code+1);
277 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000278#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000279 if (verbose) {
280 int i;
281 u_long *lp = (u_long *)&icp->icmp_ip;
282
283 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
284 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
285 type, pr_type(type), icp->icmp_code);
286 for (i = 4; i < cc ; i += sizeof(long))
287 printf("%2d: x%8.8lx\n", i, *lp++);
288 }
289#endif
290 return(0);
291}
292
293static void /* not inline */
294send_probe(int seq, int ttl)
295{
296 struct opacket *op = outpacket;
297 struct ip *ip = &op->ip;
298 struct udphdr *up = &op->udp;
299 int i;
300 struct timezone tz;
301
302 ip->ip_off = 0;
303 ip->ip_hl = sizeof(*ip) >> 2;
304 ip->ip_p = IPPROTO_UDP;
305 ip->ip_len = datalen;
306 ip->ip_ttl = ttl;
307 ip->ip_v = IPVERSION;
308 ip->ip_id = htons(ident+seq);
309
310 up->source = htons(ident);
311 up->dest = htons(port+seq);
312 up->len = htons((u_short)(datalen - sizeof(struct ip)));
313 up->check = 0;
314
315 op->seq = seq;
316 op->ttl = ttl;
317 (void) gettimeofday(&op->tv, &tz);
318
319 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
320 sizeof(struct sockaddr));
321 if (i < 0 || i != datalen) {
322 if (i<0)
323 perror("sendto");
324 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
325 datalen, i);
326 (void) fflush(stdout);
327 }
328}
329
330
Eric Andersen5c58d282001-07-10 16:29:00 +0000331int
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000332#ifndef CONFIG_TRACEROUTE
Aaron Lehmann7dd2cec2002-08-23 07:52:58 +0000333main(int argc, char *argv[])
Eric Andersen5c58d282001-07-10 16:29:00 +0000334#else
Aaron Lehmann7dd2cec2002-08-23 07:52:58 +0000335traceroute_main(int argc, char *argv[])
Eric Andersen5c58d282001-07-10 16:29:00 +0000336#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000337{
338 extern char *optarg;
339 extern int optind;
340 struct hostent *hp;
Eric Andersen5c58d282001-07-10 16:29:00 +0000341 struct sockaddr_in from, *to;
342 int ch, i, on, probe, seq, tos, ttl;
343
344 int options = 0; /* socket options */
345 char *source = 0;
346 int nprobes = 3;
347
348 on = 1;
349 seq = tos = 0;
350 to = (struct sockaddr_in *)&whereto;
351 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
352 switch(ch) {
353 case 'd':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000354#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000355 options |= SO_DEBUG;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000356#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000357 break;
358 case 'm':
359 max_ttl = atoi(optarg);
360 if (max_ttl <= 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000361 bb_error_msg_and_die("max ttl must be >1.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000362 break;
363 case 'n':
364 nflag++;
365 break;
366 case 'p':
367 port = atoi(optarg);
368 if (port < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000369 bb_error_msg_and_die("port must be >0.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000370 break;
371 case 'q':
372 nprobes = atoi(optarg);
373 if (nprobes < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000374 bb_error_msg_and_die("nprobes must be >0.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000375 break;
376 case 'r':
377 options |= SO_DONTROUTE;
378 break;
379 case 's':
380 /*
381 * set the ip source address of the outbound
382 * probe (e.g., on a multi-homed host).
383 */
384 source = optarg;
385 break;
386 case 't':
387 tos = atoi(optarg);
388 if (tos < 0 || tos > 255)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000389 bb_error_msg_and_die("tos must be 0 to 255.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000390 break;
391 case 'v':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000392#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000393 verbose++;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000394#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000395 break;
396 case 'w':
397 waittime = atoi(optarg);
398 if (waittime <= 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000399 bb_error_msg_and_die("wait must be >1 sec.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000400 break;
401 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000402 bb_show_usage();
Eric Andersen5c58d282001-07-10 16:29:00 +0000403 }
404 argc -= optind;
405 argv += optind;
406
407 if (argc < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000408 bb_show_usage();
Eric Andersen5c58d282001-07-10 16:29:00 +0000409
410 setlinebuf (stdout);
411
Eric Andersen7467c8d2001-07-12 20:26:32 +0000412 memset(&whereto, 0, sizeof(struct sockaddr));
413 hp = xgethostbyname(*argv);
Eric Andersen5c58d282001-07-10 16:29:00 +0000414 to->sin_family = hp->h_addrtype;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000415 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
Eric Andersen5c58d282001-07-10 16:29:00 +0000416 hostname = (char *)hp->h_name;
Eric Andersen5c58d282001-07-10 16:29:00 +0000417 if (*++argv)
418 datalen = atoi(*argv);
419 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000420 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
Mike Frysinger66c37d12005-07-31 22:22:20 +0000421 (int)(MAXPACKET - sizeof(struct opacket)));
Eric Andersen5c58d282001-07-10 16:29:00 +0000422 datalen += sizeof(struct opacket);
423 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000424 memset(outpacket, 0, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000425 outpacket->ip.ip_dst = to->sin_addr;
426 outpacket->ip.ip_tos = tos;
427 outpacket->ip.ip_v = IPVERSION;
428 outpacket->ip.ip_id = 0;
429
430 ident = (getpid() & 0xffff) | 0x8000;
431
Eric Andersen7467c8d2001-07-12 20:26:32 +0000432 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000433 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000434
435 s = create_icmp_socket();
436
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000437#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000438 if (options & SO_DEBUG)
439 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
440 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000441#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000442 if (options & SO_DONTROUTE)
443 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
444 (char *)&on, sizeof(on));
Eric Andersen5c58d282001-07-10 16:29:00 +0000445#ifdef SO_SNDBUF
446 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
447 sizeof(datalen)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000448 bb_perror_msg_and_die("SO_SNDBUF");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000449#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000450#ifdef IP_HDRINCL
451 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
452 sizeof(on)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000453 bb_perror_msg_and_die("IP_HDRINCL");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000454#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000455#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000456 if (options & SO_DEBUG)
457 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
458 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000459#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000460 if (options & SO_DONTROUTE)
461 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
462 (char *)&on, sizeof(on));
463
464 if (source) {
Eric Andersen7467c8d2001-07-12 20:26:32 +0000465 memset(&from, 0, sizeof(struct sockaddr));
Eric Andersen5c58d282001-07-10 16:29:00 +0000466 from.sin_family = AF_INET;
467 from.sin_addr.s_addr = inet_addr(source);
468 if (from.sin_addr.s_addr == -1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000469 bb_error_msg_and_die("unknown host %s", source);
Eric Andersen5c58d282001-07-10 16:29:00 +0000470 outpacket->ip.ip_src = from.sin_addr;
471#ifndef IP_HDRINCL
472 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000473 bb_perror_msg_and_die("bind");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000474#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000475 }
476
477 fprintf(stderr, "traceroute to %s (%s)", hostname,
478 inet_ntoa(to->sin_addr));
479 if (source)
480 fprintf(stderr, " from %s", source);
481 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000482
483 for (ttl = 1; ttl <= max_ttl; ++ttl) {
484 u_long lastaddr = 0;
485 int got_there = 0;
486 int unreachable = 0;
487
488 printf("%2d ", ttl);
489 for (probe = 0; probe < nprobes; ++probe) {
490 int cc, reset_timer;
491 struct timeval t1, t2;
492 struct timezone tz;
493 struct ip *ip;
494
495 (void) gettimeofday(&t1, &tz);
496 send_probe(++seq, ttl);
497 reset_timer = 1;
Paul Fox28069402005-07-20 11:55:08 +0000498 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
Eric Andersen5c58d282001-07-10 16:29:00 +0000499 (void) gettimeofday(&t2, &tz);
500 if ((i = packet_ok(packet, cc, &from, seq))) {
501 reset_timer = 1;
502 if (from.sin_addr.s_addr != lastaddr) {
503 print(packet, cc, &from);
504 lastaddr = from.sin_addr.s_addr;
505 }
506 printf(" %g ms", deltaT(&t1, &t2));
507 switch(i - 1) {
508 case ICMP_UNREACH_PORT:
Eric Andersen5c58d282001-07-10 16:29:00 +0000509 ip = (struct ip *)packet;
510 if (ip->ip_ttl <= 1)
511 printf(" !");
Eric Andersen5c58d282001-07-10 16:29:00 +0000512 ++got_there;
513 break;
514 case ICMP_UNREACH_NET:
515 ++unreachable;
516 printf(" !N");
517 break;
518 case ICMP_UNREACH_HOST:
519 ++unreachable;
520 printf(" !H");
521 break;
522 case ICMP_UNREACH_PROTOCOL:
523 ++got_there;
524 printf(" !P");
525 break;
526 case ICMP_UNREACH_NEEDFRAG:
527 ++unreachable;
528 printf(" !F");
529 break;
530 case ICMP_UNREACH_SRCFAIL:
531 ++unreachable;
532 printf(" !S");
533 break;
534 }
535 break;
536 } else
537 reset_timer = 0;
538 }
539 if (cc == 0)
540 printf(" *");
541 (void) fflush(stdout);
542 }
543 putchar('\n');
544 if (got_there || unreachable >= nprobes-1)
Eric Andersencd8c4362001-11-10 11:22:46 +0000545 return 0;
Eric Andersen5c58d282001-07-10 16:29:00 +0000546 }
547
548 return 0;
549}