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