Icmp6.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
13#include "squid.h"
14
15#if USE_ICMP
16
17#include "debug/Stream.h"
18#include "Icmp6.h"
19#include "IcmpPinger.h"
20#include "time/gadgets.h"
21
22// Some system headers are only neeed internally here.
23// They should not be included via the header.
24
25#if HAVE_NETINET_IP6_H
26#include <netinet/ip6.h>
27#endif
28
29// Icmp6 OP-Codes
30// see http://www.iana.org/assignments/icmpv6-parameters
31static const char *
33{
34 // NP: LowPktStr is for codes 0-127
35 static const char *icmp6LowPktStr[] = {
36 "ICMPv6 0", // 0
37 "Destination Unreachable", // 1 - RFC2463
38 "Packet Too Big", // 2 - RFC2463
39 "Time Exceeded", // 3 - RFC2463
40 "Parameter Problem", // 4 - RFC2463
41 };
42
43 // low codes 1-4 registered
44 if (0 < v && v < 5)
45 return icmp6LowPktStr[(int)(v&0x7f)];
46
47 // NP: HighPktStr is for codes 128-255
48 static const char *icmp6HighPktStr[] = {
49 "Echo Request", // 128 - RFC2463
50 "Echo Reply", // 129 - RFC2463
51 "Multicast Listener Query", // 130 - RFC2710
52 "Multicast Listener Report", // 131 - RFC2710
53 "Multicast Listener Done", // 132 - RFC2710
54 "Router Solicitation", // 133 - RFC4861
55 "Router Advertisement", // 134 - RFC4861
56 "Neighbor Solicitation", // 135 - RFC4861
57 "Neighbor Advertisement", // 136 - RFC4861
58 "Redirect Message", // 137 - RFC4861
59 "Router Renumbering", // 138 - Crawford
60 "ICMP Node Information Query", // 139 - RFC4620
61 "ICMP Node Information Response", // 140 - RFC4620
62 "Inverse Neighbor Discovery Solicitation", // 141 - RFC3122
63 "Inverse Neighbor Discovery Advertisement", // 142 - RFC3122
64 "Version 2 Multicast Listener Report", // 143 - RFC3810
65 "Home Agent Address Discovery Request", // 144 - RFC3775
66 "Home Agent Address Discovery Reply", // 145 - RFC3775
67 "Mobile Prefix Solicitation", // 146 - RFC3775
68 "Mobile Prefix Advertisement", // 147 - RFC3775
69 "Certification Path Solicitation", // 148 - RFC3971
70 "Certification Path Advertisement", // 149 - RFC3971
71 "ICMP Experimental (150)", // 150 - RFC4065
72 "Multicast Router Advertisement", // 151 - RFC4286
73 "Multicast Router Solicitation", // 152 - RFC4286
74 "Multicast Router Termination", // 153 - [RFC4286]
75 };
76
77 // high codes 127-153 registered
78 if (127 < v && v < 154)
79 return icmp6HighPktStr[(int)(v&0x7f)];
80
81 // give all others a generic display
82 static char buf[50];
83 snprintf(buf, sizeof(buf), "ICMPv6 %u", v);
84 return buf;
85}
86
88{
89 ; // nothing new.
90}
91
93{
94 Close();
95}
96
97int
99{
100 icmp_sock = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
101
102 if (icmp_sock < 0) {
103 int xerrno = errno;
104 debugs(50, DBG_CRITICAL, MYNAME << " icmp_sock: " << xstrerr(xerrno));
105 return -1;
106 }
107
108 icmp_ident = getpid() & 0xffff;
109 debugs(42, DBG_IMPORTANT, "ICMPv6 socket opened");
110
111 return icmp_sock;
112}
113
117void
118Icmp6::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
119{
120 int x;
121 LOCAL_ARRAY(char, pkt, MAX_PKT6_SZ);
122 struct icmp6_hdr *icmp = nullptr;
123 icmpEchoData *echo = nullptr;
124 struct addrinfo *S = nullptr;
125 size_t icmp6_pktsize = 0;
126
127 static_assert(sizeof(*icmp) + sizeof(*echo) <= sizeof(pkt), "our custom ICMPv6 Echo payload fits the packet buffer");
128
129 memset(pkt, '\0', MAX_PKT6_SZ);
130 icmp = (struct icmp6_hdr *)pkt;
131
132 /*
133 * cevans - beware signed/unsigned issues in untrusted data from
134 * the network!!
135 */
136 if (len < 0) {
137 len = 0;
138 }
139
140 // Construct Icmp6 ECHO header
141 icmp->icmp6_type = ICMP6_ECHO_REQUEST;
142 icmp->icmp6_code = 0;
143 icmp->icmp6_cksum = 0;
144 icmp->icmp6_id = icmp_ident;
145 icmp->icmp6_seq = (unsigned short) icmp_pkts_sent;
147
148 icmp6_pktsize = sizeof(struct icmp6_hdr);
149
150 // Fill Icmp6 ECHO data content
151 echo = reinterpret_cast<icmpEchoData *>(reinterpret_cast<char *>(pkt) + sizeof(*icmp));
152 echo->opcode = (unsigned char) opcode;
153 memcpy(&echo->tv, &current_time, sizeof(struct timeval));
154
155 icmp6_pktsize += sizeof(struct timeval) + sizeof(char);
156
157 if (payload) {
158 if (len > MAX_PAYLOAD)
159 len = MAX_PAYLOAD;
160
161 memcpy(echo->payload, payload, len);
162
163 icmp6_pktsize += len;
164 }
165
166 icmp->icmp6_cksum = CheckSum((unsigned short *) icmp, icmp6_pktsize);
167
168 to.getAddrInfo(S);
169 ((sockaddr_in6*)S->ai_addr)->sin6_port = 0;
170
171 assert(icmp6_pktsize <= MAX_PKT6_SZ);
172
173 debugs(42, 5, "Send Icmp6 packet to " << to << ".");
174
175 x = sendto(icmp_sock,
176 (const void *) pkt,
177 icmp6_pktsize,
178 0,
179 S->ai_addr,
180 S->ai_addrlen);
181
182 if (x < 0) {
183 int xerrno = errno;
184 debugs(42, DBG_IMPORTANT, MYNAME << "ERROR: sending to ICMPv6 packet to " << to << ": " << xstrerr(xerrno));
185 }
186 debugs(42,9, "x=" << x);
187
188 Log(to, 0, nullptr, 0, 0);
190}
191
195void
197{
198 int n;
199 struct addrinfo *from = nullptr;
200// struct ip6_hdr *ip = nullptr;
201 static char *pkt = nullptr;
202 struct icmp6_hdr *icmp6header = nullptr;
203 icmpEchoData *echo = nullptr;
204 struct timeval now;
205 static pingerReplyData preply;
206
207 if (icmp_sock < 0) {
208 debugs(42, DBG_CRITICAL, "dropping ICMPv6 read. No socket!?");
209 return;
210 }
211
212 if (pkt == nullptr) {
213 pkt = (char *)xmalloc(MAX_PKT6_SZ);
214 }
215
217
218 n = recvfrom(icmp_sock,
219 (void *)pkt,
221 0,
222 from->ai_addr,
223 &from->ai_addrlen);
224
225 if (n <= 0) {
226 debugs(42, DBG_CRITICAL, "ERROR: when calling recvfrom() on ICMPv6 socket.");
228 return;
229 }
230
231 preply.from = *from;
232
233#if GETTIMEOFDAY_NO_TZP
234
235 gettimeofday(&now);
236
237#else
238
239 gettimeofday(&now, nullptr);
240
241#endif
242
243 debugs(42, 8, n << " bytes from " << preply.from);
244
245// XXX: The IPv6 Header (ip6_hdr) is not available directly
246//
247// TTL still has to come from the IP header somewhere.
248// still need to strip and process it properly.
249// probably have to rely on RTT as given by timestamp in data sent and current.
250 /* IPv6 Header Structures (linux)
251 struct ip6_hdr
252
253 // fields (via simple define)
254 #define ip6_vfc // N.A
255 #define ip6_flow // N/A
256 #define ip6_plen // payload length.
257 #define ip6_nxt // expect to be type 0x3a - ICMPv6
258 #define ip6_hlim // MAX hops (always 64, but no guarantee)
259 #define ip6_hops // HOPS!!! (can it be true??)
260
261 ip = (struct ip6_hdr *) pkt;
262 // += sizeof(ip6_hdr);
263
264 debugs(42, DBG_CRITICAL, "ip6_nxt=" << ip->ip6_nxt <<
265 ", ip6_plen=" << ip->ip6_plen <<
266 ", ip6_hlim=" << ip->ip6_hlim <<
267 ", ip6_hops=" << ip->ip6_hops <<
268 " ::: 40 == sizef(ip6_hdr) == " << sizeof(ip6_hdr)
269 );
270 */
271
272 icmp6header = (struct icmp6_hdr *) pkt;
273
274 if (icmp6header->icmp6_type != ICMP6_ECHO_REPLY) {
275
276 switch (icmp6header->icmp6_type) {
277 case 134:
278 case 135:
279 case 136:
280 /* ignore Router/Neighbour Advertisements */
281 break;
282
283 default:
284 debugs(42, 8, preply.from << " said: " << icmp6header->icmp6_type << "/" << (int)icmp6header->icmp6_code << " " <<
285 IcmpPacketType(icmp6header->icmp6_type));
286 }
288 return;
289 }
290
291 if (icmp6header->icmp6_id != icmp_ident) {
292 debugs(42, 8, "dropping Icmp6 read. IDENT check failed. ident=='" << icmp_ident << "'=='" << icmp6header->icmp6_id << "'");
294 return;
295 }
296
297 echo = (icmpEchoData *) (pkt + sizeof(icmp6_hdr));
298
299 preply.opcode = echo->opcode;
300
301 struct timeval tv;
302 memcpy(&tv, &echo->tv, sizeof(struct timeval));
303 preply.rtt = tvSubMsec(tv, now);
304
305 /*
306 * Without access to the IPv6-Hops header we must rely on the total RTT
307 * and could calculate the hops from that, but it produces some weird value mappings using ipHops
308 * for now everything is 1 v6 hop away with variant RTT
309 * WANT: preply.hops = ip->ip6_hops; // ipHops(ip->ip_hops);
310 */
311 preply.hops = 1;
312
313 preply.psize = n - /* sizeof(ip6_hdr) - */ sizeof(icmp6_hdr) - (sizeof(icmpEchoData) - MAX_PKT6_SZ);
314
315 /* Ensure the response packet has safe payload size */
316 if ( preply.psize > (unsigned short) MAX_PKT6_SZ) {
317 preply.psize = MAX_PKT6_SZ;
318 } else if ( preply.psize < (unsigned short)0) {
319 preply.psize = 0;
320 }
321
322 Log(preply.from,
323 icmp6header->icmp6_type,
324 IcmpPacketType(icmp6header->icmp6_type),
325 preply.rtt,
326 preply.hops);
327
328 /* send results of the lookup back to squid.*/
329 control.SendResult(preply, (sizeof(pingerReplyData) - PINGER_PAYLOAD_SZ + preply.psize) );
331}
332
333#endif /* USE_ICMP */
334
static const char * IcmpPacketType(uint8_t v)
Definition: Icmp6.cc:32
#define IPPROTO_ICMPV6
Definition: Icmp6.h:38
IcmpPinger control
pinger helper contains one of these as a global object.
Definition: pinger.cc:90
#define PINGER_PAYLOAD_SZ
Definition: Icmp.h:16
int icmp_pkts_sent
Definition: pinger.cc:94
#define MAX_PKT6_SZ
Definition: Icmp.h:20
#define MAX_PAYLOAD
Definition: Icmp.h:18
#define assert(EX)
Definition: assert.h:17
static time_t now
Definition: cachemgr.cc:109
~Icmp6() override
Definition: Icmp6.cc:92
Icmp6()
Definition: Icmp6.cc:87
int Open() override
Start pinger helper and initiate control channel.
Definition: Icmp6.cc:98
void SendEcho(Ip::Address &, int, const char *, int) override
Definition: Icmp6.cc:118
void Recv(void) override
Definition: Icmp6.cc:196
void SendResult(pingerReplyData &preply, int len)
Send ICMP results back to squid.
Definition: IcmpPinger.cc:218
Definition: Icmp.h:68
virtual void Close()
Shutdown pinger helper and control channel.
Definition: Icmp.cc:25
int CheckSum(unsigned short *ptr, int size)
Calculate a packet checksum.
Definition: Icmp.cc:38
int icmp_ident
Definition: Icmp.h:122
void Log(const Ip::Address &addr, const uint8_t type, const char *pkt_str, const int rtt, const int hops)
Log the packet.
Definition: Icmp.cc:88
int icmp_sock
Definition: Icmp.h:121
static void InitAddr(struct addrinfo *&ai)
Definition: Address.cc:668
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:686
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition: Address.cc:599
#define MYNAME
Definition: Stream.h:236
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
#define xmalloc
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:68
char payload[MAX_PAYLOAD]
Definition: Icmp.h:48
unsigned char opcode
Definition: Icmp.h:47
struct timeval tv
Definition: Icmp.h:46
int unsigned int
Definition: stub_fd.cc:19
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:17
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors