1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
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.
7  */
8 
9 /* DEBUG: section 12    Internet Cache Protocol (ICP) */
10 
11 /**
12  \defgroup ServerProtocolICPInternal3 ICPv3 Internals
13  \ingroup ServerProtocolICPAPI
14  */
15 
16 #include "squid.h"
17 #include "HttpRequest.h"
18 #include "ICP.h"
19 #include "Store.h"
20 
21 /// \ingroup ServerProtocolICPInternal3
22 class ICP3State : public ICPState, public StoreClient
23 {
24 
25 public:
ICP3State(icp_common_t & aHeader,HttpRequest * aRequest)26     ICP3State(icp_common_t &aHeader, HttpRequest *aRequest) :
27         ICPState(aHeader, aRequest) {}
28 
29     ~ICP3State();
30     void created (StoreEntry *newEntry);
31 };
32 
33 /// \ingroup ServerProtocolICPInternal3
34 static void
doV3Query(int fd,Ip::Address & from,char * buf,icp_common_t header)35 doV3Query(int fd, Ip::Address &from, char *buf, icp_common_t header)
36 {
37     /* We have a valid packet */
38     char *url = buf + sizeof(icp_common_t) + sizeof(uint32_t);
39     HttpRequest *icp_request = icpGetRequest(url, header.reqnum, fd, from);
40 
41     if (!icp_request)
42         return;
43 
44     if (!icpAccessAllowed(from, icp_request)) {
45         icpDenyAccess (from, url, header.reqnum, fd);
46         delete icp_request;
47         return;
48     }
49 
50     /* The peer is allowed to use this cache */
51     ICP3State *state = new ICP3State (header, icp_request);
52     state->fd = fd;
53     state->from = from;
54     state->url = xstrdup(url);
55 
56     StoreEntry::getPublic (state, url, Http::METHOD_GET);
57 }
58 
~ICP3State()59 ICP3State::~ICP3State()
60 {}
61 
62 void
created(StoreEntry * newEntry)63 ICP3State::created(StoreEntry *newEntry)
64 {
65     StoreEntry *entry = newEntry->isNull () ? NULL : newEntry;
66     debugs(12, 5, "icpHandleIcpV3: OPCODE " << icp_opcode_str[header.opcode]);
67     icp_opcode codeToSend;
68 
69     if (icpCheckUdpHit(entry, request)) {
70         codeToSend = ICP_HIT;
71     } else if (icpGetCommonOpcode() == ICP_ERR)
72         codeToSend = ICP_MISS;
73     else
74         codeToSend = icpGetCommonOpcode();
75 
76     icpCreateAndSend (codeToSend, 0, url, header.reqnum, 0, fd, from);
77 
78     delete this;
79 }
80 
81 /// \ingroup ServerProtocolICPInternal3
82 /* Currently Harvest cached-2.x uses ICP_VERSION_3 */
83 void
icpHandleIcpV3(int fd,Ip::Address & from,char * buf,int len)84 icpHandleIcpV3(int fd, Ip::Address &from, char *buf, int len)
85 {
86     if (len <= 0) {
87         debugs(12, 3, "icpHandleIcpV3: ICP message is too small");
88         return;
89     }
90 
91     icp_common_t header (buf, len);
92     /*
93      * Length field should match the number of bytes read
94      */
95 
96     if (len != header.length) {
97         debugs(12, 3, "icpHandleIcpV3: ICP message is too small");
98         return;
99     }
100 
101     switch (header.opcode) {
102 
103     case ICP_QUERY:
104         doV3Query(fd, from, buf, header);
105         break;
106 
107     case ICP_HIT:
108 
109     case ICP_DECHO:
110 
111     case ICP_MISS:
112 
113     case ICP_DENIED:
114 
115     case ICP_MISS_NOFETCH:
116         header.handleReply(buf, from);
117         break;
118 
119     case ICP_INVALID:
120 
121     case ICP_ERR:
122         break;
123 
124     default:
125         debugs(12, DBG_CRITICAL, "icpHandleIcpV3: UNKNOWN OPCODE: " << header.opcode << " from " << from);
126         break;
127     }
128 }
129 
130