]>
Commit | Line | Data |
---|---|---|
cc192b50 | 1 | /* |
bbc27441 | 2 | * Copyright (C) 1996-2014 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 | |
26ac0430 AJ |
23 | const char *icmpPktStr[] = { |
24 | "Echo Reply", | |
25 | "ICMP 1", | |
26 | "ICMP 2", | |
27 | "Destination Unreachable", | |
28 | "Source Quench", | |
29 | "Redirect", | |
30 | "ICMP 6", | |
31 | "ICMP 7", | |
32 | "Echo", | |
33 | "ICMP 9", | |
34 | "ICMP 10", | |
35 | "Time Exceeded", | |
36 | "Parameter Problem", | |
37 | "Timestamp", | |
38 | "Timestamp Reply", | |
39 | "Info Request", | |
40 | "Info Reply", | |
41 | "Out of Range Type" | |
42 | }; | |
cc192b50 | 43 | |
b826ffb5 | 44 | Icmp4::Icmp4() : Icmp() |
26ac0430 AJ |
45 | { |
46 | ; | |
cc192b50 | 47 | } |
48 | ||
b826ffb5 | 49 | Icmp4::~Icmp4() |
cc192b50 | 50 | { |
51 | Close(); | |
52 | } | |
53 | ||
54 | int | |
b826ffb5 | 55 | Icmp4::Open(void) |
cc192b50 | 56 | { |
57 | icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); | |
58 | ||
59 | if (icmp_sock < 0) { | |
fa84c01d | 60 | debugs(50, DBG_CRITICAL, HERE << " icmp_sock: " << xstrerror()); |
cc192b50 | 61 | return -1; |
62 | } | |
63 | ||
64 | icmp_ident = getpid() & 0xffff; | |
e0236918 | 65 | debugs(42, DBG_IMPORTANT, "pinger: ICMP socket opened."); |
cc192b50 | 66 | |
67 | return icmp_sock; | |
68 | } | |
69 | ||
70 | void | |
b7ac5457 | 71 | Icmp4::SendEcho(Ip::Address &to, int opcode, const char *payload, int len) |
cc192b50 | 72 | { |
73 | int x; | |
74 | LOCAL_ARRAY(char, pkt, MAX_PKT4_SZ); | |
75 | ||
76 | struct icmphdr *icmp = NULL; | |
77 | icmpEchoData *echo; | |
78 | size_t icmp_pktsize = sizeof(struct icmphdr); | |
79 | struct addrinfo *S = NULL; | |
80 | ||
81 | memset(pkt, '\0', MAX_PKT4_SZ); | |
82 | ||
83 | icmp = (struct icmphdr *) (void *) pkt; | |
84 | ||
85 | /* | |
86 | * cevans - beware signed/unsigned issues in untrusted data from | |
87 | * the network!! | |
88 | */ | |
26ac0430 | 89 | if (len < 0) { |
cc192b50 | 90 | len = 0; |
91 | } | |
92 | ||
93 | // Construct ICMP packet header | |
94 | icmp->icmp_type = ICMP_ECHO; | |
95 | icmp->icmp_code = 0; | |
96 | icmp->icmp_cksum = 0; | |
97 | icmp->icmp_id = icmp_ident; | |
aec55359 FC |
98 | icmp->icmp_seq = (unsigned short) icmp_pkts_sent; |
99 | ++icmp_pkts_sent; | |
cc192b50 | 100 | |
101 | // Construct ICMP packet data content | |
102 | echo = (icmpEchoData *) (icmp + 1); | |
103 | echo->opcode = (unsigned char) opcode; | |
c3c6695b | 104 | memcpy(&echo->tv, ¤t_time, sizeof(struct timeval)); |
cc192b50 | 105 | |
106 | icmp_pktsize += sizeof(struct timeval) + sizeof(char); | |
107 | ||
26ac0430 | 108 | if (payload) { |
cc192b50 | 109 | if (len > MAX_PAYLOAD) |
110 | len = MAX_PAYLOAD; | |
111 | ||
41d00cd3 | 112 | memcpy(echo->payload, payload, len); |
cc192b50 | 113 | |
114 | icmp_pktsize += len; | |
115 | } | |
116 | ||
f45dd259 | 117 | icmp->icmp_cksum = CheckSum((unsigned short *) icmp, icmp_pktsize); |
cc192b50 | 118 | |
4dd643d5 | 119 | to.getAddrInfo(S); |
cc192b50 | 120 | ((sockaddr_in*)S->ai_addr)->sin_port = 0; |
121 | assert(icmp_pktsize <= MAX_PKT4_SZ); | |
122 | ||
30c48b1a | 123 | debugs(42, 5, HERE << "Send ICMP packet to " << to << "."); |
cc192b50 | 124 | |
125 | x = sendto(icmp_sock, | |
26ac0430 AJ |
126 | (const void *) pkt, |
127 | icmp_pktsize, | |
128 | 0, | |
129 | S->ai_addr, | |
130 | S->ai_addrlen); | |
cc192b50 | 131 | |
26ac0430 | 132 | if (x < 0) { |
e0236918 | 133 | debugs(42, DBG_IMPORTANT, HERE << "Error sending to ICMP packet to " << to << ". ERR: " << xstrerror()); |
cc192b50 | 134 | } |
135 | ||
136 | Log(to, ' ', NULL, 0, 0); | |
4dd643d5 | 137 | Ip::Address::FreeAddrInfo(S); |
cc192b50 | 138 | } |
139 | ||
140 | void | |
b826ffb5 | 141 | Icmp4::Recv(void) |
cc192b50 | 142 | { |
143 | int n; | |
144 | struct addrinfo *from = NULL; | |
145 | int iphdrlen = sizeof(iphdr); | |
146 | struct iphdr *ip = NULL; | |
147 | struct icmphdr *icmp = NULL; | |
148 | static char *pkt = NULL; | |
149 | struct timeval now; | |
150 | icmpEchoData *echo; | |
151 | static pingerReplyData preply; | |
152 | ||
26ac0430 | 153 | if (icmp_sock < 0) { |
fa84c01d | 154 | debugs(42, DBG_CRITICAL, HERE << "No socket! Recv() should not be called."); |
cc192b50 | 155 | return; |
156 | } | |
157 | ||
158 | if (pkt == NULL) | |
159 | pkt = (char *)xmalloc(MAX_PKT4_SZ); | |
160 | ||
4dd643d5 | 161 | Ip::Address::InitAddrInfo(from); |
cc192b50 | 162 | n = recvfrom(icmp_sock, |
163 | (void *)pkt, | |
164 | MAX_PKT4_SZ, | |
165 | 0, | |
166 | from->ai_addr, | |
167 | &from->ai_addrlen); | |
168 | ||
169 | preply.from = *from; | |
170 | ||
171 | #if GETTIMEOFDAY_NO_TZP | |
172 | ||
173 | gettimeofday(&now); | |
174 | ||
175 | #else | |
176 | ||
177 | gettimeofday(&now, NULL); | |
178 | ||
179 | #endif | |
180 | ||
181 | debugs(42, 8, HERE << n << " bytes from " << preply.from); | |
182 | ||
183 | ip = (struct iphdr *) (void *) pkt; | |
184 | ||
185 | #if HAVE_STRUCT_IPHDR_IP_HL | |
186 | ||
187 | iphdrlen = ip->ip_hl << 2; | |
188 | ||
189 | #else /* HAVE_STRUCT_IPHDR_IP_HL */ | |
190 | #if WORDS_BIGENDIAN | |
191 | ||
192 | iphdrlen = (ip->ip_vhl >> 4) << 2; | |
193 | ||
194 | #else | |
195 | ||
196 | iphdrlen = (ip->ip_vhl & 0xF) << 2; | |
197 | ||
198 | #endif | |
199 | #endif /* HAVE_STRUCT_IPHDR_IP_HL */ | |
200 | ||
201 | icmp = (struct icmphdr *) (void *) (pkt + iphdrlen); | |
202 | ||
f1402d4e | 203 | if (icmp->icmp_type != ICMP_ECHOREPLY) { |
4dd643d5 | 204 | Ip::Address::FreeAddrInfo(from); |
cc192b50 | 205 | return; |
f1402d4e | 206 | } |
cc192b50 | 207 | |
f1402d4e | 208 | if (icmp->icmp_id != icmp_ident) { |
4dd643d5 | 209 | Ip::Address::FreeAddrInfo(from); |
cc192b50 | 210 | return; |
f1402d4e | 211 | } |
cc192b50 | 212 | |
213 | echo = (icmpEchoData *) (void *) (icmp + 1); | |
214 | ||
215 | preply.opcode = echo->opcode; | |
216 | ||
217 | preply.hops = ipHops(ip->ip_ttl); | |
218 | ||
c3c6695b | 219 | struct timeval tv; |
220 | memcpy(&tv, &echo->tv, sizeof(struct timeval)); | |
221 | preply.rtt = tvSubMsec(tv, now); | |
cc192b50 | 222 | |
223 | preply.psize = n - iphdrlen - (sizeof(icmpEchoData) - MAX_PKT4_SZ); | |
224 | ||
225 | control.SendResult(preply, (sizeof(pingerReplyData) - MAX_PKT4_SZ + preply.psize) ); | |
226 | ||
227 | Log(preply.from, icmp->icmp_type, icmpPktStr[icmp->icmp_type], preply.rtt, preply.hops); | |
4dd643d5 | 228 | Ip::Address::FreeAddrInfo(from); |
cc192b50 | 229 | } |
230 | ||
231 | #endif /* USE_ICMP */ |