]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icmp/IcmpSquid.cc
Changed some structs to classes.
[thirdparty/squid.git] / src / icmp / IcmpSquid.cc
CommitLineData
cc192b50 1/*
cc192b50 2 * DEBUG: section 37 ICMP Routines
3 * AUTHOR: Duane Wessels, Amos Jeffries
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
cc192b50 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
cc192b50 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32
582c2af2 33#include "squid.h"
d841c88d
AJ
34#include "comm.h"
35#include "comm/Loops.h"
c4ad1349 36#include "fd.h"
9b5c4a9a
AJ
37#include "icmp/IcmpSquid.h"
38#include "icmp/net_db.h"
055421ee 39#include "ip/tools.h"
96097880 40#include "SquidIpc.h"
cc192b50 41#include "SquidTime.h"
42
21d845b1
FC
43#if HAVE_ERRNO_H
44#include <errno.h>
45#endif
46
cc192b50 47// Instance global to be available in main() and elsewhere.
b826ffb5 48IcmpSquid icmpEngine;
cc192b50 49
50#if USE_ICMP
51
52#define S_ICMP_ECHO 1
53#if DEAD_CODE
54#define S_ICMP_ICP 2
55#endif
56#define S_ICMP_DOM 3
57
58static void * hIpc;
59static pid_t pid;
60
61#endif /* USE_ICMP */
62
b826ffb5 63IcmpSquid::IcmpSquid() : Icmp()
cc192b50 64{
65 ; // nothing new.
66}
67
b826ffb5 68IcmpSquid::~IcmpSquid()
cc192b50 69{
70 Close();
71}
72
cc192b50 73#if USE_ICMP
74
75void
b7ac5457 76IcmpSquid::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
cc192b50 77{
78 static pingerEchoData pecho;
79 int x, slen;
80
81 /** \li Does nothing if the pinger socket is not available. */
26ac0430 82 if (icmp_sock < 0) {
cc192b50 83 debugs(37, 2, HERE << " Socket Closed. Aborted send to " << pecho.to << ", opcode " << opcode << ", len " << pecho.psize);
84 return;
85 }
86
87 /** \li If no payload is given or is set as NULL it will ignore payload and len */
26ac0430 88 if (!payload)
cc192b50 89 len = 0;
26ac0430 90
cc192b50 91 /** \li Otherwise if len is 0, uses strlen() to detect length of payload.
92 \bug This will result in part of the payload being truncated if it contains a NULL character.
93 \bug Or it may result in a buffer over-run if the payload is not nul-terminated properly.
94 */
95 else if (payload && len == 0)
96 len = strlen(payload);
97
98 /** \li
99 \bug If length specified or auto-detected is greater than the possible payload squid will die with an assert.
100 \todo This should perhapse be reduced to a truncated payload? or no payload. A WARNING is due anyway.
101 */
102 assert(len <= PINGER_PAYLOAD_SZ);
103
104 pecho.to = to;
105
106 pecho.opcode = (unsigned char) opcode;
107
108 pecho.psize = len;
109
26ac0430 110 if (len > 0)
41d00cd3 111 memcpy(pecho.payload, payload, len);
cc192b50 112
113 slen = sizeof(pingerEchoData) - PINGER_PAYLOAD_SZ + pecho.psize;
114
115 debugs(37, 2, HERE << "to " << pecho.to << ", opcode " << opcode << ", len " << pecho.psize);
116
117 x = comm_udp_send(icmp_sock, (char *)&pecho, slen, 0);
118
119 if (x < 0) {
e0236918 120 debugs(37, DBG_IMPORTANT, HERE << "send: " << xstrerror());
cc192b50 121
122 /** \li If the send results in ECONNREFUSED or EPIPE errors from helper, will cleanly shutdown the module. */
123 /** \todo This should try restarting the helper a few times?? before giving up? */
124 if (errno == ECONNREFUSED || errno == EPIPE) {
125 Close();
126 return;
127 }
128 /** All other send errors are ignored. */
9166e142 129 } else if (x != slen) {
e0236918 130 debugs(37, DBG_IMPORTANT, HERE << "Wrote " << x << " of " << slen << " bytes");
cc192b50 131 }
132}
133
134// static Callback to wrap the squid-side ICMP handler.
b826ffb5 135// the IcmpSquid::Recv cannot be declared both static and virtual.
cc192b50 136static void
137icmpSquidRecv(int unused1, void *unused2)
138{
139 icmpEngine.Recv();
140}
141
142void
b826ffb5 143IcmpSquid::Recv()
cc192b50 144{
145 int n;
146 static int fail_count = 0;
147 pingerReplyData preply;
b7ac5457 148 static Ip::Address F;
cc192b50 149
d841c88d 150 Comm::SetSelect(icmp_sock, COMM_SELECT_READ, icmpSquidRecv, NULL, 0);
cc192b50 151 memset(&preply, '\0', sizeof(pingerReplyData));
152 n = comm_udp_recv(icmp_sock,
153 (char *) &preply,
154 sizeof(pingerReplyData),
155 0);
156
157 if (n < 0 && EAGAIN != errno) {
e0236918 158 debugs(37, DBG_IMPORTANT, HERE << "recv: " << xstrerror());
cc192b50 159
160 if (errno == ECONNREFUSED)
161 Close();
162
163 if (errno == ECONNRESET)
164 Close();
165
166 if (++fail_count == 10)
167 Close();
168
169 return;
170 }
171
172 fail_count = 0;
173
174 /** If its a test probe from the pinger. Do nothing. */
175 if (n == 0) {
176 return;
177 }
178
179 F = preply.from;
180
181 F.SetPort(0);
182
183 switch (preply.opcode) {
184
185 case S_ICMP_ECHO:
186 debugs(37,4, HERE << " ICMP_ECHO of " << preply.from << " gave: hops=" << preply.hops <<", rtt=" << preply.rtt);
187 break;
188
189 case S_ICMP_DOM:
190 debugs(37,4, HERE << " DomainPing of " << preply.from << " gave: hops=" << preply.hops <<", rtt=" << preply.rtt);
191 netdbHandlePingReply(F, preply.hops, preply.rtt);
192 break;
193
194 default:
e0236918 195 debugs(37, DBG_IMPORTANT, HERE << "Bad opcode: " << preply.opcode << " from " << F);
cc192b50 196 break;
197 }
198}
199
200#endif /* USE_ICMP */
201
202void
b7ac5457 203IcmpSquid::DomainPing(Ip::Address &to, const char *domain)
cc192b50 204{
205#if USE_ICMP
206 debugs(37, 4, HERE << "'" << domain << "' (" << to << ")");
207 SendEcho(to, S_ICMP_DOM, domain, 0);
208#endif
209}
210
211int
b826ffb5 212IcmpSquid::Open(void)
cc192b50 213{
214#if USE_ICMP
215 const char *args[2];
216 int rfd;
217 int wfd;
b7ac5457 218 Ip::Address localhost;
cc192b50 219
220 /* User configured disabled. */
26ac0430 221 if (!Config.pinger.enable) {
cc192b50 222 Close();
223 return -1;
224 }
225
226 args[0] = "(pinger)";
227 args[1] = NULL;
228 localhost.SetLocalhost();
229
230 /*
231 * Do NOT use IPC_DGRAM (=IPC_UNIX_DGRAM) here because you can't
232 * send() more than 4096 bytes on a socketpair() socket (at
233 * least on FreeBSD).
234 */
235 pid = ipcCreate(IPC_UDP_SOCKET,
236 Config.pinger.program,
237 args,
238 "Pinger Socket",
239 localhost,
240 &rfd,
241 &wfd,
242 &hIpc);
243
244 if (pid < 0)
245 return -1;
246
247 assert(rfd == wfd);
248
249 icmp_sock = rfd;
250
251 fd_note(icmp_sock, "pinger");
252
d841c88d 253 Comm::SetSelect(icmp_sock, COMM_SELECT_READ, icmpSquidRecv, NULL, 0);
cc192b50 254
933dd095 255 commUnsetFdTimeout(icmp_sock);
cc192b50 256
e0236918 257 debugs(37, DBG_IMPORTANT, HERE << "Pinger socket opened on FD " << icmp_sock);
cc192b50 258
259 /* Tests the pinger immediately using localhost */
055421ee
AJ
260 if (Ip::EnableIpv6)
261 SendEcho(localhost, S_ICMP_ECHO, "ip6-localhost");
26ac0430 262 if (localhost.SetIPv4())
cc192b50 263 SendEcho(localhost, S_ICMP_ECHO, "localhost");
264
1191b93b 265#if _SQUID_MSWIN_
cc192b50 266
267 debugs(37, 4, HERE << "Pinger handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid);
268
269#endif /* _SQUID_MSWIN_ */
cc192b50 270 return icmp_sock;
b8e19d32
HN
271#else /* USE_ICMP */
272 return -1;
273#endif /* USE_ICMP */
cc192b50 274}
275
276void
b826ffb5 277IcmpSquid::Close(void)
cc192b50 278{
279#if USE_ICMP
280
281 if (icmp_sock < 0)
282 return;
283
e0236918 284 debugs(37, DBG_IMPORTANT, HERE << "Closing Pinger socket on FD " << icmp_sock);
cc192b50 285
1191b93b 286#if _SQUID_MSWIN_
cc192b50 287
288 send(icmp_sock, (const void *) "$shutdown\n", 10, 0);
289
290#endif
291
292 comm_close(icmp_sock);
293
1191b93b 294#if _SQUID_MSWIN_
cc192b50 295
296 if (hIpc) {
297 if (WaitForSingleObject(hIpc, 12000) != WAIT_OBJECT_0) {
298 getCurrentTime();
fa84c01d 299 debugs(37, DBG_CRITICAL, HERE << "WARNING: (pinger," << pid << ") didn't exit in 12 seconds");
cc192b50 300 }
301
302 CloseHandle(hIpc);
303 }
304
305#endif
306 icmp_sock = -1;
307
308#endif
309}