source: squid-ssl/trunk/fuentes/src/icmp/Icmp6.cc @ 5496

Last change on this file since 5496 was 5496, checked in by Juanma, 21 months ago

Initial release

File size: 9.5 KB
Line 
1/*
2 * Copyright (C) 1996-2015 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 "Icmp6.h"
19#include "IcmpPinger.h"
20#include "leakcheck.h"
21#include "SquidTime.h"
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
30// Icmp6 OP-Codes
31// see http://www.iana.org/assignments/icmpv6-parameters
32static const char *
33IcmpPacketType(uint8_t v)
34{
35    // NP: LowPktStr is for codes 0-127
36    static const char *icmp6LowPktStr[] = {
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
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[] = {
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]
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}
87
88Icmp6::Icmp6() : Icmp()
89{
90    ; // nothing new.
91}
92
93Icmp6::~Icmp6()
94{
95    Close();
96}
97
98int
99Icmp6::Open(void)
100{
101    icmp_sock = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
102
103    if (icmp_sock < 0) {
104        debugs(50, DBG_CRITICAL, HERE << " icmp_sock: " << xstrerror());
105        return -1;
106    }
107
108    icmp_ident = getpid() & 0xffff;
109    debugs(42, DBG_IMPORTANT, "pinger: ICMPv6 socket opened");
110
111    return icmp_sock;
112}
113
114/**
115 * Generates an RFC 4443 Icmp6 ECHO Packet and sends into the network.
116 */
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 = NULL;
123    icmpEchoData *echo = NULL;
124    struct addrinfo *S = NULL;
125    size_t icmp6_pktsize = 0;
126
127    memset(pkt, '\0', MAX_PKT6_SZ);
128    icmp = (struct icmp6_hdr *)pkt;
129
130    /*
131     * cevans - beware signed/unsigned issues in untrusted data from
132     * the network!!
133     */
134    if (len < 0) {
135        len = 0;
136    }
137
138    // Construct Icmp6 ECHO header
139    icmp->icmp6_type = ICMP6_ECHO_REQUEST;
140    icmp->icmp6_code = 0;
141    icmp->icmp6_cksum = 0;
142    icmp->icmp6_id = icmp_ident;
143    icmp->icmp6_seq = (unsigned short) icmp_pkts_sent;
144    ++icmp_pkts_sent;
145
146    icmp6_pktsize = sizeof(struct icmp6_hdr);
147
148    // Fill Icmp6 ECHO data content
149    echo = (icmpEchoData *) (pkt + sizeof(icmp6_hdr));
150    echo->opcode = (unsigned char) opcode;
151    memcpy(&echo->tv, &current_time, sizeof(struct timeval));
152
153    icmp6_pktsize += sizeof(struct timeval) + sizeof(char);
154
155    if (payload) {
156        if (len > MAX_PAYLOAD)
157            len = MAX_PAYLOAD;
158
159        memcpy(echo->payload, payload, len);
160
161        icmp6_pktsize += len;
162    }
163
164    icmp->icmp6_cksum = CheckSum((unsigned short *) icmp, icmp6_pktsize);
165
166    to.getAddrInfo(S);
167    ((sockaddr_in6*)S->ai_addr)->sin6_port = 0;
168
169    assert(icmp6_pktsize <= MAX_PKT6_SZ);
170
171    debugs(42, 5, HERE << "Send Icmp6 packet to " << to << ".");
172
173    x = sendto(icmp_sock,
174               (const void *) pkt,
175               icmp6_pktsize,
176               0,
177               S->ai_addr,
178               S->ai_addrlen);
179
180    if (x < 0) {
181        debugs(42, DBG_IMPORTANT, HERE << "Error sending to ICMPv6 packet to " << to << ". ERR: " << xstrerror());
182    }
183    debugs(42,9, HERE << "x=" << x);
184
185    Log(to, 0, NULL, 0, 0);
186    Ip::Address::FreeAddr(S);
187}
188
189/**
190 * Reads an RFC 4443 Icmp6 ECHO-REPLY Packet from the network.
191 */
192void
193Icmp6::Recv(void)
194{
195    int n;
196    struct addrinfo *from = NULL;
197//    struct ip6_hdr *ip = NULL;
198    static char *pkt = NULL;
199    struct icmp6_hdr *icmp6header = NULL;
200    icmpEchoData *echo = NULL;
201    struct timeval now;
202    static pingerReplyData preply;
203
204    if (icmp_sock < 0) {
205        debugs(42, DBG_CRITICAL, HERE << "dropping ICMPv6 read. No socket!?");
206        return;
207    }
208
209    if (pkt == NULL) {
210        pkt = (char *)xmalloc(MAX_PKT6_SZ);
211    }
212
213    Ip::Address::InitAddr(from);
214
215    n = recvfrom(icmp_sock,
216                 (void *)pkt,
217                 MAX_PKT6_SZ,
218                 0,
219                 from->ai_addr,
220                 &from->ai_addrlen);
221
222    if (n <= 0) {
223        debugs(42, DBG_CRITICAL, HERE << "Error when calling recvfrom() on ICMPv6 socket.");
224        Ip::Address::FreeAddr(from);
225        return;
226    }
227
228    preply.from = *from;
229
230#if GETTIMEOFDAY_NO_TZP
231
232    gettimeofday(&now);
233
234#else
235
236    gettimeofday(&now, NULL);
237
238#endif
239
240    debugs(42, 8, HERE << n << " bytes from " << preply.from);
241
242// FIXME INET6 : The IPv6 Header (ip6_hdr) is not availble directly >:-(
243//
244// TTL still has to come from the IP header somewhere.
245//  still need to strip and process it properly.
246//  probably have to rely on RTT as given by timestamp in data sent and current.
247    /* IPv6 Header Structures (linux)
248    struct ip6_hdr
249
250    // fields (via simple define)
251    #define ip6_vfc     // N.A
252    #define ip6_flow    // N/A
253    #define ip6_plen    // payload length.
254    #define ip6_nxt     // expect to be type 0x3a - ICMPv6
255    #define ip6_hlim    // MAX hops  (always 64, but no guarantee)
256    #define ip6_hops    // HOPS!!!  (can it be true??)
257
258        ip = (struct ip6_hdr *) pkt;
259        pkt += sizeof(ip6_hdr);
260
261    debugs(42, DBG_CRITICAL, HERE << "ip6_nxt=" << ip->ip6_nxt <<
262            ", ip6_plen=" << ip->ip6_plen <<
263            ", ip6_hlim=" << ip->ip6_hlim <<
264            ", ip6_hops=" << ip->ip6_hops   <<
265            " ::: 40 == sizef(ip6_hdr) == " << sizeof(ip6_hdr)
266    );
267    */
268
269    icmp6header = (struct icmp6_hdr *) pkt;
270    pkt += sizeof(icmp6_hdr);
271
272    if (icmp6header->icmp6_type != ICMP6_ECHO_REPLY) {
273
274        switch (icmp6header->icmp6_type) {
275        case 134:
276        case 135:
277        case 136:
278            /* ignore Router/Neighbour Advertisements */
279            break;
280
281        default:
282            debugs(42, 8, HERE << preply.from << " said: " << icmp6header->icmp6_type << "/" << (int)icmp6header->icmp6_code << " " <<
283                   IcmpPacketType(icmp6header->icmp6_type));
284        }
285        Ip::Address::FreeAddr(from);
286        return;
287    }
288
289    if (icmp6header->icmp6_id != icmp_ident) {
290        debugs(42, 8, HERE << "dropping Icmp6 read. IDENT check failed. ident=='" << icmp_ident << "'=='" << icmp6header->icmp6_id << "'");
291        Ip::Address::FreeAddr(from);
292        return;
293    }
294
295    echo = (icmpEchoData *) pkt;
296
297    preply.opcode = echo->opcode;
298
299    struct timeval tv;
300    memcpy(&tv, &echo->tv, sizeof(struct timeval));
301    preply.rtt = tvSubMsec(tv, now);
302
303    /*
304     * FIXME INET6: Without access to the IPv6-Hops header we must rely on the total RTT
305     *      and could caculate the hops from that, but it produces some weird value mappings using ipHops
306     *  for now everything is 1 v6 hop away with variant RTT
307     * WANT:    preply.hops = ip->ip6_hops; // ipHops(ip->ip_hops);
308     */
309    preply.hops = 1;
310
311    preply.psize = n - /* sizeof(ip6_hdr) - */ sizeof(icmp6_hdr) - (sizeof(icmpEchoData) - MAX_PKT6_SZ);
312
313    /* Ensure the response packet has safe payload size */
314    if ( preply.psize > (unsigned short) MAX_PKT6_SZ) {
315        preply.psize = MAX_PKT6_SZ;
316    } else if ( preply.psize < (unsigned short)0) {
317        preply.psize = 0;
318    }
319
320    Log(preply.from,
321        icmp6header->icmp6_type,
322        IcmpPacketType(icmp6header->icmp6_type),
323        preply.rtt,
324        preply.hops);
325
326    /* send results of the lookup back to squid.*/
327    control.SendResult(preply, (sizeof(pingerReplyData) - PINGER_PAYLOAD_SZ + preply.psize) );
328    Ip::Address::FreeAddr(from);
329}
330
331#endif /* USE_ICMP */
332
Note: See TracBrowser for help on using the repository browser.