Icmp6.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2017 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
32 static const char *
33 IcmpPacketType(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 
89 {
90  ; // nothing new.
91 }
92 
94 {
95  Close();
96 }
97 
98 int
100 {
101  icmp_sock = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
102 
103  if (icmp_sock < 0) {
104  int xerrno = errno;
105  debugs(50, DBG_CRITICAL, MYNAME << " icmp_sock: " << xstrerr(xerrno));
106  return -1;
107  }
108 
109  icmp_ident = getpid() & 0xffff;
110  debugs(42, DBG_IMPORTANT, "pinger: ICMPv6 socket opened");
111 
112  return icmp_sock;
113 }
114 
118 void
119 Icmp6::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
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 
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;
145  ++icmp_pkts_sent;
146 
147  icmp6_pktsize = sizeof(struct icmp6_hdr);
148 
149  // Fill Icmp6 ECHO data content
150  echo = (icmpEchoData *) (pkt + sizeof(icmp6_hdr));
151  echo->opcode = (unsigned char) opcode;
152  memcpy(&echo->tv, &current_time, sizeof(struct timeval));
153 
154  icmp6_pktsize += sizeof(struct timeval) + sizeof(char);
155 
156  if (payload) {
157  if (len > MAX_PAYLOAD)
158  len = MAX_PAYLOAD;
159 
160  memcpy(echo->payload, payload, len);
161 
162  icmp6_pktsize += len;
163  }
164 
165  icmp->icmp6_cksum = CheckSum((unsigned short *) icmp, icmp6_pktsize);
166 
167  to.getAddrInfo(S);
168  ((sockaddr_in6*)S->ai_addr)->sin6_port = 0;
169 
170  assert(icmp6_pktsize <= MAX_PKT6_SZ);
171 
172  debugs(42, 5, HERE << "Send Icmp6 packet to " << to << ".");
173 
174  x = sendto(icmp_sock,
175  (const void *) pkt,
176  icmp6_pktsize,
177  0,
178  S->ai_addr,
179  S->ai_addrlen);
180 
181  if (x < 0) {
182  int xerrno = errno;
183  debugs(42, DBG_IMPORTANT, MYNAME << "ERROR: sending to ICMPv6 packet to " << to << ": " << xstrerr(xerrno));
184  }
185  debugs(42,9, HERE << "x=" << x);
186 
187  Log(to, 0, NULL, 0, 0);
189 }
190 
194 void
196 {
197  int n;
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;
203  struct timeval now;
204  static pingerReplyData preply;
205 
206  if (icmp_sock < 0) {
207  debugs(42, DBG_CRITICAL, HERE << "dropping ICMPv6 read. No socket!?");
208  return;
209  }
210 
211  if (pkt == NULL) {
212  pkt = (char *)xmalloc(MAX_PKT6_SZ);
213  }
214 
215  Ip::Address::InitAddr(from);
216 
217  n = recvfrom(icmp_sock,
218  (void *)pkt,
219  MAX_PKT6_SZ,
220  0,
221  from->ai_addr,
222  &from->ai_addrlen);
223 
224  if (n <= 0) {
225  debugs(42, DBG_CRITICAL, HERE << "Error when calling recvfrom() on ICMPv6 socket.");
226  Ip::Address::FreeAddr(from);
227  return;
228  }
229 
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.
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)
250  struct ip6_hdr
251 
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??)
259 
260  ip = (struct ip6_hdr *) pkt;
261  FIXME += sizeof(ip6_hdr);
262 
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)
268  );
269  */
270 
271  icmp6header = (struct icmp6_hdr *) pkt;
272 
273  if (icmp6header->icmp6_type != ICMP6_ECHO_REPLY) {
274 
275  switch (icmp6header->icmp6_type) {
276  case 134:
277  case 135:
278  case 136:
279  /* ignore Router/Neighbour Advertisements */
280  break;
281 
282  default:
283  debugs(42, 8, HERE << preply.from << " said: " << icmp6header->icmp6_type << "/" << (int)icmp6header->icmp6_code << " " <<
284  IcmpPacketType(icmp6header->icmp6_type));
285  }
286  Ip::Address::FreeAddr(from);
287  return;
288  }
289 
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);
293  return;
294  }
295 
296  echo = (icmpEchoData *) (pkt + sizeof(icmp6_hdr));
297 
298  preply.opcode = echo->opcode;
299 
300  struct timeval tv;
301  memcpy(&tv, &echo->tv, sizeof(struct timeval));
302  preply.rtt = tvSubMsec(tv, now);
303 
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
307  * for now everything is 1 v6 hop away with variant RTT
308  * WANT: preply.hops = ip->ip6_hops; // ipHops(ip->ip_hops);
309  */
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 */
315  if ( preply.psize > (unsigned short) MAX_PKT6_SZ) {
316  preply.psize = MAX_PKT6_SZ;
317  } else if ( preply.psize < (unsigned short)0) {
318  preply.psize = 0;
319  }
320 
321  Log(preply.from,
322  icmp6header->icmp6_type,
323  IcmpPacketType(icmp6header->icmp6_type),
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) );
329  Ip::Address::FreeAddr(from);
330 }
331 
332 #endif /* USE_ICMP */
333 
#define PINGER_PAYLOAD_SZ
Definition: Icmp.h:16
Definition: Icmp.h:64
#define assert(EX)
Definition: assert.h:17
Icmp6()
Definition: Icmp6.cc:88
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:694
virtual void Recv(void)
Definition: Icmp6.cc:195
virtual int Open()
Start pinger helper and initiate control channel.
Definition: Icmp6.cc:99
#define DBG_CRITICAL
Definition: Debug.h:44
IcmpPinger control
pinger helper contains one of these as a global object.
Definition: pinger.cc:90
struct timeval current_time
Definition: stub_time.cc:15
unsigned char opcode
Definition: Icmp.h:44
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
#define MAX_PAYLOAD
Definition: Icmp.h:18
virtual ~Icmp6()
Definition: Icmp6.cc:93
int icmp_sock
Definition: Icmp.h:118
int tvSubMsec(struct timeval, struct timeval)
Definition: stub_time.cc:20
const char * xstrerr(int error)
Definition: xstrerror.cc:83
int CheckSum(unsigned short *ptr, int size)
Calculate a packet checksum.
Definition: Icmp.cc:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
#define DBG_IMPORTANT
Definition: Debug.h:45
virtual void SendEcho(Ip::Address &, int, const char *, int)
Definition: Icmp6.cc:119
static void InitAddr(struct addrinfo *&ai)
Definition: Address.cc:676
struct timeval tv
Definition: Icmp.h:43
#define IPPROTO_ICMPV6
Definition: Icmp6.h:38
int icmp_ident
Definition: Icmp.h:119
#define LOCAL_ARRAY(type, name, size)
Definition: leakcheck.h:18
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
bool SIGHDLR int STUB void int
Definition: stub_tools.cc:68
#define MYNAME
Definition: Debug.h:160
#define xmalloc
socklen_t ai_addrlen
struct sockaddr * ai_addr
#define MAX_PKT6_SZ
Definition: Icmp.h:20
static const char * IcmpPacketType(uint8_t v)
Definition: Icmp6.cc:33
void SendResult(pingerReplyData &preply, int len)
Send ICMP results back to squid.
Definition: IcmpPinger.cc:216
#define NULL
Definition: types.h:166
virtual void Close()
Shutdown pinger helper and control channel.
Definition: Icmp.cc:25
int icmp_pkts_sent
Definition: pinger.cc:94
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition: Address.cc:607
char payload[MAX_PAYLOAD]
Definition: Icmp.h:45

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors