]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icmp/Icmp4.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / icmp / Icmp4.cc
CommitLineData
cc192b50 1/*
5b74111a 2 * Copyright (C) 1996-2018 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
602d9612 17#include "Debug.h"
b826ffb5
AJ
18#include "Icmp4.h"
19#include "IcmpPinger.h"
602d9612
A
20#include "leakcheck.h"
21#include "SquidTime.h"
cc192b50 22
618e3200
AJ
23static const char *
24IcmpPacketType(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}
cc192b50 55
b826ffb5 56Icmp4::Icmp4() : Icmp()
26ac0430
AJ
57{
58 ;
cc192b50 59}
60
b826ffb5 61Icmp4::~Icmp4()
cc192b50 62{
63 Close();
64}
65
66int
b826ffb5 67Icmp4::Open(void)
cc192b50 68{
69 icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
70
71 if (icmp_sock < 0) {
b69e9ffa
AJ
72 int xerrno = errno;
73 debugs(50, DBG_CRITICAL, MYNAME << " icmp_sock: " << xstrerr(xerrno));
cc192b50 74 return -1;
75 }
76
77 icmp_ident = getpid() & 0xffff;
e0236918 78 debugs(42, DBG_IMPORTANT, "pinger: ICMP socket opened.");
cc192b50 79
80 return icmp_sock;
81}
82
83void
b7ac5457 84Icmp4::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
cc192b50 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 */
26ac0430 102 if (len < 0) {
cc192b50 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;
aec55359
FC
111 icmp->icmp_seq = (unsigned short) icmp_pkts_sent;
112 ++icmp_pkts_sent;
cc192b50 113
114 // Construct ICMP packet data content
115 echo = (icmpEchoData *) (icmp + 1);
116 echo->opcode = (unsigned char) opcode;
c3c6695b 117 memcpy(&echo->tv, &current_time, sizeof(struct timeval));
cc192b50 118
119 icmp_pktsize += sizeof(struct timeval) + sizeof(char);
120
26ac0430 121 if (payload) {
cc192b50 122 if (len > MAX_PAYLOAD)
123 len = MAX_PAYLOAD;
124
41d00cd3 125 memcpy(echo->payload, payload, len);
cc192b50 126
127 icmp_pktsize += len;
128 }
129
f45dd259 130 icmp->icmp_cksum = CheckSum((unsigned short *) icmp, icmp_pktsize);
cc192b50 131
4dd643d5 132 to.getAddrInfo(S);
cc192b50 133 ((sockaddr_in*)S->ai_addr)->sin_port = 0;
134 assert(icmp_pktsize <= MAX_PKT4_SZ);
135
30c48b1a 136 debugs(42, 5, HERE << "Send ICMP packet to " << to << ".");
cc192b50 137
138 x = sendto(icmp_sock,
26ac0430
AJ
139 (const void *) pkt,
140 icmp_pktsize,
141 0,
142 S->ai_addr,
143 S->ai_addrlen);
cc192b50 144
26ac0430 145 if (x < 0) {
b69e9ffa
AJ
146 int xerrno = errno;
147 debugs(42, DBG_IMPORTANT, MYNAME << "ERROR: sending to ICMP packet to " << to << ": " << xstrerr(xerrno));
cc192b50 148 }
149
150 Log(to, ' ', NULL, 0, 0);
851614a8 151 Ip::Address::FreeAddr(S);
cc192b50 152}
153
154void
b826ffb5 155Icmp4::Recv(void)
cc192b50 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
26ac0430 167 if (icmp_sock < 0) {
fa84c01d 168 debugs(42, DBG_CRITICAL, HERE << "No socket! Recv() should not be called.");
cc192b50 169 return;
170 }
171
172 if (pkt == NULL)
173 pkt = (char *)xmalloc(MAX_PKT4_SZ);
174
851614a8 175 Ip::Address::InitAddr(from);
cc192b50 176 n = recvfrom(icmp_sock,
177 (void *)pkt,
178 MAX_PKT4_SZ,
179 0,
180 from->ai_addr,
181 &from->ai_addrlen);
182
618e3200
AJ
183 if (n <= 0) {
184 debugs(42, DBG_CRITICAL, HERE << "Error when calling recvfrom() on ICMP socket.");
851614a8 185 Ip::Address::FreeAddr(from);
618e3200
AJ
186 return;
187 }
188
cc192b50 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
f1402d4e 223 if (icmp->icmp_type != ICMP_ECHOREPLY) {
851614a8 224 Ip::Address::FreeAddr(from);
cc192b50 225 return;
f1402d4e 226 }
cc192b50 227
f1402d4e 228 if (icmp->icmp_id != icmp_ident) {
851614a8 229 Ip::Address::FreeAddr(from);
cc192b50 230 return;
f1402d4e 231 }
cc192b50 232
233 echo = (icmpEchoData *) (void *) (icmp + 1);
234
235 preply.opcode = echo->opcode;
236
237 preply.hops = ipHops(ip->ip_ttl);
238
c3c6695b 239 struct timeval tv;
240 memcpy(&tv, &echo->tv, sizeof(struct timeval));
241 preply.rtt = tvSubMsec(tv, now);
cc192b50 242
243 preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT4_SZ);
244
618e3200
AJ
245 if (preply.psize < 0) {
246 debugs(42, DBG_CRITICAL, HERE << "Malformed ICMP packet.");
851614a8 247 Ip::Address::FreeAddr(from);
618e3200
AJ
248 return;
249 }
250
cc192b50 251 control.SendResult(preply, (sizeof(pingerReplyData) - MAX_PKT4_SZ + preply.psize) );
252
618e3200 253 Log(preply.from, icmp->icmp_type, IcmpPacketType(icmp->icmp_type), preply.rtt, preply.hops);
851614a8 254 Ip::Address::FreeAddr(from);
cc192b50 255}
256
257#endif /* USE_ICMP */
f53969cc 258