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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors