]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/Icmp6.cc
6954fd014d2ea60528b406d9d6a5c4c6f44efad1
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 42 ICMP Pinger program */
11 //#define SQUID_HELPER 1
19 #include "IcmpPinger.h"
20 #include "leakcheck.h"
21 #include "SquidTime.h"
23 // Some system headers are only neeed internally here.
24 // They should not be included via the header.
26 #if HAVE_NETINET_IP6_H
27 #include <netinet/ip6.h>
31 // see http://www.iana.org/assignments/icmpv6-parameters
33 IcmpPacketType(uint8_t v
)
35 // NP: LowPktStr is for codes 0-127
36 static const char *icmp6LowPktStr
[] = {
38 "Destination Unreachable", // 1 - RFC2463
39 "Packet Too Big", // 2 - RFC2463
40 "Time Exceeded", // 3 - RFC2463
41 "Parameter Problem", // 4 - RFC2463
44 // low codes 1-4 registered
46 return icmp6LowPktStr
[(int)(v
&0x7f)];
48 // NP: HighPktStr is for codes 128-255
49 static const char *icmp6HighPktStr
[] = {
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]
78 // high codes 127-153 registered
79 if (127 < v
&& v
< 154)
80 return icmp6HighPktStr
[(int)(v
&0x7f)];
82 // give all others a generic display
84 snprintf(buf
, sizeof(buf
), "ICMPv6 %u", v
);
88 Icmp6::Icmp6() : Icmp()
101 icmp_sock
= socket(PF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
105 debugs(50, DBG_CRITICAL
, MYNAME
<< " icmp_sock: " << xstrerr(xerrno
));
109 icmp_ident
= getpid() & 0xffff;
110 debugs(42, DBG_IMPORTANT
, "pinger: ICMPv6 socket opened");
116 * Generates an RFC 4443 Icmp6 ECHO Packet and sends into the network.
119 Icmp6::SendEcho(Ip::Address
&to
, int opcode
, const char *payload
, int len
)
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;
128 memset(pkt
, '\0', MAX_PKT6_SZ
);
129 icmp
= (struct icmp6_hdr
*)pkt
;
132 * cevans - beware signed/unsigned issues in untrusted data from
139 // Construct Icmp6 ECHO header
140 icmp
->icmp6_type
= ICMP6_ECHO_REQUEST
;
141 icmp
->icmp6_code
= 0;
142 icmp
->icmp6_cksum
= 0;
143 icmp
->icmp6_id
= icmp_ident
;
144 icmp
->icmp6_seq
= (unsigned short) icmp_pkts_sent
;
147 icmp6_pktsize
= sizeof(struct icmp6_hdr
);
149 // Fill Icmp6 ECHO data content
150 echo
= (icmpEchoData
*) (pkt
+ sizeof(icmp6_hdr
));
151 echo
->opcode
= (unsigned char) opcode
;
152 memcpy(&echo
->tv
, ¤t_time
, sizeof(struct timeval
));
154 icmp6_pktsize
+= sizeof(struct timeval
) + sizeof(char);
157 if (len
> MAX_PAYLOAD
)
160 memcpy(echo
->payload
, payload
, len
);
162 icmp6_pktsize
+= len
;
165 icmp
->icmp6_cksum
= CheckSum((unsigned short *) icmp
, icmp6_pktsize
);
168 ((sockaddr_in6
*)S
->ai_addr
)->sin6_port
= 0;
170 assert(icmp6_pktsize
<= MAX_PKT6_SZ
);
172 debugs(42, 5, HERE
<< "Send Icmp6 packet to " << to
<< ".");
174 x
= sendto(icmp_sock
,
183 debugs(42, DBG_IMPORTANT
, MYNAME
<< "ERROR: sending to ICMPv6 packet to " << to
<< ": " << xstrerr(xerrno
));
185 debugs(42,9, HERE
<< "x=" << x
);
187 Log(to
, 0, NULL
, 0, 0);
188 Ip::Address::FreeAddr(S
);
192 * Reads an RFC 4443 Icmp6 ECHO-REPLY Packet from the network.
198 struct addrinfo
*from
= NULL
;
199 // struct ip6_hdr *ip = NULL;
200 static char *pkt
= NULL
;
201 struct icmp6_hdr
*icmp6header
= NULL
;
202 icmpEchoData
*echo
= NULL
;
204 static pingerReplyData preply
;
207 debugs(42, DBG_CRITICAL
, HERE
<< "dropping ICMPv6 read. No socket!?");
212 pkt
= (char *)xmalloc(MAX_PKT6_SZ
);
215 Ip::Address::InitAddr(from
);
217 n
= recvfrom(icmp_sock
,
225 debugs(42, DBG_CRITICAL
, HERE
<< "Error when calling recvfrom() on ICMPv6 socket.");
226 Ip::Address::FreeAddr(from
);
232 #if GETTIMEOFDAY_NO_TZP
238 gettimeofday(&now
, NULL
);
242 debugs(42, 8, HERE
<< n
<< " bytes from " << preply
.from
);
244 // FIXME INET6 : The IPv6 Header (ip6_hdr) is not availble directly >:-(
246 // TTL still has to come from the IP header somewhere.
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.
249 /* IPv6 Header Structures (linux)
252 // fields (via simple define)
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??)
260 ip = (struct ip6_hdr *) pkt;
261 FIXME += sizeof(ip6_hdr);
263 debugs(42, DBG_CRITICAL, HERE << "ip6_nxt=" << ip->ip6_nxt <<
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)
271 icmp6header
= (struct icmp6_hdr
*) pkt
;
273 if (icmp6header
->icmp6_type
!= ICMP6_ECHO_REPLY
) {
275 switch (icmp6header
->icmp6_type
) {
279 /* ignore Router/Neighbour Advertisements */
283 debugs(42, 8, HERE
<< preply
.from
<< " said: " << icmp6header
->icmp6_type
<< "/" << (int)icmp6header
->icmp6_code
<< " " <<
284 IcmpPacketType(icmp6header
->icmp6_type
));
286 Ip::Address::FreeAddr(from
);
290 if (icmp6header
->icmp6_id
!= icmp_ident
) {
291 debugs(42, 8, HERE
<< "dropping Icmp6 read. IDENT check failed. ident=='" << icmp_ident
<< "'=='" << icmp6header
->icmp6_id
<< "'");
292 Ip::Address::FreeAddr(from
);
296 echo
= (icmpEchoData
*) (pkt
+ sizeof(icmp6_hdr
));
298 preply
.opcode
= echo
->opcode
;
301 memcpy(&tv
, &echo
->tv
, sizeof(struct timeval
));
302 preply
.rtt
= tvSubMsec(tv
, now
);
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
307 * for now everything is 1 v6 hop away with variant RTT
308 * WANT: preply.hops = ip->ip6_hops; // ipHops(ip->ip_hops);
312 preply
.psize
= n
- /* sizeof(ip6_hdr) - */ sizeof(icmp6_hdr
) - (sizeof(icmpEchoData
) - MAX_PKT6_SZ
);
314 /* Ensure the response packet has safe payload size */
315 if ( preply
.psize
> (unsigned short) MAX_PKT6_SZ
) {
316 preply
.psize
= MAX_PKT6_SZ
;
317 } else if ( preply
.psize
< (unsigned short)0) {
322 icmp6header
->icmp6_type
,
323 IcmpPacketType(icmp6header
->icmp6_type
),
327 /* send results of the lookup back to squid.*/
328 control
.SendResult(preply
, (sizeof(pingerReplyData
) - PINGER_PAYLOAD_SZ
+ preply
.psize
) );
329 Ip::Address::FreeAddr(from
);
332 #endif /* USE_ICMP */