pinger.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:9k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: pinger.c,v 1.39 1998/11/21 16:54:28 wessels Exp $
  3.  *
  4.  * DEBUG: section 42    ICMP Pinger program
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #if USE_ICMP
  36. #include <netinet/in_systm.h>
  37. #include <netinet/in.h>
  38. #include <netinet/ip.h>
  39. #include <netinet/ip_icmp.h>
  40. #ifndef _SQUID_LINUX_
  41. #define icmphdr icmp
  42. #define iphdr ip
  43. #endif
  44. #ifdef _SQUID_LINUX_
  45. #ifdef icmp_id
  46. #undef icmp_id
  47. #endif
  48. #ifdef icmp_seq
  49. #undef icmp_seq
  50. #endif
  51. #define icmp_type type
  52. #define icmp_code code
  53. #define icmp_cksum checksum
  54. #define icmp_id un.echo.id
  55. #define icmp_seq un.echo.sequence
  56. #define ip_hl ihl
  57. #define ip_v version
  58. #define ip_tos tos
  59. #define ip_len tot_len
  60. #define ip_id id
  61. #define ip_off frag_off
  62. #define ip_ttl ttl
  63. #define ip_p protocol
  64. #define ip_sum check
  65. #define ip_src saddr
  66. #define ip_dst daddr
  67. #endif
  68. #if ALLOW_SOURCE_PING
  69. #define MAX_PKT_SZ 8192
  70. #define MAX_PAYLOAD (MAX_PKT_SZ - sizeof(struct icmphdr) - sizeof (char) - sizeof(struct timeval) - 1)
  71. #else
  72. #define MAX_PAYLOAD SQUIDHOSTNAMELEN
  73. #define MAX_PKT_SZ (MAX_PAYLOAD + sizeof(struct timeval) + sizeof (char) + sizeof(struct icmphdr) + 1)
  74. #endif
  75. typedef struct {
  76.     struct timeval tv;
  77.     unsigned char opcode;
  78.     char payload[MAX_PAYLOAD];
  79. } icmpEchoData;
  80. int icmp_ident = -1;
  81. int icmp_pkts_sent = 0;
  82. static const char *icmpPktStr[] =
  83. {
  84.     "Echo Reply",
  85.     "ICMP 1",
  86.     "ICMP 2",
  87.     "Destination Unreachable",
  88.     "Source Quench",
  89.     "Redirect",
  90.     "ICMP 6",
  91.     "ICMP 7",
  92.     "Echo",
  93.     "ICMP 9",
  94.     "ICMP 10",
  95.     "Time Exceeded",
  96.     "Parameter Problem",
  97.     "Timestamp",
  98.     "Timestamp Reply",
  99.     "Info Request",
  100.     "Info Reply",
  101.     "Out of Range Type"
  102. };
  103. static int in_cksum(unsigned short *ptr, int size);
  104. static void pingerRecv(void);
  105. static void pingerLog(struct icmphdr *, struct in_addr, int, int);
  106. static int ipHops(int ttl);
  107. static void pingerSendtoSquid(pingerReplyData * preply);
  108. void
  109. pingerOpen(void)
  110. {
  111.     struct protoent *proto = NULL;
  112.     if ((proto = getprotobyname("icmp")) == 0) {
  113. debug(42, 0) ("pingerOpen: unknown protocol: icmpn");
  114. exit(1);
  115.     }
  116.     icmp_sock = socket(PF_INET, SOCK_RAW, proto->p_proto);
  117.     if (icmp_sock < 0) {
  118. debug(50, 0) ("pingerOpen: icmp_sock: %sn", xstrerror());
  119. exit(1);
  120.     }
  121.     icmp_ident = getpid() & 0xffff;
  122.     debug(42, 0) ("pinger: ICMP socket openedn");
  123. }
  124. void
  125. pingerClose(void)
  126. {
  127.     close(icmp_sock);
  128.     icmp_sock = -1;
  129.     icmp_ident = 0;
  130. }
  131. static void
  132. pingerSendEcho(struct in_addr to, int opcode, char *payload, int len)
  133. {
  134.     LOCAL_ARRAY(char, pkt, MAX_PKT_SZ);
  135.     struct icmphdr *icmp = NULL;
  136.     icmpEchoData *echo;
  137.     int icmp_pktsize = sizeof(struct icmphdr);
  138.     struct sockaddr_in S;
  139.     memset(pkt, '', MAX_PKT_SZ);
  140.     icmp = (struct icmphdr *) (void *) pkt;
  141.     icmp->icmp_type = ICMP_ECHO;
  142.     icmp->icmp_code = 0;
  143.     icmp->icmp_cksum = 0;
  144.     icmp->icmp_id = icmp_ident;
  145.     icmp->icmp_seq = (u_short) icmp_pkts_sent++;
  146.     echo = (icmpEchoData *) (icmp + 1);
  147.     echo->opcode = (unsigned char) opcode;
  148.     echo->tv = current_time;
  149.     icmp_pktsize += sizeof(icmpEchoData) - MAX_PAYLOAD;
  150.     if (payload) {
  151. if (len > MAX_PAYLOAD)
  152.     len = MAX_PAYLOAD;
  153. xmemcpy(echo->payload, payload, len);
  154. icmp_pktsize += len;
  155.     }
  156.     icmp->icmp_cksum = in_cksum((u_short *) icmp, icmp_pktsize);
  157.     S.sin_family = AF_INET;
  158.     S.sin_addr = to;
  159.     S.sin_port = 0;
  160.     assert(icmp_pktsize <= MAX_PKT_SZ);
  161.     sendto(icmp_sock,
  162. pkt,
  163. icmp_pktsize,
  164. 0,
  165. (struct sockaddr *) &S,
  166. sizeof(struct sockaddr_in));
  167.     pingerLog(icmp, to, 0, 0);
  168. }
  169. static void
  170. pingerRecv(void)
  171. {
  172.     int n;
  173.     socklen_t fromlen;
  174.     struct sockaddr_in from;
  175.     int iphdrlen = 20;
  176.     struct iphdr *ip = NULL;
  177.     struct icmphdr *icmp = NULL;
  178.     static char *pkt = NULL;
  179.     struct timeval now;
  180.     icmpEchoData *echo;
  181.     static pingerReplyData preply;
  182.     if (pkt == NULL)
  183. pkt = xmalloc(MAX_PKT_SZ);
  184.     fromlen = sizeof(from);
  185.     n = recvfrom(icmp_sock,
  186. pkt,
  187. MAX_PKT_SZ,
  188. 0,
  189. (struct sockaddr *) &from,
  190. &fromlen);
  191.     gettimeofday(&now, NULL);
  192.     debug(42, 9) ("pingerRecv: %d bytes from %sn", n, inet_ntoa(from.sin_addr));
  193.     ip = (struct iphdr *) (void *) pkt;
  194. #if HAVE_IP_HL
  195.     iphdrlen = ip->ip_hl << 2;
  196. #else /* HAVE_IP_HL */
  197. #if WORDS_BIGENDIAN
  198.     iphdrlen = (ip->ip_vhl >> 4) << 2;
  199. #else
  200.     iphdrlen = (ip->ip_vhl & 0xF) << 2;
  201. #endif
  202. #endif /* HAVE_IP_HL */
  203.     icmp = (struct icmphdr *) (void *) (pkt + iphdrlen);
  204.     if (icmp->icmp_type != ICMP_ECHOREPLY)
  205. return;
  206.     if (icmp->icmp_id != icmp_ident)
  207. return;
  208.     echo = (icmpEchoData *) (void *) (icmp + 1);
  209.     preply.from = from.sin_addr;
  210.     preply.opcode = echo->opcode;
  211.     preply.hops = ipHops(ip->ip_ttl);
  212.     preply.rtt = tvSubMsec(echo->tv, now);
  213.     preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT_SZ);
  214.     pingerSendtoSquid(&preply);
  215.     pingerLog(icmp, from.sin_addr, preply.rtt, preply.hops);
  216. }
  217. static int
  218. in_cksum(unsigned short *ptr, int size)
  219. {
  220.     long sum;
  221.     unsigned short oddbyte;
  222.     unsigned short answer;
  223.     sum = 0;
  224.     while (size > 1) {
  225. sum += *ptr++;
  226. size -= 2;
  227.     }
  228.     if (size == 1) {
  229. oddbyte = 0;
  230. *((unsigned char *) &oddbyte) = *(unsigned char *) ptr;
  231. sum += oddbyte;
  232.     }
  233.     sum = (sum >> 16) + (sum & 0xffff);
  234.     sum += (sum >> 16);
  235.     answer = ~sum;
  236.     return (answer);
  237. }
  238. static void
  239. pingerLog(struct icmphdr *icmp, struct in_addr addr, int rtt, int hops)
  240. {
  241.     debug(42, 2) ("pingerLog: %9d.%06d %-16s %d %-15.15s %dms %d hopsn",
  242. (int) current_time.tv_sec,
  243. (int) current_time.tv_usec,
  244. inet_ntoa(addr),
  245. (int) icmp->icmp_type,
  246. icmpPktStr[icmp->icmp_type],
  247. rtt,
  248. hops);
  249. }
  250. static int
  251. ipHops(int ttl)
  252. {
  253.     if (ttl < 33)
  254. return 33 - ttl;
  255.     if (ttl < 63)
  256. return 63 - ttl; /* 62 = (64+60)/2 */
  257.     if (ttl < 65)
  258. return 65 - ttl; /* 62 = (64+60)/2 */
  259.     if (ttl < 129)
  260. return 129 - ttl;
  261.     if (ttl < 193)
  262. return 193 - ttl;
  263.     return 256 - ttl;
  264. }
  265. static int
  266. pingerReadRequest(void)
  267. {
  268.     static pingerEchoData pecho;
  269.     int n;
  270.     int guess_size;
  271.     memset(&pecho, '', sizeof(pecho));
  272.     n = recv(0, (char *) &pecho, sizeof(pecho), 0);
  273.     if (n < 0)
  274. return n;
  275.     guess_size = n - (sizeof(pingerEchoData) - PINGER_PAYLOAD_SZ);
  276.     if (guess_size != pecho.psize)
  277. fprintf(stderr, "size mismatch, guess=%d psize=%dn",
  278.     guess_size, pecho.psize);
  279.     pingerSendEcho(pecho.to,
  280. pecho.opcode,
  281. pecho.payload,
  282. pecho.psize);
  283.     return n;
  284. }
  285. static void
  286. pingerSendtoSquid(pingerReplyData * preply)
  287. {
  288.     int len = sizeof(pingerReplyData) - MAX_PKT_SZ + preply->psize;
  289.     if (send(1, (char *) preply, len, 0) < 0) {
  290. debug(50, 0) ("pinger: send: %sn", xstrerror());
  291. exit(1);
  292.     }
  293. }
  294. time_t
  295. getCurrentTime(void)
  296. {
  297. #if GETTIMEOFDAY_NO_TZP
  298.     gettimeofday(&current_time);
  299. #else
  300.     gettimeofday(&current_time, NULL);
  301. #endif
  302.     return squid_curtime = current_time.tv_sec;
  303. }
  304. int
  305. main(int argc, char *argv[])
  306. {
  307.     fd_set R;
  308.     int x;
  309.     struct timeval tv;
  310.     const char *debug_args = "ALL,1";
  311.     char *t;
  312.     time_t last_check_time = 0;
  313.     if ((t = getenv("SQUID_DEBUG")))
  314. debug_args = xstrdup(t);
  315.     getCurrentTime();
  316.     _db_init(NULL, debug_args);
  317.     pingerOpen();
  318.     for (;;) {
  319. tv.tv_sec = 10;
  320. tv.tv_usec = 0;
  321. FD_ZERO(&R);
  322. FD_SET(0, &R);
  323. FD_SET(icmp_sock, &R);
  324. x = select(icmp_sock + 1, &R, NULL, NULL, &tv);
  325. getCurrentTime();
  326. if (x < 0)
  327.     exit(1);
  328. if (FD_ISSET(0, &R))
  329.     if (pingerReadRequest() < 0) {
  330. debug(42, 0) ("Pinger exiting.n");
  331. exit(1);
  332.     }
  333. if (FD_ISSET(icmp_sock, &R))
  334.     pingerRecv();
  335. if (10 + last_check_time < squid_curtime) {
  336.     if (send(1, (char *) &tv, 0, 0) < 0)
  337. exit(1);
  338.     last_check_time = squid_curtime;
  339. }
  340.     }
  341.     /* NOTREACHED */
  342. }
  343. #else
  344. #include <stdio.h>
  345. int
  346. main(int argc, char *argv[])
  347. {
  348.     fprintf(stderr, "%s: ICMP support not compiled in.n", argv[0]);
  349.     return 1;
  350. }
  351. #endif /* USE_ICMP */