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