tunnel.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 26 Secure Sockets Layer Proxy */
10 
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "base/AsyncCallbacks.h"
14 #include "base/CbcPointer.h"
15 #include "base/JobWait.h"
16 #include "base/Raw.h"
17 #include "CachePeer.h"
18 #include "cbdata.h"
19 #include "client_side.h"
20 #include "client_side_request.h"
21 #include "clients/HttpTunneler.h"
22 #include "comm.h"
23 #include "comm/Connection.h"
24 #include "comm/ConnOpener.h"
25 #include "comm/Read.h"
26 #include "comm/Write.h"
27 #include "errorpage.h"
28 #include "fd.h"
29 #include "fde.h"
30 #include "FwdState.h"
31 #include "globals.h"
32 #include "HappyConnOpener.h"
33 #include "http.h"
34 #include "http/StatusCode.h"
35 #include "http/Stream.h"
36 #include "HttpRequest.h"
37 #include "icmp/net_db.h"
38 #include "ip/QosConfig.h"
39 #include "LogTags.h"
40 #include "MemBuf.h"
41 #include "neighbors.h"
42 #include "PeerSelectState.h"
43 #include "ResolvedPeers.h"
44 #include "sbuf/SBuf.h"
46 #include "SquidConfig.h"
47 #include "StatCounters.h"
48 #if USE_OPENSSL
49 #include "ssl/bio.h"
50 #include "ssl/ServerBump.h"
51 #endif
52 #include "tools.h"
53 #include "tunnel.h"
54 #if USE_DELAY_POOLS
55 #include "DelayId.h"
56 #endif
57 
58 #include <climits>
59 #include <cerrno>
60 
66 /*
67  * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
68  * of pre-formatted data. Then we can use that as the client side of the tunnel
69  * instead of re-implementing it here and occasionally getting the ConnStateData
70  * read/write state wrong.
71  *
72  * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
73  */
75 {
77 
78 public:
80  ~TunnelStateData() override;
81  TunnelStateData(const TunnelStateData &); // do not implement
82  TunnelStateData &operator =(const TunnelStateData &); // do not implement
83 
84  class Connection;
85  static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
86  static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
87  static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
88  static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
89 
90  bool noConnections() const;
92  void closeConnections();
93 
94  char *url;
98 
99  const char * getHost() const {
100  return (server.conn != nullptr && server.conn->getPeer() ? server.conn->getPeer()->host : request->url.host());
101  };
102 
106 
109  // If we are forcing a tunnel after receiving a client CONNECT, then we
110  // have already responded to that CONNECT before tunnel.cc started.
112  return false;
113 #if USE_OPENSSL
114  // We are bumping and we had already send "OK CONNECTED"
116  return false;
117 #endif
118  return !(request != nullptr &&
120  }
121 
124  void startConnecting();
125  void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason);
126 
129 
131  {
132 
133  public:
134  Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(nullptr), delayedLoops(0),
135  dirty(false),
136  readPending(nullptr), readPendingFunc(nullptr) {}
137 
138  ~Connection();
139 
141  template <typename Method>
142  void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState);
143 
145  void noteClosure();
146 
147  int bytesWanted(int lower=0, int upper = INT_MAX) const;
148  void bytesIn(int const &);
149 #if USE_DELAY_POOLS
150 
151  void setDelayId(DelayId const &);
152 #endif
153 
154  void error(int const xerrno);
155  int debugLevelForError(int const xerrno) const;
156 
157  void dataSent (size_t amount);
159  void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
160  int len;
161  char *buf;
163  uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
164 
166  uint8_t delayedLoops;
167 
168  bool dirty;
169 
170  // XXX: make these an AsyncCall when event API can handle them
173 
174 #if USE_DELAY_POOLS
175 
177 #endif
178 
179  private:
182  };
183 
185  int *status_ptr;
186 
189  time_t startTime;
192 
195 
196  int n_tries;
197 
199  const char *banRetries;
200 
201  // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
203 
206 
209 
213 
216 
217  void copyRead(Connection &from, IOCB *completion);
218 
222 
223  /* PeerSelectionInitiator API */
224  void noteDestination(Comm::ConnectionPointer conn) override;
225  void noteDestinationsEnd(ErrorState *selectionError) override;
226 
227  void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
228 
232 
234  void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
235 
236  void notifyConnOpener();
237 
238  void saveError(ErrorState *finalError);
239  void sendError(ErrorState *finalError, const char *reason);
240 
241 private:
242  void usePinned();
243 
246 
250 
251  template <typename StepStart>
252  void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
253 
255  const char *checkRetry();
256 
257  bool transporting() const;
258 
259  // TODO: convert to unique_ptr
261  ErrorState *savedError = nullptr;
262 
265 
267  void deleteThis();
268 
269  void cancelStep(const char *reason);
270 
271  bool exhaustedTries() const;
272  void updateAttempts(int);
273 
274 public:
275  bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
276  void copy(size_t len, Connection &from, Connection &to, IOCB *);
277  void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
278  void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
279  void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
280  void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
281 
282  void copyClientBytes();
283  void copyServerBytes();
284 
286  void clientClosed();
287 
289  void serverClosed();
290 
293  void retryOrBail(const char *context);
294 };
295 
302 
304 static void
306 {
307  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
308  tunnelState->serverClosed();
309 }
310 
311 void
313 {
315 
316  peeringTimer.stop();
317 
319 }
320 
322 static void
324 {
325  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
326  tunnelState->clientClosed();
327 }
328 
329 void
331 {
334 }
335 
340 void
342 {
343  if (noConnections())
344  return deleteThis();
345 
346  // XXX: The code below should precede the noConnections() check above. When
347  // there is no writer, we should trigger an immediate noConnections()
348  // outcome instead of waiting for an asynchronous call to our own closure
349  // callback (that will call this method again). We should not move this code
350  // until a noConnections() outcome guarantees a nil writer because such a
351  // move will unnecessary delay deleteThis().
352 
353  if (remainingConnection.writer) {
354  debugs(26, 5, "waiting to finish writing to " << remainingConnection.conn);
355  // the write completion callback must close its remainingConnection
356  // after noticing that the other connection is gone
357  return;
358  }
359 
360  // XXX: Stop abusing connection closure callback for terminating tunneling
361  // in cases like this, where our code knows that tunneling must end. The
362  // closure callback should be dedicated to handling rare connection closures
363  // originated _outside_ of TunnelStateData (e.g., during shutdown). In all
364  // other cases, our own close()-calling code must detail the
365  // closure-triggering error (if any) _and_ clear all callbacks: Our code
366  // does not need to be (asynchronously) notified of the closure that it
367  // itself has initiated! Until that (significant) refactoring,
368  // serverClosed() and clientClosed() callbacks will continue to mishandle
369  // those rare closures as regular ones, and access.log records will continue
370  // to lack some tunneling error indicators/details.
371  //
372  // This asynchronous close() leads to another finishWritingAndDelete() call
373  // but with true noConnections() that finally triggers deleteThis().
374  remainingConnection.conn->close();
375 }
376 
378 void
380 {
382  // ConnStateData pipeline should contain the CONNECT we are performing
383  // but it may be invalid already (bug 4392)
384  if (const auto h = http.valid()) {
385  if (const auto c = h->getConn())
386  if (const auto ctx = c->pipeline.front())
387  ctx->finished();
388  }
389  delete this;
390 }
391 
392 // TODO: Replace with a reusable API guaranteeing non-nil pointer forwarding.
394 static auto &
396 {
397  Assure(cr);
398  Assure(cr->request);
399  return *cr->request;
400 }
401 
403  startTime(squid_curtime),
404  destinations(new ResolvedPeers()),
405  destinationsFound(false),
406  committedToServer(false),
407  n_tries(0),
408  banRetries(nullptr),
409  codeContext(CodeContext::Current()),
410  peeringTimer(&guaranteedRequest(clientRequest))
411 {
412  debugs(26, 3, "TunnelStateData constructed this=" << this);
415 
416  assert(clientRequest);
417  url = xstrdup(clientRequest->uri);
418  request = clientRequest->request;
419  Must(request);
420  server.size_ptr = &clientRequest->out.size;
421  client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
422  status_ptr = &clientRequest->al->http.code;
423  al = clientRequest->al;
424  http = clientRequest;
425 
427 
428  client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
429 
430  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
433 }
434 
436 {
437  debugs(26, 3, "TunnelStateData destructed this=" << this);
439  xfree(url);
440  cancelStep("~TunnelStateData");
441  delete savedError;
442 }
443 
445 {
446  if (readPending)
448 
449  safe_free(buf);
450 }
451 
452 const char *
454 {
455  if (shutting_down)
456  return "shutting down";
457  if (exhaustedTries())
458  return "exhausted tries";
460  return "forwarding timeout";
461  if (banRetries)
462  return banRetries;
463  if (noConnections())
464  return "no connections";
465 
466  // TODO: Use std::optional for peer_reply_status to avoid treating zero value specially.
468  return "received HTTP status code is not reforwardable";
469 
470  // TODO: check pinned connections; see FwdState::pinnedCanRetry()
471  return nullptr;
472 }
473 
474 void
475 TunnelStateData::retryOrBail(const char *context)
476 {
477  assert(!server.conn);
478 
479  const auto *bailDescription = checkRetry();
480  if (!bailDescription) {
481  if (!destinations->empty())
482  return startConnecting(); // try connecting to another destination
483 
484  if (subscribed) {
485  debugs(26, 4, "wait for more destinations to try");
486  return; // expect a noteDestination*() call
487  }
488 
489  // fall through to bail
490  }
491 
492  /* bail */
493 
494  peeringTimer.stop();
495 
496  // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
497  // Then, the remaining method code (below) should become the common part of
498  // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
499  if (!savedError)
501  const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
503  if (canSendError)
504  return sendError(savedError, bailDescription ? bailDescription : context);
506 
508 }
509 
510 int
511 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
512 {
513 #if USE_DELAY_POOLS
514  return delayId.bytesWanted(lowerbound, upperbound);
515 #else
516  (void)lowerbound;
517  return upperbound;
518 #endif
519 }
520 
521 void
523 {
524  debugs(26, 3, "len=" << len << " + count=" << count);
525 #if USE_DELAY_POOLS
526  delayId.bytesIn(count);
527 #endif
528 
529  len += count;
530 }
531 
534 void
536 {
537  request->hier.resetPeerNotes(conn, origin);
538  al->hier.resetPeerNotes(conn, origin);
539 }
540 
542 void
544 {
545  Assure(n_tries <= newValue); // n_tries cannot decrease
546 
547  // Squid probably creates at most one FwdState/TunnelStateData object per
548  // ALE, but, unlike an assignment would, this increment logic works even if
549  // Squid uses multiple such objects for a given ALE in some esoteric cases.
550  al->requestAttempts += (newValue - n_tries);
551 
552  n_tries = newValue;
553  debugs(26, 5, n_tries);
554 }
555 
556 int
558 {
559 #ifdef ECONNRESET
560 
561  if (xerrno == ECONNRESET)
562  return 2;
563 
564 #endif
565 
566  if (ignoreErrno(xerrno))
567  return 3;
568 
569  return 1;
570 }
571 
572 /* Read from server side and queue it for writing to the client */
573 void
574 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
575 {
576  TunnelStateData *tunnelState = (TunnelStateData *)data;
577  assert(cbdataReferenceValid(tunnelState));
578  debugs(26, 3, c);
579 
580  tunnelState->readServer(buf, len, errcode, xerrno);
581 }
582 
583 void
584 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
585 {
586  debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
588 
589  /*
590  * Bail out early on Comm::ERR_CLOSING
591  * - close handlers will tidy up for us
592  */
593 
594  if (errcode == Comm::ERR_CLOSING)
595  return;
596 
597  if (len > 0) {
598  server.bytesIn(len);
599  statCounter.server.all.kbytes_in += len;
600  statCounter.server.other.kbytes_in += len;
602  }
603 
604  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
606 }
607 
608 void
610 {
611  debugs(50, debugLevelForError(xerrno), conn << ": read/write failure: " << xstrerr(xerrno));
612 
613  if (!ignoreErrno(xerrno))
614  conn->close();
615 }
616 
617 /* Read from client side and queue it for writing to the server */
618 void
619 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
620 {
621  TunnelStateData *tunnelState = (TunnelStateData *)data;
622  assert (cbdataReferenceValid (tunnelState));
623 
624  tunnelState->readClient(buf, len, errcode, xerrno);
625 }
626 
627 void
628 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
629 {
630  debugs(26, 3, client.conn << ", read " << len << " bytes, err=" << errcode);
632 
633  /*
634  * Bail out early on Comm::ERR_CLOSING
635  * - close handlers will tidy up for us
636  */
637 
638  if (errcode == Comm::ERR_CLOSING)
639  return;
640 
641  if (len > 0) {
642  client.bytesIn(len);
644  }
645 
646  if (keepGoingAfterRead(len, errcode, xerrno, client, server))
648 }
649 
652 bool
653 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
654 {
655  debugs(26, 3, "from={" << from.conn << "}, to={" << to.conn << "}");
656 
657  /* I think this is to prevent free-while-in-a-callback behaviour
658  * - RBC 20030229
659  * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
660  */
661  const CbcPointer<TunnelStateData> safetyLock(this);
662 
663  /* Bump the source connection read timeout on any activity */
664  if (Comm::IsConnOpen(from.conn)) {
665  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
667  commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
668  }
669 
670  /* Bump the dest connection read timeout on any activity */
671  /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
672  if (Comm::IsConnOpen(to.conn)) {
673  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
675  commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
676  }
677 
678  if (errcode)
679  from.error (xerrno);
680  else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
681  debugs(26, 3, "Nothing to write or client gone. Terminate the tunnel.");
682  from.conn->close();
683 
684  /* Only close the remote end if we've finished queueing data to it */
685  if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
686  to.conn->close();
687  }
688  } else if (cbdataReferenceValid(this)) {
689  return true;
690  }
691 
692  return false;
693 }
694 
695 void
696 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
697 {
698  debugs(26, 3, "Schedule Write");
699  AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
700  CommIoCbPtrFun(completion, this));
701  to.write(from.buf, len, call, nullptr);
702 }
703 
704 /* Writes data from the client buffer to the server side */
705 void
706 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
707 {
708  TunnelStateData *tunnelState = (TunnelStateData *)data;
709  assert (cbdataReferenceValid (tunnelState));
710  tunnelState->server.writer = nullptr;
711 
712  tunnelState->writeServerDone(buf, len, flag, xerrno);
713 }
714 
715 void
716 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
717 {
718  debugs(26, 3, server.conn << ", " << len << " bytes written, flag=" << flag);
719 
720  if (flag == Comm::ERR_CLOSING)
721  return;
722 
724 
725  /* Error? */
726  if (flag != Comm::OK) {
727  debugs(26, 4, "to-server write failed: " << xerrno);
728  server.error(xerrno); // may call comm_close
729  return;
730  }
731 
732  /* EOF? */
733  if (len == 0) {
734  debugs(26, 4, "No read input. Closing server connection.");
735  server.conn->close();
736  return;
737  }
738 
739  /* Valid data */
740  statCounter.server.all.kbytes_out += len;
741  statCounter.server.other.kbytes_out += len;
742  client.dataSent(len);
743 
744  /* If the other end has closed, so should we */
745  if (!Comm::IsConnOpen(client.conn)) {
746  debugs(26, 4, "Client gone away. Shutting down server connection.");
747  server.conn->close();
748  return;
749  }
750 
751  const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
752 
753  if (cbdataReferenceValid(this))
754  copyClientBytes();
755 }
756 
757 /* Writes data from the server buffer to the client side */
758 void
759 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
760 {
761  TunnelStateData *tunnelState = (TunnelStateData *)data;
762  assert (cbdataReferenceValid (tunnelState));
763  tunnelState->client.writer = nullptr;
764 
765  tunnelState->writeClientDone(buf, len, flag, xerrno);
766 }
767 
768 void
770 {
771  debugs(26, 3, "len=" << len << " - amount=" << amount);
772  assert(amount == (size_t)len);
773  len =0;
774  /* increment total object size */
775 
776  if (size_ptr)
777  *size_ptr += amount;
778 
779 }
780 
781 void
782 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
783 {
784  writer = callback;
785  dirty = true;
786  Comm::Write(conn, b, size, callback, free_func);
787 }
788 
789 template <typename Method>
790 void
792 {
793  Must(!Comm::IsConnOpen(conn));
794  Must(!closer);
795  Must(Comm::IsConnOpen(aConn));
796  conn = aConn;
797  closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
798  comm_add_close_handler(conn->fd, closer);
799 }
800 
801 void
803 {
804  debugs(26, 3, conn);
805  conn = nullptr;
806  closer = nullptr;
807  writer = nullptr; // may already be nil
808 }
809 
810 void
811 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
812 {
813  debugs(26, 3, client.conn << ", " << len << " bytes written, flag=" << flag);
814 
815  if (flag == Comm::ERR_CLOSING)
816  return;
817 
818  /* Error? */
819  if (flag != Comm::OK) {
820  debugs(26, 4, "from-client read failed: " << xerrno);
821  client.error(xerrno); // may call comm_close
822  return;
823  }
824 
825  /* EOF? */
826  if (len == 0) {
827  debugs(26, 4, "Closing client connection due to 0 byte read.");
828  client.conn->close();
829  return;
830  }
831 
832  /* Valid data */
834  server.dataSent(len);
835 
836  /* If the other end has closed, so should we */
837  if (!Comm::IsConnOpen(server.conn)) {
838  debugs(26, 4, "Server has gone away. Terminating client connection.");
839  client.conn->close();
840  return;
841  }
842 
843  CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
844 
845  if (cbdataReferenceValid(this))
846  copyServerBytes();
847 }
848 
849 static void
851 {
852  TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
853  debugs(26, 3, io.conn);
854  /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
855  CbcPointer<TunnelStateData> safetyLock(tunnelState);
856 
857  tunnelState->closeConnections();
858 }
859 
860 void
862 {
863  debugs(26, 3, "because " << reason << "; " << conn);
864  assert(!server.conn);
865  if (IsConnOpen(conn))
866  conn->close();
867 }
868 
869 void
871 {
873  server.conn->close();
875  client.conn->close();
876 }
877 
878 static void
880 {
881  if (!data)
882  return;
883 
884  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
885  const auto savedContext = CodeContext::Current();
887  tunnel->client.readPending = nullptr;
888  static uint64_t counter=0;
889  debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
890  tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
891  CodeContext::Reset(savedContext);
892 }
893 
894 static void
896 {
897  if (!data)
898  return;
899 
900  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
901  const auto savedContext = CodeContext::Current();
903  tunnel->server.readPending = nullptr;
904  static uint64_t counter=0;
905  debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
906  tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
907  CodeContext::Reset(savedContext);
908 }
909 
910 void
912 {
913  assert(from.len == 0);
914  // If only the minimum permitted read size is going to be attempted
915  // then we schedule an event to try again in a few I/O cycles.
916  // Allow at least 1 byte to be read every (0.3*10) seconds.
917  int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
918  // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
919  // from.readPendingFunc is tunnelDelayedClientRead()).
920  // XXX: Bug #4913: For delay pools, use delayRead() API instead.
921  if (bw == 1 && ++from.delayedLoops < 10) {
922  from.readPending = this;
923  eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
924  return;
925  }
926 
927  AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
928  CommIoCbPtrFun(completion, this));
929  comm_read(from.conn, from.buf, bw, call);
930 }
931 
932 void
934 {
935  if (preReadClientData.length()) {
936  size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
937  memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
938  preReadClientData.consume(copyBytes);
939  client.bytesIn(copyBytes);
940  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
942  } else
944 }
945 
946 void
948 {
949  if (preReadServerData.length()) {
950  size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
951  memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
952  preReadServerData.consume(copyBytes);
953  server.bytesIn(copyBytes);
954  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
956  } else
958 }
959 
964 static void
966 {
967  assert(!tunnelState->transportWait);
968  assert(!tunnelState->encryptionWait);
969  assert(!tunnelState->peerWait);
970 
971  assert(tunnelState->server.conn);
972  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
973  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
974  commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
975 
976  *tunnelState->status_ptr = Http::scOkay;
977  if (cbdataReferenceValid(tunnelState)) {
978 
979  // Shovel any payload already pushed into reply buffer by the server response
980  if (!tunnelState->server.len)
981  tunnelState->copyServerBytes();
982  else {
983  debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
984  tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
985  }
986 
987  if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
988  SBuf * const in = &tunnelState->http->getConn()->inBuf;
989  debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
990  tunnelState->preReadClientData.append(*in);
991  in->consume(); // ConnStateData buffer accounting after the shuffle.
992  }
993  tunnelState->copyClientBytes();
994  }
995 }
996 
1002 static void
1003 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
1004 {
1005  TunnelStateData *tunnelState = (TunnelStateData *)data;
1006  debugs(26, 3, conn << ", flag=" << flag);
1007  tunnelState->client.writer = nullptr;
1008 
1009  if (flag != Comm::OK) {
1010  *tunnelState->status_ptr = Http::scInternalServerError;
1011  tunnelErrorComplete(conn->fd, data, 0);
1012  return;
1013  }
1014 
1015  if (auto http = tunnelState->http.get()) {
1016  http->out.headers_sz += len;
1017  http->out.size += len;
1018  }
1019 
1020  tunnelStartShoveling(tunnelState);
1021 }
1022 
1023 void
1025 {
1026  peerWait.finish();
1027  server.len = 0;
1028 
1029  // XXX: al->http.code (i.e. *status_ptr) should not be (re)set
1030  // until we actually start responding to the client. Right here/now, we only
1031  // know how this cache_peer has responded to us.
1032  if (answer.peerResponseStatus != Http::scNone)
1033  *status_ptr = answer.peerResponseStatus;
1034 
1035  auto sawProblem = false;
1036 
1037  if (!answer.positive()) {
1038  sawProblem = true;
1039  assert(!answer.conn);
1040  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1041  sawProblem = true;
1042  closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
1043  }
1044 
1045  if (!sawProblem) {
1046  assert(answer.positive()); // paranoid
1047  // copy any post-200 OK bytes to our buffer
1048  preReadServerData = answer.leftovers;
1049  notePeerReadyToShovel(answer.conn);
1050  return;
1051  }
1052 
1053  ErrorState *error = nullptr;
1054  if (answer.positive()) {
1056  } else {
1057  error = answer.squidError.get();
1058  Must(error);
1059  answer.squidError.clear(); // preserve error for errorSendComplete()
1060  }
1061  assert(error);
1062  saveError(error);
1063  retryOrBail("tunneler error");
1064 }
1065 
1066 void
1068 {
1069  assert(!client.dirty);
1070  commitToServer(conn);
1071 
1073  tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1074  else {
1076  AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1079  const auto mb = al->reply->pack();
1080  client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1081  delete mb;
1082  }
1083 }
1084 
1085 void
1087 {
1088  committedToServer = true;
1089  banRetries = "committed to server";
1090  PeerSelectionInitiator::subscribed = false; // may already be false
1091  server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1092 }
1093 
1094 static void
1095 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1096 {
1097  TunnelStateData *tunnelState = (TunnelStateData *)data;
1098  debugs(26, 3, "FD " << fd);
1099  assert(tunnelState != nullptr);
1100  /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
1101  CbcPointer<TunnelStateData> safetyLock(tunnelState);
1102 
1103  if (Comm::IsConnOpen(tunnelState->client.conn))
1104  tunnelState->client.conn->close();
1105 
1106  if (Comm::IsConnOpen(tunnelState->server.conn))
1107  tunnelState->server.conn->close();
1108 }
1109 
1110 void
1112 {
1113  transportWait.finish();
1114 
1115  updateAttempts(answer.n_tries);
1116 
1117  ErrorState *error = nullptr;
1118  if ((error = answer.error.get())) {
1119  banRetries = "HappyConnOpener gave up";
1120  Must(!Comm::IsConnOpen(answer.conn));
1121  syncHierNote(answer.conn, request->url.host());
1122  answer.error.clear();
1123  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1125  closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1126  }
1127 
1128  if (error) {
1129  saveError(error);
1130  retryOrBail("tried all destinations");
1131  return;
1132  }
1133 
1134  connectDone(answer.conn, request->url.host(), answer.reused);
1135 }
1136 
1137 void
1138 TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1139 {
1140  Must(Comm::IsConnOpen(conn));
1141 
1142  if (reused)
1144  // else Comm::ConnOpener already applied proper/current markings
1145 
1146  // TODO: add pconn race state tracking
1147 
1148  syncHierNote(conn, origin);
1149 
1150 #if USE_DELAY_POOLS
1151  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1152  if (conn->getPeer() && conn->getPeer()->options.no_delay)
1154 #endif
1155 
1157 
1158  request->peer_host = conn->getPeer() ? conn->getPeer()->host : nullptr;
1159 
1160  bool toOrigin = false; // same semantics as StateFlags::toOrigin
1161  if (const auto * const peer = conn->getPeer()) {
1162  request->prepForPeering(*peer);
1163  toOrigin = peer->options.originserver;
1164  } else {
1166  toOrigin = true;
1167  }
1168 
1169  if (!toOrigin)
1170  connectToPeer(conn);
1171  else {
1172  notePeerReadyToShovel(conn);
1173  }
1174 }
1175 
1177 bool
1179 {
1180  return n_tries >= Config.forward_max_tries;
1181 }
1182 
1183 void
1185 {
1186  debugs(26, 3, MYNAME);
1187  /* Create state structure. */
1188  TunnelStateData *tunnelState = nullptr;
1189  ErrorState *err = nullptr;
1191  char *url = http->uri;
1192 
1193  /*
1194  * client_addr.isNoAddr() indicates this is an "internal" request
1195  * from peer_digest.c, asn.c, netdb.c, etc and should always
1196  * be allowed. yuck, I know.
1197  */
1198 
1200  /*
1201  * Check if this host is allowed to fetch MISSES from us (miss_access)
1202  * default is to allow.
1203  */
1205  ch.al = http->al;
1207  ch.my_addr = request->my_addr;
1208  ch.syncAle(request, http->log_uri);
1209  if (ch.fastCheck().denied()) {
1210  debugs(26, 4, "MISS access forbidden.");
1213  http->al->http.code = Http::scForbidden;
1215  return;
1216  }
1217  }
1218 
1219  debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1220  ++statCounter.server.all.requests;
1221  ++statCounter.server.other.requests;
1222 
1223  tunnelState = new TunnelStateData(http);
1224 #if USE_DELAY_POOLS
1225  tunnelState->server.setDelayId(DelayId::DelayClient(http));
1226 #endif
1227  tunnelState->startSelectingDestinations(request, http->al, nullptr);
1228 }
1229 
1230 void
1232 {
1233  if (const auto p = conn->getPeer()) {
1234  if (p->secure.encryptTransport)
1235  return advanceDestination("secure connection to peer", conn, [this,&conn] {
1236  secureConnectionToPeer(conn);
1237  });
1238  }
1239 
1240  connectedToPeer(conn);
1241 }
1242 
1244 void
1246 {
1247  const auto callback = asyncCallback(5, 4, TunnelStateData::noteSecurityPeerConnectorAnswer, this);
1248  const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1249  encryptionWait.start(connector, callback);
1250 }
1251 
1253 template <typename StepStart>
1254 void
1255 TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1256 {
1257  // TODO: Extract destination-specific handling from TunnelStateData so that
1258  // all the awkward, limited-scope advanceDestination() calls can be replaced
1259  // with a single simple try/catch,retry block.
1260  try {
1261  startStep();
1262  // now wait for the step callback
1263  } catch (...) {
1264  debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1265  closePendingConnection(conn, "connection preparation exception");
1266  if (!savedError)
1268  retryOrBail(stepDescription);
1269  }
1270 }
1271 
1273 void
1275 {
1276  encryptionWait.finish();
1277 
1278  ErrorState *error = nullptr;
1279  assert(!answer.tunneled);
1280  if ((error = answer.error.get())) {
1281  assert(!answer.conn);
1282  answer.error.clear();
1283  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1285  closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1286  }
1287 
1288  if (error) {
1289  saveError(error);
1290  retryOrBail("TLS peer connection error");
1291  return;
1292  }
1293 
1294  connectedToPeer(answer.conn);
1295 }
1296 
1297 void
1299 {
1300  advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1302  });
1303 }
1304 
1305 void
1307 {
1308  const auto callback = asyncCallback(5, 4, TunnelStateData::tunnelEstablishmentDone, this);
1309  const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1310 #if USE_DELAY_POOLS
1311  tunneler->setDelayId(server.delayId);
1312 #endif
1313  peerWait.start(tunneler, callback);
1314 }
1315 
1316 void
1318 {
1319  destinationsFound = true;
1320 
1321  if (!path) { // decided to use a pinned connection
1322  // We can call usePinned() without fear of clashing with an earlier
1323  // forwarding attempt because PINNED must be the first destination.
1325  usePinned();
1326  return;
1327  }
1328 
1329  destinations->addPath(path);
1330 
1331  if (transportWait) {
1332  assert(!transporting());
1333  notifyConnOpener();
1334  return; // and continue to wait for tunnelConnectDone() callback
1335  }
1336 
1337  if (transporting())
1338  return; // and continue to receive destinations for backup
1339 
1340  startConnecting();
1341 }
1342 
1343 void
1345 {
1348  if (!destinationsFound) {
1349 
1350  // XXX: Honor clientExpectsConnectResponse() before replying.
1351 
1352  if (selectionError)
1353  return sendError(selectionError, "path selection has failed");
1354 
1355  // TODO: Merge with FwdState and remove this likely unnecessary check.
1356  if (savedError)
1357  return sendError(savedError, "path selection found no paths (with an impossible early error)");
1358 
1360  "path selection found no paths");
1361  }
1362  // else continue to use one of the previously noted destinations;
1363  // if all of them fail, tunneling as whole will fail
1364  Must(!selectionError); // finding at least one path means selection succeeded
1365 
1366  if (transportWait) {
1367  assert(!transporting());
1368  notifyConnOpener();
1369  return; // and continue to wait for the noteConnection() callback
1370  }
1371 
1372  if (transporting()) {
1373  // We are already using a previously opened connection (but were also
1374  // receiving more destinations in case we need to re-forward).
1375  debugs(17, 7, "keep transporting");
1376  return;
1377  }
1378 
1379  // destinationsFound, but none of them worked, and we were waiting for more
1380  debugs(17, 7, "no more destinations to try after " << n_tries << " failed attempts");
1381  if (!savedError) {
1382  // retryOrBail() must be preceded by saveError(), but in case we forgot:
1383  const auto finalError = new ErrorState(ERR_CANNOT_FORWARD, Http::scBadGateway, request.getRaw(), al);
1384  static const auto d = MakeNamedErrorDetail("RETRY_TO_NONE");
1385  finalError->detailError(d);
1386  saveError(finalError);
1387  } // else use actual error from last forwarding attempt
1388 
1389  // XXX: Honor clientExpectsConnectResponse() before replying.
1390  sendError(savedError, "all found paths have failed");
1391 }
1392 
1396 bool
1398 {
1400 }
1401 
1403 void
1405 {
1406  debugs(26, 4, savedError << " ? " << error);
1407  assert(error);
1408  delete savedError; // may be nil
1409  savedError = error;
1410 }
1411 
1414 void
1415 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1416 {
1417  debugs(26, 3, "aborting transaction for " << reason);
1418 
1419  peeringTimer.stop();
1420 
1421  cancelStep(reason);
1422 
1423  assert(finalError);
1424 
1425  // get rid of any cached error unless that is what the caller is sending
1426  if (savedError != finalError)
1427  delete savedError; // may be nil
1428  savedError = nullptr;
1429 
1430  // we cannot try other destinations after responding with an error
1431  PeerSelectionInitiator::subscribed = false; // may already be false
1432 
1433  *status_ptr = finalError->httpStatus;
1434  finalError->callback = tunnelErrorComplete;
1435  finalError->callback_data = this;
1436  errorSend(client.conn, finalError);
1437 }
1438 
1442 void
1443 TunnelStateData::cancelStep(const char *reason)
1444 {
1445  transportWait.cancel(reason);
1446  encryptionWait.cancel(reason);
1447  peerWait.cancel(reason);
1448 }
1449 
1450 void
1452 {
1453  assert(!destinations->empty());
1454  assert(!transporting());
1455 
1456  delete savedError; // may still be nil
1457  savedError = nullptr;
1459 
1460  const auto callback = asyncCallback(17, 5, TunnelStateData::noteConnection, this);
1461  const auto cs = new HappyConnOpener(destinations, callback, request, startTime, n_tries, al);
1462  cs->setHost(request->url.host());
1463  cs->setRetriable(false);
1464  cs->allowPersistent(false);
1465  destinations->notificationPending = true; // start() is async
1466  transportWait.start(cs, callback);
1467 }
1468 
1470 void
1472 {
1473  Must(request);
1474  const auto connManager = request->pinnedConnection();
1475  Comm::ConnectionPointer serverConn = nullptr;
1476 
1477  try {
1479  debugs(26, 7, "pinned peer connection: " << serverConn);
1480  } catch (ErrorState * const error) {
1481  syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1482  // XXX: Honor clientExpectsConnectResponse() before replying.
1483  // a PINNED path failure is fatal; do not wait for more paths
1484  sendError(error, "pinned path failure");
1485  return;
1486  }
1487 
1488  updateAttempts(n_tries + 1);
1489 
1490  // Set HttpRequest pinned related flags for consistency even if
1491  // they are not really used by tunnel.cc code.
1492  request->flags.pinned = true;
1493 
1494  Assure(connManager);
1495  if (connManager->pinnedAuth())
1496  request->flags.auth = true;
1497 
1498  // the server may close the pinned connection before this request
1499  const auto reused = true;
1500  connectDone(serverConn, connManager->pinning.host, reused);
1501 }
1502 
1504 
1505 bool
1507 {
1509 }
1510 
1511 #if USE_DELAY_POOLS
1512 void
1514 {
1515  delayId = newDelay;
1516 }
1517 
1518 #endif
1519 
1521 void
1523 {
1525  debugs(17, 7, "reusing pending notification");
1526  } else {
1528  CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
1529  }
1530 }
1531 
1539 void
1541 {
1542  Must(Comm::IsConnOpen(clientConn));
1543  Must(Comm::IsConnOpen(srvConn));
1544 
1545  debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1546 
1547  /* Create state structure. */
1548  ++statCounter.server.all.requests;
1549  ++statCounter.server.other.requests;
1550 
1551  auto conn = request->clientConnectionManager.get();
1552  Must(conn);
1553  Http::StreamPointer context = conn->pipeline.front();
1554  Must(context && context->http);
1555 
1556  debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1557 
1558  TunnelStateData *tunnelState = new TunnelStateData(context->http);
1559  tunnelState->commitToServer(srvConn);
1560 
1561  request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1562 
1563 #if USE_DELAY_POOLS
1564  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1565  if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1566  tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1567 #endif
1568 
1569  request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1570 
1571  debugs(26, 4, "determine post-connect handling pathway.");
1572  if (const auto peer = srvConn->getPeer())
1573  request->prepForPeering(*peer);
1574  else
1576 
1577  tunnelState->preReadServerData = preReadServerData;
1578 
1579  tunnelStartShoveling(tunnelState);
1580 }
1581 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void noteConnection(HappyConnOpenerAnswer &)
Definition: tunnel.cc:1111
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:159
void ERCB(int fd, void *, size_t)
error page callback
Definition: errorpage.h:30
static DelayId DelayClient(ClientHttpRequest *, HttpReply *reply=nullptr)
Definition: DelayId.cc:68
~TunnelStateData() override
Definition: tunnel.cc:435
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
char * peer_host
Definition: HttpRequest.h:165
void updateAttempts(int)
sets n_tries to the given value (while keeping ALE in sync)
Definition: tunnel.cc:543
CodeContext::Pointer codeContext
our creator context
Definition: tunnel.cc:202
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
int * status_ptr
pointer for logging HTTP status
Definition: tunnel.cc:185
time_t startTime
object creation time, before any peer selection/connection attempts
Definition: tunnel.cc:189
void notePeerReadyToShovel(const Comm::ConnectionPointer &)
called when negotiations with the peer have been successfully completed
Definition: tunnel.cc:1067
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:70
#define xmalloc
void copyClientBytes()
Definition: tunnel.cc:933
bool noConnections() const
Definition: tunnel.cc:1506
void clientClosed()
handles client-to-Squid connection closure; may destroy us
Definition: tunnel.cc:330
Interface for those who need a list of peers to forward a request to.
JobWait< Http::Tunneler > peerWait
Definition: tunnel.cc:212
void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
Start using an established connection.
Definition: tunnel.cc:1138
void noteClosure()
reacts to the external closure of our connection
Definition: tunnel.cc:802
Ip::Address src_addr
struct SquidConfig::@98 accessList
ERCB * callback
Definition: errorpage.h:185
bool destinationsFinalized
whether all of the available candidate paths received from DNS
Definition: ResolvedPeers.h:82
@ scNone
Definition: StatusCode.h:21
SBuf inBuf
read I/O buffer for the client connection
Definition: Server.h:113
void FREE(void *)
Definition: forward.h:37
void eventDelete(EVH *func, void *arg)
Definition: event.cc:127
CbcPointer< ErrorState > error
problem details (nil on success)
Http::StatusCode peer_reply_status
last HTTP status code received
bool isEmpty() const
Definition: SBuf.h:435
RequestFlags flags
Definition: HttpRequest.h:141
static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:759
CbcPointer< ErrorState > error
problem details (nil on success)
void addPath(const Comm::ConnectionPointer &)
add a candidate path to try after all the existing paths
static ERCB tunnelErrorComplete
Definition: tunnel.cc:296
ConnStateData * getConn() const
Connection server
Definition: tunnel.cc:184
TunnelStateData & operator=(const TunnelStateData &)
static void tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
Definition: tunnel.cc:1003
struct StatCounters::@112::@122 all
void error(char *format,...)
bool committedToServer
whether the decision to tunnel to a particular destination was final
Definition: tunnel.cc:194
void saveError(ErrorState *finalError)
remembers an error to be used if there will be no more connection attempts
Definition: tunnel.cc:1404
void copyServerBytes()
Definition: tunnel.cc:947
HttpReplyPointer reply
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:330
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
Definition: tunnel.cc:861
Definition: SBuf.h:93
acl_access * miss
Definition: SquidConfig.h:362
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer
Definition: tunnel.cc:1245
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:511
#define xstrdup
void updateLoggingTags(const LogTags_ot code)
update the code in the transaction processing tags
bool clientExpectsConnectResponse() const
Whether the client sent a CONNECT request to us.
Definition: tunnel.cc:108
void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:628
struct StatCounters::@112 server
HierarchyLogEntry hier
struct ClientHttpRequest::Out out
C * getRaw() const
Definition: RefCount.h:89
void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: tunnel.cc:1317
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:265
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
bool dirty
whether write() has been called (at least once)
Definition: tunnel.cc:168
TunnelStateData * readPending
Definition: tunnel.cc:171
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ OK
Definition: Flag.h:16
void error(int const xerrno)
Definition: tunnel.cc:609
void closeConnections()
closes both client and server connections
Definition: tunnel.cc:870
void connectToPeer(const Comm::ConnectionPointer &)
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1231
void finishWritingAndDelete(Connection &)
Definition: tunnel.cc:341
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:40
@ ERR_CLOSING
Definition: Flag.h:24
struct StatCounters::@111 client_http
AsyncCall::Pointer writer
pending Comm::Write callback
Definition: tunnel.cc:162
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
TunnelStateData(ClientHttpRequest *)
Definition: tunnel.cc:402
bool empty() const
whether we lack any known candidate paths
Definition: ResolvedPeers.h:46
#define DBG_DATA
Definition: Stream.h:40
size_t headers_sz
Response header bytes written to the client connection.
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:77
void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
starts a preparation step for an established connection; retries on failures
Definition: tunnel.cc:1255
const char * checkRetry()
Definition: tunnel.cc:453
void syncHierNote(const Comm::ConnectionPointer &server, const char *origin)
Definition: tunnel.cc:535
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition: tunnel.cc:261
Definition: Raw.h:20
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:59
static CLCB tunnelClientClosed
Definition: tunnel.cc:298
void update(const LogTags_ot t)
Definition: LogTags.cc:63
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition: tunnel.cc:965
void copyRead(Connection &from, IOCB *completion)
Definition: tunnel.cc:911
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: tunnel.cc:1024
Comm::ConnectionPointer conn
peer connection (secured on success)
ByteCounter kbytes_in
Definition: StatCounters.h:46
int size
Definition: ModDevPoll.cc:69
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:792
const char * rawContent() const
Definition: SBuf.cc:509
SBuf consume(size_type n=npos)
Definition: SBuf.cc:481
void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:811
time_t read
Definition: SquidConfig.h:112
PeeringActivityTimer peeringTimer
Measures time spent on selecting and communicating with peers.
Definition: tunnel.cc:215
void sendError(ErrorState *finalError, const char *reason)
Definition: tunnel.cc:1415
@ scForbidden
Definition: StatusCode.h:48
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1569
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:37
@ LOG_TCP_TUNNEL
an attempt to establish a bidirectional TCP tunnel
Definition: LogTags.h:59
SBuf preReadClientData
Definition: tunnel.cc:187
void write(const char *b, int size, AsyncCall::Pointer &callback, FREE *free_func)
writes 'b' buffer, setting the 'writer' member to 'callback'.
Definition: tunnel.cc:782
bool destinationsFound
At least one candidate path found.
Definition: tunnel.cc:191
AccessLogEntryPointer al
Definition: tunnel.cc:97
void setDelayId(DelayId const &)
Definition: tunnel.cc:1513
const Acl::Answer & fastCheck()
Definition: Checklist.cc:298
CbcPointer< ClientHttpRequest > http
Definition: tunnel.cc:95
MemBuf * pack() const
Definition: HttpReply.cc:112
@ scBadGateway
Definition: StatusCode.h:75
#define INT_MAX
Definition: types.h:70
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:725
void copy(size_t len, Connection &from, Connection &to, IOCB *)
Definition: tunnel.cc:696
int n_tries
the number of forwarding attempts so far
Definition: tunnel.cc:196
CachePeer * getPeer() const
Definition: Connection.cc:121
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
void dataSent(size_t amount)
Definition: tunnel.cc:769
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
Definition: tunnel.cc:1540
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:34
void startConnecting()
Definition: tunnel.cc:1451
void commitToServer(const Comm::ConnectionPointer &)
Definition: tunnel.cc:1086
void bytesIn(int const &)
Definition: tunnel.cc:522
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:59
Comm::ConnectionPointer conn
The currently connected connection.
Definition: tunnel.cc:165
uint8_t delayedLoops
how many times a read on this connection has been postponed.
Definition: tunnel.cc:166
bool denied() const
Definition: Acl.h:88
void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1344
Comm::ConnectionPointer conn
Definition: CommCalls.h:80
#define safe_free(x)
Definition: xalloc.h:73
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:312
void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:716
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition: tunnel.cc:205
#define assert(EX)
Definition: assert.h:17
bool intercepted
Definition: RequestFlags.h:66
class AccessLogEntry::CacheDetails cache
HierarchyLogEntry hier
Definition: HttpRequest.h:157
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
void clear()
make pointer not set; does not invalidate cbdata
Definition: CbcPointer.h:144
struct StatCounters::@112::@122 other
bool no_delay
Definition: CachePeer.h:128
@ scServiceUnavailable
Definition: StatusCode.h:76
char * url
Definition: tunnel.cc:94
#define Assure(condition)
Definition: Assure.h:35
Ip::Address my_addr
Definition: HttpRequest.h:155
@ scInternalServerError
Definition: StatusCode.h:73
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: tunnel.cc:208
static CTCB tunnelTimeout
Definition: tunnel.cc:299
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:33
#define asyncCallback(dbgSection, dbgLevel, method, object)
static CLCB tunnelServerClosed
Definition: tunnel.cc:297
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:325
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
CBDATA_CHILD(TunnelStateData)
Comm::ConnectionPointer clientConnection
Definition: Server.h:100
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: tunnel.cc:1306
uint64_t size
Response header and body bytes written to the client connection.
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
bool isNoAddr() const
Definition: Address.cc:304
#define xfree
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
Definition: ResolvedPeers.h:85
void EVH(void *)
Definition: event.h:18
Final result (an open connection or an error) sent to the job initiator.
Flag
Definition: Flag.h:15
A PeerConnector for TLS cache_peers and origin servers. No SslBump capabilities.
void retryOrBail(const char *context)
Definition: tunnel.cc:475
int ignoreErrno(int ierrno)
Definition: comm.cc:1422
#define fd_table
Definition: fde.h:189
void start(const JobPointer &aJob, const AsyncCall::Pointer &aCallback)
starts waiting for the given job to call the given callback
Definition: JobWait.h:69
int debugLevelForError(int const xerrno) const
Definition: tunnel.cc:557
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: tunnel.cc:1471
HttpRequestMethod method
Definition: HttpRequest.h:114
Comm::ConnectionPointer conn
PeerConnectionPointer conn
static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:619
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:592
char * host
Definition: CachePeer.h:66
bool at(const BumpStep stp) const
whether we are currently performing the given processing step
Definition: ServerBump.h:47
void prepForPeering(const CachePeer &peer)
get ready to be sent to the given cache_peer, including originserver
Definition: HttpRequest.cc:446
@ ERR_FORWARDING_DENIED
Definition: forward.h:21
static const Pointer & Current()
Definition: CodeContext.cc:33
struct SquidConfig::@84 Timeout
void cancelStep(const char *reason)
Definition: tunnel.cc:1443
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:706
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:653
HttpRequest::Pointer request
Definition: tunnel.cc:96
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: tunnel.cc:1522
#define Must(condition)
Definition: TextException.h:75
void tunnelStart(ClientHttpRequest *http)
Definition: tunnel.cc:1184
SBuf preReadServerData
Definition: tunnel.cc:188
void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
initiates Comm::Connection ownership, including closure monitoring
Definition: tunnel.cc:791
SBuf leftovers
peer-generated bytes after a positive answer (or empty)
Ssl::ServerBump * serverBump()
Definition: client_side.h:285
static HttpReplyPointer MakeConnectionEstablished()
construct and return an HTTP/200 (Connection Established) response
Definition: HttpReply.cc:121
struct CachePeer::@27 options
#define MYNAME
Definition: Stream.h:219
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:193
const AccessLogEntry::Pointer al
access.log entry
bool reused
whether conn was open earlier, by/for somebody else
int shutting_down
int forward_max_tries
Definition: SquidConfig.h:351
void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:584
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: tunnel.cc:190
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
AsyncCall::Pointer closer
the registered close handler for the connection
Definition: tunnel.cc:181
void serverClosed()
handles Squid-to-server connection closure; may destroy us
Definition: tunnel.cc:312
static auto & guaranteedRequest(const ClientHttpRequest *const cr)
safely extracts HttpRequest from a never-nil ClientHttpRequest pointer
Definition: tunnel.cc:395
@ scOkay
Definition: StatusCode.h:27
const char * getHost() const
Definition: tunnel.cc:99
time_t lifetime
Definition: SquidConfig.h:114
void connectedToPeer(const Comm::ConnectionPointer &)
called after connection setup (including any encryption)
Definition: tunnel.cc:1298
void * callback_data
Definition: errorpage.h:186
void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &)
callback handler for the Security::PeerConnector encryptor
Definition: tunnel.cc:1274
bool transporting() const
Definition: tunnel.cc:1397
static EVH tunnelDelayedServerRead
Definition: tunnel.cc:301
Ip::Address client_addr
Definition: HttpRequest.h:149
StatusCode peerResponseStatus
the status code of the successfully parsed CONNECT response (or scNone)
void host(const char *src)
Definition: Uri.cc:123
Connection client
Definition: tunnel.cc:184
void netdbPingSite(const char *hostname)
Definition: net_db.cc:811
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
Definition: RequestFlags.h:120
ByteCounter kbytes_out
Definition: StatCounters.h:47
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void stop()
pauses timer if stop() has not been called
Definition: FwdState.h:64
const char * banRetries
a reason to ban reforwarding attempts (or nil)
Definition: tunnel.cc:199
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition: tunnel.cc:1178
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:107
static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:574
Http::StatusCode httpStatus
Definition: errorpage.h:173
CbcPointer< ErrorState > squidError
problem details (or nil)
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:232
class SquidConfig Config
Definition: SquidConfig.cc:12
HttpRequest *const request
ErrorDetail::Pointer MakeNamedErrorDetail(const char *name)
Definition: Detail.cc:54
StatCounters statCounter
Definition: StatCounters.cc:12
void deleteThis()
destroys the tunnel (after performing potentially-throwing cleanup)
Definition: tunnel.cc:379
static EVH tunnelDelayedClientRead
Definition: tunnel.cc:300

 

Introduction

Documentation

Support

Miscellaneous