]> git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/IcmpPinger.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / icmp / IcmpPinger.cc
1 /*
2 * Copyright (C) 1996-2020 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
13 #include "squid.h"
14
15 #if USE_ICMP
16
17 #include "Debug.h"
18 #include "Icmp4.h"
19 #include "Icmp6.h"
20 #include "IcmpPinger.h"
21 #include "SquidTime.h"
22
23 #include <cerrno>
24
25 IcmpPinger::IcmpPinger() : Icmp()
26 {
27 // these start invalid. Setup properly in Open()
28 socket_from_squid = -1;
29 socket_to_squid = -1;
30 }
31
32 IcmpPinger::~IcmpPinger()
33 {
34 Close();
35 }
36
37 #if _SQUID_WINDOWS_
38 void
39 Win32SockCleanup(void)
40 {
41 WSACleanup();
42 return;
43 }
44 #endif
45
46 int
47 IcmpPinger::Open(void)
48 {
49 #if _SQUID_WINDOWS_
50
51 WSADATA wsaData;
52 WSAPROTOCOL_INFO wpi;
53 char buf[sizeof(wpi)];
54 int x;
55
56 struct sockaddr_in PS;
57 int xerrno;
58
59 WSAStartup(2, &wsaData);
60 atexit(Win32SockCleanup);
61
62 getCurrentTime();
63 _db_init(NULL, "ALL,1");
64 setmode(0, O_BINARY);
65 setmode(1, O_BINARY);
66 x = read(0, buf, sizeof(wpi));
67
68 if (x < (int)sizeof(wpi)) {
69 xerrno = errno;
70 getCurrentTime();
71 debugs(42, DBG_CRITICAL, MYNAME << " read: FD 0: " << xstrerr(xerrno));
72 write(1, "ERR\n", 4);
73 return -1;
74 }
75
76 memcpy(&wpi, buf, sizeof(wpi));
77
78 write(1, "OK\n", 3);
79 x = read(0, buf, sizeof(PS));
80
81 if (x < (int)sizeof(PS)) {
82 xerrno = errno;
83 getCurrentTime();
84 debugs(42, DBG_CRITICAL, MYNAME << " read: FD 0: " << xstrerr(xerrno));
85 write(1, "ERR\n", 4);
86 return -1;
87 }
88
89 memcpy(&PS, buf, sizeof(PS));
90
91 icmp_sock = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, &wpi, 0, 0);
92
93 if (icmp_sock == -1) {
94 xerrno = errno;
95 getCurrentTime();
96 debugs(42, DBG_CRITICAL, MYNAME << "WSASocket: " << xstrerr(xerrno));
97 write(1, "ERR\n", 4);
98 return -1;
99 }
100
101 x = connect(icmp_sock, (struct sockaddr *) &PS, sizeof(PS));
102
103 if (SOCKET_ERROR == x) {
104 xerrno = errno;
105 getCurrentTime();
106 debugs(42, DBG_CRITICAL, MYNAME << "connect: " << xstrerr(xerrno));
107 write(1, "ERR\n", 4);
108 return -1;
109 }
110
111 write(1, "OK\n", 3);
112 memset(buf, 0, sizeof(buf));
113 x = recv(icmp_sock, (void *) buf, sizeof(buf), 0);
114
115 if (x < 3) {
116 xerrno = errno;
117 debugs(42, DBG_CRITICAL, MYNAME << "recv: " << xstrerr(xerrno));
118 return -1;
119 }
120
121 x = send(icmp_sock, (const void *) buf, strlen(buf), 0);
122 xerrno = errno;
123
124 if (x < 3 || strncmp("OK\n", buf, 3)) {
125 debugs(42, DBG_CRITICAL, MYNAME << "recv: " << xstrerr(xerrno));
126 return -1;
127 }
128
129 getCurrentTime();
130 debugs(42, DBG_IMPORTANT, "pinger: Squid socket opened");
131
132 /* windows uses a socket stream as a dual-direction channel */
133 socket_to_squid = icmp_sock;
134 socket_from_squid = icmp_sock;
135
136 return icmp_sock;
137
138 #else /* !_SQUID_WINDOWS_ */
139
140 /* non-windows apps use stdin/out pipes as the squid channel(s) */
141 socket_from_squid = 0; // use STDIN macro ??
142 socket_to_squid = 1; // use STDOUT macro ??
143 return socket_to_squid;
144 #endif
145 }
146
147 void
148 IcmpPinger::Close(void)
149 {
150 #if _SQUID_WINDOWS_
151
152 shutdown(icmp_sock, SD_BOTH);
153 close(icmp_sock);
154 icmp_sock = -1;
155 #endif
156
157 /* also shutdown the helper engines */
158 icmp4.Close();
159 icmp6.Close();
160 }
161
162 void
163 IcmpPinger::Recv(void)
164 {
165 static pingerEchoData pecho;
166 int n;
167 int guess_size;
168
169 pecho = pingerEchoData();
170 n = recv(socket_from_squid, &pecho, sizeof(pecho), 0);
171
172 if (n < 0) {
173 debugs(42, DBG_IMPORTANT, "Pinger exiting.");
174 Close();
175 exit(EXIT_FAILURE);
176 }
177
178 if (0 == n) {
179 /* EOF indicator */
180 debugs(42, DBG_CRITICAL, "EOF encountered. Pinger exiting.");
181 errno = 0;
182 Close();
183 exit(EXIT_FAILURE);
184 }
185
186 guess_size = n - (sizeof(pingerEchoData) - PINGER_PAYLOAD_SZ);
187
188 if (guess_size != pecho.psize) {
189 debugs(42, 2, HERE << "size mismatch, guess=" << guess_size << ", psize=" << pecho.psize);
190 /* don't process this message, but keep running */
191 return;
192 }
193
194 /* pass request for ICMPv6 handing */
195 if (pecho.to.isIPv6()) {
196 debugs(42, 2, HERE << " Pass " << pecho.to << " off to ICMPv6 module.");
197 icmp6.SendEcho(pecho.to,
198 pecho.opcode,
199 pecho.payload,
200 pecho.psize);
201 }
202
203 /* pass the packet for ICMP handling */
204 else if (pecho.to.isIPv4()) {
205 debugs(42, 2, HERE << " Pass " << pecho.to << " off to ICMPv4 module.");
206 icmp4.SendEcho(pecho.to,
207 pecho.opcode,
208 pecho.payload,
209 pecho.psize);
210 } else {
211 debugs(42, DBG_IMPORTANT, HERE << " IP has unknown Type. " << pecho.to );
212 }
213 }
214
215 void
216 IcmpPinger::SendResult(pingerReplyData &preply, int len)
217 {
218 debugs(42, 2, HERE << "return result to squid. len=" << len);
219
220 if (send(socket_to_squid, &preply, len, 0) < 0) {
221 int xerrno = errno;
222 debugs(42, DBG_CRITICAL, "pinger: FATAL error on send: " << xstrerr(xerrno));
223 Close();
224 exit(EXIT_FAILURE);
225 }
226 }
227
228 #endif /* USE_ICMP */
229