IcmpSquid.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 
78  assert(len <= PINGER_PAYLOAD_SZ);
79 
80  pecho.to = to;
81 
82  pecho.opcode = (unsigned char) opcode;
83 
84  pecho.psize = len;
85 
86  if (len > 0)
87  memcpy(pecho.payload, payload, len);
88 
89  slen = sizeof(pingerEchoData) - PINGER_PAYLOAD_SZ + pecho.psize;
90 
91  debugs(37, 2, HERE << "to " << pecho.to << ", opcode " << opcode << ", len " << pecho.psize);
92 
93  x = comm_udp_send(icmp_sock, (char *)&pecho, slen, 0);
94 
95  if (x < 0) {
96  int xerrno = errno;
97  debugs(37, DBG_IMPORTANT, MYNAME << "send: " << xstrerr(xerrno));
98 
101  if (xerrno == ECONNREFUSED || xerrno == EPIPE) {
102  Close();
103  return;
104  }
106  } else if (x != slen) {
107  debugs(37, DBG_IMPORTANT, HERE << "Wrote " << x << " of " << slen << " bytes");
108  }
109 }
110 
111 // static Callback to wrap the squid-side ICMP handler.
112 // the IcmpSquid::Recv cannot be declared both static and virtual.
113 static void
114 icmpSquidRecv(int unused1, void *unused2)
115 {
116  icmpEngine.Recv();
117 }
118 
119 void
121 {
122  int n;
123  static int fail_count = 0;
124  pingerReplyData preply;
125  static Ip::Address F;
126 
129  (char *) &preply,
130  sizeof(pingerReplyData),
131  0);
132 
133  if (n < 0 && EAGAIN != errno) {
134  int xerrno = errno;
135  debugs(37, DBG_IMPORTANT, MYNAME << "recv: " << xstrerr(xerrno));
136 
137  if (xerrno == ECONNREFUSED)
138  Close();
139 
140  if (xerrno == ECONNRESET)
141  Close();
142 
143  if (++fail_count == 10)
144  Close();
145 
146  return;
147  }
148 
149  fail_count = 0;
150 
152  if (n == 0) {
153  return;
154  }
155 
156  F = preply.from;
157 
158  F.port(0);
159 
160  switch (preply.opcode) {
161 
162  case S_ICMP_ECHO:
163  debugs(37,4, HERE << " ICMP_ECHO of " << preply.from << " gave: hops=" << preply.hops <<", rtt=" << preply.rtt);
164  break;
165 
166  case S_ICMP_DOM:
167  debugs(37,4, HERE << " DomainPing of " << preply.from << " gave: hops=" << preply.hops <<", rtt=" << preply.rtt);
168  netdbHandlePingReply(F, preply.hops, preply.rtt);
169  break;
170 
171  default:
172  debugs(37, DBG_IMPORTANT, HERE << "Bad opcode: " << preply.opcode << " from " << F);
173  break;
174  }
175 }
176 
177 #endif /* USE_ICMP */
178 
179 void
180 IcmpSquid::DomainPing(Ip::Address &to, const char *domain)
181 {
182 #if USE_ICMP
183  debugs(37, 4, HERE << "'" << domain << "' (" << to << ")");
184  SendEcho(to, S_ICMP_DOM, domain, 0);
185 #endif
186 }
187 
188 int
190 {
191 #if USE_ICMP
192  const char *args[2];
193  int rfd;
194  int wfd;
195  Ip::Address localhost;
196 
197  /* User configured disabled. */
198  if (!IcmpCfg.enable) {
199  Close();
200  return -1;
201  }
202 
203  args[0] = "(pinger)";
204  args[1] = NULL;
205  localhost.setLocalhost();
206 
207  /*
208  * Do NOT use IPC_DGRAM (=IPC_UNIX_DGRAM) here because you can't
209  * send() more than 4096 bytes on a socketpair() socket (at
210  * least on FreeBSD).
211  */
214  args,
215  "Pinger Socket",
216  localhost,
217  &rfd,
218  &wfd,
219  &hIpc);
220 
221  if (pid < 0)
222  return -1;
223 
224  assert(rfd == wfd);
225 
226  icmp_sock = rfd;
227 
228  fd_note(icmp_sock, "pinger");
229 
231 
233 
234  debugs(37, DBG_IMPORTANT, HERE << "Pinger socket opened on FD " << icmp_sock);
235 
236  /* Tests the pinger immediately using localhost */
237  if (Ip::EnableIpv6)
238  SendEcho(localhost, S_ICMP_ECHO, "ip6-localhost");
239  if (localhost.setIPv4())
240  SendEcho(localhost, S_ICMP_ECHO, "localhost");
241 
242 #if _SQUID_WINDOWS_
243 
244  debugs(37, 4, HERE << "Pinger handle: 0x" << std::hex << hIpc << std::dec << ", PID: " << pid);
245 
246 #endif /* _SQUID_WINDOWS_ */
247  return icmp_sock;
248 #else /* USE_ICMP */
249  return -1;
250 #endif /* USE_ICMP */
251 }
252 
253 void
255 {
256 #if USE_ICMP
257 
258  if (icmp_sock < 0)
259  return;
260 
261  debugs(37, DBG_IMPORTANT, HERE << "Closing Pinger socket on FD " << icmp_sock);
262 
263 #if _SQUID_WINDOWS_
264 
265  send(icmp_sock, (const void *) "$shutdown\n", 10, 0);
266 
267 #endif
268 
270 
271 #if _SQUID_WINDOWS_
272 
273  if (hIpc) {
274  if (WaitForSingleObject(hIpc, 12000) != WAIT_OBJECT_0) {
275  getCurrentTime();
276  debugs(37, DBG_CRITICAL, HERE << "WARNING: (pinger," << pid << ") didn't exit in 12 seconds");
277  }
278 
279  CloseHandle(hIpc);
280  }
281 
282 #endif
283  icmp_sock = -1;
284 
285 #endif
286 }
287 
void DomainPing(Ip::Address &to, const char *domain)
Definition: IcmpSquid.cc:180
#define PINGER_PAYLOAD_SZ
Definition: Icmp.h:16
char payload[PINGER_PAYLOAD_SZ]
Definition: Icmp.h:31
int comm_udp_recv(int fd, void *buf, size_t len, int flags)
Definition: comm.cc:134
Definition: Icmp.h:67
#define COMM_SELECT_READ
Definition: defines.h:36
unsigned short port() const
Definition: Address.cc:778
#define assert(EX)
Definition: assert.h:17
virtual ~IcmpSquid()
Definition: IcmpSquid.cc:44
void fd_note(int fd, const char *s)
Definition: fd.cc:246
virtual void Recv(void)
Handle ICMP responses.
Definition: IcmpSquid.cc:120
void setLocalhost()
Definition: Address.cc:255
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
#define DBG_CRITICAL
Definition: Debug.h:45
static void * hIpc
Definition: IcmpSquid.cc:34
SBuf program
Definition: IcmpConfig.h:32
IcmpConfig IcmpCfg
Definition: IcmpConfig.cc:17
int psize
Definition: Icmp.h:30
int icmp_sock
Definition: Icmp.h:121
virtual int Open()
Start pinger helper and initiate control channel.
Definition: IcmpSquid.cc:189
const char * xstrerr(int error)
Definition: xstrerror.cc:83
ssize_t comm_udp_send(int s, const void *buf, size_t len, int flags)
Definition: comm.cc:141
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
#define DBG_IMPORTANT
Definition: Debug.h:46
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:225
#define IPC_UDP_SOCKET
Definition: defines.h:147
const char * c_str()
Definition: SBuf.cc:526
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
static void icmpSquidRecv(int unused1, void *unused2)
Definition: IcmpSquid.cc:114
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
static pid_t pid
Definition: IcmpSquid.cc:35
time_t getCurrentTime(void)
Get current time.
#define MYNAME
Definition: Debug.h:166
Ip::Address to
Definition: Icmp.h:28
virtual void Close()
Shutdown pinger helper and control channel.
Definition: IcmpSquid.cc:254
#define S_ICMP_ECHO
Definition: IcmpSquid.cc:31
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
virtual void SendEcho(Ip::Address &to, int opcode, const char *payload=NULL, int len=0)
Definition: IcmpSquid.cc:52
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
void commUnsetFdTimeout(int fd)
clear a timeout handler by FD number
Definition: comm.cc:539
int enable
Definition: IcmpConfig.h:35
unsigned char opcode
Definition: Icmp.h:29
IcmpSquid icmpEngine
Definition: IcmpSquid.cc:27
#define comm_close(x)
Definition: comm.h:28
#define NULL
Definition: types.h:166
void netdbHandlePingReply(const Ip::Address &from, int hops, int rtt)
Definition: net_db.cc:925
#define S_ICMP_DOM
Definition: IcmpSquid.cc:32

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors