]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icmp/pinger.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / icmp / pinger.cc
CommitLineData
9d90e665 1/*
bde978a6 2 * Copyright (C) 1996-2015 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
FC
42#include "squid.h"
43#include "Debug.h"
985c86bc 44#include "SquidTime.h"
9d90e665 45
43426991 46#if USE_ICMP
47
663ff9aa
AJ
48#include "Icmp4.h"
49#include "Icmp6.h"
50#include "IcmpPinger.h"
059d13ed 51#include "ip/tools.h"
0ab98d6b 52
7aa9bb3e 53#if _SQUID_WINDOWS_
bdb741f4 54
bfe8dedf 55#if HAVE_WINSOCK2_H
bdb741f4 56#include <winsock2.h>
fcabe077
FC
57#elif HAVE_WINSOCK_H
58#include <winsock.h>
bfe8dedf 59#endif
bdb741f4 60#include <process.h>
cc192b50 61#include "fde.h"
bdb741f4 62
63#define PINGER_TIMEOUT 5
64
cc192b50 65/* windows uses the control socket for feedback to squid */
66#define LINK_TO_SQUID squid_link
bdb741f4 67
cc192b50 68// windows still requires WSAFD but there are too many dependancy problems
69// to just link to win32.cc where it is normally defined.
bdb741f4 70
cc192b50 71int
72Win32__WSAFDIsSet(int fd, fd_set FAR * set)
bdb741f4 73{
cc192b50 74 fde *F = &fd_table[fd];
75 SOCKET s = F->win32.handle;
bdb741f4 76
cc192b50 77 return __WSAFDIsSet(s, set);
bdb741f4 78}
79
cc192b50 80#else
bdb741f4 81
cc192b50 82#define PINGER_TIMEOUT 10
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
cc192b50 89// ICMP Engines are declared global here so they can call each other easily.
663ff9aa
AJ
90IcmpPinger control;
91Icmp4 icmp4;
663ff9aa 92Icmp6 icmp6;
62e76326 93
5be53f2d 94int icmp_pkts_sent = 0;
9d90e665 95
63be0a78 96/**
97 \ingroup pinger
98 \par This is the pinger external process.
99 *
100 \param argc Ignored.
101 \param argv Ignored.
102 */
cc192b50 103int
104main(int argc, char *argv[])
9d90e665 105{
cc192b50 106 fd_set R;
bdb741f4 107 int x;
cc192b50 108 int max_fd = 0;
bdb741f4 109
cc192b50 110 struct timeval tv;
111 const char *debug_args = "ALL,10";
112 char *t;
113 time_t last_check_time = 0;
bdb741f4 114
cc192b50 115 /*
116 * cevans - do this first. It grabs a raw socket. After this we can
117 * drop privs
118 */
119 int icmp4_worker = -1;
cc192b50 120 int icmp6_worker = -1;
cc192b50 121 int squid_link = -1;
62e76326 122
63be0a78 123 /** start by initializing the pinger debug cache.log-pinger. */
cc192b50 124 if ((t = getenv("SQUID_DEBUG")))
125 debug_args = xstrdup(t);
bdb741f4 126
127 getCurrentTime();
62e76326 128
059d13ed
AJ
129 // determine IPv4 or IPv6 capabilities before using sockets.
130 Ip::ProbeTransport();
131
cc192b50 132 _db_init(NULL, debug_args);
b6a2f15e 133
fa84c01d 134 debugs(42, DBG_CRITICAL, "pinger: Initialising ICMP pinger ...");
62e76326 135
cc192b50 136 icmp4_worker = icmp4.Open();
26ac0430 137 if (icmp4_worker < 0) {
fa84c01d 138 debugs(42, DBG_CRITICAL, "pinger: Unable to start ICMP pinger.");
b6a2f15e 139 }
cc192b50 140 max_fd = max(max_fd, icmp4_worker);
62e76326 141
cc192b50 142#if USE_IPV6
143 icmp6_worker = icmp6.Open();
26ac0430 144 if (icmp6_worker <0 ) {
fa84c01d 145 debugs(42, DBG_CRITICAL, "pinger: Unable to start ICMPv6 pinger.");
9d90e665 146 }
cc192b50 147 max_fd = max(max_fd, icmp6_worker);
d20b1cd0 148#endif
62e76326 149
63be0a78 150 /** abort if neither worker could open a socket. */
055421ee 151 if (icmp4_worker < 0 && icmp6_worker < 0) {
fa84c01d 152 debugs(42, DBG_CRITICAL, "FATAL: pinger: Unable to open any ICMP sockets.");
055421ee 153 exit(1);
b6a2f15e 154 }
62e76326 155
26ac0430 156 if ( (squid_link = control.Open()) < 0) {
fa84c01d 157 debugs(42, DBG_CRITICAL, "FATAL: pinger: Unable to setup Pinger control sockets.");
cc192b50 158 icmp4.Close();
cc192b50 159 icmp6.Close();
cc192b50 160 exit(1); // fatal error if the control channel fails.
365a4bce 161 }
cc192b50 162 max_fd = max(max_fd, squid_link);
62e76326 163
77468ee5
AJ
164 if (setgid(getgid()) < 0) {
165 debugs(42, DBG_CRITICAL, "FATAL: pinger: setgid(" << getgid() << ") failed: " << xstrerror());
166 icmp4.Close();
167 icmp6.Close();
6595704b 168 exit (1);
77468ee5
AJ
169 }
170 if (setuid(getuid()) < 0) {
171 debugs(42, DBG_CRITICAL, "FATAL: pinger: setuid(" << getuid() << ") failed: " << xstrerror());
172 icmp4.Close();
173 icmp6.Close();
174 exit (1);
175 }
b6a2f15e 176
ad25ac5d
AJ
177 last_check_time = squid_curtime;
178
9d90e665 179 for (;;) {
bdb741f4 180 tv.tv_sec = PINGER_TIMEOUT;
62e76326 181 tv.tv_usec = 0;
182 FD_ZERO(&R);
26ac0430 183 if (icmp4_worker >= 0) {
cc192b50 184 FD_SET(icmp4_worker, &R);
185 }
26ac0430 186 if (icmp6_worker >= 0) {
cc192b50 187 FD_SET(icmp6_worker, &R);
188 }
055421ee 189
cc192b50 190 FD_SET(squid_link, &R);
191 x = select(10, &R, NULL, NULL, &tv);
62e76326 192 getCurrentTime();
193
bdb741f4 194 if (x < 0) {
fa84c01d 195 debugs(42, DBG_CRITICAL, HERE << " FATAL Shutdown. select()==" << x << ", ERR: " << xstrerror());
cc192b50 196 control.Close();
62e76326 197 exit(1);
bdb741f4 198 }
62e76326 199
cc192b50 200 if (FD_ISSET(squid_link, &R)) {
201 control.Recv();
202 }
62e76326 203
cc192b50 204 if (icmp6_worker >= 0 && FD_ISSET(icmp6_worker, &R)) {
205 icmp6.Recv();
206 }
cc192b50 207 if (icmp4_worker >= 0 && FD_ISSET(icmp4_worker, &R)) {
208 icmp4.Recv();
209 }
62e76326 210
bdb741f4 211 if (PINGER_TIMEOUT + last_check_time < squid_curtime) {
cc192b50 212 if (send(LINK_TO_SQUID, &tv, 0, 0) < 0) {
fa84c01d 213 debugs(42, DBG_CRITICAL, "pinger: Closing. No requests in last " << PINGER_TIMEOUT << " seconds.");
cc192b50 214 control.Close();
62e76326 215 exit(1);
bdb741f4 216 }
62e76326 217
218 last_check_time = squid_curtime;
219 }
9d90e665 220 }
62e76326 221
145766ef 222 /* NOTREACHED */
bdb741f4 223 return 0;
9d90e665 224}
365a4bce 225
5e66b1a6 226#else /* !USE_ICMP */
074d6a40
AJ
227
228#include <ostream>
9d90e665 229int
230main(int argc, char *argv[])
231{
074d6a40 232 std::cerr << argv[0] << ": ICMP support not compiled in." << std::endl;
9d90e665 233 return 1;
234}
62e76326 235
9d90e665 236#endif /* USE_ICMP */
f53969cc 237