diff options
author | Leonid Lisovskiy <lly.dev@gmail.com> | 2009-11-23 06:20:09 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-11-23 06:20:09 +0100 |
commit | 4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26 (patch) | |
tree | d652a32a9dcc9e1acaff57bf019211068db55cdc | |
parent | 0d56568654973a522bd005616b86d4dc8c833c81 (diff) | |
download | busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.tar.gz busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.tar.bz2 busybox-w32-4c06531d5e2b053b642cea6fc4e7bc91ea4cbd26.zip |
traceroute6: new applet by Leonid Lisovskiy. +1562 bytes
Signed-off-by: Leonid Lisovskiy <lly.dev@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | include/applets.h | 1 | ||||
-rw-r--r-- | include/usage.h | 27 | ||||
-rw-r--r-- | networking/Config.in | 7 | ||||
-rw-r--r-- | networking/traceroute.c | 502 |
4 files changed, 428 insertions, 109 deletions
diff --git a/include/applets.h b/include/applets.h index a2d1e95a5..d1a84eeaf 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -395,6 +395,7 @@ IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | |||
395 | IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) | 395 | IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) |
396 | IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 396 | IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
397 | IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) | 397 | IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) |
398 | IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) | ||
398 | IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) | 399 | IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) |
399 | IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 400 | IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
400 | IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) | 401 | IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) |
diff --git a/include/usage.h b/include/usage.h index 3ccf160bd..920f8e8c9 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -4648,17 +4648,18 @@ | |||
4648 | "hello world\n" | 4648 | "hello world\n" |
4649 | 4649 | ||
4650 | #define traceroute_trivial_usage \ | 4650 | #define traceroute_trivial_usage \ |
4651 | "[-FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \ | 4651 | "[-46FIldnrv] [-f 1st_ttl] [-m max_ttl] [-p port#] [-q nqueries]\n" \ |
4652 | " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \ | 4652 | " [-s src_addr] [-t tos] [-w wait] [-g gateway] [-i iface]\n" \ |
4653 | " [-z pausemsecs] HOST [data size]" | 4653 | " [-z pausemsecs] HOST [data size]" |
4654 | #define traceroute_full_usage "\n\n" \ | 4654 | #define traceroute_full_usage "\n\n" \ |
4655 | "Trace the route to HOST\n" \ | 4655 | "Trace the route to HOST\n" \ |
4656 | "\nOptions:" \ | 4656 | "\nOptions:" \ |
4657 | "\n -4, -6 Force IPv4 or IPv6 hostname resolution" \ | ||
4657 | "\n -F Set the don't fragment bit" \ | 4658 | "\n -F Set the don't fragment bit" \ |
4658 | "\n -I Use ICMP ECHO instead of UDP datagrams" \ | 4659 | "\n -I Use ICMP ECHO instead of UDP datagrams" \ |
4659 | "\n -l Display the ttl value of the returned packet" \ | 4660 | "\n -l Display the ttl value of the returned packet" \ |
4660 | "\n -d Set SO_DEBUG options to socket" \ | 4661 | "\n -d Set SO_DEBUG options to socket" \ |
4661 | "\n -n Print hop addresses numerically rather than symbolically" \ | 4662 | "\n -n Print numeric addresses" \ |
4662 | "\n -r Bypass the normal routing tables and send directly to a host" \ | 4663 | "\n -r Bypass the normal routing tables and send directly to a host" \ |
4663 | "\n -v Verbose" \ | 4664 | "\n -v Verbose" \ |
4664 | "\n -m max_ttl Max time-to-live (max number of hops)" \ | 4665 | "\n -m max_ttl Max time-to-live (max number of hops)" \ |
@@ -4668,9 +4669,29 @@ | |||
4668 | "\n -s src_addr IP address to use as the source address" \ | 4669 | "\n -s src_addr IP address to use as the source address" \ |
4669 | "\n -t tos Type-of-service in probe packets (default 0)" \ | 4670 | "\n -t tos Type-of-service in probe packets (default 0)" \ |
4670 | "\n -w wait Time in seconds to wait for a response" \ | 4671 | "\n -w wait Time in seconds to wait for a response" \ |
4671 | "\n (default 3 sec)" \ | 4672 | "\n (default 3)" \ |
4672 | "\n -g Loose source route gateway (8 max)" \ | 4673 | "\n -g Loose source route gateway (8 max)" \ |
4673 | 4674 | ||
4675 | #define traceroute6_trivial_usage \ | ||
4676 | "[-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n" \ | ||
4677 | " [-s src_addr] [-t tos] [-w wait] [-i iface]\n" \ | ||
4678 | " HOST [data size]" | ||
4679 | #define traceroute6_full_usage "\n\n" \ | ||
4680 | "Trace the route to HOST\n" \ | ||
4681 | "\nOptions:" \ | ||
4682 | "\n -d Set SO_DEBUG options to socket" \ | ||
4683 | "\n -n Print numeric addresses" \ | ||
4684 | "\n -r Bypass the normal routing tables and send directly to a host" \ | ||
4685 | "\n -v Verbose" \ | ||
4686 | "\n -m max_ttl Max time-to-live (max number of hops)" \ | ||
4687 | "\n -p port# Base UDP port number used in probes" \ | ||
4688 | "\n (default is 33434)" \ | ||
4689 | "\n -q nqueries Number of probes per 'ttl' (default 3)" \ | ||
4690 | "\n -s src_addr IP address to use as the source address" \ | ||
4691 | "\n -t tos Type-of-service in probe packets (default 0)" \ | ||
4692 | "\n -w wait Time in seconds to wait for a response" \ | ||
4693 | "\n (default 3)" \ | ||
4694 | |||
4674 | #define true_trivial_usage \ | 4695 | #define true_trivial_usage \ |
4675 | "" | 4696 | "" |
4676 | #define true_full_usage "\n\n" \ | 4697 | #define true_full_usage "\n\n" \ |
diff --git a/networking/Config.in b/networking/Config.in index 3d29622da..668823784 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
@@ -888,6 +888,13 @@ config TRACEROUTE | |||
888 | help | 888 | help |
889 | Utility to trace the route of IP packets. | 889 | Utility to trace the route of IP packets. |
890 | 890 | ||
891 | config TRACEROUTE6 | ||
892 | bool "traceroute6" | ||
893 | default n | ||
894 | depends on FEATURE_IPV6 && TRACEROUTE | ||
895 | help | ||
896 | Utility to trace the route of IPv6 packets. | ||
897 | |||
891 | config FEATURE_TRACEROUTE_VERBOSE | 898 | config FEATURE_TRACEROUTE_VERBOSE |
892 | bool "Enable verbose output" | 899 | bool "Enable verbose output" |
893 | default n | 900 | default n |
diff --git a/networking/traceroute.c b/networking/traceroute.c index d36ddee14..18a8c25d4 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -23,6 +23,23 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * traceroute6 | ||
27 | * | ||
28 | * Modified for NRL 4.4BSD IPv6 release. | ||
29 | * 07/31/96 bgp | ||
30 | * | ||
31 | * Modified for Linux IPv6 by Pedro Roque <roque@di.fc.ul.pt> | ||
32 | * 31/07/1996 | ||
33 | * | ||
34 | * As ICMP error messages for IPv6 now include more than 8 bytes | ||
35 | * UDP datagrams are now sent via an UDP socket instead of magic | ||
36 | * RAW socket tricks. | ||
37 | * | ||
38 | * Converted to busybox applet by Leonid Lisovskiy <lly@sf.net> | ||
39 | * 2009-11-16 | ||
40 | */ | ||
41 | |||
42 | /* | ||
26 | * traceroute host - trace the route ip packets follow going to "host". | 43 | * traceroute host - trace the route ip packets follow going to "host". |
27 | * | 44 | * |
28 | * Attempt to trace the route an ip packet would follow to some | 45 | * Attempt to trace the route an ip packet would follow to some |
@@ -231,7 +248,8 @@ | |||
231 | 248 | ||
232 | 249 | ||
233 | #define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ | 250 | #define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ |
234 | IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") | 251 | IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \ |
252 | "4" IF_TRACEROUTE6("6") | ||
235 | enum { | 253 | enum { |
236 | OPT_DONT_FRAGMNT = (1 << 0), /* F */ | 254 | OPT_DONT_FRAGMNT = (1 << 0), /* F */ |
237 | OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ | 255 | OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ |
@@ -250,6 +268,9 @@ enum { | |||
250 | OPT_WAITTIME = (1 << 14), /* w */ | 268 | OPT_WAITTIME = (1 << 14), /* w */ |
251 | OPT_PAUSE_MS = (1 << 15), /* z */ | 269 | OPT_PAUSE_MS = (1 << 15), /* z */ |
252 | OPT_FIRST_TTL = (1 << 16), /* f */ | 270 | OPT_FIRST_TTL = (1 << 16), /* f */ |
271 | OPT_SOURCE_ROUTE = (1 << 17) * ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE, /* g */ | ||
272 | OPT_IPV4 = (1 << (17+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)), /* 4 */ | ||
273 | OPT_IPV6 = (1 << (18+ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE)) * ENABLE_TRACEROUTE6, /* 6 */ | ||
253 | }; | 274 | }; |
254 | #define verbose (option_mask32 & OPT_VERBOSE) | 275 | #define verbose (option_mask32 & OPT_VERBOSE) |
255 | 276 | ||
@@ -267,13 +288,21 @@ struct outdata_t { | |||
267 | struct timeval tv_UNUSED PACKED; /* time packet left */ | 288 | struct timeval tv_UNUSED PACKED; /* time packet left */ |
268 | }; | 289 | }; |
269 | 290 | ||
291 | #if ENABLE_TRACEROUTE6 | ||
292 | struct outdata6_t { | ||
293 | uint32_t ident6; | ||
294 | uint32_t seq6; | ||
295 | struct timeval tv_UNUSED PACKED; /* time packet left */ | ||
296 | }; | ||
297 | #endif | ||
298 | |||
270 | struct globals { | 299 | struct globals { |
271 | struct ip *outip; | 300 | struct ip *outip; |
272 | struct outdata_t *outdata; | 301 | struct outdata_t *outdata; |
273 | len_and_sockaddr *dest_lsa; | 302 | len_and_sockaddr *dest_lsa; |
274 | int packlen; /* total length of packet */ | 303 | int packlen; /* total length of packet */ |
275 | int pmtu; /* Path MTU Discovery (RFC1191) */ | 304 | int pmtu; /* Path MTU Discovery (RFC1191) */ |
276 | uint16_t ident; | 305 | uint32_t ident; |
277 | uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ | 306 | uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ |
278 | int waittime; // 5; /* time to wait for response (in seconds) */ | 307 | int waittime; // 5; /* time to wait for response (in seconds) */ |
279 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 308 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
@@ -314,18 +343,30 @@ struct globals { | |||
314 | #define outudp ((struct udphdr *)(outip + 1)) | 343 | #define outudp ((struct udphdr *)(outip + 1)) |
315 | 344 | ||
316 | 345 | ||
346 | /* libbb candidate? tftp uses this idiom too */ | ||
347 | static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) | ||
348 | { | ||
349 | len_and_sockaddr *new_lsa = xzalloc(LSA_LEN_SIZE + lsa->len); | ||
350 | memcpy(new_lsa, lsa, LSA_LEN_SIZE + lsa->len); | ||
351 | return new_lsa; | ||
352 | } | ||
353 | |||
354 | |||
317 | static int | 355 | static int |
318 | wait_for_reply(struct sockaddr_in *fromp) | 356 | wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) |
319 | { | 357 | { |
320 | struct pollfd pfd[1]; | 358 | struct pollfd pfd[1]; |
321 | int read_len = 0; | 359 | int read_len = 0; |
322 | socklen_t fromlen = sizeof(*fromp); | ||
323 | 360 | ||
324 | pfd[0].fd = rcvsock; | 361 | pfd[0].fd = rcvsock; |
325 | pfd[0].events = POLLIN; | 362 | pfd[0].events = POLLIN; |
326 | if (safe_poll(pfd, 1, waittime * 1000) > 0) | 363 | if (safe_poll(pfd, 1, waittime * 1000) > 0) { |
327 | read_len = recvfrom(rcvsock, recv_pkt, sizeof(recv_pkt), 0, | 364 | read_len = recv_from_to(rcvsock, |
328 | (struct sockaddr *)fromp, &fromlen); | 365 | recv_pkt, sizeof(recv_pkt), |
366 | /*flags:*/ 0, | ||
367 | &from_lsa->u.sa, to, from_lsa->len); | ||
368 | } | ||
369 | |||
329 | return read_len; | 370 | return read_len; |
330 | } | 371 | } |
331 | 372 | ||
@@ -369,20 +410,30 @@ send_probe(int seq, int ttl) | |||
369 | void *out; | 410 | void *out; |
370 | 411 | ||
371 | /* Payload */ | 412 | /* Payload */ |
372 | outdata->seq = seq; | 413 | #if ENABLE_TRACEROUTE6 |
373 | outdata->ttl = ttl; | 414 | if (dest_lsa->u.sa.sa_family == AF_INET6) { |
415 | struct outdata6_t *pkt = (struct outdata6_t *) outip; | ||
416 | pkt->ident6 = htonl(ident); | ||
417 | pkt->seq6 = htonl(seq); | ||
418 | /*gettimeofday(&pkt->tv, &tz);*/ | ||
419 | } else | ||
420 | #endif | ||
421 | { | ||
422 | outdata->seq = seq; | ||
423 | outdata->ttl = ttl; | ||
374 | // UNUSED: was storing gettimeofday's result there, but never ever checked it | 424 | // UNUSED: was storing gettimeofday's result there, but never ever checked it |
375 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ | 425 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ |
376 | |||
377 | if (option_mask32 & OPT_USE_ICMP) { | ||
378 | outicmp->icmp_seq = htons(seq); | ||
379 | 426 | ||
380 | /* Always calculate checksum for icmp packets */ | 427 | if (option_mask32 & OPT_USE_ICMP) { |
381 | outicmp->icmp_cksum = 0; | 428 | outicmp->icmp_seq = htons(seq); |
382 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, | 429 | |
383 | packlen - (sizeof(*outip) + optlen)); | 430 | /* Always calculate checksum for icmp packets */ |
384 | if (outicmp->icmp_cksum == 0) | 431 | outicmp->icmp_cksum = 0; |
385 | outicmp->icmp_cksum = 0xffff; | 432 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, |
433 | packlen - (sizeof(*outip) + optlen)); | ||
434 | if (outicmp->icmp_cksum == 0) | ||
435 | outicmp->icmp_cksum = 0xffff; | ||
436 | } | ||
386 | } | 437 | } |
387 | 438 | ||
388 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! | 439 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! |
@@ -411,21 +462,32 @@ send_probe(int seq, int ttl) | |||
411 | } | 462 | } |
412 | #endif | 463 | #endif |
413 | 464 | ||
465 | #if ENABLE_TRACEROUTE6 | ||
466 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | ||
467 | res = setsockopt(sndsock, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); | ||
468 | if (res < 0) | ||
469 | bb_perror_msg_and_die("setsockopt UNICAST_HOPS %d", ttl); | ||
470 | out = outip; | ||
471 | len = packlen; | ||
472 | } else | ||
473 | #endif | ||
474 | { | ||
414 | #if defined(IP_TTL) | 475 | #if defined(IP_TTL) |
415 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, | 476 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, |
416 | (char *)&ttl, sizeof(ttl)) < 0) { | 477 | (char *)&ttl, sizeof(ttl)) < 0) { |
417 | bb_perror_msg_and_die("setsockopt ttl %d", ttl); | 478 | bb_perror_msg_and_die("setsockopt ttl %d", ttl); |
418 | } | 479 | } |
419 | #endif | 480 | #endif |
420 | 481 | len = packlen - sizeof(*outip); | |
421 | len = packlen - sizeof(*outip); | 482 | if (option_mask32 & OPT_USE_ICMP) |
422 | if (option_mask32 & OPT_USE_ICMP) | 483 | out = outicmp; |
423 | out = outicmp; | 484 | else { |
424 | else { | 485 | out = outdata; |
425 | out = outdata; | 486 | len -= sizeof(*outudp); |
426 | len -= sizeof(*outudp); | 487 | set_nport(dest_lsa, htons(port + seq)); |
427 | set_nport(dest_lsa, htons(port + seq)); | 488 | } |
428 | } | 489 | } |
490 | |||
429 | res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); | 491 | res = xsendto(sndsock, out, len, &dest_lsa->u.sa, dest_lsa->len); |
430 | if (res != len) { | 492 | if (res != len) { |
431 | bb_info_msg("sent %d octets, ret=%d", len, res); | 493 | bb_info_msg("sent %d octets, ret=%d", len, res); |
@@ -436,7 +498,7 @@ send_probe(int seq, int ttl) | |||
436 | /* | 498 | /* |
437 | * Convert an ICMP "type" field to a printable string. | 499 | * Convert an ICMP "type" field to a printable string. |
438 | */ | 500 | */ |
439 | static inline const char * | 501 | static const char * |
440 | pr_type(unsigned char t) | 502 | pr_type(unsigned char t) |
441 | { | 503 | { |
442 | static const char *const ttab[] = { | 504 | static const char *const ttab[] = { |
@@ -446,7 +508,23 @@ pr_type(unsigned char t) | |||
446 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", | 508 | "Param Problem", "Timestamp", "Timestamp Reply", "Info Request", |
447 | "Info Reply", "Mask Request", "Mask Reply" | 509 | "Info Reply", "Mask Request", "Mask Reply" |
448 | }; | 510 | }; |
511 | # if ENABLE_TRACEROUTE6 | ||
512 | static const char *const ttab6[] = { | ||
513 | [0] "Error", "Dest Unreachable", "Packet Too Big", "Time Exceeded", | ||
514 | [4] "Param Problem", | ||
515 | [8] "Echo Request", "Echo Reply", "Membership Query", "Membership Report", | ||
516 | [12] "Membership Reduction", "Router Solicit", "Router Advert", "Neighbor Solicit", | ||
517 | [16] "Neighbor Advert", "Redirect", | ||
518 | }; | ||
449 | 519 | ||
520 | if (dest_lsa->u.sa.sa_family == AF_INET6) { | ||
521 | if (t < 5) | ||
522 | return ttab6[t]; | ||
523 | if (t < 128 || t > ND_REDIRECT) | ||
524 | return "OUT-OF-RANGE"; | ||
525 | return ttab6[(t & 63) + 8]; | ||
526 | } | ||
527 | # endif | ||
450 | if (t >= ARRAY_SIZE(ttab)) | 528 | if (t >= ARRAY_SIZE(ttab)) |
451 | return "OUT-OF-RANGE"; | 529 | return "OUT-OF-RANGE"; |
452 | 530 | ||
@@ -455,11 +533,11 @@ pr_type(unsigned char t) | |||
455 | #endif | 533 | #endif |
456 | 534 | ||
457 | #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE | 535 | #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE |
458 | #define packet_ok(read_len, from, seq) \ | 536 | #define packet4_ok(read_len, from, seq) \ |
459 | packet_ok(read_len, seq) | 537 | packet4_ok(read_len, seq) |
460 | #endif | 538 | #endif |
461 | static int | 539 | static int |
462 | packet_ok(int read_len, const struct sockaddr_in *from, int seq) | 540 | packet4_ok(int read_len, const struct sockaddr_in *from, int seq) |
463 | { | 541 | { |
464 | const struct icmp *icp; | 542 | const struct icmp *icp; |
465 | unsigned char type, code; | 543 | unsigned char type, code; |
@@ -502,7 +580,7 @@ packet_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
502 | && icp->icmp_id == htons(ident) | 580 | && icp->icmp_id == htons(ident) |
503 | && icp->icmp_seq == htons(seq) | 581 | && icp->icmp_seq == htons(seq) |
504 | ) { | 582 | ) { |
505 | return -2; | 583 | return ICMP_UNREACH_PORT+1; |
506 | } | 584 | } |
507 | 585 | ||
508 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); | 586 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); |
@@ -544,6 +622,98 @@ packet_ok(int read_len, const struct sockaddr_in *from, int seq) | |||
544 | return 0; | 622 | return 0; |
545 | } | 623 | } |
546 | 624 | ||
625 | #if ENABLE_TRACEROUTE6 | ||
626 | # if !ENABLE_FEATURE_TRACEROUTE_VERBOSE | ||
627 | #define packet_ok(read_len, from_lsa, to, seq) \ | ||
628 | packet_ok(read_len, from_lsa, seq) | ||
629 | # endif | ||
630 | static int | ||
631 | packet_ok(int read_len, len_and_sockaddr *from_lsa, | ||
632 | struct sockaddr *to, | ||
633 | int seq) | ||
634 | { | ||
635 | const struct icmp6_hdr *icp; | ||
636 | unsigned char type, code; | ||
637 | |||
638 | if (from_lsa->u.sa.sa_family == AF_INET) | ||
639 | return packet4_ok(read_len, &from_lsa->u.sin, seq); | ||
640 | |||
641 | icp = (struct icmp6_hdr *) recv_pkt; | ||
642 | |||
643 | type = icp->icmp6_type; | ||
644 | code = icp->icmp6_code; | ||
645 | |||
646 | if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT) | ||
647 | || type == ICMP6_DST_UNREACH | ||
648 | ) { | ||
649 | struct ip6_hdr *hip; | ||
650 | struct udphdr *up; | ||
651 | int nexthdr; | ||
652 | |||
653 | hip = (struct ip6_hdr *)(icp + 1); | ||
654 | up = (struct udphdr *) (hip + 1); | ||
655 | nexthdr = hip->ip6_nxt; | ||
656 | |||
657 | if (nexthdr == IPPROTO_FRAGMENT) { | ||
658 | nexthdr = *(unsigned char*)up; | ||
659 | up++; | ||
660 | } | ||
661 | if (nexthdr == IPPROTO_UDP) { | ||
662 | struct outdata6_t *pkt; | ||
663 | |||
664 | pkt = (struct outdata6_t *) (up + 1); | ||
665 | |||
666 | if (ntohl(pkt->ident6) == ident | ||
667 | && ntohl(pkt->seq6) == seq | ||
668 | ) { | ||
669 | return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1); | ||
670 | } | ||
671 | } | ||
672 | |||
673 | } | ||
674 | |||
675 | # if ENABLE_FEATURE_TRACEROUTE_VERBOSE | ||
676 | if (verbose) { | ||
677 | unsigned char *p; | ||
678 | char pa1[MAXHOSTNAMELEN]; | ||
679 | char pa2[MAXHOSTNAMELEN]; | ||
680 | int i; | ||
681 | |||
682 | p = (unsigned char *) (icp + 1); | ||
683 | |||
684 | printf("\n%d bytes from %s to " | ||
685 | "%s: icmp type %d (%s) code %d\n", | ||
686 | read_len, | ||
687 | inet_ntop(AF_INET6, &from_lsa->u.sin6.sin6_addr, pa1, sizeof(pa1)), | ||
688 | inet_ntop(AF_INET6, &((struct sockaddr_in6*)to)->sin6_addr, pa2, sizeof(pa2)), | ||
689 | type, pr_type(type), icp->icmp6_code); | ||
690 | |||
691 | read_len -= sizeof(struct icmp6_hdr); | ||
692 | for (i = 0; i < read_len ; i++) { | ||
693 | if (i % 16 == 0) | ||
694 | printf("%04x:", i); | ||
695 | if (i % 4 == 0) | ||
696 | bb_putchar(' '); | ||
697 | printf("%02x", p[i]); | ||
698 | if ((i % 16 == 15) && (i + 1 < read_len)) | ||
699 | bb_putchar('\n'); | ||
700 | } | ||
701 | bb_putchar('\n'); | ||
702 | } | ||
703 | # endif | ||
704 | |||
705 | return 0; | ||
706 | } | ||
707 | #else /* !ENABLE_TRACEROUTE6 */ | ||
708 | static ALWAYS_INLINE int | ||
709 | packet_ok(int read_len, len_and_sockaddr *from_lsa, | ||
710 | struct sockaddr *to UNUSED_PARAM, | ||
711 | int seq) | ||
712 | { | ||
713 | return packet4_ok(read_len, &from_lsa->u.sin, seq); | ||
714 | } | ||
715 | #endif | ||
716 | |||
547 | /* | 717 | /* |
548 | * Construct an Internet address representation. | 718 | * Construct an Internet address representation. |
549 | * If the -n flag has been supplied, give | 719 | * If the -n flag has been supplied, give |
@@ -572,17 +742,22 @@ print_inetname(const struct sockaddr *from) | |||
572 | } | 742 | } |
573 | 743 | ||
574 | static void | 744 | static void |
575 | print(int read_len, const struct sockaddr_in *from) | 745 | print(int read_len, const struct sockaddr *from, const struct sockaddr *to) |
576 | { | 746 | { |
577 | print_inetname((const struct sockaddr*)from); | 747 | print_inetname(from); |
578 | if (verbose) { | ||
579 | const struct ip *ip; | ||
580 | int hlen; | ||
581 | 748 | ||
582 | ip = (struct ip *) recv_pkt; | 749 | if (verbose) { |
583 | hlen = ip->ip_hl << 2; | 750 | char *ina = xmalloc_sockaddr2dotted_noport(to); |
584 | read_len -= hlen; | 751 | #if ENABLE_TRACEROUTE6 |
585 | printf(" %d bytes to %s", read_len, inet_ntoa(ip->ip_dst)); | 752 | if (to->sa_family == AF_INET6) { |
753 | read_len -= sizeof(struct ip6_hdr); | ||
754 | } else | ||
755 | #endif | ||
756 | { | ||
757 | read_len -= ((struct ip*)recv_pkt)->ip_hl << 2; | ||
758 | } | ||
759 | printf(" %d bytes to %s", read_len, ina); | ||
760 | free(ina); | ||
586 | } | 761 | } |
587 | } | 762 | } |
588 | 763 | ||
@@ -598,9 +773,8 @@ print_delta_ms(unsigned t1p, unsigned t2p) | |||
598 | * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] | 773 | * [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] |
599 | * [-w waittime] [-z pausemsecs] host [packetlen]" | 774 | * [-w waittime] [-z pausemsecs] host [packetlen]" |
600 | */ | 775 | */ |
601 | 776 | static int | |
602 | int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 777 | common_traceroute_main(int op, char **argv) |
603 | int traceroute_main(int argc UNUSED_PARAM, char **argv) | ||
604 | { | 778 | { |
605 | int i; | 779 | int i; |
606 | int minpacket; | 780 | int minpacket; |
@@ -609,7 +783,6 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
609 | int nprobes = 3; | 783 | int nprobes = 3; |
610 | int first_ttl = 1; | 784 | int first_ttl = 1; |
611 | unsigned pausemsecs = 0; | 785 | unsigned pausemsecs = 0; |
612 | unsigned op; | ||
613 | char *source; | 786 | char *source; |
614 | char *device; | 787 | char *device; |
615 | char *tos_str; | 788 | char *tos_str; |
@@ -623,20 +796,29 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
623 | llist_t *source_route_list = NULL; | 796 | llist_t *source_route_list = NULL; |
624 | int lsrr = 0; | 797 | int lsrr = 0; |
625 | #endif | 798 | #endif |
799 | #if ENABLE_TRACEROUTE6 | ||
800 | sa_family_t af = AF_UNSPEC; | ||
801 | #else | ||
802 | enum { af = AF_INET }; | ||
803 | #endif | ||
626 | int ttl; | 804 | int ttl; |
627 | int seq; | 805 | int seq; |
806 | len_and_sockaddr *from_lsa; | ||
807 | struct sockaddr *lastaddr; | ||
808 | struct sockaddr *to; | ||
628 | 809 | ||
629 | INIT_G(); | 810 | INIT_G(); |
630 | 811 | ||
631 | /* minimum 1 arg */ | 812 | /* minimum 1 arg */ |
632 | opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); | 813 | opt_complementary = "-1:x-x" IF_FEATURE_TRACEROUTE_SOURCE_ROUTE(":g::"); |
633 | op = getopt32(argv, OPT_STRING | 814 | op |= getopt32(argv, OPT_STRING |
634 | , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str | 815 | , &tos_str, &device, &max_ttl_str, &port_str, &nprobes_str |
635 | , &source, &waittime_str, &pausemsecs_str, &first_ttl_str | 816 | , &source, &waittime_str, &pausemsecs_str, &first_ttl_str |
636 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 817 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
637 | , &source_route_list | 818 | , &source_route_list |
638 | #endif | 819 | #endif |
639 | ); | 820 | ); |
821 | argv += optind; | ||
640 | 822 | ||
641 | #if 0 /* IGNORED */ | 823 | #if 0 /* IGNORED */ |
642 | if (op & OPT_IP_CHKSUM) | 824 | if (op & OPT_IP_CHKSUM) |
@@ -681,21 +863,53 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
681 | } | 863 | } |
682 | #endif | 864 | #endif |
683 | 865 | ||
684 | minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; | 866 | #if ENABLE_TRACEROUTE6 |
685 | if (!(op & OPT_USE_ICMP)) | 867 | if (op & OPT_IPV4) |
686 | minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; | 868 | af = AF_INET; |
869 | if (op & OPT_IPV6) { | ||
870 | af = AF_INET6; | ||
871 | minpacket = sizeof(struct outdata6_t); | ||
872 | } else | ||
873 | #endif | ||
874 | { | ||
875 | minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR | ||
876 | + sizeof(*outdata) + optlen; | ||
877 | if (!(op & OPT_USE_ICMP)) | ||
878 | minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; | ||
879 | } | ||
687 | packlen = minpacket; | 880 | packlen = minpacket; |
688 | 881 | ||
689 | /* Process destination and optional packet size */ | 882 | /* Process destination and optional packet size */ |
690 | argv += optind; | ||
691 | if (argv[1]) | 883 | if (argv[1]) |
692 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); | 884 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); |
885 | #if ENABLE_TRACEROUTE6 | ||
886 | dest_lsa = xhost_and_af2sockaddr(argv[0], port, af); | ||
887 | af = dest_lsa->u.sa.sa_family; | ||
888 | #else | ||
693 | dest_lsa = xhost2sockaddr(argv[0], port); | 889 | dest_lsa = xhost2sockaddr(argv[0], port); |
890 | #endif | ||
694 | 891 | ||
695 | /* Ensure the socket fds won't be 0, 1 or 2 */ | 892 | /* Ensure the socket fds won't be 0, 1 or 2 */ |
696 | bb_sanitize_stdio(); | 893 | bb_sanitize_stdio(); |
697 | 894 | ||
698 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); | 895 | #if ENABLE_TRACEROUTE6 |
896 | if (af == AF_INET6) { | ||
897 | xmove_fd(xsocket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6), rcvsock); | ||
898 | # ifdef IPV6_RECVPKTINFO | ||
899 | setsockopt(rcvsock, SOL_IPV6, IPV6_RECVPKTINFO, | ||
900 | &const_int_1, sizeof(const_int_1)); | ||
901 | setsockopt(rcvsock, SOL_IPV6, IPV6_2292PKTINFO, | ||
902 | &const_int_1, sizeof(const_int_1)); | ||
903 | # else | ||
904 | setsockopt(rcvsock, SOL_IPV6, IPV6_PKTINFO, | ||
905 | &const_int_1, sizeof(const_int_1)); | ||
906 | # endif | ||
907 | } else | ||
908 | #endif | ||
909 | { | ||
910 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); | ||
911 | } | ||
912 | |||
699 | #if TRACEROUTE_SO_DEBUG | 913 | #if TRACEROUTE_SO_DEBUG |
700 | if (op & OPT_DEBUG) | 914 | if (op & OPT_DEBUG) |
701 | setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, | 915 | setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, |
@@ -705,34 +919,45 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
705 | setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, | 919 | setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, |
706 | &const_int_1, sizeof(const_int_1)); | 920 | &const_int_1, sizeof(const_int_1)); |
707 | 921 | ||
708 | if (op & OPT_USE_ICMP) | 922 | #if ENABLE_TRACEROUTE6 |
709 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); | 923 | if (af == AF_INET6) { |
710 | else | 924 | static const int two = 2; |
711 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); | 925 | if (setsockopt(rcvsock, SOL_RAW, IPV6_CHECKSUM, &two, sizeof(two)) < 0) |
926 | bb_perror_msg_and_die("setsockopt RAW_CHECKSUM"); | ||
927 | xmove_fd(xsocket(af, SOCK_DGRAM, 0), sndsock); | ||
928 | } else | ||
929 | #endif | ||
930 | { | ||
931 | if (op & OPT_USE_ICMP) | ||
932 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); | ||
933 | else | ||
934 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); | ||
712 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS | 935 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS |
713 | if (lsrr > 0) { | 936 | if (lsrr > 0) { |
714 | unsigned char optlist[MAX_IPOPTLEN]; | 937 | unsigned char optlist[MAX_IPOPTLEN]; |
715 | 938 | ||
716 | /* final hop */ | 939 | /* final hop */ |
717 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; | 940 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; |
718 | ++lsrr; | 941 | ++lsrr; |
719 | 942 | ||
720 | /* force 4 byte alignment */ | 943 | /* force 4 byte alignment */ |
721 | optlist[0] = IPOPT_NOP; | 944 | optlist[0] = IPOPT_NOP; |
722 | /* loose source route option */ | 945 | /* loose source route option */ |
723 | optlist[1] = IPOPT_LSRR; | 946 | optlist[1] = IPOPT_LSRR; |
724 | i = lsrr * sizeof(gwlist[0]); | 947 | i = lsrr * sizeof(gwlist[0]); |
725 | optlist[2] = i + 3; | 948 | optlist[2] = i + 3; |
726 | /* pointer to LSRR addresses */ | 949 | /* pointer to LSRR addresses */ |
727 | optlist[3] = IPOPT_MINOFF; | 950 | optlist[3] = IPOPT_MINOFF; |
728 | memcpy(optlist + 4, gwlist, i); | 951 | memcpy(optlist + 4, gwlist, i); |
729 | 952 | ||
730 | if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, | 953 | if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, |
731 | (char *)optlist, i + sizeof(gwlist[0])) < 0) { | 954 | (char *)optlist, i + sizeof(gwlist[0])) < 0) { |
732 | bb_perror_msg_and_die("IP_OPTIONS"); | 955 | bb_perror_msg_and_die("IP_OPTIONS"); |
956 | } | ||
733 | } | 957 | } |
734 | } | ||
735 | #endif | 958 | #endif |
959 | } | ||
960 | |||
736 | #ifdef SO_SNDBUF | 961 | #ifdef SO_SNDBUF |
737 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { | 962 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { |
738 | bb_perror_msg_and_die("SO_SNDBUF"); | 963 | bb_perror_msg_and_die("SO_SNDBUF"); |
@@ -759,29 +984,66 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
759 | 984 | ||
760 | outip = xzalloc(packlen); | 985 | outip = xzalloc(packlen); |
761 | 986 | ||
762 | if (op & OPT_USE_ICMP) { | 987 | ident = getpid(); |
763 | ident = getpid() | 0x8000; | 988 | |
764 | outicmp->icmp_type = ICMP_ECHO; | 989 | if (af == AF_INET) { |
765 | outicmp->icmp_id = htons(ident); | 990 | if (op & OPT_USE_ICMP) { |
766 | outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); | 991 | ident |= 0x8000; |
767 | } else { | 992 | outicmp->icmp_type = ICMP_ECHO; |
768 | outdata = (struct outdata_t *)(outudp + 1); | 993 | outicmp->icmp_id = htons(ident); |
994 | outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); | ||
995 | } else { | ||
996 | outdata = (struct outdata_t *)(outudp + 1); | ||
997 | } | ||
769 | } | 998 | } |
770 | 999 | ||
771 | if (op & OPT_DEVICE) /* hmm, do we need error check? */ | 1000 | if (op & OPT_DEVICE) /* hmm, do we need error check? */ |
772 | setsockopt_bindtodevice(sndsock, device); | 1001 | setsockopt_bindtodevice(sndsock, device); |
773 | 1002 | ||
774 | if (op & OPT_SOURCE) { | 1003 | if (op & OPT_SOURCE) { |
1004 | #if ENABLE_TRACEROUTE6 | ||
1005 | // TODO: need xdotted_and_af2sockaddr? | ||
1006 | len_and_sockaddr *source_lsa = xhost_and_af2sockaddr(source, 0, af); | ||
1007 | #else | ||
775 | len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); | 1008 | len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); |
776 | /* Ping does this (why?) */ | 1009 | #endif |
777 | if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, | 1010 | /* Ping4 does this (why?) */ |
778 | &source_lsa->u.sa, source_lsa->len)) | 1011 | if (af == AF_INET) |
779 | bb_error_msg_and_die("can't set multicast source interface"); | 1012 | if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, |
1013 | &source_lsa->u.sa, source_lsa->len)) | ||
1014 | bb_error_msg_and_die("can't set multicast source interface"); | ||
780 | //TODO: we can query source port we bound to, | 1015 | //TODO: we can query source port we bound to, |
781 | // and check it in replies... if we care enough | 1016 | // and check it in replies... if we care enough |
782 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); | 1017 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); |
783 | free(source_lsa); | 1018 | free(source_lsa); |
784 | } | 1019 | } |
1020 | #if ENABLE_TRACEROUTE6 | ||
1021 | else if (af == AF_INET6) { | ||
1022 | //TODO: why we don't do it for IPv4? | ||
1023 | len_and_sockaddr *source_lsa; | ||
1024 | |||
1025 | int probe_fd = xsocket(af, SOCK_DGRAM, 0); | ||
1026 | if (op & OPT_DEVICE) | ||
1027 | setsockopt_bindtodevice(probe_fd, device); | ||
1028 | set_nport(dest_lsa, htons(1025)); | ||
1029 | /* dummy connect. makes kernel pick source IP (and port) */ | ||
1030 | xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); | ||
1031 | |||
1032 | /* read IP and port */ | ||
1033 | source_lsa = get_sock_lsa(probe_fd); | ||
1034 | if (source_lsa == NULL) | ||
1035 | bb_error_msg_and_die("can't get probe addr"); | ||
1036 | |||
1037 | close(probe_fd); | ||
1038 | |||
1039 | /* bind our sockets to this IP (but not port) */ | ||
1040 | set_nport(source_lsa, 0); | ||
1041 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); | ||
1042 | xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); | ||
1043 | |||
1044 | free(source_lsa); | ||
1045 | } | ||
1046 | #endif | ||
785 | 1047 | ||
786 | /* Revert to non-privileged user after opening sockets */ | 1048 | /* Revert to non-privileged user after opening sockets */ |
787 | xsetgid(getgid()); | 1049 | xsetgid(getgid()); |
@@ -793,11 +1055,11 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
793 | printf(" from %s", source); | 1055 | printf(" from %s", source); |
794 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); | 1056 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); |
795 | 1057 | ||
1058 | from_lsa = dup_sockaddr(dest_lsa); | ||
1059 | lastaddr = xzalloc(dest_lsa->len); | ||
1060 | to = xzalloc(dest_lsa->len); | ||
796 | seq = 0; | 1061 | seq = 0; |
797 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { | 1062 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { |
798 | //TODO: make it protocol agnostic (get rid of sockaddr_in) | ||
799 | struct sockaddr_in from; | ||
800 | uint32_t lastaddr = 0; | ||
801 | int probe; | 1063 | int probe; |
802 | int unreachable = 0; /* counter */ | 1064 | int unreachable = 0; /* counter */ |
803 | int gotlastaddr = 0; /* flags */ | 1065 | int gotlastaddr = 0; /* flags */ |
@@ -819,44 +1081,55 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
819 | send_probe(++seq, ttl); | 1081 | send_probe(++seq, ttl); |
820 | 1082 | ||
821 | first = 0; | 1083 | first = 0; |
822 | while ((read_len = wait_for_reply(&from)) != 0) { | 1084 | while ((read_len = wait_for_reply(from_lsa, to)) != 0) { |
823 | t2 = monotonic_us(); | 1085 | t2 = monotonic_us(); |
824 | i = packet_ok(read_len, &from, seq); | 1086 | i = packet_ok(read_len, from_lsa, to, seq); |
825 | /* Skip short packet */ | 1087 | /* Skip short packet */ |
826 | if (i == 0) | 1088 | if (i == 0) |
827 | continue; | 1089 | continue; |
1090 | |||
828 | if (!gotlastaddr | 1091 | if (!gotlastaddr |
829 | || from.sin_addr.s_addr != lastaddr | 1092 | || (memcmp(lastaddr, &from_lsa->u.sa, from_lsa->len) != 0) |
830 | ) { | 1093 | ) { |
831 | print(read_len, &from); | 1094 | print(read_len, &from_lsa->u.sa, to); |
832 | lastaddr = from.sin_addr.s_addr; | 1095 | memcpy(lastaddr, &from_lsa->u.sa, from_lsa->len); |
833 | gotlastaddr = 1; | 1096 | gotlastaddr = 1; |
834 | } | 1097 | } |
1098 | |||
835 | print_delta_ms(t1, t2); | 1099 | print_delta_ms(t1, t2); |
836 | ip = (struct ip *)recv_pkt; | 1100 | ip = (struct ip *)recv_pkt; |
837 | if (op & OPT_TTL_FLAG) | 1101 | |
838 | printf(" (%d)", ip->ip_ttl); | 1102 | if (from_lsa->u.sa.sa_family == AF_INET) |
839 | if (i == -2) { | 1103 | if (op & OPT_TTL_FLAG) |
840 | if (ip->ip_ttl <= 1) | 1104 | printf(" (%d)", ip->ip_ttl); |
841 | printf(" !"); | 1105 | |
842 | got_there = 1; | ||
843 | break; | ||
844 | } | ||
845 | /* time exceeded in transit */ | 1106 | /* time exceeded in transit */ |
846 | if (i == -1) | 1107 | if (i == -1) |
847 | break; | 1108 | break; |
848 | i--; | 1109 | i--; |
849 | switch (i) { | 1110 | switch (i) { |
1111 | #if ENABLE_TRACEROUTE6 | ||
1112 | case ICMP6_DST_UNREACH_NOPORT << 8: | ||
1113 | got_there = 1; | ||
1114 | break; | ||
1115 | #endif | ||
850 | case ICMP_UNREACH_PORT: | 1116 | case ICMP_UNREACH_PORT: |
851 | if (ip->ip_ttl <= 1) | 1117 | if (ip->ip_ttl <= 1) |
852 | printf(" !"); | 1118 | printf(" !"); |
853 | got_there = 1; | 1119 | got_there = 1; |
854 | break; | 1120 | break; |
1121 | |||
855 | case ICMP_UNREACH_NET: | 1122 | case ICMP_UNREACH_NET: |
1123 | #if ENABLE_TRACEROUTE6 && (ICMP6_DST_UNREACH_NOROUTE != ICMP_UNREACH_NET) | ||
1124 | case ICMP6_DST_UNREACH_NOROUTE << 8: | ||
1125 | #endif | ||
856 | printf(" !N"); | 1126 | printf(" !N"); |
857 | ++unreachable; | 1127 | ++unreachable; |
858 | break; | 1128 | break; |
859 | case ICMP_UNREACH_HOST: | 1129 | case ICMP_UNREACH_HOST: |
1130 | #if ENABLE_TRACEROUTE6 | ||
1131 | case ICMP6_DST_UNREACH_ADDR << 8: | ||
1132 | #endif | ||
860 | printf(" !H"); | 1133 | printf(" !H"); |
861 | ++unreachable; | 1134 | ++unreachable; |
862 | break; | 1135 | break; |
@@ -869,6 +1142,9 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
869 | ++unreachable; | 1142 | ++unreachable; |
870 | break; | 1143 | break; |
871 | case ICMP_UNREACH_SRCFAIL: | 1144 | case ICMP_UNREACH_SRCFAIL: |
1145 | #if ENABLE_TRACEROUTE6 | ||
1146 | case ICMP6_DST_UNREACH_ADMIN << 8: | ||
1147 | #endif | ||
872 | printf(" !S"); | 1148 | printf(" !S"); |
873 | ++unreachable; | 1149 | ++unreachable; |
874 | break; | 1150 | break; |
@@ -924,3 +1200,17 @@ int traceroute_main(int argc UNUSED_PARAM, char **argv) | |||
924 | 1200 | ||
925 | return 0; | 1201 | return 0; |
926 | } | 1202 | } |
1203 | |||
1204 | int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
1205 | int traceroute_main(int argc UNUSED_PARAM, char **argv) | ||
1206 | { | ||
1207 | return common_traceroute_main(0, argv); | ||
1208 | } | ||
1209 | |||
1210 | #if ENABLE_TRACEROUTE6 | ||
1211 | int traceroute6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
1212 | int traceroute6_main(int argc UNUSED_PARAM, char **argv) | ||
1213 | { | ||
1214 | return common_traceroute_main(OPT_IPV6, argv); | ||
1215 | } | ||
1216 | #endif | ||