blob: be9ea1d952fc11c0d4a3d6ee0a68d4212d081fa6 [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 Andersenbe0c3602001-08-02 10:55:32 +000078
79 /* It turns out that libc5 doesn't have proper icmp support
80 * built into it header files, so we have to supplement it */
81#if __GNU_LIBRARY__ < 5
82static const int ICMP_MINLEN = 8; /* abs minimum */
83
84struct icmp_ra_addr
85{
86 u_int32_t ira_addr;
87 u_int32_t ira_preference;
88};
89
90
91struct icmp
92{
93 u_int8_t icmp_type; /* type of message, see below */
94 u_int8_t icmp_code; /* type sub code */
95 u_int16_t icmp_cksum; /* ones complement checksum of struct */
96 union
97 {
98 u_char ih_pptr; /* ICMP_PARAMPROB */
99 struct in_addr ih_gwaddr; /* gateway address */
100 struct ih_idseq /* echo datagram */
101 {
102 u_int16_t icd_id;
103 u_int16_t icd_seq;
104 } ih_idseq;
105 u_int32_t ih_void;
106
107 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
108 struct ih_pmtu
109 {
110 u_int16_t ipm_void;
111 u_int16_t ipm_nextmtu;
112 } ih_pmtu;
113
114 struct ih_rtradv
115 {
116 u_int8_t irt_num_addrs;
117 u_int8_t irt_wpa;
118 u_int16_t irt_lifetime;
119 } ih_rtradv;
120 } icmp_hun;
121#define icmp_pptr icmp_hun.ih_pptr
122#define icmp_gwaddr icmp_hun.ih_gwaddr
123#define icmp_id icmp_hun.ih_idseq.icd_id
124#define icmp_seq icmp_hun.ih_idseq.icd_seq
125#define icmp_void icmp_hun.ih_void
126#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
127#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
128#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
129#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
130#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
131 union
132 {
133 struct
134 {
135 u_int32_t its_otime;
136 u_int32_t its_rtime;
137 u_int32_t its_ttime;
138 } id_ts;
139 struct
140 {
141 struct ip idi_ip;
142 /* options and then 64 bits of data */
143 } id_ip;
144 struct icmp_ra_addr id_radv;
145 u_int32_t id_mask;
146 u_int8_t id_data[1];
147 } icmp_dun;
148#define icmp_otime icmp_dun.id_ts.its_otime
149#define icmp_rtime icmp_dun.id_ts.its_rtime
150#define icmp_ttime icmp_dun.id_ts.its_ttime
151#define icmp_ip icmp_dun.id_ip.idi_ip
152#define icmp_radv icmp_dun.id_radv
153#define icmp_mask icmp_dun.id_mask
154#define icmp_data icmp_dun.id_data
155};
156
157#define ICMP_MINLEN 8 /* abs minimum */
158#define ICMP_UNREACH 3 /* dest unreachable, codes: */
159#define ICMP_TIMXCEED 11 /* time exceeded, code: */
160#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
161#define ICMP_UNREACH_NET 0 /* bad net */
162#define ICMP_UNREACH_HOST 1 /* bad host */
163#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
164#define ICMP_UNREACH_PORT 3 /* bad port */
165#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
166#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
167#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000168
Eric Andersenaf6b40a2001-07-31 22:53:36 +0000169
Eric Andersen5c58d282001-07-10 16:29:00 +0000170#define MAXPACKET 65535 /* max ip packet size */
171#ifndef MAXHOSTNAMELEN
172#define MAXHOSTNAMELEN 64
173#endif
174
175/*
176 * format of a (udp) probe packet.
177 */
178struct opacket {
179 struct ip ip;
180 struct udphdr udp;
181 u_char seq; /* sequence number of this packet */
182 u_char ttl; /* ttl packet left with */
183 struct timeval tv; /* time packet left */
184};
185
186/*
187 * Definitions for internet protocol version 4.
188 * Per RFC 791, September 1981.
189 */
190#define IPVERSION 4
191
192
193#include "busybox.h"
194
Eric Andersen5c58d282001-07-10 16:29:00 +0000195static u_char packet[512]; /* last inbound (icmp) packet */
196static struct opacket *outpacket; /* last output (udp) packet */
197
198static int s; /* receive (icmp) socket file descriptor */
199static int sndsock; /* send (udp) socket file descriptor */
200
201static struct sockaddr whereto; /* Who to try to reach */
202static int datalen; /* How much data */
203
204static char *hostname;
205
206static int max_ttl = 30;
207static u_short ident;
208static u_short port = 32768+666; /* start udp dest port # for probe packets */
209
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000210#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000211static int verbose;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000212#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000213static int waittime = 5; /* time to wait for response (in seconds) */
214static int nflag; /* print addresses numerically */
215
Eric Andersen7467c8d2001-07-12 20:26:32 +0000216/*
217 * Construct an Internet address representation.
218 * If the nflag has been supplied, give
219 * numeric value, otherwise try for symbolic name.
220 */
Eric Andersen044228d2001-07-17 01:12:36 +0000221static inline void
222inetname(struct sockaddr_in *from)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000223{
224 char *cp;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000225 static char domain[MAXHOSTNAMELEN + 1];
Eric Andersencd8c4362001-11-10 11:22:46 +0000226 char name[MAXHOSTNAMELEN + 1];
Eric Andersen7467c8d2001-07-12 20:26:32 +0000227 static int first = 1;
Eric Andersen044228d2001-07-17 01:12:36 +0000228 const char *ina;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000229
230 if (first && !nflag) {
231 first = 0;
Eric Andersenad79c0b2002-06-06 12:24:51 +0000232 if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000233 domain[0] = 0;
234 }
235 cp = 0;
Eric Andersen044228d2001-07-17 01:12:36 +0000236 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
Eric Andersenad79c0b2002-06-06 12:24:51 +0000237 if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
Eric Andersencd8c4362001-11-10 11:22:46 +0000238 if ((cp = strchr(name, '.')) &&
Eric Andersen7467c8d2001-07-12 20:26:32 +0000239 !strcmp(cp + 1, domain))
240 *cp = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000241 cp = (char *)name;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000242 }
243 }
Eric Andersen044228d2001-07-17 01:12:36 +0000244 ina = inet_ntoa(from->sin_addr);
245 if (nflag)
246 printf(" %s", ina);
247 else
248 printf(" %s (%s)", (cp ? cp : ina), ina);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000249}
250
251static inline void
252print(u_char *buf, int cc, struct sockaddr_in *from)
253{
254 struct ip *ip;
255 int hlen;
256
257 ip = (struct ip *) buf;
258 hlen = ip->ip_hl << 2;
259 cc -= hlen;
260
Eric Andersen044228d2001-07-17 01:12:36 +0000261 inetname(from);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000262#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000263 if (verbose)
264 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
265#endif
266}
267
268static inline double
269deltaT(struct timeval *t1p, struct timeval *t2p)
270{
271 double dt;
272
273 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
274 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
275 return (dt);
276}
277
278static inline int
279wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
280{
281 fd_set fds;
282 static struct timeval wait;
283 int cc = 0;
284 int fromlen = sizeof (*from);
285
286 FD_ZERO(&fds);
287 FD_SET(sock, &fds);
288 if (reset_timer) {
289 /*
290 * traceroute could hang if someone else has a ping
291 * running and our ICMP reply gets dropped but we don't
292 * realize it because we keep waking up to handle those
293 * other ICMP packets that keep coming in. To fix this,
294 * "reset_timer" will only be true if the last packet that
295 * came in was for us or if this is the first time we're
296 * waiting for a reply since sending out a probe. Note
297 * that this takes advantage of the select() feature on
298 * Linux where the remaining timeout is written to the
299 * struct timeval area.
300 */
301 wait.tv_sec = waittime;
302 wait.tv_usec = 0;
303 }
304
305 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
306 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
307 (struct sockaddr *)from, &fromlen);
308
309 return(cc);
310}
311
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000312#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000313/*
314 * Convert an ICMP "type" field to a printable string.
315 */
316static inline const char *
Eric Andersenad79c0b2002-06-06 12:24:51 +0000317pr_type(u_char t)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000318{
319 static const char * const ttab[] = {
320 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
321 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
322 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
323 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
324 "Info Reply"
325 };
326
327 if(t > 16)
328 return("OUT-OF-RANGE");
329
330 return(ttab[t]);
331}
332#endif
333
334static inline int
335packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
336{
337 struct icmp *icp;
338 u_char type, code;
339 int hlen;
340 struct ip *ip;
341
342 ip = (struct ip *) buf;
343 hlen = ip->ip_hl << 2;
344 if (cc < hlen + ICMP_MINLEN) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000345#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000346 if (verbose)
347 printf("packet too short (%d bytes) from %s\n", cc,
348 inet_ntoa(from->sin_addr));
349#endif
350 return (0);
351 }
352 cc -= hlen;
353 icp = (struct icmp *)(buf + hlen);
354 type = icp->icmp_type; code = icp->icmp_code;
355 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
356 type == ICMP_UNREACH) {
357 struct ip *hip;
358 struct udphdr *up;
359
360 hip = &icp->icmp_ip;
361 hlen = hip->ip_hl << 2;
362 up = (struct udphdr *)((u_char *)hip + hlen);
363 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
364 up->source == htons(ident) &&
365 up->dest == htons(port+seq))
366 return (type == ICMP_TIMXCEED? -1 : code+1);
367 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000368#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000369 if (verbose) {
370 int i;
371 u_long *lp = (u_long *)&icp->icmp_ip;
372
373 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
374 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
375 type, pr_type(type), icp->icmp_code);
376 for (i = 4; i < cc ; i += sizeof(long))
377 printf("%2d: x%8.8lx\n", i, *lp++);
378 }
379#endif
380 return(0);
381}
382
383static void /* not inline */
384send_probe(int seq, int ttl)
385{
386 struct opacket *op = outpacket;
387 struct ip *ip = &op->ip;
388 struct udphdr *up = &op->udp;
389 int i;
390 struct timezone tz;
391
392 ip->ip_off = 0;
393 ip->ip_hl = sizeof(*ip) >> 2;
394 ip->ip_p = IPPROTO_UDP;
395 ip->ip_len = datalen;
396 ip->ip_ttl = ttl;
397 ip->ip_v = IPVERSION;
398 ip->ip_id = htons(ident+seq);
399
400 up->source = htons(ident);
401 up->dest = htons(port+seq);
402 up->len = htons((u_short)(datalen - sizeof(struct ip)));
403 up->check = 0;
404
405 op->seq = seq;
406 op->ttl = ttl;
407 (void) gettimeofday(&op->tv, &tz);
408
409 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
410 sizeof(struct sockaddr));
411 if (i < 0 || i != datalen) {
412 if (i<0)
413 perror("sendto");
414 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
415 datalen, i);
416 (void) fflush(stdout);
417 }
418}
419
420
Eric Andersen5c58d282001-07-10 16:29:00 +0000421int
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000422#ifndef CONFIG_TRACEROUTE
Aaron Lehmann7dd2cec2002-08-23 07:52:58 +0000423main(int argc, char *argv[])
Eric Andersen5c58d282001-07-10 16:29:00 +0000424#else
Aaron Lehmann7dd2cec2002-08-23 07:52:58 +0000425traceroute_main(int argc, char *argv[])
Eric Andersen5c58d282001-07-10 16:29:00 +0000426#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000427{
428 extern char *optarg;
429 extern int optind;
430 struct hostent *hp;
Eric Andersen5c58d282001-07-10 16:29:00 +0000431 struct sockaddr_in from, *to;
432 int ch, i, on, probe, seq, tos, ttl;
433
434 int options = 0; /* socket options */
435 char *source = 0;
436 int nprobes = 3;
437
438 on = 1;
439 seq = tos = 0;
440 to = (struct sockaddr_in *)&whereto;
441 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
442 switch(ch) {
443 case 'd':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000444#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000445 options |= SO_DEBUG;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000446#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000447 break;
448 case 'm':
449 max_ttl = atoi(optarg);
450 if (max_ttl <= 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000451 bb_error_msg_and_die("max ttl must be >1.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000452 break;
453 case 'n':
454 nflag++;
455 break;
456 case 'p':
457 port = atoi(optarg);
458 if (port < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000459 bb_error_msg_and_die("port must be >0.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000460 break;
461 case 'q':
462 nprobes = atoi(optarg);
463 if (nprobes < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000464 bb_error_msg_and_die("nprobes must be >0.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000465 break;
466 case 'r':
467 options |= SO_DONTROUTE;
468 break;
469 case 's':
470 /*
471 * set the ip source address of the outbound
472 * probe (e.g., on a multi-homed host).
473 */
474 source = optarg;
475 break;
476 case 't':
477 tos = atoi(optarg);
478 if (tos < 0 || tos > 255)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000479 bb_error_msg_and_die("tos must be 0 to 255.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000480 break;
481 case 'v':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000482#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000483 verbose++;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000484#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000485 break;
486 case 'w':
487 waittime = atoi(optarg);
488 if (waittime <= 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000489 bb_error_msg_and_die("wait must be >1 sec.");
Eric Andersen5c58d282001-07-10 16:29:00 +0000490 break;
491 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000492 bb_show_usage();
Eric Andersen5c58d282001-07-10 16:29:00 +0000493 }
494 argc -= optind;
495 argv += optind;
496
497 if (argc < 1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000498 bb_show_usage();
Eric Andersen5c58d282001-07-10 16:29:00 +0000499
500 setlinebuf (stdout);
501
Eric Andersen7467c8d2001-07-12 20:26:32 +0000502 memset(&whereto, 0, sizeof(struct sockaddr));
503 hp = xgethostbyname(*argv);
Eric Andersen5c58d282001-07-10 16:29:00 +0000504 to->sin_family = hp->h_addrtype;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000505 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
Eric Andersen5c58d282001-07-10 16:29:00 +0000506 hostname = (char *)hp->h_name;
Eric Andersen5c58d282001-07-10 16:29:00 +0000507 if (*++argv)
508 datalen = atoi(*argv);
509 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000510 bb_error_msg_and_die("packet size must be 0 <= s < %d.",
Eric Andersen5c58d282001-07-10 16:29:00 +0000511 MAXPACKET - sizeof(struct opacket));
512 datalen += sizeof(struct opacket);
513 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000514 memset(outpacket, 0, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000515 outpacket->ip.ip_dst = to->sin_addr;
516 outpacket->ip.ip_tos = tos;
517 outpacket->ip.ip_v = IPVERSION;
518 outpacket->ip.ip_id = 0;
519
520 ident = (getpid() & 0xffff) | 0x8000;
521
Eric Andersen7467c8d2001-07-12 20:26:32 +0000522 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000523 bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000524
525 s = create_icmp_socket();
526
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000527#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000528 if (options & SO_DEBUG)
529 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
530 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000531#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000532 if (options & SO_DONTROUTE)
533 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
534 (char *)&on, sizeof(on));
Eric Andersen5c58d282001-07-10 16:29:00 +0000535#ifdef SO_SNDBUF
536 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
537 sizeof(datalen)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000538 bb_perror_msg_and_die("SO_SNDBUF");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000539#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000540#ifdef IP_HDRINCL
541 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
542 sizeof(on)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000543 bb_perror_msg_and_die("IP_HDRINCL");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000544#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000545#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000546 if (options & SO_DEBUG)
547 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
548 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000549#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000550 if (options & SO_DONTROUTE)
551 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
552 (char *)&on, sizeof(on));
553
554 if (source) {
Eric Andersen7467c8d2001-07-12 20:26:32 +0000555 memset(&from, 0, sizeof(struct sockaddr));
Eric Andersen5c58d282001-07-10 16:29:00 +0000556 from.sin_family = AF_INET;
557 from.sin_addr.s_addr = inet_addr(source);
558 if (from.sin_addr.s_addr == -1)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000559 bb_error_msg_and_die("unknown host %s", source);
Eric Andersen5c58d282001-07-10 16:29:00 +0000560 outpacket->ip.ip_src = from.sin_addr;
561#ifndef IP_HDRINCL
562 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000563 bb_perror_msg_and_die("bind");
Eric Andersenad79c0b2002-06-06 12:24:51 +0000564#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000565 }
566
567 fprintf(stderr, "traceroute to %s (%s)", hostname,
568 inet_ntoa(to->sin_addr));
569 if (source)
570 fprintf(stderr, " from %s", source);
571 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000572
573 for (ttl = 1; ttl <= max_ttl; ++ttl) {
574 u_long lastaddr = 0;
575 int got_there = 0;
576 int unreachable = 0;
577
578 printf("%2d ", ttl);
579 for (probe = 0; probe < nprobes; ++probe) {
580 int cc, reset_timer;
581 struct timeval t1, t2;
582 struct timezone tz;
583 struct ip *ip;
584
585 (void) gettimeofday(&t1, &tz);
586 send_probe(++seq, ttl);
587 reset_timer = 1;
588 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
589 (void) gettimeofday(&t2, &tz);
590 if ((i = packet_ok(packet, cc, &from, seq))) {
591 reset_timer = 1;
592 if (from.sin_addr.s_addr != lastaddr) {
593 print(packet, cc, &from);
594 lastaddr = from.sin_addr.s_addr;
595 }
596 printf(" %g ms", deltaT(&t1, &t2));
597 switch(i - 1) {
598 case ICMP_UNREACH_PORT:
Eric Andersen5c58d282001-07-10 16:29:00 +0000599 ip = (struct ip *)packet;
600 if (ip->ip_ttl <= 1)
601 printf(" !");
Eric Andersen5c58d282001-07-10 16:29:00 +0000602 ++got_there;
603 break;
604 case ICMP_UNREACH_NET:
605 ++unreachable;
606 printf(" !N");
607 break;
608 case ICMP_UNREACH_HOST:
609 ++unreachable;
610 printf(" !H");
611 break;
612 case ICMP_UNREACH_PROTOCOL:
613 ++got_there;
614 printf(" !P");
615 break;
616 case ICMP_UNREACH_NEEDFRAG:
617 ++unreachable;
618 printf(" !F");
619 break;
620 case ICMP_UNREACH_SRCFAIL:
621 ++unreachable;
622 printf(" !S");
623 break;
624 }
625 break;
626 } else
627 reset_timer = 0;
628 }
629 if (cc == 0)
630 printf(" *");
631 (void) fflush(stdout);
632 }
633 putchar('\n');
634 if (got_there || unreachable >= nprobes-1)
Eric Andersencd8c4362001-11-10 11:22:46 +0000635 return 0;
Eric Andersen5c58d282001-07-10 16:29:00 +0000636 }
637
638 return 0;
639}