]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icmp/pinger.cc
Windows: Drop obsolete WinSock v1 library (#1384)
[thirdparty/squid.git] / src / icmp / pinger.cc
CommitLineData
9d90e665 1/*
b8ae064d 2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
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.
9d90e665 7 */
8
bbc27441
AJ
9/* DEBUG: section 42 ICMP Pinger program */
10
128fe1c6 11#define SQUID_HELPER 1
12
63be0a78 13/**
14 \defgroup pinger pinger
15 \ingroup ExternalPrograms
16 \par
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:
20 *
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.
24 *
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.
29 *
30 \par
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.
40 */
41
582c2af2 42#include "squid.h"
675b8408 43#include "debug/Stream.h"
9d90e665 44
43426991 45#if USE_ICMP
46
0d51e000 47#include "base/Stopwatch.h"
663ff9aa
AJ
48#include "Icmp4.h"
49#include "Icmp6.h"
50#include "IcmpPinger.h"
059d13ed 51#include "ip/tools.h"
98cacedb 52#include "time/gadgets.h"
0ab98d6b 53
59eac907
AJ
54#if HAVE_SYS_CAPABILITY_H
55#include <sys/capability.h>
56#endif
57
7aa9bb3e 58#if _SQUID_WINDOWS_
bdb741f4 59
bfe8dedf 60#if HAVE_WINSOCK2_H
bdb741f4 61#include <winsock2.h>
bfe8dedf 62#endif
bdb741f4 63#include <process.h>
59eac907 64
cc192b50 65#include "fde.h"
bdb741f4 66
cc192b50 67/* windows uses the control socket for feedback to squid */
68#define LINK_TO_SQUID squid_link
bdb741f4 69
2f8abb64 70// windows still requires WSAFD but there are too many dependency problems
cc192b50 71// to just link to win32.cc where it is normally defined.
bdb741f4 72
cc192b50 73int
74Win32__WSAFDIsSet(int fd, fd_set FAR * set)
bdb741f4 75{
cc192b50 76 fde *F = &fd_table[fd];
77 SOCKET s = F->win32.handle;
bdb741f4 78
cc192b50 79 return __WSAFDIsSet(s, set);
bdb741f4 80}
81
cc192b50 82#else
bdb741f4 83
cc192b50 84/* non-windows use STDOUT for feedback to squid */
f53969cc 85#define LINK_TO_SQUID 1
bdb741f4 86
f53969cc 87#endif /* _SQUID_WINDOWS_ */
bdb741f4 88
0d51e000
AJ
89using namespace std::literals::chrono_literals;
90static const auto PingerTimeout = 10s;
91
cc192b50 92// ICMP Engines are declared global here so they can call each other easily.
663ff9aa
AJ
93IcmpPinger control;
94Icmp4 icmp4;
663ff9aa 95Icmp6 icmp6;
62e76326 96
5be53f2d 97int icmp_pkts_sent = 0;
9d90e665 98
63be0a78 99/**
100 \ingroup pinger
101 \par This is the pinger external process.
63be0a78 102 */
cc192b50 103int
8b082ed9 104main(int, char **)
9d90e665 105{
cc192b50 106 fd_set R;
bdb741f4 107 int x;
cc192b50 108 int max_fd = 0;
bdb741f4 109
cc192b50 110 /*
111 * cevans - do this first. It grabs a raw socket. After this we can
112 * drop privs
113 */
114 int icmp4_worker = -1;
cc192b50 115 int icmp6_worker = -1;
cc192b50 116 int squid_link = -1;
62e76326 117
879c39f7 118 Debug::NameThisHelper("pinger");
bdb741f4 119
120 getCurrentTime();
62e76326 121
059d13ed
AJ
122 // determine IPv4 or IPv6 capabilities before using sockets.
123 Ip::ProbeTransport();
124
879c39f7 125 debugs(42, DBG_CRITICAL, "Initialising ICMP pinger ...");
62e76326 126
cc192b50 127 icmp4_worker = icmp4.Open();
26ac0430 128 if (icmp4_worker < 0) {
879c39f7 129 debugs(42, DBG_CRITICAL, "ERROR: Unable to start ICMP pinger.");
b6a2f15e 130 }
cc192b50 131 max_fd = max(max_fd, icmp4_worker);
62e76326 132
cc192b50 133#if USE_IPV6
134 icmp6_worker = icmp6.Open();
26ac0430 135 if (icmp6_worker <0 ) {
879c39f7 136 debugs(42, DBG_CRITICAL, "ERROR: Unable to start ICMPv6 pinger.");
9d90e665 137 }
cc192b50 138 max_fd = max(max_fd, icmp6_worker);
d20b1cd0 139#endif
62e76326 140
63be0a78 141 /** abort if neither worker could open a socket. */
055421ee 142 if (icmp4_worker < 0 && icmp6_worker < 0) {
879c39f7 143 debugs(42, DBG_CRITICAL, "FATAL: Unable to open any ICMP sockets.");
24885773 144 exit(EXIT_FAILURE);
b6a2f15e 145 }
62e76326 146
26ac0430 147 if ( (squid_link = control.Open()) < 0) {
879c39f7 148 debugs(42, DBG_CRITICAL, "FATAL: Unable to setup Pinger control sockets.");
cc192b50 149 icmp4.Close();
cc192b50 150 icmp6.Close();
24885773 151 exit(EXIT_FAILURE); // fatal error if the control channel fails.
365a4bce 152 }
cc192b50 153 max_fd = max(max_fd, squid_link);
62e76326 154
77468ee5 155 if (setgid(getgid()) < 0) {
23c38c73 156 int xerrno = errno;
879c39f7 157 debugs(42, DBG_CRITICAL, "FATAL: setgid(" << getgid() << ") failed: " << xstrerr(xerrno));
77468ee5
AJ
158 icmp4.Close();
159 icmp6.Close();
24885773 160 exit(EXIT_FAILURE);
77468ee5
AJ
161 }
162 if (setuid(getuid()) < 0) {
23c38c73 163 int xerrno = errno;
879c39f7 164 debugs(42, DBG_CRITICAL, "FATAL: setuid(" << getuid() << ") failed: " << xstrerr(xerrno));
77468ee5
AJ
165 icmp4.Close();
166 icmp6.Close();
24885773 167 exit(EXIT_FAILURE);
77468ee5 168 }
b6a2f15e 169
23c38c73
YK
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;
879c39f7 178 debugs(42, DBG_CRITICAL, "FATAL: cap_init() failed: " << xstrerr(xerrno));
23c38c73
YK
179 icmp4.Close();
180 icmp6.Close();
24885773 181 exit(EXIT_FAILURE);
23c38c73
YK
182 } else {
183 if (cap_set_proc(caps) != 0) {
184 int xerrno = errno;
185 // cap_set_proc(cap_init()) is expected to never fail
879c39f7 186 debugs(42, DBG_CRITICAL, "FATAL: cap_set_proc(none) failed: " << xstrerr(xerrno));
23c38c73
YK
187 cap_free(caps);
188 icmp4.Close();
189 icmp6.Close();
24885773 190 exit(EXIT_FAILURE);
23c38c73
YK
191 }
192 cap_free(caps);
193 }
194#endif
195
9d90e665 196 for (;;) {
0d51e000
AJ
197 struct timeval tv;
198 tv.tv_sec = std::chrono::seconds(PingerTimeout).count();
62e76326 199 tv.tv_usec = 0;
200 FD_ZERO(&R);
26ac0430 201 if (icmp4_worker >= 0) {
cc192b50 202 FD_SET(icmp4_worker, &R);
203 }
26ac0430 204 if (icmp6_worker >= 0) {
cc192b50 205 FD_SET(icmp6_worker, &R);
206 }
055421ee 207
cc192b50 208 FD_SET(squid_link, &R);
0d51e000
AJ
209 Stopwatch timer;
210 timer.resume();
aee3523a 211 x = select(max_fd+1, &R, nullptr, nullptr, &tv);
62e76326 212 getCurrentTime();
213
bdb741f4 214 if (x < 0) {
23c38c73 215 int xerrno = errno;
d816f28d 216 debugs(42, DBG_CRITICAL, "FATAL: select()==" << x << ", ERR: " << xstrerr(xerrno));
cc192b50 217 control.Close();
24885773 218 exit(EXIT_FAILURE);
bdb741f4 219 }
62e76326 220
cc192b50 221 if (FD_ISSET(squid_link, &R)) {
222 control.Recv();
223 }
62e76326 224
cc192b50 225 if (icmp6_worker >= 0 && FD_ISSET(icmp6_worker, &R)) {
226 icmp6.Recv();
227 }
cc192b50 228 if (icmp4_worker >= 0 && FD_ISSET(icmp4_worker, &R)) {
229 icmp4.Recv();
230 }
62e76326 231
0d51e000
AJ
232 const auto delay = std::chrono::duration_cast<std::chrono::seconds>(timer.total());
233 if (delay >= PingerTimeout) {
cc192b50 234 if (send(LINK_TO_SQUID, &tv, 0, 0) < 0) {
0d51e000 235 debugs(42, DBG_CRITICAL, "Closing. No requests in last " << delay.count() << " seconds.");
cc192b50 236 control.Close();
24885773 237 exit(EXIT_FAILURE);
bdb741f4 238 }
62e76326 239 }
9d90e665 240 }
62e76326 241
145766ef 242 /* NOTREACHED */
24885773 243 return EXIT_SUCCESS;
9d90e665 244}
365a4bce 245
5e66b1a6 246#else /* !USE_ICMP */
074d6a40
AJ
247
248#include <ostream>
9d90e665 249int
250main(int argc, char *argv[])
251{
074d6a40 252 std::cerr << argv[0] << ": ICMP support not compiled in." << std::endl;
24885773 253 return EXIT_FAILURE;
9d90e665 254}
62e76326 255
9d90e665 256#endif /* USE_ICMP */
f53969cc 257