blob: 5bd3ddb0edfea119b4678ef9c66e5aadf606b5b6 [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 Andersenbdfd0d72001-10-24 05:00:29 +000065#undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
66//#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
67#undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
Eric Andersen7467c8d2001-07-12 20:26:32 +000068
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 Andersencd8c4362001-11-10 11:22:46 +000075#include "inet_common.h"
Eric Andersen5c58d282001-07-10 16:29:00 +000076#include <netdb.h>
77#include <endian.h>
Eric Andersen5c58d282001-07-10 16:29:00 +000078#include <netinet/udp.h>
79#include <netinet/ip.h>
80#include <netinet/ip_icmp.h>
81
Eric Andersenbe0c3602001-08-02 10:55:32 +000082
83 /* It turns out that libc5 doesn't have proper icmp support
84 * built into it header files, so we have to supplement it */
85#if __GNU_LIBRARY__ < 5
86static const int ICMP_MINLEN = 8; /* abs minimum */
87
88struct icmp_ra_addr
89{
90 u_int32_t ira_addr;
91 u_int32_t ira_preference;
92};
93
94
95struct icmp
96{
97 u_int8_t icmp_type; /* type of message, see below */
98 u_int8_t icmp_code; /* type sub code */
99 u_int16_t icmp_cksum; /* ones complement checksum of struct */
100 union
101 {
102 u_char ih_pptr; /* ICMP_PARAMPROB */
103 struct in_addr ih_gwaddr; /* gateway address */
104 struct ih_idseq /* echo datagram */
105 {
106 u_int16_t icd_id;
107 u_int16_t icd_seq;
108 } ih_idseq;
109 u_int32_t ih_void;
110
111 /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
112 struct ih_pmtu
113 {
114 u_int16_t ipm_void;
115 u_int16_t ipm_nextmtu;
116 } ih_pmtu;
117
118 struct ih_rtradv
119 {
120 u_int8_t irt_num_addrs;
121 u_int8_t irt_wpa;
122 u_int16_t irt_lifetime;
123 } ih_rtradv;
124 } icmp_hun;
125#define icmp_pptr icmp_hun.ih_pptr
126#define icmp_gwaddr icmp_hun.ih_gwaddr
127#define icmp_id icmp_hun.ih_idseq.icd_id
128#define icmp_seq icmp_hun.ih_idseq.icd_seq
129#define icmp_void icmp_hun.ih_void
130#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
131#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
132#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
133#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
134#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
135 union
136 {
137 struct
138 {
139 u_int32_t its_otime;
140 u_int32_t its_rtime;
141 u_int32_t its_ttime;
142 } id_ts;
143 struct
144 {
145 struct ip idi_ip;
146 /* options and then 64 bits of data */
147 } id_ip;
148 struct icmp_ra_addr id_radv;
149 u_int32_t id_mask;
150 u_int8_t id_data[1];
151 } icmp_dun;
152#define icmp_otime icmp_dun.id_ts.its_otime
153#define icmp_rtime icmp_dun.id_ts.its_rtime
154#define icmp_ttime icmp_dun.id_ts.its_ttime
155#define icmp_ip icmp_dun.id_ip.idi_ip
156#define icmp_radv icmp_dun.id_radv
157#define icmp_mask icmp_dun.id_mask
158#define icmp_data icmp_dun.id_data
159};
160
161#define ICMP_MINLEN 8 /* abs minimum */
162#define ICMP_UNREACH 3 /* dest unreachable, codes: */
163#define ICMP_TIMXCEED 11 /* time exceeded, code: */
164#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
165#define ICMP_UNREACH_NET 0 /* bad net */
166#define ICMP_UNREACH_HOST 1 /* bad host */
167#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
168#define ICMP_UNREACH_PORT 3 /* bad port */
169#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
170#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
171#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000172
Eric Andersenaf6b40a2001-07-31 22:53:36 +0000173
Eric Andersen5c58d282001-07-10 16:29:00 +0000174#define MAXPACKET 65535 /* max ip packet size */
175#ifndef MAXHOSTNAMELEN
176#define MAXHOSTNAMELEN 64
177#endif
178
179/*
180 * format of a (udp) probe packet.
181 */
182struct opacket {
183 struct ip ip;
184 struct udphdr udp;
185 u_char seq; /* sequence number of this packet */
186 u_char ttl; /* ttl packet left with */
187 struct timeval tv; /* time packet left */
188};
189
190/*
191 * Definitions for internet protocol version 4.
192 * Per RFC 791, September 1981.
193 */
194#define IPVERSION 4
195
196
197#include "busybox.h"
198
Eric Andersen5c58d282001-07-10 16:29:00 +0000199static u_char packet[512]; /* last inbound (icmp) packet */
200static struct opacket *outpacket; /* last output (udp) packet */
201
202static int s; /* receive (icmp) socket file descriptor */
203static int sndsock; /* send (udp) socket file descriptor */
204
205static struct sockaddr whereto; /* Who to try to reach */
206static int datalen; /* How much data */
207
208static char *hostname;
209
210static int max_ttl = 30;
211static u_short ident;
212static u_short port = 32768+666; /* start udp dest port # for probe packets */
213
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000214#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000215static int verbose;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000216#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000217static int waittime = 5; /* time to wait for response (in seconds) */
218static int nflag; /* print addresses numerically */
219
Eric Andersen7467c8d2001-07-12 20:26:32 +0000220/*
221 * Construct an Internet address representation.
222 * If the nflag has been supplied, give
223 * numeric value, otherwise try for symbolic name.
224 */
Eric Andersen044228d2001-07-17 01:12:36 +0000225static inline void
226inetname(struct sockaddr_in *from)
Eric Andersen7467c8d2001-07-12 20:26:32 +0000227{
228 char *cp;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000229 static char domain[MAXHOSTNAMELEN + 1];
Eric Andersencd8c4362001-11-10 11:22:46 +0000230 char name[MAXHOSTNAMELEN + 1];
Eric Andersen7467c8d2001-07-12 20:26:32 +0000231 static int first = 1;
Eric Andersen044228d2001-07-17 01:12:36 +0000232 const char *ina;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000233
234 if (first && !nflag) {
235 first = 0;
236 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
Eric Andersen044228d2001-07-17 01:12:36 +0000237 (cp = strchr(domain, '.')))
Eric Andersen7467c8d2001-07-12 20:26:32 +0000238 (void) strcpy(domain, cp + 1);
239 else
240 domain[0] = 0;
241 }
242 cp = 0;
Eric Andersen044228d2001-07-17 01:12:36 +0000243 if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
Eric Andersencd8c4362001-11-10 11:22:46 +0000244 if(INET_rresolve(name, sizeof(name), from, 0, 0xffffffff) >= 0) {
245 if ((cp = strchr(name, '.')) &&
Eric Andersen7467c8d2001-07-12 20:26:32 +0000246 !strcmp(cp + 1, domain))
247 *cp = 0;
Eric Andersencd8c4362001-11-10 11:22:46 +0000248 cp = (char *)name;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000249 }
250 }
Eric Andersen044228d2001-07-17 01:12:36 +0000251 ina = inet_ntoa(from->sin_addr);
252 if (nflag)
253 printf(" %s", ina);
254 else
255 printf(" %s (%s)", (cp ? cp : ina), ina);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000256}
257
258static inline void
259print(u_char *buf, int cc, struct sockaddr_in *from)
260{
261 struct ip *ip;
262 int hlen;
263
264 ip = (struct ip *) buf;
265 hlen = ip->ip_hl << 2;
266 cc -= hlen;
267
Eric Andersen044228d2001-07-17 01:12:36 +0000268 inetname(from);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000269#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000270 if (verbose)
271 printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
272#endif
273}
274
275static inline double
276deltaT(struct timeval *t1p, struct timeval *t2p)
277{
278 double dt;
279
280 dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
281 (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
282 return (dt);
283}
284
285static inline int
286wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
287{
288 fd_set fds;
289 static struct timeval wait;
290 int cc = 0;
291 int fromlen = sizeof (*from);
292
293 FD_ZERO(&fds);
294 FD_SET(sock, &fds);
295 if (reset_timer) {
296 /*
297 * traceroute could hang if someone else has a ping
298 * running and our ICMP reply gets dropped but we don't
299 * realize it because we keep waking up to handle those
300 * other ICMP packets that keep coming in. To fix this,
301 * "reset_timer" will only be true if the last packet that
302 * came in was for us or if this is the first time we're
303 * waiting for a reply since sending out a probe. Note
304 * that this takes advantage of the select() feature on
305 * Linux where the remaining timeout is written to the
306 * struct timeval area.
307 */
308 wait.tv_sec = waittime;
309 wait.tv_usec = 0;
310 }
311
312 if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
313 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
314 (struct sockaddr *)from, &fromlen);
315
316 return(cc);
317}
318
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000319#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000320/*
321 * Convert an ICMP "type" field to a printable string.
322 */
323static inline const char *
324pr_type(t)
325 u_char t;
326{
327 static const char * const ttab[] = {
328 "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
329 "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
330 "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
331 "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
332 "Info Reply"
333 };
334
335 if(t > 16)
336 return("OUT-OF-RANGE");
337
338 return(ttab[t]);
339}
340#endif
341
342static inline int
343packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
344{
345 struct icmp *icp;
346 u_char type, code;
347 int hlen;
348 struct ip *ip;
349
350 ip = (struct ip *) buf;
351 hlen = ip->ip_hl << 2;
352 if (cc < hlen + ICMP_MINLEN) {
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000353#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000354 if (verbose)
355 printf("packet too short (%d bytes) from %s\n", cc,
356 inet_ntoa(from->sin_addr));
357#endif
358 return (0);
359 }
360 cc -= hlen;
361 icp = (struct icmp *)(buf + hlen);
362 type = icp->icmp_type; code = icp->icmp_code;
363 if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
364 type == ICMP_UNREACH) {
365 struct ip *hip;
366 struct udphdr *up;
367
368 hip = &icp->icmp_ip;
369 hlen = hip->ip_hl << 2;
370 up = (struct udphdr *)((u_char *)hip + hlen);
371 if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
372 up->source == htons(ident) &&
373 up->dest == htons(port+seq))
374 return (type == ICMP_TIMXCEED? -1 : code+1);
375 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000376#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen7467c8d2001-07-12 20:26:32 +0000377 if (verbose) {
378 int i;
379 u_long *lp = (u_long *)&icp->icmp_ip;
380
381 printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
382 cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
383 type, pr_type(type), icp->icmp_code);
384 for (i = 4; i < cc ; i += sizeof(long))
385 printf("%2d: x%8.8lx\n", i, *lp++);
386 }
387#endif
388 return(0);
389}
390
391static void /* not inline */
392send_probe(int seq, int ttl)
393{
394 struct opacket *op = outpacket;
395 struct ip *ip = &op->ip;
396 struct udphdr *up = &op->udp;
397 int i;
398 struct timezone tz;
399
400 ip->ip_off = 0;
401 ip->ip_hl = sizeof(*ip) >> 2;
402 ip->ip_p = IPPROTO_UDP;
403 ip->ip_len = datalen;
404 ip->ip_ttl = ttl;
405 ip->ip_v = IPVERSION;
406 ip->ip_id = htons(ident+seq);
407
408 up->source = htons(ident);
409 up->dest = htons(port+seq);
410 up->len = htons((u_short)(datalen - sizeof(struct ip)));
411 up->check = 0;
412
413 op->seq = seq;
414 op->ttl = ttl;
415 (void) gettimeofday(&op->tv, &tz);
416
417 i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
418 sizeof(struct sockaddr));
419 if (i < 0 || i != datalen) {
420 if (i<0)
421 perror("sendto");
422 printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
423 datalen, i);
424 (void) fflush(stdout);
425 }
426}
427
428
Eric Andersen5c58d282001-07-10 16:29:00 +0000429int
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000430#ifndef CONFIG_TRACEROUTE
Eric Andersen5c58d282001-07-10 16:29:00 +0000431main(argc, argv)
432#else
433traceroute_main(argc, argv)
434#endif
435 int argc;
436 char *argv[];
437{
438 extern char *optarg;
439 extern int optind;
440 struct hostent *hp;
Eric Andersen5c58d282001-07-10 16:29:00 +0000441 struct sockaddr_in from, *to;
442 int ch, i, on, probe, seq, tos, ttl;
443
444 int options = 0; /* socket options */
445 char *source = 0;
446 int nprobes = 3;
447
448 on = 1;
449 seq = tos = 0;
450 to = (struct sockaddr_in *)&whereto;
451 while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
452 switch(ch) {
453 case 'd':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000454#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000455 options |= SO_DEBUG;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000456#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000457 break;
458 case 'm':
459 max_ttl = atoi(optarg);
460 if (max_ttl <= 1)
461 error_msg_and_die("max ttl must be >1.");
462 break;
463 case 'n':
464 nflag++;
465 break;
466 case 'p':
467 port = atoi(optarg);
468 if (port < 1)
469 error_msg_and_die("port must be >0.");
470 break;
471 case 'q':
472 nprobes = atoi(optarg);
473 if (nprobes < 1)
474 error_msg_and_die("nprobes must be >0.");
475 break;
476 case 'r':
477 options |= SO_DONTROUTE;
478 break;
479 case 's':
480 /*
481 * set the ip source address of the outbound
482 * probe (e.g., on a multi-homed host).
483 */
484 source = optarg;
485 break;
486 case 't':
487 tos = atoi(optarg);
488 if (tos < 0 || tos > 255)
489 error_msg_and_die("tos must be 0 to 255.");
490 break;
491 case 'v':
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000492#ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
Eric Andersen5c58d282001-07-10 16:29:00 +0000493 verbose++;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000494#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000495 break;
496 case 'w':
497 waittime = atoi(optarg);
498 if (waittime <= 1)
499 error_msg_and_die("wait must be >1 sec.");
500 break;
501 default:
502 show_usage();
503 }
504 argc -= optind;
505 argv += optind;
506
507 if (argc < 1)
508 show_usage();
509
510 setlinebuf (stdout);
511
Eric Andersen7467c8d2001-07-12 20:26:32 +0000512 memset(&whereto, 0, sizeof(struct sockaddr));
513 hp = xgethostbyname(*argv);
Eric Andersen5c58d282001-07-10 16:29:00 +0000514 to->sin_family = hp->h_addrtype;
Eric Andersen7467c8d2001-07-12 20:26:32 +0000515 memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
Eric Andersen5c58d282001-07-10 16:29:00 +0000516 hostname = (char *)hp->h_name;
Eric Andersen5c58d282001-07-10 16:29:00 +0000517 if (*++argv)
518 datalen = atoi(*argv);
519 if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
520 error_msg_and_die("packet size must be 0 <= s < %d.",
521 MAXPACKET - sizeof(struct opacket));
522 datalen += sizeof(struct opacket);
523 outpacket = (struct opacket *)xmalloc((unsigned)datalen);
Eric Andersen7467c8d2001-07-12 20:26:32 +0000524 memset(outpacket, 0, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000525 outpacket->ip.ip_dst = to->sin_addr;
526 outpacket->ip.ip_tos = tos;
527 outpacket->ip.ip_v = IPVERSION;
528 outpacket->ip.ip_id = 0;
529
530 ident = (getpid() & 0xffff) | 0x8000;
531
Eric Andersen7467c8d2001-07-12 20:26:32 +0000532 if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
533 perror_msg_and_die(can_not_create_raw_socket);
534
535 s = create_icmp_socket();
536
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000537#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000538 if (options & SO_DEBUG)
539 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
540 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000541#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000542 if (options & SO_DONTROUTE)
543 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
544 (char *)&on, sizeof(on));
Eric Andersen5c58d282001-07-10 16:29:00 +0000545#ifdef SO_SNDBUF
546 if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
547 sizeof(datalen)) < 0)
548 perror_msg_and_die("SO_SNDBUF");
549#endif SO_SNDBUF
550#ifdef IP_HDRINCL
551 if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
552 sizeof(on)) < 0)
553 perror_msg_and_die("IP_HDRINCL");
554#endif IP_HDRINCL
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000555#ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
Eric Andersen5c58d282001-07-10 16:29:00 +0000556 if (options & SO_DEBUG)
557 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
558 (char *)&on, sizeof(on));
Eric Andersen7467c8d2001-07-12 20:26:32 +0000559#endif
Eric Andersen5c58d282001-07-10 16:29:00 +0000560 if (options & SO_DONTROUTE)
561 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
562 (char *)&on, sizeof(on));
563
564 if (source) {
Eric Andersen7467c8d2001-07-12 20:26:32 +0000565 memset(&from, 0, sizeof(struct sockaddr));
Eric Andersen5c58d282001-07-10 16:29:00 +0000566 from.sin_family = AF_INET;
567 from.sin_addr.s_addr = inet_addr(source);
568 if (from.sin_addr.s_addr == -1)
569 error_msg_and_die("unknown host %s", source);
570 outpacket->ip.ip_src = from.sin_addr;
571#ifndef IP_HDRINCL
572 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
573 perror_msg_and_die("bind");
574#endif IP_HDRINCL
575 }
576
577 fprintf(stderr, "traceroute to %s (%s)", hostname,
578 inet_ntoa(to->sin_addr));
579 if (source)
580 fprintf(stderr, " from %s", source);
581 fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
Eric Andersen5c58d282001-07-10 16:29:00 +0000582
583 for (ttl = 1; ttl <= max_ttl; ++ttl) {
584 u_long lastaddr = 0;
585 int got_there = 0;
586 int unreachable = 0;
587
588 printf("%2d ", ttl);
589 for (probe = 0; probe < nprobes; ++probe) {
590 int cc, reset_timer;
591 struct timeval t1, t2;
592 struct timezone tz;
593 struct ip *ip;
594
595 (void) gettimeofday(&t1, &tz);
596 send_probe(++seq, ttl);
597 reset_timer = 1;
598 while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
599 (void) gettimeofday(&t2, &tz);
600 if ((i = packet_ok(packet, cc, &from, seq))) {
601 reset_timer = 1;
602 if (from.sin_addr.s_addr != lastaddr) {
603 print(packet, cc, &from);
604 lastaddr = from.sin_addr.s_addr;
605 }
606 printf(" %g ms", deltaT(&t1, &t2));
607 switch(i - 1) {
608 case ICMP_UNREACH_PORT:
Eric Andersen5c58d282001-07-10 16:29:00 +0000609 ip = (struct ip *)packet;
610 if (ip->ip_ttl <= 1)
611 printf(" !");
Eric Andersen5c58d282001-07-10 16:29:00 +0000612 ++got_there;
613 break;
614 case ICMP_UNREACH_NET:
615 ++unreachable;
616 printf(" !N");
617 break;
618 case ICMP_UNREACH_HOST:
619 ++unreachable;
620 printf(" !H");
621 break;
622 case ICMP_UNREACH_PROTOCOL:
623 ++got_there;
624 printf(" !P");
625 break;
626 case ICMP_UNREACH_NEEDFRAG:
627 ++unreachable;
628 printf(" !F");
629 break;
630 case ICMP_UNREACH_SRCFAIL:
631 ++unreachable;
632 printf(" !S");
633 break;
634 }
635 break;
636 } else
637 reset_timer = 0;
638 }
639 if (cc == 0)
640 printf(" *");
641 (void) fflush(stdout);
642 }
643 putchar('\n');
644 if (got_there || unreachable >= nprobes-1)
Eric Andersencd8c4362001-11-10 11:22:46 +0000645 return 0;
Eric Andersen5c58d282001-07-10 16:29:00 +0000646 }
647
648 return 0;
649}