FwdState.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 17 Request Forwarding */
10 
11 #include "squid.h"
12 #include "AccessLogEntry.h"
13 #include "acl/Address.h"
14 #include "acl/FilledChecklist.h"
15 #include "acl/Gadgets.h"
16 #include "anyp/PortCfg.h"
17 #include "base/AsyncCallbacks.h"
18 #include "base/AsyncCbdataCalls.h"
19 #include "CacheManager.h"
20 #include "CachePeer.h"
21 #include "client_side.h"
22 #include "clients/forward.h"
23 #include "clients/HttpTunneler.h"
24 #include "clients/WhoisGateway.h"
25 #include "comm/Connection.h"
26 #include "comm/ConnOpener.h"
27 #include "comm/Loops.h"
28 #include "CommCalls.h"
29 #include "errorpage.h"
30 #include "event.h"
31 #include "fd.h"
32 #include "fde.h"
33 #include "FwdState.h"
34 #include "globals.h"
35 #include "HappyConnOpener.h"
36 #include "hier_code.h"
37 #include "http.h"
38 #include "http/Stream.h"
39 #include "HttpReply.h"
40 #include "HttpRequest.h"
41 #include "icmp/net_db.h"
42 #include "internal.h"
43 #include "ip/Intercept.h"
44 #include "ip/NfMarkConfig.h"
45 #include "ip/QosConfig.h"
46 #include "ip/tools.h"
47 #include "MemObject.h"
48 #include "mgr/Registration.h"
49 #include "neighbors.h"
50 #include "pconn.h"
51 #include "PeerPoolMgr.h"
52 #include "ResolvedPeers.h"
54 #include "SquidConfig.h"
56 #include "Store.h"
57 #include "StoreClient.h"
58 #include "urn.h"
59 #if USE_OPENSSL
61 #include "ssl/Config.h"
62 #include "ssl/helper.h"
63 #include "ssl/ServerBump.h"
64 #include "ssl/support.h"
65 #else
67 #endif
68 
69 #include <cerrno>
70 
72 
73 static OBJH fwdStats;
74 
75 #define MAX_FWD_STATS_IDX 9
77 
78 PconnPool *fwdPconnPool = new PconnPool("server-peers", nullptr);
79 
81 
82 void
84 {
85  Pointer tmp = fwd; // Grab a temporary pointer to keep the object alive during our scope.
86 
87  if (Comm::IsConnOpen(fwd->serverConnection())) {
88  fwd->closeServerConnection("store entry aborted");
89  } else {
90  debugs(17, 7, "store entry aborted; no connection to close");
91  }
92  fwd->stopAndDestroy("store entry aborted");
93 }
94 
95 void
97 {
98  debugs(17, 3, "because " << reason << "; " << conn);
101  if (IsConnOpen(conn)) {
102  fwdPconnPool->noteUses(fd_table[conn->fd].pconn.uses);
103  conn->close();
104  }
105 }
106 
107 void
109 {
110  debugs(17, 3, "because " << reason << "; " << serverConn);
113  closeHandler = nullptr;
114  fwdPconnPool->noteUses(fd_table[serverConn->fd].pconn.uses);
115  serverConn->close();
116 }
117 
118 /**** PUBLIC INTERFACE ********************************************************/
119 
121  entry(e),
122  request(r),
123  al(alp),
124  err(nullptr),
125  clientConn(client),
126  start_t(squid_curtime),
127  n_tries(0),
128  waitingForDispatched(false),
129  destinations(new ResolvedPeers()),
130  pconnRace(raceImpossible),
131  storedWholeReply_(nullptr),
132  peeringTimer(r)
133 {
134  debugs(17, 2, "Forwarding client request " << client << ", url=" << e->url());
136  e->lock("FwdState");
137  flags.connected_okay = false;
138  flags.dont_retry = false;
139  flags.forward_completed = false;
140  flags.destinationsFound = false;
141  debugs(17, 3, "FwdState constructed, this=" << this);
142 }
143 
144 // Called once, right after object creation, when it is safe to set self
146 {
147  // Protect ourselves from being destroyed when the only Server pointing
148  // to us is gone (while we expect to talk to more Servers later).
149  // Once we set self, we are responsible for clearing it when we do not
150  // expect to talk to any servers.
151  self = aSelf; // refcounted
152 
153  // We hope that either the store entry aborts or peer is selected.
154  // Otherwise we are going to leak our object.
155 
156  // Ftp::Relay needs to preserve control connection on data aborts
157  // so it registers its own abort handler that calls ours when needed.
158  if (!request->flags.ftpNative) {
159  AsyncCall::Pointer call = asyncCall(17, 4, "FwdState::Abort", cbdataDialer(&FwdState::HandleStoreAbort, this));
161  }
162 
163  // just in case; should already be initialized to false
164  request->flags.pinned = false;
165 
166 #if STRICT_ORIGINAL_DST
167  // Bug 3243: CVE 2009-0801
168  // Bypass of browser same-origin access control in intercepted communication
169  // To resolve this we must force DIRECT and only to the original client destination.
170  const bool isIntercepted = request && !request->flags.redirected && (request->flags.intercepted || request->flags.interceptTproxy);
171  const bool useOriginalDst = Config.onoff.client_dst_passthru || (request && !request->flags.hostVerified);
172  if (isIntercepted && useOriginalDst) {
173  selectPeerForIntercepted();
174  return;
175  }
176 #endif
177 
178  // do full route options selection
180 }
181 
183 void
184 FwdState::stopAndDestroy(const char *reason)
185 {
186  debugs(17, 3, "for " << reason);
187 
188  cancelStep(reason);
189 
190  peeringTimer.stop();
191 
192  PeerSelectionInitiator::subscribed = false; // may already be false
193  self = nullptr; // we hope refcounting destroys us soon; may already be nil
194  /* do not place any code here as this object may be gone by now */
195 }
196 
200 void
201 FwdState::cancelStep(const char *reason)
202 {
203  transportWait.cancel(reason);
204  encryptionWait.cancel(reason);
205  peerWait.cancel(reason);
206 }
207 
208 #if STRICT_ORIGINAL_DST
209 void
211 FwdState::selectPeerForIntercepted()
212 {
213  // We do not support re-wrapping inside CONNECT.
214  // Our only alternative is to fake a noteDestination() call.
215 
216  // use pinned connection if available
217  if (ConnStateData *client = request->pinnedConnection()) {
218  // emulate the PeerSelector::selectPinned() "Skip ICP" effect
220 
221  usePinned();
222  return;
223  }
224 
225  // use client original destination as second preferred choice
226  const auto p = new Comm::Connection();
227  p->peerType = ORIGINAL_DST;
228  p->remote = clientConn->local;
230 
231  debugs(17, 3, "using client original destination: " << *p);
232  destinations->addPath(p);
235  useDestinations();
236 }
237 #endif
238 
240 void
242 {
243  if (!err || !al)
244  return;
245 
246  const auto lte = LogTagsErrors::FromErrno(err->type == ERR_READ_TIMEOUT ? ETIMEDOUT : err->xerrno);
247  al->cache.code.err.update(lte);
248  if (!err->detail) {
249  static const auto d = MakeNamedErrorDetail("WITH_SERVER");
250  err->detailError(d);
251  }
253 }
254 
255 void
257 {
258  if (flags.forward_completed) {
259  debugs(17, DBG_IMPORTANT, "ERROR: FwdState::completed called on a completed request! Bad!");
260  return;
261  }
262 
263  flags.forward_completed = true;
264 
266  debugs(17, 3, "entry aborted");
267  return ;
268  }
269 
270 #if URL_CHECKSUM_DEBUG
271 
272  entry->mem_obj->checkUrlChecksum();
273 #endif
274 
275  if (entry->store_status == STORE_PENDING) {
276  if (entry->isEmpty()) {
278  if (!err) // we quit (e.g., fd closed) before an error or content
280  assert(err);
283  err = nullptr;
284 #if USE_OPENSSL
288  // no flags.dont_retry: completed() is a post-reforward() act
289  }
290 #endif
291  } else {
292  updateAleWithFinalError(); // if any
293  if (storedWholeReply_)
295  else
296  entry->completeTruncated("FwdState default");
297  }
298  }
299 
300  if (storePendingNClients(entry) > 0)
302 
303 }
304 
306 {
307  debugs(17, 3, "FwdState destructor start");
308 
309  if (! flags.forward_completed)
310  completed();
311 
312  doneWithRetries();
313 
315 
316  delete err;
317 
318  entry->unregisterAbortCallback("FwdState object destructed");
319 
320  entry->unlock("FwdState");
321 
322  entry = nullptr;
323 
324  cancelStep("~FwdState");
325 
327  closeServerConnection("~FwdState");
328 
329  debugs(17, 3, "FwdState destructed, this=" << this);
330 }
331 
337 void
339 {
353  ch.al = al;
355  ch.syncAle(request, nullptr);
356  if (ch.fastCheck().denied()) {
357  auto page_id = FindDenyInfoPage(ch.currentAnswer(), true);
358  if (page_id == ERR_NONE)
359  page_id = ERR_FORWARDING_DENIED;
360 
361  const auto anErr = new ErrorState(page_id, Http::scForbidden, request, al);
362  errorAppendEntry(entry, anErr); // frees anErr
363  return;
364  }
365  }
366 
367  debugs(17, 3, "'" << entry->url() << "'");
368  /*
369  * This seems like an odd place to bind mem_obj and request.
370  * Might want to assert that request is NULL at this point
371  */
373 #if URL_CHECKSUM_DEBUG
374 
375  entry->mem_obj->checkUrlChecksum();
376 #endif
377 
378  if (shutting_down) {
379  /* more yuck */
381  errorAppendEntry(entry, anErr); // frees anErr
382  return;
383  }
384 
385  if (request->flags.internal) {
386  debugs(17, 2, "calling internalStart() due to request flag");
388  return;
389  }
390 
391  switch (request->url.getScheme()) {
392 
393  case AnyP::PROTO_URN:
395  return;
396 
397  default:
399  fwd->start(fwd);
400  return;
401  }
402 
403  /* NOTREACHED */
404 }
405 
406 void
408 {
409  // Hides AccessLogEntry.h from code that does not supply ALE anyway.
410  Start(clientConn, entry, request, nullptr);
411 }
412 
415 static inline time_t
416 diffOrZero(const time_t larger, const time_t smaller)
417 {
418  return (larger > smaller) ? (larger - smaller) : 0;
419 }
420 
422 time_t
423 FwdState::ForwardTimeout(const time_t fwdStart)
424 {
425  // time already spent on forwarding (0 if clock went backwards)
426  const time_t timeSpent = diffOrZero(squid_curtime, fwdStart);
427  return diffOrZero(Config.Timeout.forward, timeSpent);
428 }
429 
430 bool
431 FwdState::EnoughTimeToReForward(const time_t fwdStart)
432 {
433  return ForwardTimeout(fwdStart) > 0;
434 }
435 
436 void
438 {
439  if (!destinations->empty()) {
440  connectStart();
441  } else {
443  debugs(17, 4, "wait for more destinations to try");
444  return; // expect a noteDestination*() call
445  }
446 
447  debugs(17, 3, "Connection failed: " << entry->url());
448  if (!err) {
450  fail(anErr);
451  } // else use actual error from last connection attempt
452 
453  stopAndDestroy("tried all destinations");
454  }
455 }
456 
457 void
459 {
460  debugs(17, 3, errorState << "; was: " << err);
461 
462  delete err;
463  err = errorState;
464 
465  if (!errorState->request)
466  errorState->request = request;
467 
468  if (err->type == ERR_ZERO_SIZE_OBJECT)
470 
471  destinationReceipt = nullptr; // may already be nil
472 }
473 
475 void
477 {
479 
480  if (pconnRace == racePossible) {
481  debugs(17, 5, "pconn race happened");
483  if (destinationReceipt) {
485  destinationReceipt = nullptr;
486  }
487  }
488 
489  if (ConnStateData *pinned_connection = request->pinnedConnection()) {
490  pinned_connection->pinning.zeroReply = true;
491  debugs(17, 4, "zero reply on pinned connection");
492  }
493 }
494 
498 void
500 {
501  debugs(17, 3, entry->url() );
502  assert(serverConnection() == conn);
503  assert(Comm::IsConnOpen(conn));
505  closeHandler = nullptr;
506  serverConn = nullptr;
507  destinationReceipt = nullptr;
508 }
509 
510 // \deprecated use unregister(Comm::ConnectionPointer &conn) instead
511 void
513 {
514  debugs(17, 3, entry->url() );
515  assert(fd == serverConnection()->fd);
517 }
518 
525 void
527 {
528  const auto replyStatus = entry->mem().baseReply().sline.status();
529  debugs(17, 3, *entry << " status " << replyStatus << ' ' << entry->url());
530 #if URL_CHECKSUM_DEBUG
531 
532  entry->mem_obj->checkUrlChecksum();
533 #endif
534 
535  logReplyStatus(n_tries, replyStatus);
536 
537  // will already be false if complete() was called before/without dispatch()
538  waitingForDispatched = false;
539 
540  if (reforward()) {
541  debugs(17, 3, "re-forwarding " << replyStatus << " " << entry->url());
542 
545  serverConn = nullptr;
546  destinationReceipt = nullptr;
547 
548  storedWholeReply_ = nullptr;
549  entry->reset();
550 
551  useDestinations();
552 
553  } else {
555  debugs(17, 3, "server FD " << serverConnection()->fd << " not re-forwarding status " << replyStatus);
556  else
557  debugs(17, 3, "server (FD closed) not re-forwarding status " << replyStatus);
558 
559  completed();
560 
561  stopAndDestroy("forwarding completed");
562  }
563 }
564 
568 bool
570 {
572 }
573 
574 void
575 FwdState::markStoredReplyAsWhole(const char * const whyWeAreSure)
576 {
577  debugs(17, 5, whyWeAreSure << " for " << *entry);
578 
579  // the caller wrote everything to Store, but Store may silently abort writes
581  return;
582 
583  storedWholeReply_ = whyWeAreSure;
584 }
585 
586 void
588 {
589  flags.destinationsFound = true;
590 
591  if (!path) {
592  // We can call usePinned() without fear of clashing with an earlier
593  // forwarding attempt because PINNED must be the first destination.
595  usePinned();
596  return;
597  }
598 
599  debugs(17, 3, path);
600 
601  destinations->addPath(path);
602 
603  if (transportWait) {
604  assert(!transporting());
606  return; // and continue to wait for FwdState::noteConnection() callback
607  }
608 
609  if (transporting())
610  return; // and continue to receive destinations for backup
611 
612  useDestinations();
613 }
614 
615 void
617 {
620 
621  if (!flags.destinationsFound) {
622  if (selectionError) {
623  debugs(17, 3, "Will abort forwarding because path selection has failed.");
624  Must(!err); // if we tried to connect, then path selection succeeded
625  fail(selectionError);
626  }
627 
628  stopAndDestroy("path selection found no paths");
629  return;
630  }
631  // else continue to use one of the previously noted destinations;
632  // if all of them fail, forwarding as whole will fail
633  Must(!selectionError); // finding at least one path means selection succeeded
634 
635  if (transportWait) {
636  assert(!transporting());
638  return; // and continue to wait for FwdState::noteConnection() callback
639  }
640 
641  if (transporting()) {
642  // We are already using a previously opened connection (but were also
643  // receiving more destinations in case we need to re-forward).
644  debugs(17, 7, "keep transporting");
645  return;
646  }
647 
648  // destinationsFound, but none of them worked, and we were waiting for more
649  debugs(17, 7, "no more destinations to try after " << n_tries << " failed attempts");
650  if (!err) {
651  const auto finalError = new ErrorState(ERR_CANNOT_FORWARD, Http::scBadGateway, request, al);
652  static const auto d = MakeNamedErrorDetail("REFORWARD_TO_NONE");
653  finalError->detailError(d);
654  fail(finalError);
655  } // else use actual error from last forwarding attempt
656  stopAndDestroy("all found paths have failed");
657 }
658 
660 void
662 {
664  debugs(17, 7, "reusing pending notification about " << *destinations);
665  } else {
666  debugs(17, 7, "notifying about " << *destinations);
668  CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
669  }
670 }
671 
672 /**** CALLBACK WRAPPERS ************************************************************/
673 
674 static void
676 {
677  FwdState *fwd = (FwdState *)params.data;
678  fwd->serverClosed();
679 }
680 
681 /**** PRIVATE *****************************************************************/
682 
683 /*
684  * FwdState::checkRetry
685  *
686  * Return TRUE if the request SHOULD be retried. This method is
687  * called when the HTTP connection fails, or when the connection
688  * is closed before reading the end of HTTP headers from the server.
689  */
690 bool
692 {
693  if (shutting_down)
694  return false;
695 
696  if (!self) { // we have aborted before the server called us back
697  debugs(17, 5, "not retrying because of earlier abort");
698  // we will be destroyed when the server clears its Pointer to us
699  return false;
700  }
701 
703  return false;
704 
705  if (!entry->isEmpty())
706  return false;
707 
708  if (exhaustedTries())
709  return false;
710 
711  if (request->flags.pinned && !pinnedCanRetry())
712  return false;
713 
715  return false;
716 
717  if (flags.dont_retry)
718  return false;
719 
720  if (request->bodyNibbled())
721  return false;
722 
723  // NP: not yet actually connected anywhere. retry is safe.
724  if (!flags.connected_okay)
725  return true;
726 
727  if (!checkRetriable())
728  return false;
729 
730  return true;
731 }
732 
734 bool
736 {
737  // Optimize: A compliant proxy may retry PUTs, but Squid lacks the [rather
738  // complicated] code required to protect the PUT request body from being
739  // nibbled during the first try. Thus, Squid cannot retry some PUTs today.
740  if (request->body_pipe != nullptr)
741  return false;
742 
743  // RFC2616 9.1 Safe and Idempotent Methods
745 }
746 
747 void
749 {
750  // XXX: This method logic attempts to tolerate Connection::close() called
751  // for serverConn earlier, by one of our dispatch()ed jobs. If that happens,
752  // serverConn will already be closed here or, worse, it will already be open
753  // for the next forwarding attempt. The current code prevents us getting
754  // stuck, but the long term solution is to stop sharing serverConn.
755  debugs(17, 2, serverConn);
757  const auto uses = fd_table[serverConn->fd].pconn.uses;
758  debugs(17, 3, "prior uses: " << uses);
759  fwdPconnPool->noteUses(uses); // XXX: May not have come from fwdPconnPool
761  }
762  serverConn = nullptr;
763  closeHandler = nullptr;
764  destinationReceipt = nullptr;
765 
766  // will already be false if this closure happened before/without dispatch()
767  waitingForDispatched = false;
768 
769  retryOrBail();
770 }
771 
772 void
774 {
775  if (checkRetry()) {
776  debugs(17, 3, "re-forwarding (" << n_tries << " tries, " << (squid_curtime - start_t) << " secs)");
777  useDestinations();
778  return;
779  }
780 
781  // TODO: should we call completed() here and move doneWithRetries there?
782  doneWithRetries();
783 
784  if (self != nullptr && !err && shutting_down && entry->isEmpty()) {
786  errorAppendEntry(entry, anErr);
787  }
788 
789  stopAndDestroy("cannot retry");
790 }
791 
792 // If the Server quits before nibbling at the request body, the body sender
793 // will not know (so that we can retry). Call this if we will not retry. We
794 // will notify the sender so that it does not get stuck waiting for space.
795 void
797 {
798  if (request && request->body_pipe != nullptr)
800 }
801 
802 // called by the server that failed after calling unregister()
803 void
805 {
806  debugs(17, 2, "self=" << self << " err=" << err << ' ' << entry->url());
808  serverConn = nullptr;
809  destinationReceipt = nullptr;
810 
811  // might already be false due to uncertainties documented in serverClosed()
812  waitingForDispatched = false;
813 
814  retryOrBail();
815 }
816 
818 template <typename StepStart>
819 void
820 FwdState::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
821 {
822  // TODO: Extract destination-specific handling from FwdState so that all the
823  // awkward, limited-scope advanceDestination() calls can be replaced with a
824  // single simple try/catch,retry block.
825  try {
826  startStep();
827  // now wait for the step callback
828  } catch (...) {
829  debugs (17, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
830  closePendingConnection(conn, "connection preparation exception");
831  if (!err)
833  retryOrBail();
834  }
835 }
836 
839 void
841 {
843 
844  transportWait.finish();
845 
846  updateAttempts(answer.n_tries);
847 
848  ErrorState *error = nullptr;
849  if ((error = answer.error.get())) {
850  flags.dont_retry = true; // or HappyConnOpener would not have given up
851  syncHierNote(answer.conn, request->url.host());
852  Must(!Comm::IsConnOpen(answer.conn));
853  answer.error.clear(); // preserve error for errorSendComplete()
854  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
855  // The socket could get closed while our callback was queued. Sync
856  // Connection. XXX: Connection::fd may already be stale/invalid here.
857  // We do not know exactly why the connection got closed, so we play it
858  // safe, allowing retries only for persistent (reused) connections
859  if (answer.reused) {
860  destinationReceipt = answer.conn;
862  }
863  syncHierNote(answer.conn, request->url.host());
864  closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
866  } else {
867  assert(!error);
868  destinationReceipt = answer.conn;
870  // serverConn remains nil until syncWithServerConn()
871  }
872 
873  if (error) {
874  fail(error);
875  retryOrBail();
876  return;
877  }
878 
879  if (answer.reused) {
880  syncWithServerConn(answer.conn, request->url.host(), answer.reused);
881  return dispatch();
882  }
883 
884  // Check if we need to TLS before use
885  if (const auto *peer = answer.conn->getPeer()) {
886  // Assume that it is only possible for the client-first from the
887  // bumping modes to try connect to a remote server. The bumped
888  // requests with other modes are using pinned connections or fails.
889  const bool clientFirstBump = request->flags.sslBumped;
890  // We need a CONNECT tunnel to send encrypted traffic through a proxy,
891  // but we do not support TLS inside TLS, so we exclude HTTPS proxies.
892  const bool originWantsEncryptedTraffic =
894  request->flags.sslPeek ||
895  clientFirstBump;
896  if (originWantsEncryptedTraffic && // the "encrypted traffic" part
897  !peer->options.originserver && // the "through a proxy" part
898  !peer->secure.encryptTransport) // the "exclude HTTPS proxies" part
899  return advanceDestination("establish tunnel through proxy", answer.conn, [this,&answer] {
900  establishTunnelThruProxy(answer.conn);
901  });
902  }
903 
905 }
906 
907 void
909 {
910  const auto callback = asyncCallback(17, 4, FwdState::tunnelEstablishmentDone, this);
911  HttpRequest::Pointer requestPointer = request;
912  const auto tunneler = new Http::Tunneler(conn, requestPointer, callback, connectingTimeout(conn), al);
913 
914  // TODO: Replace this hack with proper Comm::Connection-Pool association
915  // that is not tied to fwdPconnPool and can handle disappearing pools.
916  tunneler->noteFwdPconnUse = true;
917 
918 #if USE_DELAY_POOLS
919  Must(conn);
920  Must(conn->getPeer());
921  if (!conn->getPeer()->options.no_delay)
922  tunneler->setDelayId(entry->mem_obj->mostBytesAllowed());
923 #endif
924  peerWait.start(tunneler, callback);
925 }
926 
928 void
930 {
931  peerWait.finish();
932 
933  ErrorState *error = nullptr;
934  if (!answer.positive()) {
935  Must(!answer.conn);
936  error = answer.squidError.get();
937  Must(error);
938  answer.squidError.clear(); // preserve error for fail()
939  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
940  // The socket could get closed while our callback was queued. Sync
941  // Connection. XXX: Connection::fd may already be stale/invalid here.
942  closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
944  } else if (!answer.leftovers.isEmpty()) {
945  // This should not happen because TLS servers do not speak first. If we
946  // have to handle this, then pass answer.leftovers via a PeerConnector
947  // to ServerBio. See ClientBio::setReadBufData().
948  static int occurrences = 0;
949  const auto level = (occurrences++ < 100) ? DBG_IMPORTANT : 2;
950  debugs(17, level, "ERROR: Early data after CONNECT response. " <<
951  "Found " << answer.leftovers.length() << " bytes. " <<
952  "Closing " << answer.conn);
954  closePendingConnection(answer.conn, "server spoke before tunnelEstablishmentDone");
955  }
956  if (error) {
957  fail(error);
958  retryOrBail();
959  return;
960  }
961 
963 }
964 
966 void
968 {
970 
971  const auto p = conn->getPeer();
972  const bool peerWantsTls = p && p->secure.encryptTransport;
973  // userWillTlsToPeerForUs assumes CONNECT == HTTPS
974  const bool userWillTlsToPeerForUs = p && p->options.originserver &&
976  const bool needTlsToPeer = peerWantsTls && !userWillTlsToPeerForUs;
977  const bool clientFirstBump = request->flags.sslBumped; // client-first (already) bumped connection
978  const bool needsBump = request->flags.sslPeek || clientFirstBump;
979 
980  // 'GET https://...' requests. If a peer is used the request is forwarded
981  // as is
982  const bool needTlsToOrigin = !p && request->url.getScheme() == AnyP::PROTO_HTTPS && !clientFirstBump;
983 
984  if (needTlsToPeer || needTlsToOrigin || needsBump) {
985  return advanceDestination("secure connection to peer", conn, [this,&conn] {
987  });
988  }
989 
990  // if not encrypting just run the post-connect actions
992 }
993 
995 void
997 {
998  HttpRequest::Pointer requestPointer = request;
999  const auto callback = asyncCallback(17, 4, FwdState::connectedToPeer, this);
1000  const auto sslNegotiationTimeout = connectingTimeout(conn);
1001  Security::PeerConnector *connector = nullptr;
1002 #if USE_OPENSSL
1003  if (request->flags.sslPeek)
1004  connector = new Ssl::PeekingPeerConnector(requestPointer, conn, clientConn, callback, al, sslNegotiationTimeout);
1005  else
1006 #endif
1007  connector = new Security::BlindPeerConnector(requestPointer, conn, callback, al, sslNegotiationTimeout);
1008  connector->noteFwdPconnUse = true;
1009  encryptionWait.start(connector, callback);
1010 }
1011 
1013 void
1015 {
1016  encryptionWait.finish();
1017 
1018  ErrorState *error = nullptr;
1019  if ((error = answer.error.get())) {
1020  assert(!answer.conn);
1021  answer.error.clear(); // preserve error for errorSendComplete()
1022  } else if (answer.tunneled) {
1023  assert(!answer.conn);
1024  // TODO: When ConnStateData establishes tunnels, its state changes
1025  // [in ways that may affect logging?]. Consider informing
1026  // ConnStateData about our tunnel or otherwise unifying tunnel
1027  // establishment [side effects].
1028  flags.dont_retry = true; // TunnelStateData took forwarding control
1029  entry->abort();
1030  complete(); // destroys us
1031  return;
1032  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1033  // The socket could get closed while our callback was queued. Sync
1034  // Connection. XXX: Connection::fd may already be stale/invalid here.
1035  closePendingConnection(answer.conn, "conn was closed while waiting for connectedToPeer");
1037  }
1038 
1039  if (error) {
1040  fail(error);
1041  retryOrBail();
1042  return;
1043  }
1044 
1046 }
1047 
1049 void
1051 {
1052  syncWithServerConn(conn, request->url.host(), false);
1053 
1054  // should reach ConnStateData before the dispatched Client job starts
1057 
1059 
1060  dispatch();
1061 }
1062 
1064 void
1065 FwdState::syncWithServerConn(const Comm::ConnectionPointer &conn, const char *host, const bool reused)
1066 {
1067  Must(IsConnOpen(conn));
1068  serverConn = conn;
1069  // no effect on destinationReceipt (which may even be nil here)
1070 
1072 
1073  if (reused) {
1076  } else {
1078  // Comm::ConnOpener already applied proper/current markings
1079  }
1080 
1081  syncHierNote(serverConn, host);
1082 }
1083 
1084 void
1086 {
1087  if (request)
1089  if (al)
1090  al->hier.resetPeerNotes(server, host);
1091 }
1092 
1094 void
1095 FwdState::updateAttempts(const int newValue)
1096 {
1097  Assure(n_tries <= newValue); // n_tries cannot decrease
1098 
1099  // Squid probably creates at most one FwdState/TunnelStateData object per
1100  // ALE, but, unlike an assignment would, this increment logic works even if
1101  // Squid uses multiple such objects for a given ALE in some esoteric cases.
1102  if (al)
1103  al->requestAttempts += (newValue - n_tries);
1104 
1105  n_tries = newValue;
1106  debugs(17, 5, n_tries);
1107 }
1108 
1114 void
1116 {
1117  debugs(17, 3, *destinations << " to " << entry->url());
1118 
1120 
1121  assert(!destinations->empty());
1122  assert(!transporting());
1123 
1124  // Ditch error page if it was created before.
1125  // A new one will be created if there's another problem
1126  delete err;
1127  err = nullptr;
1128  request->clearError();
1129 
1130  const auto callback = asyncCallback(17, 5, FwdState::noteConnection, this);
1131  HttpRequest::Pointer cause = request;
1132  const auto cs = new HappyConnOpener(destinations, callback, cause, start_t, n_tries, al);
1133  cs->setHost(request->url.host());
1134  bool retriable = checkRetriable();
1135  if (!retriable && Config.accessList.serverPconnForNonretriable) {
1137  ch.al = al;
1138  ch.syncAle(request, nullptr);
1139  retriable = ch.fastCheck().allowed();
1140  }
1141  cs->setRetriable(retriable);
1142  cs->allowPersistent(pconnRace != raceHappened);
1143  destinations->notificationPending = true; // start() is async
1144  transportWait.start(cs, callback);
1145 }
1146 
1148 void
1150 {
1151  const auto connManager = request->pinnedConnection();
1152  debugs(17, 7, "connection manager: " << connManager);
1153 
1154  try {
1155  // TODO: Refactor syncWithServerConn() and callers to always set
1156  // serverConn inside that method.
1158  debugs(17, 5, "connection: " << serverConn);
1159  } catch (ErrorState * const anErr) {
1160  syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1161  serverConn = nullptr;
1162  fail(anErr);
1163  // Connection managers monitor their idle pinned to-server
1164  // connections and close from-client connections upon seeing
1165  // a to-server connection closure. Retrying here is futile.
1166  stopAndDestroy("pinned connection failure");
1167  return;
1168  }
1169 
1170  updateAttempts(n_tries + 1);
1171 
1172  request->flags.pinned = true;
1173 
1174  assert(connManager);
1175  if (connManager->pinnedAuth())
1176  request->flags.auth = true;
1177 
1178  // the server may close the pinned connection before this request
1179  const auto reused = true;
1180  syncWithServerConn(serverConn, connManager->pinning.host, reused);
1181 
1182  dispatch();
1183 }
1184 
1185 void
1187 {
1188  debugs(17, 3, clientConn << ": Fetching " << request->method << ' ' << entry->url());
1189  /*
1190  * Assert that server_fd is set. This is to guarantee that fwdState
1191  * is attached to something and will be deallocated when server_fd
1192  * is closed.
1193  */
1195 
1197  waitingForDispatched = true;
1198 
1199  fd_note(serverConnection()->fd, entry->url());
1200 
1201  fd_table[serverConnection()->fd].noteUse();
1202 
1203  /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
1205 
1206  assert(entry->locked());
1207 
1209 
1210  flags.connected_okay = true;
1211 
1213 
1214  /* Retrieves remote server TOS or MARK value, and stores it as part of the
1215  * original client request FD object. It is later used to forward
1216  * remote server's TOS/MARK in the response to the client in case of a MISS.
1217  */
1218  if (Ip::Qos::TheConfig.isHitNfmarkActive()) {
1220  fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1221  /* Get the netfilter CONNMARK */
1223  }
1224  }
1225 
1226 #if _SQUID_LINUX_
1227  /* Bug 2537: The TOS forward part of QOS only applies to patched Linux kernels. */
1228  if (Ip::Qos::TheConfig.isHitTosActive()) {
1230  fde * clientFde = &fd_table[clientConn->fd]; // XXX: move the fd_table access into Ip::Qos
1231  /* Get the TOS value for the packet */
1233  }
1234  }
1235 #endif
1236 
1237 #if USE_OPENSSL
1238  if (request->flags.sslPeek) {
1239  // we were just asked to peek at the server, and we did that
1242  unregister(serverConn); // async call owns it now
1243  flags.dont_retry = true; // we gave up forwarding control
1244  entry->abort();
1245  complete(); // destroys us
1246  return;
1247  }
1248 #endif
1249 
1250  if (const auto peer = serverConnection()->getPeer()) {
1251  ++peer->stats.fetches;
1252  request->prepForPeering(*peer);
1253  httpStart(this);
1254  } else {
1257 
1258  switch (request->url.getScheme()) {
1259 
1260  case AnyP::PROTO_HTTPS:
1261  httpStart(this);
1262  break;
1263 
1264  case AnyP::PROTO_HTTP:
1265  httpStart(this);
1266  break;
1267 
1268  case AnyP::PROTO_FTP:
1269  if (request->flags.ftpNative)
1270  Ftp::StartRelay(this);
1271  else
1272  Ftp::StartGateway(this);
1273  break;
1274 
1275  case AnyP::PROTO_URN:
1276  fatal_dump("Should never get here");
1277  break;
1278 
1279  case AnyP::PROTO_WHOIS:
1280  whoisStart(this);
1281  break;
1282 
1283  case AnyP::PROTO_WAIS: /* Not implemented */
1284 
1285  default:
1286  debugs(17, DBG_IMPORTANT, "WARNING: Cannot retrieve '" << entry->url() << "'.");
1287  const auto anErr = new ErrorState(ERR_UNSUP_REQ, Http::scBadRequest, request, al);
1288  fail(anErr);
1289  // Set the dont_retry flag because this is not a transient (network) error.
1290  flags.dont_retry = true;
1292  serverConn->close(); // trigger cleanup
1293  }
1294  break;
1295  }
1296  }
1297 }
1298 
1299 /*
1300  * FwdState::reforward
1301  *
1302  * returns TRUE if the transaction SHOULD be re-forwarded to the
1303  * next choice in the serverDestinations list. This method is called when
1304  * peer communication completes normally, or experiences
1305  * some error after receiving the end of HTTP headers.
1306  */
1307 int
1309 {
1310  StoreEntry *e = entry;
1311 
1312  if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
1313  debugs(17, 3, "entry aborted");
1314  return 0;
1315  }
1316 
1318  assert(e->mem_obj);
1319 #if URL_CHECKSUM_DEBUG
1320 
1321  e->mem_obj->checkUrlChecksum();
1322 #endif
1323 
1324  debugs(17, 3, e->url() << "?" );
1325 
1326  if (request->flags.pinned && !pinnedCanRetry()) {
1327  debugs(17, 3, "pinned connection; cannot retry");
1328  return 0;
1329  }
1330 
1331  if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
1332  debugs(17, 3, "No, ENTRY_FWD_HDR_WAIT isn't set");
1333  return 0;
1334  }
1335 
1336  if (exhaustedTries())
1337  return 0;
1338 
1339  if (request->bodyNibbled())
1340  return 0;
1341 
1343  debugs(17, 3, "No alternative forwarding paths left");
1344  return 0;
1345  }
1346 
1347  const auto s = entry->mem().baseReply().sline.status();
1348  debugs(17, 3, "status " << s);
1349  return Http::IsReforwardableStatus(s);
1350 }
1351 
1352 // TODO: Refactor to fix multiple mgr:forward accounting/reporting bugs. See
1353 // https://lists.squid-cache.org/pipermail/squid-users/2024-December/027331.html
1354 static void
1356 {
1357  int i;
1358  int j;
1359  storeAppendPrintf(s, "Status");
1360 
1361  // XXX: Missing try#0 heading for FwdReplyCodes[0][i]
1362  for (j = 1; j <= MAX_FWD_STATS_IDX; ++j) {
1363  storeAppendPrintf(s, "\ttry#%d", j);
1364  }
1365 
1366  storeAppendPrintf(s, "\n");
1367 
1368  for (i = 0; i <= (int) Http::scInvalidHeader; ++i) {
1369  // XXX: Missing reporting of status codes for which logReplyStatus() was
1370  // only called with n_tries exceeding 1. To be more precise, we are
1371  // missing (the equivalent of) logReplyStatus() calls for attempts done
1372  // outside of FwdState. Relying on n_tries<=1 counters is too fragile.
1373  if (!FwdReplyCodes[0][i] && !FwdReplyCodes[1][i])
1374  continue;
1375 
1376  storeAppendPrintf(s, "%3d", i);
1377 
1378  // XXX: Missing FwdReplyCodes[0][i] reporting
1379  for (j = 1; j <= MAX_FWD_STATS_IDX; ++j) {
1380  storeAppendPrintf(s, "\t%d", FwdReplyCodes[j][i]);
1381  }
1382 
1383  storeAppendPrintf(s, "\n");
1384  }
1385 }
1386 
1387 /**** STATIC MEMBER FUNCTIONS *************************************************/
1388 
1389 void
1391 {
1393 }
1394 
1395 void
1397 {
1398  Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
1399 }
1400 
1401 void
1403 {
1404  if (status > Http::scInvalidHeader)
1405  return;
1406 
1407  assert(tries >= 0);
1408 
1409  if (tries > MAX_FWD_STATS_IDX)
1410  tries = MAX_FWD_STATS_IDX;
1411 
1412  ++ FwdReplyCodes[tries][status];
1413 }
1414 
1415 bool
1417 {
1418  return n_tries >= Config.forward_max_tries;
1419 }
1420 
1421 bool
1423 {
1425 
1426  // pconn race on pinned connection: Currently we do not have any mechanism
1427  // to retry current pinned connection path.
1428  if (pconnRace == raceHappened)
1429  return false;
1430 
1431  // If a bumped connection was pinned, then the TLS client was given our peer
1432  // details. Do not retry because we do not ensure that those details stay
1433  // constant. Step1-bumped connections do not get our TLS peer details, are
1434  // never pinned, and, hence, never reach this method.
1435  if (request->flags.sslBumped)
1436  return false;
1437 
1438  // The other pinned cases are FTP proxying and connection-based HTTP
1439  // authentication. TODO: Do these cases have restrictions?
1440  return true;
1441 }
1442 
1443 time_t
1445 {
1446  const auto connTimeout = conn->connectTimeout(start_t);
1447  return positiveTimeout(connTimeout);
1448 }
1449 
1450 /**** PRIVATE NON-MEMBER FUNCTIONS ********************************************/
1451 
1452 /*
1453  * DPW 2007-05-19
1454  * Formerly static, but now used by client_side_request.cc
1455  */
1457 tos_t
1459 {
1460  for (acl_tos *l = head; l; l = l->next) {
1461  if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1462  return l->tos;
1463  }
1464 
1465  return 0;
1466 }
1467 
1471 {
1472  for (acl_nfmark *l = head; l; l = l->next) {
1473  if (!l->aclList || ch->fastCheck(l->aclList).allowed())
1474  return l->markConfig;
1475  }
1476 
1477  return {};
1478 }
1479 
1480 void
1482 {
1483  // skip if an outgoing address is already set.
1484  if (!conn->local.isAnyAddr()) return;
1485 
1486  // ensure that at minimum the wildcard local matches remote protocol
1487  if (conn->remote.isIPv4())
1488  conn->local.setIPv4();
1489 
1490  // maybe use TPROXY client address
1491  if (request && request->flags.spoofClientIp) {
1492  if (!conn->getPeer() || !conn->getPeer()->options.no_tproxy) {
1493 #if FOLLOW_X_FORWARDED_FOR && LINUX_NETFILTER
1495  conn->local = request->indirect_client_addr;
1496  else
1497 #endif
1498  conn->local = request->client_addr;
1499  conn->local.port(0); // let OS pick the source port to prevent address clashes
1500  // some flags need setting on the socket to use this address
1501  conn->flags |= COMM_DOBIND;
1502  conn->flags |= COMM_TRANSPARENT;
1503  return;
1504  }
1505  // else no tproxy today ...
1506  }
1507 
1509  return; // anything will do.
1510  }
1511 
1512  ACLFilledChecklist ch(nullptr, request);
1513  ch.dst_peer_name = conn->getPeer() ? conn->getPeer()->name : nullptr;
1514  ch.dst_addr = conn->remote;
1515 
1516  // TODO use the connection details in ACL.
1517  // needs a bit of rework in ACLFilledChecklist to use Comm::Connection instead of ConnStateData
1518 
1519  for (Acl::Address *l = Config.accessList.outgoing_address; l; l = l->next) {
1520 
1521  /* check if the outgoing address is usable to the destination */
1522  if (conn->remote.isIPv4() != l->addr.isIPv4()) continue;
1523 
1524  /* check ACLs for this outgoing address */
1525  if (!l->aclList || ch.fastCheck(l->aclList).allowed()) {
1526  conn->local = l->addr;
1527  return;
1528  }
1529  }
1530 }
1531 
1533 static tos_t
1535 {
1536  if (!Ip::Qos::TheConfig.tosToServer)
1537  return 0;
1538 
1539  ACLFilledChecklist ch(nullptr, request);
1540  ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1541  ch.dst_addr = conn.remote;
1542  return aclMapTOS(Ip::Qos::TheConfig.tosToServer, &ch);
1543 }
1544 
1546 static nfmark_t
1548 {
1549  if (!Ip::Qos::TheConfig.nfmarkToServer)
1550  return 0;
1551 
1552  ACLFilledChecklist ch(nullptr, request);
1553  ch.dst_peer_name = conn.getPeer() ? conn.getPeer()->name : nullptr;
1554  ch.dst_addr = conn.remote;
1555  const auto mc = aclFindNfMarkConfig(Ip::Qos::TheConfig.nfmarkToServer, &ch);
1556  return mc.mark;
1557 }
1558 
1559 void
1561 {
1562  // Get the server side TOS and Netfilter mark to be set on the connection.
1563  conn.tos = GetTosToServer(request, conn);
1564  conn.nfmark = GetNfmarkToServer(request, conn);
1565  debugs(17, 3, "from " << conn.local << " tos " << int(conn.tos) << " netfilter mark " << conn.nfmark);
1566 }
1567 
1568 void
1570 {
1571  GetMarkingsToServer(request, conn);
1572 
1573  // TODO: Avoid these calls if markings has not changed.
1574  if (conn.tos)
1575  Ip::Qos::setSockTos(&conn, conn.tos);
1576  if (conn.nfmark)
1577  Ip::Qos::setSockNfmark(&conn, conn.nfmark);
1578 }
1579 
1580 /* PeeringActivityTimer */
1581 
1582 // The simple methods below are not inlined to avoid exposing some of the
1583 // current FwdState.h users to a full HttpRequest definition they do not need.
1584 
1586 {
1587  Assure(request);
1588  timer().resume();
1589 }
1590 
1592 {
1593  stop();
1594 }
1595 
1596 Stopwatch &
1598 {
1599  return request->hier.totalPeeringTime;
1600 }
1601 
bool bodyNibbled() const
Definition: HttpRequest.cc:440
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:159
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:952
JobPointer job() const
Definition: JobWait.h:76
bool tunneled
whether we spliced the connections instead of negotiating encryption
void noteConnection(HappyConnOpenerAnswer &)
Definition: FwdState.cc:840
Stopwatch & timer()
managed Stopwatch object within HierarchyLogEntry
Definition: FwdState.cc:1597
~PeeringActivityTimer()
pauses timer if stop() has not been called
Definition: FwdState.cc:1591
static OBJH fwdStats
Definition: FwdState.cc:73
#define MAX_FWD_STATS_IDX
Definition: FwdState.cc:75
Ip::Address dst_addr
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:70
@ ERR_READ_ERROR
Definition: forward.h:28
LogTagsErrors err
various problems augmenting the primary log tag
Definition: LogTags.h:87
BodyPipe::Pointer body_pipe
optional pipeline to receive message body
Definition: Message.h:97
Comm::ConnectionPointer serverConn
a successfully opened connection to a server.
Definition: FwdState.h:237
Acl::Address * outgoing_address
Definition: SquidConfig.h:380
struct squidaio_request_t * next
Definition: aiops.cc:51
bool spoofClientIp
Definition: RequestFlags.h:74
time_t start_t
Definition: FwdState.h:213
void unregisterAbortCallback(const char *reason)
Definition: store.cc:1489
void whoisStart(FwdState *fwd)
Definition: WhoisGateway.cc:56
@ ENTRY_DISPATCHED
Definition: enums.h:96
@ ERR_GATEWAY_FAILURE
Definition: forward.h:67
Ip::Address src_addr
@ scBadRequest
Definition: StatusCode.h:45
void reactToZeroSizeObject()
ERR_ZERO_SIZE_OBJECT requires special adjustments.
Definition: FwdState.cc:476
struct SquidConfig::@98 accessList
int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
Definition: QosConfig.cc:589
bool destinationsFinalized
whether all of the available candidate paths received from DNS
Definition: ResolvedPeers.h:82
JobWait< Http::Tunneler > peerWait
Definition: FwdState.h:231
@ Error
Definition: ResultCode.h:19
void fd_note(int fd, const char *s)
Definition: fd.cc:216
HttpRequestPointer request
the owner of managed HierarchyLogEntry
Definition: FwdState.h:77
CbcPointer< ErrorState > error
problem details (nil on success)
#define EBIT_SET(flag, bit)
Definition: defines.h:65
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:738
bool isEmpty() const
Definition: SBuf.h:435
MemObject * mem_obj
Definition: Store.h:220
RequestFlags flags
Definition: HttpRequest.h:141
CbcPointer< ErrorState > error
problem details (nil on success)
void clearError()
clear error details, useful for retries/repeats
Definition: HttpRequest.cc:465
static void initModule()
Definition: FwdState.cc:1390
void addPath(const Comm::ConnectionPointer &)
add a candidate path to try after all the existing paths
void update(const LogTagsErrors &other)
Definition: LogTags.cc:14
void syncWithServerConn(const Comm::ConnectionPointer &server, const char *host, const bool reused)
commits to using the given open to-peer connection
Definition: FwdState.cc:1065
const char * url() const
Definition: store.cc:1566
void updateError(const Error &)
sets (or updates the already stored) transaction error as needed
bool isAnyAddr() const
Definition: Address.cc:190
MemObject & mem()
Definition: Store.h:47
void useDestinations()
Definition: FwdState.cc:437
static CLCB fwdServerClosedWrapper
Definition: FwdState.cc:71
void secureConnectionToPeerIfNeeded(const Comm::ConnectionPointer &)
handles an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:967
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
void lock(const char *context)
Definition: store.cc:445
@ ENTRY_ABORTED
Definition: enums.h:110
void error(char *format,...)
unsigned int nfConnmarkFromServer
Definition: fde.h:171
AccessLogEntryPointer al
info for the future access.log entry
Definition: FwdState.h:204
bool isHttpSafe() const
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:330
@ ERR_UNSUP_REQ
Definition: forward.h:44
void getTosFromServer(const Comm::ConnectionPointer &server, fde *clientFde)
Definition: QosConfig.cc:47
int tproxy_uses_indirect_client
Definition: SquidConfig.h:330
acl_access * miss
Definition: SquidConfig.h:362
struct FwdState::@59 flags
@ PING_WAITING
Sent ICP queries to peers and still awaiting responses.
Definition: enums.h:38
void internalStart(const Comm::ConnectionPointer &clientConn, HttpRequest *request, StoreEntry *entry, const AccessLogEntry::Pointer &ale)
Definition: internal.cc:32
@ raceHappened
Definition: FwdState.h:243
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition: FwdState.h:224
time_t connectingTimeout(const Comm::ConnectionPointer &conn) const
Definition: FwdState.cc:1444
DelayId mostBytesAllowed() const
Definition: MemObject.cc:466
bool hostVerified
Definition: RequestFlags.h:68
PconnPool * fwdPconnPool
a collection of previously used persistent Squid-to-peer HTTP(S) connections
Definition: FwdState.cc:78
void noteUses(int uses)
Definition: pconn.cc:545
void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
starts a preparation step for an established connection; retries on failures
Definition: FwdState.cc:820
struct SquidConfig::@97 onoff
HierarchyLogEntry hier
void connectStart()
Definition: FwdState.cc:1115
unsigned char tos_t
Definition: forward.h:27
uint16_t flags
Definition: Store.h:231
void detailError(const ErrorDetail::Pointer &dCode)
set error type-specific detail code
Definition: errorpage.h:111
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ dirOpened
opened (by Squid to an origin server or peer)
Definition: QosConfig.h:72
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: FwdState.cc:1149
Http::StatusLine sline
Definition: HttpReply.h:56
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:150
void syncHierNote(const Comm::ConnectionPointer &server, const char *host)
Definition: FwdState.cc:1085
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: FwdState.cc:929
bool no_tproxy
Definition: CachePeer.h:145
@ ERR_NONE
Definition: forward.h:15
void cancelStep(const char *reason)
Definition: FwdState.cc:201
bool isIPv4() const
Definition: Address.cc:178
StatusCode
Definition: StatusCode.h:20
void unregister(Comm::ConnectionPointer &conn)
Definition: FwdState.cc:499
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:40
void fail(ErrorState *err)
Definition: FwdState.cc:458
Acl::Address * next
Definition: Address.h:28
A PeerConnector for HTTP origin servers. Capable of SslBumping.
acl_access * serverPconnForNonretriable
Definition: SquidConfig.h:405
static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Initiates request forwarding to a peer or origin server.
Definition: FwdState.cc:338
@ ORIGINAL_DST
Definition: hier_code.h:36
char * name
Definition: CachePeer.h:61
void reset()
Definition: store.cc:1621
const Acl::Answer & currentAnswer() const
Definition: Checklist.h:106
static time_t diffOrZero(const time_t larger, const time_t smaller)
Definition: FwdState.cc:416
bool isIdempotent() const
Definition: fde.h:51
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
static void RegisterWithCacheManager(void)
Definition: FwdState.cc:1396
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
static void HandleStoreAbort(FwdState *)
called by Store if the entry is no longer usable
Definition: FwdState.cc:83
@ racePossible
Definition: FwdState.h:243
bool empty() const
whether we lack any known candidate paths
Definition: ResolvedPeers.h:46
list of address-based ACLs.
Definition: Address.h:20
void getOutgoingAddress(HttpRequest *request, const Comm::ConnectionPointer &conn)
Definition: FwdState.cc:1481
err_type FindDenyInfoPage(const Acl::Answer &answer, const bool redirect_allowed)
Definition: Gadgets.cc:34
void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: FwdState.cc:587
void stopAndDestroy(const char *reason)
ends forwarding; relies on refcounting so the effect may not be immediate
Definition: FwdState.cc:184
@ PROTO_URN
Definition: ProtocolType.h:35
void closeServerConnection(const char *reason)
stops monitoring server connection for closure and updates pconn stats
Definition: FwdState.cc:108
#define COMM_TRANSPARENT
Definition: Connection.h:50
UnaryCbdataDialer< Argument1 > cbdataDialer(typename UnaryCbdataDialer< Argument1 >::Handler *handler, Argument1 *arg1)
Comm::ConnectionPointer conn
peer connection (secured on success)
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition: FwdState.cc:1416
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:182
time_t connectTimeout(const time_t fwdStart) const
Definition: Connection.cc:161
void OBJH(StoreEntry *)
Definition: forward.h:44
static nfmark_t GetNfmarkToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1547
@ scForbidden
Definition: StatusCode.h:48
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1569
void dispatch()
Definition: FwdState.cc:1186
bool pinnedCanRetry() const
Definition: FwdState.cc:1422
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
const HttpReply & baseReply() const
Definition: MemObject.h:60
void updateAleWithFinalError()
updates ALE when we finalize the transaction error (if any)
Definition: FwdState.cc:241
@ ENTRY_FWD_HDR_WAIT
Definition: enums.h:106
void abort()
Definition: store.cc:1077
const Comm::ConnectionPointer & serverConnection() const
Definition: FwdState.h:138
void doneWithRetries()
Definition: FwdState.cc:796
err_type type
Definition: errorpage.h:170
Ip::Address indirect_client_addr
Definition: HttpRequest.h:152
HttpRequestPointer request
Definition: errorpage.h:177
const Acl::Answer & fastCheck()
Definition: Checklist.cc:298
unsigned short port() const
Definition: Address.cc:798
@ scBadGateway
Definition: StatusCode.h:75
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:725
Ip::Address local
Definition: Connection.h:146
#define EBIT_TEST(flag, bit)
Definition: defines.h:67
CachePeer * getPeer() const
Definition: Connection.cc:121
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
ping_status_t ping_status
Definition: Store.h:241
void successfullyConnectedToPeer(const Comm::ConnectionPointer &)
called when all negotiations with the peer have been completed
Definition: FwdState.cc:1050
void httpsPeeked(PinnedIdleContext pic)
called by FwdState when it is done bumping the server
void updateAttempts(int)
sets n_tries to the given value (while keeping ALE, if any, in sync)
Definition: FwdState.cc:1095
@ METHOD_CONNECT
Definition: MethodType.h:29
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: FwdState.cc:908
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: FwdState.h:227
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:59
bool waitingForDispatched
whether we are waiting for the last dispatch()ed activity to end
Definition: FwdState.h:234
int unlock(const char *context)
Definition: store.cc:469
Comm::ConnectionPointer clientConn
a possibly open connection to the client.
Definition: FwdState.h:212
void noteDestinationsEnd(ErrorState *selectionError) override
Definition: FwdState.cc:616
bool denied() const
Definition: Acl.h:88
FwdState(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Definition: FwdState.cc:120
AsyncCall::Pointer closeHandler
The serverConn close handler.
Definition: FwdState.h:240
int n_tries
the number of forwarding attempts so far
Definition: FwdState.h:214
int client_dst_passthru
Definition: SquidConfig.h:338
Ip::Address remote
Definition: Connection.h:149
store_status_t store_status
Definition: Store.h:243
static tos_t GetTosToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1534
PeeringActivityTimer(const HttpRequestPointer &)
resumes timer
Definition: FwdState.cc:1585
@ ERR_ZERO_SIZE_OBJECT
Definition: forward.h:46
#define assert(EX)
Definition: assert.h:17
SSL Connection
Definition: Session.h:49
bool intercepted
Definition: RequestFlags.h:66
class AccessLogEntry::CacheDetails cache
uint32_t nfmark_t
Definition: forward.h:26
~FwdState() override
Definition: FwdState.cc:305
HierarchyLogEntry hier
Definition: HttpRequest.h:157
bool setIPv4()
Definition: Address.cc:244
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:161
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:431
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
static time_t ForwardTimeout(const time_t fwdStart)
time left to finish the whole forwarding process (which started at fwdStart)
Definition: FwdState.cc:423
void clear()
make pointer not set; does not invalidate cbdata
Definition: CbcPointer.h:144
bool no_delay
Definition: CachePeer.h:128
@ scServiceUnavailable
Definition: StatusCode.h:76
const AnyP::UriScheme & getScheme() const
Definition: Uri.h:58
void retryOrBail()
Definition: FwdState.cc:773
bool checkRetry()
Definition: FwdState.cc:691
#define Assure(condition)
Definition: Assure.h:35
ErrorState * err
Definition: FwdState.h:211
@ scInternalServerError
Definition: StatusCode.h:73
void completed()
Definition: FwdState.cc:256
ErrorDetail::Pointer detail
Definition: errorpage.h:205
#define asyncCallback(dbgSection, dbgLevel, method, object)
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:325
void fatal_dump(const char *message)
Definition: fatal.cc:78
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:419
time_t squid_curtime
Definition: stub_libtime.cc:20
static void logReplyStatus(int tries, const Http::StatusCode status)
Definition: FwdState.cc:1402
bool isNoAddr() const
Definition: Address.cc:304
void NoteOutgoingConnectionSuccess(CachePeer *const peer)
Definition: CachePeer.h:237
int xerrno
Definition: errorpage.h:179
void completeSuccessfully(const char *whyWeAreSureWeStoredTheWholeReply)
Definition: store.cc:1017
void resume()
Definition: Stopwatch.cc:31
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
Definition: ResolvedPeers.h:85
Final result (an open connection or an error) sent to the job initiator.
A PeerConnector for TLS cache_peers and origin servers. No SslBump capabilities.
virtual void notePeerConnection(Comm::ConnectionPointer)
called just before a FwdState-dispatched job starts using connection
Definition: client_side.h:207
#define fd_table
Definition: fde.h:189
void urnStart(HttpRequest *r, StoreEntry *e, const AccessLogEntryPointer &ale)
Definition: urn.cc:204
void start(const JobPointer &aJob, const AsyncCall::Pointer &aCallback)
starts waiting for the given job to call the given callback
Definition: JobWait.h:69
@ ERR_READ_TIMEOUT
Definition: forward.h:26
tos_t aclMapTOS(acl_tos *head, ACLChecklist *ch)
Checks for a TOS value to apply depending on the ACL.
Definition: FwdState.cc:1458
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
#define COMM_DOBIND
Definition: Connection.h:49
@ PROTO_WHOIS
Definition: ProtocolType.h:36
time_t positiveTimeout(const time_t timeout)
Definition: neighbors.cc:1092
@ PROTO_HTTPS
Definition: ProtocolType.h:27
HttpRequestMethod method
Definition: HttpRequest.h:114
Config TheConfig
Globally available instance of Qos::Config.
Definition: QosConfig.cc:287
@ ERR_SHUTTING_DOWN
Definition: forward.h:72
Comm::ConnectionPointer conn
@ PROTO_FTP
Definition: ProtocolType.h:26
@ PING_DONE
Definition: enums.h:41
PeerConnectionPointer conn
nfmark_t getNfConnmark(const Comm::ConnectionPointer &conn, const ConnectionDirection connDir)
Definition: QosConfig.cc:150
@ PROTO_HTTP
Definition: ProtocolType.h:25
bool allowed() const
Definition: Acl.h:82
const char * storedWholeReply_
Definition: FwdState.h:248
void prepForPeering(const CachePeer &peer)
get ready to be sent to the given cache_peer, including originserver
Definition: HttpRequest.cc:446
a netfilter mark/mask pair
Definition: NfMarkConfig.h:22
@ ERR_FORWARDING_DENIED
Definition: forward.h:21
void reinstatePath(const PeerConnectionPointer &)
void complete()
Definition: FwdState.cc:526
int reforward()
Definition: FwdState.cc:1308
squidaio_request_t * head
Definition: aiops.cc:127
void StartRelay(FwdState *const fwdState)
A new FTP Relay job.
Definition: FtpRelay.cc:807
struct SquidConfig::@84 Timeout
@ raceImpossible
Definition: FwdState.h:243
static LogTagsErrors FromErrno(int errNo)
constructs an object matching errno(3) of a failed I/O call
Definition: LogTags.cc:22
@ PROTO_WAIS
Definition: ProtocolType.h:30
static char server[MAXLINE]
void connectedToPeer(Security::EncryptorAnswer &answer)
called when all negotiations with the TLS-speaking peer have been completed
Definition: FwdState.cc:1014
void expectNoConsumption()
there will be no more setConsumer() calls
Definition: BodyPipe.cc:267
static int FwdReplyCodes[MAX_FWD_STATS_IDX+1][Http::scInvalidHeader+1]
Definition: FwdState.cc:76
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
bool isEmpty() const
Definition: Store.h:65
void StartGateway(FwdState *const fwdState)
A new FTP Gateway job.
Definition: FtpGateway.cc:2681
@ ERR_CONNECT_FAIL
Definition: forward.h:30
PeeringActivityTimer peeringTimer
Measures time spent on selecting and communicating with peers.
Definition: FwdState.h:251
#define Must(condition)
Definition: TextException.h:75
Ip::NfMarkConfig aclFindNfMarkConfig(acl_nfmark *head, ACLChecklist *ch)
Checks for a netfilter mark value to apply depending on the ACL.
Definition: FwdState.cc:1470
PeerConnectionPointer destinationReceipt
peer selection result (or nil)
Definition: FwdState.h:238
#define DBG_IMPORTANT
Definition: Stream.h:38
SBuf leftovers
peer-generated bytes after a positive answer (or empty)
struct CachePeer::@27 options
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:193
StoreEntry * entry
Definition: FwdState.h:202
bool reused
whether conn was open earlier, by/for somebody else
int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
Definition: QosConfig.cc:557
@ scInvalidHeader
Squid header parsing error.
Definition: StatusCode.h:88
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer (including origin servers)
Definition: FwdState.cc:996
time_t forward
Definition: SquidConfig.h:116
int shutting_down
int forward_max_tries
Definition: SquidConfig.h:351
static void fwdStart(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *)
Same as Start() but no master xaction info (AccessLogEntry) available.
Definition: FwdState.cc:407
bool encryptTransport
whether transport encryption (TLS/SSL) is to be used on connections to the peer
Definition: PeerOptions.h:147
PconnRace pconnRace
current pconn race state
Definition: FwdState.h:244
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
Definition: HttpRequest.cc:456
bool IsReforwardableStatus(StatusCode)
whether to send the request to another peer based on the current response status code
Definition: StatusCode.cc:281
@ ERR_CANNOT_FORWARD
Definition: forward.h:23
Stopwatch totalPeeringTime
cumulative time spent (so far) communicating with all peers (see %<tt)
int locked() const
Definition: Store.h:145
void markStoredReplyAsWhole(const char *whyWeAreSure)
Definition: FwdState.cc:575
bool transporting() const
Definition: FwdState.cc:569
void start(Pointer aSelf)
Definition: FwdState.cc:145
void registerAbortCallback(const AsyncCall::Pointer &)
notify the StoreEntry writer of a 3rd-party initiated StoreEntry abort
Definition: store.cc:1481
bool noteFwdPconnUse
hack: whether the connection requires fwdPconnPool->noteUses()
Definition: PeerConnector.h:62
HttpRequest * request
Definition: FwdState.h:203
Security::PeerOptions secure
security settings for peer connection
Definition: CachePeer.h:219
Ip::Address client_addr
Definition: HttpRequest.h:149
void serverClosed()
Definition: FwdState.cc:748
void host(const char *src)
Definition: Uri.cc:123
void netdbPingSite(const char *hostname)
Definition: net_db.cc:811
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
get rid of a to-server connection that failed to become serverConn
Definition: FwdState.cc:96
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void stop()
pauses timer if stop() has not been called
Definition: FwdState.h:64
HttpRequestPointer request
Definition: MemObject.h:205
bool checkRetriable()
Whether we may try sending this request again after a failure.
Definition: FwdState.cc:735
void completeTruncated(const char *whyWeConsiderTheReplyTruncated)
Definition: store.cc:1024
void comm_remove_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:981
nfmark_t nfmark
Definition: Connection.h:163
CbcPointer< ErrorState > squidError
problem details (or nil)
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:232
bool ftpNative
carries a representation of an FTP command [received on ftp_port]
Definition: RequestFlags.h:112
void handleUnregisteredServerEnd()
Definition: FwdState.cc:804
class SquidConfig Config
Definition: SquidConfig.cc:12
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1560
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: FwdState.h:236
int unsigned int
Definition: stub_fd.cc:19
int storePendingNClients(const StoreEntry *e)
void httpStart(FwdState *fwd)
Definition: http.cc:2524
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition: Detail.cc:54
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: FwdState.cc:661
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:64
@ STORE_PENDING
Definition: enums.h:46

 

Introduction

Documentation

Support

Miscellaneous