]> git.ipfire.org Git - thirdparty/squid.git/blame - src/pinger.cc
Adding SHA source code from Perl module source.
[thirdparty/squid.git] / src / pinger.cc
CommitLineData
9d90e665 1
2/*
d57288d2 3 * $Id: pinger.cc,v 1.28 1997/10/31 05:15:08 wessels Exp $
9d90e665 4 *
f43e2ec2 5 * DEBUG: section 42 ICMP Pinger program
9d90e665 6 * AUTHOR: Duane Wessels
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
9d90e665 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
9d90e665 32#include "squid.h"
9d90e665 33
43426991 34#if USE_ICMP
35
9d90e665 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
429fdbec 66#define MAX_PKT_SZ 8192
67#define MAX_PAYLOAD (MAX_PKT_SZ - sizeof(struct icmphdr) - sizeof (char) - sizeof(struct timeval) - 1)
9d90e665 68
69typedef struct {
70 struct timeval tv;
71 unsigned char opcode;
72 char payload[MAX_PAYLOAD];
73} icmpEchoData;
74
5be53f2d 75int icmp_ident = -1;
76int icmp_pkts_sent = 0;
9d90e665 77
0ee4272b 78static const char *icmpPktStr[] =
9d90e665 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
f5b8bbc4 100static int in_cksum(unsigned short *ptr, int size);
101static void pingerRecv(void);
102static void pingerLog(struct icmphdr *, struct in_addr, int, int);
103static int ipHops(int ttl);
104static void pingerSendtoSquid(pingerReplyData * preply);
9d90e665 105
106void
107pingerOpen(void)
108{
109 struct protoent *proto = NULL;
110 if ((proto = getprotobyname("icmp")) == 0) {
a3d5953d 111 debug(42, 0) ("pingerOpen: unknown protocol: icmp\n");
9d90e665 112 exit(1);
113 }
114 icmp_sock = socket(PF_INET, SOCK_RAW, proto->p_proto);
115 if (icmp_sock < 0) {
a3d5953d 116 debug(50, 0) ("pingerOpen: icmp_sock: %s\n", xstrerror());
9d90e665 117 exit(1);
118 }
119 icmp_ident = getpid() & 0xffff;
a3d5953d 120 debug(42, 0) ("ICMP socket opened\n", icmp_sock);
9d90e665 121}
122
9d90e665 123void
124pingerClose(void)
125{
126 close(icmp_sock);
127 icmp_sock = -1;
128 icmp_ident = 0;
129}
130
131static void
132pingerSendEcho(struct in_addr to, int opcode, char *payload, int len)
133{
429fdbec 134 LOCAL_ARRAY(char, pkt, MAX_PKT_SZ);
9d90e665 135 struct icmphdr *icmp = NULL;
136 icmpEchoData *echo;
137 int icmp_pktsize = sizeof(struct icmphdr);
138 int x;
139 struct sockaddr_in S;
429fdbec 140 memset(pkt, '\0', MAX_PKT_SZ);
9d90e665 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;
3c0117c9 154 xmemcpy(echo->payload, payload, len);
9d90e665 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
170static void
171pingerRecv(void)
172{
173 int n;
174 int fromlen;
175 struct sockaddr_in from;
176 int iphdrlen = 20;
177 struct iphdr *ip = NULL;
639ed75c 178 struct icmphdr *icmp = NULL;
429fdbec 179 LOCAL_ARRAY(char, pkt, MAX_PKT_SZ);
9d90e665 180 struct timeval now;
181 icmpEchoData *echo;
182 static pingerReplyData preply;
183
184 fromlen = sizeof(from);
185 n = recvfrom(icmp_sock,
186 pkt,
429fdbec 187 MAX_PKT_SZ,
9d90e665 188 0,
189 (struct sockaddr *) &from,
190 &fromlen);
191 gettimeofday(&now, NULL);
a3d5953d 192 debug(42, 9) ("pingerRecv: %d bytes from %s\n", n, inet_ntoa(from.sin_addr));
9d90e665 193 ip = (struct iphdr *) (void *) pkt;
194#if HAVE_IP_HL
195 iphdrlen = ip->ip_hl << 2;
9c4f4529 196#else /* HAVE_IP_HL */
d57288d2 197#if WORDS_BIGENDIAN
9d90e665 198 iphdrlen = (ip->ip_vhl >> 4) << 2;
d57288d2 199#else
9d90e665 200 iphdrlen = (ip->ip_vhl & 0xF) << 2;
201#endif
9c4f4529 202#endif /* HAVE_IP_HL */
9d90e665 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);
429fdbec 213 preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT_SZ);
9d90e665 214 pingerSendtoSquid(&preply);
215 pingerLog(icmp, from.sin_addr, preply.rtt, preply.hops);
216}
217
218
219static int
220in_cksum(unsigned short *ptr, int size)
221{
639ed75c 222 long sum;
9d90e665 223 unsigned short oddbyte;
639ed75c 224 unsigned short answer;
9d90e665 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
241static void
242pingerLog(struct icmphdr *icmp, struct in_addr addr, int rtt, int hops)
243{
a3d5953d 244 debug(42, 2) ("pingerLog: %9d.%06d %-16s %d %-15.15s %dms %d hops\n",
9d90e665 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
254static int
255ipHops(int ttl)
256{
f15528f6 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;
9d90e665 268}
269
270static int
271pingerReadRequest(void)
272{
273 static pingerEchoData pecho;
274 int n;
275 int guess_size;
e924600d 276 memset(&pecho, '\0', sizeof(pecho));
9d90e665 277 n = recv(0, (char *) &pecho, sizeof(pecho), 0);
429fdbec 278 if (n < 0)
9d90e665 279 return n;
429fdbec 280 guess_size = n - (sizeof(pingerEchoData) - MAX_PKT_SZ);
9d90e665 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
291static void
292pingerSendtoSquid(pingerReplyData * preply)
293{
429fdbec 294 int len = sizeof(pingerReplyData) - MAX_PKT_SZ + preply->psize;
d56d7f57 295 if (send(1, (char *) preply, len, 0) < 0) {
a3d5953d 296 debug(50, 0) ("pinger: send: %s\n", xstrerror());
365a4bce 297 exit(1);
298 }
9d90e665 299}
300
301time_t
302getCurrentTime(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
313int
314main(int argc, char *argv[])
315{
316 fd_set R;
317 int x;
365a4bce 318 struct timeval tv;
0ee4272b 319 const char *debug_args = "ALL,1";
365a4bce 320 char *t;
145766ef 321 time_t last_check_time = 0;
365a4bce 322
323 if ((t = getenv("SQUID_DEBUG")))
324 debug_args = xstrdup(t);
9d90e665 325 getCurrentTime();
365a4bce 326 _db_init(NULL, debug_args);
327
9d90e665 328 pingerOpen();
329 for (;;) {
145766ef 330 tv.tv_sec = 10;
365a4bce 331 tv.tv_usec = 0;
9d90e665 332 FD_ZERO(&R);
333 FD_SET(0, &R);
334 FD_SET(icmp_sock, &R);
365a4bce 335 x = select(icmp_sock + 1, &R, NULL, NULL, &tv);
9d90e665 336 getCurrentTime();
365a4bce 337 if (x < 0)
9d90e665 338 return 1;
339 if (FD_ISSET(0, &R))
429fdbec 340 if (pingerReadRequest() < 0) {
a3d5953d 341 debug(42, 0) ("Pinger exiting.\n");
9d90e665 342 return 1;
429fdbec 343 }
9d90e665 344 if (FD_ISSET(icmp_sock, &R))
345 pingerRecv();
eb647c47 346 if (10 + last_check_time < squid_curtime) {
d56d7f57 347 if (send(1, (char *) &tv, 0, 0) < 0)
f6c78bd2 348 return 1;
145766ef 349 last_check_time = squid_curtime;
350 }
9d90e665 351 }
145766ef 352 /* NOTREACHED */
9d90e665 353}
365a4bce 354
9d90e665 355#else
356#include <stdio.h>
357int
358main(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 */