]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/FilledChecklist.cc
Supply AccessLogEntry (ALE) for more fast ACL checks. (#182)
[thirdparty/squid.git] / src / acl / FilledChecklist.cc
1 /*
2 * Copyright (C) 1996-2018 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 #include "squid.h"
10 #include "acl/FilledChecklist.h"
11 #include "client_side.h"
12 #include "comm/Connection.h"
13 #include "comm/forward.h"
14 #include "ExternalACLEntry.h"
15 #include "http/Stream.h"
16 #include "HttpReply.h"
17 #include "HttpRequest.h"
18 #include "SquidConfig.h"
19 #if USE_AUTH
20 #include "auth/AclProxyAuth.h"
21 #include "auth/UserRequest.h"
22 #endif
23
24 CBDATA_CLASS_INIT(ACLFilledChecklist);
25
26 ACLFilledChecklist::ACLFilledChecklist() :
27 dst_rdns(NULL),
28 request (NULL),
29 reply (NULL),
30 #if USE_AUTH
31 auth_user_request (NULL),
32 #endif
33 #if SQUID_SNMP
34 snmp_community(NULL),
35 #endif
36 #if USE_OPENSSL
37 sslErrors(NULL),
38 #endif
39 requestErrorType(ERR_MAX),
40 conn_(NULL),
41 fd_(-1),
42 destinationDomainChecked_(false),
43 sourceDomainChecked_(false)
44 {
45 my_addr.setEmpty();
46 src_addr.setEmpty();
47 dst_addr.setEmpty();
48 rfc931[0] = '\0';
49 }
50
51 ACLFilledChecklist::~ACLFilledChecklist()
52 {
53 assert (!asyncInProgress());
54
55 safe_free(dst_rdns); // created by xstrdup().
56
57 HTTPMSGUNLOCK(request);
58
59 HTTPMSGUNLOCK(reply);
60
61 cbdataReferenceDone(conn_);
62
63 #if USE_OPENSSL
64 cbdataReferenceDone(sslErrors);
65 #endif
66
67 debugs(28, 4, HERE << "ACLFilledChecklist destroyed " << this);
68 }
69
70 static void
71 showDebugWarning(const char *msg)
72 {
73 static uint16_t count = 0;
74 if (count > 10)
75 return;
76
77 ++count;
78 debugs(28, DBG_IMPORTANT, "ALE missing " << msg);
79 }
80
81 void
82 ACLFilledChecklist::verifyAle() const
83 {
84 // make sure the ALE fields used by Format::assemble to
85 // fill the old external_acl_type codes are set if any
86 // data on them exists in the Checklist
87
88 if (!al->cache.port && conn()) {
89 showDebugWarning("listening port");
90 al->cache.port = conn()->port;
91 }
92
93 if (request) {
94 if (!al->request) {
95 showDebugWarning("HttpRequest object");
96 // XXX: al->request should be original,
97 // but the request may be already adapted
98 al->request = request;
99 HTTPMSGLOCK(al->request);
100 }
101
102 if (!al->adapted_request) {
103 showDebugWarning("adapted HttpRequest object");
104 al->adapted_request = request;
105 HTTPMSGLOCK(al->adapted_request);
106 }
107
108 if (al->url.isEmpty()) {
109 showDebugWarning("URL");
110 // XXX: al->url should be the request URL from client,
111 // but request->url may be different (e.g.,redirected)
112 al->url = request->url.absolute();
113 }
114 }
115
116 if (reply && !al->reply) {
117 showDebugWarning("HttpReply object");
118 al->reply = reply;
119 HTTPMSGLOCK(al->reply);
120 }
121
122 #if USE_IDENT
123 if (*rfc931 && !al->cache.rfc931) {
124 showDebugWarning("IDENT");
125 al->cache.rfc931 = xstrdup(rfc931);
126 }
127 #endif
128 }
129
130 void
131 ACLFilledChecklist::syncAle(HttpRequest *adaptedRequest, const char *logUri) const
132 {
133 if (!al)
134 return;
135 if (!al->adapted_request) {
136 al->adapted_request = adaptedRequest;
137 HTTPMSGLOCK(al->adapted_request);
138 }
139 if (al->url.isEmpty())
140 al->url = logUri;
141 }
142
143 ConnStateData *
144 ACLFilledChecklist::conn() const
145 {
146 return cbdataReferenceValid(conn_) ? conn_ : nullptr;
147 }
148
149 void
150 ACLFilledChecklist::conn(ConnStateData *aConn)
151 {
152 if (conn() == aConn)
153 return;
154 assert (conn() == NULL);
155 conn_ = cbdataReference(aConn);
156 }
157
158 int
159 ACLFilledChecklist::fd() const
160 {
161 const auto c = conn();
162 return (c && c->clientConnection) ? c->clientConnection->fd : fd_;
163 }
164
165 void
166 ACLFilledChecklist::fd(int aDescriptor)
167 {
168 const auto c = conn();
169 assert(!c || !c->clientConnection || c->clientConnection->fd == aDescriptor);
170 fd_ = aDescriptor;
171 }
172
173 bool
174 ACLFilledChecklist::destinationDomainChecked() const
175 {
176 return destinationDomainChecked_;
177 }
178
179 void
180 ACLFilledChecklist::markDestinationDomainChecked()
181 {
182 assert (!finished() && !destinationDomainChecked());
183 destinationDomainChecked_ = true;
184 }
185
186 bool
187 ACLFilledChecklist::sourceDomainChecked() const
188 {
189 return sourceDomainChecked_;
190 }
191
192 void
193 ACLFilledChecklist::markSourceDomainChecked()
194 {
195 assert (!finished() && !sourceDomainChecked());
196 sourceDomainChecked_ = true;
197 }
198
199 /*
200 * There are two common ACLFilledChecklist lifecycles paths:
201 *
202 * A) Using aclCheckFast(): The caller creates an ACLFilledChecklist object
203 * on stack and calls aclCheckFast().
204 *
205 * B) Using aclNBCheck() and callbacks: The caller allocates an
206 * ACLFilledChecklist object (via operator new) and passes it to
207 * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(),
208 * which will invoke the callback function as requested by the
209 * original caller of aclNBCheck(). This callback function must
210 * *not* delete the list. After the callback function returns,
211 * checkCallback() will delete the list (i.e., self).
212 */
213 ACLFilledChecklist::ACLFilledChecklist(const acl_access *A, HttpRequest *http_request, const char *ident):
214 dst_rdns(NULL),
215 request(NULL),
216 reply(NULL),
217 #if USE_AUTH
218 auth_user_request(NULL),
219 #endif
220 #if SQUID_SNMP
221 snmp_community(NULL),
222 #endif
223 #if USE_OPENSSL
224 sslErrors(NULL),
225 #endif
226 requestErrorType(ERR_MAX),
227 conn_(NULL),
228 fd_(-1),
229 destinationDomainChecked_(false),
230 sourceDomainChecked_(false)
231 {
232 my_addr.setEmpty();
233 src_addr.setEmpty();
234 dst_addr.setEmpty();
235 rfc931[0] = '\0';
236
237 changeAcl(A);
238 setRequest(http_request);
239 setIdent(ident);
240 }
241
242 void ACLFilledChecklist::setRequest(HttpRequest *httpRequest)
243 {
244 assert(!request);
245 if (httpRequest) {
246 request = httpRequest;
247 HTTPMSGLOCK(request);
248 #if FOLLOW_X_FORWARDED_FOR
249 if (Config.onoff.acl_uses_indirect_client)
250 src_addr = request->indirect_client_addr;
251 else
252 #endif /* FOLLOW_X_FORWARDED_FOR */
253 src_addr = request->client_addr;
254 my_addr = request->my_addr;
255
256 if (request->clientConnectionManager.valid())
257 conn(request->clientConnectionManager.get());
258 }
259 }
260
261 void
262 ACLFilledChecklist::setIdent(const char *ident)
263 {
264 #if USE_IDENT
265 assert(!rfc931[0]);
266 if (ident)
267 xstrncpy(rfc931, ident, USER_IDENT_SZ);
268 #endif
269 }
270