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