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