diff options
-rw-r--r-- | networking/traceroute.c | 725 |
1 files changed, 166 insertions, 559 deletions
diff --git a/networking/traceroute.c b/networking/traceroute.c index 958299aaa..244a74d6d 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c | |||
@@ -215,13 +215,6 @@ | |||
215 | #include "libbb.h" | 215 | #include "libbb.h" |
216 | #include "inet_common.h" | 216 | #include "inet_common.h" |
217 | 217 | ||
218 | |||
219 | /* | ||
220 | * Definitions for internet protocol version 4. | ||
221 | * Per RFC 791, September 1981. | ||
222 | */ | ||
223 | #define IPVERSION 4 | ||
224 | |||
225 | #ifndef IPPROTO_ICMP | 218 | #ifndef IPPROTO_ICMP |
226 | # define IPPROTO_ICMP 1 | 219 | # define IPPROTO_ICMP 1 |
227 | #endif | 220 | #endif |
@@ -229,122 +222,57 @@ | |||
229 | # define IPPROTO_IP 0 | 222 | # define IPPROTO_IP 0 |
230 | #endif | 223 | #endif |
231 | 224 | ||
232 | /* | 225 | /* Keep in sync with getopt32 call! */ |
233 | * Overlay for ip header used by other protocols (tcp, udp). | 226 | enum { |
234 | */ | 227 | OPT_DONT_FRAGMNT = (1 << 0), /* F */ |
235 | struct ipovly { | 228 | OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ |
236 | unsigned char ih_x1[9]; /* (unused) */ | 229 | OPT_TTL_FLAG = (1 << 2), /* l */ |
237 | unsigned char ih_pr; /* protocol */ | 230 | OPT_ADDR_NUM = (1 << 3), /* n */ |
238 | short ih_len; /* protocol length */ | 231 | OPT_BYPASS_ROUTE = (1 << 4), /* r */ |
239 | struct in_addr ih_src; /* source internet address */ | 232 | OPT_DEBUG = (1 << 5), /* d */ |
240 | struct in_addr ih_dst; /* destination internet address */ | 233 | OPT_VERBOSE = (1 << 6) * ENABLE_FEATURE_TRACEROUTE_VERBOSE, /* v */ |
234 | OPT_IP_CHKSUM = (1 << 7), /* x */ | ||
235 | OPT_TOS = (1 << 8), /* t */ | ||
236 | OPT_DEVICE = (1 << 9), /* i */ | ||
237 | OPT_MAX_TTL = (1 << 10), /* m */ | ||
238 | OPT_PORT = (1 << 11), /* p */ | ||
239 | OPT_NPROBES = (1 << 12), /* q */ | ||
240 | OPT_SOURCE = (1 << 13), /* s */ | ||
241 | OPT_WAITTIME = (1 << 14), /* w */ | ||
242 | OPT_PAUSE_MS = (1 << 15), /* z */ | ||
243 | OPT_FIRST_TTL = (1 << 16), /* f */ | ||
241 | }; | 244 | }; |
245 | #define verbose (option_mask32 & OPT_VERBOSE) | ||
242 | 246 | ||
243 | /* | 247 | enum { |
244 | * UDP kernel structures and variables. | 248 | SIZEOF_ICMP_HDR = 8, |
245 | */ | 249 | rcvsock = 3, /* receive (icmp) socket file descriptor */ |
246 | struct udpiphdr { | 250 | sndsock = 4, /* send (udp/icmp) socket file descriptor */ |
247 | struct ipovly ui_i; /* overlaid ip structure */ | ||
248 | struct udphdr ui_u; /* udp header */ | ||
249 | }; | ||
250 | #define ui_next ui_i.ih_next | ||
251 | #define ui_prev ui_i.ih_prev | ||
252 | #define ui_x1 ui_i.ih_x1 | ||
253 | #define ui_pr ui_i.ih_pr | ||
254 | #define ui_len ui_i.ih_len | ||
255 | #define ui_src ui_i.ih_src | ||
256 | #define ui_dst ui_i.ih_dst | ||
257 | #define ui_sport ui_u.uh_sport | ||
258 | #define ui_dport ui_u.uh_dport | ||
259 | #define ui_ulen ui_u.uh_ulen | ||
260 | #define ui_sum ui_u.uh_sum | ||
261 | |||
262 | |||
263 | /* Host name and address list */ | ||
264 | struct hostinfo { | ||
265 | char *name; | ||
266 | int n; | ||
267 | uint32_t *addrs; | ||
268 | }; | 251 | }; |
269 | 252 | ||
270 | /* Data section of the probe packet */ | 253 | /* Data section of the probe packet */ |
271 | typedef struct outdata { | 254 | struct outdata_t { |
272 | unsigned char seq; /* sequence number of this packet */ | 255 | unsigned char seq; /* sequence number of this packet */ |
273 | unsigned char ttl; /* ttl packet left with */ | 256 | unsigned char ttl; /* ttl packet left with */ |
274 | // UNUSED. Retaining to have the same packet size. | 257 | // UNUSED. Retaining to have the same packet size. |
275 | struct timeval tv_UNUSED PACKED; /* time packet left */ | 258 | struct timeval tv_UNUSED PACKED; /* time packet left */ |
276 | } outdata_t; | ||
277 | |||
278 | struct IFADDRLIST { | ||
279 | uint32_t addr; | ||
280 | char device[sizeof(struct ifreq)]; | ||
281 | }; | 259 | }; |
282 | 260 | ||
283 | |||
284 | /* Keep in sync with getopt32 call! */ | ||
285 | #define OPT_DONT_FRAGMNT (1<<0) /* F */ | ||
286 | #define OPT_USE_ICMP (1<<1) /* I */ | ||
287 | #define OPT_TTL_FLAG (1<<2) /* l */ | ||
288 | #define OPT_ADDR_NUM (1<<3) /* n */ | ||
289 | #define OPT_BYPASS_ROUTE (1<<4) /* r */ | ||
290 | #define OPT_DEBUG (1<<5) /* d */ | ||
291 | #define OPT_VERBOSE (1<<6) /* v */ | ||
292 | #define OPT_IP_CHKSUM (1<<7) /* x */ | ||
293 | #define OPT_TOS (1<<8) /* t */ | ||
294 | #define OPT_DEVICE (1<<9) /* i */ | ||
295 | #define OPT_MAX_TTL (1<<10) /* m */ | ||
296 | #define OPT_PORT (1<<11) /* p */ | ||
297 | #define OPT_NPROBES (1<<12) /* q */ | ||
298 | #define OPT_SOURCE (1<<13) /* s */ | ||
299 | #define OPT_WAITTIME (1<<14) /* w */ | ||
300 | #define OPT_PAUSE_MS (1<<15) /* z */ | ||
301 | #define OPT_FIRST_TTL (1<<16) /* f */ | ||
302 | |||
303 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | ||
304 | /* use icmp echo instead of udp packets */ | ||
305 | #define useicmp (option_mask32 & OPT_USE_ICMP) | ||
306 | #endif | ||
307 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE | ||
308 | #define verbose (option_mask32 & OPT_VERBOSE) | ||
309 | #endif | ||
310 | #define nflag (option_mask32 & OPT_ADDR_NUM) | ||
311 | |||
312 | |||
313 | struct globals { | 261 | struct globals { |
314 | struct ip *outip; /* last output (udp) packet */ | 262 | struct ip *outip; |
315 | struct udphdr *outudp; /* last output (udp) packet */ | 263 | struct outdata_t *outdata; |
316 | struct outdata *outdata; /* last output (udp) packet */ | 264 | len_and_sockaddr *dest_lsa; |
317 | |||
318 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | ||
319 | struct icmp *outicmp; /* last output (icmp) packet */ | ||
320 | #endif | ||
321 | |||
322 | int rcvsock; /* receive (icmp) socket file descriptor */ | ||
323 | int sndsock; /* send (udp/icmp) socket file descriptor */ | ||
324 | |||
325 | int packlen; /* total length of packet */ | 265 | int packlen; /* total length of packet */ |
326 | int minpacket; /* min ip packet size */ | ||
327 | int maxpacket; // 32 * 1024; /* max ip packet size */ | ||
328 | int pmtu; /* Path MTU Discovery (RFC1191) */ | 266 | int pmtu; /* Path MTU Discovery (RFC1191) */ |
329 | |||
330 | char *hostname; | ||
331 | |||
332 | uint16_t ident; | 267 | uint16_t ident; |
333 | uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ | 268 | uint16_t port; // 32768 + 666; /* start udp dest port # for probe packets */ |
334 | |||
335 | int waittime; // 5; /* time to wait for response (in seconds) */ | 269 | int waittime; // 5; /* time to wait for response (in seconds) */ |
336 | int doipcksum; // 1; /* calculate ip checksums by default */ | ||
337 | |||
338 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 270 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
339 | int optlen; /* length of ip options */ | 271 | int optlen; /* length of ip options */ |
340 | #else | 272 | #else |
341 | #define optlen 0 | 273 | #define optlen 0 |
342 | #endif | 274 | #endif |
343 | 275 | unsigned char recv_pkt[512]; /* last inbound (icmp) packet */ | |
344 | struct sockaddr_storage whereto; /* Who to try to reach */ | ||
345 | struct sockaddr_storage wherefrom; /* Who we are */ | ||
346 | /* last inbound (icmp) packet */ | ||
347 | unsigned char packet[512]; | ||
348 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 276 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
349 | /* Maximum number of gateways (include room for one noop) */ | 277 | /* Maximum number of gateways (include room for one noop) */ |
350 | #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t))) | 278 | #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(uint32_t))) |
@@ -355,206 +283,39 @@ struct globals { | |||
355 | 283 | ||
356 | #define G (*ptr_to_globals) | 284 | #define G (*ptr_to_globals) |
357 | #define outip (G.outip ) | 285 | #define outip (G.outip ) |
358 | #define outudp (G.outudp ) | ||
359 | #define outdata (G.outdata ) | 286 | #define outdata (G.outdata ) |
360 | #define outicmp (G.outicmp ) | 287 | #define dest_lsa (G.dest_lsa ) |
361 | #define rcvsock (G.rcvsock ) | ||
362 | #define sndsock (G.sndsock ) | ||
363 | #define packlen (G.packlen ) | 288 | #define packlen (G.packlen ) |
364 | #define minpacket (G.minpacket) | ||
365 | #define maxpacket (G.maxpacket) | ||
366 | #define pmtu (G.pmtu ) | 289 | #define pmtu (G.pmtu ) |
367 | #define hostname (G.hostname ) | ||
368 | #define ident (G.ident ) | 290 | #define ident (G.ident ) |
369 | #define port (G.port ) | 291 | #define port (G.port ) |
370 | #define waittime (G.waittime ) | 292 | #define waittime (G.waittime ) |
371 | #define doipcksum (G.doipcksum) | ||
372 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 293 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
373 | #define optlen (G.optlen ) | 294 | # define optlen (G.optlen ) |
374 | #endif | 295 | #endif |
375 | #define packet (G.packet ) | 296 | #define recv_pkt (G.recv_pkt ) |
376 | #define whereto (G.whereto ) | ||
377 | #define wherefrom (G.wherefrom) | ||
378 | #define gwlist (G.gwlist ) | 297 | #define gwlist (G.gwlist ) |
379 | #define INIT_G() do { \ | 298 | #define INIT_G() do { \ |
380 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ | 299 | SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ |
381 | maxpacket = 32 * 1024; \ | ||
382 | port = 32768 + 666; \ | 300 | port = 32768 + 666; \ |
383 | waittime = 5; \ | 301 | waittime = 5; \ |
384 | doipcksum = 1; \ | ||
385 | } while (0) | 302 | } while (0) |
386 | 303 | ||
304 | #define outicmp ((struct icmp *)(outip + 1)) | ||
305 | #define outudp ((struct udphdr *)(outip + 1)) | ||
387 | 306 | ||
388 | /* | ||
389 | * Return the interface list | ||
390 | */ | ||
391 | static int | ||
392 | ifaddrlist(struct IFADDRLIST **ipaddrp) | ||
393 | { | ||
394 | enum { IFREQ_BUFSIZE = (32 * 1024) / sizeof(struct ifreq) }; | ||
395 | |||
396 | int fd, nipaddr; | ||
397 | #ifdef HAVE_SOCKADDR_SA_LEN | ||
398 | int n; | ||
399 | #endif | ||
400 | struct ifreq *ifrp, *ifend, *ifnext; | ||
401 | struct sockaddr_in *addr_sin; | ||
402 | struct IFADDRLIST *al; | ||
403 | struct ifconf ifc; | ||
404 | struct ifreq ifr; | ||
405 | /* Was on stack, but 32k is a bit too much: */ | ||
406 | struct ifreq *ibuf = xmalloc(IFREQ_BUFSIZE * sizeof(ibuf[0])); | ||
407 | struct IFADDRLIST *st_ifaddrlist; | ||
408 | |||
409 | fd = xsocket(AF_INET, SOCK_DGRAM, 0); | ||
410 | |||
411 | ifc.ifc_len = IFREQ_BUFSIZE * sizeof(ibuf[0]); | ||
412 | ifc.ifc_buf = (caddr_t)ibuf; | ||
413 | |||
414 | if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 | ||
415 | || ifc.ifc_len < (int)sizeof(struct ifreq) | ||
416 | ) { | ||
417 | if (errno == EINVAL) | ||
418 | bb_error_msg_and_die( | ||
419 | "SIOCGIFCONF: ifreq struct too small (%u bytes)", | ||
420 | (unsigned)(IFREQ_BUFSIZE * sizeof(ibuf[0]))); | ||
421 | bb_perror_msg_and_die("SIOCGIFCONF"); | ||
422 | } | ||
423 | ifrp = ibuf; | ||
424 | ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len); | ||
425 | |||
426 | nipaddr = 1 + (ifc.ifc_len / sizeof(struct ifreq)); | ||
427 | st_ifaddrlist = xzalloc(nipaddr * sizeof(struct IFADDRLIST)); | ||
428 | al = st_ifaddrlist; | ||
429 | nipaddr = 0; | ||
430 | |||
431 | for (; ifrp < ifend; ifrp = ifnext) { | ||
432 | #ifdef HAVE_SOCKADDR_SA_LEN | ||
433 | n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name); | ||
434 | if (n < sizeof(*ifrp)) | ||
435 | ifnext = ifrp + 1; | ||
436 | else | ||
437 | ifnext = (struct ifreq *)((char *)ifrp + n); | ||
438 | if (ifrp->ifr_addr.sa_family != AF_INET) | ||
439 | continue; | ||
440 | #else | ||
441 | ifnext = ifrp + 1; | ||
442 | #endif | ||
443 | /* | ||
444 | * Need a template to preserve address info that is | ||
445 | * used below to locate the next entry. (Otherwise, | ||
446 | * SIOCGIFFLAGS stomps over it because the requests | ||
447 | * are returned in a union.) | ||
448 | */ | ||
449 | strncpy_IFNAMSIZ(ifr.ifr_name, ifrp->ifr_name); | ||
450 | if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) { | ||
451 | if (errno == ENXIO) | ||
452 | continue; | ||
453 | bb_perror_msg_and_die("SIOCGIFFLAGS: %.*s", | ||
454 | (int)sizeof(ifr.ifr_name), ifr.ifr_name); | ||
455 | } | ||
456 | |||
457 | /* Must be up */ | ||
458 | if ((ifr.ifr_flags & IFF_UP) == 0) | ||
459 | continue; | ||
460 | |||
461 | safe_strncpy(al->device, ifr.ifr_name, sizeof(ifr.ifr_name) + 1); | ||
462 | #ifdef sun | ||
463 | /* Ignore sun virtual interfaces */ | ||
464 | if (strchr(al->device, ':') != NULL) | ||
465 | continue; | ||
466 | #endif | ||
467 | ioctl_or_perror_and_die(fd, SIOCGIFADDR, (char *)&ifr, | ||
468 | "SIOCGIFADDR: %s", al->device); | ||
469 | |||
470 | addr_sin = (struct sockaddr_in *)&ifr.ifr_addr; | ||
471 | al->addr = addr_sin->sin_addr.s_addr; | ||
472 | ++al; | ||
473 | ++nipaddr; | ||
474 | } | ||
475 | if (nipaddr == 0) | ||
476 | bb_error_msg_and_die("can't find any network interfaces"); | ||
477 | |||
478 | free(ibuf); | ||
479 | close(fd); | ||
480 | *ipaddrp = st_ifaddrlist; | ||
481 | return nipaddr; | ||
482 | } | ||
483 | |||
484 | static void | ||
485 | setsin(struct sockaddr_in *addr_sin, uint32_t addr) | ||
486 | { | ||
487 | memset(addr_sin, 0, sizeof(*addr_sin)); | ||
488 | #ifdef HAVE_SOCKADDR_SA_LEN | ||
489 | addr_sin->sin_len = sizeof(*addr_sin); | ||
490 | #endif | ||
491 | addr_sin->sin_family = AF_INET; | ||
492 | addr_sin->sin_addr.s_addr = addr; | ||
493 | } | ||
494 | |||
495 | /* | ||
496 | * Return the source address for the given destination address | ||
497 | */ | ||
498 | static void | ||
499 | findsaddr(const struct sockaddr_in *to, struct sockaddr_in *from) | ||
500 | { | ||
501 | int i, n; | ||
502 | FILE *f; | ||
503 | uint32_t mask; | ||
504 | uint32_t dest, tmask; | ||
505 | struct IFADDRLIST *al; | ||
506 | char buf[256], tdevice[256], device[256]; | ||
507 | |||
508 | f = xfopen_for_read("/proc/net/route"); | ||
509 | |||
510 | /* Find the appropriate interface */ | ||
511 | n = 0; | ||
512 | mask = 0; | ||
513 | device[0] = '\0'; | ||
514 | while (fgets(buf, sizeof(buf), f) != NULL) { | ||
515 | ++n; | ||
516 | if (n == 1 && strncmp(buf, "Iface", 5) == 0) | ||
517 | continue; | ||
518 | i = sscanf(buf, "%255s %x %*s %*s %*s %*s %*s %x", | ||
519 | tdevice, &dest, &tmask); | ||
520 | if (i != 3) | ||
521 | bb_error_msg_and_die("junk in buffer"); | ||
522 | if ((to->sin_addr.s_addr & tmask) == dest | ||
523 | && (tmask > mask || mask == 0) | ||
524 | ) { | ||
525 | mask = tmask; | ||
526 | strcpy(device, tdevice); | ||
527 | } | ||
528 | } | ||
529 | fclose(f); | ||
530 | |||
531 | if (device[0] == '\0') | ||
532 | bb_error_msg_and_die("can't find interface"); | ||
533 | |||
534 | /* Get the interface address list */ | ||
535 | n = ifaddrlist(&al); | ||
536 | |||
537 | /* Find our appropriate source address */ | ||
538 | for (i = n; i > 0; --i, ++al) | ||
539 | if (strcmp(device, al->device) == 0) | ||
540 | break; | ||
541 | if (i <= 0) | ||
542 | bb_error_msg_and_die("can't find interface %s", device); | ||
543 | |||
544 | setsin(from, al->addr); | ||
545 | } | ||
546 | 307 | ||
547 | static int | 308 | static int |
548 | wait_for_reply(int sock, struct sockaddr_in *fromp) | 309 | wait_for_reply(struct sockaddr_in *fromp) |
549 | { | 310 | { |
550 | struct pollfd pfd[1]; | 311 | struct pollfd pfd[1]; |
551 | int cc = 0; | 312 | int cc = 0; |
552 | socklen_t fromlen = sizeof(*fromp); | 313 | socklen_t fromlen = sizeof(*fromp); |
553 | 314 | ||
554 | pfd[0].fd = sock; | 315 | pfd[0].fd = rcvsock; |
555 | pfd[0].events = POLLIN; | 316 | pfd[0].events = POLLIN; |
556 | if (safe_poll(pfd, 1, waittime * 1000) > 0) | 317 | if (safe_poll(pfd, 1, waittime * 1000) > 0) |
557 | cc = recvfrom(sock, packet, sizeof(packet), 0, | 318 | cc = recvfrom(rcvsock, recv_pkt, sizeof(recv_pkt), 0, |
558 | (struct sockaddr *)fromp, &fromlen); | 319 | (struct sockaddr *)fromp, &fromlen); |
559 | return cc; | 320 | return cc; |
560 | } | 321 | } |
@@ -595,22 +356,8 @@ in_cksum(uint16_t *addr, int len) | |||
595 | static void | 356 | static void |
596 | send_probe(int seq, int ttl) | 357 | send_probe(int seq, int ttl) |
597 | { | 358 | { |
598 | int cc; | 359 | int len, res; |
599 | struct udpiphdr *ui, *oui; | 360 | void *out; |
600 | struct ip tip; | ||
601 | |||
602 | outip->ip_ttl = ttl; | ||
603 | outip->ip_id = htons(ident + seq); | ||
604 | |||
605 | /* | ||
606 | * In most cases, the kernel will recalculate the ip checksum. | ||
607 | * But we must do it anyway so that the udp checksum comes out right. | ||
608 | */ | ||
609 | if (doipcksum) { | ||
610 | outip->ip_sum = in_cksum((uint16_t *)outip, sizeof(*outip) + optlen); | ||
611 | if (outip->ip_sum == 0) | ||
612 | outip->ip_sum = 0xffff; | ||
613 | } | ||
614 | 361 | ||
615 | /* Payload */ | 362 | /* Payload */ |
616 | outdata->seq = seq; | 363 | outdata->seq = seq; |
@@ -618,39 +365,15 @@ send_probe(int seq, int ttl) | |||
618 | // UNUSED: was storing gettimeofday's result there, but never ever checked it | 365 | // UNUSED: was storing gettimeofday's result there, but never ever checked it |
619 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ | 366 | /*memcpy(&outdata->tv, tp, sizeof(outdata->tv));*/ |
620 | 367 | ||
621 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | 368 | if (option_mask32 & OPT_USE_ICMP) { |
622 | if (useicmp) | ||
623 | outicmp->icmp_seq = htons(seq); | 369 | outicmp->icmp_seq = htons(seq); |
624 | else | ||
625 | #endif | ||
626 | outudp->dest = htons(port + seq); | ||
627 | 370 | ||
628 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | ||
629 | if (useicmp) { | ||
630 | /* Always calculate checksum for icmp packets */ | 371 | /* Always calculate checksum for icmp packets */ |
631 | outicmp->icmp_cksum = 0; | 372 | outicmp->icmp_cksum = 0; |
632 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, | 373 | outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, |
633 | packlen - (sizeof(*outip) + optlen)); | 374 | packlen - (sizeof(*outip) + optlen)); |
634 | if (outicmp->icmp_cksum == 0) | 375 | if (outicmp->icmp_cksum == 0) |
635 | outicmp->icmp_cksum = 0xffff; | 376 | outicmp->icmp_cksum = 0xffff; |
636 | } else | ||
637 | #endif | ||
638 | if (doipcksum) { | ||
639 | /* Checksum (we must save and restore ip header) */ | ||
640 | tip = *outip; | ||
641 | ui = (struct udpiphdr *)outip; | ||
642 | oui = (struct udpiphdr *)&tip; | ||
643 | /* Easier to zero and put back things that are ok */ | ||
644 | memset(ui, 0, sizeof(ui->ui_i)); | ||
645 | ui->ui_src = oui->ui_src; | ||
646 | ui->ui_dst = oui->ui_dst; | ||
647 | ui->ui_pr = oui->ui_pr; | ||
648 | ui->ui_len = outudp->len; | ||
649 | outudp->check = 0; | ||
650 | outudp->check = in_cksum((uint16_t *)ui, packlen); | ||
651 | if (outudp->check == 0) | ||
652 | outudp->check = 0xffff; | ||
653 | *outip = tip; | ||
654 | } | 377 | } |
655 | 378 | ||
656 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! | 379 | //BUG! verbose is (x & OPT_VERBOSE), not a counter! |
@@ -679,17 +402,25 @@ send_probe(int seq, int ttl) | |||
679 | } | 402 | } |
680 | #endif | 403 | #endif |
681 | 404 | ||
682 | #if !defined(IP_HDRINCL) && defined(IP_TTL) | 405 | #if defined(IP_TTL) |
683 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, | 406 | if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, |
684 | (char *)&ttl, sizeof(ttl)) < 0) { | 407 | (char *)&ttl, sizeof(ttl)) < 0) { |
685 | bb_perror_msg_and_die("setsockopt ttl %d", ttl); | 408 | bb_perror_msg_and_die("setsockopt ttl %d", ttl); |
686 | } | 409 | } |
687 | #endif | 410 | #endif |
688 | 411 | ||
689 | cc = xsendto(sndsock, outip, packlen, | 412 | len = packlen - sizeof(*outip); |
690 | (struct sockaddr *)&whereto, sizeof(whereto)); | 413 | if (option_mask32 & OPT_USE_ICMP) |
691 | if (cc != packlen) { | 414 | out = outicmp; |
692 | bb_info_msg("sent %s %d octets, ret=%d", hostname, packlen, cc); | 415 | else { |
416 | out = outdata; | ||
417 | len -= sizeof(*outudp); | ||
418 | set_nport(dest_lsa, htons(port + seq)); | ||
419 | } | ||
420 | res = xsendto(sndsock, out, len, | ||
421 | (struct sockaddr *)&dest_lsa->u.sa, dest_lsa->len); | ||
422 | if (res != len) { | ||
423 | bb_info_msg("sent %d octets, ret=%d", len, res); | ||
693 | } | 424 | } |
694 | } | 425 | } |
695 | 426 | ||
@@ -716,18 +447,18 @@ pr_type(unsigned char t) | |||
716 | #endif | 447 | #endif |
717 | 448 | ||
718 | #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE | 449 | #if !ENABLE_FEATURE_TRACEROUTE_VERBOSE |
719 | #define packet_ok(buf, cc, from, seq) \ | 450 | #define packet_ok(cc, from, seq) \ |
720 | packet_ok(buf, cc, seq) | 451 | packet_ok(cc, seq) |
721 | #endif | 452 | #endif |
722 | static int | 453 | static int |
723 | packet_ok(const unsigned char *buf, int cc, const struct sockaddr_in *from, int seq) | 454 | packet_ok(int cc, const struct sockaddr_in *from, int seq) |
724 | { | 455 | { |
725 | const struct icmp *icp; | 456 | const struct icmp *icp; |
726 | unsigned char type, code; | 457 | unsigned char type, code; |
727 | int hlen; | 458 | int hlen; |
728 | const struct ip *ip; | 459 | const struct ip *ip; |
729 | 460 | ||
730 | ip = (struct ip *) buf; | 461 | ip = (struct ip *) recv_pkt; |
731 | hlen = ip->ip_hl << 2; | 462 | hlen = ip->ip_hl << 2; |
732 | if (cc < hlen + ICMP_MINLEN) { | 463 | if (cc < hlen + ICMP_MINLEN) { |
733 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE | 464 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE |
@@ -738,7 +469,7 @@ packet_ok(const unsigned char *buf, int cc, const struct sockaddr_in *from, int | |||
738 | return 0; | 469 | return 0; |
739 | } | 470 | } |
740 | cc -= hlen; | 471 | cc -= hlen; |
741 | icp = (struct icmp *)(buf + hlen); | 472 | icp = (struct icmp *)(recv_pkt + hlen); |
742 | type = icp->icmp_type; | 473 | type = icp->icmp_type; |
743 | code = icp->icmp_code; | 474 | code = icp->icmp_code; |
744 | /* Path MTU Discovery (RFC1191) */ | 475 | /* Path MTU Discovery (RFC1191) */ |
@@ -755,33 +486,37 @@ packet_ok(const unsigned char *buf, int cc, const struct sockaddr_in *from, int | |||
755 | 486 | ||
756 | hip = &icp->icmp_ip; | 487 | hip = &icp->icmp_ip; |
757 | hlen = hip->ip_hl << 2; | 488 | hlen = hip->ip_hl << 2; |
758 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | 489 | if (option_mask32 & OPT_USE_ICMP) { |
759 | if (useicmp) { | ||
760 | struct icmp *hicmp; | 490 | struct icmp *hicmp; |
761 | 491 | ||
762 | /* XXX */ | 492 | /* XXX */ |
763 | if (type == ICMP_ECHOREPLY && | 493 | if (type == ICMP_ECHOREPLY |
764 | icp->icmp_id == htons(ident) && | 494 | && icp->icmp_id == htons(ident) |
765 | icp->icmp_seq == htons(seq)) | 495 | && icp->icmp_seq == htons(seq) |
496 | ) { | ||
766 | return -2; | 497 | return -2; |
498 | } | ||
767 | 499 | ||
768 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); | 500 | hicmp = (struct icmp *)((unsigned char *)hip + hlen); |
769 | /* XXX 8 is a magic number */ | 501 | if (hlen + SIZEOF_ICMP_HDR <= cc |
770 | if (hlen + 8 <= cc && | 502 | && hip->ip_p == IPPROTO_ICMP |
771 | hip->ip_p == IPPROTO_ICMP && | 503 | && hicmp->icmp_id == htons(ident) |
772 | hicmp->icmp_id == htons(ident) && | 504 | && hicmp->icmp_seq == htons(seq) |
773 | hicmp->icmp_seq == htons(seq)) | 505 | ) { |
774 | return (type == ICMP_TIMXCEED ? -1 : code + 1); | 506 | return (type == ICMP_TIMXCEED ? -1 : code + 1); |
775 | } else | 507 | } |
776 | #endif | 508 | } else { |
777 | { | 509 | up = (struct udphdr *)((char *)hip + hlen); |
778 | up = (struct udphdr *)((unsigned char *)hip + hlen); | 510 | if (hlen + 12 <= cc |
779 | /* XXX 8 is a magic number */ | 511 | && hip->ip_p == IPPROTO_UDP |
780 | if (hlen + 12 <= cc && | 512 | // Off: since we do not form the entire IP packet, |
781 | hip->ip_p == IPPROTO_UDP && | 513 | // but defer it to kernel, we can't set source port, |
782 | up->source == htons(ident) && | 514 | // and thus can't check it here in the reply |
783 | up->dest == htons(port + seq)) | 515 | /* && up->source == htons(ident) */ |
516 | && up->dest == htons(port + seq) | ||
517 | ) { | ||
784 | return (type == ICMP_TIMXCEED ? -1 : code + 1); | 518 | return (type == ICMP_TIMXCEED ? -1 : code + 1); |
519 | } | ||
785 | } | 520 | } |
786 | } | 521 | } |
787 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE | 522 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE |
@@ -812,85 +547,31 @@ print_inetname(const struct sockaddr_in *from) | |||
812 | const char *ina; | 547 | const char *ina; |
813 | 548 | ||
814 | ina = inet_ntoa(from->sin_addr); | 549 | ina = inet_ntoa(from->sin_addr); |
815 | if (nflag) | 550 | if (option_mask32 & OPT_ADDR_NUM) |
816 | printf(" %s", ina); | 551 | printf(" %s", ina); |
817 | else { | 552 | else { |
818 | char *n = NULL; | 553 | char *n = NULL; |
819 | if (from->sin_addr.s_addr != INADDR_ANY) | 554 | if (from->sin_addr.s_addr != INADDR_ANY) |
820 | n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); | 555 | n = xmalloc_sockaddr2host_noport((struct sockaddr*)from); |
821 | printf(" %s (%s)", (n ? n : ina), ina); | 556 | printf(" %s (%s)", (n ? n : ina), ina); |
822 | free(n); | 557 | free(n); |
823 | } | 558 | } |
824 | } | 559 | } |
825 | 560 | ||
826 | static void | 561 | static void |
827 | print(const unsigned char *buf, int cc, const struct sockaddr_in *from) | 562 | print(int cc, const struct sockaddr_in *from) |
828 | { | 563 | { |
829 | const struct ip *ip; | ||
830 | int hlen; | ||
831 | |||
832 | ip = (struct ip *) buf; | ||
833 | hlen = ip->ip_hl << 2; | ||
834 | cc -= hlen; | ||
835 | |||
836 | print_inetname(from); | 564 | print_inetname(from); |
837 | #if ENABLE_FEATURE_TRACEROUTE_VERBOSE | 565 | if (verbose) { |
838 | if (verbose) | 566 | const struct ip *ip; |
839 | printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); | 567 | int hlen; |
840 | #endif | ||
841 | } | ||
842 | 568 | ||
843 | static struct hostinfo * | 569 | ip = (struct ip *) recv_pkt; |
844 | gethostinfo(const char *host) | 570 | hlen = ip->ip_hl << 2; |
845 | { | 571 | cc -= hlen; |
846 | int n; | 572 | printf(" %d bytes to %s", cc, inet_ntoa(ip->ip_dst)); |
847 | struct hostent *hp; | ||
848 | struct hostinfo *hi; | ||
849 | char **p; | ||
850 | uint32_t addr, *ap; | ||
851 | |||
852 | hi = xzalloc(sizeof(*hi)); | ||
853 | addr = inet_addr(host); | ||
854 | if (addr != 0xffffffff) { | ||
855 | hi->name = xstrdup(host); | ||
856 | hi->n = 1; | ||
857 | hi->addrs = xzalloc(sizeof(hi->addrs[0])); | ||
858 | hi->addrs[0] = addr; | ||
859 | return hi; | ||
860 | } | 573 | } |
861 | |||
862 | hp = xgethostbyname(host); | ||
863 | if (hp->h_addrtype != AF_INET || hp->h_length != 4) | ||
864 | bb_perror_msg_and_die("bad host %s", host); | ||
865 | hi->name = xstrdup(hp->h_name); | ||
866 | for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) | ||
867 | continue; | ||
868 | hi->n = n; | ||
869 | hi->addrs = xzalloc(n * sizeof(hi->addrs[0])); | ||
870 | for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) | ||
871 | memcpy(ap, *p, sizeof(*ap)); | ||
872 | return hi; | ||
873 | } | ||
874 | |||
875 | static void | ||
876 | freehostinfo(struct hostinfo *hi) | ||
877 | { | ||
878 | free(hi->name); | ||
879 | free(hi->addrs); | ||
880 | free(hi); | ||
881 | } | ||
882 | |||
883 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | ||
884 | static void | ||
885 | getaddr(uint32_t *ap, const char *host) | ||
886 | { | ||
887 | struct hostinfo *hi; | ||
888 | |||
889 | hi = gethostinfo(host); | ||
890 | *ap = hi->addrs[0]; | ||
891 | freehostinfo(hi); | ||
892 | } | 574 | } |
893 | #endif | ||
894 | 575 | ||
895 | static void | 576 | static void |
896 | print_delta_ms(unsigned t1p, unsigned t2p) | 577 | print_delta_ms(unsigned t1p, unsigned t2p) |
@@ -900,46 +581,38 @@ print_delta_ms(unsigned t1p, unsigned t2p) | |||
900 | } | 581 | } |
901 | 582 | ||
902 | /* | 583 | /* |
903 | "Usage: %s [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl]\n" | 584 | Usage: [-dFIlnrvx] [-g gateway] [-i iface] [-f first_ttl] |
904 | "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n" | 585 | [-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos] |
905 | "\t[-w waittime] [-z pausemsecs] host [packetlen]" | 586 | [-w waittime] [-z pausemsecs] host [packetlen]" |
906 | */ | 587 | */ |
907 | 588 | ||
908 | int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 589 | int traceroute_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
909 | int traceroute_main(int argc, char **argv) | 590 | int traceroute_main(int argc, char **argv) |
910 | { | 591 | { |
911 | unsigned char *outp; | 592 | int minpacket; |
912 | struct sockaddr_in *from; | 593 | int ttl, i; |
913 | struct sockaddr_in *to; | ||
914 | struct hostinfo *hi; | ||
915 | int ttl, probe, i; | ||
916 | int seq = 0; | 594 | int seq = 0; |
917 | int tos = 0; | 595 | int tos = 0; |
918 | char *tos_str; | 596 | int max_ttl = 30; |
919 | char *source; | 597 | int nprobes = 3; |
598 | int first_ttl = 1; | ||
599 | unsigned pausemsecs = 0; | ||
920 | unsigned op; | 600 | unsigned op; |
921 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 601 | char *source; |
922 | int lsrr = 0; | ||
923 | #endif | ||
924 | struct IFADDRLIST *al; | ||
925 | char *device; | 602 | char *device; |
926 | int max_ttl = 30; | 603 | char *tos_str; |
927 | char *max_ttl_str; | 604 | char *max_ttl_str; |
928 | char *port_str; | 605 | char *port_str; |
929 | int nprobes = 3; | ||
930 | char *nprobes_str; | 606 | char *nprobes_str; |
931 | char *waittime_str; | 607 | char *waittime_str; |
932 | unsigned pausemsecs = 0; | ||
933 | char *pausemsecs_str; | 608 | char *pausemsecs_str; |
934 | int first_ttl = 1; | ||
935 | char *first_ttl_str; | 609 | char *first_ttl_str; |
936 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 610 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
937 | llist_t *source_route_list = NULL; | 611 | llist_t *source_route_list = NULL; |
612 | int lsrr = 0; | ||
938 | #endif | 613 | #endif |
939 | 614 | ||
940 | INIT_G(); | 615 | INIT_G(); |
941 | from = (struct sockaddr_in *)&wherefrom; | ||
942 | to = (struct sockaddr_in *)&whereto; | ||
943 | 616 | ||
944 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 617 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
945 | opt_complementary = "x-x:g::"; | 618 | opt_complementary = "x-x:g::"; |
@@ -958,10 +631,10 @@ int traceroute_main(int argc, char **argv) | |||
958 | #endif | 631 | #endif |
959 | ); | 632 | ); |
960 | 633 | ||
961 | if (op & OPT_IP_CHKSUM) { | 634 | #if 0 /* IGNORED */ |
962 | doipcksum = 0; | 635 | if (op & OPT_IP_CHKSUM) |
963 | bb_error_msg("warning: ip checksums disabled"); | 636 | bb_error_msg("warning: ip checksums disabled"); |
964 | } | 637 | #endif |
965 | if (op & OPT_TOS) | 638 | if (op & OPT_TOS) |
966 | tos = xatou_range(tos_str, 0, 255); | 639 | tos = xatou_range(tos_str, 0, 255); |
967 | if (op & OPT_MAX_TTL) | 640 | if (op & OPT_MAX_TTL) |
@@ -988,42 +661,33 @@ int traceroute_main(int argc, char **argv) | |||
988 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 661 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
989 | if (source_route_list) { | 662 | if (source_route_list) { |
990 | while (source_route_list) { | 663 | while (source_route_list) { |
664 | len_and_sockaddr *lsa; | ||
665 | |||
991 | if (lsrr >= NGATEWAYS) | 666 | if (lsrr >= NGATEWAYS) |
992 | bb_error_msg_and_die("no more than %d gateways", NGATEWAYS); | 667 | bb_error_msg_and_die("no more than %d gateways", NGATEWAYS); |
993 | getaddr(gwlist + lsrr, llist_pop(&source_route_list)); | 668 | lsa = xhost_and_af2sockaddr(llist_pop(&source_route_list), 0, AF_INET); |
669 | gwlist[lsrr] = lsa->u.sin.sin_addr.s_addr; | ||
670 | free(lsa); | ||
994 | ++lsrr; | 671 | ++lsrr; |
995 | } | 672 | } |
996 | optlen = (lsrr + 1) * sizeof(gwlist[0]); | 673 | optlen = (lsrr + 1) * sizeof(gwlist[0]); |
997 | } | 674 | } |
998 | #endif | 675 | #endif |
999 | 676 | ||
1000 | minpacket = sizeof(*outip) + sizeof(*outdata) + optlen; | 677 | minpacket = sizeof(*outip) + SIZEOF_ICMP_HDR + sizeof(*outdata) + optlen; |
1001 | 678 | if (!(op & OPT_USE_ICMP)) | |
1002 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | 679 | minpacket += sizeof(*outudp) - SIZEOF_ICMP_HDR; |
1003 | if (useicmp) | 680 | packlen = minpacket; |
1004 | minpacket += 8; /* XXX magic number */ | ||
1005 | else | ||
1006 | #endif | ||
1007 | minpacket += sizeof(*outudp); | ||
1008 | packlen = minpacket; /* minimum sized packet */ | ||
1009 | 681 | ||
1010 | /* Process destination and optional packet size */ | 682 | /* Process destination and optional packet size */ |
1011 | argv += optind; | 683 | argv += optind; |
1012 | argc -= optind; | 684 | argc -= optind; |
1013 | switch (argc) { | 685 | switch (argc) { |
1014 | case 2: | 686 | case 2: |
1015 | packlen = xatoul_range(argv[1], minpacket, maxpacket); | 687 | packlen = xatoul_range(argv[1], minpacket, 32 * 1024); |
1016 | /* Fall through */ | 688 | /* Fall through */ |
1017 | case 1: | 689 | case 1: |
1018 | hostname = argv[0]; | 690 | dest_lsa = xhost2sockaddr(argv[0], port); |
1019 | hi = gethostinfo(hostname); | ||
1020 | setsin(to, hi->addrs[0]); | ||
1021 | if (hi->n > 1) | ||
1022 | bb_error_msg("warning: %s has multiple addresses; using %s", | ||
1023 | hostname, inet_ntoa(to->sin_addr)); | ||
1024 | hostname = hi->name; | ||
1025 | hi->name = NULL; | ||
1026 | freehostinfo(hi); | ||
1027 | break; | 691 | break; |
1028 | default: | 692 | default: |
1029 | bb_show_usage(); | 693 | bb_show_usage(); |
@@ -1032,8 +696,7 @@ int traceroute_main(int argc, char **argv) | |||
1032 | /* Ensure the socket fds won't be 0, 1 or 2 */ | 696 | /* Ensure the socket fds won't be 0, 1 or 2 */ |
1033 | bb_sanitize_stdio(); | 697 | bb_sanitize_stdio(); |
1034 | 698 | ||
1035 | rcvsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP); | 699 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), rcvsock); |
1036 | |||
1037 | #if TRACEROUTE_SO_DEBUG | 700 | #if TRACEROUTE_SO_DEBUG |
1038 | if (op & OPT_DEBUG) | 701 | if (op & OPT_DEBUG) |
1039 | setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, | 702 | setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG, |
@@ -1043,15 +706,17 @@ int traceroute_main(int argc, char **argv) | |||
1043 | setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, | 706 | setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE, |
1044 | &const_int_1, sizeof(const_int_1)); | 707 | &const_int_1, sizeof(const_int_1)); |
1045 | 708 | ||
1046 | sndsock = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); | 709 | if (op & OPT_USE_ICMP) |
1047 | 710 | xmove_fd(xsocket(AF_INET, SOCK_RAW, IPPROTO_ICMP), sndsock); | |
711 | else | ||
712 | xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sndsock); | ||
1048 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE | 713 | #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE |
1049 | #if defined(IP_OPTIONS) | 714 | #if defined(IP_OPTIONS) |
1050 | if (lsrr > 0) { | 715 | if (lsrr > 0) { |
1051 | unsigned char optlist[MAX_IPOPTLEN]; | 716 | unsigned char optlist[MAX_IPOPTLEN]; |
1052 | 717 | ||
1053 | /* final hop */ | 718 | /* final hop */ |
1054 | gwlist[lsrr] = to->sin_addr.s_addr; | 719 | gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; |
1055 | ++lsrr; | 720 | ++lsrr; |
1056 | 721 | ||
1057 | /* force 4 byte alignment */ | 722 | /* force 4 byte alignment */ |
@@ -1071,24 +736,20 @@ int traceroute_main(int argc, char **argv) | |||
1071 | } | 736 | } |
1072 | #endif /* IP_OPTIONS */ | 737 | #endif /* IP_OPTIONS */ |
1073 | #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */ | 738 | #endif /* CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE */ |
1074 | |||
1075 | #ifdef SO_SNDBUF | 739 | #ifdef SO_SNDBUF |
1076 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { | 740 | if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, &packlen, sizeof(packlen)) < 0) { |
1077 | bb_perror_msg_and_die("SO_SNDBUF"); | 741 | bb_perror_msg_and_die("SO_SNDBUF"); |
1078 | } | 742 | } |
1079 | #endif | 743 | #endif |
1080 | #ifdef IP_HDRINCL | ||
1081 | if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, &const_int_1, sizeof(const_int_1)) < 0 | ||
1082 | && errno != ENOPROTOOPT | ||
1083 | ) { | ||
1084 | bb_perror_msg_and_die("IP_HDRINCL"); | ||
1085 | } | ||
1086 | #else | ||
1087 | #ifdef IP_TOS | 744 | #ifdef IP_TOS |
1088 | if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { | 745 | if ((op & OPT_TOS) && setsockopt(sndsock, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) < 0) { |
1089 | bb_perror_msg_and_die("setsockopt tos %d", tos); | 746 | bb_perror_msg_and_die("setsockopt tos %d", tos); |
1090 | } | 747 | } |
1091 | #endif | 748 | #endif |
749 | #ifdef IP_DONTFRAG | ||
750 | if (op & OPT_DONT_FRAGMNT) | ||
751 | setsockopt(sndsock, IPPROTO_IP, IP_DONTFRAG, | ||
752 | &const_int_1, sizeof(const_int_1)); | ||
1092 | #endif | 753 | #endif |
1093 | #if TRACEROUTE_SO_DEBUG | 754 | #if TRACEROUTE_SO_DEBUG |
1094 | if (op & OPT_DEBUG) | 755 | if (op & OPT_DEBUG) |
@@ -1099,136 +760,82 @@ int traceroute_main(int argc, char **argv) | |||
1099 | setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, | 760 | setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, |
1100 | &const_int_1, sizeof(const_int_1)); | 761 | &const_int_1, sizeof(const_int_1)); |
1101 | 762 | ||
1102 | /* Revert to non-privileged user after opening sockets */ | ||
1103 | xsetgid(getgid()); | ||
1104 | xsetuid(getuid()); | ||
1105 | |||
1106 | outip = xzalloc(packlen); | 763 | outip = xzalloc(packlen); |
1107 | 764 | ||
1108 | outip->ip_v = IPVERSION; | 765 | if (op & OPT_USE_ICMP) { |
1109 | if (op & OPT_TOS) | 766 | ident = getpid() | 0x8000; |
1110 | outip->ip_tos = tos; | ||
1111 | outip->ip_len = htons(packlen); | ||
1112 | if (op & OPT_DONT_FRAGMNT) | ||
1113 | outip->ip_off = htons(IP_DF); | ||
1114 | outp = (unsigned char *)(outip + 1); | ||
1115 | outip->ip_dst = to->sin_addr; | ||
1116 | |||
1117 | outip->ip_hl = (outp - (unsigned char *)outip) >> 2; | ||
1118 | ident = (getpid() & 0xffff) | 0x8000; | ||
1119 | #if ENABLE_FEATURE_TRACEROUTE_USE_ICMP | ||
1120 | if (useicmp) { | ||
1121 | outip->ip_p = IPPROTO_ICMP; | ||
1122 | outicmp = (struct icmp *)outp; | ||
1123 | outicmp->icmp_type = ICMP_ECHO; | 767 | outicmp->icmp_type = ICMP_ECHO; |
1124 | outicmp->icmp_id = htons(ident); | 768 | outicmp->icmp_id = htons(ident); |
1125 | outdata = (outdata_t *)(outp + 8); /* XXX magic number */ | 769 | outdata = (struct outdata_t *)((char *)outicmp + SIZEOF_ICMP_HDR); |
1126 | } else | 770 | } else { |
1127 | #endif | 771 | outdata = (struct outdata_t *)(outudp + 1); |
1128 | { | ||
1129 | outip->ip_p = IPPROTO_UDP; | ||
1130 | outudp = (struct udphdr *)outp; | ||
1131 | outudp->source = htons(ident); | ||
1132 | outudp->len = htons((uint16_t)(packlen - (sizeof(*outip) + optlen))); | ||
1133 | outdata = (outdata_t *)(outudp + 1); | ||
1134 | } | 772 | } |
1135 | 773 | ||
1136 | /* Look for a specific device */ | 774 | if (op & OPT_DEVICE) /* hmm, do we need error check? */ |
1137 | if (op & OPT_DEVICE) { | 775 | setsockopt_bindtodevice(sndsock, device); |
1138 | /* Get the interface address list */ | ||
1139 | int n = ifaddrlist(&al); | ||
1140 | for (; n > 0; --n, ++al) | ||
1141 | if (strcmp(device, al->device) == 0) | ||
1142 | goto found_dev; | ||
1143 | bb_error_msg_and_die("can't find interface %s", device); | ||
1144 | } | ||
1145 | found_dev: | ||
1146 | 776 | ||
1147 | /* Determine our source address */ | 777 | if (op & OPT_SOURCE) { |
1148 | if (!(op & OPT_SOURCE)) { | 778 | len_and_sockaddr *source_lsa = xdotted2sockaddr(source, 0); |
1149 | /* | 779 | /* Ping does this (why?) */ |
1150 | * If a device was specified, use the interface address. | 780 | if (setsockopt(sndsock, IPPROTO_IP, IP_MULTICAST_IF, |
1151 | * Otherwise, try to determine our source address. | 781 | &source_lsa->u.sa, source_lsa->len)) |
1152 | */ | 782 | bb_error_msg_and_die("can't set multicast source interface"); |
1153 | if (op & OPT_DEVICE) | 783 | //TODO: we can query source port we bound to, |
1154 | setsin(from, al->addr); | 784 | // and check it in replies... if we care enough |
1155 | findsaddr(to, from); | 785 | xbind(sndsock, &source_lsa->u.sa, source_lsa->len); |
1156 | } else { | 786 | free(source_lsa); |
1157 | hi = gethostinfo(source); | ||
1158 | source = hi->name; | ||
1159 | hi->name = NULL; | ||
1160 | /* | ||
1161 | * If the device was specified make sure it | ||
1162 | * corresponds to the source address specified. | ||
1163 | * Otherwise, use the first address (and warn if | ||
1164 | * there are more than one). | ||
1165 | */ | ||
1166 | if (op & OPT_DEVICE) { | ||
1167 | uint32_t *ap; | ||
1168 | for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) | ||
1169 | if (*ap == al->addr) | ||
1170 | goto found_dev2; | ||
1171 | bb_error_msg_and_die("%s is not on interface %s", | ||
1172 | source, device); | ||
1173 | found_dev2: | ||
1174 | setsin(from, *ap); | ||
1175 | } else { | ||
1176 | setsin(from, hi->addrs[0]); | ||
1177 | if (hi->n > 1) | ||
1178 | bb_error_msg( | ||
1179 | "warning: %s has multiple addresses; using %s", | ||
1180 | source, inet_ntoa(from->sin_addr)); | ||
1181 | } | ||
1182 | freehostinfo(hi); | ||
1183 | } | 787 | } |
1184 | 788 | ||
1185 | outip->ip_src = from->sin_addr; | 789 | /* Revert to non-privileged user after opening sockets */ |
1186 | #ifndef IP_HDRINCL | 790 | xsetgid(getgid()); |
1187 | xbind(sndsock, (struct sockaddr *)from, sizeof(*from)); | 791 | xsetuid(getuid()); |
1188 | #endif | ||
1189 | 792 | ||
1190 | printf("traceroute to %s (%s)", hostname, inet_ntoa(to->sin_addr)); | 793 | printf("traceroute to %s (%s)", argv[0], |
794 | xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa)); | ||
1191 | if (op & OPT_SOURCE) | 795 | if (op & OPT_SOURCE) |
1192 | printf(" from %s", source); | 796 | printf(" from %s", source); |
1193 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); | 797 | printf(", %d hops max, %d byte packets\n", max_ttl, packlen); |
1194 | 798 | ||
1195 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { | 799 | for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { |
800 | //TODO: make it protocol agnostic (get rid of sockaddr_in) | ||
801 | struct sockaddr_in from; | ||
1196 | uint32_t lastaddr = 0; | 802 | uint32_t lastaddr = 0; |
1197 | int gotlastaddr = 0; | 803 | int probe; |
804 | int unreachable = 0; /* counter */ | ||
805 | int gotlastaddr = 0; /* flags */ | ||
1198 | int got_there = 0; | 806 | int got_there = 0; |
1199 | int unreachable = 0; | 807 | int first = 1; |
1200 | int sentfirst = 0; | ||
1201 | 808 | ||
1202 | printf("%2d ", ttl); | 809 | printf("%2d", ttl); |
1203 | for (probe = 0; probe < nprobes; ++probe) { | 810 | for (probe = 0; probe < nprobes; ++probe) { |
1204 | int cc; | 811 | int cc; |
1205 | unsigned t1; | 812 | unsigned t1; |
1206 | unsigned t2; | 813 | unsigned t2; |
1207 | struct ip *ip; | 814 | struct ip *ip; |
1208 | 815 | ||
1209 | if (sentfirst && pausemsecs > 0) | 816 | if (!first && pausemsecs > 0) |
1210 | usleep(pausemsecs * 1000); | 817 | usleep(pausemsecs * 1000); |
1211 | fflush(stdout); | 818 | fflush(stdout); |
1212 | 819 | ||
1213 | t1 = monotonic_us(); | 820 | t1 = monotonic_us(); |
1214 | send_probe(++seq, ttl); | 821 | send_probe(++seq, ttl); |
1215 | ++sentfirst; | 822 | first = 0; |
1216 | 823 | ||
1217 | while ((cc = wait_for_reply(rcvsock, from)) != 0) { | 824 | while ((cc = wait_for_reply(&from)) != 0) { |
1218 | t2 = monotonic_us(); | 825 | t2 = monotonic_us(); |
1219 | i = packet_ok(packet, cc, from, seq); | 826 | i = packet_ok(cc, &from, seq); |
1220 | /* Skip short packet */ | 827 | /* Skip short packet */ |
1221 | if (i == 0) | 828 | if (i == 0) |
1222 | continue; | 829 | continue; |
1223 | if (!gotlastaddr | 830 | if (!gotlastaddr |
1224 | || from->sin_addr.s_addr != lastaddr | 831 | || from.sin_addr.s_addr != lastaddr |
1225 | ) { | 832 | ) { |
1226 | print(packet, cc, from); | 833 | print(cc, &from); |
1227 | lastaddr = from->sin_addr.s_addr; | 834 | lastaddr = from.sin_addr.s_addr; |
1228 | ++gotlastaddr; | 835 | gotlastaddr = 1; |
1229 | } | 836 | } |
1230 | print_delta_ms(t1, t2); | 837 | print_delta_ms(t1, t2); |
1231 | ip = (struct ip *)packet; | 838 | ip = (struct ip *)recv_pkt; |
1232 | if (op & OPT_TTL_FLAG) | 839 | if (op & OPT_TTL_FLAG) |
1233 | printf(" (%d)", ip->ip_ttl); | 840 | printf(" (%d)", ip->ip_ttl); |
1234 | if (i == -2) { | 841 | if (i == -2) { |