traceroute.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  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. static u_char packet[512]; /* last inbound (icmp) packet */
  95. static struct opacket *outpacket; /* last output (udp) packet */
  96. static int s; /* receive (icmp) socket file descriptor */
  97. static int sndsock; /* send (udp) socket file descriptor */
  98. static struct sockaddr whereto; /* Who to try to reach */
  99. static int datalen; /* How much data */
  100. static char *hostname;
  101. static int max_ttl = 30;
  102. static u_short ident;
  103. static u_short port = 32768+666; /* start udp dest port # for probe packets */
  104. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  105. static int verbose;
  106. #endif
  107. static int waittime = 5; /* time to wait for response (in seconds) */
  108. static int nflag; /* print addresses numerically */
  109. /*
  110. * Construct an Internet address representation.
  111. * If the nflag has been supplied, give
  112. * numeric value, otherwise try for symbolic name.
  113. */
  114. static inline void
  115. inetname(struct sockaddr_in *from)
  116. {
  117. char *cp;
  118. static char domain[MAXHOSTNAMELEN + 1];
  119. char name[MAXHOSTNAMELEN + 1];
  120. static int first = 1;
  121. const char *ina;
  122. if (first && !nflag) {
  123. first = 0;
  124. if (getdomainname(domain, MAXHOSTNAMELEN) != 0)
  125. domain[0] = 0;
  126. }
  127. cp = 0;
  128. if (!nflag && from->sin_addr.s_addr != INADDR_ANY) {
  129. if(INET_rresolve(name, sizeof(name), from, 0x4000, 0xffffffff) >= 0) {
  130. if ((cp = strchr(name, '.')) &&
  131. !strcmp(cp + 1, domain))
  132. *cp = 0;
  133. cp = (char *)name;
  134. }
  135. }
  136. ina = inet_ntoa(from->sin_addr);
  137. if (nflag)
  138. printf(" %s", ina);
  139. else
  140. printf(" %s (%s)", (cp ? cp : ina), ina);
  141. }
  142. static inline void
  143. print(u_char *buf, int cc, struct sockaddr_in *from)
  144. {
  145. struct ip *ip;
  146. int hlen;
  147. ip = (struct ip *) buf;
  148. hlen = ip->ip_hl << 2;
  149. cc -= hlen;
  150. inetname(from);
  151. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  152. if (verbose)
  153. printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
  154. #endif
  155. }
  156. static inline double
  157. deltaT(struct timeval *t1p, struct timeval *t2p)
  158. {
  159. double dt;
  160. dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
  161. (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
  162. return (dt);
  163. }
  164. static inline int
  165. wait_for_reply(int sock, struct sockaddr_in *from, int reset_timer)
  166. {
  167. fd_set fds;
  168. static struct timeval wait;
  169. int cc = 0;
  170. int fromlen = sizeof (*from);
  171. FD_ZERO(&fds);
  172. FD_SET(sock, &fds);
  173. if (reset_timer) {
  174. /*
  175. * traceroute could hang if someone else has a ping
  176. * running and our ICMP reply gets dropped but we don't
  177. * realize it because we keep waking up to handle those
  178. * other ICMP packets that keep coming in. To fix this,
  179. * "reset_timer" will only be true if the last packet that
  180. * came in was for us or if this is the first time we're
  181. * waiting for a reply since sending out a probe. Note
  182. * that this takes advantage of the select() feature on
  183. * Linux where the remaining timeout is written to the
  184. * struct timeval area.
  185. */
  186. wait.tv_sec = waittime;
  187. wait.tv_usec = 0;
  188. }
  189. if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
  190. cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
  191. (struct sockaddr *)from, &fromlen);
  192. return(cc);
  193. }
  194. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  195. /*
  196. * Convert an ICMP "type" field to a printable string.
  197. */
  198. static inline const char *
  199. pr_type(u_char t)
  200. {
  201. static const char * const ttab[] = {
  202. "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
  203. "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
  204. "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
  205. "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
  206. "Info Reply"
  207. };
  208. if(t > 16)
  209. return("OUT-OF-RANGE");
  210. return(ttab[t]);
  211. }
  212. #endif
  213. static inline int
  214. packet_ok(u_char *buf, int cc, struct sockaddr_in *from, int seq)
  215. {
  216. struct icmp *icp;
  217. u_char type, code;
  218. int hlen;
  219. struct ip *ip;
  220. ip = (struct ip *) buf;
  221. hlen = ip->ip_hl << 2;
  222. if (cc < hlen + ICMP_MINLEN) {
  223. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  224. if (verbose)
  225. printf("packet too short (%d bytes) from %s\n", cc,
  226. inet_ntoa(from->sin_addr));
  227. #endif
  228. return (0);
  229. }
  230. cc -= hlen;
  231. icp = (struct icmp *)(buf + hlen);
  232. type = icp->icmp_type; code = icp->icmp_code;
  233. if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
  234. type == ICMP_UNREACH) {
  235. struct ip *hip;
  236. struct udphdr *up;
  237. hip = &icp->icmp_ip;
  238. hlen = hip->ip_hl << 2;
  239. up = (struct udphdr *)((u_char *)hip + hlen);
  240. if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP &&
  241. up->source == htons(ident) &&
  242. up->dest == htons(port+seq))
  243. return (type == ICMP_TIMXCEED? -1 : code+1);
  244. }
  245. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  246. if (verbose) {
  247. int i;
  248. u_long *lp = (u_long *)&icp->icmp_ip;
  249. printf("\n%d bytes from %s to %s: icmp type %d (%s) code %d\n",
  250. cc, inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst),
  251. type, pr_type(type), icp->icmp_code);
  252. for (i = 4; i < cc ; i += sizeof(long))
  253. printf("%2d: x%8.8lx\n", i, *lp++);
  254. }
  255. #endif
  256. return(0);
  257. }
  258. static void /* not inline */
  259. send_probe(int seq, int ttl)
  260. {
  261. struct opacket *op = outpacket;
  262. struct ip *ip = &op->ip;
  263. struct udphdr *up = &op->udp;
  264. int i;
  265. struct timezone tz;
  266. ip->ip_off = 0;
  267. ip->ip_hl = sizeof(*ip) >> 2;
  268. ip->ip_p = IPPROTO_UDP;
  269. ip->ip_len = datalen;
  270. ip->ip_ttl = ttl;
  271. ip->ip_v = IPVERSION;
  272. ip->ip_id = htons(ident+seq);
  273. up->source = htons(ident);
  274. up->dest = htons(port+seq);
  275. up->len = htons((u_short)(datalen - sizeof(struct ip)));
  276. up->check = 0;
  277. op->seq = seq;
  278. op->ttl = ttl;
  279. (void) gettimeofday(&op->tv, &tz);
  280. i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
  281. sizeof(struct sockaddr));
  282. if (i < 0 || i != datalen) {
  283. if (i<0)
  284. perror("sendto");
  285. printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
  286. datalen, i);
  287. (void) fflush(stdout);
  288. }
  289. }
  290. int
  291. #ifndef CONFIG_TRACEROUTE
  292. main(int argc, char *argv[])
  293. #else
  294. traceroute_main(int argc, char *argv[])
  295. #endif
  296. {
  297. extern char *optarg;
  298. extern int optind;
  299. struct hostent *hp;
  300. struct sockaddr_in from, *to;
  301. int ch, i, on, probe, seq, tos, ttl;
  302. int options = 0; /* socket options */
  303. char *source = 0;
  304. int nprobes = 3;
  305. on = 1;
  306. seq = tos = 0;
  307. to = (struct sockaddr_in *)&whereto;
  308. while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
  309. switch(ch) {
  310. case 'd':
  311. #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
  312. options |= SO_DEBUG;
  313. #endif
  314. break;
  315. case 'm':
  316. max_ttl = atoi(optarg);
  317. if (max_ttl <= 1)
  318. bb_error_msg_and_die("max ttl must be >1.");
  319. break;
  320. case 'n':
  321. nflag++;
  322. break;
  323. case 'p':
  324. port = atoi(optarg);
  325. if (port < 1)
  326. bb_error_msg_and_die("port must be >0.");
  327. break;
  328. case 'q':
  329. nprobes = atoi(optarg);
  330. if (nprobes < 1)
  331. bb_error_msg_and_die("nprobes must be >0.");
  332. break;
  333. case 'r':
  334. options |= SO_DONTROUTE;
  335. break;
  336. case 's':
  337. /*
  338. * set the ip source address of the outbound
  339. * probe (e.g., on a multi-homed host).
  340. */
  341. source = optarg;
  342. break;
  343. case 't':
  344. tos = atoi(optarg);
  345. if (tos < 0 || tos > 255)
  346. bb_error_msg_and_die("tos must be 0 to 255.");
  347. break;
  348. case 'v':
  349. #ifdef CONFIG_FEATURE_TRACEROUTE_VERBOSE
  350. verbose++;
  351. #endif
  352. break;
  353. case 'w':
  354. waittime = atoi(optarg);
  355. if (waittime <= 1)
  356. bb_error_msg_and_die("wait must be >1 sec.");
  357. break;
  358. default:
  359. bb_show_usage();
  360. }
  361. argc -= optind;
  362. argv += optind;
  363. if (argc < 1)
  364. bb_show_usage();
  365. setlinebuf (stdout);
  366. memset(&whereto, 0, sizeof(struct sockaddr));
  367. hp = xgethostbyname(*argv);
  368. to->sin_family = hp->h_addrtype;
  369. memcpy(&to->sin_addr, hp->h_addr, hp->h_length);
  370. hostname = (char *)hp->h_name;
  371. if (*++argv)
  372. datalen = atoi(*argv);
  373. if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket))
  374. bb_error_msg_and_die("packet size must be 0 <= s < %d.",
  375. MAXPACKET - sizeof(struct opacket));
  376. datalen += sizeof(struct opacket);
  377. outpacket = (struct opacket *)xmalloc((unsigned)datalen);
  378. memset(outpacket, 0, datalen);
  379. outpacket->ip.ip_dst = to->sin_addr;
  380. outpacket->ip.ip_tos = tos;
  381. outpacket->ip.ip_v = IPVERSION;
  382. outpacket->ip.ip_id = 0;
  383. ident = (getpid() & 0xffff) | 0x8000;
  384. if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
  385. bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket);
  386. s = create_icmp_socket();
  387. #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
  388. if (options & SO_DEBUG)
  389. (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
  390. (char *)&on, sizeof(on));
  391. #endif
  392. if (options & SO_DONTROUTE)
  393. (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
  394. (char *)&on, sizeof(on));
  395. #ifdef SO_SNDBUF
  396. if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
  397. sizeof(datalen)) < 0)
  398. bb_perror_msg_and_die("SO_SNDBUF");
  399. #endif
  400. #ifdef IP_HDRINCL
  401. if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
  402. sizeof(on)) < 0)
  403. bb_perror_msg_and_die("IP_HDRINCL");
  404. #endif
  405. #ifdef CONFIG_FEATURE_TRACEROUTE_SO_DEBUG
  406. if (options & SO_DEBUG)
  407. (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
  408. (char *)&on, sizeof(on));
  409. #endif
  410. if (options & SO_DONTROUTE)
  411. (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
  412. (char *)&on, sizeof(on));
  413. if (source) {
  414. memset(&from, 0, sizeof(struct sockaddr));
  415. from.sin_family = AF_INET;
  416. from.sin_addr.s_addr = inet_addr(source);
  417. if (from.sin_addr.s_addr == -1)
  418. bb_error_msg_and_die("unknown host %s", source);
  419. outpacket->ip.ip_src = from.sin_addr;
  420. #ifndef IP_HDRINCL
  421. if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0)
  422. bb_perror_msg_and_die("bind");
  423. #endif
  424. }
  425. fprintf(stderr, "traceroute to %s (%s)", hostname,
  426. inet_ntoa(to->sin_addr));
  427. if (source)
  428. fprintf(stderr, " from %s", source);
  429. fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
  430. for (ttl = 1; ttl <= max_ttl; ++ttl) {
  431. u_long lastaddr = 0;
  432. int got_there = 0;
  433. int unreachable = 0;
  434. printf("%2d ", ttl);
  435. for (probe = 0; probe < nprobes; ++probe) {
  436. int cc, reset_timer;
  437. struct timeval t1, t2;
  438. struct timezone tz;
  439. struct ip *ip;
  440. (void) gettimeofday(&t1, &tz);
  441. send_probe(++seq, ttl);
  442. reset_timer = 1;
  443. while ((cc = wait_for_reply(s, &from, reset_timer)) != 0) {
  444. (void) gettimeofday(&t2, &tz);
  445. if ((i = packet_ok(packet, cc, &from, seq))) {
  446. reset_timer = 1;
  447. if (from.sin_addr.s_addr != lastaddr) {
  448. print(packet, cc, &from);
  449. lastaddr = from.sin_addr.s_addr;
  450. }
  451. printf(" %g ms", deltaT(&t1, &t2));
  452. switch(i - 1) {
  453. case ICMP_UNREACH_PORT:
  454. ip = (struct ip *)packet;
  455. if (ip->ip_ttl <= 1)
  456. printf(" !");
  457. ++got_there;
  458. break;
  459. case ICMP_UNREACH_NET:
  460. ++unreachable;
  461. printf(" !N");
  462. break;
  463. case ICMP_UNREACH_HOST:
  464. ++unreachable;
  465. printf(" !H");
  466. break;
  467. case ICMP_UNREACH_PROTOCOL:
  468. ++got_there;
  469. printf(" !P");
  470. break;
  471. case ICMP_UNREACH_NEEDFRAG:
  472. ++unreachable;
  473. printf(" !F");
  474. break;
  475. case ICMP_UNREACH_SRCFAIL:
  476. ++unreachable;
  477. printf(" !S");
  478. break;
  479. }
  480. break;
  481. } else
  482. reset_timer = 0;
  483. }
  484. if (cc == 0)
  485. printf(" *");
  486. (void) fflush(stdout);
  487. }
  488. putchar('\n');
  489. if (got_there || unreachable >= nprobes-1)
  490. return 0;
  491. }
  492. return 0;
  493. }