IcmpSquid.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 37 ICMP Routines */
10 
11 #include "squid.h"
12 #include "comm.h"
13 #include "comm/Loops.h"
14 #include "defines.h"
15 #include "fd.h"
16 #include "icmp/IcmpConfig.h"
17 #include "icmp/IcmpSquid.h"
18 #include "icmp/net_db.h"
19 #include "ip/tools.h"
20 #include "SquidConfig.h"
21 #include "SquidIpc.h"
22 #include "SquidTime.h"
23 
24 #include <cerrno>
25 
26 // Instance global to be available in main() and elsewhere.
28 
29 #if USE_ICMP
30 
31 #define S_ICMP_ECHO 1
32 #define S_ICMP_DOM 3
33 
34 static void * hIpc;
35 static pid_t pid;
36 
37 #endif /* USE_ICMP */
38 
40 {
41  ; // nothing new.
42 }
43 
45 {
46  Close();
47 }
48 
49 #if USE_ICMP
50 
51 void
52 IcmpSquid::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
53 {
54  static pingerEchoData pecho;
55  int x, slen;
56 
58  if (icmp_sock < 0) {
59  debugs(37, 2, HERE << " Socket Closed. Aborted send to " << pecho.to << ", opcode " << opcode << ", len " << pecho.psize);
60  return;
61  }
62 
64  if (!payload)
65  len = 0;
66 
71  else if (payload && len == 0)
72  len = strlen(payload);
73 
74  // XXX: If length specified or auto-detected is greater than the possible payload squid will die with an assert.
75  // TODO: This should perhapse be reduced to a truncated payload? or no payload. A WARNING is due anyway.
77 
78  pecho.to = to;
79 
80  pecho.opcode = (unsigned char) opcode;
81 
82  pecho.psize = len;
83 
84  if (len > 0)
85  memcpy(pecho.payload, payload, len);
86 
87  slen = sizeof(pingerEchoData) - PINGER_PAYLOAD_SZ + pecho.psize;
88 
89  debugs(37, 2, HERE << "to " << pecho.to << ", opcode " << opcode << ", len " << pecho.psize);
90 
91  x = comm_udp_send(icmp_sock, (char *)&pecho, slen, 0);
92 
93  if (x < 0) {
94  int xerrno = errno;
95  debugs(37, DBG_IMPORTANT, MYNAME << "send: " << xstrerr(xerrno));
96 
98  // TODO: try restarting the helper a few times before giving up?
99  if (xerrno == ECONNREFUSED || xerrno == EPIPE) {
100  Close();
101  return;
102  }
104  } else if (x != slen) {
105  debugs(37, DBG_IMPORTANT, HERE << "Wrote " << x << " of " << slen << " bytes");
106  }
107 }
108 
109 // static Callback to wrap the squid-side ICMP handler.
110 // the IcmpSquid::Recv cannot be declared both static and virtual.
111 static void
112 icmpSquidRecv(int unused1, void *unused2)
113 {
114  icmpEngine.Recv();
115 }
116 
117 void
119 {
120  int n;
121  static int fail_count = 0;
122  pingerReplyData preply;
123  static Ip::Address F;
124 
127  (char *) &preply,
128  sizeof(pingerReplyData),
129  0);
130 
131  if (n < 0 && EAGAIN != errno) {
132  int xerrno = errno;
133  debugs(37, DBG_IMPORTANT, MYNAME << "recv: " << xstrerr(xerrno));
134 
135  if (xerrno == ECONNREFUSED)
136  Close();
137 
138  if (xerrno == ECONNRESET)
139  Close();
140 
141  if (++fail_count == 10)
142  Close();
143 
144  return;
145  }
146 
147  fail_count = 0;
148 
150  if (n == 0) {
151  return;
152  }
153 
154  F = preply.from;
155 
156  F.port(0);
157 
158  switch (preply.opcode) {
159 
160  case S_ICMP_ECHO:
161  debugs(37,4, HERE << " ICMP_ECHO of " << preply.from << " gave: hops=" << preply.hops <<", rtt=" << preply.rtt);
162  break;
163 
164  case S_ICMP_DOM:
165  debugs(37,4, HERE << " DomainPing of " << preply.from << " gave: hops=" << preply.hops <<", rtt=" << preply.rtt);
166  netdbHandlePingReply(F, preply.hops, preply.rtt);
167  break;
168 
169  default:
170  debugs(37, DBG_IMPORTANT, HERE << "Bad opcode: " << preply.opcode << " from " << F);
171  break;
172  }
173 }
174 
175 #endif /* USE_ICMP */
176 
177 void
178 IcmpSquid::DomainPing(Ip::Address &to, const char *domain)
179 {
180 #if USE_ICMP
181  debugs(37, 4, HERE << "'" << domain << "' (" << to << ")");
182  SendEcho(to, S_ICMP_DOM, domain, 0);
183 #endif
184 }
185 
186 int
188 {
189 #if USE_ICMP
190  const char *args[2];
191  int rfd;
192  int wfd;
193  Ip::Address localhost;
194 
195  /* User configured disabled. */
196  if (!IcmpCfg.enable) {
197  Close();
198  return -1;
199  }
200 
201  args[0] = "(pinger)";
202  args[1] = NULL;
203  localhost.setLocalhost();
204 
205  /*
206  * Do NOT use IPC_DGRAM (=IPC_UNIX_DGRAM) here because you can't
207  * send() more than 4096 bytes on a socketpair() socket (at
208  * least on FreeBSD).
209  */
212  args,
213  "Pinger Socket",
214  localhost,
215  &rfd,
216  &wfd,
217  &hIpc);
218 
219  if (pid < 0)
220  return -1;
221 
222  assert(rfd == wfd);
223 
224  icmp_sock = rfd;
225 
226  fd_note(icmp_sock, "pinger");
227 
229 
231 
232  debugs(37, DBG_IMPORTANT, HERE << "Pinger socket opened on FD " << icmp_sock);
233 
234  /* Tests the pinger immediately using localhost */
235  if (Ip::EnableIpv6)
236  SendEcho(localhost, S_ICMP_ECHO, "ip6-localhost");
237  if (localhost.setIPv4())
238  SendEcho(localhost, S_ICMP_ECHO, "localhost");
239 
240 #if _SQUID_WINDOWS_
241 
242  debugs(37, 4, HERE << "Pinger handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid);
243 
244 #endif /* _SQUID_WINDOWS_ */
245  return icmp_sock;
246 #else /* USE_ICMP */
247  return -1;
248 #endif /* USE_ICMP */
249 }
250 
251 void
253 {
254 #if USE_ICMP
255 
256  if (icmp_sock < 0)
257  return;
258 
259  debugs(37, DBG_IMPORTANT, HERE << "Closing Pinger socket on FD " << icmp_sock);
260 
261 #if _SQUID_WINDOWS_
262 
263  send(icmp_sock, (const void *) "$shutdown\n", 10, 0);
264 
265 #endif
266 
268 
269 #if _SQUID_WINDOWS_
270 
271  if (hIpc) {
272  if (WaitForSingleObject(hIpc, 12000) != WAIT_OBJECT_0) {
273  getCurrentTime();
274  debugs(37, DBG_CRITICAL, HERE << "WARNING: (pinger," << pid << ") didn't exit in 12 seconds");
275  }
276 
277  CloseHandle(hIpc);
278  }
279 
280 #endif
281  icmp_sock = -1;
282 
283 #endif
284 }
285 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
virtual void Recv(void)
Handle ICMP responses.
Definition: IcmpSquid.cc:118
#define MYNAME
Definition: Debug.h:170
virtual void SendEcho(Ip::Address &to, int opcode, const char *payload=NULL, int len=0)
Definition: IcmpSquid.cc:52
virtual void Close()
Shutdown pinger helper and control channel.
Definition: IcmpSquid.cc:252
void setLocalhost()
Definition: Address.cc:255
#define IPC_UDP_SOCKET
Definition: defines.h:147
void fd_note(int fd, const char *s)
Definition: fd.cc:246
#define PINGER_PAYLOAD_SZ
Definition: Icmp.h:16
IcmpSquid icmpEngine
Definition: IcmpSquid.cc:27
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
ssize_t comm_udp_send(int s, const void *buf, size_t len, int flags)
Definition: comm.cc:142
int comm_udp_recv(int fd, void *buf, size_t len, int flags)
Definition: comm.cc:135
#define comm_close(x)
Definition: comm.h:28
#define DBG_CRITICAL
Definition: Debug.h:45
#define S_ICMP_DOM
Definition: IcmpSquid.cc:32
time_t getCurrentTime(void)
Get current time.
#define DBG_IMPORTANT
Definition: Debug.h:46
int icmp_sock
Definition: Icmp.h:121
char payload[PINGER_PAYLOAD_SZ]
Definition: Icmp.h:31
static void * hIpc
Definition: IcmpSquid.cc:34
static pid_t pid
Definition: IcmpSquid.cc:35
virtual int Open()
Start pinger helper and initiate control channel.
Definition: IcmpSquid.cc:187
void commUnsetFdTimeout(int fd)
clear a timeout handler by FD number
Definition: comm.cc:554
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:128
int enable
Definition: IcmpConfig.h:35
static void icmpSquidRecv(int unused1, void *unused2)
Definition: IcmpSquid.cc:112
Ip::Address to
Definition: Icmp.h:28
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:157
unsigned char opcode
Definition: Icmp.h:29
#define assert(EX)
Definition: assert.h:19
bool setIPv4()
Definition: Address.cc:224
#define COMM_SELECT_READ
Definition: defines.h:36
const char * c_str()
Definition: SBuf.cc:526
pid_t ipcCreate(int type, const char *prog, const char *const args[], const char *name, Ip::Address &local_addr, int *rfd, int *wfd, void **hIpc)
Definition: ipc.cc:62
int psize
Definition: Icmp.h:30
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:225
void DomainPing(Ip::Address &to, const char *domain)
Definition: IcmpSquid.cc:178
SBuf program
Definition: IcmpConfig.h:32
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
#define S_ICMP_ECHO
Definition: IcmpSquid.cc:31
IcmpConfig IcmpCfg
Definition: IcmpConfig.cc:17
void netdbHandlePingReply(const Ip::Address &from, int hops, int rtt)
Definition: net_db.cc:924
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
virtual ~IcmpSquid()
Definition: IcmpSquid.cc:44
Definition: Icmp.h:67

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors