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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors