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