Icmp4.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 "Icmp4.h"
19 #include "IcmpPinger.h"
20 #include "leakcheck.h"
21 #include "SquidTime.h"
22 
23 static const char *
24 IcmpPacketType(uint8_t v)
25 {
26  static const char *icmpPktStr[] = {
27  "Echo Reply",
28  "ICMP 1",
29  "ICMP 2",
30  "Destination Unreachable",
31  "Source Quench",
32  "Redirect",
33  "ICMP 6",
34  "ICMP 7",
35  "Echo",
36  "ICMP 9",
37  "ICMP 10",
38  "Time Exceeded",
39  "Parameter Problem",
40  "Timestamp",
41  "Timestamp Reply",
42  "Info Request",
43  "Info Reply",
44  "Out of Range Type"
45  };
46 
47  if (v > 17) {
48  static char buf[50];
49  snprintf(buf, sizeof(buf), "ICMP %u (invalid)", v);
50  return buf;
51  }
52 
53  return icmpPktStr[v];
54 }
55 
57 {
58  ;
59 }
60 
62 {
63  Close();
64 }
65 
66 int
68 {
69  icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
70 
71  if (icmp_sock < 0) {
72  int xerrno = errno;
73  debugs(50, DBG_CRITICAL, MYNAME << " icmp_sock: " << xstrerr(xerrno));
74  return -1;
75  }
76 
77  icmp_ident = getpid() & 0xffff;
78  debugs(42, DBG_IMPORTANT, "pinger: ICMP socket opened.");
79 
80  return icmp_sock;
81 }
82 
83 void
84 Icmp4::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
85 {
86  int x;
87  LOCAL_ARRAY(char, pkt, MAX_PKT4_SZ);
88 
89  struct icmphdr *icmp = NULL;
90  icmpEchoData *echo;
91  size_t icmp_pktsize = sizeof(struct icmphdr);
92  struct addrinfo *S = NULL;
93 
94  memset(pkt, '\0', MAX_PKT4_SZ);
95 
96  icmp = (struct icmphdr *) (void *) pkt;
97 
98  /*
99  * cevans - beware signed/unsigned issues in untrusted data from
100  * the network!!
101  */
102  if (len < 0) {
103  len = 0;
104  }
105 
106  // Construct ICMP packet header
107  icmp->icmp_type = ICMP_ECHO;
108  icmp->icmp_code = 0;
109  icmp->icmp_cksum = 0;
110  icmp->icmp_id = icmp_ident;
111  icmp->icmp_seq = (unsigned short) icmp_pkts_sent;
112  ++icmp_pkts_sent;
113 
114  // Construct ICMP packet data content
115  echo = (icmpEchoData *) (icmp + 1);
116  echo->opcode = (unsigned char) opcode;
117  memcpy(&echo->tv, &current_time, sizeof(struct timeval));
118 
119  icmp_pktsize += sizeof(struct timeval) + sizeof(char);
120 
121  if (payload) {
122  if (len > MAX_PAYLOAD)
123  len = MAX_PAYLOAD;
124 
125  memcpy(echo->payload, payload, len);
126 
127  icmp_pktsize += len;
128  }
129 
130  icmp->icmp_cksum = CheckSum((unsigned short *) icmp, icmp_pktsize);
131 
132  to.getAddrInfo(S);
133  ((sockaddr_in*)S->ai_addr)->sin_port = 0;
134  assert(icmp_pktsize <= MAX_PKT4_SZ);
135 
136  debugs(42, 5, HERE << "Send ICMP packet to " << to << ".");
137 
138  x = sendto(icmp_sock,
139  (const void *) pkt,
140  icmp_pktsize,
141  0,
142  S->ai_addr,
143  S->ai_addrlen);
144 
145  if (x < 0) {
146  int xerrno = errno;
147  debugs(42, DBG_IMPORTANT, MYNAME << "ERROR: sending to ICMP packet to " << to << ": " << xstrerr(xerrno));
148  }
149 
150  Log(to, ' ', NULL, 0, 0);
152 }
153 
154 void
156 {
157  int n;
158  struct addrinfo *from = NULL;
159  int iphdrlen = sizeof(iphdr);
160  struct iphdr *ip = NULL;
161  struct icmphdr *icmp = NULL;
162  static char *pkt = NULL;
163  struct timeval now;
164  icmpEchoData *echo;
165  static pingerReplyData preply;
166 
167  if (icmp_sock < 0) {
168  debugs(42, DBG_CRITICAL, HERE << "No socket! Recv() should not be called.");
169  return;
170  }
171 
172  if (pkt == NULL)
173  pkt = (char *)xmalloc(MAX_PKT4_SZ);
174 
175  Ip::Address::InitAddr(from);
176  n = recvfrom(icmp_sock,
177  (void *)pkt,
178  MAX_PKT4_SZ,
179  0,
180  from->ai_addr,
181  &from->ai_addrlen);
182 
183  if (n <= 0) {
184  debugs(42, DBG_CRITICAL, HERE << "Error when calling recvfrom() on ICMP socket.");
185  Ip::Address::FreeAddr(from);
186  return;
187  }
188 
189  preply.from = *from;
190 
191 #if GETTIMEOFDAY_NO_TZP
192 
193  gettimeofday(&now);
194 
195 #else
196 
197  gettimeofday(&now, NULL);
198 
199 #endif
200 
201  debugs(42, 8, HERE << n << " bytes from " << preply.from);
202 
203  ip = (struct iphdr *) (void *) pkt;
204 
205 #if HAVE_STRUCT_IPHDR_IP_HL
206 
207  iphdrlen = ip->ip_hl << 2;
208 
209 #else /* HAVE_STRUCT_IPHDR_IP_HL */
210 #if WORDS_BIGENDIAN
211 
212  iphdrlen = (ip->ip_vhl >> 4) << 2;
213 
214 #else
215 
216  iphdrlen = (ip->ip_vhl & 0xF) << 2;
217 
218 #endif
219 #endif /* HAVE_STRUCT_IPHDR_IP_HL */
220 
221  icmp = (struct icmphdr *) (void *) (pkt + iphdrlen);
222 
223  if (icmp->icmp_type != ICMP_ECHOREPLY) {
224  Ip::Address::FreeAddr(from);
225  return;
226  }
227 
228  if (icmp->icmp_id != icmp_ident) {
229  Ip::Address::FreeAddr(from);
230  return;
231  }
232 
233  echo = (icmpEchoData *) (void *) (icmp + 1);
234 
235  preply.opcode = echo->opcode;
236 
237  preply.hops = ipHops(ip->ip_ttl);
238 
239  struct timeval tv;
240  memcpy(&tv, &echo->tv, sizeof(struct timeval));
241  preply.rtt = tvSubMsec(tv, now);
242 
243  preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT4_SZ);
244 
245  if (preply.psize < 0) {
246  debugs(42, DBG_CRITICAL, HERE << "Malformed ICMP packet.");
247  Ip::Address::FreeAddr(from);
248  return;
249  }
250 
251  control.SendResult(preply, (sizeof(pingerReplyData) - MAX_PKT4_SZ + preply.psize) );
252 
253  Log(preply.from, icmp->icmp_type, IcmpPacketType(icmp->icmp_type), preply.rtt, preply.hops);
254  Ip::Address::FreeAddr(from);
255 }
256 
257 #endif /* USE_ICMP */
258 
Definition: Icmp.h:64
#define assert(EX)
Definition: assert.h:17
#define iphdr
Definition: Icmp4.h:28
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:694
int ipHops(int ttl)
Definition: Icmp.cc:67
#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
Icmp4()
Definition: Icmp4.cc:56
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 IPPROTO_ICMP
Definition: Icmp4.h:116
#define MAX_PAYLOAD
Definition: Icmp.h:18
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
int psize
Definition: Icmp.h:38
unsigned char opcode
Definition: Icmp.h:35
static void InitAddr(struct addrinfo *&ai)
Definition: Address.cc:676
struct timeval tv
Definition: Icmp.h:43
virtual int Open()
Start pinger helper and initiate control channel.
Definition: Icmp4.cc:67
int icmp_ident
Definition: Icmp.h:119
#define ICMP_ECHOREPLY
Definition: Icmp4.h:112
#define LOCAL_ARRAY(type, name, size)
Definition: leakcheck.h:18
int hops
Definition: Icmp.h:37
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
static const char * IcmpPacketType(uint8_t v)
Definition: Icmp4.cc:24
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:147
#define MYNAME
Definition: Debug.h:160
#define xmalloc
#define icmphdr
Definition: Icmp4.h:27
socklen_t ai_addrlen
struct sockaddr * ai_addr
#define ICMP_ECHO
Definition: Icmp4.h:108
virtual void SendEcho(Ip::Address &, int, const char *, int)
Definition: Icmp4.cc:84
virtual void Recv(void)
Handle ICMP responses.
Definition: Icmp4.cc:155
Ip::Address from
Definition: Icmp.h:34
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
#define MAX_PKT4_SZ
Definition: Icmp.h:19
virtual ~Icmp4()
Definition: Icmp4.cc:61

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors