]>
Commit | Line | Data |
---|---|---|
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 | |
83 | typedef struct { | |
84 | struct timeval tv; | |
85 | unsigned char opcode; | |
86 | char payload[MAX_PAYLOAD]; | |
87 | } icmpEchoData; | |
88 | ||
5be53f2d | 89 | int icmp_ident = -1; |
90 | int icmp_pkts_sent = 0; | |
9d90e665 | 91 | |
0ee4272b | 92 | static 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 | 114 | static int in_cksum(unsigned short *ptr, int size); |
115 | static void pingerRecv(void); | |
116 | static void pingerLog(struct icmphdr *, struct in_addr, int, int); | |
117 | static int ipHops(int ttl); | |
118 | static void pingerSendtoSquid(pingerReplyData * preply); | |
9d90e665 | 119 | |
120 | void | |
121 | pingerOpen(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 | 137 | void |
138 | pingerClose(void) | |
139 | { | |
140 | close(icmp_sock); | |
141 | icmp_sock = -1; | |
142 | icmp_ident = 0; | |
143 | } | |
144 | ||
145 | static void | |
146 | pingerSendEcho(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 | ||
195 | static void | |
196 | pingerRecv(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 | ||
246 | static int | |
247 | in_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 | ||
268 | static void | |
269 | pingerLog(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 | ||
281 | static int | |
282 | ipHops(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 | ||
297 | static int | |
298 | pingerReadRequest(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 | ||
321 | static void | |
322 | pingerSendtoSquid(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 | ||
331 | time_t | |
332 | getCurrentTime(void) | |
333 | { | |
334 | #if GETTIMEOFDAY_NO_TZP | |
335 | gettimeofday(¤t_time); | |
336 | #else | |
337 | gettimeofday(¤t_time, NULL); | |
338 | #endif | |
339 | return squid_curtime = current_time.tv_sec; | |
340 | } | |
341 | ||
342 | ||
343 | int | |
344 | main(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> | |
394 | int | |
395 | main(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 */ |