]> git.ipfire.org Git - thirdparty/squid.git/blame - src/FwdState.cc
Cleanup: replace USE_SSL wrapper macro with USE_OPENSSL
[thirdparty/squid.git] / src / FwdState.cc
CommitLineData
41462d93 1/*
41462d93 2 * DEBUG: section 17 Request Forwarding
3 * AUTHOR: Duane Wessels
4 *
2b6662ba 5 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 6 * ----------------------------------------------------------
41462d93 7 *
2b6662ba 8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
41462d93 16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
26ac0430 21 *
41462d93 22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26ac0430 26 *
41462d93 27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
cbdec147 29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 30 *
41462d93 31 */
32
582c2af2 33#include "squid.h"
4bf68cfa 34#include "AccessLogEntry.h"
0dc8ffa5 35#include "acl/AclAddress.h"
c0941a6a
AR
36#include "acl/FilledChecklist.h"
37#include "acl/Gadgets.h"
5ae65581 38#include "anyp/PortCfg.h"
25b481e6 39#include "CacheManager.h"
602d9612 40#include "CachePeer.h"
582c2af2 41#include "client_side.h"
f9b72e0c 42#include "comm/Connection.h"
aed188fd 43#include "comm/ConnOpener.h"
d841c88d 44#include "comm/Loops.h"
582c2af2 45#include "CommCalls.h"
aa839030 46#include "errorpage.h"
582c2af2 47#include "event.h"
fc54b8d2 48#include "fd.h"
aa839030 49#include "fde.h"
fc54b8d2 50#include "ftp.h"
eb13c21e 51#include "FwdState.h"
582c2af2 52#include "globals.h"
fc54b8d2 53#include "gopher.h"
bbaf2685 54#include "hier_code.h"
fc54b8d2 55#include "http.h"
924f73bc 56#include "HttpReply.h"
aa839030 57#include "HttpRequest.h"
582c2af2 58#include "icmp/net_db.h"
fc54b8d2 59#include "internal.h"
582c2af2 60#include "ip/Intercept.h"
425de4c8 61#include "ip/QosConfig.h"
582c2af2 62#include "ip/tools.h"
aa839030 63#include "MemObject.h"
582c2af2 64#include "mgr/Registration.h"
fc54b8d2 65#include "neighbors.h"
781ce8ff 66#include "pconn.h"
cfd66529 67#include "PeerSelectState.h"
4d5904f7 68#include "SquidConfig.h"
aa839030 69#include "SquidTime.h"
70#include "Store.h"
e87137f1 71#include "StoreClient.h"
5eb529cb 72#include "urn.h"
fc54b8d2 73#include "whois.h"
cb4f4424 74#if USE_OPENSSL
2cef0ca6
AR
75#include "ssl/cert_validate_message.h"
76#include "ssl/Config.h"
4d16918e 77#include "ssl/ErrorDetail.h"
602d9612 78#include "ssl/helper.h"
fd4624d7 79#include "ssl/ServerBump.h"
602d9612 80#include "ssl/support.h"
4db984be 81#endif
21d845b1
FC
82#if HAVE_ERRNO_H
83#include <errno.h>
84#endif
cfd66529 85
6b679a01 86static PSC fwdPeerSelectionCompleteWrapper;
575d05c4 87static CLCB fwdServerClosedWrapper;
cb4f4424 88#if USE_OPENSSL
b6b6f466 89static PF fwdNegotiateSSLWrapper;
90#endif
b6b6f466 91static CNCB fwdConnectDoneWrapper;
92
8ddcc35d 93static OBJH fwdStats;
94
95#define MAX_FWD_STATS_IDX 9
955394ce 96static int FwdReplyCodes[MAX_FWD_STATS_IDX + 1][Http::scInvalidHeader + 1];
db1cd23c 97
781ce8ff 98static PconnPool *fwdPconnPool = new PconnPool("server-side");
b6b6f466 99CBDATA_CLASS_INIT(FwdState);
781ce8ff 100
429871db 101void
102FwdState::abort(void* d)
103{
104 FwdState* fwd = (FwdState*)d;
6ecaf21a 105 Pointer tmp = fwd; // Grab a temporary pointer to keep the object alive during our scope.
429871db 106
6b679a01 107 if (Comm::IsConnOpen(fwd->serverConnection())) {
5229395c 108 comm_remove_close_handler(fwd->serverConnection()->fd, fwdServerClosedWrapper, fwd);
6dd9a2e4
AJ
109 debugs(17, 3, HERE << "store entry aborted; closing " <<
110 fwd->serverConnection());
111 fwd->serverConnection()->close();
112 } else {
113 debugs(17, 7, HERE << "store entry aborted; no connection to close");
cff02fa6 114 }
c33a88ca 115 fwd->serverDestinations.clear();
429871db 116 fwd->self = NULL;
117}
118
b6b6f466 119/**** PUBLIC INTERFACE ********************************************************/
c7f9eb6d 120
4bf68cfa 121FwdState::FwdState(const Comm::ConnectionPointer &client, StoreEntry * e, HttpRequest * r, const AccessLogEntryPointer &alp):
c901ed8c 122 al(alp)
db1cd23c 123{
3157a816 124 debugs(17, 2, HERE << "Forwarding client request " << client << ", url=" << e->url() );
b6b6f466 125 entry = e;
5c336a3b 126 clientConn = client;
b248c2a3
AJ
127 request = r;
128 HTTPMSGLOCK(request);
bc81ee68 129 pconnRace = raceImpossible;
b6b6f466 130 start_t = squid_curtime;
00ae51e4 131 serverDestinations.reserve(Config.forward_max_tries);
1bfe9ade 132 e->lock("FwdState");
b6b6f466 133 EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
7a0fb323 134}
135
136// Called once, right after object creation, when it is safe to set self
fc68f6b1 137void FwdState::start(Pointer aSelf)
138{
7a0fb323 139 // Protect ourselves from being destroyed when the only Server pointing
140 // to us is gone (while we expect to talk to more Servers later).
141 // Once we set self, we are responsible for clearing it when we do not
142 // expect to talk to any servers.
143 self = aSelf; // refcounted
144
145 // We hope that either the store entry aborts or peer is selected.
146 // Otherwise we are going to leak our object.
34266cde 147
3900307b 148 entry->registerAbort(FwdState::abort, this);
bfe4e2fe 149
32c32865 150#if STRICT_ORIGINAL_DST
bfe4e2fe
AJ
151 // Bug 3243: CVE 2009-0801
152 // Bypass of browser same-origin access control in intercepted communication
153 // To resolve this we must force DIRECT and only to the original client destination.
0d901ef4 154 const bool isIntercepted = request && !request->flags.redirected && (request->flags.intercepted || request->flags.interceptTproxy);
2962f8b8
AJ
155 const bool useOriginalDst = Config.onoff.client_dst_passthru || (request && !request->flags.hostVerified);
156 if (isIntercepted && useOriginalDst) {
d7ce0bcd 157 selectPeerForIntercepted();
7177edfb
AJ
158 // 3.2 does not suppro re-wrapping inside CONNECT.
159 // our only alternative is to fake destination "found" and continue with the forwarding.
bfe4e2fe 160 startConnectionOrFail();
7177edfb 161 return;
bfe4e2fe 162 }
32c32865
AJ
163#endif
164
7177edfb 165 // do full route options selection
d4806c91 166 peerSelect(&serverDestinations, request, al, entry, fwdPeerSelectionCompleteWrapper, this);
db1cd23c 167}
168
32c32865 169#if STRICT_ORIGINAL_DST
d7ce0bcd
AR
170/// bypasses peerSelect() when dealing with intercepted requests
171void
172FwdState::selectPeerForIntercepted()
173{
174 // use pinned connection if available
175 Comm::ConnectionPointer p;
693cb033 176 if (ConnStateData *client = request->pinnedConnection()) {
d7ce0bcd 177 p = client->validatePinnedConnection(request, NULL);
693cb033
CT
178 if (Comm::IsConnOpen(p)) {
179 /* duplicate peerSelectPinned() effects */
180 p->peerType = PINNED;
181 entry->ping_status = PING_DONE; /* Skip ICP */
d7ce0bcd 182
693cb033
CT
183 debugs(17, 3, "reusing a pinned conn: " << *p);
184 serverDestinations.push_back(p);
185 } else {
186 debugs(17,2, "Pinned connection is not valid: " << p);
955394ce 187 ErrorState *anErr = new ErrorState(ERR_ZERO_SIZE_OBJECT, Http::scServiceUnavailable, request);
693cb033
CT
188 fail(anErr);
189 }
190 // Either use the valid pinned connection or fail if it is invalid.
191 return;
d7ce0bcd
AR
192 }
193
7177edfb
AJ
194 // use client original destination as second preferred choice
195 p = new Comm::Connection();
196 p->peerType = ORIGINAL_DST;
197 p->remote = clientConn->local;
198 getOutgoingAddress(request, p);
199
200 debugs(17, 3, HERE << "using client original destination: " << *p);
d7ce0bcd
AR
201 serverDestinations.push_back(p);
202}
32c32865 203#endif
d7ce0bcd 204
802a8c1d 205void
206FwdState::completed()
41462d93 207{
e857372a 208 if (flags.forward_completed) {
e0236918 209 debugs(17, DBG_IMPORTANT, HERE << "FwdState::completed called on a completed request! Bad!");
fc68f6b1 210 return;
211 }
212
e857372a 213 flags.forward_completed = true;
802a8c1d 214
c4a88a3e
CT
215 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
216 debugs(17, 3, HERE << "entry aborted");
217 return ;
218 }
219
bc87dc25 220#if URL_CHECKSUM_DEBUG
62e76326 221
b6b6f466 222 entry->mem_obj->checkUrlChecksum();
225644d7 223#endif
62e76326 224
b6b6f466 225 if (entry->store_status == STORE_PENDING) {
226 if (entry->isEmpty()) {
a04b7e6e 227 if (!err) // we quit (e.g., fd closed) before an error or content
955394ce 228 fail(new ErrorState(ERR_READ_ERROR, Http::scBadGateway, request));
b6b6f466 229 assert(err);
230 errorAppendEntry(entry, err);
231 err = NULL;
cb4f4424 232#if USE_OPENSSL
2cef0ca6
AR
233 if (request->flags.sslPeek && request->clientConnectionManager.valid()) {
234 CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
235 ConnStateData::httpsPeeked, Comm::ConnectionPointer(NULL));
236 }
237#endif
62e76326 238 } else {
b6b6f466 239 EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
240 entry->complete();
d88e3c49 241 entry->releaseRequest();
62e76326 242 }
f563eea9 243 }
62e76326 244
b6b6f466 245 if (storePendingNClients(entry) > 0)
246 assert(!EBIT_TEST(entry->flags, ENTRY_FWD_HDR_WAIT));
62e76326 247
802a8c1d 248}
249
250FwdState::~FwdState()
251{
252 debugs(17, 3, HERE << "FwdState destructor starting");
fc68f6b1 253
802a8c1d 254 if (! flags.forward_completed)
fc68f6b1 255 completed();
802a8c1d 256
9d2760b6
AR
257 doneWithRetries();
258
6dd9f4bd 259 HTTPMSGUNLOCK(request);
62e76326 260
913524f0 261 delete err;
62e76326 262
3900307b 263 entry->unregisterAbort();
429871db 264
1bfe9ade 265 entry->unlock("FwdState");
62e76326 266
b6b6f466 267 entry = NULL;
62e76326 268
e3a4aecc
AJ
269 if (calls.connector != NULL) {
270 calls.connector->cancel("FwdState destructed");
271 calls.connector = NULL;
272 }
273
6b679a01 274 if (Comm::IsConnOpen(serverConn)) {
5229395c
AJ
275 comm_remove_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
276 debugs(17, 3, HERE << "closing FD " << serverConnection()->fd);
00ae51e4 277 serverConn->close();
b6b6f466 278 }
fc68f6b1 279
c33a88ca 280 serverDestinations.clear();
cfd66529 281
b6b6f466 282 debugs(17, 3, HERE << "FwdState destructor done");
283}
62e76326 284
38413773 285/**
b6b6f466 286 * This is the entry point for client-side to start forwarding
287 * a transaction. It is a static method that may or may not
288 * allocate a FwdState.
289 */
be0c6690 290void
4bf68cfa 291FwdState::Start(const Comm::ConnectionPointer &clientConn, StoreEntry *entry, HttpRequest *request, const AccessLogEntryPointer &al)
b6b6f466 292{
b50e327b 293 /** \note
b6b6f466 294 * client_addr == no_addr indicates this is an "internal" request
295 * from peer_digest.c, asn.c, netdb.c, etc and should always
296 * be allowed. yuck, I know.
297 */
62e76326 298
4dd643d5 299 if ( Config.accessList.miss && !request->client_addr.isNoAddr() &&
39a19cb7 300 request->protocol != AnyP::PROTO_INTERNAL && request->protocol != AnyP::PROTO_CACHE_OBJECT) {
b50e327b 301 /**
fbd3636b
NR
302 * Check if this host is allowed to fetch MISSES from us (miss_access).
303 * Intentionally replace the src_addr automatically selected by the checklist code
304 * we do NOT want the indirect client address to be tested here.
b6b6f466 305 */
c0941a6a 306 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
b6b6f466 307 ch.src_addr = request->client_addr;
2efeb0b7 308 if (ch.fastCheck() == ACCESS_DENIED) {
b6b6f466 309 err_type page_id;
9ce7856a 310 page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName, 1);
b6b6f466 311
312 if (page_id == ERR_NONE)
313 page_id = ERR_FORWARDING_DENIED;
314
955394ce 315 ErrorState *anErr = new ErrorState(page_id, Http::scForbidden, request);
b6b6f466 316 errorAppendEntry(entry, anErr); // frees anErr
be0c6690 317 return;
b6b6f466 318 }
319 }
320
cfd66529 321 debugs(17, 3, HERE << "'" << entry->url() << "'");
f4ef658f 322 /*
323 * This seems like an odd place to bind mem_obj and request.
324 * Might want to assert that request is NULL at this point
325 */
b248c2a3
AJ
326 entry->mem_obj->request = request;
327 HTTPMSGLOCK(entry->mem_obj->request);
b6b6f466 328#if URL_CHECKSUM_DEBUG
329
330 entry->mem_obj->checkUrlChecksum();
331#endif
332
333 if (shutting_down) {
334 /* more yuck */
955394ce 335 ErrorState *anErr = new ErrorState(ERR_SHUTTING_DOWN, Http::scServiceUnavailable, request);
b6b6f466 336 errorAppendEntry(entry, anErr); // frees anErr
be0c6690 337 return;
6801f8a8 338 }
62e76326 339
b6b6f466 340 switch (request->protocol) {
341
0c3d3f65 342 case AnyP::PROTO_INTERNAL:
e37bd29b 343 internalStart(clientConn, request, entry);
be0c6690 344 return;
b6b6f466 345
39a19cb7 346 case AnyP::PROTO_CACHE_OBJECT:
5c336a3b 347 CacheManager::GetInstance()->Start(clientConn, request, entry);
be0c6690 348 return;
b6b6f466 349
0c3d3f65 350 case AnyP::PROTO_URN:
b6b6f466 351 urnStart(request, entry);
be0c6690 352 return;
b6b6f466 353
354 default:
4bf68cfa 355 FwdState::Pointer fwd = new FwdState(clientConn, entry, request, al);
7a0fb323 356 fwd->start(fwd);
be0c6690 357 return;
b6b6f466 358 }
359
360 /* NOTREACHED */
41462d93 361}
362
4bf68cfa
AR
363void
364FwdState::fwdStart(const Comm::ConnectionPointer &clientConn, StoreEntry *entry, HttpRequest *request)
365{
366 // Hides AccessLogEntry.h from code that does not supply ALE anyway.
367 Start(clientConn, entry, request, NULL);
368}
369
cfd66529 370void
6b679a01 371FwdState::startConnectionOrFail()
cfd66529 372{
8652f8e7 373 debugs(17, 3, HERE << entry->url());
cfd66529 374
00ae51e4 375 if (serverDestinations.size() > 0) {
8652f8e7
AJ
376 // Ditch error page if it was created before.
377 // A new one will be created if there's another problem
913524f0
AJ
378 delete err;
379 err = NULL;
8652f8e7
AJ
380
381 // Update the logging information about this new server connection.
382 // Done here before anything else so the errors get logged for
383 // this server link regardless of what happens when connecting to it.
384 // IF sucessfuly connected this top destination will become the serverConnection().
385 request->hier.note(serverDestinations[0], request->GetHost());
129fe2a1 386 request->clearError();
8652f8e7 387
cfd66529
AJ
388 connectStart();
389 } else {
95b83010
CT
390 debugs(17, 3, HERE << "Connection failed: " << entry->url());
391 if (!err) {
955394ce 392 ErrorState *anErr = new ErrorState(ERR_CANNOT_FORWARD, Http::scInternalServerError, request);
95b83010 393 fail(anErr);
8652f8e7 394 } // else use actual error from last connection attempt
cfd66529
AJ
395 self = NULL; // refcounted
396 }
397}
398
b6b6f466 399void
400FwdState::fail(ErrorState * errorState)
401{
9b769c67 402 debugs(17, 3, err_type_str[errorState->type] << " \"" << Http::StatusCodeString(errorState->httpStatus) << "\"\n\t" << entry->url());
b6b6f466 403
913524f0 404 delete err;
b6b6f466 405 err = errorState;
406
b248c2a3
AJ
407 if (!errorState->request) {
408 errorState->request = request;
409 HTTPMSGLOCK(errorState->request);
410 }
64b66b76 411
693cb033
CT
412 if (err->type != ERR_ZERO_SIZE_OBJECT)
413 return;
414
415 if (pconnRace == racePossible) {
bc81ee68
AR
416 debugs(17, 5, HERE << "pconn race happened");
417 pconnRace = raceHappened;
418 }
693cb033
CT
419
420 if (ConnStateData *pinned_connection = request->pinnedConnection()) {
421 pinned_connection->pinning.zeroReply = true;
422 flags.dont_retry = true; // we want to propagate failure to the client
423 debugs(17, 4, "zero reply on pinned connection");
424 }
b6b6f466 425}
426
38413773 427/**
b6b6f466 428 * Frees fwdState without closing FD or generating an abort
429 */
430void
00ae51e4 431FwdState::unregister(Comm::ConnectionPointer &conn)
5229395c
AJ
432{
433 debugs(17, 3, HERE << entry->url() );
434 assert(serverConnection() == conn);
6b679a01 435 assert(Comm::IsConnOpen(conn));
5229395c 436 comm_remove_close_handler(conn->fd, fwdServerClosedWrapper, this);
00ae51e4 437 serverConn = NULL;
5229395c
AJ
438}
439
440// Legacy method to be removed in favor of the above as soon as possible
441void
b6b6f466 442FwdState::unregister(int fd)
443{
5229395c
AJ
444 debugs(17, 3, HERE << entry->url() );
445 assert(fd == serverConnection()->fd);
00ae51e4 446 unregister(serverConn);
b6b6f466 447}
448
38413773 449/**
b6b6f466 450 * server-side modules call fwdComplete() when they are done
451 * downloading an object. Then, we either 1) re-forward the
452 * request somewhere else if needed, or 2) call storeComplete()
453 * to finish it off
454 */
455void
456FwdState::complete()
457{
9b769c67 458 debugs(17, 3, HERE << entry->url() << "\n\tstatus " << entry->getReply()->sline.status());
b6b6f466 459#if URL_CHECKSUM_DEBUG
460
461 entry->mem_obj->checkUrlChecksum();
462#endif
463
9b769c67 464 logReplyStatus(n_tries, entry->getReply()->sline.status());
b6b6f466 465
466 if (reforward()) {
9b769c67 467 debugs(17, 3, HERE << "re-forwarding " << entry->getReply()->sline.status() << " " << entry->url());
b6b6f466 468
6b679a01 469 if (Comm::IsConnOpen(serverConn))
00ae51e4 470 unregister(serverConn);
b6b6f466 471
cfd66529
AJ
472 entry->reset();
473
8652f8e7 474 // drop the last path off the selection list. try the next one.
523c3de3 475 serverDestinations.erase(serverDestinations.begin());
8652f8e7
AJ
476 startConnectionOrFail();
477
b6b6f466 478 } else {
6b679a01 479 if (Comm::IsConnOpen(serverConn))
9b769c67 480 debugs(17, 3, HERE << "server FD " << serverConnection()->fd << " not re-forwarding status " << entry->getReply()->sline.status());
6b679a01 481 else
9b769c67 482 debugs(17, 3, HERE << "server (FD closed) not re-forwarding status " << entry->getReply()->sline.status());
9e5c22cf
AJ
483 EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
484 entry->complete();
fc68f6b1 485
6b679a01 486 if (!Comm::IsConnOpen(serverConn))
fc68f6b1 487 completed();
488
7a0fb323 489 self = NULL; // refcounted
b6b6f466 490 }
491}
492
b6b6f466 493/**** CALLBACK WRAPPERS ************************************************************/
494
495static void
a37fdd8a 496fwdPeerSelectionCompleteWrapper(Comm::ConnectionList * unused, ErrorState *err, void *data)
b6b6f466 497{
498 FwdState *fwd = (FwdState *) data;
a37fdd8a
AJ
499 if (err)
500 fwd->fail(err);
6b679a01 501 fwd->startConnectionOrFail();
b6b6f466 502}
503
504static void
575d05c4 505fwdServerClosedWrapper(const CommCloseCbParams &params)
b6b6f466 506{
575d05c4
AJ
507 FwdState *fwd = (FwdState *)params.data;
508 fwd->serverClosed(params.fd);
b6b6f466 509}
510
cb4f4424 511#if USE_OPENSSL
b6b6f466 512static void
513fwdNegotiateSSLWrapper(int fd, void *data)
514{
515 FwdState *fwd = (FwdState *) data;
516 fwd->negotiateSSL(fd);
517}
518
519#endif
520
cfd66529 521void
f01d4b80 522fwdConnectDoneWrapper(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
b6b6f466 523{
524 FwdState *fwd = (FwdState *) data;
aed188fd 525 fwd->connectDone(conn, status, xerrno);
b6b6f466 526}
527
528/**** PRIVATE *****************************************************************/
529
545782b8 530/*
531 * FwdState::checkRetry
26ac0430 532 *
545782b8 533 * Return TRUE if the request SHOULD be retried. This method is
534 * called when the HTTP connection fails, or when the connection
535 * is closed before server-side read the end of HTTP headers.
536 */
b6b6f466 537bool
538FwdState::checkRetry()
68bd6892 539{
d8fd0f18 540 if (shutting_down)
b6b6f466 541 return false;
62e76326 542
9d2760b6
AR
543 if (!self) { // we have aborted before the server called us back
544 debugs(17, 5, HERE << "not retrying because of earlier abort");
545 // we will be destroyed when the server clears its Pointer to us
546 return false;
547 }
548
b6b6f466 549 if (entry->store_status != STORE_PENDING)
550 return false;
62e76326 551
b6b6f466 552 if (!entry->isEmpty())
553 return false;
62e76326 554
23a1e39c 555 if (n_tries > Config.forward_max_tries)
b6b6f466 556 return false;
4ed0e075 557
b6b6f466 558 if (squid_curtime - start_t > Config.Timeout.forward)
559 return false;
62e76326 560
b6b6f466 561 if (flags.dont_retry)
562 return false;
62e76326 563
3b9899f7
AR
564 if (request->bodyNibbled())
565 return false;
566
0bbd5532
AJ
567 // NP: not yet actually connected anywhere. retry is safe.
568 if (!flags.connected_okay)
569 return true;
570
5d4989a8 571 if (!checkRetriable())
572 return false;
573
b6b6f466 574 return true;
68bd6892 575}
576
545782b8 577/*
578 * FwdState::checkRetriable
579 *
580 * Return TRUE if this is the kind of request that can be retried
581 * after a failure. If the request is not retriable then we don't
582 * want to risk sending it on a persistent connection. Instead we'll
583 * force it to go on a new HTTP connection.
584 */
b6b6f466 585bool
586FwdState::checkRetriable()
cb928909 587{
ccbcff0e
AR
588 // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
589 // complicated] code required to protect the PUT request body from being
590 // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
591 if (request->body_pipe != NULL)
592 return false;
593
c2a7cefd
AJ
594 // RFC2616 9.1 Safe and Idempotent Methods
595 return (request->method.isHttpSafe() || request->method.isIdempotent());
cb928909 596}
597
b6b6f466 598void
599FwdState::serverClosed(int fd)
910169e5 600{
cfd66529 601 debugs(17, 2, HERE << "FD " << fd << " " << entry->url());
3e8c047e 602 retryOrBail();
603}
604
605void
26ac0430
AJ
606FwdState::retryOrBail()
607{
b6b6f466 608 if (checkRetry()) {
cfd66529 609 debugs(17, 3, HERE << "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
bc81ee68
AR
610 // we should retry the same destination if it failed due to pconn race
611 if (pconnRace == raceHappened)
612 debugs(17, 4, HERE << "retrying the same destination");
613 else
b181c1df 614 serverDestinations.erase(serverDestinations.begin()); // last one failed. try another.
8652f8e7
AJ
615 startConnectionOrFail();
616 return;
d8fd0f18 617 }
62e76326 618
9d2760b6
AR
619 // TODO: should we call completed() here and move doneWithRetries there?
620 doneWithRetries();
621
622 if (self != NULL && !err && shutting_down) {
955394ce 623 ErrorState *anErr = new ErrorState(ERR_SHUTTING_DOWN, Http::scServiceUnavailable, request);
f01d4b80 624 errorAppendEntry(entry, anErr);
f563eea9 625 }
62e76326 626
b6b6f466 627 self = NULL; // refcounted
910169e5 628}
629
9d2760b6
AR
630// If the Server quits before nibbling at the request body, the body sender
631// will not know (so that we can retry). Call this if we will not retry. We
632// will notify the sender so that it does not get stuck waiting for space.
633void
634FwdState::doneWithRetries()
635{
636 if (request && request->body_pipe != NULL)
637 request->body_pipe->expectNoConsumption();
638}
639
3e8c047e 640// called by the server that failed after calling unregister()
641void
642FwdState::handleUnregisteredServerEnd()
643{
cfd66529 644 debugs(17, 2, HERE << "self=" << self << " err=" << err << ' ' << entry->url());
6b679a01 645 assert(!Comm::IsConnOpen(serverConn));
3e8c047e 646 retryOrBail();
647}
648
cb4f4424 649#if USE_OPENSSL
b6b6f466 650void
651FwdState::negotiateSSL(int fd)
a7ad6e4e 652{
8e9bae99 653 unsigned long ssl_lib_error = SSL_ERROR_NONE;
a7ad6e4e 654 SSL *ssl = fd_table[fd].ssl;
655 int ret;
62e76326 656
a7ad6e4e 657 if ((ret = SSL_connect(ssl)) <= 0) {
62e76326 658 int ssl_error = SSL_get_error(ssl, ret);
8e9bae99
CT
659#ifdef EPROTO
660 int sysErrNo = EPROTO;
661#else
662 int sysErrNo = EACCES;
663#endif
62e76326 664
665 switch (ssl_error) {
666
667 case SSL_ERROR_WANT_READ:
d841c88d 668 Comm::SetSelect(fd, COMM_SELECT_READ, fwdNegotiateSSLWrapper, this, 0);
62e76326 669 return;
670
671 case SSL_ERROR_WANT_WRITE:
d841c88d 672 Comm::SetSelect(fd, COMM_SELECT_WRITE, fwdNegotiateSSLWrapper, this, 0);
62e76326 673 return;
674
8e9bae99
CT
675 case SSL_ERROR_SSL:
676 case SSL_ERROR_SYSCALL:
677 ssl_lib_error = ERR_get_error();
e0236918 678 debugs(81, DBG_IMPORTANT, "fwdNegotiateSSL: Error negotiating SSL connection on FD " << fd <<
8e9bae99 679 ": " << ERR_error_string(ssl_lib_error, NULL) << " (" << ssl_error <<
26ac0430 680 "/" << ret << "/" << errno << ")");
62e76326 681
8e9bae99
CT
682 // store/report errno when ssl_error is SSL_ERROR_SYSCALL, ssl_lib_error is 0, and ret is -1
683 if (ssl_error == SSL_ERROR_SYSCALL && ret == -1 && ssl_lib_error == 0)
684 sysErrNo = errno;
62e76326 685
8e9bae99
CT
686 // falling through to complete error handling
687
688 default:
e7a7152c
CT
689 // TODO: move into a method before merge
690 Ssl::ErrorDetail *errDetails;
4d16918e 691 Ssl::ErrorDetail *errFromFailure = (Ssl::ErrorDetail *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail);
e34763f4 692 if (errFromFailure != NULL) {
4d16918e
CT
693 // The errFromFailure is attached to the ssl object
694 // and will be released when ssl object destroyed.
7a957a93 695 // Copy errFromFailure to a new Ssl::ErrorDetail object.
e7a7152c 696 errDetails = new Ssl::ErrorDetail(*errFromFailure);
ef5fbcff 697 } else {
7a957a93 698 // server_cert can be NULL here
061bbdec 699 X509 *server_cert = SSL_get_peer_certificate(ssl);
de878a55 700 errDetails = new Ssl::ErrorDetail(SQUID_ERR_SSL_HANDSHAKE, server_cert, NULL);
061bbdec 701 X509_free(server_cert);
8e9bae99
CT
702 }
703
704 if (ssl_lib_error != SSL_ERROR_NONE)
e7a7152c 705 errDetails->setLibError(ssl_lib_error);
4d16918e 706
061bbdec 707 if (request->clientConnectionManager.valid()) {
7a957a93 708 // remember the server certificate from the ErrorDetail object
fd4624d7
CT
709 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
710 serverBump->serverCert.resetAndLock(errDetails->peerCert());
fb2178bb 711
7a957a93 712 // remember validation errors, if any
62a7607e 713 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors*>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
7a957a93 714 serverBump->sslErrors = cbdataReference(errs);
87f237a9 715 }
061bbdec 716
1b85f289
CT
717 // For intercepted connections, set the host name to the server
718 // certificate CN. Otherwise, we just hope that CONNECT is using
719 // a user-entered address (a host name or a user-entered IP).
720 const bool isConnectRequest = !request->clientConnectionManager->port->flags.isIntercepted();
721 if (request->flags.sslPeek && !isConnectRequest) {
722 if (X509 *srvX509 = errDetails->peerCert()) {
723 if (const char *name = Ssl::CommonHostName(srvX509)) {
724 request->SetHost(name);
725 debugs(83, 3, HERE << "reset request host: " << name);
726 }
2c065fc8
AR
727 }
728 }
e7a7152c 729 }
4d16918e 730
2c065fc8 731 ErrorState *const anErr = makeConnectingError(ERR_SECURE_CONNECT_FAIL);
e7a7152c
CT
732 anErr->xerrno = sysErrNo;
733 anErr->detail = errDetails;
b6b6f466 734 fail(anErr);
62e76326 735
5229395c
AJ
736 if (serverConnection()->getPeer()) {
737 peerConnectFailed(serverConnection()->getPeer());
62e76326 738 }
739
00ae51e4 740 serverConn->close();
62e76326 741 return;
742 }
a7ad6e4e 743 }
62e76326 744
fb2178bb 745 if (request->clientConnectionManager.valid()) {
7a957a93 746 // remember the server certificate from the ErrorDetail object
fd4624d7
CT
747 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
748 serverBump->serverCert.reset(SSL_get_peer_certificate(ssl));
749
7a957a93 750 // remember validation errors, if any
62a7607e 751 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
7a957a93 752 serverBump->sslErrors = cbdataReference(errs);
fd4624d7 753 }
fb2178bb 754 }
62e76326 755
5229395c
AJ
756 if (serverConnection()->getPeer() && !SSL_session_reused(ssl)) {
757 if (serverConnection()->getPeer()->sslSession)
758 SSL_SESSION_free(serverConnection()->getPeer()->sslSession);
f38c5e43 759
5229395c 760 serverConnection()->getPeer()->sslSession = SSL_get1_session(ssl);
f38c5e43 761 }
762
2cef0ca6 763 if (Ssl::TheConfig.ssl_crt_validator) {
b56756cb 764 Ssl::CertValidationRequest validationRequest;
14798e73
CT
765 // WARNING: Currently we do not use any locking for any of the
766 // members of the Ssl::CertValidationRequest class. In this code the
b56756cb 767 // Ssl::CertValidationRequest object used only to pass data to
2cef0ca6 768 // Ssl::CertValidationHelper::submit method.
14798e73 769 validationRequest.ssl = ssl;
b56756cb 770 validationRequest.domainName = request->GetHost();
62a7607e 771 if (Ssl::CertErrors *errs = static_cast<Ssl::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors)))
b56756cb
CT
772 // validationRequest disappears on return so no need to cbdataReference
773 validationRequest.errors = errs;
2cef0ca6 774 else
b56756cb 775 validationRequest.errors = NULL;
2cef0ca6 776 try {
4a77bb4e 777 debugs(83, 5, "Sending SSL certificate for validation to ssl_crtvd.");
14798e73 778 Ssl::CertValidationHelper::GetInstance()->sslSubmit(validationRequest, sslCrtvdHandleReplyWrapper, this);
2cef0ca6
AR
779 return;
780 } catch (const std::exception &e) {
4a77bb4e 781 debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtvd " <<
b56756cb 782 "request for " << validationRequest.domainName <<
2cef0ca6
AR
783 " certificate: " << e.what() << "; will now block to " <<
784 "validate that certificate.");
785 // fall through to do blocking in-process generation.
955394ce 786 ErrorState *anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request);
77dce8a5
CT
787 fail(anErr);
788 if (serverConnection()->getPeer()) {
789 peerConnectFailed(serverConnection()->getPeer());
790 }
791 serverConn->close();
792 self = NULL;
793 return;
2cef0ca6
AR
794 }
795 }
2cef0ca6 796
b6b6f466 797 dispatch();
a7ad6e4e 798}
799
2cef0ca6 800void
14798e73 801FwdState::sslCrtvdHandleReplyWrapper(void *data, Ssl::CertValidationResponse const &validationResponse)
2cef0ca6
AR
802{
803 FwdState * fwd = (FwdState *)(data);
14798e73 804 fwd->sslCrtvdHandleReply(validationResponse);
2cef0ca6
AR
805}
806
807void
14798e73 808FwdState::sslCrtvdHandleReply(Ssl::CertValidationResponse const &validationResponse)
2cef0ca6 809{
62a7607e 810 Ssl::CertErrors *errs = NULL;
2cef0ca6 811 Ssl::ErrorDetail *errDetails = NULL;
77dce8a5 812 bool validatorFailed = false;
2cef0ca6
AR
813 if (!Comm::IsConnOpen(serverConnection())) {
814 return;
815 }
2cef0ca6 816
14798e73
CT
817 debugs(83,5, request->GetHost() << " cert validation result: " << validationResponse.resultCode);
818
819 if (validationResponse.resultCode == HelperReply::Error)
820 errs = sslCrtvdCheckForErrors(validationResponse, errDetails);
821 else if (validationResponse.resultCode != HelperReply::Okay)
4a77bb4e 822 validatorFailed = true;
dd7167ea 823
14798e73
CT
824 if (!errDetails && !validatorFailed) {
825 dispatch();
826 return;
2cef0ca6 827 }
77dce8a5
CT
828
829 ErrorState *anErr = NULL;
830 if (validatorFailed) {
955394ce 831 anErr = new ErrorState(ERR_GATEWAY_FAILURE, Http::scInternalServerError, request);
77dce8a5
CT
832 } else {
833
834 // Check the list error with
835 if (errDetails && request->clientConnectionManager.valid()) {
836 // remember the server certificate from the ErrorDetail object
837 if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
838 // remember validation errors, if any
839 if (errs) {
840 if (serverBump->sslErrors)
268a2e8f 841 cbdataReferenceDone(serverBump->sslErrors);
77dce8a5
CT
842 serverBump->sslErrors = cbdataReference(errs);
843 }
2cef0ca6
AR
844 }
845 }
77dce8a5
CT
846
847 anErr = makeConnectingError(ERR_SECURE_CONNECT_FAIL);
848 anErr->detail = errDetails;
849 /*anErr->xerrno= Should preserved*/
2cef0ca6
AR
850 }
851
2cef0ca6
AR
852 fail(anErr);
853 if (serverConnection()->getPeer()) {
854 peerConnectFailed(serverConnection()->getPeer());
855 }
856 serverConn->close();
857 self = NULL;
858 return;
859}
268a2e8f 860
97538c72
AR
861/// Checks errors in the cert. validator response against sslproxy_cert_error.
862/// The first honored error, if any, is returned via errDetails parameter.
62a7607e
CT
863/// The method returns all seen errors except SSL_ERROR_NONE as Ssl::CertErrors.
864Ssl::CertErrors *
14798e73 865FwdState::sslCrtvdCheckForErrors(Ssl::CertValidationResponse const &resp, Ssl::ErrorDetail *& errDetails)
268a2e8f 866{
62a7607e 867 Ssl::CertErrors *errs = NULL;
268a2e8f 868
97538c72 869 ACLFilledChecklist *check = NULL;
268a2e8f
CT
870 if (acl_access *acl = Config.ssl_client.cert_error)
871 check = new ACLFilledChecklist(acl, request, dash_str);
872
97538c72 873 SSL *ssl = fd_table[serverConnection()->fd].ssl;
b56756cb 874 typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
97538c72 875 for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
268a2e8f
CT
876 debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
877
4a77bb4e 878 assert(i->error_no != SSL_ERROR_NONE);
268a2e8f 879
97538c72 880 if (!errDetails) {
268a2e8f
CT
881 bool allowed = false;
882 if (check) {
62a7607e 883 check->sslErrors = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get()));
268a2e8f
CT
884 if (check->fastCheck() == ACCESS_ALLOWED)
885 allowed = true;
886 }
887 // else the Config.ssl_client.cert_error access list is not defined
888 // and the first error will cause the error page
889
890 if (allowed) {
891 debugs(83, 3, "bypassing SSL error " << i->error_no << " in " << "buffer");
892 } else {
893 debugs(83, 5, "confirming SSL error " << i->error_no);
4a77bb4e
CT
894 X509 *brokenCert = i->cert.get();
895 Ssl::X509_Pointer peerCert(SSL_get_peer_certificate(ssl));
268a2e8f 896 const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
4a77bb4e 897 errDetails = new Ssl::ErrorDetail(i->error_no, peerCert.get(), brokenCert, aReason);
268a2e8f 898 }
7830d88a
FC
899 if (check) {
900 delete check->sslErrors;
901 check->sslErrors = NULL;
902 }
268a2e8f
CT
903 }
904
97538c72 905 if (!errs)
62a7607e 906 errs = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get()));
22636a68 907 else
62a7607e 908 errs->push_back_unique(Ssl::CertError(i->error_no, i->cert.get()));
268a2e8f 909 }
c732c598
CT
910 if (check)
911 delete check;
268a2e8f
CT
912
913 return errs;
914}
915
b6b6f466 916void
917FwdState::initiateSSL()
a7ad6e4e 918{
a7ad6e4e 919 SSL *ssl;
920 SSL_CTX *sslContext = NULL;
a3c6762c 921 const CachePeer *peer = serverConnection()->getPeer();
5229395c 922 int fd = serverConnection()->fd;
62e76326 923
a7ad6e4e 924 if (peer) {
62e76326 925 assert(peer->use_ssl);
926 sslContext = peer->sslContext;
a7ad6e4e 927 } else {
62e76326 928 sslContext = Config.ssl_client.sslContext;
a7ad6e4e 929 }
62e76326 930
a7ad6e4e 931 assert(sslContext);
62e76326 932
a7ad6e4e 933 if ((ssl = SSL_new(sslContext)) == NULL) {
e0236918 934 debugs(83, DBG_IMPORTANT, "fwdInitiateSSL: Error allocating handle: " << ERR_error_string(ERR_get_error(), NULL) );
955394ce 935 ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request);
129fe2a1 936 // TODO: create Ssl::ErrorDetail with OpenSSL-supplied error code
b6b6f466 937 fail(anErr);
938 self = NULL; // refcounted
62e76326 939 return;
a7ad6e4e 940 }
62e76326 941
a7ad6e4e 942 SSL_set_fd(ssl, fd);
62e76326 943
a7ad6e4e 944 if (peer) {
62e76326 945 if (peer->ssldomain)
946 SSL_set_ex_data(ssl, ssl_ex_index_server, peer->ssldomain);
947
a7ad6e4e 948#if NOT_YET
62e76326 949
950 else if (peer->name)
951 SSL_set_ex_data(ssl, ssl_ex_index_server, peer->name);
952
a7ad6e4e 953#endif
62e76326 954
955 else
956 SSL_set_ex_data(ssl, ssl_ex_index_server, peer->host);
f38c5e43 957
958 if (peer->sslSession)
959 SSL_set_session(ssl, peer->sslSession);
960
a7ad6e4e 961 } else {
53650ffa
CT
962 // While we are peeking at the certificate, we may not know the server
963 // name that the client will request (after interception or CONNECT)
35cd4281 964 // unless it was the CONNECT request with a user-typed address.
53650ffa
CT
965 const char *hostname = request->GetHost();
966 const bool hostnameIsIp = request->GetHostIsNumeric();
1b85f289
CT
967 const bool isConnectRequest = request->clientConnectionManager.valid() &&
968 !request->clientConnectionManager->port->flags.isIntercepted();
35cd4281 969 if (!request->flags.sslPeek || isConnectRequest)
2c065fc8
AR
970 SSL_set_ex_data(ssl, ssl_ex_index_server, (void*)hostname);
971
53650ffa 972 // Use SNI TLS extension only when we connect directly
7a957a93 973 // to the origin server and we know the server host name.
53650ffa
CT
974 if (!hostnameIsIp)
975 Ssl::setClientSNI(ssl, hostname);
a7ad6e4e 976 }
62e76326 977
2cef0ca6
AR
978 // If CertValidation Helper used do not lookup checklist for errors,
979 // but keep a list of errors to send it to CertValidator
980 if (!Ssl::TheConfig.ssl_crt_validator) {
2cef0ca6
AR
981 // Create the ACL check list now, while we have access to more info.
982 // The list is used in ssl_verify_cb() and is freed in ssl_free().
983 if (acl_access *acl = Config.ssl_client.cert_error) {
984 ACLFilledChecklist *check = new ACLFilledChecklist(acl, request, dash_str);
2cef0ca6
AR
985 SSL_set_ex_data(ssl, ssl_ex_index_cert_error_check, check);
986 }
4d5a6db8 987 }
988
e7bcc25f
CT
989 // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE
990 X509 *peeked_cert;
fd4624d7 991 if (request->clientConnectionManager.valid() &&
87f237a9
A
992 request->clientConnectionManager->serverBump() &&
993 (peeked_cert = request->clientConnectionManager->serverBump()->serverCert.get())) {
e7bcc25f
CT
994 CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509);
995 SSL_set_ex_data(ssl, ssl_ex_index_ssl_peeked_cert, peeked_cert);
996 }
997
a7ad6e4e 998 fd_table[fd].ssl = ssl;
999 fd_table[fd].read_method = &ssl_read_method;
1000 fd_table[fd].write_method = &ssl_write_method;
b6b6f466 1001 negotiateSSL(fd);
a7ad6e4e 1002}
62e76326 1003
a7ad6e4e 1004#endif
1005
b6b6f466 1006void
f01d4b80 1007FwdState::connectDone(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno)
41462d93 1008{
2f538b78 1009 if (status != COMM_OK) {
9c8a6c3b 1010 ErrorState *const anErr = makeConnectingError(ERR_CONNECT_FAIL);
b6b6f466 1011 anErr->xerrno = xerrno;
b6b6f466 1012 fail(anErr);
62e76326 1013
2f538b78 1014 /* it might have been a timeout with a partially open link */
00ae51e4
AJ
1015 if (conn != NULL) {
1016 if (conn->getPeer())
1017 peerConnectFailed(conn->getPeer());
62e76326 1018
80463bb4 1019 conn->close();
2f538b78 1020 }
aed188fd 1021 retryOrBail();
2f538b78
AJ
1022 return;
1023 }
62e76326 1024
00ae51e4 1025 serverConn = conn;
3b9899f7 1026 flags.connected_okay = true;
00ae51e4 1027
f01d4b80 1028 debugs(17, 3, HERE << serverConnection() << ": '" << entry->url() << "'" );
62e76326 1029
5229395c 1030 comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
2f538b78 1031
5229395c
AJ
1032 if (serverConnection()->getPeer())
1033 peerConnectSucceded(serverConnection()->getPeer());
2f538b78 1034
cb4f4424 1035#if USE_OPENSSL
693cb033 1036 if (!request->flags.pinned) {
39322eba 1037 if ((serverConnection()->getPeer() && serverConnection()->getPeer()->use_ssl) ||
37276dbb
AR
1038 (!serverConnection()->getPeer() && request->protocol == AnyP::PROTO_HTTPS) ||
1039 request->flags.sslPeek) {
39322eba
J
1040 initiateSSL();
1041 return;
1042 }
41462d93 1043 }
2f538b78
AJ
1044#endif
1045
1046 dispatch();
41462d93 1047}
1048
b6b6f466 1049void
1050FwdState::connectTimeout(int fd)
41462d93 1051{
bf8fe701 1052 debugs(17, 2, "fwdConnectTimeout: FD " << fd << ": '" << entry->url() << "'" );
6b679a01
AJ
1053 assert(serverDestinations[0] != NULL);
1054 assert(fd == serverDestinations[0]->fd);
62e76326 1055
528b2c61 1056 if (entry->isEmpty()) {
955394ce 1057 ErrorState *anErr = new ErrorState(ERR_CONNECT_FAIL, Http::scGateway_Timeout, request);
b6b6f466 1058 anErr->xerrno = ETIMEDOUT;
1059 fail(anErr);
62e76326 1060
cfd66529 1061 /* This marks the peer DOWN ... */
6b679a01
AJ
1062 if (serverDestinations[0]->getPeer())
1063 peerConnectFailed(serverDestinations[0]->getPeer());
41462d93 1064 }
62e76326 1065
6b679a01
AJ
1066 if (Comm::IsConnOpen(serverDestinations[0])) {
1067 serverDestinations[0]->close();
746beefe 1068 }
41462d93 1069}
1070
cfd66529 1071/**
ae18571d
AJ
1072 * Called after Forwarding path selection (via peer select) has taken place.
1073 * And whenever forwarding needs to attempt a new connection (routing failover)
1074 * We have a vector of possible localIP->remoteIP paths now ready to start being connected.
cfd66529 1075 */
b6b6f466 1076void
1077FwdState::connectStart()
41462d93 1078{
6b679a01
AJ
1079 assert(serverDestinations.size() > 0);
1080
cfd66529 1081 debugs(17, 3, "fwdConnectStart: " << entry->url());
62e76326 1082
a122fdeb 1083 if (!request->hier.first_conn_start.tv_sec) // first attempt
3ff65596
AR
1084 request->hier.first_conn_start = current_time;
1085
cfd66529
AJ
1086 /* connection timeout */
1087 int ctimeout;
6b679a01
AJ
1088 if (serverDestinations[0]->getPeer()) {
1089 ctimeout = serverDestinations[0]->getPeer()->connect_timeout > 0 ?
1090 serverDestinations[0]->getPeer()->connect_timeout : Config.Timeout.peer_connect;
db1cd23c 1091 } else {
62e76326 1092 ctimeout = Config.Timeout.connect;
db1cd23c 1093 }
62e76326 1094
cfd66529
AJ
1095 /* calculate total forwarding timeout ??? */
1096 int ftimeout = Config.Timeout.forward - (squid_curtime - start_t);
777831e0 1097 if (ftimeout < 0)
1098 ftimeout = 5;
1099
1100 if (ftimeout < ctimeout)
1101 ctimeout = ftimeout;
1102
450fe1cb 1103 if (serverDestinations[0]->getPeer() && request->flags.sslBumped) {
2cf8425b 1104 debugs(50, 4, "fwdConnectStart: Ssl bumped connections through parent proxy are not allowed");
955394ce 1105 ErrorState *anErr = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request);
b68415a1
CT
1106 fail(anErr);
1107 self = NULL; // refcounted
1108 return;
985bfe6b 1109 }
d67acb4e 1110
e857372a 1111 request->flags.pinned = false; // XXX: what if the ConnStateData set this to flag existing credentials?
2efeb0b7
AJ
1112 // XXX: answer: the peer selection *should* catch it and give us only the pinned peer. so we reverse the =0 step below.
1113 // XXX: also, logs will now lie if pinning is broken and leads to an error message.
6b679a01 1114 if (serverDestinations[0]->peerType == PINNED) {
26ac0430 1115 ConnStateData *pinned_connection = request->pinnedConnection();
693cb033 1116 debugs(17,7, "pinned peer connection: " << pinned_connection);
bc81ee68
AR
1117 // pinned_connection may become nil after a pconn race
1118 if (pinned_connection)
1119 serverConn = pinned_connection->validatePinnedConnection(request, serverDestinations[0]->getPeer());
1120 else
1121 serverConn = NULL;
e3a4aecc 1122 if (Comm::IsConnOpen(serverConn)) {
7ac40923 1123 pinned_connection->stopPinnedConnectionMonitoring();
3b9899f7 1124 flags.connected_okay = true;
95dc7ff4 1125 ++n_tries;
e857372a 1126 request->flags.pinned = true;
35894b9a 1127 request->hier.note(serverConn, pinned_connection->pinning.host);
d67acb4e 1128 if (pinned_connection->pinnedAuth())
e857372a 1129 request->flags.auth = true;
23211a9f 1130 comm_add_close_handler(serverConn->fd, fwdServerClosedWrapper, this);
bc81ee68
AR
1131 // the server may close the pinned connection before this request
1132 pconnRace = racePossible;
6b679a01 1133 dispatch();
d67acb4e
AJ
1134 return;
1135 }
693cb033 1136 // Pinned connection failure.
85563fd9 1137 debugs(17,2,HERE << "Pinned connection failed: " << pinned_connection);
955394ce 1138 ErrorState *anErr = new ErrorState(ERR_ZERO_SIZE_OBJECT, Http::scServiceUnavailable, request);
693cb033
CT
1139 fail(anErr);
1140 self = NULL; // refcounted
1141 return;
26ac0430 1142 }
d67acb4e 1143
642a305c 1144 // Use pconn to avoid opening a new connection.
7a150c71
AJ
1145 const char *host = NULL;
1146 if (!serverDestinations[0]->getPeer())
06093389 1147 host = request->GetHost();
bc81ee68
AR
1148
1149 Comm::ConnectionPointer temp;
1150 // Avoid pconns after races so that the same client does not suffer twice.
1151 // This does not increase the total number of connections because we just
1152 // closed the connection that failed the race. And re-pinning assumes this.
1153 if (pconnRace != raceHappened)
1154 temp = fwdPconnPool->pop(serverDestinations[0], host, checkRetriable());
bbf706ff 1155
bc81ee68
AR
1156 const bool openedPconn = Comm::IsConnOpen(temp);
1157 pconnRace = openedPconn ? racePossible : raceImpossible;
cfd66529 1158
6b679a01 1159 // if we found an open persistent connection to use. use it.
bc81ee68 1160 if (openedPconn) {
80463bb4 1161 serverConn = temp;
3b9899f7 1162 flags.connected_okay = true;
642a305c 1163 debugs(17, 3, HERE << "reusing pconn " << serverConnection());
95dc7ff4 1164 ++n_tries;
4ed0e075 1165
5229395c 1166 comm_add_close_handler(serverConnection()->fd, fwdServerClosedWrapper, this);
b5523edc
AJ
1167
1168 /* Update server side TOS and Netfilter mark on the connection. */
1169 if (Ip::Qos::TheConfig.isAclTosActive()) {
f123f5e9
CT
1170 const tos_t tos = GetTosToServer(request);
1171 Ip::Qos::setSockTos(temp, tos);
b5523edc
AJ
1172 }
1173#if SO_MARK
1174 if (Ip::Qos::TheConfig.isAclNfmarkActive()) {
f123f5e9
CT
1175 const nfmark_t nfmark = GetNfmarkToServer(request);
1176 Ip::Qos::setSockNfmark(temp, nfmark);
b5523edc
AJ
1177 }
1178#endif
1179
c8ceec27 1180 dispatch();
c8ceec27 1181 return;
41462d93 1182 }
62e76326 1183
bc81ee68
AR
1184 // We will try to open a new connection, possibly to the same destination.
1185 // We reset serverDestinations[0] in case we are using it again because
1186 // ConnOpener modifies its destination argument.
4dd643d5 1187 serverDestinations[0]->local.port(0);
bc81ee68
AR
1188 serverConn = NULL;
1189
bc87dc25 1190#if URL_CHECKSUM_DEBUG
b6b6f466 1191 entry->mem_obj->checkUrlChecksum();
bc87dc25 1192#endif
62e76326 1193
b5523edc
AJ
1194 /* Get the server side TOS and Netfilter mark to be set on the connection. */
1195 if (Ip::Qos::TheConfig.isAclTosActive()) {
1196 serverDestinations[0]->tos = GetTosToServer(request);
1197 }
11e8cfe3 1198#if SO_MARK && USE_LIBCAP
a750e510 1199 serverDestinations[0]->nfmark = GetNfmarkToServer(request);
25b481e6 1200 debugs(17, 3, "fwdConnectStart: got outgoing addr " << serverDestinations[0]->local << ", tos " << int(serverDestinations[0]->tos)
a750e510 1201 << ", netfilter mark " << serverDestinations[0]->nfmark);
425de4c8 1202#else
a750e510 1203 serverDestinations[0]->nfmark = 0;
25b481e6 1204 debugs(17, 3, "fwdConnectStart: got outgoing addr " << serverDestinations[0]->local << ", tos " << int(serverDestinations[0]->tos));
b5523edc
AJ
1205#endif
1206
e3a4aecc
AJ
1207 calls.connector = commCbCall(17,3, "fwdConnectDoneWrapper", CommConnectCbPtrFun(fwdConnectDoneWrapper, this));
1208 Comm::ConnOpener *cs = new Comm::ConnOpener(serverDestinations[0], calls.connector, ctimeout);
7a150c71
AJ
1209 if (host)
1210 cs->setHost(host);
855150a4 1211 AsyncJob::Start(cs);
41462d93 1212}
1213
b6b6f466 1214void
1215FwdState::dispatch()
41462d93 1216{
5c336a3b 1217 debugs(17, 3, HERE << clientConn << ": Fetching '" << RequestMethodStr(request->method) << " " << entry->url() << "'");
e0ebe27c 1218 /*
1219 * Assert that server_fd is set. This is to guarantee that fwdState
1220 * is attached to something and will be deallocated when server_fd
1221 * is closed.
1222 */
6b679a01 1223 assert(Comm::IsConnOpen(serverConn));
62e76326 1224
5229395c 1225 fd_note(serverConnection()->fd, entry->url());
62e76326 1226
5229395c 1227 fd_table[serverConnection()->fd].noteUse(fwdPconnPool);
62e76326 1228
a7ad6e4e 1229 /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
1230 assert(entry->ping_status != PING_WAITING);
62e76326 1231
1bfe9ade 1232 assert(entry->locked());
62e76326 1233
a7ad6e4e 1234 EBIT_SET(entry->flags, ENTRY_DISPATCHED);
62e76326 1235
cc192b50 1236 netdbPingSite(request->GetHost());
62e76326 1237
425de4c8 1238 /* Retrieves remote server TOS or MARK value, and stores it as part of the
7172612f 1239 * original client request FD object. It is later used to forward
425de4c8 1240 * remote server's TOS/MARK in the response to the client in case of a MISS.
7172612f 1241 */
425de4c8 1242 if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
b5523edc
AJ
1243 if (Comm::IsConnOpen(clientConn) && Comm::IsConnOpen(serverConnection())) {
1244 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
425de4c8 1245 /* Get the netfilter mark for the connection */
b5523edc 1246 Ip::Qos::getNfmarkFromServer(serverConnection(), clientFde);
425de4c8
AJ
1247 }
1248 }
1249
1250#if _SQUID_LINUX_
1251 /* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
1252 if (Ip::Qos::TheConfig.isHitTosActive()) {
b5523edc
AJ
1253 if (Comm::IsConnOpen(clientConn)) {
1254 fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
425de4c8 1255 /* Get the TOS value for the packet */
b5523edc 1256 Ip::Qos::getTosFromServer(serverConnection(), clientFde);
7172612f 1257 }
26ac0430 1258 }
7172612f
AJ
1259#endif
1260
cb4f4424 1261#if USE_OPENSSL
2c065fc8 1262 if (request->flags.sslPeek) {
d7ce0bcd 1263 CallJobHere1(17, 4, request->clientConnectionManager, ConnStateData,
061bbdec 1264 ConnStateData::httpsPeeked, serverConnection());
d7ce0bcd
AR
1265 unregister(serverConn); // async call owns it now
1266 complete(); // destroys us
1267 return;
061bbdec 1268 }
d7ce0bcd
AR
1269#endif
1270
5229395c 1271 if (serverConnection()->getPeer() != NULL) {
95dc7ff4 1272 ++ serverConnection()->getPeer()->stats.fetches;
5229395c
AJ
1273 request->peer_login = serverConnection()->getPeer()->login;
1274 request->peer_domain = serverConnection()->getPeer()->domain;
b6b6f466 1275 httpStart(this);
41462d93 1276 } else {
2c065fc8 1277 assert(!request->flags.sslPeek);
b6b6f466 1278 request->peer_login = NULL;
1279 request->peer_domain = NULL;
62e76326 1280
1281 switch (request->protocol) {
cb4f4424 1282#if USE_OPENSSL
62e76326 1283
0c3d3f65 1284 case AnyP::PROTO_HTTPS:
b6b6f466 1285 httpStart(this);
62e76326 1286 break;
a7ad6e4e 1287#endif
62e76326 1288
0c3d3f65 1289 case AnyP::PROTO_HTTP:
b6b6f466 1290 httpStart(this);
62e76326 1291 break;
1292
0c3d3f65 1293 case AnyP::PROTO_GOPHER:
b6b6f466 1294 gopherStart(this);
62e76326 1295 break;
1296
0c3d3f65 1297 case AnyP::PROTO_FTP:
b6b6f466 1298 ftpStart(this);
62e76326 1299 break;
1300
39a19cb7 1301 case AnyP::PROTO_CACHE_OBJECT:
62e76326 1302
0c3d3f65 1303 case AnyP::PROTO_INTERNAL:
62e76326 1304
0c3d3f65 1305 case AnyP::PROTO_URN:
62e76326 1306 fatal_dump("Should never get here");
1307 break;
1308
0c3d3f65 1309 case AnyP::PROTO_WHOIS:
b6b6f466 1310 whoisStart(this);
62e76326 1311 break;
1312
0c3d3f65 1313 case AnyP::PROTO_WAIS: /* Not implemented */
fc68f6b1 1314
62e76326 1315 default:
7be06178 1316 debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'.");
955394ce 1317 ErrorState *anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request);
b6b6f466 1318 fail(anErr);
7be06178 1319 // Set the dont_retry flag because this is not a transient (network) error.
e857372a 1320 flags.dont_retry = true;
6b679a01 1321 if (Comm::IsConnOpen(serverConn)) {
00ae51e4 1322 serverConn->close();
746beefe 1323 }
62e76326 1324 break;
1325 }
41462d93 1326 }
1327}
1328
545782b8 1329/*
1330 * FwdState::reforward
1331 *
1332 * returns TRUE if the transaction SHOULD be re-forwarded to the
8bbb16e3 1333 * next choice in the serverDestinations list. This method is called when
545782b8 1334 * server-side communication completes normally, or experiences
1335 * some error after receiving the end of HTTP headers.
1336 */
b6b6f466 1337int
1338FwdState::reforward()
db1cd23c 1339{
b6b6f466 1340 StoreEntry *e = entry;
c4a88a3e
CT
1341
1342 if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
1343 debugs(17, 3, HERE << "entry aborted");
1344 return 0;
1345 }
1346
db1cd23c 1347 assert(e->store_status == STORE_PENDING);
1348 assert(e->mem_obj);
bc87dc25 1349#if URL_CHECKSUM_DEBUG
62e76326 1350
528b2c61 1351 e->mem_obj->checkUrlChecksum();
bc87dc25 1352#endif
62e76326 1353
cfd66529 1354 debugs(17, 3, HERE << e->url() << "?" );
62e76326 1355
d6eb18d6 1356 if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
cfd66529 1357 debugs(17, 3, HERE << "No, ENTRY_FWD_HDR_WAIT isn't set");
62e76326 1358 return 0;
d6eb18d6 1359 }
62e76326 1360
437823b4 1361 if (n_tries > Config.forward_max_tries)
62e76326 1362 return 0;
1363
58217e94 1364 if (request->bodyNibbled())
62e76326 1365 return 0;
1366
8652f8e7
AJ
1367 if (serverDestinations.size() <= 1) {
1368 // NP: <= 1 since total count includes the recently failed one.
cfd66529 1369 debugs(17, 3, HERE << "No alternative forwarding paths left");
62e76326 1370 return 0;
db1cd23c 1371 }
62e76326 1372
9b769c67 1373 const Http::StatusCode s = e->getReply()->sline.status();
cfd66529 1374 debugs(17, 3, HERE << "status " << s);
b6b6f466 1375 return reforwardableStatus(s);
db1cd23c 1376}
1377
2ac4f6b5
AR
1378/**
1379 * Create "503 Service Unavailable" or "504 Gateway Timeout" error depending
1380 * on whether this is a validation request. RFC 2616 says that we MUST reply
1381 * with "504 Gateway Timeout" if validation fails and cached reply has
1382 * proxy-revalidate, must-revalidate or s-maxage Cache-Control directive.
1383 */
1384ErrorState *
1385FwdState::makeConnectingError(const err_type type) const
1386{
450fe1cb 1387 return new ErrorState(type, request->flags.needValidation ?
955394ce 1388 Http::scGateway_Timeout : Http::scServiceUnavailable, request);
2ac4f6b5
AR
1389}
1390
b6b6f466 1391static void
1392fwdStats(StoreEntry * s)
64d8034e 1393{
b6b6f466 1394 int i;
1395 int j;
1396 storeAppendPrintf(s, "Status");
62e76326 1397
95dc7ff4
FC
1398 for (j = 1; j < MAX_FWD_STATS_IDX; ++j) {
1399 storeAppendPrintf(s, "\ttry#%d", j);
64d8034e 1400 }
64d8034e 1401
b6b6f466 1402 storeAppendPrintf(s, "\n");
0185bd6f 1403
955394ce 1404 for (i = 0; i <= (int) Http::scInvalidHeader; ++i) {
b6b6f466 1405 if (FwdReplyCodes[0][i] == 0)
1406 continue;
0185bd6f 1407
b6b6f466 1408 storeAppendPrintf(s, "%3d", i);
0185bd6f 1409
95dc7ff4 1410 for (j = 0; j <= MAX_FWD_STATS_IDX; ++j) {
b6b6f466 1411 storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]);
62e76326 1412 }
62e76326 1413
b6b6f466 1414 storeAppendPrintf(s, "\n");
e0ebe27c 1415 }
7197b20d 1416}
1417
b6b6f466 1418/**** STATIC MEMBER FUNCTIONS *************************************************/
db1cd23c 1419
b6b6f466 1420bool
955394ce 1421FwdState::reforwardableStatus(const Http::StatusCode s) const
db1cd23c 1422{
b6b6f466 1423 switch (s) {
62e76326 1424
955394ce 1425 case Http::scBadGateway:
62e76326 1426
955394ce 1427 case Http::scGateway_Timeout:
b6b6f466 1428 return true;
62e76326 1429
955394ce 1430 case Http::scForbidden:
62e76326 1431
955394ce 1432 case Http::scInternalServerError:
62e76326 1433
955394ce 1434 case Http::scNotImplemented:
62e76326 1435
955394ce 1436 case Http::scServiceUnavailable:
b6b6f466 1437 return Config.retry.onerror;
62e76326 1438
b6b6f466 1439 default:
1440 return false;
db1cd23c 1441 }
b6b6f466 1442
1443 /* NOTREACHED */
db1cd23c 1444}
8ddcc35d 1445
06093389
AJ
1446/**
1447 * Decide where details need to be gathered to correctly describe a persistent connection.
1448 * What is needed:
642a305c
AJ
1449 * - the address/port details about this link
1450 * - domain name of server at other end of this link (either peer or requested host)
06093389 1451 */
781ce8ff 1452void
642a305c 1453FwdState::pconnPush(Comm::ConnectionPointer &conn, const char *domain)
781ce8ff 1454{
642a305c 1455 if (conn->getPeer()) {
7a150c71 1456 fwdPconnPool->push(conn, NULL);
06093389 1457 } else {
642a305c 1458 fwdPconnPool->push(conn, domain);
06093389 1459 }
781ce8ff 1460}
1461
8ddcc35d 1462void
b6b6f466 1463FwdState::initModule()
8ddcc35d 1464{
6852be71 1465 RegisterWithCacheManager();
8ddcc35d 1466}
1467
62ee09ca 1468void
84f50787 1469FwdState::RegisterWithCacheManager(void)
62ee09ca 1470{
8822ebee 1471 Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
62ee09ca 1472}
1473
b6b6f466 1474void
955394ce 1475FwdState::logReplyStatus(int tries, const Http::StatusCode status)
8ddcc35d 1476{
955394ce 1477 if (status > Http::scInvalidHeader)
62e76326 1478 return;
1479
75eb730e 1480 assert(tries >= 0);
62e76326 1481
8ddcc35d 1482 if (tries > MAX_FWD_STATS_IDX)
62e76326 1483 tries = MAX_FWD_STATS_IDX;
1484
95dc7ff4 1485 ++ FwdReplyCodes[tries][status];
8ddcc35d 1486}
1487
b6b6f466 1488/**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
62e76326 1489
057f5854 1490/*
1491 * DPW 2007-05-19
1492 * Formerly static, but now used by client_side_request.cc
1493 */
425de4c8
AJ
1494/// Checks for a TOS value to apply depending on the ACL
1495tos_t
b6b6f466 1496aclMapTOS(acl_tos * head, ACLChecklist * ch)
b6a2f15e 1497{
b6b6f466 1498 acl_tos *l;
62e76326 1499
b6b6f466 1500 for (l = head; l; l = l->next) {
2efeb0b7 1501 if (!l->aclList || ch->fastCheck(l->aclList) == ACCESS_ALLOWED)
b6b6f466 1502 return l->tos;
1503 }
5894ad28 1504
b6b6f466 1505 return 0;
1506}
5894ad28 1507
425de4c8
AJ
1508/// Checks for a netfilter mark value to apply depending on the ACL
1509nfmark_t
1510aclMapNfmark(acl_nfmark * head, ACLChecklist * ch)
1511{
1512 acl_nfmark *l;
1513
1514 for (l = head; l; l = l->next) {
2efeb0b7 1515 if (!l->aclList || ch->fastCheck(l->aclList) == ACCESS_ALLOWED)
425de4c8
AJ
1516 return l->nfmark;
1517 }
1518
1519 return 0;
1520}
1521
cfd66529 1522void
f9b72e0c 1523getOutgoingAddress(HttpRequest * request, Comm::ConnectionPointer conn)
b6b6f466 1524{
07f889c1 1525 // skip if an outgoing address is already set.
4dd643d5 1526 if (!conn->local.isAnyAddr()) return;
cfd66529 1527
07f889c1 1528 // ensure that at minimum the wildcard local matches remote protocol
4dd643d5
AJ
1529 if (conn->remote.isIPv4())
1530 conn->local.setIPv4();
07f889c1 1531
cfd66529 1532 // maybe use TPROXY client address
450fe1cb 1533 if (request && request->flags.spoofClientIp) {
739b352a 1534 if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
96d64448
AJ
1535#if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
1536 if (Config.onoff.tproxy_uses_indirect_client)
45906573 1537 conn->local = request->indirect_client_addr;
96d64448
AJ
1538 else
1539#endif
45906573 1540 conn->local = request->client_addr;
cfd66529
AJ
1541 // some flags need setting on the socket to use this address
1542 conn->flags |= COMM_DOBIND;
1543 conn->flags |= COMM_TRANSPARENT;
1544 return;
1545 }
b0758e04
AJ
1546 // else no tproxy today ...
1547 }
c303f6e3 1548
b50e327b 1549 if (!Config.accessList.outgoing_address) {
cfd66529 1550 return; // anything will do.
b50e327b
AJ
1551 }
1552
c0941a6a 1553 ACLFilledChecklist ch(NULL, request, NULL);
739b352a 1554 ch.dst_peer = conn->getPeer();
cfd66529
AJ
1555 ch.dst_addr = conn->remote;
1556
1557 // TODO use the connection details in ACL.
1558 // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
6db78a1a 1559
0dc8ffa5 1560 AclAddress *l;
cfd66529
AJ
1561 for (l = Config.accessList.outgoing_address; l; l = l->next) {
1562
1563 /* check if the outgoing address is usable to the destination */
4dd643d5 1564 if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
cfd66529
AJ
1565
1566 /* check ACLs for this outgoing address */
2efeb0b7 1567 if (!l->aclList || ch.fastCheck(l->aclList) == ACCESS_ALLOWED) {
cfd66529
AJ
1568 conn->local = l->addr;
1569 return;
1570 }
1571 }
b6b6f466 1572}
62e76326 1573
425de4c8
AJ
1574tos_t
1575GetTosToServer(HttpRequest * request)
1576{
1577 ACLFilledChecklist ch(NULL, request, NULL);
425de4c8
AJ
1578 return aclMapTOS(Ip::Qos::TheConfig.tosToServer, &ch);
1579}
1580
1581nfmark_t
1582GetNfmarkToServer(HttpRequest * request)
b6b6f466 1583{
c0941a6a 1584 ACLFilledChecklist ch(NULL, request, NULL);
425de4c8 1585 return aclMapNfmark(Ip::Qos::TheConfig.nfmarkToServer, &ch);
b6a2f15e 1586}