IcmpPinger.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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 42 ICMP Pinger program */
10 
11 #define SQUID_HELPER 1
12 
13 #include "squid.h"
14 
15 #if USE_ICMP
16 
17 #include "compat/socket.h"
18 #include "compat/unistd.h"
19 #include "debug/Stream.h"
20 #include "Icmp4.h"
21 #include "Icmp6.h"
22 #include "IcmpPinger.h"
23 
24 #include <cerrno>
25 
27 {
28  // these start invalid. Setup properly in Open()
29  socket_from_squid = -1;
30  socket_to_squid = -1;
31 }
32 
34 {
35  Close();
36 }
37 
38 #if _SQUID_WINDOWS_
39 void
40 Win32SockCleanup(void)
41 {
42  WSACleanup();
43  return;
44 }
45 #endif
46 
47 int
49 {
50 #if _SQUID_WINDOWS_
51 
52  WSADATA wsaData;
53  WSAPROTOCOL_INFO wpi;
54  char buf[sizeof(wpi)+1];
55  int x;
56 
57  struct sockaddr_in PS;
58  int xerrno;
59 
60  static_assert(sizeof(WSAPROTOCOL_INFO) >= sizeof(PS), "PS must fit into wpi-sized buf");
61 
62  WSAStartup(2, &wsaData);
63  atexit(Win32SockCleanup);
64 
66 
67  Debug::debugOptions = xstrdup("ALL,1");
69 
70  setmode(0, O_BINARY);
71  setmode(1, O_BINARY);
72  x = xread(0, buf, sizeof(wpi));
73 
74  if (x < (int)sizeof(wpi)) {
75  xerrno = errno;
77  debugs(42, DBG_CRITICAL, MYNAME << " read: FD 0: " << xstrerr(xerrno));
78  xwrite(1, "ERR\n", 4);
79  return -1;
80  }
81 
82  memcpy(&wpi, buf, sizeof(wpi));
83 
84  xwrite(1, "OK\n", 3);
85  x = xread(0, buf, sizeof(PS));
86 
87  if (x < (int)sizeof(PS)) {
88  xerrno = errno;
90  debugs(42, DBG_CRITICAL, MYNAME << " read: FD 0: " << xstrerr(xerrno));
91  xwrite(1, "ERR\n", 4);
92  return -1;
93  }
94 
95  memcpy(&PS, buf, sizeof(PS));
96 
97  icmp_sock = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &wpi, 0, 0);
98 
99  if (icmp_sock == -1) {
100  xerrno = errno;
101  getCurrentTime();
102  debugs(42, DBG_CRITICAL, MYNAME << "WSASocket: " << xstrerr(xerrno));
103  xwrite(1, "ERR\n", 4);
104  return -1;
105  }
106 
107  x = xconnect(icmp_sock, (struct sockaddr *) &PS, sizeof(PS));
108 
109  if (x != 0) {
110  xerrno = errno;
111  getCurrentTime();
112  debugs(42, DBG_CRITICAL, MYNAME << "connect: " << xstrerr(xerrno));
113  xwrite(1, "ERR\n", 4);
114  return -1;
115  }
116 
117  xwrite(1, "OK\n", 3);
118  memset(buf, 0, sizeof(buf));
119  x = xrecv(icmp_sock, buf, sizeof(buf)-1, 0);
120 
121  if (x < 3) {
122  xerrno = errno;
123  debugs(42, DBG_CRITICAL, MYNAME << "recv: " << xstrerr(xerrno));
124  return -1;
125  }
126 
127  x = xsend(icmp_sock, buf, x, 0);
128  xerrno = errno;
129 
130  if (x < 3 || strncmp("OK\n", buf, 3)) {
131  debugs(42, DBG_CRITICAL, MYNAME << "recv: " << xstrerr(xerrno));
132  return -1;
133  }
134 
135  getCurrentTime();
136  debugs(42, DBG_IMPORTANT, "Squid socket opened");
137 
138  /* windows uses a socket stream as a dual-direction channel */
141 
142  return icmp_sock;
143 
144 #else /* !_SQUID_WINDOWS_ */
145 
146  /* non-windows apps use stdin/out pipes as the squid channel(s) */
147  socket_from_squid = 0; // use STDIN macro ??
148  socket_to_squid = 1; // use STDOUT macro ??
149  return socket_to_squid;
150 #endif
151 }
152 
153 void
155 {
156 #if _SQUID_WINDOWS_
157  if (icmp_sock >= 0) {
158  shutdown(icmp_sock, SD_BOTH);
159  xclose(icmp_sock);
160  icmp_sock = -1;
161  }
162 #endif
163 
164  /* also shutdown the helper engines */
165  icmp4.Close();
166  icmp6.Close();
167 }
168 
169 void
171 {
172  static pingerEchoData pecho;
173  int n;
174  int guess_size;
175 
176  pecho = pingerEchoData();
177  n = xrecv(socket_from_squid, &pecho, sizeof(pecho), 0);
178 
179  if (n < 0) {
180  debugs(42, DBG_IMPORTANT, "Pinger exiting.");
181  Close();
182  exit(EXIT_FAILURE);
183  }
184 
185  if (0 == n) {
186  /* EOF indicator */
187  debugs(42, DBG_CRITICAL, "EOF encountered. Pinger exiting.");
188  errno = 0;
189  Close();
190  exit(EXIT_FAILURE);
191  }
192 
193  guess_size = n - (sizeof(pingerEchoData) - PINGER_PAYLOAD_SZ);
194 
195  if (guess_size != pecho.psize) {
196  debugs(42, 2, "size mismatch, guess=" << guess_size << ", psize=" << pecho.psize);
197  /* don't process this message, but keep running */
198  return;
199  }
200 
201  /* pass request for ICMPv6 handing */
202  if (pecho.to.isIPv6()) {
203  debugs(42, 2, " Pass " << pecho.to << " off to ICMPv6 module.");
204  icmp6.SendEcho(pecho.to,
205  pecho.opcode,
206  pecho.payload,
207  pecho.psize);
208  }
209 
210  /* pass the packet for ICMP handling */
211  else if (pecho.to.isIPv4()) {
212  debugs(42, 2, " Pass " << pecho.to << " off to ICMPv4 module.");
213  icmp4.SendEcho(pecho.to,
214  pecho.opcode,
215  pecho.payload,
216  pecho.psize);
217  } else {
218  debugs(42, DBG_IMPORTANT, "ERROR: IP has unknown Type. " << pecho.to );
219  }
220 }
221 
222 void
224 {
225  debugs(42, 2, "return result to squid. len=" << len);
226 
227  if (xsend(socket_to_squid, &preply, len, 0) < 0) {
228  int xerrno = errno;
229  debugs(42, DBG_CRITICAL, "FATAL: send failure: " << xstrerr(xerrno));
230  Close();
231  exit(EXIT_FAILURE);
232  }
233 }
234 
235 #endif /* USE_ICMP */
236 
static char * debugOptions
Definition: Stream.h:80
const char * xstrerr(int error)
Definition: xstrerror.cc:83
#define DBG_CRITICAL
Definition: Stream.h:37
Icmp4 icmp4
pinger helper contains one of these as a global object.
Definition: pinger.cc:94
#define PINGER_PAYLOAD_SZ
Definition: Icmp.h:16
#define xstrdup
int xwrite(int fd, const void *buf, size_t bufSize)
POSIX write(2) equivalent.
Definition: unistd.h:67
int socket_to_squid
Definition: IcmpPinger.h:47
virtual void Close()
Shutdown pinger helper and control channel.
Definition: Icmp.cc:26
bool isIPv4() const
Definition: Address.cc:178
int icmp_sock
Definition: Icmp.h:121
char payload[PINGER_PAYLOAD_SZ]
Definition: Icmp.h:31
ssize_t xsend(int socketFd, const void *buf, size_t bufLength, int flags)
POSIX send(2) equivalent.
Definition: socket.h:110
#define O_BINARY
Definition: defines.h:134
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
bool isIPv6() const
Definition: Address.cc:184
void SendEcho(Ip::Address &, int, const char *, int) override
Definition: Icmp6.cc:120
Ip::Address to
Definition: Icmp.h:28
~IcmpPinger() override
Definition: IcmpPinger.cc:33
unsigned char opcode
Definition: Icmp.h:29
int psize
Definition: Icmp.h:30
void SendResult(pingerReplyData &preply, int len)
Send ICMP results back to squid.
Definition: IcmpPinger.cc:223
int Open() override
Start and initiate control channel to squid.
Definition: IcmpPinger.cc:48
ssize_t xrecv(int socketFd, void *buf, size_t bufLength, int flags)
POSIX recv(2) equivalent.
Definition: socket.h:98
int socket_from_squid
Definition: IcmpPinger.h:46
void Close() override
Shutdown pinger helper and control channel.
Definition: IcmpPinger.cc:154
static void Win32SockCleanup(void)
int xread(int fd, void *buf, size_t bufSize)
POSIX read(2) equivalent.
Definition: unistd.h:61
#define DBG_IMPORTANT
Definition: Stream.h:38
#define MYNAME
Definition: Stream.h:219
void Recv(void) override
Handle ICMP requests from squid, passing to helpers.
Definition: IcmpPinger.cc:170
void SendEcho(Ip::Address &, int, const char *, int) override
Definition: Icmp4.cc:85
int xclose(int fd)
POSIX close(2) equivalent.
Definition: unistd.h:43
static void BanCacheLogUse()
Definition: debug.cc:1118
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
int xconnect(int socketFd, const struct sockaddr *sa, socklen_t saLength)
POSIX connect(2) equivalent.
Definition: socket.h:74
Icmp6 icmp6
pinger helper contains one of these as a global object.
Definition: pinger.cc:95
Definition: Icmp.h:67

 

Introduction

Documentation

Support

Miscellaneous