pinger.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 
42 #include "squid.h"
43 #include "debug/Stream.h"
44 
45 #if USE_ICMP
46 
47 #include "Icmp4.h"
48 #include "Icmp6.h"
49 #include "IcmpPinger.h"
50 #include "ip/tools.h"
51 #include "time/gadgets.h"
52 
53 #if _SQUID_WINDOWS_
54 
55 #if HAVE_WINSOCK2_H
56 #include <winsock2.h>
57 #elif HAVE_WINSOCK_H
58 #include <winsock.h>
59 #endif
60 #include <process.h>
61 #include "fde.h"
62 
63 #define PINGER_TIMEOUT 5
64 
65 /* windows uses the control socket for feedback to squid */
66 #define LINK_TO_SQUID squid_link
67 
68 // windows still requires WSAFD but there are too many dependency problems
69 // to just link to win32.cc where it is normally defined.
70 
71 int
72 Win32__WSAFDIsSet(int fd, fd_set FAR * set)
73 {
74  fde *F = &fd_table[fd];
75  SOCKET s = F->win32.handle;
76 
77  return __WSAFDIsSet(s, set);
78 }
79 
80 #else
81 
82 #define PINGER_TIMEOUT 10
83 
84 /* non-windows use STDOUT for feedback to squid */
85 #define LINK_TO_SQUID 1
86 
87 #endif /* _SQUID_WINDOWS_ */
88 
89 // ICMP Engines are declared global here so they can call each other easily.
93 
95 
100 int
101 main(int, char **)
102 {
103  fd_set R;
104  int x;
105  int max_fd = 0;
106 
107  struct timeval tv;
108  time_t last_check_time = 0;
109 
110  /*
111  * cevans - do this first. It grabs a raw socket. After this we can
112  * drop privs
113  */
114  int icmp4_worker = -1;
115  int icmp6_worker = -1;
116  int squid_link = -1;
117 
118  Debug::NameThisHelper("pinger");
119 
120  getCurrentTime();
121 
122  // determine IPv4 or IPv6 capabilities before using sockets.
124 
125  debugs(42, DBG_CRITICAL, "Initialising ICMP pinger ...");
126 
127  icmp4_worker = icmp4.Open();
128  if (icmp4_worker < 0) {
129  debugs(42, DBG_CRITICAL, "ERROR: Unable to start ICMP pinger.");
130  }
131  max_fd = max(max_fd, icmp4_worker);
132 
133 #if USE_IPV6
134  icmp6_worker = icmp6.Open();
135  if (icmp6_worker <0 ) {
136  debugs(42, DBG_CRITICAL, "ERROR: Unable to start ICMPv6 pinger.");
137  }
138  max_fd = max(max_fd, icmp6_worker);
139 #endif
140 
142  if (icmp4_worker < 0 && icmp6_worker < 0) {
143  debugs(42, DBG_CRITICAL, "FATAL: Unable to open any ICMP sockets.");
144  exit(EXIT_FAILURE);
145  }
146 
147  if ( (squid_link = control.Open()) < 0) {
148  debugs(42, DBG_CRITICAL, "FATAL: Unable to setup Pinger control sockets.");
149  icmp4.Close();
150  icmp6.Close();
151  exit(EXIT_FAILURE); // fatal error if the control channel fails.
152  }
153  max_fd = max(max_fd, squid_link);
154 
155  if (setgid(getgid()) < 0) {
156  int xerrno = errno;
157  debugs(42, DBG_CRITICAL, "FATAL: setgid(" << getgid() << ") failed: " << xstrerr(xerrno));
158  icmp4.Close();
159  icmp6.Close();
160  exit(EXIT_FAILURE);
161  }
162  if (setuid(getuid()) < 0) {
163  int xerrno = errno;
164  debugs(42, DBG_CRITICAL, "FATAL: setuid(" << getuid() << ") failed: " << xstrerr(xerrno));
165  icmp4.Close();
166  icmp6.Close();
167  exit(EXIT_FAILURE);
168  }
169 
170 #if USE_LIBCAP
171  // Drop remaining capabilities (if installed as non-setuid setcap cap_net_raw=ep).
172  // If pinger binary was installed setuid root, setuid() above already dropped all
173  // capabilities, and this is no-op.
174  cap_t caps;
175  caps = cap_init();
176  if (!caps) {
177  int xerrno = errno;
178  debugs(42, DBG_CRITICAL, "FATAL: cap_init() failed: " << xstrerr(xerrno));
179  icmp4.Close();
180  icmp6.Close();
181  exit(EXIT_FAILURE);
182  } else {
183  if (cap_set_proc(caps) != 0) {
184  int xerrno = errno;
185  // cap_set_proc(cap_init()) is expected to never fail
186  debugs(42, DBG_CRITICAL, "FATAL: cap_set_proc(none) failed: " << xstrerr(xerrno));
187  cap_free(caps);
188  icmp4.Close();
189  icmp6.Close();
190  exit(EXIT_FAILURE);
191  }
192  cap_free(caps);
193  }
194 #endif
195 
196  last_check_time = squid_curtime;
197 
198  for (;;) {
199  tv.tv_sec = PINGER_TIMEOUT;
200  tv.tv_usec = 0;
201  FD_ZERO(&R);
202  if (icmp4_worker >= 0) {
203  FD_SET(icmp4_worker, &R);
204  }
205  if (icmp6_worker >= 0) {
206  FD_SET(icmp6_worker, &R);
207  }
208 
209  FD_SET(squid_link, &R);
210  x = select(max_fd+1, &R, NULL, NULL, &tv);
211  getCurrentTime();
212 
213  if (x < 0) {
214  int xerrno = errno;
215  debugs(42, DBG_CRITICAL, "FATAL: select()==" << x << ", ERR: " << xstrerr(xerrno));
216  control.Close();
217  exit(EXIT_FAILURE);
218  }
219 
220  if (FD_ISSET(squid_link, &R)) {
221  control.Recv();
222  }
223 
224  if (icmp6_worker >= 0 && FD_ISSET(icmp6_worker, &R)) {
225  icmp6.Recv();
226  }
227  if (icmp4_worker >= 0 && FD_ISSET(icmp4_worker, &R)) {
228  icmp4.Recv();
229  }
230 
231  if (PINGER_TIMEOUT + last_check_time < squid_curtime) {
232  if (send(LINK_TO_SQUID, &tv, 0, 0) < 0) {
233  debugs(42, DBG_CRITICAL, "Closing. No requests in last " << PINGER_TIMEOUT << " seconds.");
234  control.Close();
235  exit(EXIT_FAILURE);
236  }
237 
238  last_check_time = squid_curtime;
239  }
240  }
241 
242  /* NOTREACHED */
243  return EXIT_SUCCESS;
244 }
245 
246 #else /* !USE_ICMP */
247 
248 #include <ostream>
249 int
250 main(int argc, char *argv[])
251 {
252  std::cerr << argv[0] << ": ICMP support not compiled in." << std::endl;
253  return EXIT_FAILURE;
254 }
255 
256 #endif /* USE_ICMP */
257 
time_t squid_curtime
Definition: stub_libtime.cc:20
static void NameThisHelper(const char *name)
Definition: debug.cc:382
Definition: Icmp4.h:134
virtual void Recv(void)
Handle ICMP responses.
Definition: Icmp4.cc:156
virtual int Open()
Start pinger helper and initiate control channel.
Definition: Icmp4.cc:66
Definition: Icmp6.h:46
virtual void Recv(void)
Definition: Icmp6.cc:196
virtual int Open()
Start pinger helper and initiate control channel.
Definition: Icmp6.cc:98
virtual void Close()
Shutdown pinger helper and control channel.
Definition: IcmpPinger.cc:150
virtual void Recv(void)
Handle ICMP requests from squid, passing to helpers.
Definition: IcmpPinger.cc:165
virtual int Open()
Start and initiate control channel to squid.
Definition: IcmpPinger.cc:46
virtual void Close()
Shutdown pinger helper and control channel.
Definition: Icmp.cc:25
Definition: fde.h:52
A const & max(A const &lhs, A const &rhs)
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define DBG_CRITICAL
Definition: Stream.h:40
#define fd_table
Definition: fde.h:189
int main(int, char **)
Definition: pinger.cc:101
static uint32 F(uint32 X, uint32 Y, uint32 Z)
Definition: md4.c:46
void ProbeTransport(void)
Probe to discover IPv6 capabilities.
IcmpPinger control
pinger helper contains one of these as a global object.
Definition: pinger.cc:90
int icmp_pkts_sent
Definition: pinger.cc:94
#define PINGER_TIMEOUT
Definition: pinger.cc:82
#define LINK_TO_SQUID
Definition: pinger.cc:85
Icmp6 icmp6
pinger helper contains one of these as a global object.
Definition: pinger.cc:92
Icmp4 icmp4
pinger helper contains one of these as a global object.
Definition: pinger.cc:91
time_t getCurrentTime() STUB_RETVAL(0) int tvSubUsec(struct timeval
#define NULL
Definition: types.h:166
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors