]> git.ipfire.org Git - thirdparty/squid.git/blame - src/icp_v2.cc
remove ICP_AUTH_SIZE
[thirdparty/squid.git] / src / icp_v2.cc
CommitLineData
7a2f978b 1#include "squid.h"
2
3static void icpLogIcp(icpUdpData *);
4static void icpHandleIcpV2(int, struct sockaddr_in, char *, int);
5
6static void
7icpLogIcp(icpUdpData * queue)
8{
9 icp_common_t *header = (icp_common_t *) (void *) queue->msg;
10 char *url = (char *) header + sizeof(icp_common_t);
11 AccessLogEntry al;
7a2f978b 12 clientdbUpdate(queue->address.sin_addr, queue->logcode, PROTO_ICP);
13 if (!Config.onoff.log_udp)
14 return;
15 memset(&al, '\0', sizeof(AccessLogEntry));
27cd7235 16 al.icp.opcode = ICP_QUERY;
7a2f978b 17 al.url = url;
18 al.cache.caddr = queue->address.sin_addr;
19 al.cache.size = queue->len;
20 al.cache.code = queue->logcode;
21 al.cache.msec = tvSubMsec(queue->start, current_time);
22 accessLogLog(&al);
23}
24
25void
26icpUdpReply(int fd, void *data)
27{
28 icpUdpData *queue = data;
29 int x;
30 /* Disable handler, in case of errors. */
31 commSetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
79d39a72 32 while ((queue = UdpQueueHead) != NULL) {
7a2f978b 33 debug(12, 5) ("icpUdpReply: FD %d sending %d bytes to %s port %d\n",
34 fd,
35 queue->len,
36 inet_ntoa(queue->address.sin_addr),
37 ntohs(queue->address.sin_port));
f2908497 38 Counter.icp.pkts_sent++;
a7c05555 39 if (queue->logcode == LOG_UDP_HIT)
40 Counter.icp.hits_sent++;
7a2f978b 41 x = comm_udp_sendto(fd,
42 &queue->address,
43 sizeof(struct sockaddr_in),
44 queue->msg,
45 queue->len);
46 if (x < 0) {
b224ea98 47 if (ignoreErrno(errno))
7a2f978b 48 break; /* don't de-queue */
f2908497 49 } else {
a7c05555 50 kb_incr(&Counter.icp.kbytes_sent, (size_t) x);
7a2f978b 51 }
52 UdpQueueHead = queue->next;
53 if (queue->logcode)
54 icpLogIcp(queue);
55 safe_free(queue->msg);
56 safe_free(queue);
57 }
58 /* Reinstate handler if needed */
59 if (UdpQueueHead) {
60 commSetSelect(fd, COMM_SELECT_WRITE, icpUdpReply, UdpQueueHead, 0);
61 }
62}
63
64void *
65icpCreateMessage(
66 icp_opcode opcode,
67 int flags,
68 const char *url,
69 int reqnum,
70 int pad)
71{
72 char *buf = NULL;
73 icp_common_t *headerp = NULL;
74 char *urloffset = NULL;
75 int buf_len;
76 buf_len = sizeof(icp_common_t) + strlen(url) + 1;
27cd7235 77 if (opcode == ICP_QUERY)
7a2f978b 78 buf_len += sizeof(u_num32);
79 buf = xcalloc(buf_len, 1);
80 headerp = (icp_common_t *) (void *) buf;
79d39a72 81 headerp->opcode = (char) opcode;
7a2f978b 82 headerp->version = ICP_VERSION_CURRENT;
79d39a72 83 headerp->length = (u_short) htons(buf_len);
7a2f978b 84 headerp->reqnum = htonl(reqnum);
85 headerp->flags = htonl(flags);
86 headerp->pad = htonl(pad);
87 headerp->shostid = htonl(theOutICPAddr.s_addr);
88 urloffset = buf + sizeof(icp_common_t);
27cd7235 89 if (opcode == ICP_QUERY)
7a2f978b 90 urloffset += sizeof(u_num32);
91 xmemcpy(urloffset, url, strlen(url));
92 return buf;
93}
94
7a2f978b 95void
96icpUdpSend(int fd,
97 const struct sockaddr_in *to,
98 icp_common_t * msg,
99 log_type logcode,
100 protocol_t proto)
101{
102 icpUdpData *data = xcalloc(1, sizeof(icpUdpData));
103 debug(12, 4) ("icpUdpSend: Queueing %s for %s\n",
27cd7235 104 icp_opcode_str[msg->opcode],
7a2f978b 105 inet_ntoa(to->sin_addr));
106 data->address = *to;
107 data->msg = msg;
108 data->len = (int) ntohs(msg->length);
a7c05555 109 data->start = current_time;
7a2f978b 110 data->logcode = logcode;
111 data->proto = proto;
112 AppendUdp(data);
113 commSetSelect(fd, COMM_SELECT_WRITE, icpUdpReply, UdpQueueHead, 0);
114}
115
116int
117icpCheckUdpHit(StoreEntry * e, request_t * request)
118{
119 if (e == NULL)
120 return 0;
121 if (!storeEntryValidToSend(e))
122 return 0;
123 if (Config.onoff.icp_hit_stale)
124 return 1;
125 if (refreshCheck(e, request, 30))
126 return 0;
7a2f978b 127 return 1;
128}
7a2f978b 129
130static void
131icpHandleIcpV2(int fd, struct sockaddr_in from, char *buf, int len)
132{
133 icp_common_t header;
134 icp_common_t *headerp = (icp_common_t *) (void *) buf;
135 StoreEntry *entry = NULL;
136 char *url = NULL;
137 const cache_key *key;
138 request_t *icp_request = NULL;
139 int allow = 0;
7a2f978b 140 aclCheck_t checklist;
141 icp_common_t *reply;
142 int src_rtt = 0;
143 u_num32 flags = 0;
144 header.opcode = headerp->opcode;
145 header.version = headerp->version;
146 header.length = ntohs(headerp->length);
147 header.reqnum = ntohl(headerp->reqnum);
148 header.flags = ntohl(headerp->flags);
149 header.shostid = ntohl(headerp->shostid);
150 header.pad = ntohl(headerp->pad);
151
152 switch (header.opcode) {
27cd7235 153 case ICP_QUERY:
7a2f978b 154 /* We have a valid packet */
155 url = buf + sizeof(header) + sizeof(u_num32);
156 if ((icp_request = urlParse(METHOD_GET, url)) == NULL) {
27cd7235 157 reply = icpCreateMessage(ICP_ERR, 0, url, header.reqnum, 0);
7a2f978b 158 icpUdpSend(fd, &from, reply, LOG_UDP_INVALID, PROTO_NONE);
159 break;
160 }
161 checklist.src_addr = from.sin_addr;
162 checklist.request = icp_request;
163 allow = aclCheckFast(Config.accessList.icp, &checklist);
164 if (!allow) {
165 debug(12, 2) ("icpHandleIcpV2: Access Denied for %s by %s.\n",
166 inet_ntoa(from.sin_addr), AclMatchedName);
167 if (clientdbDeniedPercent(from.sin_addr) < 95) {
27cd7235 168 reply = icpCreateMessage(ICP_DENIED, 0, url, header.reqnum, 0);
7a2f978b 169 icpUdpSend(fd, &from, reply, LOG_UDP_DENIED, icp_request->protocol);
1a47dc5a 170 } else {
171 /*
172 * count this DENIED query in the clientdb, even though
173 * we're not sending an ICP reply...
174 */
175 clientdbUpdate(from.sin_addr,
176 LOG_UDP_DENIED,
177 Config.Port.icp);
7a2f978b 178 }
179 break;
180 }
181 if (header.flags & ICP_FLAG_SRC_RTT) {
182 int rtt = netdbHostRtt(icp_request->host);
183 int hops = netdbHostHops(icp_request->host);
184 src_rtt = ((hops & 0xFFFF) << 16) | (rtt & 0xFFFF);
185 if (rtt)
186 flags |= ICP_FLAG_SRC_RTT;
187 }
188 /* The peer is allowed to use this cache */
189 key = storeKeyPublic(url, METHOD_GET);
190 entry = storeGet(key);
27cd7235 191 debug(12, 5) ("icpHandleIcpV2: OPCODE %s\n", icp_opcode_str[header.opcode]);
7a2f978b 192 if (icpCheckUdpHit(entry, icp_request)) {
067bea91 193 reply = icpCreateMessage(ICP_HIT, flags, url, header.reqnum, src_rtt);
194 icpUdpSend(fd, &from, reply, LOG_UDP_HIT, icp_request->protocol);
195 break;
7a2f978b 196 }
197 /* if store is rebuilding, return a UDP_HIT, but not a MISS */
198 if (store_rebuilding && opt_reload_hit_only) {
27cd7235 199 reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
7a2f978b 200 icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, icp_request->protocol);
201 } else if (hit_only_mode_until > squid_curtime) {
27cd7235 202 reply = icpCreateMessage(ICP_MISS_NOFETCH, flags, url, header.reqnum, src_rtt);
7a2f978b 203 icpUdpSend(fd, &from, reply, LOG_UDP_MISS_NOFETCH, icp_request->protocol);
204 } else {
27cd7235 205 reply = icpCreateMessage(ICP_MISS, flags, url, header.reqnum, src_rtt);
7a2f978b 206 icpUdpSend(fd, &from, reply, LOG_UDP_MISS, icp_request->protocol);
207 }
208 break;
209
27cd7235 210 case ICP_HIT:
a7c05555 211 Counter.icp.hits_recv++;
27cd7235 212 case ICP_SECHO:
213 case ICP_DECHO:
214 case ICP_MISS:
215 case ICP_DENIED:
216 case ICP_MISS_NOFETCH:
7a2f978b 217 if (neighbors_do_private_keys && header.reqnum == 0) {
218 debug(12, 0) ("icpHandleIcpV2: Neighbor %s returned reqnum = 0\n",
219 inet_ntoa(from.sin_addr));
220 debug(12, 0) ("icpHandleIcpV2: Disabling use of private keys\n");
221 neighbors_do_private_keys = 0;
222 }
223 url = buf + sizeof(header);
7a2f978b 224 debug(12, 3) ("icpHandleIcpV2: %s from %s for '%s'\n",
27cd7235 225 icp_opcode_str[header.opcode],
7a2f978b 226 inet_ntoa(from.sin_addr),
227 url);
228 if (neighbors_do_private_keys && header.reqnum)
229 key = storeKeyPrivate(url, METHOD_GET, header.reqnum);
230 else
231 key = storeKeyPublic(url, METHOD_GET);
232 debug(12, 3) ("icpHandleIcpV2: Looking for key '%s'\n",
233 storeKeyText(key));
234 if ((entry = storeGet(key)) == NULL) {
235 debug(12, 3) ("icpHandleIcpV2: Ignoring %s for NULL Entry.\n",
27cd7235 236 icp_opcode_str[header.opcode]);
7a2f978b 237 } else {
238 /* call neighborsUdpAck even if ping_status != PING_WAITING */
79d39a72 239 neighborsUdpAck(url, &header, &from, entry);
7a2f978b 240 }
241 break;
242
27cd7235 243 case ICP_INVALID:
244 case ICP_ERR:
7a2f978b 245 break;
246
247 default:
248 debug(12, 0) ("icpHandleIcpV2: UNKNOWN OPCODE: %d from %s\n",
249 header.opcode, inet_ntoa(from.sin_addr));
250 break;
251 }
252 if (icp_request)
3f6c0fb2 253 memFree(MEM_REQUEST_T, icp_request);
7a2f978b 254}
255
256#ifdef ICP_PKT_DUMP
257static void
258icpPktDump(icp_common_t * pkt)
259{
260 struct in_addr a;
261
262 debug(12, 9) ("opcode: %3d %s\n",
263 (int) pkt->opcode,
27cd7235 264 icp_opcode_str[pkt->opcode]);
7a2f978b 265 debug(12, 9) ("version: %-8d\n", (int) pkt->version);
266 debug(12, 9) ("length: %-8d\n", (int) ntohs(pkt->length));
267 debug(12, 9) ("reqnum: %-8d\n", ntohl(pkt->reqnum));
268 debug(12, 9) ("flags: %-8x\n", ntohl(pkt->flags));
269 a.s_addr = ntohl(pkt->shostid);
270 debug(12, 9) ("shostid: %s\n", inet_ntoa(a));
271 debug(12, 9) ("payload: %s\n", (char *) pkt + sizeof(icp_common_t));
272}
273#endif
274
275void
79d39a72 276icpHandleUdp(int sock, void *datanotused)
7a2f978b 277{
278 struct sockaddr_in from;
279 int from_len;
280 LOCAL_ARRAY(char, buf, SQUID_UDP_SO_RCVBUF);
281 int len;
282 icp_common_t *headerp = NULL;
283 int icp_version;
284
285 commSetSelect(sock, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
286 from_len = sizeof(from);
287 memset(&from, '\0', from_len);
288 len = recvfrom(sock,
289 buf,
290 SQUID_UDP_SO_RCVBUF - 1,
291 0,
292 (struct sockaddr *) &from,
293 &from_len);
294 if (len < 0) {
295#ifdef _SQUID_LINUX_
296 /* Some Linux systems seem to set the FD for reading and then
297 * return ECONNREFUSED when sendto() fails and generates an ICMP
298 * port unreachable message. */
299 /* or maybe an EHOSTUNREACH "No route to host" message */
300 if (errno != ECONNREFUSED && errno != EHOSTUNREACH)
301#endif
302 debug(50, 1) ("icpHandleUdp: FD %d recvfrom: %s\n",
303 sock, xstrerror());
304 return;
305 }
f2908497 306 Counter.icp.pkts_recv++;
a7c05555 307 kb_incr(&Counter.icp.kbytes_recv, (size_t) len);
7a2f978b 308 buf[len] = '\0';
309 debug(12, 4) ("icpHandleUdp: FD %d: received %d bytes from %s.\n",
310 sock,
311 len,
312 inet_ntoa(from.sin_addr));
313#ifdef ICP_PACKET_DUMP
314 icpPktDump(buf);
315#endif
316 if (len < sizeof(icp_common_t)) {
317 debug(12, 4) ("icpHandleUdp: Ignoring too-small UDP packet\n");
318 return;
319 }
320 headerp = (icp_common_t *) (void *) buf;
321 if ((icp_version = (int) headerp->version) == ICP_VERSION_2)
322 icpHandleIcpV2(sock, from, buf, len);
323 else if (icp_version == ICP_VERSION_3)
324 icpHandleIcpV3(sock, from, buf, len);
325 else
326 debug(12, 0) ("WARNING: Unused ICP version %d received from %s:%d\n",
327 icp_version,
328 inet_ntoa(from.sin_addr),
329 ntohs(from.sin_port));
330}
15df8349 331
332void
333icpConnectionsOpen(void)
334{
335 u_short port;
336 struct in_addr addr;
337 struct sockaddr_in xaddr;
338 int x;
339 int len;
340 wordlist *s;
341 if (Config2.Accel.on && !Config.onoff.accel_with_proxy)
342 return;
343 if ((port = Config.Port.icp) <= 0)
344 return;
345 enter_suid();
346 theInIcpConnection = comm_open(SOCK_DGRAM,
347 0,
348 Config.Addrs.udp_incoming,
349 port,
350 COMM_NONBLOCKING,
351 "ICP Port");
352 leave_suid();
353 if (theInIcpConnection < 0)
354 fatal("Cannot open ICP Port");
355 fd_note(theInIcpConnection, "ICP socket");
356 commSetSelect(theInIcpConnection,
357 COMM_SELECT_READ,
358 icpHandleUdp,
359 NULL, 0);
360 for (s = Config.mcast_group_list; s; s = s->next)
361 ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL);
1e948d78 362 debug(1, 1) ("Accepting ICP messages on port %d, FD %d.\n",
15df8349 363 (int) port, theInIcpConnection);
364 if ((addr = Config.Addrs.udp_outgoing).s_addr != no_addr.s_addr) {
365 enter_suid();
366 theOutIcpConnection = comm_open(SOCK_DGRAM,
367 0,
368 addr,
369 port,
370 COMM_NONBLOCKING,
371 "ICP Port");
372 leave_suid();
373 if (theOutIcpConnection < 0)
374 fatal("Cannot open Outgoing ICP Port");
375 commSetSelect(theOutIcpConnection,
376 COMM_SELECT_READ,
377 icpHandleUdp,
378 NULL, 0);
1e948d78 379 debug(1, 1) ("Outgoing ICP messages on port %d, FD %d.\n",
380 (int) port, theOutIcpConnection);
15df8349 381 fd_note(theOutIcpConnection, "Outgoing ICP socket");
382 fd_note(theInIcpConnection, "Incoming ICP socket");
383 } else {
384 theOutIcpConnection = theInIcpConnection;
385 }
386 memset(&theOutICPAddr, '\0', sizeof(struct in_addr));
387 len = sizeof(struct sockaddr_in);
388 memset(&xaddr, '\0', len);
389 x = getsockname(theOutIcpConnection,
390 (struct sockaddr *) &xaddr, &len);
391 if (x < 0)
392 debug(50, 1) ("theOutIcpConnection FD %d: getsockname: %s\n",
393 theOutIcpConnection, xstrerror());
394 else
395 theOutICPAddr = xaddr.sin_addr;
396}
c0fbae16 397
398void
399icpConnectionsClose(void)
400{
401 if (theInIcpConnection < 0)
402 return;
403 debug(1, 1) ("FD %d Closing ICP connection\n", theInIcpConnection);
404 if (theInIcpConnection != theOutIcpConnection)
405 comm_close(theInIcpConnection);
406 /*
407 * Here we set 'theInIcpConnection' to -1 even though the ICP 'in'
408 * and 'out' sockets might be just one FD. This prevents this
409 * function from executing repeatedly. When we are really ready to
410 * exit or restart, main will comm_close the 'out' descriptor.
411 */
412 theInIcpConnection = -1;
413 /*
414 * Normally we only write to the outgoing ICP socket, but
415 * we also have a read handler there to catch messages sent
416 * to that specific interface. During shutdown, we must
417 * disable reading on the outgoing socket.
418 */
419 assert(theOutIcpConnection > -1);
420 commSetSelect(theOutIcpConnection, COMM_SELECT_READ, NULL, NULL, 0);
421}