tunnel.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 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/CbcPointer.h"
14 #include "base/JobWait.h"
15 #include "CachePeer.h"
16 #include "cbdata.h"
17 #include "client_side.h"
18 #include "client_side_request.h"
19 #include "clients/HttpTunneler.h"
20 #include "comm.h"
21 #include "comm/Connection.h"
22 #include "comm/ConnOpener.h"
23 #include "comm/Read.h"
24 #include "comm/Write.h"
25 #include "errorpage.h"
26 #include "fd.h"
27 #include "fde.h"
28 #include "FwdState.h"
29 #include "globals.h"
30 #include "HappyConnOpener.h"
31 #include "http.h"
32 #include "http/Stream.h"
33 #include "HttpRequest.h"
34 #include "icmp/net_db.h"
35 #include "ip/QosConfig.h"
36 #include "LogTags.h"
37 #include "MemBuf.h"
38 #include "neighbors.h"
39 #include "PeerSelectState.h"
40 #include "ResolvedPeers.h"
41 #include "sbuf/SBuf.h"
43 #include "SquidConfig.h"
44 #include "SquidTime.h"
45 #include "StatCounters.h"
46 #if USE_OPENSSL
47 #include "ssl/bio.h"
48 #include "ssl/ServerBump.h"
49 #endif
50 #include "tools.h"
51 #include "tunnel.h"
52 #if USE_DELAY_POOLS
53 #include "DelayId.h"
54 #endif
55 
56 #include <climits>
57 #include <cerrno>
58 
64 /*
65  * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
66  * of pre-formatted data. Then we can use that as the client side of the tunnel
67  * instead of re-implementing it here and occasionally getting the ConnStateData
68  * read/write state wrong.
69  *
70  * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
71  */
73 {
75 
76 public:
78  virtual ~TunnelStateData();
79  TunnelStateData(const TunnelStateData &); // do not implement
80  TunnelStateData &operator =(const TunnelStateData &); // do not implement
81 
82  class Connection;
83  static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
84  static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
85  static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
86  static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
87 
88  bool noConnections() const;
90  void closeConnections();
91 
92  char *url;
96 
97  const char * getHost() const {
98  return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->url.host());
99  };
100 
103  // If we are forcing a tunnel after receiving a client CONNECT, then we
104  // have already responded to that CONNECT before tunnel.cc started.
106  return false;
107 #if USE_OPENSSL
108  // We are bumping and we had already send "OK CONNECTED"
109  if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->at(XactionStep::tlsBump2, XactionStep::tlsBump3))
110  return false;
111 #endif
112  return !(request != NULL &&
114  }
115 
118  void startConnecting();
119  void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason);
120 
123 
125  {
126 
127  public:
128  Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), delayedLoops(0),
129  dirty(false),
131 
132  ~Connection();
133 
135  template <typename Method>
136  void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState);
137 
139  void noteClosure();
140 
141  int bytesWanted(int lower=0, int upper = INT_MAX) const;
142  void bytesIn(int const &);
143 #if USE_DELAY_POOLS
144 
145  void setDelayId(DelayId const &);
146 #endif
147 
148  void error(int const xerrno);
149  int debugLevelForError(int const xerrno) const;
150 
151  void dataSent (size_t amount);
153  void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
154  int len;
155  char *buf;
157  uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
158 
160  uint8_t delayedLoops;
161 
162  bool dirty;
163 
164  // XXX: make these an AsyncCall when event API can handle them
167 
168 #if USE_DELAY_POOLS
169 
171 #endif
172 
173  private:
176  };
177 
179  int *status_ptr;
180 
183  time_t startTime;
186  bool retriable;
189  // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
191 
194 
197 
201 
202  void copyRead(Connection &from, IOCB *completion);
203 
207 
208  /* PeerSelectionInitiator API */
209  virtual void noteDestination(Comm::ConnectionPointer conn) override;
210  virtual void noteDestinationsEnd(ErrorState *selectionError) override;
211 
212  void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
213 
217 
219  void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
220 
221  void notifyConnOpener();
222 
223  void saveError(ErrorState *finalError);
224  void sendError(ErrorState *finalError, const char *reason);
225 
226 private:
229  {
230  public:
232 
234  method_(method), tunnel_(tunnel), answer_() {}
235 
236  /* CallDialer API */
237  virtual bool canDial(AsyncCall &) { return tunnel_.valid(); }
238  void dial(AsyncCall &) { ((&(*tunnel_))->*method_)(answer_); }
239  virtual void print(std::ostream &os) const {
240  os << '(' << tunnel_.get() << ", " << answer_ << ')';
241  }
242 
243  /* Security::PeerConnector::CbDialer API */
244  virtual Security::EncryptorAnswer &answer() { return answer_; }
245 
246  private:
250  };
251 
252  void usePinned();
253 
256 
260 
261  template <typename StepStart>
262  void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
263 
265  const char *checkRetry();
268  bool usingDestination() const;
269 
271  ErrorState *savedError = nullptr;
272 
275 
276  void deleteThis();
277 
278  void cancelStep(const char *reason);
279 
280 public:
281  bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
282  void copy(size_t len, Connection &from, Connection &to, IOCB *);
283  void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
284  void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
285  void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
286  void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
287 
288  void copyClientBytes();
289  void copyServerBytes();
290 
292  void clientClosed();
293 
295  void serverClosed();
296 
299  void retryOrBail(const char *context);
300 };
301 
308 
310 static void
312 {
313  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
314  tunnelState->serverClosed();
315 }
316 
317 void
319 {
321 
322  retryOrBail(__FUNCTION__);
323 }
324 
326 static void
328 {
329  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
330  tunnelState->clientClosed();
331 }
332 
333 void
335 {
337 
338  if (noConnections())
339  return deleteThis();
340 
341  if (!server.writer)
342  server.conn->close();
343 }
344 
346 void
348 {
350  // ConnStateData pipeline should contain the CONNECT we are performing
351  // but it may be invalid already (bug 4392)
352  if (const auto h = http.valid()) {
353  if (const auto c = h->getConn())
354  if (const auto ctx = c->pipeline.front())
355  ctx->finished();
356  }
357  delete this;
358 }
359 
361  startTime(squid_curtime),
362  destinations(new ResolvedPeers()),
363  destinationsFound(false),
364  retriable(true),
365  codeContext(CodeContext::Current())
366 {
367  debugs(26, 3, "TunnelStateData constructed this=" << this);
370 
371  assert(clientRequest);
372  url = xstrdup(clientRequest->uri);
373  request = clientRequest->request;
374  Must(request);
375  server.size_ptr = &clientRequest->out.size;
376  client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
377  status_ptr = &clientRequest->al->http.code;
378  al = clientRequest->al;
379  http = clientRequest;
380 
381  client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
382 
383  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
386 }
387 
389 {
390  debugs(26, 3, "TunnelStateData destructed this=" << this);
392  xfree(url);
393  cancelStep("~TunnelStateData");
394  delete savedError;
395 }
396 
398 {
399  if (readPending)
401 
402  safe_free(buf);
403 }
404 
405 const char *
407 {
408  if (shutting_down)
409  return "shutting down";
411  return "forwarding timeout";
412  if (!retriable)
413  return "not retriable";
414  if (noConnections())
415  return "no connections";
416  return nullptr;
417 }
418 
419 void
420 TunnelStateData::retryOrBail(const char *context)
421 {
422  assert(!server.conn);
423 
424  const auto *bailDescription = checkRetry();
425  if (!bailDescription) {
426  if (!destinations->empty())
427  return startConnecting(); // try connecting to another destination
428 
429  if (subscribed) {
430  debugs(26, 4, "wait for more destinations to try");
431  return; // expect a noteDestination*() call
432  }
433 
434  // fall through to bail
435  }
436 
437  /* bail */
438 
439  if (request)
440  request->hier.stopPeerClock(false);
441 
442  // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
443  // Then, the remaining method code (below) should become the common part of
444  // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
445  if (!savedError)
447  const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
449  if (canSendError)
450  return sendError(savedError, bailDescription ? bailDescription : context);
452 
453  if (noConnections())
454  return deleteThis();
455 
456  // This is a "Comm::IsConnOpen(client.conn) but !canSendError" case.
457  // Closing the connection (after finishing writing) is the best we can do.
458  if (!client.writer)
459  client.conn->close();
460  // else writeClientDone() must notice a closed server and close the client
461 }
462 
463 int
464 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
465 {
466 #if USE_DELAY_POOLS
467  return delayId.bytesWanted(lowerbound, upperbound);
468 #else
469  (void)lowerbound;
470  return upperbound;
471 #endif
472 }
473 
474 void
476 {
477  debugs(26, 3, HERE << "len=" << len << " + count=" << count);
478 #if USE_DELAY_POOLS
479  delayId.bytesIn(count);
480 #endif
481 
482  len += count;
483 }
484 
487 void
489 {
490  request->hier.resetPeerNotes(conn, origin);
491  al->hier.resetPeerNotes(conn, origin);
492 }
493 
494 int
496 {
497 #ifdef ECONNRESET
498 
499  if (xerrno == ECONNRESET)
500  return 2;
501 
502 #endif
503 
504  if (ignoreErrno(xerrno))
505  return 3;
506 
507  return 1;
508 }
509 
510 /* Read from server side and queue it for writing to the client */
511 void
512 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
513 {
514  TunnelStateData *tunnelState = (TunnelStateData *)data;
515  assert(cbdataReferenceValid(tunnelState));
516  debugs(26, 3, HERE << c);
517 
518  tunnelState->readServer(buf, len, errcode, xerrno);
519 }
520 
521 void
522 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
523 {
524  debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
526 
527  /*
528  * Bail out early on Comm::ERR_CLOSING
529  * - close handlers will tidy up for us
530  */
531 
532  if (errcode == Comm::ERR_CLOSING)
533  return;
534 
535  if (len > 0) {
536  server.bytesIn(len);
537  statCounter.server.all.kbytes_in += len;
538  statCounter.server.other.kbytes_in += len;
540  }
541 
542  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
544 }
545 
546 void
548 {
549  debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerr(xerrno));
550 
551  if (!ignoreErrno(xerrno))
552  conn->close();
553 }
554 
555 /* Read from client side and queue it for writing to the server */
556 void
557 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
558 {
559  TunnelStateData *tunnelState = (TunnelStateData *)data;
560  assert (cbdataReferenceValid (tunnelState));
561 
562  tunnelState->readClient(buf, len, errcode, xerrno);
563 }
564 
565 void
566 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
567 {
568  debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
570 
571  /*
572  * Bail out early on Comm::ERR_CLOSING
573  * - close handlers will tidy up for us
574  */
575 
576  if (errcode == Comm::ERR_CLOSING)
577  return;
578 
579  if (len > 0) {
580  client.bytesIn(len);
582  }
583 
584  if (keepGoingAfterRead(len, errcode, xerrno, client, server))
586 }
587 
590 bool
591 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
592 {
593  debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
594 
595  /* I think this is to prevent free-while-in-a-callback behaviour
596  * - RBC 20030229
597  * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
598  */
599  const CbcPointer<TunnelStateData> safetyLock(this);
600 
601  /* Bump the source connection read timeout on any activity */
602  if (Comm::IsConnOpen(from.conn)) {
603  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
605  commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
606  }
607 
608  /* Bump the dest connection read timeout on any activity */
609  /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
610  if (Comm::IsConnOpen(to.conn)) {
611  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
613  commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
614  }
615 
616  if (errcode)
617  from.error (xerrno);
618  else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
619  debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
620  from.conn->close();
621 
622  /* Only close the remote end if we've finished queueing data to it */
623  if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
624  to.conn->close();
625  }
626  } else if (cbdataReferenceValid(this)) {
627  return true;
628  }
629 
630  return false;
631 }
632 
633 void
634 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
635 {
636  debugs(26, 3, HERE << "Schedule Write");
637  AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
638  CommIoCbPtrFun(completion, this));
639  to.write(from.buf, len, call, NULL);
640 }
641 
642 /* Writes data from the client buffer to the server side */
643 void
644 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
645 {
646  TunnelStateData *tunnelState = (TunnelStateData *)data;
647  assert (cbdataReferenceValid (tunnelState));
648  tunnelState->server.writer = NULL;
649 
650  tunnelState->writeServerDone(buf, len, flag, xerrno);
651 }
652 
653 void
654 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
655 {
656  debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
657 
658  if (flag == Comm::ERR_CLOSING)
659  return;
660 
662 
663  /* Error? */
664  if (flag != Comm::OK) {
665  debugs(26, 4, "to-server write failed: " << xerrno);
666  server.error(xerrno); // may call comm_close
667  return;
668  }
669 
670  /* EOF? */
671  if (len == 0) {
672  debugs(26, 4, HERE << "No read input. Closing server connection.");
673  server.conn->close();
674  return;
675  }
676 
677  /* Valid data */
678  statCounter.server.all.kbytes_out += len;
679  statCounter.server.other.kbytes_out += len;
680  client.dataSent(len);
681 
682  /* If the other end has closed, so should we */
683  if (!Comm::IsConnOpen(client.conn)) {
684  debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
685  server.conn->close();
686  return;
687  }
688 
689  const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
690 
691  if (cbdataReferenceValid(this))
692  copyClientBytes();
693 }
694 
695 /* Writes data from the server buffer to the client side */
696 void
697 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
698 {
699  TunnelStateData *tunnelState = (TunnelStateData *)data;
700  assert (cbdataReferenceValid (tunnelState));
701  tunnelState->client.writer = NULL;
702 
703  tunnelState->writeClientDone(buf, len, flag, xerrno);
704 }
705 
706 void
708 {
709  debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
710  assert(amount == (size_t)len);
711  len =0;
712  /* increment total object size */
713 
714  if (size_ptr)
715  *size_ptr += amount;
716 
717 }
718 
719 void
720 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
721 {
722  writer = callback;
723  dirty = true;
724  Comm::Write(conn, b, size, callback, free_func);
725 }
726 
727 template <typename Method>
728 void
730 {
732  Must(!closer);
733  Must(Comm::IsConnOpen(aConn));
734  conn = aConn;
735  closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
736  comm_add_close_handler(conn->fd, closer);
737 }
738 
739 void
741 {
742  debugs(26, 3, conn);
743  conn = nullptr;
744  closer = nullptr;
745  writer = nullptr; // may already be nil
746 }
747 
748 void
749 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
750 {
751  debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
752 
753  if (flag == Comm::ERR_CLOSING)
754  return;
755 
756  /* Error? */
757  if (flag != Comm::OK) {
758  debugs(26, 4, "from-client read failed: " << xerrno);
759  client.error(xerrno); // may call comm_close
760  return;
761  }
762 
763  /* EOF? */
764  if (len == 0) {
765  debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
766  client.conn->close();
767  return;
768  }
769 
770  /* Valid data */
772  server.dataSent(len);
773 
774  /* If the other end has closed, so should we */
775  if (!Comm::IsConnOpen(server.conn)) {
776  debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
777  client.conn->close();
778  return;
779  }
780 
781  CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
782 
783  if (cbdataReferenceValid(this))
784  copyServerBytes();
785 }
786 
787 static void
789 {
790  TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
791  debugs(26, 3, HERE << io.conn);
792  /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
793  CbcPointer<TunnelStateData> safetyLock(tunnelState);
794 
795  tunnelState->closeConnections();
796 }
797 
798 void
800 {
801  debugs(26, 3, "because " << reason << "; " << conn);
802  assert(!server.conn);
803  if (IsConnOpen(conn))
804  conn->close();
805 }
806 
807 void
809 {
811  server.conn->close();
813  client.conn->close();
814 }
815 
816 static void
818 {
819  if (!data)
820  return;
821 
822  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
823  const auto savedContext = CodeContext::Current();
825  tunnel->client.readPending = NULL;
826  static uint64_t counter=0;
827  debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
828  tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
829  CodeContext::Reset(savedContext);
830 }
831 
832 static void
834 {
835  if (!data)
836  return;
837 
838  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
839  const auto savedContext = CodeContext::Current();
841  tunnel->server.readPending = NULL;
842  static uint64_t counter=0;
843  debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
844  tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
845  CodeContext::Reset(savedContext);
846 }
847 
848 void
850 {
851  assert(from.len == 0);
852  // If only the minimum permitted read size is going to be attempted
853  // then we schedule an event to try again in a few I/O cycles.
854  // Allow at least 1 byte to be read every (0.3*10) seconds.
855  int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
856  // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
857  // from.readPendingFunc is tunnelDelayedClientRead()).
858  // XXX: Bug #4913: Use DeferredRead instead.
859  if (bw == 1 && ++from.delayedLoops < 10) {
860  from.readPending = this;
861  eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
862  return;
863  }
864 
865  AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
866  CommIoCbPtrFun(completion, this));
867  comm_read(from.conn, from.buf, bw, call);
868 }
869 
870 void
872 {
873  if (preReadClientData.length()) {
874  size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
875  memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
876  preReadClientData.consume(copyBytes);
877  client.bytesIn(copyBytes);
878  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
880  } else
882 }
883 
884 void
886 {
887  if (preReadServerData.length()) {
888  size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
889  memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
890  preReadServerData.consume(copyBytes);
891  server.bytesIn(copyBytes);
892  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
894  } else
896 }
897 
902 static void
904 {
905  assert(!tunnelState->transportWait);
906  assert(!tunnelState->encryptionWait);
907  assert(!tunnelState->peerWait);
908 
909  assert(tunnelState->server.conn);
910  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
911  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
912  commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
913 
914  *tunnelState->status_ptr = Http::scOkay;
915  tunnelState->al->cache.code.update(LOG_TCP_TUNNEL);
916  if (cbdataReferenceValid(tunnelState)) {
917 
918  // Shovel any payload already pushed into reply buffer by the server response
919  if (!tunnelState->server.len)
920  tunnelState->copyServerBytes();
921  else {
922  debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
923  tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
924  }
925 
926  if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
927  SBuf * const in = &tunnelState->http->getConn()->inBuf;
928  debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
929  tunnelState->preReadClientData.append(*in);
930  in->consume(); // ConnStateData buffer accounting after the shuffle.
931  }
932  tunnelState->copyClientBytes();
933  }
934 }
935 
941 static void
942 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
943 {
944  TunnelStateData *tunnelState = (TunnelStateData *)data;
945  debugs(26, 3, HERE << conn << ", flag=" << flag);
946  tunnelState->client.writer = NULL;
947 
948  if (flag != Comm::OK) {
949  *tunnelState->status_ptr = Http::scInternalServerError;
950  tunnelErrorComplete(conn->fd, data, 0);
951  return;
952  }
953 
954  if (auto http = tunnelState->http.get()) {
955  http->out.headers_sz += len;
956  http->out.size += len;
957  }
958 
959  tunnelStartShoveling(tunnelState);
960 }
961 
962 void
964 {
965  peerWait.finish();
966  server.len = 0;
967 
969 
970  if (answer.peerResponseStatus != Http::scNone)
971  *status_ptr = answer.peerResponseStatus;
972 
973  auto sawProblem = false;
974 
975  if (!answer.positive()) {
976  sawProblem = true;
977  assert(!answer.conn);
978  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
979  sawProblem = true;
980  closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
981  }
982 
983  if (!sawProblem) {
984  assert(answer.positive()); // paranoid
985  // copy any post-200 OK bytes to our buffer
986  preReadServerData = answer.leftovers;
987  notePeerReadyToShovel(answer.conn);
988  return;
989  }
990 
991  ErrorState *error = nullptr;
992  if (answer.positive()) {
994  } else {
995  error = answer.squidError.get();
996  Must(error);
997  answer.squidError.clear(); // preserve error for errorSendComplete()
998  }
999  assert(error);
1000  saveError(error);
1001  retryOrBail("tunneler error");
1002 }
1003 
1004 void
1006 {
1007  assert(!client.dirty);
1008  retriable = false;
1009  server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1010 
1012  tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1013  else {
1015  AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1018  const auto mb = al->reply->pack();
1019  client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1020  delete mb;
1021  }
1022 }
1023 
1024 static void
1025 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1026 {
1027  TunnelStateData *tunnelState = (TunnelStateData *)data;
1028  debugs(26, 3, HERE << "FD " << fd);
1029  assert(tunnelState != NULL);
1030  /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
1031  CbcPointer<TunnelStateData> safetyLock(tunnelState);
1032 
1033  if (Comm::IsConnOpen(tunnelState->client.conn))
1034  tunnelState->client.conn->close();
1035 
1036  if (Comm::IsConnOpen(tunnelState->server.conn))
1037  tunnelState->server.conn->close();
1038 }
1039 
1040 void
1042 {
1043  transportWait.finish();
1044 
1045  ErrorState *error = nullptr;
1046  if ((error = answer.error.get())) {
1047  Must(!Comm::IsConnOpen(answer.conn));
1048  syncHierNote(answer.conn, request->url.host());
1049  answer.error.clear();
1050  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1052  closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1053  }
1054 
1055  if (error) {
1056  saveError(error);
1057  retryOrBail("tried all destinations");
1058  return;
1059  }
1060 
1061  connectDone(answer.conn, request->url.host(), answer.reused);
1062 }
1063 
1064 void
1065 TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1066 {
1068 
1069  if (reused)
1071  // else Comm::ConnOpener already applied proper/current markings
1072 
1073  syncHierNote(conn, origin);
1074 
1075 #if USE_DELAY_POOLS
1076  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1077  if (conn->getPeer() && conn->getPeer()->options.no_delay)
1079 #endif
1080 
1082 
1083  request->peer_host = conn->getPeer() ? conn->getPeer()->host : nullptr;
1084 
1085  bool toOrigin = false; // same semantics as StateFlags::toOrigin
1086  if (const auto * const peer = conn->getPeer()) {
1087  request->prepForPeering(*peer);
1088  toOrigin = peer->options.originserver;
1089  } else {
1091  toOrigin = true;
1092  }
1093 
1094  if (!toOrigin)
1096  else {
1098  }
1099 }
1100 
1101 void
1103 {
1104  debugs(26, 3, HERE);
1105  /* Create state structure. */
1106  TunnelStateData *tunnelState = NULL;
1107  ErrorState *err = NULL;
1109  char *url = http->uri;
1110 
1111  /*
1112  * client_addr.isNoAddr() indicates this is an "internal" request
1113  * from peer_digest.c, asn.c, netdb.c, etc and should always
1114  * be allowed. yuck, I know.
1115  */
1116 
1118  /*
1119  * Check if this host is allowed to fetch MISSES from us (miss_access)
1120  * default is to allow.
1121  */
1123  ch.al = http->al;
1125  ch.my_addr = request->my_addr;
1126  ch.syncAle(request, http->log_uri);
1127  if (ch.fastCheck().denied()) {
1128  debugs(26, 4, HERE << "MISS access forbidden.");
1130  http->al->http.code = Http::scForbidden;
1132  return;
1133  }
1134  }
1135 
1136  debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1137  ++statCounter.server.all.requests;
1138  ++statCounter.server.other.requests;
1139 
1140  tunnelState = new TunnelStateData(http);
1141 #if USE_DELAY_POOLS
1142  tunnelState->server.setDelayId(DelayId::DelayClient(http));
1143 #endif
1144  tunnelState->startSelectingDestinations(request, http->al, nullptr);
1145 }
1146 
1147 void
1149 {
1150  if (const auto p = conn->getPeer()) {
1151  if (p->secure.encryptTransport)
1152  return advanceDestination("secure connection to peer", conn, [this,&conn] {
1154  });
1155  }
1156 
1158 }
1159 
1161 void
1163 {
1164  AsyncCall::Pointer callback = asyncCall(5,4, "TunnelStateData::noteSecurityPeerConnectorAnswer",
1166  const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1167  encryptionWait.start(connector, callback);
1168 }
1169 
1171 template <typename StepStart>
1172 void
1173 TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1174 {
1175  // TODO: Extract destination-specific handling from TunnelStateData so that
1176  // all the awkward, limited-scope advanceDestination() calls can be replaced
1177  // with a single simple try/catch,retry block.
1178  try {
1179  startStep();
1180  // now wait for the step callback
1181  } catch (...) {
1182  debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1183  closePendingConnection(conn, "connection preparation exception");
1184  if (!savedError)
1186  retryOrBail(stepDescription);
1187  }
1188 }
1189 
1191 void
1193 {
1194  encryptionWait.finish();
1195 
1196  ErrorState *error = nullptr;
1197  assert(!answer.tunneled);
1198  if ((error = answer.error.get())) {
1199  assert(!answer.conn);
1200  answer.error.clear();
1201  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1203  closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1204  }
1205 
1206  if (error) {
1207  saveError(error);
1208  retryOrBail("TLS peer connection error");
1209  return;
1210  }
1211 
1212  connectedToPeer(answer.conn);
1213 }
1214 
1215 void
1217 {
1218  advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1220  });
1221 }
1222 
1223 void
1225 {
1226  AsyncCall::Pointer callback = asyncCall(5,4,
1227  "TunnelStateData::tunnelEstablishmentDone",
1229  const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1230 #if USE_DELAY_POOLS
1231  tunneler->setDelayId(server.delayId);
1232 #endif
1233  peerWait.start(tunneler, callback);
1234 }
1235 
1236 void
1238 {
1239  destinationsFound = true;
1240 
1241  if (!path) { // decided to use a pinned connection
1242  // We can call usePinned() without fear of clashing with an earlier
1243  // forwarding attempt because PINNED must be the first destination.
1245  usePinned();
1246  return;
1247  }
1248 
1249  destinations->addPath(path);
1250 
1251  if (usingDestination()) {
1252  // We are already using a previously opened connection but also
1253  // receiving destinations in case we need to re-forward.
1254  Must(!transportWait);
1255  return;
1256  }
1257 
1258  if (transportWait) {
1259  notifyConnOpener();
1260  return; // and continue to wait for tunnelConnectDone() callback
1261  }
1262 
1263  startConnecting();
1264 }
1265 
1266 void
1268 {
1271  if (!destinationsFound) {
1272 
1273  // XXX: Honor clientExpectsConnectResponse() before replying.
1274 
1275  if (selectionError)
1276  return sendError(selectionError, "path selection has failed");
1277 
1278  if (savedError)
1279  return sendError(savedError, "all found paths have failed");
1280 
1282  "path selection found no paths");
1283  }
1284  // else continue to use one of the previously noted destinations;
1285  // if all of them fail, tunneling as whole will fail
1286  Must(!selectionError); // finding at least one path means selection succeeded
1287 
1288  if (usingDestination()) {
1289  // We are already using a previously opened connection but also
1290  // receiving destinations in case we need to re-forward.
1291  Must(!transportWait);
1292  return;
1293  }
1294 
1295  Must(transportWait); // or we would be stuck with nothing to do or wait for
1296  notifyConnOpener();
1297 }
1298 
1299 bool
1301 {
1303 }
1304 
1306 void
1308 {
1309  debugs(26, 4, savedError << " ? " << error);
1310  assert(error);
1311  delete savedError; // may be nil
1312  savedError = error;
1313 }
1314 
1317 void
1318 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1319 {
1320  debugs(26, 3, "aborting transaction for " << reason);
1321 
1322  if (request)
1323  request->hier.stopPeerClock(false);
1324 
1325  cancelStep(reason);
1326 
1327  assert(finalError);
1328 
1329  // get rid of any cached error unless that is what the caller is sending
1330  if (savedError != finalError)
1331  delete savedError; // may be nil
1332  savedError = nullptr;
1333 
1334  // we cannot try other destinations after responding with an error
1335  PeerSelectionInitiator::subscribed = false; // may already be false
1336 
1337  *status_ptr = finalError->httpStatus;
1338  finalError->callback = tunnelErrorComplete;
1339  finalError->callback_data = this;
1340  errorSend(client.conn, finalError);
1341 }
1342 
1346 void
1347 TunnelStateData::cancelStep(const char *reason)
1348 {
1349  transportWait.cancel(reason);
1350  encryptionWait.cancel(reason);
1351  peerWait.cancel(reason);
1352 }
1353 
1354 void
1356 {
1357  if (request)
1359 
1360  assert(!destinations->empty());
1362  AsyncCall::Pointer callback = asyncCall(17, 5, "TunnelStateData::noteConnection", HappyConnOpener::CbDialer<TunnelStateData>(&TunnelStateData::noteConnection, this));
1363  const auto cs = new HappyConnOpener(destinations, callback, request, startTime, 0, al);
1364  cs->setHost(request->url.host());
1365  cs->setRetriable(false);
1366  cs->allowPersistent(false);
1367  destinations->notificationPending = true; // start() is async
1368  transportWait.start(cs, callback);
1369 }
1370 
1372 void
1374 {
1375  Must(request);
1376  const auto connManager = request->pinnedConnection();
1377  try {
1378  const auto serverConn = ConnStateData::BorrowPinnedConnection(request.getRaw(), al);
1379  debugs(26, 7, "pinned peer connection: " << serverConn);
1380 
1381  // Set HttpRequest pinned related flags for consistency even if
1382  // they are not really used by tunnel.cc code.
1383  request->flags.pinned = true;
1384  if (connManager->pinnedAuth())
1385  request->flags.auth = true;
1386 
1387  // the server may close the pinned connection before this request
1388  const auto reused = true;
1389  connectDone(serverConn, connManager->pinning.host, reused);
1390  } catch (ErrorState * const error) {
1391  syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1392  // XXX: Honor clientExpectsConnectResponse() before replying.
1393  // a PINNED path failure is fatal; do not wait for more paths
1394  sendError(error, "pinned path failure");
1395  return;
1396  }
1397 
1398 }
1399 
1401 
1402 bool
1404 {
1406 }
1407 
1408 #if USE_DELAY_POOLS
1409 void
1411 {
1412  delayId = newDelay;
1413 }
1414 
1415 #endif
1416 
1418 void
1420 {
1422  debugs(17, 7, "reusing pending notification");
1423  } else {
1425  CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
1426  }
1427 }
1428 
1436 void
1438 {
1439  Must(Comm::IsConnOpen(clientConn));
1440  Must(Comm::IsConnOpen(srvConn));
1441 
1442  debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1443 
1444  /* Create state structure. */
1445  ++statCounter.server.all.requests;
1446  ++statCounter.server.other.requests;
1447 
1449  Must(conn);
1450  Http::StreamPointer context = conn->pipeline.front();
1451  Must(context && context->http);
1452 
1453  debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1454 
1455  TunnelStateData *tunnelState = new TunnelStateData(context->http);
1456  tunnelState->retriable = false;
1457 
1458  request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1459 
1460  tunnelState->server.initConnection(srvConn, tunnelServerClosed, "tunnelServerClosed", tunnelState);
1461 
1462 #if USE_DELAY_POOLS
1463  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1464  if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1465  tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1466 #endif
1467 
1468  request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1469 
1470  debugs(26, 4, "determine post-connect handling pathway.");
1471  if (const auto peer = srvConn->getPeer())
1472  request->prepForPeering(*peer);
1473  else
1475 
1476  tunnelState->preReadServerData = preReadServerData;
1477 
1478  tunnelStartShoveling(tunnelState);
1479 }
1480 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void noteConnection(HappyConnOpenerAnswer &)
Definition: tunnel.cc:1041
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:162
virtual void print(std::ostream &os) const
Definition: tunnel.cc:239
void ERCB(int fd, void *, size_t)
error page callback
Definition: errorpage.h:28
static DelayId DelayClient(ClientHttpRequest *, HttpReply *reply=nullptr)
Definition: DelayId.cc:67
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:922
JobPointer job() const
Definition: JobWait.h:76
void dial(AsyncCall &)
Definition: tunnel.cc:238
bool tunneled
whether we spliced the connections instead of negotiating encryption
char * peer_host
Definition: HttpRequest.h:165
TunnelStateData(const TunnelStateData &)
CodeContext::Pointer codeContext
our creator context
Definition: tunnel.cc:190
AnyP::ProtocolVersion http_ver
Definition: Message.h:73
struct SquidConfig::@97 Timeout
int * status_ptr
pointer for logging HTTP status
Definition: tunnel.cc:179
time_t startTime
object creation time, before any peer selection/connection attempts
Definition: tunnel.cc:183
void notePeerReadyToShovel(const Comm::ConnectionPointer &)
called when negotiations with the peer have been successfully completed
Definition: tunnel.cc:1005
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:66
#define xmalloc
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
void copyClientBytes()
Definition: tunnel.cc:871
CbcPointer< TunnelStateData > tunnel_
Definition: tunnel.cc:248
bool noConnections() const
Definition: tunnel.cc:1403
void clientClosed()
handles client-to-Squid connection closure; may destroy us
Definition: tunnel.cc:334
Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
Definition: tunnel.cc:229
Interface for those who need a list of peers to forward a request to.
JobWait< Http::Tunneler > peerWait
Definition: tunnel.cc:200
void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
Start using an established connection.
Definition: tunnel.cc:1065
void noteClosure()
reacts to the external closure of our connection
Definition: tunnel.cc:740
Ip::Address src_addr
void stopPeerClock(const bool force)
Definition: access_log.cc:304
ERCB * callback
Definition: errorpage.h:184
bool destinationsFinalized
whether all of the available candidate paths received from DNS
Definition: ResolvedPeers.h:81
@ scNone
Definition: StatusCode.h:21
SBuf inBuf
read I/O buffer for the client connection
Definition: Server.h:111
void FREE(void *)
Definition: forward.h:36
void eventDelete(EVH *func, void *arg)
Definition: event.cc:130
CbcPointer< ErrorState > error
problem details (nil on success)
bool isEmpty() const
Definition: SBuf.h:424
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:697
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:302
ConnStateData * getConn() const
void(TunnelStateData::* Method)(Security::EncryptorAnswer &)
Definition: tunnel.cc:231
Connection server
Definition: tunnel.cc:178
TunnelStateData & operator=(const TunnelStateData &)
static void tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
Definition: tunnel.cc:942
void error(char *format,...)
void saveError(ErrorState *finalError)
remembers an error to be used if there will be no more connection attempts
Definition: tunnel.cc:1307
void copyServerBytes()
Definition: tunnel.cc:885
HttpReplyPointer reply
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:335
void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
Definition: tunnel.cc:799
Definition: SBuf.h:87
acl_access * miss
Definition: SquidConfig.h:369
void secureConnectionToPeer(const Comm::ConnectionPointer &)
encrypts an established TCP connection to peer
Definition: tunnel.cc:1162
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:464
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:564
#define xstrdup
bool clientExpectsConnectResponse() const
Whether the client sent a CONNECT request to us.
Definition: tunnel.cc:102
void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:566
HierarchyLogEntry hier
struct ClientHttpRequest::Out out
C * getRaw() const
Definition: RefCount.h:80
virtual void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: tunnel.cc:1237
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:398
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
bool dirty
whether write() has been called (at least once)
Definition: tunnel.cc:162
TunnelStateData * readPending
Definition: tunnel.cc:165
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
struct StatCounters::@129 server
@ OK
Definition: Flag.h:16
void error(int const xerrno)
Definition: tunnel.cc:547
void closeConnections()
closes both client and server connections
Definition: tunnel.cc:808
void connectToPeer(const Comm::ConnectionPointer &)
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1148
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:42
@ ERR_CLOSING
Definition: Flag.h:25
AsyncCall::Pointer writer
pending Comm::Write callback
Definition: tunnel.cc:156
Callback dialer API to allow Tunneler to set the answer.
Definition: HttpTunneler.h:40
TunnelStateData(ClientHttpRequest *)
Definition: tunnel.cc:360
bool usingDestination() const
Definition: tunnel.cc:1300
bool empty() const
whether we lack any known candidate paths
Definition: ResolvedPeers.h:45
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:75
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:1173
const char * checkRetry()
Definition: tunnel.cc:406
void syncHierNote(const Comm::ConnectionPointer &server, const char *origin)
Definition: tunnel.cc:488
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition: tunnel.cc:271
Definition: Debug.h:184
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:59
static CLCB tunnelClientClosed
Definition: tunnel.cc:304
void update(const LogTags_ot t)
Definition: LogTags.cc:54
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition: tunnel.cc:903
void copyRead(Connection &from, IOCB *completion)
Definition: tunnel.cc:849
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: tunnel.cc:963
Comm::ConnectionPointer conn
peer connection (secured on success)
ByteCounter kbytes_in
Definition: StatCounters.h:45
int size
Definition: ModDevPoll.cc:76
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:751
#define NULL
Definition: types.h:166
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:749
time_t read
Definition: SquidConfig.h:110
void sendError(ErrorState *finalError, const char *reason)
Definition: tunnel.cc:1318
@ scForbidden
Definition: StatusCode.h:47
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1609
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:39
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
@ LOG_TCP_TUNNEL
Definition: LogTags.h:56
SBuf preReadClientData
Definition: tunnel.cc:181
struct StatCounters::@129::@139 all
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:720
bool destinationsFound
Definition: tunnel.cc:185
Security::EncryptorAnswer answer_
Definition: tunnel.cc:249
AccessLogEntryPointer al
Definition: tunnel.cc:95
void setDelayId(DelayId const &)
Definition: tunnel.cc:1410
CbcPointer< ClientHttpRequest > http
Definition: tunnel.cc:93
MemBuf * pack() const
Definition: HttpReply.cc:111
#define true
Definition: GnuRegex.c:234
#define INT_MAX
Definition: types.h:76
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:733
void copy(size_t len, Connection &from, Connection &to, IOCB *)
Definition: tunnel.cc:634
CachePeer * getPeer() const
Definition: Connection.cc:124
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:152
void dataSent(size_t amount)
Definition: tunnel.cc:707
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
Definition: tunnel.cc:1437
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:36
void startConnecting()
Definition: tunnel.cc:1355
Callback dialer API to allow PeerConnector to set the answer.
Definition: PeerConnector.h:57
virtual ~TunnelStateData()
Definition: tunnel.cc:388
void bytesIn(int const &)
Definition: tunnel.cc:475
#define CallJobHere(debugSection, debugLevel, job, Class, method)
Definition: AsyncJobCalls.h:58
Comm::ConnectionPointer conn
The currently connected connection.
Definition: tunnel.cc:159
uint8_t delayedLoops
how many times a read on this connection has been postponed.
Definition: tunnel.cc:160
bool denied() const
Definition: Acl.h:155
virtual void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1267
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
#define safe_free(x)
Definition: xalloc.h:73
struct SquidConfig::@112 accessList
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:654
int conn
the current server connection FD
Definition: Transport.cc:26
JobWait< HappyConnOpener > transportWait
waits for a transport connection to the peer to be established/opened
Definition: tunnel.cc:193
#define assert(EX)
Definition: assert.h:19
void startPeerClock()
Start recording total time spent communicating with peers.
Definition: access_log.cc:297
bool intercepted
Definition: RequestFlags.h:62
class AccessLogEntry::CacheDetails cache
HierarchyLogEntry hier
Definition: HttpRequest.h:157
bool retriable
Definition: tunnel.cc:188
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:463
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
@ scServiceUnavailable
Definition: StatusCode.h:74
MyAnswerDialer(Method method, TunnelStateData *tunnel)
Definition: tunnel.cc:233
char * url
Definition: tunnel.cc:92
Ip::Address my_addr
Definition: HttpRequest.h:155
virtual bool canDial(AsyncCall &)
Definition: tunnel.cc:237
@ scInternalServerError
Definition: StatusCode.h:71
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: tunnel.cc:196
static CTCB tunnelTimeout
Definition: tunnel.cc:305
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:34
static CLCB tunnelServerClosed
Definition: tunnel.cc:303
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:408
time_t squid_curtime
Definition: stub_time.cc:17
CBDATA_CHILD(TunnelStateData)
Comm::ConnectionPointer clientConnection
Definition: Server.h:98
void establishTunnelThruProxy(const Comm::ConnectionPointer &)
Definition: tunnel.cc:1224
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:284
#define xfree
bool notificationPending
whether HappyConnOpener::noteCandidatesChange() is scheduled to fire
Definition: ResolvedPeers.h:84
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 simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.
void retryOrBail(const char *context)
Definition: tunnel.cc:420
int ignoreErrno(int ierrno)
Definition: comm.cc:1411
#define fd_table
Definition: fde.h:189
virtual Security::EncryptorAnswer & answer()
gives PeerConnector access to the in-dialer answer
Definition: tunnel.cc:244
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:495
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: tunnel.cc:1373
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:557
char * host
Definition: CachePeer.h:40
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:447
@ ERR_FORWARDING_DENIED
Definition: forward.h:21
static const Pointer & Current()
Definition: CodeContext.cc:33
void cancelStep(const char *reason)
Definition: tunnel.cc:1347
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:644
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:591
HttpRequest::Pointer request
Definition: tunnel.cc:94
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: tunnel.cc:1419
AsyncCall dialer for our callback. Gives us access to callback Answer.
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:73
void tunnelStart(ClientHttpRequest *http)
Definition: tunnel.cc:1102
SBuf preReadServerData
Definition: tunnel.cc:182
void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
initiates Comm::Connection ownership, including closure monitoring
Definition: tunnel.cc:729
SBuf leftovers
peer-generated bytes after a positive answer (or empty)
Ssl::ServerBump * serverBump()
Definition: client_side.h:286
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
static HttpReplyPointer MakeConnectionEstablished()
construct and return an HTTP/200 (Connection Established) response
Definition: HttpReply.cc:120
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:251
const AccessLogEntry::Pointer al
access.log entry
bool reused
whether conn was open earlier, by/for somebody else
struct StatCounters::@128 client_http
int shutting_down
void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:522
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: tunnel.cc:184
struct StatCounters::@129::@139 other
void prepForDirect()
get ready to be sent directly to an origin server, excluding originserver
Definition: HttpRequest.cc:457
@ ERR_CANNOT_FORWARD
Definition: forward.h:23
AsyncCall::Pointer closer
the registered close handler for the connection
Definition: tunnel.cc:175
void serverClosed()
handles Squid-to-server connection closure; may destroy us
Definition: tunnel.cc:318
@ scOkay
Definition: StatusCode.h:26
const char * getHost() const
Definition: tunnel.cc:97
time_t lifetime
Definition: SquidConfig.h:112
void connectedToPeer(const Comm::ConnectionPointer &)
called after connection setup (including any encryption)
Definition: tunnel.cc:1216
void * callback_data
Definition: errorpage.h:185
void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &)
callback handler for the Security::PeerConnector encryptor
Definition: tunnel.cc:1192
#define false
Definition: GnuRegex.c:233
static EVH tunnelDelayedServerRead
Definition: tunnel.cc:307
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:98
Connection client
Definition: tunnel.cc:178
void netdbPingSite(const char *hostname)
Definition: net_db.cc:908
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
Definition: RequestFlags.h:111
ByteCounter kbytes_out
Definition: StatCounters.h:46
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:108
static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:512
Http::StatusCode httpStatus
Definition: errorpage.h:171
CbcPointer< ErrorState > squidError
problem details (or nil)
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:232
class SquidConfig Config
Definition: SquidConfig.cc:12
HttpRequest *const request
StatCounters statCounter
Definition: StatCounters.cc:12
#define DBG_DATA
Definition: Debug.h:43
void deleteThis()
destroys the tunnel (after performing potentially-throwing cleanup)
Definition: tunnel.cc:347
static EVH tunnelDelayedClientRead
Definition: tunnel.cc:306

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors