hop.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:11k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  * HOP.C   -- trace route packets take to a remote host
  3.  *
  4.  * 02-90 -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *    UC Davis, Computing Services
  6.  *    Davis, CA
  7.  * 04-90 -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  * 08-90 -- Modified by Bill Simpson to display domain names
  9.  */
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include "global.h"
  13. #include "mbuf.h"
  14. #include "usock.h"
  15. #include "socket.h"
  16. #include "session.h"
  17. #include "timer.h"
  18. #include "proc.h"
  19. #include "netuser.h"
  20. #include "domain.h"
  21. #include "commands.h"
  22. #include "tty.h"
  23. #include "cmdparse.h"
  24. #include "ip.h"
  25. #include "icmp.h"
  26. #include "udp.h"
  27. #include "hardware.h"
  28. #define HOPMAXQUERY 5 /* Max# queries each TTL value */
  29. static uint16 Hoprport = 32768+666; /* funny port for udp probes */
  30. #define HOP_HIGHBIT 32768 /* Mask to check ICMP msgs */
  31. #define HOPTRACE 1 /* Enable HOP tracing */
  32. #ifdef HOPTRACE
  33. static int Hoptrace = 0;
  34. static int hoptrace(int argc,char *argv[],void *p);
  35. #endif
  36. static unsigned  short Hopmaxttl  = 30; /* max attempts */
  37. static unsigned  short Hopmaxwait = 5; /* secs timeout each attempt */
  38. static unsigned  short Hopquery   = 3; /* #probes each attempt */
  39. static int hopcheck(int argc,char *argv[],void *p);
  40. static int hopttl(int argc,char *argv[],void *p);
  41. static int hokwait(int argc,char *argv[],void *p);
  42. static int hopnum(int argc,char *argv[],void *p);
  43. static int geticmp(int s,uint16 lport,uint16 fport,
  44. int32 *sender,char *type,char *code);
  45. static int keychar(int c);
  46. static struct cmds Hopcmds[] = {
  47. "check", hopcheck, 2048, 2, "check <host>",
  48. "maxttl", hopttl, 0, 0, NULL,
  49. "maxwait", hokwait, 0, 0, NULL,
  50. "queries", hopnum, 0, 0, NULL,
  51. #ifdef HOPTRACE
  52. "trace", hoptrace, 0, 0, NULL,
  53. #endif
  54. NULL,
  55. };
  56. /* attempt to trace route to a remote host */
  57. int
  58. dohop(argc,argv,p)
  59. int argc;
  60. char *argv[];
  61. void *p;
  62. {
  63. return subcmd(Hopcmds,argc,argv,p);
  64. }
  65. /* Set/show # queries sent each TTL value */
  66. static int
  67. hopnum(argc,argv,p)
  68. int argc;
  69. char *argv[];
  70. void *p;
  71. {
  72. uint16 r;
  73. uint16 x = Hopquery;
  74. r = setshort(&x,"# queries each attempt",argc,argv);
  75. if ((x <= 0)||(x > HOPMAXQUERY)) {
  76. printf("Must be  0 < x <= %dn",HOPMAXQUERY);
  77. return 0;
  78. } else {
  79. Hopquery = x;
  80. }
  81.     return (int)r;
  82. }
  83. #ifdef HOPTRACE
  84. /* Set/show tracelevel */
  85. static int
  86. hoptrace(argc,argv,p)
  87. int argc;
  88. char *argv[];
  89. void *p;
  90. {
  91. return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  92. }
  93. #endif
  94. /* Set/show maximum TTL value for a traceroute query */
  95. static int
  96. hopttl(argc,argv,p)
  97. int argc;
  98. char *argv[];
  99. void *p;
  100. {
  101. uint16 r;
  102. uint16 x = Hopmaxttl;
  103. r = setshort(&x,"Max attempts to reach host",argc,argv);
  104. if ((x <= 0)||(x > 255)) {
  105. printf("Must be  0 < x <= 255n");
  106. return 0;
  107. } else {
  108. Hopmaxttl = x;
  109. }
  110.     return (int)r;
  111. }
  112. /* Set/show #secs until timeout for a traceroute query */
  113. static int
  114. hokwait(argc,argv,p)
  115. int argc;
  116. char *argv[];
  117. void *p;
  118. {
  119. uint16 r;
  120. uint16 x = Hopmaxwait;
  121. r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  122. if (x <= 0) {
  123. printf("Must be >= 0n");
  124. return 0;
  125. } else {
  126. Hopmaxwait = x;
  127. }
  128.     return (int)r;
  129. }
  130. /* send probes to trace route of a remote host */
  131. static int
  132. hopcheck(argc,argv,p)
  133. int argc;
  134. char *argv[];
  135. void *p;
  136. {
  137. struct session *sp; /* Session for trace output */
  138. int s; /* Socket for queries */
  139. int s1; /* Raw socket for replies */
  140. struct socket lsocket; /* Local socket sending queries */
  141. struct socket rsocket; /* Final destination of queries */
  142. int32 cticks; /* Timer for query replies */
  143. int32 icsource; /* Sender of last ICMP reply */
  144. char ictype; /* ICMP type last ICMP reply */
  145. char iccode; /* ICMP code last ICMP reply */
  146. int32 lastaddr; /* Sender of previous ICMP reply */
  147. struct sockaddr_in sock;
  148. register struct usock *usp;
  149. register struct sockaddr_in *sinp;
  150. unsigned char sndttl, q;
  151. int tracedone = 0;
  152. int ilookup = 1; /* Control of inverse domain lookup */
  153. int c;
  154. extern int optind;
  155. char *hostname;
  156. int save_trace;
  157. int user_reset = 0;
  158. optind = 1;
  159. while((c = getopt(argc,argv,"n")) != EOF){
  160. switch(c){
  161. case 'n':
  162. ilookup = 0;
  163. break;
  164. }
  165. }
  166. hostname = argv[optind];
  167. /* Allocate a session descriptor */
  168. if((sp = newsession(Cmdline,HOP,1)) == NULL){
  169. printf("Too many sessionsn");
  170. keywait(NULL,1);
  171. return 1;
  172. }
  173. sp->inproc = keychar;
  174. s = -1;
  175. /* Setup UDP socket to remote host */
  176. sock.sin_family = AF_INET;
  177. sock.sin_port = Hoprport;
  178. printf("Resolving %s... ",hostname);
  179. if((sock.sin_addr.s_addr = resolve(hostname)) == 0){
  180. printf("unknownn",hostname);
  181. keywait(NULL,1);
  182. freesession(sp);
  183. return 1;
  184. }
  185. /* Open socket to remote host */
  186. printf("%s ",psocket((struct sockaddr *)&sock));
  187. if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  188. printf("Can't create udp socketn");
  189. keywait(NULL,1);
  190. freesession(sp);
  191. return 1;
  192. }
  193. if(connect(s,(struct sockaddr *)&sock,sizeof(sock)) == -1){
  194. printf("Connect failedn");
  195. keywait(NULL,1);
  196. freesession(sp);
  197. return 1;
  198. }
  199. if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  200. printf("Can't create raw socketn");
  201. keywait(NULL,1);
  202. close(s);
  203. freesession(sp);
  204. return 1;
  205. }
  206. printf("n");
  207. /* turn off icmp tracing while hop-checking */
  208. save_trace = Icmp_trace;
  209. Icmp_trace = 0;
  210. /* Setup structures to send queries */
  211. /* Retrieve socket details for user socket control block */
  212. usp = itop(s);
  213. sinp = (struct sockaddr_in *)usp->name;
  214. lsocket.address = sinp->sin_addr.s_addr;
  215. lsocket.port = sinp->sin_port;
  216. sinp = (struct sockaddr_in *)usp->peername;
  217. rsocket.address = sinp->sin_addr.s_addr;
  218. /* Send queries with increasing TTL; start with TTL=1 */
  219. if (Hoptrace)
  220. logmsg(s,"HOPCHECK start trace to %sn",sp->name);
  221. for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  222. /* Increment funny UDP port number each round */
  223. rsocket.port = sinp->sin_port;
  224. printf("%3d:",sndttl);
  225. lastaddr = (int32)0;
  226. /* Send a round of queries */
  227. for (q=0; (q < Hopquery); ++q) {
  228. struct mbuf *bp;
  229. bp = ambufw(0);
  230. send_udp(&lsocket,&rsocket,0,sndttl,&bp,0,0,0);
  231. cticks = msclock();
  232. kalarm( ((long)Hopmaxwait*1000L) );
  233. /* Wait for a reply to our query */
  234. if(geticmp(s1,lsocket.port,rsocket.port,
  235.  &icsource,&ictype,&iccode) == -1){
  236. if(errno != EALARM){
  237. user_reset = 1;
  238. goto done; /* User reset */
  239. }
  240. /* Alarm rang, give up waiting for replies */
  241. printf(" ***");
  242. continue;
  243. }
  244. /* Save #ticks taken for reply */
  245.                         cticks = msclock() - cticks;
  246. /* Report ICMP reply */
  247. if (icsource != lastaddr) {
  248. struct rr *save_rrlp, *rrlp;
  249. if(lastaddr != (int32)0)
  250. printf("n    ");
  251. printf(" %-15s",inet_ntoa(icsource));
  252. if(ilookup){
  253. for(rrlp = save_rrlp = inverse_a(icsource);
  254.     rrlp != NULL;
  255.     rrlp = rrlp->next){
  256. if(rrlp->rdlength > 0){
  257. switch(rrlp->type){
  258. case TYPE_PTR:
  259. printf(" %s", rrlp->rdata.name);
  260. goto got_name;
  261. case TYPE_A:
  262. printf(" %s", rrlp->name);
  263. goto got_name;
  264. }
  265. #ifdef notdef
  266. if(rrlp->next != NULL)
  267. printf("n%20s"," ");
  268. #endif
  269. }
  270. }
  271. got_name: ;
  272. free_rr(save_rrlp);
  273. }
  274. lastaddr = icsource;
  275. }
  276.                         printf(" (%ld ms)",cticks);
  277. #ifdef HOPTRACE
  278. if (Hoptrace)
  279. logmsg(s,
  280.     "(hopcheck) ICMP from %s (%ldms) %s %s",
  281.     inet_ntoa(icsource),
  282.     cticks,
  283.     Icmptypes[ictype],
  284.     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  285. #endif
  286. /* Check type of reply */
  287. if (ictype == ICMP_TIME_EXCEED)
  288. continue;
  289. /* Reply was: destination unreachable */
  290. switch(iccode) {
  291. case ICMP_PORT_UNREACH:
  292. ++tracedone;
  293. break;
  294. case ICMP_NET_UNREACH:
  295. ++tracedone;
  296. printf(" !N");
  297. break;
  298. case ICMP_HOST_UNREACH:
  299. ++tracedone;
  300. printf(" !H");
  301. break;
  302. case ICMP_PROT_UNREACH:
  303. ++tracedone;
  304. printf(" !P");
  305. break;
  306. case ICMP_FRAG_NEEDED:
  307. ++tracedone;
  308. printf(" !F");
  309. break;
  310. case ICMP_ROUTE_FAIL:
  311. ++tracedone;
  312. printf(" !S");
  313. break;
  314.                         case ICMP_ADMIN_PROHIB:
  315.                                 ++tracedone;
  316.                                 printf(" !A");
  317.                                 break;
  318.                         default:
  319.                                 printf(" !?");
  320.                                 break;
  321. }
  322. }
  323. /* Done with this round of queries */
  324. kalarm((long)0);
  325. printf("n");
  326. /* Check if we reached remote host this round */
  327. if (tracedone != 0)
  328. break;
  329. }
  330. /* Done with traceroute */
  331. done: close(s);
  332. s = -1;
  333. close(s1);
  334. if(user_reset)
  335. printf("n"); /* May have been in middle of line */
  336. printf("traceroute done: ");
  337. Icmp_trace = save_trace;
  338. if(user_reset){
  339. printf("user abortn");
  340. } else if (sndttl >= Hopmaxttl) {
  341. printf("!! maximum TTL exceededn");
  342. } else if ((icsource == rsocket.address)
  343.     &&(iccode == ICMP_PORT_UNREACH)) {
  344. printf("normal (%s %s)n",
  345. Icmptypes[ictype],Unreach[iccode]);
  346. } else {
  347. printf("!! %s %sn",
  348. Icmptypes[ictype],Unreach[iccode]);
  349. }
  350. #ifdef HOPTRACE
  351. if (Hoptrace)
  352. logmsg(s,"HOPCHECK to %s done",sp->name);
  353. #endif
  354. keywait(NULL,1);
  355. freesession(sp);
  356. return 0;
  357. }
  358. /* Hop check session keyboard upcall routine -- handles ^C */
  359. static int
  360. keychar(c)
  361. int c;
  362. {
  363. switch(c){
  364. case CTLC:
  365. alert(Current->proc,EABORT);
  366. return 0;
  367. }
  368. return 1;
  369. }
  370. /* Read raw network socket looking for ICMP messages in response to our
  371.  * UDP probes
  372.  */
  373. static int
  374. geticmp(s,lport,fport,sender,type,code)
  375. int s;
  376. uint16 lport;
  377. uint16 fport;
  378. int32 *sender;
  379. char *type,*code;
  380. {
  381. int size;
  382. struct icmp icmphdr;
  383. struct ip iphdr;
  384. struct udp udphdr;
  385. struct mbuf *bp;
  386. struct sockaddr_in sock;
  387. for(;;){
  388. size = sizeof(sock);
  389. if(recv_mbuf(s,&bp,0,(struct sockaddr *)&sock,&size) == -1)
  390. return -1;
  391. /* It's an ICMP message, let's see if it's interesting */
  392. ntohicmp(&icmphdr,&bp);
  393. if((icmphdr.type != ICMP_TIME_EXCEED ||
  394.  icmphdr.code != ICMP_TTL_EXCEED)
  395.  && icmphdr.type != ICMP_DEST_UNREACH){
  396. /* We're not interested in these */
  397. free_p(&bp);
  398. continue;
  399. }
  400. ntohip(&iphdr,&bp);
  401. if(iphdr.protocol != UDP_PTCL){
  402. /* Not UDP, so can't be interesting */
  403. free_p(&bp);
  404. continue;
  405. }
  406. ntohudp(&udphdr,&bp);
  407. if(udphdr.dest != fport || udphdr.source != lport){
  408. /* Not from our hopcheck session */
  409. free_p(&bp);
  410. continue;
  411. }
  412. /* Passed all of our checks, so return it */
  413. *sender = sock.sin_addr.s_addr;
  414. *type = icmphdr.type;
  415. *code = icmphdr.code;
  416. free_p(&bp);
  417. return 0;
  418. }
  419. }