]>
Commit | Line | Data |
---|---|---|
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 |
23 | static const char * |
24 | IcmpPacketType(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 | 56 | Icmp4::Icmp4() : Icmp() |
26ac0430 AJ |
57 | { |
58 | ; | |
cc192b50 | 59 | } |
60 | ||
b826ffb5 | 61 | Icmp4::~Icmp4() |
cc192b50 | 62 | { |
63 | Close(); | |
64 | } | |
65 | ||
66 | int | |
b826ffb5 | 67 | Icmp4::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 | ||
83 | void | |
b7ac5457 | 84 | Icmp4::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, ¤t_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 | ||
154 | void | |
b826ffb5 | 155 | Icmp4::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 |