tunnel.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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  explicit Connection(const char *aSide);
135  ~Connection();
136 
138  template <typename Method>
139  void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState);
140 
142  void noteClosure();
143 
145  void noteEof();
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 
164  const char * const side;
165 
166  char *buf;
168  uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
169 
171  uint8_t delayedLoops;
172 
173  bool dirty;
174 
175  bool receivedEof = false;
176 
177  // XXX: make these an AsyncCall when event API can handle them
180 
181 #if USE_DELAY_POOLS
182 
184 #endif
185 
186  private:
189  };
190 
192  int *status_ptr;
193 
196  time_t startTime;
199 
202 
203  int n_tries;
204 
206  const char *banRetries;
207 
208  // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
210 
213 
216 
220 
223 
224  void copyRead(Connection &from, Connection &to, IOCB *completion);
225 
229 
230  /* PeerSelectionInitiator API */
231  void noteDestination(Comm::ConnectionPointer conn) override;
232  void noteDestinationsEnd(ErrorState *selectionError) override;
233 
234  void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
235 
239 
241  void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
242 
243  void notifyConnOpener();
244 
245  void saveError(ErrorState *finalError);
246  void sendError(ErrorState *finalError, const char *reason);
247 
248 private:
249  void usePinned();
250 
253 
257 
258  template <typename StepStart>
259  void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
260 
262  const char *checkRetry();
263 
264  bool transporting() const;
265 
266  // TODO: convert to unique_ptr
268  ErrorState *savedError = nullptr;
269 
272 
274  void deleteThis();
275 
276  void cancelStep(const char *reason);
277 
278  bool exhaustedTries() const;
279  void updateAttempts(int);
280 
281 public:
282  bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
283  void copy(size_t len, Connection &from, Connection &to, IOCB *);
284  void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
285  void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
286  void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
287  void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
288 
289  void copyClientBytes();
290  void copyServerBytes();
291 
293  void clientClosed();
294 
296  void serverClosed();
297 
300  void retryOrBail(const char *context);
301 };
302 
309 
310 static std::ostream &
311 operator <<(std::ostream &os, const TunnelStateData::Connection &c)
312 {
313  os << '{';
314  os << c.side;
315 
316  if (c.conn)
317  os << ' ' << c.conn->id;
318 
319  if (c.len)
320  os << " buf=" << c.len;
321 
322  if (c.writer)
323  os << " writing";
324  else if (!c.dirty)
325  os << " clean";
326 
327  if (c.delayedLoops)
328  os << " delayedLoops=" << c.delayedLoops;
329  if (c.readPending)
330  os << " delaying";
331 
332  if (c.receivedEof)
333  os << " rEOF";
334 
335  os << '}';
336  return os;
337 }
338 
340 static void
342 {
343  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
344  tunnelState->serverClosed();
345 }
346 
347 void
349 {
351 
352  peeringTimer.stop();
353 
355 }
356 
358 static void
360 {
361  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
362  tunnelState->clientClosed();
363 }
364 
365 void
367 {
370 }
371 
376 void
378 {
379  if (noConnections())
380  return deleteThis();
381 
382  // XXX: The code below should precede the noConnections() check above. When
383  // there is no writer, we should trigger an immediate noConnections()
384  // outcome instead of waiting for an asynchronous call to our own closure
385  // callback (that will call this method again). We should not move this code
386  // until a noConnections() outcome guarantees a nil writer because such a
387  // move will unnecessary delay deleteThis().
388 
389  if (remainingConnection.writer) {
390  debugs(26, 5, "waiting to finish writing to " << remainingConnection);
391  // the write completion callback must close its remainingConnection
392  // after noticing that the other connection is gone
393  return;
394  }
395 
396  // XXX: Stop abusing connection closure callback for terminating tunneling
397  // in cases like this, where our code knows that tunneling must end. The
398  // closure callback should be dedicated to handling rare connection closures
399  // originated _outside_ of TunnelStateData (e.g., during shutdown). In all
400  // other cases, our own close()-calling code must detail the
401  // closure-triggering error (if any) _and_ clear all callbacks: Our code
402  // does not need to be (asynchronously) notified of the closure that it
403  // itself has initiated! Until that (significant) refactoring,
404  // serverClosed() and clientClosed() callbacks will continue to mishandle
405  // those rare closures as regular ones, and access.log records will continue
406  // to lack some tunneling error indicators/details.
407  //
408  // This asynchronous close() leads to another finishWritingAndDelete() call
409  // but with true noConnections() that finally triggers deleteThis().
410  remainingConnection.conn->close();
411 }
412 
414 void
416 {
418  // ConnStateData pipeline should contain the CONNECT we are performing
419  // but it may be invalid already (bug 4392)
420  if (const auto h = http.valid()) {
421  if (const auto c = h->getConn())
422  if (const auto ctx = c->pipeline.front())
423  ctx->finished();
424  }
425  delete this;
426 }
427 
428 // TODO: Replace with a reusable API guaranteeing non-nil pointer forwarding.
430 static auto &
432 {
433  Assure(cr);
434  Assure(cr->request);
435  return *cr->request;
436 }
437 
439  client("client"),
440  server("server"),
441  startTime(squid_curtime),
442  destinations(new ResolvedPeers()),
443  destinationsFound(false),
444  committedToServer(false),
445  n_tries(0),
446  banRetries(nullptr),
447  codeContext(CodeContext::Current()),
448  peeringTimer(&guaranteedRequest(clientRequest))
449 {
450  debugs(26, 3, "TunnelStateData constructed this=" << this);
453 
454  assert(clientRequest);
455  url = xstrdup(clientRequest->uri);
456  request = clientRequest->request;
457  Must(request);
458  server.size_ptr = &clientRequest->out.size;
459  client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
460  status_ptr = &clientRequest->al->http.code;
461  al = clientRequest->al;
462  http = clientRequest;
463 
465 
466  client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
467 
468  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
471 }
472 
474 {
475  debugs(26, 3, "TunnelStateData destructed this=" << this);
477  xfree(url);
478  cancelStep("~TunnelStateData");
479  delete savedError;
480 }
481 
482 TunnelStateData::Connection::Connection(const char * const aSide):
483  len(0),
484  side(aSide),
485  buf(static_cast<char *>(xmalloc(SQUID_TCP_SO_RCVBUF))),
486  size_ptr(nullptr),
487  delayedLoops(0),
488  dirty(false),
489  readPending(nullptr),
490  readPendingFunc(nullptr)
491 {
492 }
493 
495 {
496  if (readPending)
497  eventDelete(readPendingFunc, readPending);
498 
499  safe_free(buf);
500 }
501 
502 const char *
504 {
505  if (shutting_down)
506  return "shutting down";
507  if (exhaustedTries())
508  return "exhausted tries";
510  return "forwarding timeout";
511  if (banRetries)
512  return banRetries;
513  if (noConnections())
514  return "no connections";
515 
516  // TODO: Use std::optional for peer_reply_status to avoid treating zero value specially.
518  return "received HTTP status code is not reforwardable";
519 
520  // TODO: check pinned connections; see FwdState::pinnedCanRetry()
521  return nullptr;
522 }
523 
524 void
525 TunnelStateData::retryOrBail(const char *context)
526 {
527  assert(!server.conn);
528 
529  const auto *bailDescription = checkRetry();
530  if (!bailDescription) {
531  if (!destinations->empty())
532  return startConnecting(); // try connecting to another destination
533 
534  if (subscribed) {
535  debugs(26, 4, "wait for more destinations to try");
536  return; // expect a noteDestination*() call
537  }
538 
539  // fall through to bail
540  }
541 
542  /* bail */
543 
544  peeringTimer.stop();
545 
546  // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
547  // Then, the remaining method code (below) should become the common part of
548  // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
549  if (!savedError)
551  const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
553  if (canSendError)
554  return sendError(savedError, bailDescription ? bailDescription : context);
556 
558 }
559 
560 int
561 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
562 {
563 #if USE_DELAY_POOLS
564  return delayId.bytesWanted(lowerbound, upperbound);
565 #else
566  (void)lowerbound;
567  return upperbound;
568 #endif
569 }
570 
571 void
573 {
574  debugs(26, 3, "len=" << len << " + count=" << count);
575 #if USE_DELAY_POOLS
576  delayId.bytesIn(count);
577 #endif
578 
579  len += count;
580 }
581 
584 void
586 {
587  request->hier.resetPeerNotes(conn, origin);
588  al->hier.resetPeerNotes(conn, origin);
589 }
590 
592 void
594 {
595  Assure(n_tries <= newValue); // n_tries cannot decrease
596 
597  // Squid probably creates at most one FwdState/TunnelStateData object per
598  // ALE, but, unlike an assignment would, this increment logic works even if
599  // Squid uses multiple such objects for a given ALE in some esoteric cases.
600  al->requestAttempts += (newValue - n_tries);
601 
602  n_tries = newValue;
603  debugs(26, 5, n_tries);
604 }
605 
606 int
608 {
609 #ifdef ECONNRESET
610 
611  if (xerrno == ECONNRESET)
612  return 2;
613 
614 #endif
615 
616  if (ignoreErrno(xerrno))
617  return 3;
618 
619  return 1;
620 }
621 
622 /* Read from server side and queue it for writing to the client */
623 void
624 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
625 {
626  TunnelStateData *tunnelState = (TunnelStateData *)data;
627  assert(cbdataReferenceValid(tunnelState));
628  debugs(26, 3, c);
629 
630  tunnelState->readServer(buf, len, errcode, xerrno);
631 }
632 
633 void
634 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
635 {
636  debugs(26, 3, server << ", read " << len << " bytes, err=" << errcode);
638 
639  /*
640  * Bail out early on Comm::ERR_CLOSING
641  * - close handlers will tidy up for us
642  */
643 
644  if (errcode == Comm::ERR_CLOSING)
645  return;
646 
647  if (len > 0) {
648  server.bytesIn(len);
649  statCounter.server.all.kbytes_in += len;
650  statCounter.server.other.kbytes_in += len;
652  }
653 
654  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
656 }
657 
658 void
660 {
661  debugs(50, debugLevelForError(xerrno), *this << ": read/write failure: " << xstrerr(xerrno));
662 
663  if (!ignoreErrno(xerrno))
664  conn->close();
665 }
666 
667 /* Read from client side and queue it for writing to the server */
668 void
669 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
670 {
671  TunnelStateData *tunnelState = (TunnelStateData *)data;
672  assert (cbdataReferenceValid (tunnelState));
673 
674  tunnelState->readClient(buf, len, errcode, xerrno);
675 }
676 
677 void
678 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
679 {
680  debugs(26, 3, client << ", read " << len << " bytes, err=" << errcode);
682 
683  /*
684  * Bail out early on Comm::ERR_CLOSING
685  * - close handlers will tidy up for us
686  */
687 
688  if (errcode == Comm::ERR_CLOSING)
689  return;
690 
691  if (len > 0) {
692  client.bytesIn(len);
694  }
695 
696  if (keepGoingAfterRead(len, errcode, xerrno, client, server))
698 }
699 
702 bool
703 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
704 {
705  debugs(26, 3, "from=" << from << "; writing to=" << to);
706 
707  /* I think this is to prevent free-while-in-a-callback behaviour
708  * - RBC 20030229
709  * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
710  */
711  const CbcPointer<TunnelStateData> safetyLock(this);
712 
713  /* Bump the source connection read timeout on any activity */
714  if (Comm::IsConnOpen(from.conn)) {
715  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
717  commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
718  }
719 
720  /* Bump the dest connection read timeout on any activity */
721  /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
722  if (Comm::IsConnOpen(to.conn)) {
723  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
725  commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
726  }
727 
728  if (errcode) {
729  from.error (xerrno);
730  return false;
731  }
732 
733  if (len == 0) {
734  debugs(26, 3, "closing " << from << " after a zero-byte read");
735  from.conn->close();
736 
737  /* Only close the remote end if we've finished queueing data to it */
738  if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
739  to.conn->close();
740  }
741  return false;
742  }
743 
744  // Stop reading from source if the destination is gone. This both increases
745  // `from` chances to realize what happened at the `to` end and terminates an
746  // otherwise potentially infinite stream of incoming `from` bytes.
747  if (!Comm::IsConnOpen(to.conn)) {
748  debugs(26, 3, "closing " << from << " because " << to << " is gone");
749  from.conn->close();
750  return false;
751  }
752 
753  if (!cbdataReferenceValid(this))
754  return false;
755 
756  Assure(len > 0);
757  return true;
758 }
759 
760 void
761 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
762 {
763  debugs(26, 3, "Schedule Write");
764  AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
765  CommIoCbPtrFun(completion, this));
766  to.write(from.buf, len, call, nullptr);
767 }
768 
769 /* Writes data from the client buffer to the server side */
770 void
771 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
772 {
773  TunnelStateData *tunnelState = (TunnelStateData *)data;
774  assert (cbdataReferenceValid (tunnelState));
775  tunnelState->server.writer = nullptr;
776 
777  tunnelState->writeServerDone(buf, len, flag, xerrno);
778 }
779 
780 void
781 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
782 {
783  debugs(26, 3, server << ", " << len << " bytes written, flag=" << flag);
784 
785  if (flag == Comm::ERR_CLOSING)
786  return;
787 
789 
790  /* Error? */
791  if (flag != Comm::OK) {
792  debugs(26, 4, "to-server write failed: " << xerrno);
793  server.error(xerrno); // may call comm_close
794  return;
795  }
796 
797  /* EOF? */
798  if (len == 0) {
799  debugs(26, 4, "No read input. Closing server connection.");
800  server.conn->close();
801  return;
802  }
803 
804  /* Valid data */
805  statCounter.server.all.kbytes_out += len;
806  statCounter.server.other.kbytes_out += len;
807  client.dataSent(len);
808 
809  /* If the other end has closed, so should we */
810  if (!Comm::IsConnOpen(client.conn)) {
811  debugs(26, 4, "Client gone away. Shutting down server connection.");
812  server.conn->close();
813  return;
814  }
815 
816  const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
817 
818  if (cbdataReferenceValid(this))
819  copyClientBytes();
820 }
821 
822 /* Writes data from the server buffer to the client side */
823 void
824 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
825 {
826  TunnelStateData *tunnelState = (TunnelStateData *)data;
827  assert (cbdataReferenceValid (tunnelState));
828  tunnelState->client.writer = nullptr;
829 
830  tunnelState->writeClientDone(buf, len, flag, xerrno);
831 }
832 
833 void
835 {
836  debugs(26, 3, "len=" << len << " - amount=" << amount);
837  assert(amount == (size_t)len);
838  len =0;
839  /* increment total object size */
840 
841  if (size_ptr)
842  *size_ptr += amount;
843 
844 }
845 
846 void
847 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
848 {
849  writer = callback;
850  dirty = true;
851  Comm::Write(conn, b, size, callback, free_func);
852 }
853 
854 template <typename Method>
855 void
857 {
858  debugs(26, 3, *this << " uses " << aConn);
859  Must(!Comm::IsConnOpen(conn));
860  Must(!closer);
861  Must(Comm::IsConnOpen(aConn));
862  conn = aConn;
863  closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
864  comm_add_close_handler(conn->fd, closer);
865 }
866 
867 void
869 {
870  debugs(26, 3, *this);
871  conn = nullptr;
872  closer = nullptr;
873  writer = nullptr; // may already be nil
874 }
875 
876 void
878 {
879  debugs(26, 3, "from " << *this);
880  receivedEof = true;
881 }
882 
883 void
884 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
885 {
886  debugs(26, 3, client << ", " << len << " bytes written, flag=" << flag);
887 
888  if (flag == Comm::ERR_CLOSING)
889  return;
890 
891  /* Error? */
892  if (flag != Comm::OK) {
893  debugs(26, 4, "to-client write failed: " << xerrno);
894  client.error(xerrno); // may call comm_close
895  return;
896  }
897 
898  /* EOF? */
899  if (len == 0) {
900  debugs(26, 4, "Closing client connection due to 0 byte read.");
901  client.conn->close();
902  return;
903  }
904 
905  /* Valid data */
907  server.dataSent(len);
908 
909  /* If the other end has closed, so should we */
910  if (!Comm::IsConnOpen(server.conn)) {
911  debugs(26, 4, "Server has gone away. Terminating client connection.");
912  client.conn->close();
913  return;
914  }
915 
916  CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
917 
918  if (cbdataReferenceValid(this))
919  copyServerBytes();
920 }
921 
922 static void
924 {
925  TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
926  debugs(26, 3, io.conn);
927  /* Temporary lock to protect our own feet (comm_close -> tunnelClientClosed -> Free) */
928  CbcPointer<TunnelStateData> safetyLock(tunnelState);
929 
930  tunnelState->closeConnections();
931 }
932 
933 void
935 {
936  debugs(26, 3, "because " << reason << "; " << conn);
937  assert(!server.conn);
938  if (IsConnOpen(conn))
939  conn->close();
940 }
941 
942 void
944 {
946  server.conn->close();
948  client.conn->close();
949 }
950 
951 static void
953 {
954  if (!data)
955  return;
956 
957  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
958  const auto savedContext = CodeContext::Current();
960  tunnel->client.readPending = nullptr;
961  static uint64_t counter=0;
962  debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
963  tunnel->copyRead(tunnel->client, tunnel->server, TunnelStateData::ReadClient);
964  CodeContext::Reset(savedContext);
965 }
966 
967 static void
969 {
970  if (!data)
971  return;
972 
973  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
974  const auto savedContext = CodeContext::Current();
976  tunnel->server.readPending = nullptr;
977  static uint64_t counter=0;
978  debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
979  tunnel->copyRead(tunnel->server, tunnel->client, TunnelStateData::ReadServer);
980  CodeContext::Reset(savedContext);
981 }
982 
983 void
984 TunnelStateData::copyRead(Connection &from, Connection &to, IOCB * const completion)
985 {
986  debugs(26, 5, "from=" << from << "; writing to=" << to);
987 
988  assert(from.len == 0);
989  // If only the minimum permitted read size is going to be attempted
990  // then we schedule an event to try again in a few I/O cycles.
991  // Allow at least 1 byte to be read every (0.3*10) seconds.
992  int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
993  // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
994  // from.readPendingFunc is tunnelDelayedClientRead()).
995  // XXX: Bug #4913: For delay pools, use delayRead() API instead.
996  if (bw == 1 && ++from.delayedLoops < 10) {
997  from.readPending = this;
998  eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
999  return;
1000  }
1001 
1002  AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
1003  CommIoCbPtrFun(completion, this));
1004  comm_read(from.conn, from.buf, bw, call);
1005 }
1006 
1007 void
1009 {
1010  if (preReadClientData.length()) {
1011  debugs(26, 7, "pre-read bytes: " << preReadClientData.length());
1012  size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
1013  memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
1014  preReadClientData.consume(copyBytes);
1015  client.bytesIn(copyBytes);
1016  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
1018  } else
1020 }
1021 
1022 void
1024 {
1025  if (preReadServerData.length()) {
1026  debugs(26, 7, "pre-read bytes: " << preReadServerData.length());
1027  size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
1028  memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
1029  preReadServerData.consume(copyBytes);
1030  server.bytesIn(copyBytes);
1031  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
1033  } else
1035 }
1036 
1041 static void
1043 {
1044  assert(!tunnelState->transportWait);
1045  assert(!tunnelState->encryptionWait);
1046  assert(!tunnelState->peerWait);
1047 
1048  assert(tunnelState->server.conn);
1049  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1050  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1051  commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
1052 
1053  *tunnelState->status_ptr = Http::scOkay;
1054  if (cbdataReferenceValid(tunnelState)) {
1055 
1056  // Shovel any payload already pushed into reply buffer by the server response
1057  if (!tunnelState->server.len)
1058  tunnelState->copyServerBytes();
1059  else {
1060  debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
1061  tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
1062  }
1063 
1064  if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
1065  SBuf * const in = &tunnelState->http->getConn()->inBuf;
1066  debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
1067  tunnelState->preReadClientData.append(*in);
1068  in->consume(); // ConnStateData buffer accounting after the shuffle.
1069  }
1070  tunnelState->copyClientBytes();
1071  }
1072 }
1073 
1079 static void
1080 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
1081 {
1082  TunnelStateData *tunnelState = (TunnelStateData *)data;
1083  debugs(26, 3, tunnelState->client << ", flag=" << flag);
1084  tunnelState->client.writer = nullptr;
1085 
1086  if (flag != Comm::OK) {
1087  *tunnelState->status_ptr = Http::scInternalServerError;
1088  tunnelErrorComplete(conn->fd, data, 0);
1089  return;
1090  }
1091 
1092  if (auto http = tunnelState->http.get()) {
1093  http->out.headers_sz += len;
1094  http->out.size += len;
1095  }
1096 
1097  tunnelStartShoveling(tunnelState);
1098 }
1099 
1100 void
1102 {
1103  peerWait.finish();
1104  server.len = 0;
1105 
1106  // XXX: al->http.code (i.e. *status_ptr) should not be (re)set
1107  // until we actually start responding to the client. Right here/now, we only
1108  // know how this cache_peer has responded to us.
1109  if (answer.peerResponseStatus != Http::scNone)
1110  *status_ptr = answer.peerResponseStatus;
1111 
1112  auto sawProblem = false;
1113 
1114  if (!answer.positive()) {
1115  sawProblem = true;
1116  assert(!answer.conn);
1117  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1118  sawProblem = true;
1119  closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
1120  }
1121 
1122  if (!sawProblem) {
1123  assert(answer.positive()); // paranoid
1124  // copy any post-200 OK bytes to our buffer
1125  preReadServerData = answer.leftovers;
1126  notePeerReadyToShovel(answer.conn);
1127  return;
1128  }
1129 
1130  ErrorState *error = nullptr;
1131  if (answer.positive()) {
1133  } else {
1134  error = answer.squidError.get();
1135  Must(error);
1136  answer.squidError.clear(); // preserve error for errorSendComplete()
1137  }
1138  assert(error);
1139  saveError(error);
1140  retryOrBail("tunneler error");
1141 }
1142 
1143 void
1145 {
1146  assert(!client.dirty);
1147  commitToServer(conn);
1148 
1150  tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1151  else {
1153  AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1156  const auto mb = al->reply->pack();
1157  client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1158  delete mb;
1159  }
1160 }
1161 
1162 void
1164 {
1165  committedToServer = true;
1166  banRetries = "committed to server";
1167  PeerSelectionInitiator::subscribed = false; // may already be false
1168  server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1169 }
1170 
1171 static void
1172 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1173 {
1174  TunnelStateData *tunnelState = (TunnelStateData *)data;
1175  debugs(26, 3, "FD " << fd);
1176  assert(tunnelState != nullptr);
1177  /* temporary lock to save our own feet (comm_close -> tunnelClientClosed -> Free) */
1178  CbcPointer<TunnelStateData> safetyLock(tunnelState);
1179 
1180  if (Comm::IsConnOpen(tunnelState->client.conn))
1181  tunnelState->client.conn->close();
1182 
1183  if (Comm::IsConnOpen(tunnelState->server.conn))
1184  tunnelState->server.conn->close();
1185 }
1186 
1187 void
1189 {
1190  transportWait.finish();
1191 
1192  updateAttempts(answer.n_tries);
1193 
1194  ErrorState *error = nullptr;
1195  if ((error = answer.error.get())) {
1196  banRetries = "HappyConnOpener gave up";
1197  Must(!Comm::IsConnOpen(answer.conn));
1198  syncHierNote(answer.conn, request->url.host());
1199  answer.error.clear();
1200  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1202  closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1203  }
1204 
1205  if (error) {
1206  saveError(error);
1207  retryOrBail("tried all destinations");
1208  return;
1209  }
1210 
1211  connectDone(answer.conn, request->url.host(), answer.reused);
1212 }
1213 
1214 void
1215 TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1216 {
1217  Must(Comm::IsConnOpen(conn));
1218 
1219  if (reused)
1221  // else Comm::ConnOpener already applied proper/current markings
1222 
1223  // TODO: add pconn race state tracking
1224 
1225  syncHierNote(conn, origin);
1226 
1227 #if USE_DELAY_POOLS
1228  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1229  if (conn->getPeer() && conn->getPeer()->options.no_delay)
1231 #endif
1232 
1234 
1235  bool toOrigin = false; // same semantics as StateFlags::toOrigin
1236  if (const auto * const peer = conn->getPeer()) {
1237  request->prepForPeering(*peer);
1238  toOrigin = peer->options.originserver;
1239  } else {
1241  toOrigin = true;
1242  }
1243 
1244  if (!toOrigin)
1245  connectToPeer(conn);
1246  else {
1247  notePeerReadyToShovel(conn);
1248  }
1249 }
1250 
1252 bool
1254 {
1255  return n_tries >= Config.forward_max_tries;
1256 }
1257 
1258 void
1260 {
1261  debugs(26, 3, MYNAME);
1262  /* Create state structure. */
1263  TunnelStateData *tunnelState = nullptr;
1264  ErrorState *err = nullptr;
1266  char *url = http->uri;
1267 
1268  /*
1269  * client_addr.isNoAddr() indicates this is an "internal" request
1270  * from peer_digest.c, asn.c, netdb.c, etc and should always
1271  * be allowed. yuck, I know.
1272  */
1273 
1275  /*
1276  * Check if this host is allowed to fetch MISSES from us (miss_access)
1277  * default is to allow.
1278  */
1280  ch.al = http->al;
1282  ch.my_addr = request->my_addr;
1283  ch.syncAle(request, http->log_uri);
1284  if (ch.fastCheck().denied()) {
1285  debugs(26, 4, "MISS access forbidden.");
1288  http->al->http.code = Http::scForbidden;
1290  return;
1291  }
1292  }
1293 
1294  debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1295  ++statCounter.server.all.requests;
1296  ++statCounter.server.other.requests;
1297 
1298  tunnelState = new TunnelStateData(http);
1299 #if USE_DELAY_POOLS
1300  tunnelState->server.setDelayId(DelayId::DelayClient(http));
1301 #endif
1302  tunnelState->startSelectingDestinations(request, http->al, nullptr);
1303 }
1304 
1305 void
1307 {
1308  if (const auto p = conn->getPeer()) {
1309  if (p->secure.encryptTransport)
1310  return advanceDestination("secure connection to peer", conn, [this,&conn] {
1311  secureConnectionToPeer(conn);
1312  });
1313  }
1314 
1315  connectedToPeer(conn);
1316 }
1317 
1319 void
1321 {
1322  const auto callback = asyncCallback(5, 4, TunnelStateData::noteSecurityPeerConnectorAnswer, this);
1323  const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1324  encryptionWait.start(connector, callback);
1325 }
1326 
1328 template <typename StepStart>
1329 void
1330 TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1331 {
1332  // TODO: Extract destination-specific handling from TunnelStateData so that
1333  // all the awkward, limited-scope advanceDestination() calls can be replaced
1334  // with a single simple try/catch,retry block.
1335  try {
1336  startStep();
1337  // now wait for the step callback
1338  } catch (...) {
1339  debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1340  closePendingConnection(conn, "connection preparation exception");
1341  if (!savedError)
1343  retryOrBail(stepDescription);
1344  }
1345 }
1346 
1348 void
1350 {
1351  encryptionWait.finish();
1352 
1353  ErrorState *error = nullptr;
1354  assert(!answer.tunneled);
1355  if ((error = answer.error.get())) {
1356  assert(!answer.conn);
1357  answer.error.clear();
1358  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1360  closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1361  }
1362 
1363  if (error) {
1364  saveError(error);
1365  retryOrBail("TLS peer connection error");
1366  return;
1367  }
1368 
1369  connectedToPeer(answer.conn);
1370 }
1371 
1372 void
1374 {
1375  advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1377  });
1378 }
1379 
1380 void
1382 {
1383  const auto callback = asyncCallback(5, 4, TunnelStateData::tunnelEstablishmentDone, this);
1384  const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1385 #if USE_DELAY_POOLS
1386  tunneler->setDelayId(server.delayId);
1387 #endif
1388  peerWait.start(tunneler, callback);
1389 }
1390 
1391 void
1393 {
1394  destinationsFound = true;
1395 
1396  if (!path) { // decided to use a pinned connection
1397  // We can call usePinned() without fear of clashing with an earlier
1398  // forwarding attempt because PINNED must be the first destination.
1400  usePinned();
1401  return;
1402  }
1403 
1404  destinations->addPath(path);
1405 
1406  if (transportWait) {
1407  assert(!transporting());
1408  notifyConnOpener();
1409  return; // and continue to wait for tunnelConnectDone() callback
1410  }
1411 
1412  if (transporting())
1413  return; // and continue to receive destinations for backup
1414 
1415  startConnecting();
1416 }
1417 
1418 void
1420 {
1423  if (!destinationsFound) {
1424 
1425  // XXX: Honor clientExpectsConnectResponse() before replying.
1426 
1427  if (selectionError)
1428  return sendError(selectionError, "path selection has failed");
1429 
1430  // TODO: Merge with FwdState and remove this likely unnecessary check.
1431  if (savedError)
1432  return sendError(savedError, "path selection found no paths (with an impossible early error)");
1433 
1435  "path selection found no paths");
1436  }
1437  // else continue to use one of the previously noted destinations;
1438  // if all of them fail, tunneling as whole will fail
1439  Must(!selectionError); // finding at least one path means selection succeeded
1440 
1441  if (transportWait) {
1442  assert(!transporting());
1443  notifyConnOpener();
1444  return; // and continue to wait for the noteConnection() callback
1445  }
1446 
1447  if (transporting()) {
1448  // We are already using a previously opened connection (but were also
1449  // receiving more destinations in case we need to re-forward).
1450  debugs(17, 7, "keep transporting");
1451  return;
1452  }
1453 
1454  // destinationsFound, but none of them worked, and we were waiting for more
1455  debugs(17, 7, "no more destinations to try after " << n_tries << " failed attempts");
1456  if (!savedError) {
1457  // retryOrBail() must be preceded by saveError(), but in case we forgot:
1458  const auto finalError = new ErrorState(ERR_CANNOT_FORWARD, Http::scBadGateway, request.getRaw(), al);
1459  static const auto d = MakeNamedErrorDetail("RETRY_TO_NONE");
1460  finalError->detailError(d);
1461  saveError(finalError);
1462  } // else use actual error from last forwarding attempt
1463 
1464  // XXX: Honor clientExpectsConnectResponse() before replying.
1465  sendError(savedError, "all found paths have failed");
1466 }
1467 
1471 bool
1473 {
1475 }
1476 
1478 void
1480 {
1481  debugs(26, 4, savedError << " ? " << error);
1482  assert(error);
1483  delete savedError; // may be nil
1484  savedError = error;
1485 }
1486 
1489 void
1490 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1491 {
1492  debugs(26, 3, "aborting transaction for " << reason);
1493 
1494  peeringTimer.stop();
1495 
1496  cancelStep(reason);
1497 
1498  assert(finalError);
1499 
1500  // get rid of any cached error unless that is what the caller is sending
1501  if (savedError != finalError)
1502  delete savedError; // may be nil
1503  savedError = nullptr;
1504 
1505  // we cannot try other destinations after responding with an error
1506  PeerSelectionInitiator::subscribed = false; // may already be false
1507 
1508  *status_ptr = finalError->httpStatus;
1509  finalError->callback = tunnelErrorComplete;
1510  finalError->callback_data = this;
1511  errorSend(client.conn, finalError);
1512 }
1513 
1517 void
1518 TunnelStateData::cancelStep(const char *reason)
1519 {
1520  transportWait.cancel(reason);
1521  encryptionWait.cancel(reason);
1522  peerWait.cancel(reason);
1523 }
1524 
1525 void
1527 {
1528  assert(!destinations->empty());
1529  assert(!transporting());
1530 
1531  delete savedError; // may still be nil
1532  savedError = nullptr;
1534 
1535  const auto callback = asyncCallback(17, 5, TunnelStateData::noteConnection, this);
1536  const auto cs = new HappyConnOpener(destinations, callback, request, startTime, n_tries, al);
1537  cs->setHost(request->url.host());
1538  cs->setRetriable(false);
1539  cs->allowPersistent(false);
1540  destinations->notificationPending = true; // start() is async
1541  transportWait.start(cs, callback);
1542 }
1543 
1545 void
1547 {
1548  Must(request);
1549  const auto connManager = request->pinnedConnection();
1550  Comm::ConnectionPointer serverConn = nullptr;
1551 
1552  try {
1554  debugs(26, 7, "pinned peer connection: " << serverConn);
1555  } catch (ErrorState * const error) {
1556  syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1557  // XXX: Honor clientExpectsConnectResponse() before replying.
1558  // a PINNED path failure is fatal; do not wait for more paths
1559  sendError(error, "pinned path failure");
1560  return;
1561  }
1562 
1563  updateAttempts(n_tries + 1);
1564 
1565  // Set HttpRequest pinned related flags for consistency even if
1566  // they are not really used by tunnel.cc code.
1567  request->flags.pinned = true;
1568 
1569  Assure(connManager);
1570  if (connManager->pinnedAuth())
1571  request->flags.auth = true;
1572 
1573  // the server may close the pinned connection before this request
1574  const auto reused = true;
1575  connectDone(serverConn, connManager->pinning.host, reused);
1576 }
1577 
1579 
1580 bool
1582 {
1584 }
1585 
1586 #if USE_DELAY_POOLS
1587 void
1589 {
1590  delayId = newDelay;
1591 }
1592 
1593 #endif
1594 
1596 void
1598 {
1600  debugs(17, 7, "reusing pending notification");
1601  } else {
1603  CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
1604  }
1605 }
1606 
1614 void
1616 {
1617  Must(Comm::IsConnOpen(clientConn));
1618  Must(Comm::IsConnOpen(srvConn));
1619 
1620  debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1621 
1622  /* Create state structure. */
1623  ++statCounter.server.all.requests;
1624  ++statCounter.server.other.requests;
1625 
1626  auto conn = request->clientConnectionManager.get();
1627  Must(conn);
1628  Http::StreamPointer context = conn->pipeline.front();
1629  Must(context && context->http);
1630 
1631  debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1632 
1633  TunnelStateData *tunnelState = new TunnelStateData(context->http);
1634  tunnelState->commitToServer(srvConn);
1635 
1636  request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1637 
1638 #if USE_DELAY_POOLS
1639  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1640  if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1641  tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1642 #endif
1643 
1644  debugs(26, 4, "determine post-connect handling pathway.");
1645  if (const auto peer = srvConn->getPeer())
1646  request->prepForPeering(*peer);
1647  else
1649 
1650  tunnelState->preReadServerData = preReadServerData;
1651 
1652  tunnelStartShoveling(tunnelState);
1653 }
1654 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void noteConnection(HappyConnOpenerAnswer &)
Definition: tunnel.cc:1188
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:64
~TunnelStateData() override
Definition: tunnel.cc:473
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:942
JobPointer job() const
Definition: JobWait.h:76
bool tunneled
whether we spliced the connections instead of negotiating encryption
void updateAttempts(int)
sets n_tries to the given value (while keeping ALE in sync)
Definition: tunnel.cc:593
CodeContext::Pointer codeContext
our creator context
Definition: tunnel.cc:209
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
int * status_ptr
pointer for logging HTTP status
Definition: tunnel.cc:192
time_t startTime
object creation time, before any peer selection/connection attempts
Definition: tunnel.cc:196
void notePeerReadyToShovel(const Comm::ConnectionPointer &)
called when negotiations with the peer have been successfully completed
Definition: tunnel.cc:1144
struct StatCounters::@105 server
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:1008
bool noConnections() const
Definition: tunnel.cc:1581
void clientClosed()
handles client-to-Squid connection closure; may destroy us
Definition: tunnel.cc:366
Interface for those who need a list of peers to forward a request to.
JobWait< Http::Tunneler > peerWait
Definition: tunnel.cc:219
void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
Start using an established connection.
Definition: tunnel.cc:1215
void noteClosure()
reacts to the external closure of our connection
Definition: tunnel.cc:868
Ip::Address src_addr
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
Connection(const char *aSide)
Definition: tunnel.cc:482
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:824
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:303
ConnStateData * getConn() const
Connection server
Definition: tunnel.cc:191
TunnelStateData & operator=(const TunnelStateData &)
static void tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
Definition: tunnel.cc:1080
InstanceId< Connection, uint64_t > id
Definition: Connection.h:184
void error(char *format,...)
bool committedToServer
whether the decision to tunnel to a particular destination was final
Definition: tunnel.cc:201
void saveError(ErrorState *finalError)
remembers an error to be used if there will be no more connection attempts
Definition: tunnel.cc:1479
void copyServerBytes()
Definition: tunnel.cc:1023
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:934
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:1320
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:561
#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:678
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:1392
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:270
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:173
TunnelStateData * readPending
Definition: tunnel.cc:178
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
@ OK
Definition: Flag.h:16
void error(int const xerrno)
Definition: tunnel.cc:659
void closeConnections()
closes both client and server connections
Definition: tunnel.cc:943
struct SquidConfig::@77 Timeout
void connectToPeer(const Comm::ConnectionPointer &)
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1306
void finishWritingAndDelete(Connection &)
Definition: tunnel.cc:377
struct CachePeer::@20 options
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:40
@ ERR_CLOSING
Definition: Flag.h:24
struct StatCounters::@105::@115 other
AsyncCall::Pointer writer
pending Comm::Write callback
Definition: tunnel.cc:167
void syncAle(HttpRequest *adaptedRequest, const char *logUri) const override
assigns uninitialized adapted_request and url ALE components
static std::ostream & operator<<(std::ostream &os, const TunnelStateData::Connection &c)
Definition: tunnel.cc:311
TunnelStateData(ClientHttpRequest *)
Definition: tunnel.cc:438
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:1330
void copyRead(Connection &from, Connection &to, IOCB *completion)
Definition: tunnel.cc:984
const char * checkRetry()
Definition: tunnel.cc:503
void syncHierNote(const Comm::ConnectionPointer &server, const char *origin)
Definition: tunnel.cc:585
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition: tunnel.cc:268
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:305
void update(const LogTags_ot t)
Definition: LogTags.cc:63
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition: tunnel.cc:1042
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: tunnel.cc:1101
Comm::ConnectionPointer conn
peer connection (secured on success)
ByteCounter kbytes_in
Definition: StatCounters.h:45
int size
Definition: ModDevPoll.cc:70
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:884
time_t read
Definition: SquidConfig.h:112
PeeringActivityTimer peeringTimer
Measures time spent on selecting and communicating with peers.
Definition: tunnel.cc:222
void sendError(ErrorState *finalError, const char *reason)
Definition: tunnel.cc:1490
@ 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:194
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:847
bool destinationsFound
At least one candidate path found.
Definition: tunnel.cc:198
AccessLogEntryPointer al
Definition: tunnel.cc:97
void setDelayId(DelayId const &)
Definition: tunnel.cc:1588
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:722
void copy(size_t len, Connection &from, Connection &to, IOCB *)
Definition: tunnel.cc:761
struct StatCounters::@105::@115 all
int n_tries
the number of forwarding attempts so far
Definition: tunnel.cc:203
CachePeer * getPeer() const
Definition: Connection.cc:110
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
void dataSent(size_t amount)
Definition: tunnel.cc:834
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
Definition: tunnel.cc:1615
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:1526
void commitToServer(const Comm::ConnectionPointer &)
Definition: tunnel.cc:1163
void bytesIn(int const &)
Definition: tunnel.cc:572
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:59
Comm::ConnectionPointer conn
The currently connected connection.
Definition: tunnel.cc:170
uint8_t delayedLoops
how many times a read on this connection has been postponed.
Definition: tunnel.cc:171
bool denied() const
Definition: Acl.h:88
void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1419
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:781
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition: tunnel.cc:212
#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
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
bool receivedEof
whether read() has returned zero bytes
Definition: tunnel.cc:175
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: tunnel.cc:215
static CTCB tunnelTimeout
Definition: tunnel.cc:306
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:304
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:325
const char *const side
Definition: tunnel.cc:164
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:1381
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:525
int ignoreErrno(int ierrno)
Definition: comm.cc:1407
#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:607
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: tunnel.cc:1546
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:669
void commSetConnTimeout(const Comm::ConnectionPointer &conn, time_t timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:594
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:443
@ ERR_FORWARDING_DENIED
Definition: forward.h:21
static const Pointer & Current()
Definition: CodeContext.cc:33
void cancelStep(const char *reason)
Definition: tunnel.cc:1518
static char server[MAXLINE]
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:771
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:703
struct SquidConfig::@91 accessList
HttpRequest::Pointer request
Definition: tunnel.cc:96
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: tunnel.cc:1597
#define Must(condition)
Definition: TextException.h:75
void tunnelStart(ClientHttpRequest *http)
Definition: tunnel.cc:1259
SBuf preReadServerData
Definition: tunnel.cc:195
void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
initiates Comm::Connection ownership, including closure monitoring
Definition: tunnel.cc:856
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
#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:634
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: tunnel.cc:197
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
Definition: HttpRequest.cc:453
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
void noteEof()
reacts to a successful zero-size read(2)
Definition: tunnel.cc:877
struct StatCounters::@104 client_http
AsyncCall::Pointer closer
the registered close handler for the connection
Definition: tunnel.cc:188
void serverClosed()
handles Squid-to-server connection closure; may destroy us
Definition: tunnel.cc:348
static auto & guaranteedRequest(const ClientHttpRequest *const cr)
safely extracts HttpRequest from a never-nil ClientHttpRequest pointer
Definition: tunnel.cc:431
@ 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:1373
void * callback_data
Definition: errorpage.h:186
void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &)
callback handler for the Security::PeerConnector encryptor
Definition: tunnel.cc:1349
bool transporting() const
Definition: tunnel.cc:1472
static EVH tunnelDelayedServerRead
Definition: tunnel.cc:308
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:154
Connection client
Definition: tunnel.cc:191
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:46
#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:206
bool exhaustedTries() const
whether we have used up all permitted forwarding attempts
Definition: tunnel.cc:1253
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:624
Http::StatusCode httpStatus
Definition: errorpage.h:173
CbcPointer< ErrorState > squidError
problem details (or nil)
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:230
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:415
static EVH tunnelDelayedClientRead
Definition: tunnel.cc:307

 

Introduction

Documentation

Support

Miscellaneous