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