21
18
* it under the terms of the GNU General Public License as published by
22
19
* the Free Software Foundation; either version 2 of the License, or
23
20
* (at your option) any later version.
25
22
* This program is distributed in the hope that it will be useful,
26
23
* but WITHOUT ANY WARRANTY; without even the implied warranty of
27
24
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
25
* GNU General Public License for more details.
30
27
* You should have received a copy of the GNU General Public License
31
28
* along with this program; if not, write to the Free Software
32
29
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34
\defgroup ServerProtocolICPInternal2 ICPv2 Internals
35
\ingroup ServerProtocolICPAPI
40
42
#include "HttpRequest.h"
41
#include "ACLChecklist.h"
43
#include "acl/FilledChecklist.h"
43
45
#include "AccessLogEntry.h"
44
46
#include "wordlist.h"
45
47
#include "SquidTime.h"
46
48
#include "SwapDir.h"
48
static void icpLogIcp(struct IN_ADDR, log_type, int, const char *, int);
50
static void icpHandleIcpV2(int, struct sockaddr_in, char *, int);
49
#include "icmp/net_db.h"
50
#include "ip/IpAddress.h"
52
/// \ingroup ServerProtocolICPInternal2
53
static void icpLogIcp(const IpAddress &, log_type, int, const char *, int);
55
/// \ingroup ServerProtocolICPInternal2
56
static void icpHandleIcpV2(int, IpAddress &, char *, int);
58
/// \ingroup ServerProtocolICPInternal2
51
59
static void icpCount(void *, int, size_t, int);
62
\ingroup ServerProtocolICPInternal2
54
63
* IcpQueueHead is global so comm_incoming() knows whether or not
55
64
* to call icpUdpSendQueue.
66
static icpUdpData *IcpQueueHead = NULL;
67
/// \ingroup ServerProtocolICPInternal2
57
68
static icpUdpData *IcpQueueTail = NULL;
58
static icpUdpData *IcpQueueHead = NULL;
70
/// \ingroup ServerProtocolICPInternal2
71
IpAddress theOutICPAddr;
61
74
_icp_common_t::_icp_common_t() : opcode(ICP_INVALID), version(0), length(0), reqnum(0), flags(0), pad(0), shostid(0)
111
class ICP2State:public ICPState, public StoreClient
124
/// \ingroup ServerProtocolICPInternal2
125
class ICP2State : public ICPState, public StoreClient
115
129
ICP2State(icp_common_t & aHeader, HttpRequest *aRequest):
116
ICPState(aHeader, aRequest),rtt(0),src_rtt(0),flags(0)
130
ICPState(aHeader, aRequest),rtt(0),src_rtt(0),flags(0) {}
120
133
void created(StoreEntry * newEntry);
137
150
if (icpCheckUdpHit(entry, request)) {
138
151
codeToSend = ICP_HIT;
140
154
if (Config.onoff.test_reachability && rtt == 0) {
141
if ((rtt = netdbHostRtt(request->host)) == 0)
142
netdbPingSite(request->host);
155
if ((rtt = netdbHostRtt(request->GetHost())) == 0)
156
netdbPingSite(request->GetHost());
158
#endif /* USE_ICMP */
145
160
if (icpGetCommonOpcode() != ICP_ERR)
146
161
codeToSend = icpGetCommonOpcode();
150
165
codeToSend = ICP_MISS;
153
icpCreateAndSend(codeToSend, flags, url, header.reqnum, src_rtt, fd, &from);
168
icpCreateAndSend(codeToSend, flags, url, header.reqnum, src_rtt, fd, from);
157
172
/* End ICP2State */
174
/// \ingroup ServerProtocolICPInternal2
161
icpLogIcp(struct IN_ADDR caddr, log_type logcode, int len, const char *url, int delay)
176
icpLogIcp(const IpAddress &caddr, log_type logcode, int len, const char *url, int delay)
163
178
AccessLogEntry al;
198
214
while ((q = IcpQueueHead) != NULL) {
199
215
delay = tvSubUsec(q->queue_time, current_time);
200
216
/* increment delay to prevent looping */
201
x = icpUdpSend(fd, &q->address, (icp_common_t *) q->msg, q->logcode, ++delay);
217
x = icpUdpSend(fd, q->address, (icp_common_t *) q->msg, q->logcode, ++delay);
202
218
IcpQueueHead = q->next;
266
281
len = (int) ntohs(msg->length);
267
282
debugs(12, 5, "icpUdpSend: FD " << fd << " sending " <<
268
icp_opcode_str[msg->opcode] << ", " << len << " bytes to " <<
269
inet_ntoa(to->sin_addr) << ":" << ntohs(to->sin_port));
271
x = comm_udp_sendto(fd, to, sizeof(*to), msg, len);
283
icp_opcode_str[msg->opcode] << ", " << len << " bytes to " << to);
285
x = comm_udp_sendto(fd, to, msg, len);
275
288
/* successfully written */
276
icpLogIcp(to->sin_addr, logcode, len, (char *) (msg + 1), delay);
289
icpLogIcp(to, logcode, len, (char *) (msg + 1), delay);
277
290
icpCount(msg, SENT, (size_t) len, delay);
279
} else if (0 == delay)
292
} else if (0 == delay) {
281
293
/* send failed, but queue it */
282
294
queue = (icpUdpData *) xcalloc(1, sizeof(icpUdpData));
283
queue->address = *to;
284
296
queue->msg = msg;
285
297
queue->len = (int) ntohs(msg->length);
286
298
queue->queue_time = current_time;
371
icpCreateAndSend(icp_opcode opcode, int flags, char const *url, int reqnum, int pad, int fd, const struct sockaddr_in *from)
383
icpCreateAndSend(icp_opcode opcode, int flags, char const *url, int reqnum, int pad, int fd, const IpAddress &from)
373
385
icp_common_t *reply = _icp_common_t::createMessage(opcode, flags, url, reqnum, pad);
374
386
icpUdpSend(fd, from, reply, icpLogFromICPCode(opcode), 0);
379
icpDenyAccess(struct sockaddr_in *from, char *url, int reqnum, int fd)
390
icpDenyAccess(IpAddress &from, char *url, int reqnum, int fd)
381
debugs(12, 2, "icpDenyAccess: Access Denied for " << inet_ntoa(from->sin_addr) << " by " << AclMatchedName << ".");
392
debugs(12, 2, "icpDenyAccess: Access Denied for " << from << " by " << AclMatchedName << ".");
383
if (clientdbCutoffDenied(from->sin_addr))
394
if (clientdbCutoffDenied(from)) {
386
396
* count this DENIED query in the clientdb, even though
387
397
* we're not sending an ICP reply...
389
clientdbUpdate(from->sin_addr, LOG_UDP_DENIED, PROTO_ICP, 0);
399
clientdbUpdate(from, LOG_UDP_DENIED, PROTO_ICP, 0);
392
401
icpCreateAndSend(ICP_DENIED, 0, url, reqnum, 0, fd, from);
398
icpAccessAllowed(struct sockaddr_in *from, HttpRequest * icp_request)
406
icpAccessAllowed(IpAddress &from, HttpRequest * icp_request)
400
ACLChecklist checklist;
401
checklist.src_addr = from->sin_addr;
402
checklist.my_addr = no_addr;
403
checklist.request = HTTPMSGLOCK(icp_request);
404
checklist.accessList = cbdataReference(Config.accessList.icp);
405
/* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */
408
/* absent an explicit allow, we deny all */
409
if (!Config.accessList.icp)
412
ACLFilledChecklist checklist(Config.accessList.icp, icp_request, NULL);
413
checklist.src_addr = from;
414
checklist.my_addr.SetNoAddr();
406
415
int result = checklist.fastCheck();
421
icpGetRequest(char *url, int reqnum, int fd, struct sockaddr_in * from)
429
icpGetRequest(char *url, int reqnum, int fd, IpAddress &from)
423
if (strpbrk(url, w_space))
431
if (strpbrk(url, w_space)) {
425
432
url = rfc1738_escape(url);
426
433
icpCreateAndSend(ICP_ERR, 0, rfc1738_escape(url), reqnum, 0, fd, from);
441
doV2Query(int fd, struct sockaddr_in from, char *buf, icp_common_t header)
447
doV2Query(int fd, IpAddress &from, char *buf, icp_common_t header)
445
451
u_int32_t flags = 0;
446
452
/* We have a valid packet */
447
453
char *url = buf + sizeof(icp_common_t) + sizeof(u_int32_t);
448
HttpRequest *icp_request = icpGetRequest(url, header.reqnum, fd, &from);
454
HttpRequest *icp_request = icpGetRequest(url, header.reqnum, fd, from);
450
456
if (!icp_request)
453
459
HTTPMSGLOCK(icp_request);
455
if (!icpAccessAllowed(&from, icp_request))
457
icpDenyAccess(&from, url, header.reqnum, fd);
461
if (!icpAccessAllowed(from, icp_request)) {
462
icpDenyAccess(from, url, header.reqnum, fd);
458
463
HTTPMSGUNLOCK(icp_request);
462
if (header.flags & ICP_FLAG_SRC_RTT)
464
rtt = netdbHostRtt(icp_request->host);
465
int hops = netdbHostHops(icp_request->host);
467
if (header.flags & ICP_FLAG_SRC_RTT) {
468
rtt = netdbHostRtt(icp_request->GetHost());
469
int hops = netdbHostHops(icp_request->GetHost());
466
470
src_rtt = ((hops & 0xFFFF) << 16) | (rtt & 0xFFFF);
469
473
flags |= ICP_FLAG_SRC_RTT;
475
#endif /* USE_ICMP */
472
477
/* The peer is allowed to use this cache */
473
478
ICP2State *state = new ICP2State (header, icp_request);
494
_icp_common_t::handleReply(char *buf, struct sockaddr_in *from)
498
_icp_common_t::handleReply(char *buf, IpAddress &from)
496
if (neighbors_do_private_keys && reqnum == 0)
498
debugs(12, 0, "icpHandleIcpV2: Neighbor " << inet_ntoa(from->sin_addr) << " returned reqnum = 0");
500
if (neighbors_do_private_keys && reqnum == 0) {
501
debugs(12, 0, "icpHandleIcpV2: Neighbor " << from << " returned reqnum = 0");
499
502
debugs(12, 0, "icpHandleIcpV2: Disabling use of private keys");
500
503
neighbors_do_private_keys = 0;
503
506
char *url = buf + sizeof(icp_common_t);
504
debugs(12, 3, "icpHandleIcpV2: " << icp_opcode_str[opcode] << " from " << inet_ntoa(from->sin_addr) << " for '" << url << "'");
507
debugs(12, 3, "icpHandleIcpV2: " << icp_opcode_str[opcode] << " from " << from << " for '" << url << "'");
506
509
const cache_key *key = icpGetCacheKey(url, (int) reqnum);
507
510
/* call neighborsUdpAck even if ping_status != PING_WAITING */
570
565
icpPktDump(icp_common_t * pkt)
575
570
debugs(12, 9, "opcode: " << std::setw(3) << pkt->opcode << " " << icp_opcode_str[pkt->opcode]);
576
571
debugs(12, 9, "version: "<< std::left << std::setw(8) << pkt->version);
577
572
debugs(12, 9, "length: "<< std::left << std::setw(8) << ntohs(pkt->length));
578
573
debugs(12, 9, "reqnum: "<< std::left << std::setw(8) << ntohl(pkt->reqnum));
579
574
debugs(12, 9, "flags: "<< std::left << std::hex << std::setw(8) << ntohl(pkt->flags));
580
a.s_addr = pkt->shostid;
581
debugs(12, 9, "shostid: " << inet_ntoa(a));
575
a = (struct in_addr)pkt->shostid;
576
debugs(12, 9, "shostid: " << a );
582
577
debugs(12, 9, "payload: " << (char *) pkt + sizeof(icp_common_t));
598
592
commSetSelect(sock, COMM_SELECT_READ, icpHandleUdp, NULL, 0);
601
from_len = sizeof(from);
602
memset(&from, '\0', from_len);
603
595
len = comm_udp_recvfrom(sock,
605
597
SQUID_UDP_SO_RCVBUF - 1,
608
(struct sockaddr *) &from,
632
622
icpCount(buf, RECV, (size_t) len, 0);
634
624
debugs(12, 4, "icpHandleUdp: FD " << sock << ": received " <<
635
(unsigned long int)len << " bytes from " <<
636
inet_ntoa(from.sin_addr) << ".");
625
(unsigned long int)len << " bytes from " << from);
638
627
#ifdef ICP_PACKET_DUMP
652
641
else if (icp_version == ICP_VERSION_3)
653
642
icpHandleIcpV3(sock, from, buf, len);
655
debugs(12, 1, "WARNING: Unused ICP version " << icp_version <<
656
" received from " << inet_ntoa(from.sin_addr) << ":" << ntohs(from.sin_port));
644
debugs(12, 1, "WARNING: Unused ICP version " << icp_version <<
645
" received from " << from);
695
683
for (s = Config.mcast_group_list; s; s = s->next)
696
684
ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL);
698
debugs(12, 1, "Accepting ICP messages at " <<
699
inet_ntoa(Config.Addrs.udp_incoming) << ", port " << (int) port <<
700
", FD " << theInIcpConnection << ".");
703
if ((addr = Config.Addrs.udp_outgoing).s_addr != no_addr.s_addr) {
686
debugs(12, 1, "Accepting ICP messages at " << addr << ", FD " << theInIcpConnection << ".");
688
addr.SetEmpty(); // clear for next use.
689
addr = Config.Addrs.udp_outgoing;
690
if ( !addr.IsNoAddr() ) {
705
theOutIcpConnection = comm_open(SOCK_DGRAM,
693
theOutIcpConnection = comm_open_listener(SOCK_DGRAM,
713
700
if (theOutIcpConnection < 0)
728
715
theOutIcpConnection = theInIcpConnection;
731
memset(&theOutICPAddr, '\0', sizeof(struct IN_ADDR));
733
len = sizeof(struct sockaddr_in);
734
memset(&xaddr, '\0', len);
735
x = getsockname(theOutIcpConnection,
737
(struct sockaddr *) &xaddr, &len);
718
theOutICPAddr.SetEmpty();
720
theOutICPAddr.InitAddrInfo(xai);
722
x = getsockname(theOutIcpConnection, xai->ai_addr, &xai->ai_addrlen);
740
725
debugs(50, 1, "theOutIcpConnection FD " << theOutIcpConnection << ": getsockname: " << xstrerror());
742
theOutICPAddr = xaddr.sin_addr;
727
theOutICPAddr = *xai;
729
theOutICPAddr.FreeAddrInfo(xai);
746
* icpConnectionShutdown only closes the 'in' socket if it is
733
* icpConnectionShutdown only closes the 'in' socket if it is
747
734
* different than the 'out' socket.