免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3500 | 回复: 7
打印 上一主题 下一主题

traceroute源码和他的原理是什么? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-06-27 13:20 |只看该作者 |倒序浏览
traceroute的源码在kernel里?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2005-06-27 13:59 |只看该作者

traceroute源码和他的原理是什么?

source 我不清楚.
不過, 原理不難, 稍對 ICMP 有概念就可了解.
或找一本 tcp/ip 的書, 翻一下 ICMP 那部份, 大都會以 ping 與 traceroute 作說明例子的.

只是在不同的系統實做上, 細節部份或有不同.

论坛徽章:
0
3 [报告]
发表于 2005-06-27 14:08 |只看该作者

traceroute源码和他的原理是什么?

IP的记录路由

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
4 [报告]
发表于 2005-06-27 14:12 |只看该作者

traceroute源码和他的原理是什么?

[quote]原帖由 "SunLife"]IP的记录路由[/quote 发表:

嗯? 若指的是 source route 的話, 那可跟 traceroute 的原理不一樣哦~~~

论坛徽章:
0
5 [报告]
发表于 2005-06-27 14:24 |只看该作者

traceroute源码和他的原理是什么?

两位能详细说明一下吗?
我感觉跟icmp原理有差距.

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
6 [报告]
发表于 2005-06-27 14:42 |只看该作者

traceroute源码和他的原理是什么?

詳細我不說了. 抄一段我之前簡單說過的:

traceroute


除了用 ping 命令來檢查連線之外﹐還有另外一個非常厲害的工具我們可以使用的﹐就是 traceroute 命令了(在 windows 上面則為 tracert 命令)﹕

traceroute www.yahoo.com  
traceroute: Warning: www.yahoo.com has multiple addresses; using 216.115.102.78
traceroute to www.yahoo.akadns.net (216.115.102.7, 30 hops max, 38 byte packets
1 swtn184-1.adsl.seed.net.tw (211.74.184.1) 61.209 ms 63.117 ms 59.422 ms
2 139.175.169.1 (139.175.169.1) 60.172 ms 64.253 ms 60.136 ms
3 R58-38.seed.net.tw (139.175.58.3 61.669 ms 59.185 ms 60.218 ms
4 R58-201.seed.net.tw (139.175.58.201) 68.353 ms 70.353 ms 71.605 ms
5 R57-99.seed.net.tw (139.175.57.99) 71.593 ms 70.570 ms 71.657 ms
6 R58-166.seed.net.tw (139.175.58.166) 367.829 ms 350.511 ms 355.516 ms
7 64.124.33.168.available.above.net (64.124.33.16 218.493 ms 218.259 ms 219.996 ms
8 * * *
9 ge-2-3-0.msr1.pao.yahoo.com (216.115.101.34) 370.618 ms ge-3-3-0.msr2.pao.yahoo.com (216.115.101.3 337.389 ms 349.591 ms
10 vl21.bas2.snv.yahoo.com (216.115.100.229) 218.355 ms 217.388 ms vl20.bas1.snv.yahoo.com (216.115.100.225) 221.096 ms
11 w6.snv.yahoo.com (216.115.102.7 370.140 ms 339.934 ms 340.845 ms  


透過 traceroute 命令﹐我們可以找出通往目的地的所有經過的路由節點﹐並以數字將路由順序標識出來。假如您加上 -n 參數的話﹐節點名稱則會以 IP 位址顯示﹐因為不需要進行名稱解析﹐回應速度當然會快一些。

從上面的 traceroute 結果﹐我們可以看到每一個節點都返回 3 個 round-trip 時間作參考。這樣﹐您就能夠判斷整個連線路由中﹐交通瓶頸所在的位置在哪裡。

您或許奇怪 traceroute 是如何揪出所有路由節點的呢﹖且聽我細說﹕

您是否有留意到 ping 命令的結果有一個 TTL 值﹖通常來說﹐Time To Live 都是以時間為單位的﹐但是在路由上面卻是以跳站數目為單位的。為了防止一個封包無限期呆在網路上路由﹐每一個封包都會被賦予一個 TTL 值﹐告訴它最多能經過多少個跳站。當封包被一個路由節點處理之後﹐它原來的 TTL 值就會被扣掉 1 ﹐這樣﹐如果封包的 TTL 降到 0 的時候﹐路由器就會丟棄這個封包﹐並且同時向來源地送出一個 time_exceeded 的 ICMP 封包﹐以告知其封包的命運。

找到靈感了嗎﹖聰明的 traceroute 程式設計者正是利用了 ICMP 這個特殊功能﹐來找出每一個路由節點的﹕

首先﹐traceroute 命令會向目標位址送出 UDP 偵測封包(在 Linux 中,可用 -I 改為 ICMP 封包)﹐但將第一個送出的封包之 TTL 設為 1 。這樣﹐第一個路由節點在處理這個封包的時候﹐減掉 1 ,並發現 TTL 為 0 ﹐於是就不處理這個封包﹐並同時送回一個 ICMP 封包。這樣﹐發送端就知道第一個路由節點在哪裡了。
當接得到第一個 ICMP 返回的時候﹐程式會檢查返回主機是否就是目標主機﹐如果不是﹐則再送出第二個封包﹐但 TTL 比上次增加 1 。
這樣﹐第一路由節點接到的封包之 TTL 就不是 0 ﹐那麼處理完畢後送給下一個節點﹐同時將 TTL 扣除 1 。這樣,當下一個站收到這個封包,再扣掉 TTL 為 0 ﹐也會送回 ICMP 封包﹐這樣﹐程式就知道第二個路由節點在哪裡了。
然後重覆上一個動作﹐直到找到目標主機為止﹐或是封包的最大 TTL (通常為 30) 都用光為止﹐但您可以用 -m 參數來指定最大的 TTL 值。

怎樣﹖聰明吧﹗

但是﹐在實作中﹐未必是所有路由設備都會﹑或願意送回 ICMP 封包的。碰到這樣的情況﹐您就會看到第 8 個跳站的情形了。假如 traceroute 最後的結果一直維持著 * 符號﹐那可能是因為 ICMP 被對方的防火牆攔下來的結果。這樣的話﹐您可能無法完成防火牆後的路由追蹤了。


Tips﹕從上面的例子來觀察﹐由第 6 個跳站開始明顯降慢下來﹐而根據名稱看來﹐應該就是 ISP 連出 backbond 的節點。

假如您發現從內部網路到自己的 router 之間的連線都很快﹐過了 router 之後就很慢﹐如果不少是專線的線路出現了問題﹐那很可能到了要升級專線的時候了﹐或是這時候剛好碰到有人大量使用頻寬﹔假如速度過了 router 連到對方的機房還很快﹐然後就開始降下來﹐那您要好好審查一下當初和 ISP 簽訂的合約上﹐關於頻寬的保證問題是如何說的﹔但如果您發現連線到國外的網站﹐而速度是從進入對方國家之後才降下來的﹐那就沒什麼辦法好想了。

论坛徽章:
0
7 [报告]
发表于 2005-06-27 14:45 |只看该作者

traceroute源码和他的原理是什么?

4.4BSD的traceroute代码

  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. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. *    notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. *    notice, this list of conditions and the following disclaimer in the
  15. *    documentation and/or other materials provided with the distribution.
  16. * 3. All advertising materials mentioning features or use of this software
  17. *    must display the following acknowledgement:
  18. *        This product includes software developed by the University of
  19. *        California, Berkeley and its contributors.
  20. * 4. Neither the name of the University nor the names of its contributors
  21. *    may be used to endorse or promote products derived from this software
  22. *    without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. */

  36. #ifndef lint
  37. static char copyright[] =
  38. "@(#) Copyright (c) 1990, 1993\n\
  39.         The Regents of the University of California.  All rights reserved.\n";
  40. #endif /* not lint */

  41. #ifndef lint
  42. static char sccsid[] = "@(#)traceroute.c        8.1 (Berkeley) 6/6/93";
  43. #endif /* not lint */

  44. /*
  45. * traceroute host  - trace the route ip packets follow going to "host".
  46. *
  47. * Attempt to trace the route an ip packet would follow to some
  48. * internet host.  We find out intermediate hops by launching probe
  49. * packets with a small ttl (time to live) then listening for an
  50. * icmp "time exceeded" reply from a gateway.  We start our probes
  51. * with a ttl of one and increase by one until we get an icmp "port
  52. * unreachable" (which means we got to "host") or hit a max (which
  53. * defaults to 30 hops & can be changed with the -m flag).  Three
  54. * probes (change with -q flag) are sent at each ttl setting and a
  55. * line is printed showing the ttl, address of the gateway and
  56. * round trip time of each probe.  If the probe answers come from
  57. * different gateways, the address of each responding system will
  58. * be printed.  If there is no response within a 5 sec. timeout
  59. * interval (changed with the -w flag), a "*" is printed for that
  60. * probe.
  61. *
  62. * Probe packets are UDP format.  We don't want the destination
  63. * host to process them so the destination port is set to an
  64. * unlikely value (if some clod on the destination is using that
  65. * value, it can be changed with the -p flag).
  66. *
  67. * A sample use might be:
  68. *
  69. *     [yak 71]% traceroute nis.nsf.net.
  70. *     traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
  71. *      1  helios.ee.lbl.gov (128.3.112.1)  19 ms  19 ms  0 ms
  72. *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
  73. *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  39 ms  19 ms
  74. *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  39 ms
  75. *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  39 ms  39 ms  39 ms
  76. *      6  128.32.197.4 (128.32.197.4)  40 ms  59 ms  59 ms
  77. *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  59 ms
  78. *      8  129.140.70.13 (129.140.70.13)  99 ms  99 ms  80 ms
  79. *      9  129.140.71.6 (129.140.71.6)  139 ms  239 ms  319 ms
  80. *     10  129.140.81.7 (129.140.81.7)  220 ms  199 ms  199 ms
  81. *     11  nic.merit.edu (35.1.1.48)  239 ms  239 ms  239 ms
  82. *
  83. * Note that lines 2 & 3 are the same.  This is due to a buggy
  84. * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
  85. * packets with a zero ttl.
  86. *
  87. * A more interesting example is:
  88. *
  89. *     [yak 72]% traceroute allspice.lcs.mit.edu.
  90. *     traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
  91. *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
  92. *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  19 ms  19 ms
  93. *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  19 ms
  94. *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  19 ms  39 ms  39 ms
  95. *      5  ccn-nerif22.Berkeley.EDU (128.32.168.22)  20 ms  39 ms  39 ms
  96. *      6  128.32.197.4 (128.32.197.4)  59 ms  119 ms  39 ms
  97. *      7  131.119.2.5 (131.119.2.5)  59 ms  59 ms  39 ms
  98. *      8  129.140.70.13 (129.140.70.13)  80 ms  79 ms  99 ms
  99. *      9  129.140.71.6 (129.140.71.6)  139 ms  139 ms  159 ms
  100. *     10  129.140.81.7 (129.140.81.7)  199 ms  180 ms  300 ms
  101. *     11  129.140.72.17 (129.140.72.17)  300 ms  239 ms  239 ms
  102. *     12  * * *
  103. *     13  128.121.54.72 (128.121.54.72)  259 ms  499 ms  279 ms
  104. *     14  * * *
  105. *     15  * * *
  106. *     16  * * *
  107. *     17  * * *
  108. *     18  ALLSPICE.LCS.MIT.EDU (18.26.0.115)  339 ms  279 ms  279 ms
  109. *
  110. * (I start to see why I'm having so much trouble with mail to
  111. * MIT.)  Note that the gateways 12, 14, 15, 16 & 17 hops away
  112. * either don't send ICMP "time exceeded" messages or send them
  113. * with a ttl too small to reach us.  14 - 17 are running the
  114. * MIT C Gateway code that doesn't send "time exceeded"s.  God
  115. * only knows what's going on with 12.
  116. *
  117. * The silent gateway 12 in the above may be the result of a bug in
  118. * the 4.[23]BSD network code (and its derivatives):  4.x (x <= 3)
  119. * sends an unreachable message using whatever ttl remains in the
  120. * original datagram.  Since, for gateways, the remaining ttl is
  121. * zero, the icmp "time exceeded" is guaranteed to not make it back
  122. * to us.  The behavior of this bug is slightly more interesting
  123. * when it appears on the destination system:
  124. *
  125. *      1  helios.ee.lbl.gov (128.3.112.1)  0 ms  0 ms  0 ms
  126. *      2  lilac-dmc.Berkeley.EDU (128.32.216.1)  39 ms  19 ms  39 ms
  127. *      3  lilac-dmc.Berkeley.EDU (128.32.216.1)  19 ms  39 ms  19 ms
  128. *      4  ccngw-ner-cc.Berkeley.EDU (128.32.136.23)  39 ms  40 ms  19 ms
  129. *      5  ccn-nerif35.Berkeley.EDU (128.32.168.35)  39 ms  39 ms  39 ms
  130. *      6  csgw.Berkeley.EDU (128.32.133.254)  39 ms  59 ms  39 ms
  131. *      7  * * *
  132. *      8  * * *
  133. *      9  * * *
  134. *     10  * * *
  135. *     11  * * *
  136. *     12  * * *
  137. *     13  rip.Berkeley.EDU (128.32.131.22)  59 ms !  39 ms !  39 ms !
  138. *
  139. * Notice that there are 12 "gateways" (13 is the final
  140. * destination) and exactly the last half of them are "missing".
  141. * What's really happening is that rip (a Sun-3 running Sun OS3.5)
  142. * is using the ttl from our arriving datagram as the ttl in its
  143. * icmp reply.  So, the reply will time out on the return path
  144. * (with no notice sent to anyone since icmp's aren't sent for
  145. * icmp's) until we probe with a ttl that's at least twice the path
  146. * length.  I.e., rip is really only 7 hops away.  A reply that
  147. * returns with a ttl of 1 is a clue this problem exists.
  148. * Traceroute prints a "!" after the time if the ttl is <= 1.
  149. * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
  150. * non-standard (HPUX) software, expect to see this problem
  151. * frequently and/or take care picking the target host of your
  152. * probes.
  153. *
  154. * Other possible annotations after the time are !H, !N, !P (got a host,
  155. * network or protocol unreachable, respectively), !S or !F (source
  156. * route failed or fragmentation needed -- neither of these should
  157. * ever occur and the associated gateway is busted if you see one).  If
  158. * almost all the probes result in some kind of unreachable, traceroute
  159. * will give up and exit.
  160. *
  161. * Notes
  162. * -----
  163. * This program must be run by root or be setuid.  (I suggest that
  164. * you *don't* make it setuid -- casual use could result in a lot
  165. * of unnecessary traffic on our poor, congested nets.)
  166. *
  167. * This program requires a kernel mod that does not appear in any
  168. * system available from Berkeley:  A raw ip socket using proto
  169. * IPPROTO_RAW must interpret the data sent as an ip datagram (as
  170. * opposed to data to be wrapped in a ip datagram).  See the README
  171. * file that came with the source to this program for a description
  172. * of the mods I made to /sys/netinet/raw_ip.c.  Your mileage may
  173. * vary.  But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
  174. * MODIFIED TO RUN THIS PROGRAM.
  175. *
  176. * The udp port usage may appear bizarre (well, ok, it is bizarre).
  177. * The problem is that an icmp message only contains 8 bytes of
  178. * data from the original datagram.  8 bytes is the size of a udp
  179. * header so, if we want to associate replies with the original
  180. * datagram, the necessary information must be encoded into the
  181. * udp header (the ip id could be used but there's no way to
  182. * interlock with the kernel's assignment of ip id's and, anyway,
  183. * it would have taken a lot more kernel hacking to allow this
  184. * code to set the ip id).  So, to allow two or more users to
  185. * use traceroute simultaneously, we use this task's pid as the
  186. * source port (the high bit is set to move the port number out
  187. * of the "likely" range).  To keep track of which probe is being
  188. * replied to (so times and/or hop counts don't get confused by a
  189. * reply that was delayed in transit), we increment the destination
  190. * port number before each probe.
  191. *
  192. * Don't use this as a coding example.  I was trying to find a
  193. * routing problem and this code sort-of popped out after 48 hours
  194. * without sleep.  I was amazed it ever compiled, much less ran.
  195. *
  196. * I stole the idea for this program from Steve Deering.  Since
  197. * the first release, I've learned that had I attended the right
  198. * IETF working group meetings, I also could have stolen it from Guy
  199. * Almes or Matt Mathis.  I don't know (or care) who came up with
  200. * the idea first.  I envy the originators' perspicacity and I'm
  201. * glad they didn't keep the idea a secret.
  202. *
  203. * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
  204. * enhancements to the original distribution.
  205. *
  206. * I've hacked up a round-trip-route version of this that works by
  207. * sending a loose-source-routed udp datagram through the destination
  208. * back to yourself.  Unfortunately, SO many gateways botch source
  209. * routing, the thing is almost worthless.  Maybe one day...
  210. *
  211. *  -- Van Jacobson (van@helios.ee.lbl.gov)
  212. *     Tue Dec 20 03:50:13 PST 1988
  213. */

  214. #include <sys/param.h>;
  215. #include <sys/time.h>;
  216. #include <sys/socket.h>;
  217. #include <sys/file.h>;
  218. #include <sys/ioctl.h>;

  219. #include <netinet/in_systm.h>;
  220. #include <netinet/in.h>;
  221. #include <netinet/ip.h>;
  222. #include <netinet/ip_icmp.h>;
  223. #include <netinet/udp.h>;

  224. #include <arpa/inet.h>;

  225. #include <netdb.h>;
  226. #include <stdio.h>;
  227. #include <errno.h>;
  228. #include <stdlib.h>;
  229. #include <string.h>;
  230. #include <unistd.h>;

  231. #define        MAXPACKET        65535        /* max ip packet size */
  232. #ifndef MAXHOSTNAMELEN
  233. #define MAXHOSTNAMELEN        64
  234. #endif

  235. #ifndef FD_SET
  236. #define NFDBITS         (8*sizeof(fd_set))
  237. #define FD_SETSIZE      NFDBITS
  238. #define FD_SET(n, p)    ((p)->;fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  239. #define FD_CLR(n, p)    ((p)->;fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  240. #define FD_ISSET(n, p)  ((p)->;fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  241. #define FD_ZERO(p)      bzero((char *)(p), sizeof(*(p)))
  242. #endif

  243. #define Fprintf (void)fprintf
  244. #define Sprintf (void)sprintf
  245. #define Printf (void)printf

  246. /*
  247. * format of a (udp) probe packet.
  248. */
  249. struct opacket {
  250.         struct ip ip;
  251.         struct udphdr udp;
  252.         u_char seq;                /* sequence number of this packet */
  253.         u_char ttl;                /* ttl packet left with */
  254.         struct timeval tv;        /* time packet left */
  255. };

  256. u_char        packet[512];                /* last inbound (icmp) packet */
  257. struct opacket        *outpacket;        /* last output (udp) packet */

  258. int wait_for_reply __P((int, struct sockaddr_in *));
  259. void send_probe __P((int, int));
  260. double deltaT __P((struct timeval *, struct timeval *));
  261. int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
  262. void print __P((u_char *, int, struct sockaddr_in *));
  263. void tvsub __P((struct timeval *, struct timeval *));
  264. char *inetname __P((struct in_addr));
  265. void usage __P(());

  266. int s;                                /* receive (icmp) socket file descriptor */
  267. int sndsock;                        /* send (udp) socket file descriptor */
  268. struct timezone tz;                /* leftover */

  269. struct sockaddr whereto;        /* Who to try to reach */
  270. int datalen;                        /* How much data */
  271. int datalen;               

  272. char *source = 0;
  273. char *hostname;

  274. int nprobes = 3;
  275. int max_ttl = 30;
  276. u_short ident;
  277. u_short port = 32768+666;        /* start udp dest port # for probe packets */
  278. int options;                        /* socket options */
  279. int verbose;
  280. int waittime = 5;                /* time to wait for response (in seconds) */
  281. int nflag;                        /* print addresses numerically */

  282. int
  283. main(argc, argv)
  284.         int argc;
  285.         char *argv[];
  286. {
  287.         extern char *optarg;
  288.         extern int optind;
  289.         struct hostent *hp;
  290.         struct protoent *pe;
  291.         struct sockaddr_in from, *to;
  292.         int ch, i, on, probe, seq, tos, ttl;

  293.         on = 1;
  294.         seq = tos = 0;
  295.         to = (struct sockaddr_in *)&
  296.         while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
  297.                 switch(ch) {
  298.                 case 'd':
  299.                         options |= SO_DEBUG;
  300.                         break;
  301.                 case 'm':
  302.                         max_ttl = atoi(optarg);
  303.                         if (max_ttl <= 1) {
  304.                                 Fprintf(stderr,
  305.                                     "traceroute: max ttl must be >;1.\n");
  306.                                 exit(1);
  307.                         }
  308.                         break;
  309.                 case 'n':
  310.                         nflag++;
  311.                         break;
  312.                 case 'p':
  313.                         port = atoi(optarg);
  314.                         if (port < 1) {
  315.                                 Fprintf(stderr,
  316.                                     "traceroute: port must be >;0.\n");
  317.                                 exit(1);
  318.                         }
  319.                         break;
  320.                 case 'q':
  321.                         nprobes = atoi(optarg);
  322.                         if (nprobes < 1) {
  323.                                 Fprintf(stderr,
  324.                                     "traceroute: nprobes must be >;0.\n");
  325.                                 exit(1);
  326.                         }
  327.                         break;
  328.                 case 'r':
  329.                         options |= SO_DONTROUTE;
  330.                         break;
  331.                 case 's':
  332.                         /*
  333.                          * set the ip source address of the outbound
  334.                          * probe (e.g., on a multi-homed host).
  335.                          */
  336.                         source = optarg;
  337.                         break;
  338.                 case 't':
  339.                         tos = atoi(optarg);
  340.                         if (tos < 0 || tos >; 255) {
  341.                                 Fprintf(stderr,
  342.                                     "traceroute: tos must be 0 to 255.\n");
  343.                                 exit(1);
  344.                         }
  345.                         break;
  346.                 case 'v':
  347.                         verbose++;
  348.                         break;
  349.                 case 'w':
  350.                         waittime = atoi(optarg);
  351.                         if (waittime <= 1) {
  352.                                 Fprintf(stderr,
  353.                                     "traceroute: wait must be >;1 sec.\n");
  354.                                 exit(1);
  355.                         }
  356.                         break;
  357.                 default:
  358.                         usage();
  359.                 }
  360.         argc -= optind;
  361.         argv += optind;

  362.         if (argc < 1)
  363.                 usage();

  364.         setlinebuf (stdout);

  365.         (void) bzero((char *)&whereto, sizeof(struct sockaddr));
  366.         to->;sin_family = AF_INET;
  367.         to->;sin_addr.s_addr = inet_addr(*argv);

  368.         if (to->;sin_addr.s_addr != -1)
  369.                 hostname = *argv;
  370.         else {
  371.                 hp = gethostbyname(*argv);
  372.                 if (hp) {
  373.                         to->;sin_family = hp->;h_addrtype;
  374.                         bcopy(hp->;h_addr, (caddr_t)&to->;sin_addr, hp->;h_length);
  375.                         hostname = hp->;h_name;
  376.                 } else {
  377.                         (void)fprintf(stderr,
  378.                             "traceroute: unknown host %s\n", *argv);
  379.                         exit(1);
  380.                 }
  381.         }
  382.         if (*++argv)
  383.                 datalen = atoi(*argv);
  384.         if (datalen < 0 || datalen >;= MAXPACKET - sizeof(struct opacket)) {
  385.                 Fprintf(stderr,
  386.                     "traceroute: packet size must be 0 <= s < %ld.\n",
  387.                     MAXPACKET - sizeof(struct opacket));
  388.                 exit(1);
  389.         }
  390.         datalen += sizeof(struct opacket);
  391.         outpacket = (struct opacket *)malloc((unsigned)datalen);
  392.         if (! outpacket) {
  393.                 perror("traceroute: malloc");
  394.                 exit(1);
  395.         }
  396.         (void) bzero((char *)outpacket, datalen);
  397.         outpacket->;ip.ip_dst = to->;sin_addr;
  398.         outpacket->;ip.ip_tos = tos;
  399.         outpacket->;ip.ip_v = IPVERSION;
  400.         outpacket->;ip.ip_id = 0;

  401.         ident = (getpid() & 0xffff) | 0x8000;

  402.         if ((pe = getprotobyname("icmp")) == NULL) {
  403.                 Fprintf(stderr, "icmp: unknown protocol\n");
  404.                 exit(10);
  405.         }

  406.         if ((s = socket(AF_INET, SOCK_RAW, pe->;p_proto)) < 0) {
  407.                 perror("traceroute: icmp socket");
  408.                 exit(5);
  409.         }
  410.         if (options & SO_DEBUG)
  411.                 (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
  412.                                   (char *)&on, sizeof(on));
  413.         if (options & SO_DONTROUTE)
  414.                 (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
  415.                                   (char *)&on, sizeof(on));

  416.         if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
  417.                 perror("traceroute: raw socket");
  418.                 exit(5);
  419.         }
  420. #ifdef SO_SNDBUF
  421.         if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
  422.                        sizeof(datalen)) < 0) {
  423.                 perror("traceroute: SO_SNDBUF");
  424.                 exit(6);
  425.         }
  426. #endif
  427. #ifdef IP_HDRINCL

  428.         if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
  429.                        sizeof(on)) < 0) {
  430.                 perror("traceroute: IP_HDRINCL");
  431.                 exit(6);
  432.         }
  433. #endif
  434.         if (options & SO_DEBUG)
  435.                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
  436.                                   (char *)&on, sizeof(on));
  437.         if (options & SO_DONTROUTE)
  438.                 (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
  439.                                   (char *)&on, sizeof(on));

  440.         if (source) {

  441.                 (void) bzero((char *)&from, sizeof(struct sockaddr));
  442.                 from.sin_family = AF_INET;
  443.                 from.sin_addr.s_addr = inet_addr(source);
  444.                 if (from.sin_addr.s_addr == -1) {
  445.                         Printf("traceroute: unknown host %s\n", source);
  446.                         exit(1);
  447.                 }
  448.                 outpacket->;ip.ip_src = from.sin_addr;
  449. #ifndef IP_HDRINCL

  450.                 if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
  451.                         perror ("traceroute: bind:");
  452.                         exit (1);
  453.                 }
  454. #endif
  455.         }

  456.         Fprintf(stderr, "traceroute to %s (%s)", hostname,
  457.                 inet_ntoa(to->;sin_addr));
  458.         if (source)
  459.                 Fprintf(stderr, " from %s", source);
  460.         Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
  461.         (void) fflush(stderr);

  462.         for (ttl = 1; ttl <= max_ttl; ++ttl) {
  463.                 u_long lastaddr = 0;   
  464.                 int got_there = 0;
  465.                 int unreachable = 0;

  466.                 Printf("%2d ", ttl);
  467.                 for (probe = 0; probe < nprobes; ++probe) {
  468.                         int cc;
  469.                         struct timeval t1, t2;
  470.                         struct timezone tz;
  471.                         struct ip *ip;

  472.                         (void) gettimeofday(&t1, &tz);
  473.                         send_probe(++seq, ttl);
  474.                         while (cc = wait_for_reply(s, &from)) {
  475.                                 (void) gettimeofday(&t2, &tz);
  476.                                 if ((i = packet_ok(packet, cc, &from, seq))) {
  477.                                         if (from.sin_addr.s_addr != lastaddr) {

  478.                                                 print(packet, cc, &from);
  479.                                                 lastaddr = from.sin_addr.s_addr;
  480.                                         }
  481.                                         Printf("  %g ms", deltaT(&t1, &t2));
  482.                                         switch(i - 1) {

  483.                                         case ICMP_UNREACH_PORT:
  484. #ifndef ARCHAIC                               
  485.                                                 ip = (struct ip *)packet;
  486.                                                 if (ip->;ip_ttl <= 1)
  487.                                                         Printf(" !");
  488. #endif
  489.                                                 ++got_there;
  490.                                                 break;

  491.                                         case ICMP_UNREACH_NET:
  492.                                                 ++unreachable;
  493.                                                 Printf(" !N");
  494.                                                 break;
  495.                                         case ICMP_UNREACH_HOST:
  496.                                                 ++unreachable;
  497.                                                 Printf(" !H");
  498.                                                 break;
  499.                                         case ICMP_UNREACH_PROTOCOL:
  500.                                                 ++got_there;
  501.                                                 Printf(" !P");
  502.                                                 break;
  503.                                         case ICMP_UNREACH_NEEDFRAG:
  504.                                                 ++unreachable;
  505.                                                 Printf(" !F");
  506.                                                 break;
  507.                                         case ICMP_UNREACH_SRCFAIL:
  508.                                                 ++unreachable;
  509.                                                 Printf(" !S");
  510.                                                 break;
  511.                                         }
  512.                                         break;
  513.                                 }
  514.                         }

  515.                         if (cc == 0)
  516.                                 Printf(" *");
  517.                         (void) fflush(stdout);
  518.                 }
  519.                 putchar('\n');
  520.                 if (got_there || unreachable >;= nprobes-1)
  521.                         exit(0);
  522.         }
  523. }

  524. int
  525. wait_for_reply(sock, from)
  526.         int sock;
  527.         struct sockaddr_in *from;
  528. {
  529.         fd_set fds;
  530.         struct timeval wait;
  531.         int cc = 0;
  532.         int fromlen = sizeof (*from);

  533.         FD_ZERO(&fds);
  534.         FD_SET(sock, &fds);
  535.         wait.tv_sec = waittime; wait.tv_usec = 0;

  536.         if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) >; 0)
  537.                 cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
  538.                             (struct sockaddr *)from, &fromlen);

  539.         return(cc);
  540. }


  541. void
  542. send_probe(seq, ttl)
  543.         int seq, ttl;
  544. {
  545.         struct opacket *op = outpacket;
  546.         struct ip *ip = &op->;ip;
  547.         struct udphdr *up = &op->;udp;
  548.         int i;

  549.         ip->;ip_off = 0;
  550.         ip->;ip_hl = sizeof(*ip) >;>; 2;       
  551.         ip->;ip_p = IPPROTO_UDP;
  552.         ip->;ip_len = datalen;
  553.         ip->;ip_ttl = ttl;
  554.         ip->;ip_v = IPVERSION;
  555.         ip->;ip_id = htons(ident+seq);

  556.         up->;source= htons(ident);
  557.         up->;dest = htons(port+seq);
  558.         up->;len = htons((u_short)(datalen - sizeof(struct ip)));
  559.         up->;check = 0;

  560.         op->;seq = seq;
  561.         op->;ttl = ttl;

  562.         (void) gettimeofday(&op->;tv, &tz);

  563.         i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
  564.                    sizeof(struct sockaddr));
  565.         if (i < 0 || i != datalen)  {
  566.                 if (i<0)
  567.                         perror("sendto");
  568.                 Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
  569.                         datalen, i);
  570.                 (void) fflush(stdout);
  571.         }
  572. }


  573. double
  574. deltaT(t1p, t2p)
  575.         struct timeval *t1p, *t2p;
  576. {
  577.         register double dt;

  578.         dt = (double)(t2p->;tv_sec - t1p->;tv_sec) * 1000.0 +
  579.              (double)(t2p->;tv_usec - t1p->;tv_usec) / 1000.0;
  580.         return (dt);
  581. }


  582. /*
  583. * Convert an ICMP "type" field to a printable string.
  584. */
  585. char *
  586. pr_type(t)
  587.         u_char t;
  588. {
  589.         static char *ttab[] = {
  590.         "Echo Reply",        "ICMP 1",        "ICMP 2",        "Dest Unreachable",
  591.         "Source Quench", "Redirect",        "ICMP 6",        "ICMP 7",
  592.         "Echo",                "ICMP 9",        "ICMP 10",        "Time Exceeded",
  593.         "Param Problem", "Timestamp",        "Timestamp Reply", "Info Request",
  594.         "Info Reply"
  595.         };

  596.         if(t >; 16)
  597.                 return("OUT-OF-RANGE");

  598.         return(ttab[t]);
  599. }

  600. /*验证收到的数据包
  601.         包的格式是
  602.               |-------------------------   cc   ----------------------------------------|       
  603.               |------ hlen----------- |                       
  604.                                             |-------------- ICMP len--------------------------|       
  605.                 20 bytes   0-40 bytes  8 bytes       20 bytes    0-40 bytes  8 bytes
  606.               ___________________________________________________________________________
  607.              | IP header | IP option | ICMP header | IP header | IP option | UDP header |
  608.              |___________|___________|_____________|___________|___________|____________|
  609.                                                   
  610.                                                         |--------ICMP data ------------------|       
  611. */
  612. int
  613. packet_ok(buf, cc, from, seq)
  614.         u_char *buf;
  615.         int cc;
  616.         struct sockaddr_in *from;
  617.         int seq;
  618. {
  619.         register struct icmp *icp;
  620.         u_char type, code;
  621.         int hlen;
  622. #ifndef ARCHAIC
  623.         struct ip *ip;

  624.         ip = (struct ip *) buf;
  625.         hlen = ip->;ip_hl << 2;        /*header length,include option*/
  626.         if (cc < hlen + ICMP_MINLEN) {       
  627.                 if (verbose)
  628.                         Printf("packet too short (%d bytes) from %s\n", cc,
  629.                                 inet_ntoa(from->;sin_addr));
  630.                 return (0);
  631.         }
  632.         cc -= hlen;
  633.         icp = (struct icmp *)(buf + hlen);
  634. #else
  635.         icp = (struct icmp *)buf;
  636. #endif
  637.         type = icp->;icmp_type; code = icp->;icmp_code;

  638.         if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
  639.             type == ICMP_UNREACH) {

  640.                 struct ip *hip;
  641.                 struct udphdr *up;

  642.                 hip = &icp->;icmp_ip;
  643.                 hlen = hip->;ip_hl << 2;
  644.                 up = (struct udphdr *)((u_char *)hip + hlen);
  645.                 if (hlen + 12 <= cc && hip->;ip_p == IPPROTO_UDP &&
  646.                     up->;source == htons(ident) &&
  647.                     up->;dest == htons(port+seq))
  648.                         return (type == ICMP_TIMXCEED? -1 : code+1);
  649.         }
  650. #ifndef ARCHAIC
  651.         if (verbose) {
  652.                 int i;
  653.                 u_long *lp = (u_long *)&icp->;icmp_ip;

  654.                 Printf("\n%d bytes from %s to %s", cc,
  655.                         inet_ntoa(from->;sin_addr), inet_ntoa(ip->;ip_dst));
  656.                 Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
  657.                        icp->;icmp_code);
  658.                 for (i = 4; i < cc ; i += sizeof(long))
  659.                         Printf("%2d: x%8.8lx\n", i, *lp++);
  660.         }
  661. #endif
  662.         return(0);
  663. }



  664. void
  665. print(buf, cc, from)
  666.         u_char *buf;
  667.         int cc;
  668.         struct sockaddr_in *from;
  669. {
  670.         struct ip *ip;
  671.         int hlen;

  672.         ip = (struct ip *) buf;
  673.         hlen = ip->;ip_hl << 2;
  674.         cc -= hlen;

  675.         if (nflag)
  676.                 Printf(" %s", inet_ntoa(from->;sin_addr));
  677.         else
  678.                 Printf(" %s (%s)", inetname(from->;sin_addr),
  679.                        inet_ntoa(from->;sin_addr));

  680.         if (verbose)
  681.                 Printf (" %d bytes to %s", cc, inet_ntoa (ip->;ip_dst));
  682. }


  683. #ifdef notyet
  684. /*
  685. * Checksum routine for Internet Protocol family headers (C Version)
  686. */
  687. u_short
  688. in_cksum(addr, len)
  689.         u_short *addr;
  690.         int len;
  691. {
  692.         register int nleft = len;
  693.         register u_short *w = addr;
  694.         register u_short answer;
  695.         register int sum = 0;

  696.         /*
  697.          *  Our algorithm is simple, using a 32 bit accumulator (sum),
  698.          *  we add sequential 16 bit words to it, and at the end, fold
  699.          *  back all the carry bits from the top 16 bits into the lower
  700.          *  16 bits.
  701.          */
  702.         while (nleft >; 1)  {
  703.                 sum += *w++;
  704.                 nleft -= 2;
  705.         }

  706.         /* mop up an odd byte, if necessary */
  707.         if (nleft == 1)
  708.                 sum += *(u_char *)w;

  709.         /*
  710.          * add back carry outs from top 16 bits to low 16 bits
  711.          */
  712.         sum = (sum >;>; 16) + (sum & 0xffff);        /* add hi 16 to low 16 */
  713.         sum += (sum >;>; 16);                        /* add carry */
  714.         answer = ~sum;                                /* truncate to 16 bits */
  715.         return (answer);
  716. }
  717. #endif

  718. /*
  719. * Subtract 2 timeval structs:  out = out - in.
  720. * Out is assumed to be >;= in.
  721. */
  722. void
  723. tvsub(out, in)
  724.         register struct timeval *out, *in;
  725. {
  726.         if ((out->;tv_usec -= in->;tv_usec) < 0)   {
  727.                 out->;tv_sec--;
  728.                 out->;tv_usec += 1000000;
  729.         }
  730.         out->;tv_sec -= in->;tv_sec;
  731. }


  732. /*
  733. * Construct an Internet address representation.
  734. * If the nflag has been supplied, give
  735. * numeric value, otherwise try for symbolic name.
  736. */
  737. char *
  738. inetname(in)
  739.         struct in_addr in;
  740. {
  741.         register char *cp;
  742.         static char line[50];
  743.         struct hostent *hp;
  744.         static char domain[MAXHOSTNAMELEN + 1];
  745.         static int first = 1;

  746.         if (first && !nflag) {
  747.                 first = 0;
  748.                 if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
  749.                     (cp = index(domain, '.')))
  750.                         (void) strcpy(domain, cp + 1);
  751.                 else
  752.                         domain[0] = 0;
  753.         }
  754.         cp = 0;
  755.         if (!nflag && in.s_addr != INADDR_ANY) {
  756.                 hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
  757.                 if (hp) {
  758.                         if ((cp = index(hp->;h_name, '.')) &&
  759.                             !strcmp(cp + 1, domain))
  760.                                 *cp = 0;
  761.                         cp = hp->;h_name;
  762.                 }
  763.         }
  764.         if (cp)
  765.                 (void) strcpy(line, cp);
  766.         else {
  767.                 in.s_addr = ntohl(in.s_addr);
  768. #define C(x)        ((x) & 0xff)
  769.                 Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >;>; 24),
  770.                         C(in.s_addr >;>; 16), C(in.s_addr >;>; 8), C(in.s_addr));
  771.         }
  772.         return (line);
  773. }

  774. void
  775. usage()
  776. {
  777.         (void)fprintf(stderr,
  778. "usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
  779. [-s src_addr] [-t tos] [-w wait] host [data size]\n");
  780.         exit(1);
  781. }
复制代码

论坛徽章:
0
8 [报告]
发表于 2005-06-27 14:51 |只看该作者

traceroute源码和他的原理是什么?

traceroute uses the ipv4 ttl field or the ipv6 hop limit field and two icmp messages.
    it starts by sending a udp datagram to the destination with a ttl(or hop limit )of 1. this datagram causes the first hop router to return an icmp time exceeded in transmit error.  the ttl is then increased by one and another udp datagram sent, which locates the next router in the path. when the udp datagram reaches the final destination,the goal is to have that host return an icmp port unreachable error. this is done by sending the udp datagram to a random port that is(hopefully)not in use on that host.
    从大师的unp1 地25章抄来的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP