]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/pinger.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 42 ICMP Pinger program */
11 #define SQUID_HELPER 1
14 \defgroup pinger pinger
15 \ingroup ExternalPrograms
17 * Although it would be possible for Squid to send and receive
18 * ICMP messages directly, we use an external process for
19 * two important reasons:
21 \li Because squid handles many filedescriptors simultaneously,
22 * we get much more accurate RTT measurements when ICMP is
23 * handled by a separate process.
25 \li Superuser privileges are required to send and receive ICMP.
26 * Rather than require Squid to be started as root, we prefer
27 * to have the smaller and simpler pinger program installed
28 * with setuid permissions.
31 * If you want to use Squid's ICMP features (highly recommended!)
32 * When USE_ICMP is defined, Squid will send ICMP pings
33 * to origin server sites.
34 * This information is used in numerous ways:
35 \li - Sent in ICP replies so neighbor caches know how close
36 * you are to the source.
37 \li - For finding the closest instance of a URN.
38 \li - With the 'test_reachability' option. Squid will return
39 * ICP_OP_MISS_NOFETCH for sites which it cannot ping.
43 #include "debug/Stream.h"
49 #include "IcmpPinger.h"
51 #include "time/gadgets.h"
53 #if HAVE_SYS_CAPABILITY_H
54 #include <sys/capability.h>
68 #define PINGER_TIMEOUT 5
70 /* windows uses the control socket for feedback to squid */
71 #define LINK_TO_SQUID squid_link
73 // windows still requires WSAFD but there are too many dependency problems
74 // to just link to win32.cc where it is normally defined.
77 Win32__WSAFDIsSet(int fd
, fd_set FAR
* set
)
79 fde
*F
= &fd_table
[fd
];
80 SOCKET s
= F
->win32
.handle
;
82 return __WSAFDIsSet(s
, set
);
87 #define PINGER_TIMEOUT 10
89 /* non-windows use STDOUT for feedback to squid */
90 #define LINK_TO_SQUID 1
92 #endif /* _SQUID_WINDOWS_ */
94 // ICMP Engines are declared global here so they can call each other easily.
99 int icmp_pkts_sent
= 0;
103 \par This is the pinger external process.
113 time_t last_check_time
= 0;
116 * cevans - do this first. It grabs a raw socket. After this we can
119 int icmp4_worker
= -1;
120 int icmp6_worker
= -1;
123 Debug::NameThisHelper("pinger");
127 // determine IPv4 or IPv6 capabilities before using sockets.
128 Ip::ProbeTransport();
130 debugs(42, DBG_CRITICAL
, "Initialising ICMP pinger ...");
132 icmp4_worker
= icmp4
.Open();
133 if (icmp4_worker
< 0) {
134 debugs(42, DBG_CRITICAL
, "ERROR: Unable to start ICMP pinger.");
136 max_fd
= max(max_fd
, icmp4_worker
);
139 icmp6_worker
= icmp6
.Open();
140 if (icmp6_worker
<0 ) {
141 debugs(42, DBG_CRITICAL
, "ERROR: Unable to start ICMPv6 pinger.");
143 max_fd
= max(max_fd
, icmp6_worker
);
146 /** abort if neither worker could open a socket. */
147 if (icmp4_worker
< 0 && icmp6_worker
< 0) {
148 debugs(42, DBG_CRITICAL
, "FATAL: Unable to open any ICMP sockets.");
152 if ( (squid_link
= control
.Open()) < 0) {
153 debugs(42, DBG_CRITICAL
, "FATAL: Unable to setup Pinger control sockets.");
156 exit(EXIT_FAILURE
); // fatal error if the control channel fails.
158 max_fd
= max(max_fd
, squid_link
);
160 if (setgid(getgid()) < 0) {
162 debugs(42, DBG_CRITICAL
, "FATAL: setgid(" << getgid() << ") failed: " << xstrerr(xerrno
));
167 if (setuid(getuid()) < 0) {
169 debugs(42, DBG_CRITICAL
, "FATAL: setuid(" << getuid() << ") failed: " << xstrerr(xerrno
));
176 // Drop remaining capabilities (if installed as non-setuid setcap cap_net_raw=ep).
177 // If pinger binary was installed setuid root, setuid() above already dropped all
178 // capabilities, and this is no-op.
183 debugs(42, DBG_CRITICAL
, "FATAL: cap_init() failed: " << xstrerr(xerrno
));
188 if (cap_set_proc(caps
) != 0) {
190 // cap_set_proc(cap_init()) is expected to never fail
191 debugs(42, DBG_CRITICAL
, "FATAL: cap_set_proc(none) failed: " << xstrerr(xerrno
));
201 last_check_time
= squid_curtime
;
204 tv
.tv_sec
= PINGER_TIMEOUT
;
207 if (icmp4_worker
>= 0) {
208 FD_SET(icmp4_worker
, &R
);
210 if (icmp6_worker
>= 0) {
211 FD_SET(icmp6_worker
, &R
);
214 FD_SET(squid_link
, &R
);
215 x
= select(max_fd
+1, &R
, nullptr, nullptr, &tv
);
220 debugs(42, DBG_CRITICAL
, "FATAL: select()==" << x
<< ", ERR: " << xstrerr(xerrno
));
225 if (FD_ISSET(squid_link
, &R
)) {
229 if (icmp6_worker
>= 0 && FD_ISSET(icmp6_worker
, &R
)) {
232 if (icmp4_worker
>= 0 && FD_ISSET(icmp4_worker
, &R
)) {
236 if (PINGER_TIMEOUT
+ last_check_time
< squid_curtime
) {
237 if (send(LINK_TO_SQUID
, &tv
, 0, 0) < 0) {
238 debugs(42, DBG_CRITICAL
, "Closing. No requests in last " << PINGER_TIMEOUT
<< " seconds.");
243 last_check_time
= squid_curtime
;
251 #else /* !USE_ICMP */
255 main(int argc
, char *argv
[])
257 std::cerr
<< argv
[0] << ": ICMP support not compiled in." << std::endl
;
261 #endif /* USE_ICMP */