]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icmp/Icmp4.cc
SourceLayout: Move time related tools to time/libtime.la (#1001)
[thirdparty/squid.git] / src / icmp / Icmp4.cc
CommitLineData
cc192b50 1/*
bf95c10a 2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
cc192b50 3 *
bbc27441
AJ
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.
cc192b50 7 */
bbc27441
AJ
8
9/* DEBUG: section 42 ICMP Pinger program */
10
cc192b50 11//#define SQUID_HELPER 1
12
582c2af2 13#include "squid.h"
cc192b50 14
15#if USE_ICMP
16
675b8408 17#include "debug/Stream.h"
b826ffb5
AJ
18#include "Icmp4.h"
19#include "IcmpPinger.h"
98cacedb 20#include "time/gadgets.h"
cc192b50 21
618e3200
AJ
22static const char *
23IcmpPacketType(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}
cc192b50 54
b826ffb5 55Icmp4::Icmp4() : Icmp()
26ac0430
AJ
56{
57 ;
cc192b50 58}
59
b826ffb5 60Icmp4::~Icmp4()
cc192b50 61{
62 Close();
63}
64
65int
b826ffb5 66Icmp4::Open(void)
cc192b50 67{
68 icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
69
70 if (icmp_sock < 0) {
b69e9ffa
AJ
71 int xerrno = errno;
72 debugs(50, DBG_CRITICAL, MYNAME << " icmp_sock: " << xstrerr(xerrno));
cc192b50 73 return -1;
74 }
75
76 icmp_ident = getpid() & 0xffff;
879c39f7 77 debugs(42, DBG_IMPORTANT, "ICMP socket opened.");
cc192b50 78
79 return icmp_sock;
80}
81
82void
b7ac5457 83Icmp4::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
cc192b50 84{
85 int x;
86 LOCAL_ARRAY(char, pkt, MAX_PKT4_SZ);
87
88 struct icmphdr *icmp = NULL;
89 icmpEchoData *echo;
90 size_t icmp_pktsize = sizeof(struct icmphdr);
91 struct addrinfo *S = NULL;
92
2b9a2bba
SDJ
93 static_assert(sizeof(*icmp) + sizeof(*echo) <= sizeof(pkt), "our custom ICMPv4 Echo payload fits the packet buffer");
94
cc192b50 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 */
26ac0430 103 if (len < 0) {
cc192b50 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;
aec55359
FC
112 icmp->icmp_seq = (unsigned short) icmp_pkts_sent;
113 ++icmp_pkts_sent;
cc192b50 114
115 // Construct ICMP packet data content
2b9a2bba 116 echo = reinterpret_cast<icmpEchoData *>(reinterpret_cast<char *>(pkt) + sizeof(*icmp));
cc192b50 117 echo->opcode = (unsigned char) opcode;
c3c6695b 118 memcpy(&echo->tv, &current_time, sizeof(struct timeval));
cc192b50 119
120 icmp_pktsize += sizeof(struct timeval) + sizeof(char);
121
26ac0430 122 if (payload) {
cc192b50 123 if (len > MAX_PAYLOAD)
124 len = MAX_PAYLOAD;
125
41d00cd3 126 memcpy(echo->payload, payload, len);
cc192b50 127
128 icmp_pktsize += len;
129 }
130
f45dd259 131 icmp->icmp_cksum = CheckSum((unsigned short *) icmp, icmp_pktsize);
cc192b50 132
4dd643d5 133 to.getAddrInfo(S);
cc192b50 134 ((sockaddr_in*)S->ai_addr)->sin_port = 0;
135 assert(icmp_pktsize <= MAX_PKT4_SZ);
136
bf95c10a 137 debugs(42, 5, "Send ICMP packet to " << to << ".");
cc192b50 138
139 x = sendto(icmp_sock,
26ac0430
AJ
140 (const void *) pkt,
141 icmp_pktsize,
142 0,
143 S->ai_addr,
144 S->ai_addrlen);
cc192b50 145
26ac0430 146 if (x < 0) {
b69e9ffa
AJ
147 int xerrno = errno;
148 debugs(42, DBG_IMPORTANT, MYNAME << "ERROR: sending to ICMP packet to " << to << ": " << xstrerr(xerrno));
cc192b50 149 }
150
151 Log(to, ' ', NULL, 0, 0);
851614a8 152 Ip::Address::FreeAddr(S);
cc192b50 153}
154
155void
b826ffb5 156Icmp4::Recv(void)
cc192b50 157{
158 int n;
159 struct addrinfo *from = NULL;
160 int iphdrlen = sizeof(iphdr);
161 struct iphdr *ip = NULL;
162 struct icmphdr *icmp = NULL;
163 static char *pkt = NULL;
164 struct timeval now;
165 icmpEchoData *echo;
166 static pingerReplyData preply;
167
26ac0430 168 if (icmp_sock < 0) {
bf95c10a 169 debugs(42, DBG_CRITICAL, "No socket! Recv() should not be called.");
cc192b50 170 return;
171 }
172
173 if (pkt == NULL)
174 pkt = (char *)xmalloc(MAX_PKT4_SZ);
175
851614a8 176 Ip::Address::InitAddr(from);
cc192b50 177 n = recvfrom(icmp_sock,
178 (void *)pkt,
179 MAX_PKT4_SZ,
180 0,
181 from->ai_addr,
182 &from->ai_addrlen);
183
618e3200 184 if (n <= 0) {
d816f28d 185 debugs(42, DBG_CRITICAL, "ERROR: when calling recvfrom() on ICMP socket.");
851614a8 186 Ip::Address::FreeAddr(from);
618e3200
AJ
187 return;
188 }
189
cc192b50 190 preply.from = *from;
191
192#if GETTIMEOFDAY_NO_TZP
193
194 gettimeofday(&now);
195
196#else
197
198 gettimeofday(&now, NULL);
199
200#endif
201
bf95c10a 202 debugs(42, 8, n << " bytes from " << preply.from);
cc192b50 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
f1402d4e 224 if (icmp->icmp_type != ICMP_ECHOREPLY) {
851614a8 225 Ip::Address::FreeAddr(from);
cc192b50 226 return;
f1402d4e 227 }
cc192b50 228
f1402d4e 229 if (icmp->icmp_id != icmp_ident) {
851614a8 230 Ip::Address::FreeAddr(from);
cc192b50 231 return;
f1402d4e 232 }
cc192b50 233
234 echo = (icmpEchoData *) (void *) (icmp + 1);
235
236 preply.opcode = echo->opcode;
237
238 preply.hops = ipHops(ip->ip_ttl);
239
c3c6695b 240 struct timeval tv;
241 memcpy(&tv, &echo->tv, sizeof(struct timeval));
242 preply.rtt = tvSubMsec(tv, now);
cc192b50 243
244 preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT4_SZ);
245
618e3200 246 if (preply.psize < 0) {
d816f28d 247 debugs(42, DBG_CRITICAL, "ERROR: Malformed ICMP packet.");
851614a8 248 Ip::Address::FreeAddr(from);
618e3200
AJ
249 return;
250 }
251
cc192b50 252 control.SendResult(preply, (sizeof(pingerReplyData) - MAX_PKT4_SZ + preply.psize) );
253
618e3200 254 Log(preply.from, icmp->icmp_type, IcmpPacketType(icmp->icmp_type), preply.rtt, preply.hops);
851614a8 255 Ip::Address::FreeAddr(from);
cc192b50 256}
257
258#endif /* USE_ICMP */
f53969cc 259