Icmp4.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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
22static const char *
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
65int
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
82void
83Icmp4::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;
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
155void
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
177 n = recvfrom(icmp_sock,
178 (void *)pkt,
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.");
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) {
226 return;
227 }
228
229 if (icmp->icmp_id != icmp_ident) {
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.");
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);
256}
257
258#endif /* USE_ICMP */
259
static const char * IcmpPacketType(uint8_t v)
Definition: Icmp4.cc:23
#define ICMP_ECHOREPLY
Definition: Icmp4.h:105
#define IPPROTO_ICMP
Definition: Icmp4.h:109
#define iphdr
Definition: Icmp4.h:28
#define ICMP_ECHO
Definition: Icmp4.h:101
#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:17
static time_t now
Definition: cachemgr.cc:109
Icmp4()
Definition: Icmp4.cc:55
void SendEcho(Ip::Address &, int, const char *, int) override
Definition: Icmp4.cc:83
void Recv(void) override
Handle ICMP responses.
Definition: Icmp4.cc:156
~Icmp4() override
Definition: Icmp4.cc:60
int Open() override
Start pinger helper and initiate control channel.
Definition: Icmp4.cc:66
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:236
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
#define xmalloc
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:68
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
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