]> git.ipfire.org Git - thirdparty/squid.git/blob - src/icmp/Icmp4.cc
Merged from trunk r12948.
[thirdparty/squid.git] / src / icmp / Icmp4.cc
1 /*
2 * DEBUG: section 42 ICMP Pinger program
3 * AUTHOR: Duane Wessels, Amos Jeffries
4 *
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
7 *
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
30 *
31 */
32 //#define SQUID_HELPER 1
33
34 #include "squid.h"
35
36 #if USE_ICMP
37
38 #include "leakcheck.h"
39 #include "SquidTime.h"
40 #include "Icmp4.h"
41 #include "IcmpPinger.h"
42 #include "Debug.h"
43
44 const char *icmpPktStr[] = {
45 "Echo Reply",
46 "ICMP 1",
47 "ICMP 2",
48 "Destination Unreachable",
49 "Source Quench",
50 "Redirect",
51 "ICMP 6",
52 "ICMP 7",
53 "Echo",
54 "ICMP 9",
55 "ICMP 10",
56 "Time Exceeded",
57 "Parameter Problem",
58 "Timestamp",
59 "Timestamp Reply",
60 "Info Request",
61 "Info Reply",
62 "Out of Range Type"
63 };
64
65 Icmp4::Icmp4() : Icmp()
66 {
67 ;
68 }
69
70 Icmp4::~Icmp4()
71 {
72 Close();
73 }
74
75 int
76 Icmp4::Open(void)
77 {
78 icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
79
80 if (icmp_sock < 0) {
81 debugs(50, DBG_CRITICAL, HERE << " icmp_sock: " << xstrerror());
82 return -1;
83 }
84
85 icmp_ident = getpid() & 0xffff;
86 debugs(42, DBG_IMPORTANT, "pinger: ICMP socket opened.");
87
88 return icmp_sock;
89 }
90
91 void
92 Icmp4::SendEcho(Ip::Address &to, int opcode, const char *payload, int len)
93 {
94 int x;
95 LOCAL_ARRAY(char, pkt, MAX_PKT4_SZ);
96
97 struct icmphdr *icmp = NULL;
98 icmpEchoData *echo;
99 size_t icmp_pktsize = sizeof(struct icmphdr);
100 struct addrinfo *S = NULL;
101
102 memset(pkt, '\0', MAX_PKT4_SZ);
103
104 icmp = (struct icmphdr *) (void *) pkt;
105
106 /*
107 * cevans - beware signed/unsigned issues in untrusted data from
108 * the network!!
109 */
110 if (len < 0) {
111 len = 0;
112 }
113
114 // Construct ICMP packet header
115 icmp->icmp_type = ICMP_ECHO;
116 icmp->icmp_code = 0;
117 icmp->icmp_cksum = 0;
118 icmp->icmp_id = icmp_ident;
119 icmp->icmp_seq = (unsigned short) icmp_pkts_sent;
120 ++icmp_pkts_sent;
121
122 // Construct ICMP packet data content
123 echo = (icmpEchoData *) (icmp + 1);
124 echo->opcode = (unsigned char) opcode;
125 memcpy(&echo->tv, &current_time, sizeof(struct timeval));
126
127 icmp_pktsize += sizeof(struct timeval) + sizeof(char);
128
129 if (payload) {
130 if (len > MAX_PAYLOAD)
131 len = MAX_PAYLOAD;
132
133 memcpy(echo->payload, payload, len);
134
135 icmp_pktsize += len;
136 }
137
138 icmp->icmp_cksum = CheckSum((unsigned short *) icmp, icmp_pktsize);
139
140 to.getAddrInfo(S);
141 ((sockaddr_in*)S->ai_addr)->sin_port = 0;
142 assert(icmp_pktsize <= MAX_PKT4_SZ);
143
144 debugs(42, 5, HERE << "Send ICMP packet to " << to << ".");
145
146 x = sendto(icmp_sock,
147 (const void *) pkt,
148 icmp_pktsize,
149 0,
150 S->ai_addr,
151 S->ai_addrlen);
152
153 if (x < 0) {
154 debugs(42, DBG_IMPORTANT, HERE << "Error sending to ICMP packet to " << to << ". ERR: " << xstrerror());
155 }
156
157 Log(to, ' ', NULL, 0, 0);
158 Ip::Address::FreeAddrInfo(S);
159 }
160
161 void
162 Icmp4::Recv(void)
163 {
164 int n;
165 struct addrinfo *from = NULL;
166 int iphdrlen = sizeof(iphdr);
167 struct iphdr *ip = NULL;
168 struct icmphdr *icmp = NULL;
169 static char *pkt = NULL;
170 struct timeval now;
171 icmpEchoData *echo;
172 static pingerReplyData preply;
173
174 if (icmp_sock < 0) {
175 debugs(42, DBG_CRITICAL, HERE << "No socket! Recv() should not be called.");
176 return;
177 }
178
179 if (pkt == NULL)
180 pkt = (char *)xmalloc(MAX_PKT4_SZ);
181
182 Ip::Address::InitAddrInfo(from);
183 n = recvfrom(icmp_sock,
184 (void *)pkt,
185 MAX_PKT4_SZ,
186 0,
187 from->ai_addr,
188 &from->ai_addrlen);
189
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
202 debugs(42, 8, HERE << 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::FreeAddrInfo(from);
226 return;
227 }
228
229 if (icmp->icmp_id != icmp_ident) {
230 Ip::Address::FreeAddrInfo(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 control.SendResult(preply, (sizeof(pingerReplyData) - MAX_PKT4_SZ + preply.psize) );
247
248 Log(preply.from, icmp->icmp_type, icmpPktStr[icmp->icmp_type], preply.rtt, preply.hops);
249 Ip::Address::FreeAddrInfo(from);
250 }
251
252 #endif /* USE_ICMP */