traceroute.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*-
  2. * Copyright (c) 1990, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * This code is derived from software contributed to Berkeley by
  6. * Van Jacobson.
  7. *
  8. * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the University nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. /*
  34. * traceroute host - trace the route ip packets follow going to "host".
  35. * Notes
  36. * -----
  37. * This program must be run by root or be setuid. (I suggest that
  38. * you *don't* make it setuid -- casual use could result in a lot
  39. * of unnecessary traffic on our poor, congested nets.)
  40. *
  41. * I stole the idea for this program from Steve Deering. Since
  42. * the first release, I've learned that had I attended the right
  43. * IETF working group meetings, I also could have stolen it from Guy
  44. * Almes or Matt Mathis. I don't know (or care) who came up with
  45. * the idea first. I envy the originators' perspicacity and I'm
  46. * glad they didn't keep the idea a secret.
  47. *
  48. * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
  49. * enhancements to the original distribution.
  50. *
  51. * I've hacked up a round-trip-route version of this that works by
  52. * sending a loose-source-routed udp datagram through the destination
  53. * back to yourself. Unfortunately, SO many gateways botch source
  54. * routing, the thing is almost worthless. Maybe one day...
  55. *
  56. * -- Van Jacobson (van@helios.ee.lbl.gov)
  57. * Tue Dec 20 03:50:13 PST 1988
  58. */
  59. #undef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  60. //#define CONFIG_FEATURE_TRACEROUTE_VERBOSE
  61. #undef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG /* not in documentation man */
  62. #include <stdio.h>
  63. #include <errno.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66. #include <unistd.h>
  67. #include <sys/time.h>
  68. #include "inet_common.h"
  69. #include <netdb.h>
  70. #include <endian.h>
  71. #include <netinet/udp.h>
  72. #include <netinet/ip.h>
  73. #include <netinet/ip_icmp.h>
  74. #define MAXPACKET 65535 /* max ip packet size */
  75. #ifndef MAXHOSTNAMELEN
  76. #define MAXHOSTNAMELEN 64
  77. #endif
  78. /*
  79. * format of a (udp) probe packet.
  80. */
  81. struct opacket {
  82. struct ip ip;
  83. struct udphdr udp;
  84. u_char seq; /* sequence number of this packet */
  85. u_char ttl; /* ttl packet left with */
  86. struct timeval tv; /* time packet left */
  87. };
  88. /*
  89. * Definitions for internet protocol version 4.
  90. * Per RFC 791, September 1981.
  91. */
  92. #define IPVERSION 4
  93. #include "busybox.h"
  94. /* last inbound (icmp) packet */
  95. static u_char packet[512] __attribute__ ((aligned));
  96. static struct opacket *outpacket; /* last output (udp) packet */
  97. static int s; /* receive (icmp) socket file descriptor */
  98. static int sndsock; /* send (udp) socket file descriptor */
  99. static struct sockaddr whereto; /* Who to try to reach */
  100. static int datalen; /* How much data */
  101. static char *hostname;
  102. static int max_ttl = 30;
  103. static u_short ident;
  104. static u_short port = 32768+666; /* start udp dest port # for probe packets */
  105. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  106. static int verbose;
  107. #endif
  108. static int waittime = 5; /* time to wait for response (in seconds) */
  109. static int nflag; /* print addresses numerically */
  110. /*
  111. * Construct an Internet address representation.
  112. * If the nflag has been supplied, give
  113. * numeric value, otherwise try for symbolic name.
  114. */
  115. static inline void
  116. inetname(struct sockaddr_in *from)
  117. {
  118. char *cp;
  119. static char domain[MAXHOSTNAMELEN + 1];
  120. char name[MAXHOSTNAMELEN + 1];
  121. static int first = 1;
  122. const char *ina;
  123. if (first && !nflag) {
  124. first = 0;
  125. if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
  126. domain[0] = 0;
  127. }
  128. cp = 0;
  129. if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
  130. if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
  131. if ((cp = strchr(name, '.')) &&
  132. !strcmp(cp + 1, domain))
  133. *cp = 0;
  134. cp = (char *)name;
  135. }
  136. }
  137. ina = inet_ntoa(from->sin_addr);
  138. if (nflag)
  139. printf(" %s", ina);
  140. else
  141. printf(" %s (%s)", (cp ? cp : ina), ina);
  142. }
  143. static inline void
  144. print(u_char *buf, int cc, struct sockaddr_in *from)
  145. {
  146. struct ip *ip;
  147. int hlen;
  148. ip = (struct ip *) buf;
  149. hlen = ip->ip_hl << 2;
  150. cc -= hlen;
  151. inetname(from);
  152. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  153. if (verbose)
  154. printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
  155. #endif
  156. }
  157. static inline double
  158. deltaT(struct timeval *t1p, struct timeval *t2p)
  159. {
  160. double dt;
  161. dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
  162. (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
  163. return (dt);
  164. }
  165. static inline int
  166. wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
  167. {
  168. fd_set fds;
  169. static struct timeval wait;
  170. int cc = 0;
  171. int fromlen = sizeof (*from);
  172. FD_ZERO(&fds);
  173. FD_SET(sock, &fds);
  174. if (reset_timer) {
  175. /*
  176. * traceroute could hang if someone else has a ping
  177. * running and our ICMP reply gets dropped but we don't
  178. * realize it because we keep waking up to handle those
  179. * other ICMP packets that keep coming in. To fix this,
  180. * "reset_timer" will only be true if the last packet that
  181. * came in was for us or if this is the first time we're
  182. * waiting for a reply since sending out a probe. Note
  183. * that this takes advantage of the select() feature on
  184. * Linux where the remaining timeout is written to the
  185. * struct timeval area.
  186. */
  187. wait.tv_sec = waittime;
  188. wait.tv_usec = 0;
  189. }
  190. if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
  191. cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
  192. (struct sockaddr *)from, &fromlen);
  193. return(cc);
  194. }
  195. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  196. /*
  197. * Convert an ICMP "type" field to a printable string.
  198. */
  199. static inline const char *
  200. pr_type(u_char t)
  201. {
  202. static const char * const ttab[] = {
  203. "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
  204. "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
  205. "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
  206. "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
  207. "Info Reply"
  208. };
  209. if(t > 16)
  210. return("OUT-OF-RANGE");
  211. return(ttab[t]);
  212. }
  213. #endif
  214. static inline int
  215. packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
  216. {
  217. struct icmp *icp;
  218. u_char type, code;
  219. int hlen;
  220. struct ip *ip;
  221. ip = (struct ip *) buf;
  222. hlen = ip->ip_hl << 2;
  223. if (cc < hlen + ICMP_MINLEN) {
  224. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  225. if (verbose)
  226. printf("packet too short (%d bytes) from %s\n", cc,
  227. inet_ntoa(from->sin_addr));
  228. #endif
  229. return (0);
  230. }
  231. cc -= hlen;
  232. icp = (struct icmp *)(buf + hlen);
  233. type = icp->icmp_type; code = icp->icmp_code;
  234. if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
  235. type == ICMP_UNREACH) {
  236. struct ip *hip;
  237. struct udphdr *up;
  238. hip = &icp->icmp_ip;
  239. hlen = hip->ip_hl << 2;
  240. up = (struct udphdr *)((u_char *)hip + hlen);
  241. if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
  242. up->source == htons(ident) &&
  243. up->dest == htons(port+seq))
  244. return (type == ICMP_TIMXCEED? -1 : code+1);
  245. }
  246. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  247. if (verbose) {
  248. int i;
  249. u_long *lp = (u_long *)&icp->icmp_ip;
  250. printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
  251. cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
  252. type, pr_type(type), icp->icmp_code);
  253. for (i = 4; i < cc ; i += sizeof(long))
  254. printf("%2d: x%8.8lx\n", i, *lp++);
  255. }
  256. #endif
  257. return(0);
  258. }
  259. static void /* not inline */
  260. send_probe(int seq, int ttl)
  261. {
  262. struct opacket *op = outpacket;
  263. struct ip *ip = &op->ip;
  264. struct udphdr *up = &op->udp;
  265. int i;
  266. struct timezone tz;
  267. ip->ip_off = 0;
  268. ip->ip_hl = sizeof(*ip) >> 2;
  269. ip->ip_p = IPPROTO_UDP;
  270. ip->ip_len = datalen;
  271. ip->ip_ttl = ttl;
  272. ip->ip_v = IPVERSION;
  273. ip->ip_id = htons(ident+seq);
  274. up->source = htons(ident);
  275. up->dest = htons(port+seq);
  276. up->len = htons((u_short)(datalen - sizeof(struct ip)));
  277. up->check = 0;
  278. op->seq = seq;
  279. op->ttl = ttl;
  280. (void) gettimeofday(&op->tv, &tz);
  281. i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
  282. sizeof(struct sockaddr));
  283. if (i < 0 || i != datalen) {
  284. if (i<0)
  285. perror("sendto");
  286. printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
  287. datalen, i);
  288. (void) fflush(stdout);
  289. }
  290. }
  291. int
  292. #ifndef CONFIG_TRACEROUTE
  293. main(int argc, char *argv[])
  294. #else
  295. traceroute_main(int argc, char *argv[])
  296. #endif
  297. {
  298. extern char *optarg;
  299. extern int optind;
  300. struct hostent *hp;
  301. struct sockaddr_in from, *to;
  302. int ch, i, on, probe, seq, tos, ttl;
  303. int options = 0; /* socket options */
  304. char *source = 0;
  305. int nprobes = 3;
  306. on = 1;
  307. seq = tos = 0;
  308. to = (struct sockaddr_in *)&whereto;
  309. while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
  310. switch(ch) {
  311. case 'd':
  312. #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
  313. options |= SO_DEBUG;
  314. #endif
  315. break;
  316. case 'm':
  317. max_ttl = atoi(optarg);
  318. if (max_ttl <= 1)
  319. bb_error_msg_and_die("max ttl must be >1.");
  320. break;
  321. case 'n':
  322. nflag++;
  323. break;
  324. case 'p':
  325. port = atoi(optarg);
  326. if (port < 1)
  327. bb_error_msg_and_die("port must be >0.");
  328. break;
  329. case 'q':
  330. nprobes = atoi(optarg);
  331. if (nprobes < 1)
  332. bb_error_msg_and_die("nprobes must be >0.");
  333. break;
  334. case 'r':
  335. options |= SO_DONTROUTE;
  336. break;
  337. case 's':
  338. /*
  339. * set the ip source address of the outbound
  340. * probe (e.g., on a multi-homed host).
  341. */
  342. source = optarg;
  343. break;
  344. case 't':
  345. tos = atoi(optarg);
  346. if (tos < 0 || tos > 255)
  347. bb_error_msg_and_die("tos must be 0 to 255.");
  348. break;
  349. case 'v':
  350. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  351. verbose++;
  352. #endif
  353. break;
  354. case 'w':
  355. waittime = atoi(optarg);
  356. if (waittime <= 1)
  357. bb_error_msg_and_die("wait must be >1 sec.");
  358. break;
  359. default:
  360. bb_show_usage();
  361. }
  362. argc -= optind;
  363. argv += optind;
  364. if (argc < 1)
  365. bb_show_usage();
  366. setlinebuf (stdout);
  367. memset(&whereto, 0, sizeof(struct sockaddr));
  368. hp = xgethostbyname(*argv);
  369. to->sin_family = hp->h_addrtype;
  370. memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
  371. hostname = (char *)hp->h_name;
  372. if (*++argv)
  373. datalen = atoi(*argv);
  374. if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
  375. bb_error_msg_and_die("packet size must be 0 <= s < %d.",
  376. (int)(MAXPACKET - sizeof(struct opacket)));
  377. datalen += sizeof(struct opacket);
  378. outpacket = (struct opacket *)xmalloc((unsigned)datalen);
  379. memset(outpacket, 0, datalen);
  380. outpacket->ip.ip_dst = to->sin_addr;
  381. outpacket->ip.ip_tos = tos;
  382. outpacket->ip.ip_v = IPVERSION;
  383. outpacket->ip.ip_id = 0;
  384. ident = (getpid() & 0xffff) | 0x8000;
  385. if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
  386. bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
  387. s = create_icmp_socket();
  388. #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
  389. if (options & SO_DEBUG)
  390. (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
  391. (char *)&on, sizeof(on));
  392. #endif
  393. if (options & SO_DONTROUTE)
  394. (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
  395. (char *)&on, sizeof(on));
  396. #ifdef SO_SNDBUF
  397. if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
  398. sizeof(datalen)) < 0)
  399. bb_perror_msg_and_die("SO_SNDBUF");
  400. #endif
  401. #ifdef IP_HDRINCL
  402. if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
  403. sizeof(on)) < 0)
  404. bb_perror_msg_and_die("IP_HDRINCL");
  405. #endif
  406. #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
  407. if (options & SO_DEBUG)
  408. (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
  409. (char *)&on, sizeof(on));
  410. #endif
  411. if (options & SO_DONTROUTE)
  412. (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
  413. (char *)&on, sizeof(on));
  414. if (source) {
  415. memset(&from, 0, sizeof(struct sockaddr));
  416. from.sin_family = AF_INET;
  417. from.sin_addr.s_addr = inet_addr(source);
  418. if (from.sin_addr.s_addr == -1)
  419. bb_error_msg_and_die("unknown host %s", source);
  420. outpacket->ip.ip_src = from.sin_addr;
  421. #ifndef IP_HDRINCL
  422. if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
  423. bb_perror_msg_and_die("bind");
  424. #endif
  425. }
  426. fprintf(stderr, "traceroute to %s (%s)", hostname,
  427. inet_ntoa(to->sin_addr));
  428. if (source)
  429. fprintf(stderr, " from %s", source);
  430. fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
  431. for (ttl = 1; ttl <= max_ttl; ++ttl) {
  432. u_long lastaddr = 0;
  433. int got_there = 0;
  434. int unreachable = 0;
  435. printf("%2d ", ttl);
  436. for (probe = 0; probe < nprobes; ++probe) {
  437. int cc, reset_timer;
  438. struct timeval t1, t2;
  439. struct timezone tz;
  440. struct ip *ip;
  441. (void) gettimeofday(&t1, &tz);
  442. send_probe(++seq, ttl);
  443. reset_timer = 1;
  444. while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
  445. (void) gettimeofday(&t2, &tz);
  446. if ((i = packet_ok(packet, cc, &from, seq))) {
  447. reset_timer = 1;
  448. if (from.sin_addr.s_addr != lastaddr) {
  449. print(packet, cc, &from);
  450. lastaddr = from.sin_addr.s_addr;
  451. }
  452. printf(" %g ms", deltaT(&t1, &t2));
  453. switch(i - 1) {
  454. case ICMP_UNREACH_PORT:
  455. ip = (struct ip *)packet;
  456. if (ip->ip_ttl <= 1)
  457. printf(" !");
  458. ++got_there;
  459. break;
  460. case ICMP_UNREACH_NET:
  461. ++unreachable;
  462. printf(" !N");
  463. break;
  464. case ICMP_UNREACH_HOST:
  465. ++unreachable;
  466. printf(" !H");
  467. break;
  468. case ICMP_UNREACH_PROTOCOL:
  469. ++got_there;
  470. printf(" !P");
  471. break;
  472. case ICMP_UNREACH_NEEDFRAG:
  473. ++unreachable;
  474. printf(" !F");
  475. break;
  476. case ICMP_UNREACH_SRCFAIL:
  477. ++unreachable;
  478. printf(" !S");
  479. break;
  480. }
  481. break;
  482. } else
  483. reset_timer = 0;
  484. }
  485. if (cc == 0)
  486. printf(" *");
  487. (void) fflush(stdout);
  488. }
  489. putchar('\n');
  490. if (got_there || unreachable >= nprobes-1)
  491. return 0;
  492. }
  493. return 0;
  494. }