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