diff options
author | Eric Andersen <andersen@codepoet.org> | 2001-07-12 20:26:32 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2001-07-12 20:26:32 +0000 |
commit | 7467c8d3b6a50e2cbd8db750963d40b420ad38d1 (patch) | |
tree | 10dcece1e0bb88e35aa95c3a68896ad426e43f7a /networking/traceroute.c | |
parent | f69bfc76fa7acb0c87fa3f3b319fde361a8315a8 (diff) | |
download | busybox-w32-7467c8d3b6a50e2cbd8db750963d40b420ad38d1.tar.gz busybox-w32-7467c8d3b6a50e2cbd8db750963d40b420ad38d1.tar.bz2 busybox-w32-7467c8d3b6a50e2cbd8db750963d40b420ad38d1.zip |
Patch from vodz:
Changed email address
cmdedit API change
optimizations for traceroute and md5sum
added a new shared create_icmp_socket() function
Diffstat (limited to 'networking/traceroute.c')
-rw-r--r-- | networking/traceroute.c | 511 |
1 files changed, 242 insertions, 269 deletions
diff --git a/networking/traceroute.c b/networking/traceroute.c index a02be8a9e..106cf043b 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * This code is derived from software contributed to Berkeley by | 5 | * This code is derived from software contributed to Berkeley by |
6 | * Van Jacobson. | 6 | * Van Jacobson. |
7 | * | 7 | * |
8 | * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001 | ||
8 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions |
10 | * are met: | 11 | * are met: |
@@ -61,6 +62,10 @@ | |||
61 | * Tue Dec 20 03:50:13 PST 1988 | 62 | * Tue Dec 20 03:50:13 PST 1988 |
62 | */ | 63 | */ |
63 | 64 | ||
65 | #undef BB_FEATURE_TRACEROUTE_VERBOSE | ||
66 | //#define BB_FEATURE_TRACEROUTE_VERBOSE | ||
67 | #undef BB_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */ | ||
68 | |||
64 | #include <stdio.h> | 69 | #include <stdio.h> |
65 | #include <errno.h> | 70 | #include <errno.h> |
66 | #include <stdlib.h> | 71 | #include <stdlib.h> |
@@ -100,13 +105,6 @@ struct opacket { | |||
100 | 105 | ||
101 | #include "busybox.h" | 106 | #include "busybox.h" |
102 | 107 | ||
103 | static int wait_for_reply (int, struct sockaddr_in *, int); | ||
104 | static void send_probe (int, int); | ||
105 | static double deltaT (struct timeval *, struct timeval *); | ||
106 | static int packet_ok (u_char *, int, struct sockaddr_in *, int); | ||
107 | static void print (u_char *, int, struct sockaddr_in *); | ||
108 | static char *inetname (struct in_addr); | ||
109 | |||
110 | static u_char packet[512]; /* last inbound (icmp) packet */ | 108 | static u_char packet[512]; /* last inbound (icmp) packet */ |
111 | static struct opacket *outpacket; /* last output (udp) packet */ | 109 | static struct opacket *outpacket; /* last output (udp) packet */ |
112 | 110 | ||
@@ -122,10 +120,229 @@ static int max_ttl = 30; | |||
122 | static u_short ident; | 120 | static u_short ident; |
123 | static u_short port = 32768+666; /* start udp dest port # for probe packets */ | 121 | static u_short port = 32768+666; /* start udp dest port # for probe packets */ |
124 | 122 | ||
123 | #ifdef BB_FEATURE_TRACEROUTE_VERBOSE | ||
125 | static int verbose; | 124 | static int verbose; |
125 | #endif | ||
126 | static int waittime = 5; /* time to wait for response (in seconds) */ | 126 | static int waittime = 5; /* time to wait for response (in seconds) */ |
127 | static int nflag; /* print addresses numerically */ | 127 | static int nflag; /* print addresses numerically */ |
128 | 128 | ||
129 | /* | ||
130 | * Construct an Internet address representation. | ||
131 | * If the nflag has been supplied, give | ||
132 | * numeric value, otherwise try for symbolic name. | ||
133 | */ | ||
134 | static inline char * | ||
135 | inetname(struct in_addr in) | ||
136 | { | ||
137 | char *cp; | ||
138 | static char line[50]; | ||
139 | struct hostent *hp; | ||
140 | static char domain[MAXHOSTNAMELEN + 1]; | ||
141 | static int first = 1; | ||
142 | |||
143 | if (first && !nflag) { | ||
144 | first = 0; | ||
145 | if (gethostname(domain, MAXHOSTNAMELEN) == 0 && | ||
146 | (cp = index(domain, '.'))) | ||
147 | (void) strcpy(domain, cp + 1); | ||
148 | else | ||
149 | domain[0] = 0; | ||
150 | } | ||
151 | cp = 0; | ||
152 | if (!nflag && in.s_addr != INADDR_ANY) { | ||
153 | hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); | ||
154 | if (hp) { | ||
155 | if ((cp = index(hp->h_name, '.')) && | ||
156 | !strcmp(cp + 1, domain)) | ||
157 | *cp = 0; | ||
158 | cp = (char *)hp->h_name; | ||
159 | } | ||
160 | } | ||
161 | if (cp) | ||
162 | (void) strcpy(line, cp); | ||
163 | else { | ||
164 | in.s_addr = ntohl(in.s_addr); | ||
165 | strcpy(line, inet_ntoa(in)); | ||
166 | } | ||
167 | return (line); | ||
168 | } | ||
169 | |||
170 | static inline void | ||
171 | print(u_char *buf, int cc, struct sockaddr_in *from) | ||
172 | { | ||
173 | struct ip *ip; | ||
174 | int hlen; | ||
175 | |||
176 | ip = (struct ip *) buf; | ||
177 | hlen = ip->ip_hl << 2; | ||
178 | cc -= hlen; | ||
179 | |||
180 | if (nflag) | ||
181 | printf(" %s", inet_ntoa(from->sin_addr)); | ||
182 | else | ||
183 | printf(" %s (%s)", inetname(from->sin_addr), | ||
184 | inet_ntoa(from->sin_addr)); | ||
185 | |||
186 | #ifdef BB_FEATURE_TRACEROUTE_VERBOSE | ||
187 | if (verbose) | ||
188 | printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); | ||
189 | #endif | ||
190 | } | ||
191 | |||
192 | static inline double | ||
193 | deltaT(struct timeval *t1p, struct timeval *t2p) | ||
194 | { | ||
195 | double dt; | ||
196 | |||
197 | dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + | ||
198 | (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; | ||
199 | return (dt); | ||
200 | } | ||
201 | |||
202 | static inline int | ||
203 | wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer) | ||
204 | { | ||
205 | fd_set fds; | ||
206 | static struct timeval wait; | ||
207 | int cc = 0; | ||
208 | int fromlen = sizeof (*from); | ||
209 | |||
210 | FD_ZERO(&fds); | ||
211 | FD_SET(sock, &fds); | ||
212 | if (reset_timer) { | ||
213 | /* | ||
214 | * traceroute could hang if someone else has a ping | ||
215 | * running and our ICMP reply gets dropped but we don't | ||
216 | * realize it because we keep waking up to handle those | ||
217 | * other ICMP packets that keep coming in. To fix this, | ||
218 | * "reset_timer" will only be true if the last packet that | ||
219 | * came in was for us or if this is the first time we're | ||
220 | * waiting for a reply since sending out a probe. Note | ||
221 | * that this takes advantage of the select() feature on | ||
222 | * Linux where the remaining timeout is written to the | ||
223 | * struct timeval area. | ||
224 | */ | ||
225 | wait.tv_sec = waittime; | ||
226 | wait.tv_usec = 0; | ||
227 | } | ||
228 | |||
229 | if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) | ||
230 | cc=recvfrom(s, (char *)packet, sizeof(packet), 0, | ||
231 | (struct sockaddr *)from, &fromlen); | ||
232 | |||
233 | return(cc); | ||
234 | } | ||
235 | |||
236 | #ifdef BB_FEATURE_TRACEROUTE_VERBOSE | ||
237 | /* | ||
238 | * Convert an ICMP "type" field to a printable string. | ||
239 | */ | ||
240 | static inline const char * | ||
241 | pr_type(t) | ||
242 | u_char t; | ||
243 | { | ||
244 | static const char * const ttab[] = { | ||
245 | "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", | ||
246 | "Source Quench", "Redirect", "ICMP 6", "ICMP 7", | ||
247 | "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", | ||
248 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", | ||
249 | "Info Reply" | ||
250 | }; | ||
251 | |||
252 | if(t > 16) | ||
253 | return("OUT-OF-RANGE"); | ||
254 | |||
255 | return(ttab[t]); | ||
256 | } | ||
257 | #endif | ||
258 | |||
259 | static inline int | ||
260 | packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq) | ||
261 | { | ||
262 | struct icmp *icp; | ||
263 | u_char type, code; | ||
264 | int hlen; | ||
265 | struct ip *ip; | ||
266 | |||
267 | ip = (struct ip *) buf; | ||
268 | hlen = ip->ip_hl << 2; | ||
269 | if (cc < hlen + ICMP_MINLEN) { | ||
270 | #ifdef BB_FEATURE_TRACEROUTE_VERBOSE | ||
271 | if (verbose) | ||
272 | printf("packet too short (%d bytes) from %s\n", cc, | ||
273 | inet_ntoa(from->sin_addr)); | ||
274 | #endif | ||
275 | return (0); | ||
276 | } | ||
277 | cc -= hlen; | ||
278 | icp = (struct icmp *)(buf + hlen); | ||
279 | type = icp->icmp_type; code = icp->icmp_code; | ||
280 | if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || | ||
281 | type == ICMP_UNREACH) { | ||
282 | struct ip *hip; | ||
283 | struct udphdr *up; | ||
284 | |||
285 | hip = &icp->icmp_ip; | ||
286 | hlen = hip->ip_hl << 2; | ||
287 | up = (struct udphdr *)((u_char *)hip + hlen); | ||
288 | if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && | ||
289 | up->source == htons(ident) && | ||
290 | up->dest == htons(port+seq)) | ||
291 | return (type == ICMP_TIMXCEED? -1 : code+1); | ||
292 | } | ||
293 | #ifdef BB_FEATURE_TRACEROUTE_VERBOSE | ||
294 | if (verbose) { | ||
295 | int i; | ||
296 | u_long *lp = (u_long *)&icp->icmp_ip; | ||
297 | |||
298 | printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n", | ||
299 | cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst), | ||
300 | type, pr_type(type), icp->icmp_code); | ||
301 | for (i = 4; i < cc ; i += sizeof(long)) | ||
302 | printf("%2d: x%8.8lx\n", i, *lp++); | ||
303 | } | ||
304 | #endif | ||
305 | return(0); | ||
306 | } | ||
307 | |||
308 | static void /* not inline */ | ||
309 | send_probe(int seq, int ttl) | ||
310 | { | ||
311 | struct opacket *op = outpacket; | ||
312 | struct ip *ip = &op->ip; | ||
313 | struct udphdr *up = &op->udp; | ||
314 | int i; | ||
315 | struct timezone tz; | ||
316 | |||
317 | ip->ip_off = 0; | ||
318 | ip->ip_hl = sizeof(*ip) >> 2; | ||
319 | ip->ip_p = IPPROTO_UDP; | ||
320 | ip->ip_len = datalen; | ||
321 | ip->ip_ttl = ttl; | ||
322 | ip->ip_v = IPVERSION; | ||
323 | ip->ip_id = htons(ident+seq); | ||
324 | |||
325 | up->source = htons(ident); | ||
326 | up->dest = htons(port+seq); | ||
327 | up->len = htons((u_short)(datalen - sizeof(struct ip))); | ||
328 | up->check = 0; | ||
329 | |||
330 | op->seq = seq; | ||
331 | op->ttl = ttl; | ||
332 | (void) gettimeofday(&op->tv, &tz); | ||
333 | |||
334 | i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, | ||
335 | sizeof(struct sockaddr)); | ||
336 | if (i < 0 || i != datalen) { | ||
337 | if (i<0) | ||
338 | perror("sendto"); | ||
339 | printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, | ||
340 | datalen, i); | ||
341 | (void) fflush(stdout); | ||
342 | } | ||
343 | } | ||
344 | |||
345 | |||
129 | int | 346 | int |
130 | #ifndef BB_TRACEROUTE | 347 | #ifndef BB_TRACEROUTE |
131 | main(argc, argv) | 348 | main(argc, argv) |
@@ -138,7 +355,6 @@ traceroute_main(argc, argv) | |||
138 | extern char *optarg; | 355 | extern char *optarg; |
139 | extern int optind; | 356 | extern int optind; |
140 | struct hostent *hp; | 357 | struct hostent *hp; |
141 | struct protoent *pe; | ||
142 | struct sockaddr_in from, *to; | 358 | struct sockaddr_in from, *to; |
143 | int ch, i, on, probe, seq, tos, ttl; | 359 | int ch, i, on, probe, seq, tos, ttl; |
144 | 360 | ||
@@ -152,7 +368,9 @@ traceroute_main(argc, argv) | |||
152 | while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) | 368 | while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF) |
153 | switch(ch) { | 369 | switch(ch) { |
154 | case 'd': | 370 | case 'd': |
371 | #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG | ||
155 | options |= SO_DEBUG; | 372 | options |= SO_DEBUG; |
373 | #endif | ||
156 | break; | 374 | break; |
157 | case 'm': | 375 | case 'm': |
158 | max_ttl = atoi(optarg); | 376 | max_ttl = atoi(optarg); |
@@ -188,7 +406,9 @@ traceroute_main(argc, argv) | |||
188 | error_msg_and_die("tos must be 0 to 255."); | 406 | error_msg_and_die("tos must be 0 to 255."); |
189 | break; | 407 | break; |
190 | case 'v': | 408 | case 'v': |
409 | #ifdef BB_FEATURE_TRACEROUTE_VERBOSE | ||
191 | verbose++; | 410 | verbose++; |
411 | #endif | ||
192 | break; | 412 | break; |
193 | case 'w': | 413 | case 'w': |
194 | waittime = atoi(optarg); | 414 | waittime = atoi(optarg); |
@@ -206,21 +426,11 @@ traceroute_main(argc, argv) | |||
206 | 426 | ||
207 | setlinebuf (stdout); | 427 | setlinebuf (stdout); |
208 | 428 | ||
209 | (void) bzero((char *)&whereto, sizeof(struct sockaddr)); | 429 | memset(&whereto, 0, sizeof(struct sockaddr)); |
210 | to->sin_family = AF_INET; | 430 | hp = xgethostbyname(*argv); |
211 | to->sin_addr.s_addr = inet_addr(*argv); | ||
212 | if (to->sin_addr.s_addr != -1) | ||
213 | hostname = *argv; | ||
214 | else { | ||
215 | hp = gethostbyname(*argv); | ||
216 | if (hp) { | ||
217 | to->sin_family = hp->h_addrtype; | 431 | to->sin_family = hp->h_addrtype; |
218 | bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); | 432 | memcpy(&to->sin_addr, hp->h_addr, hp->h_length); |
219 | hostname = (char *)hp->h_name; | 433 | hostname = (char *)hp->h_name; |
220 | } else { | ||
221 | error_msg_and_die("unknown host %s", *argv); | ||
222 | } | ||
223 | } | ||
224 | if (*++argv) | 434 | if (*++argv) |
225 | datalen = atoi(*argv); | 435 | datalen = atoi(*argv); |
226 | if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) | 436 | if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) |
@@ -228,7 +438,7 @@ traceroute_main(argc, argv) | |||
228 | MAXPACKET - sizeof(struct opacket)); | 438 | MAXPACKET - sizeof(struct opacket)); |
229 | datalen += sizeof(struct opacket); | 439 | datalen += sizeof(struct opacket); |
230 | outpacket = (struct opacket *)xmalloc((unsigned)datalen); | 440 | outpacket = (struct opacket *)xmalloc((unsigned)datalen); |
231 | (void) bzero((char *)outpacket, datalen); | 441 | memset(outpacket, 0, datalen); |
232 | outpacket->ip.ip_dst = to->sin_addr; | 442 | outpacket->ip.ip_dst = to->sin_addr; |
233 | outpacket->ip.ip_tos = tos; | 443 | outpacket->ip.ip_tos = tos; |
234 | outpacket->ip.ip_v = IPVERSION; | 444 | outpacket->ip.ip_v = IPVERSION; |
@@ -236,19 +446,19 @@ traceroute_main(argc, argv) | |||
236 | 446 | ||
237 | ident = (getpid() & 0xffff) | 0x8000; | 447 | ident = (getpid() & 0xffff) | 0x8000; |
238 | 448 | ||
239 | if ((pe = getprotobyname("icmp")) == NULL) | 449 | if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) |
240 | error_msg_and_die("icmp: unknown protocol"); | 450 | perror_msg_and_die(can_not_create_raw_socket); |
241 | if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) | 451 | |
242 | perror_msg_and_die("icmp socket"); | 452 | s = create_icmp_socket(); |
453 | |||
454 | #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG | ||
243 | if (options & SO_DEBUG) | 455 | if (options & SO_DEBUG) |
244 | (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, | 456 | (void) setsockopt(s, SOL_SOCKET, SO_DEBUG, |
245 | (char *)&on, sizeof(on)); | 457 | (char *)&on, sizeof(on)); |
458 | #endif | ||
246 | if (options & SO_DONTROUTE) | 459 | if (options & SO_DONTROUTE) |
247 | (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, | 460 | (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, |
248 | (char *)&on, sizeof(on)); | 461 | (char *)&on, sizeof(on)); |
249 | |||
250 | if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) | ||
251 | perror_msg_and_die("raw socket"); | ||
252 | #ifdef SO_SNDBUF | 462 | #ifdef SO_SNDBUF |
253 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, | 463 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen, |
254 | sizeof(datalen)) < 0) | 464 | sizeof(datalen)) < 0) |
@@ -259,15 +469,17 @@ traceroute_main(argc, argv) | |||
259 | sizeof(on)) < 0) | 469 | sizeof(on)) < 0) |
260 | perror_msg_and_die("IP_HDRINCL"); | 470 | perror_msg_and_die("IP_HDRINCL"); |
261 | #endif IP_HDRINCL | 471 | #endif IP_HDRINCL |
472 | #ifdef BB_FEATURE_TRACEROUTE_SO_DEBUG | ||
262 | if (options & SO_DEBUG) | 473 | if (options & SO_DEBUG) |
263 | (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, | 474 | (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, |
264 | (char *)&on, sizeof(on)); | 475 | (char *)&on, sizeof(on)); |
476 | #endif | ||
265 | if (options & SO_DONTROUTE) | 477 | if (options & SO_DONTROUTE) |
266 | (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, | 478 | (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, |
267 | (char *)&on, sizeof(on)); | 479 | (char *)&on, sizeof(on)); |
268 | 480 | ||
269 | if (source) { | 481 | if (source) { |
270 | (void) bzero((char *)&from, sizeof(struct sockaddr)); | 482 | memset(&from, 0, sizeof(struct sockaddr)); |
271 | from.sin_family = AF_INET; | 483 | from.sin_family = AF_INET; |
272 | from.sin_addr.s_addr = inet_addr(source); | 484 | from.sin_addr.s_addr = inet_addr(source); |
273 | if (from.sin_addr.s_addr == -1) | 485 | if (from.sin_addr.s_addr == -1) |
@@ -284,7 +496,6 @@ traceroute_main(argc, argv) | |||
284 | if (source) | 496 | if (source) |
285 | fprintf(stderr, " from %s", source); | 497 | fprintf(stderr, " from %s", source); |
286 | fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); | 498 | fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen); |
287 | (void) fflush(stderr); | ||
288 | 499 | ||
289 | for (ttl = 1; ttl <= max_ttl; ++ttl) { | 500 | for (ttl = 1; ttl <= max_ttl; ++ttl) { |
290 | u_long lastaddr = 0; | 501 | u_long lastaddr = 0; |
@@ -312,11 +523,9 @@ traceroute_main(argc, argv) | |||
312 | printf(" %g ms", deltaT(&t1, &t2)); | 523 | printf(" %g ms", deltaT(&t1, &t2)); |
313 | switch(i - 1) { | 524 | switch(i - 1) { |
314 | case ICMP_UNREACH_PORT: | 525 | case ICMP_UNREACH_PORT: |
315 | #ifndef ARCHAIC | ||
316 | ip = (struct ip *)packet; | 526 | ip = (struct ip *)packet; |
317 | if (ip->ip_ttl <= 1) | 527 | if (ip->ip_ttl <= 1) |
318 | printf(" !"); | 528 | printf(" !"); |
319 | #endif ARCHAIC | ||
320 | ++got_there; | 529 | ++got_there; |
321 | break; | 530 | break; |
322 | case ICMP_UNREACH_NET: | 531 | case ICMP_UNREACH_NET: |
@@ -355,239 +564,3 @@ traceroute_main(argc, argv) | |||
355 | 564 | ||
356 | return 0; | 565 | return 0; |
357 | } | 566 | } |
358 | |||
359 | static int | ||
360 | wait_for_reply(sock, from, reset_timer) | ||
361 | int sock; | ||
362 | struct sockaddr_in *from; | ||
363 | int reset_timer; | ||
364 | { | ||
365 | fd_set fds; | ||
366 | static struct timeval wait; | ||
367 | int cc = 0; | ||
368 | int fromlen = sizeof (*from); | ||
369 | |||
370 | FD_ZERO(&fds); | ||
371 | FD_SET(sock, &fds); | ||
372 | if (reset_timer) { | ||
373 | /* | ||
374 | * traceroute could hang if someone else has a ping | ||
375 | * running and our ICMP reply gets dropped but we don't | ||
376 | * realize it because we keep waking up to handle those | ||
377 | * other ICMP packets that keep coming in. To fix this, | ||
378 | * "reset_timer" will only be true if the last packet that | ||
379 | * came in was for us or if this is the first time we're | ||
380 | * waiting for a reply since sending out a probe. Note | ||
381 | * that this takes advantage of the select() feature on | ||
382 | * Linux where the remaining timeout is written to the | ||
383 | * struct timeval area. | ||
384 | */ | ||
385 | wait.tv_sec = waittime; | ||
386 | wait.tv_usec = 0; | ||
387 | } | ||
388 | |||
389 | if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) | ||
390 | cc=recvfrom(s, (char *)packet, sizeof(packet), 0, | ||
391 | (struct sockaddr *)from, &fromlen); | ||
392 | |||
393 | return(cc); | ||
394 | } | ||
395 | |||
396 | |||
397 | static void | ||
398 | send_probe(seq, ttl) | ||
399 | int seq, ttl; | ||
400 | { | ||
401 | struct opacket *op = outpacket; | ||
402 | struct ip *ip = &op->ip; | ||
403 | struct udphdr *up = &op->udp; | ||
404 | int i; | ||
405 | struct timezone tz; | ||
406 | |||
407 | ip->ip_off = 0; | ||
408 | ip->ip_hl = sizeof(*ip) >> 2; | ||
409 | ip->ip_p = IPPROTO_UDP; | ||
410 | ip->ip_len = datalen; | ||
411 | ip->ip_ttl = ttl; | ||
412 | ip->ip_v = IPVERSION; | ||
413 | ip->ip_id = htons(ident+seq); | ||
414 | |||
415 | up->source = htons(ident); | ||
416 | up->dest = htons(port+seq); | ||
417 | up->len = htons((u_short)(datalen - sizeof(struct ip))); | ||
418 | up->check = 0; | ||
419 | |||
420 | op->seq = seq; | ||
421 | op->ttl = ttl; | ||
422 | (void) gettimeofday(&op->tv, &tz); | ||
423 | |||
424 | i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto, | ||
425 | sizeof(struct sockaddr)); | ||
426 | if (i < 0 || i != datalen) { | ||
427 | if (i<0) | ||
428 | perror("sendto"); | ||
429 | printf("traceroute: wrote %s %d chars, ret=%d\n", hostname, | ||
430 | datalen, i); | ||
431 | (void) fflush(stdout); | ||
432 | } | ||
433 | } | ||
434 | |||
435 | |||
436 | static double | ||
437 | deltaT(t1p, t2p) | ||
438 | struct timeval *t1p, *t2p; | ||
439 | { | ||
440 | register double dt; | ||
441 | |||
442 | dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 + | ||
443 | (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0; | ||
444 | return (dt); | ||
445 | } | ||
446 | |||
447 | |||
448 | /* | ||
449 | * Convert an ICMP "type" field to a printable string. | ||
450 | */ | ||
451 | static const char * | ||
452 | pr_type(t) | ||
453 | u_char t; | ||
454 | { | ||
455 | static const char * const ttab[] = { | ||
456 | "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", | ||
457 | "Source Quench", "Redirect", "ICMP 6", "ICMP 7", | ||
458 | "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", | ||
459 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", | ||
460 | "Info Reply" | ||
461 | }; | ||
462 | |||
463 | if(t > 16) | ||
464 | return("OUT-OF-RANGE"); | ||
465 | |||
466 | return(ttab[t]); | ||
467 | } | ||
468 | |||
469 | |||
470 | static int | ||
471 | packet_ok(buf, cc, from, seq) | ||
472 | u_char *buf; | ||
473 | int cc; | ||
474 | struct sockaddr_in *from; | ||
475 | int seq; | ||
476 | { | ||
477 | register struct icmp *icp; | ||
478 | u_char type, code; | ||
479 | int hlen; | ||
480 | #ifndef ARCHAIC | ||
481 | struct ip *ip; | ||
482 | |||
483 | ip = (struct ip *) buf; | ||
484 | hlen = ip->ip_hl << 2; | ||
485 | if (cc < hlen + ICMP_MINLEN) { | ||
486 | if (verbose) | ||
487 | printf("packet too short (%d bytes) from %s\n", cc, | ||
488 | inet_ntoa(from->sin_addr)); | ||
489 | return (0); | ||
490 | } | ||
491 | cc -= hlen; | ||
492 | icp = (struct icmp *)(buf + hlen); | ||
493 | #else | ||
494 | icp = (struct icmp *)buf; | ||
495 | #endif ARCHAIC | ||
496 | type = icp->icmp_type; code = icp->icmp_code; | ||
497 | if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || | ||
498 | type == ICMP_UNREACH) { | ||
499 | struct ip *hip; | ||
500 | struct udphdr *up; | ||
501 | |||
502 | hip = &icp->icmp_ip; | ||
503 | hlen = hip->ip_hl << 2; | ||
504 | up = (struct udphdr *)((u_char *)hip + hlen); | ||
505 | if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && | ||
506 | up->source == htons(ident) && | ||
507 | up->dest == htons(port+seq)) | ||
508 | return (type == ICMP_TIMXCEED? -1 : code+1); | ||
509 | } | ||
510 | #ifndef ARCHAIC | ||
511 | if (verbose) { | ||
512 | int i; | ||
513 | u_long *lp = (u_long *)&icp->icmp_ip; | ||
514 | |||
515 | printf("\n%d bytes from %s to %s", cc, | ||
516 | inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst)); | ||
517 | printf(": icmp type %d (%s) code %d\n", type, pr_type(type), | ||
518 | icp->icmp_code); | ||
519 | for (i = 4; i < cc ; i += sizeof(long)) | ||
520 | printf("%2d: x%8.8lx\n", i, *lp++); | ||
521 | } | ||
522 | #endif ARCHAIC | ||
523 | return(0); | ||
524 | } | ||
525 | |||
526 | |||
527 | static void | ||
528 | print(buf, cc, from) | ||
529 | u_char *buf; | ||
530 | int cc; | ||
531 | struct sockaddr_in *from; | ||
532 | { | ||
533 | struct ip *ip; | ||
534 | int hlen; | ||
535 | |||
536 | ip = (struct ip *) buf; | ||
537 | hlen = ip->ip_hl << 2; | ||
538 | cc -= hlen; | ||
539 | |||
540 | if (nflag) | ||
541 | printf(" %s", inet_ntoa(from->sin_addr)); | ||
542 | else | ||
543 | printf(" %s (%s)", inetname(from->sin_addr), | ||
544 | inet_ntoa(from->sin_addr)); | ||
545 | |||
546 | if (verbose) | ||
547 | printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); | ||
548 | } | ||
549 | |||
550 | |||
551 | /* | ||
552 | * Construct an Internet address representation. | ||
553 | * If the nflag has been supplied, give | ||
554 | * numeric value, otherwise try for symbolic name. | ||
555 | */ | ||
556 | static char * | ||
557 | inetname(in) | ||
558 | struct in_addr in; | ||
559 | { | ||
560 | register char *cp; | ||
561 | static char line[50]; | ||
562 | struct hostent *hp; | ||
563 | static char domain[MAXHOSTNAMELEN + 1]; | ||
564 | static int first = 1; | ||
565 | |||
566 | if (first && !nflag) { | ||
567 | first = 0; | ||
568 | if (gethostname(domain, MAXHOSTNAMELEN) == 0 && | ||
569 | (cp = index(domain, '.'))) | ||
570 | (void) strcpy(domain, cp + 1); | ||
571 | else | ||
572 | domain[0] = 0; | ||
573 | } | ||
574 | cp = 0; | ||
575 | if (!nflag && in.s_addr != INADDR_ANY) { | ||
576 | hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET); | ||
577 | if (hp) { | ||
578 | if ((cp = index(hp->h_name, '.')) && | ||
579 | !strcmp(cp + 1, domain)) | ||
580 | *cp = 0; | ||
581 | cp = (char *)hp->h_name; | ||
582 | } | ||
583 | } | ||
584 | if (cp) | ||
585 | (void) strcpy(line, cp); | ||
586 | else { | ||
587 | in.s_addr = ntohl(in.s_addr); | ||
588 | #define C(x) ((x) & 0xff) | ||
589 | sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24), | ||
590 | C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); | ||
591 | } | ||
592 | return (line); | ||
593 | } | ||