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;
181 
184  time_t startTime;
187  bool retriable;
190  // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
192 
195 
198 
202 
203  void copyRead(Connection &from, IOCB *completion);
204 
208 
209  /* PeerSelectionInitiator API */
210  virtual void noteDestination(Comm::ConnectionPointer conn) override;
211  virtual void noteDestinationsEnd(ErrorState *selectionError) override;
212 
213  void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
214 
218 
220  void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
221 
222  void notifyConnOpener();
223 
224  void saveError(ErrorState *finalError);
225  void sendError(ErrorState *finalError, const char *reason);
226 
227 private:
230  {
231  public:
233 
235  method_(method), tunnel_(tunnel), answer_() {}
236 
237  /* CallDialer API */
238  virtual bool canDial(AsyncCall &) { return tunnel_.valid(); }
239  void dial(AsyncCall &) { ((&(*tunnel_))->*method_)(answer_); }
240  virtual void print(std::ostream &os) const {
241  os << '(' << tunnel_.get() << ", " << answer_ << ')';
242  }
243 
244  /* Security::PeerConnector::CbDialer API */
245  virtual Security::EncryptorAnswer &answer() { return answer_; }
246 
247  private:
251  };
252 
253  void usePinned();
254 
257 
261 
262  template <typename StepStart>
263  void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
264 
266  const char *checkRetry();
269  bool usingDestination() const;
270 
272  ErrorState *savedError = nullptr;
273 
276 
277  void deleteThis();
278 
279  void cancelStep(const char *reason);
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 
311 static void
313 {
314  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
315  tunnelState->serverClosed();
316 }
317 
318 void
320 {
322 }
323 
325 static void
327 {
328  const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
329  tunnelState->clientClosed();
330 }
331 
332 void
334 {
336 
337  if (noConnections())
338  return deleteThis();
339 
340  if (!server.writer)
341  server.conn->close();
342 }
343 
345 void
347 {
349  // ConnStateData pipeline should contain the CONNECT we are performing
350  // but it may be invalid already (bug 4392)
351  if (const auto h = http.valid()) {
352  if (const auto c = h->getConn())
353  if (const auto ctx = c->pipeline.front())
354  ctx->finished();
355  }
356  delete this;
357 }
358 
360  startTime(squid_curtime),
361  destinations(new ResolvedPeers()),
362  destinationsFound(false),
363  retriable(true),
364  codeContext(CodeContext::Current())
365 {
366  debugs(26, 3, "TunnelStateData constructed this=" << this);
369 
370  assert(clientRequest);
371  url = xstrdup(clientRequest->uri);
372  request = clientRequest->request;
373  Must(request);
374  server.size_ptr = &clientRequest->out.size;
375  client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
376  status_ptr = &clientRequest->al->http.code;
377  logTag_ptr = &clientRequest->logType;
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  // Since no TCP payload has been passed to client or server, we may
423  // TCP-connect to other destinations (including alternate IPs).
424 
425  assert(!server.conn);
426 
427  const auto *bailDescription = checkRetry();
428  if (!bailDescription) {
429  if (!destinations->empty())
430  return startConnecting(); // try connecting to another destination
431 
432  if (subscribed) {
433  debugs(26, 4, "wait for more destinations to try");
434  return; // expect a noteDestination*() call
435  }
436 
437  // fall through to bail
438  }
439 
440  /* bail */
441 
442  if (request)
443  request->hier.stopPeerClock(false);
444 
445  // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
446  // Then, the remaining method code (below) should become the common part of
447  // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
448  if (!savedError)
450  const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
452  if (canSendError)
453  return sendError(savedError, bailDescription ? bailDescription : context);
455 
456  if (noConnections())
457  return deleteThis();
458 
459  // This is a "Comm::IsConnOpen(client.conn) but !canSendError" case.
460  // Closing the connection (after finishing writing) is the best we can do.
461  if (!client.writer)
462  client.conn->close();
463  // else writeClientDone() must notice a closed server and close the client
464 }
465 
466 int
467 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
468 {
469 #if USE_DELAY_POOLS
470  return delayId.bytesWanted(lowerbound, upperbound);
471 #else
472  (void)lowerbound;
473  return upperbound;
474 #endif
475 }
476 
477 void
479 {
480  debugs(26, 3, HERE << "len=" << len << " + count=" << count);
481 #if USE_DELAY_POOLS
482  delayId.bytesIn(count);
483 #endif
484 
485  len += count;
486 }
487 
490 void
492 {
493  request->hier.resetPeerNotes(conn, origin);
494  if (al)
495  al->hier.resetPeerNotes(conn, origin);
496 }
497 
498 int
500 {
501 #ifdef ECONNRESET
502 
503  if (xerrno == ECONNRESET)
504  return 2;
505 
506 #endif
507 
508  if (ignoreErrno(xerrno))
509  return 3;
510 
511  return 1;
512 }
513 
514 /* Read from server side and queue it for writing to the client */
515 void
516 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
517 {
518  TunnelStateData *tunnelState = (TunnelStateData *)data;
519  assert(cbdataReferenceValid(tunnelState));
520  debugs(26, 3, HERE << c);
521 
522  tunnelState->readServer(buf, len, errcode, xerrno);
523 }
524 
525 void
526 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
527 {
528  debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
530 
531  /*
532  * Bail out early on Comm::ERR_CLOSING
533  * - close handlers will tidy up for us
534  */
535 
536  if (errcode == Comm::ERR_CLOSING)
537  return;
538 
539  if (len > 0) {
540  server.bytesIn(len);
541  statCounter.server.all.kbytes_in += len;
542  statCounter.server.other.kbytes_in += len;
544  }
545 
546  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
548 }
549 
550 void
552 {
553  debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerr(xerrno));
554 
555  if (!ignoreErrno(xerrno))
556  conn->close();
557 }
558 
559 /* Read from client side and queue it for writing to the server */
560 void
561 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
562 {
563  TunnelStateData *tunnelState = (TunnelStateData *)data;
564  assert (cbdataReferenceValid (tunnelState));
565 
566  tunnelState->readClient(buf, len, errcode, xerrno);
567 }
568 
569 void
570 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
571 {
572  debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
574 
575  /*
576  * Bail out early on Comm::ERR_CLOSING
577  * - close handlers will tidy up for us
578  */
579 
580  if (errcode == Comm::ERR_CLOSING)
581  return;
582 
583  if (len > 0) {
584  client.bytesIn(len);
586  }
587 
588  if (keepGoingAfterRead(len, errcode, xerrno, client, server))
590 }
591 
594 bool
595 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
596 {
597  debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
598 
599  /* I think this is to prevent free-while-in-a-callback behaviour
600  * - RBC 20030229
601  * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
602  */
603  const CbcPointer<TunnelStateData> safetyLock(this);
604 
605  /* Bump the source connection read timeout on any activity */
606  if (Comm::IsConnOpen(from.conn)) {
607  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
609  commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
610  }
611 
612  /* Bump the dest connection read timeout on any activity */
613  /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
614  if (Comm::IsConnOpen(to.conn)) {
615  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
617  commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
618  }
619 
620  if (errcode)
621  from.error (xerrno);
622  else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
623  debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
624  from.conn->close();
625 
626  /* Only close the remote end if we've finished queueing data to it */
627  if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
628  to.conn->close();
629  }
630  } else if (cbdataReferenceValid(this)) {
631  return true;
632  }
633 
634  return false;
635 }
636 
637 void
638 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
639 {
640  debugs(26, 3, HERE << "Schedule Write");
641  AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
642  CommIoCbPtrFun(completion, this));
643  to.write(from.buf, len, call, NULL);
644 }
645 
646 /* Writes data from the client buffer to the server side */
647 void
648 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
649 {
650  TunnelStateData *tunnelState = (TunnelStateData *)data;
651  assert (cbdataReferenceValid (tunnelState));
652  tunnelState->server.writer = NULL;
653 
654  tunnelState->writeServerDone(buf, len, flag, xerrno);
655 }
656 
657 void
658 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
659 {
660  debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
661 
662  if (flag == Comm::ERR_CLOSING)
663  return;
664 
666 
667  /* Error? */
668  if (flag != Comm::OK) {
669  debugs(26, 4, "to-server write failed: " << xerrno);
670  server.error(xerrno); // may call comm_close
671  return;
672  }
673 
674  /* EOF? */
675  if (len == 0) {
676  debugs(26, 4, HERE << "No read input. Closing server connection.");
677  server.conn->close();
678  return;
679  }
680 
681  /* Valid data */
682  statCounter.server.all.kbytes_out += len;
683  statCounter.server.other.kbytes_out += len;
684  client.dataSent(len);
685 
686  /* If the other end has closed, so should we */
687  if (!Comm::IsConnOpen(client.conn)) {
688  debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
689  server.conn->close();
690  return;
691  }
692 
693  const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
694 
695  if (cbdataReferenceValid(this))
696  copyClientBytes();
697 }
698 
699 /* Writes data from the server buffer to the client side */
700 void
701 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
702 {
703  TunnelStateData *tunnelState = (TunnelStateData *)data;
704  assert (cbdataReferenceValid (tunnelState));
705  tunnelState->client.writer = NULL;
706 
707  tunnelState->writeClientDone(buf, len, flag, xerrno);
708 }
709 
710 void
712 {
713  debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
714  assert(amount == (size_t)len);
715  len =0;
716  /* increment total object size */
717 
718  if (size_ptr)
719  *size_ptr += amount;
720 
721 }
722 
723 void
724 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
725 {
726  writer = callback;
727  dirty = true;
728  Comm::Write(conn, b, size, callback, free_func);
729 }
730 
731 template <typename Method>
732 void
734 {
736  Must(!closer);
737  Must(Comm::IsConnOpen(aConn));
738  conn = aConn;
739  closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
740  comm_add_close_handler(conn->fd, closer);
741 }
742 
743 void
745 {
746  debugs(26, 3, conn);
747  conn = nullptr;
748  closer = nullptr;
749  writer = nullptr; // may already be nil
750 }
751 
752 void
753 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
754 {
755  debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
756 
757  if (flag == Comm::ERR_CLOSING)
758  return;
759 
760  /* Error? */
761  if (flag != Comm::OK) {
762  debugs(26, 4, "from-client read failed: " << xerrno);
763  client.error(xerrno); // may call comm_close
764  return;
765  }
766 
767  /* EOF? */
768  if (len == 0) {
769  debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
770  client.conn->close();
771  return;
772  }
773 
774  /* Valid data */
776  server.dataSent(len);
777 
778  /* If the other end has closed, so should we */
779  if (!Comm::IsConnOpen(server.conn)) {
780  debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
781  client.conn->close();
782  return;
783  }
784 
785  CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
786 
787  if (cbdataReferenceValid(this))
788  copyServerBytes();
789 }
790 
791 static void
793 {
794  TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
795  debugs(26, 3, HERE << io.conn);
796  /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
797  CbcPointer<TunnelStateData> safetyLock(tunnelState);
798 
799  tunnelState->closeConnections();
800 }
801 
802 void
804 {
805  debugs(26, 3, "because " << reason << "; " << conn);
806  assert(!server.conn);
807  if (IsConnOpen(conn))
808  conn->close();
809 }
810 
811 void
813 {
815  server.conn->close();
817  client.conn->close();
818 }
819 
820 static void
822 {
823  if (!data)
824  return;
825 
826  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
827  const auto savedContext = CodeContext::Current();
829  tunnel->client.readPending = NULL;
830  static uint64_t counter=0;
831  debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
832  tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
833  CodeContext::Reset(savedContext);
834 }
835 
836 static void
838 {
839  if (!data)
840  return;
841 
842  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
843  const auto savedContext = CodeContext::Current();
845  tunnel->server.readPending = NULL;
846  static uint64_t counter=0;
847  debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
848  tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
849  CodeContext::Reset(savedContext);
850 }
851 
852 void
854 {
855  assert(from.len == 0);
856  // If only the minimum permitted read size is going to be attempted
857  // then we schedule an event to try again in a few I/O cycles.
858  // Allow at least 1 byte to be read every (0.3*10) seconds.
859  int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
860  // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
861  // from.readPendingFunc is tunnelDelayedClientRead()).
862  // XXX: Bug #4913: Use DeferredRead instead.
863  if (bw == 1 && ++from.delayedLoops < 10) {
864  from.readPending = this;
865  eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
866  return;
867  }
868 
869  AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
870  CommIoCbPtrFun(completion, this));
871  comm_read(from.conn, from.buf, bw, call);
872 }
873 
874 void
876 {
877  if (preReadClientData.length()) {
878  size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
879  memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
880  preReadClientData.consume(copyBytes);
881  client.bytesIn(copyBytes);
882  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
884  } else
886 }
887 
888 void
890 {
891  if (preReadServerData.length()) {
892  size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
893  memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
894  preReadServerData.consume(copyBytes);
895  server.bytesIn(copyBytes);
896  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
898  } else
900 }
901 
906 static void
908 {
909  assert(!tunnelState->transportWait);
910  assert(!tunnelState->encryptionWait);
911  assert(!tunnelState->peerWait);
912 
913  assert(tunnelState->server.conn);
914  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
915  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
916  commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
917 
918  *tunnelState->status_ptr = Http::scOkay;
919  if (tunnelState->logTag_ptr)
920  tunnelState->logTag_ptr->update(LOG_TCP_TUNNEL);
921  if (cbdataReferenceValid(tunnelState)) {
922 
923  // Shovel any payload already pushed into reply buffer by the server response
924  if (!tunnelState->server.len)
925  tunnelState->copyServerBytes();
926  else {
927  debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
928  tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
929  }
930 
931  if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
932  SBuf * const in = &tunnelState->http->getConn()->inBuf;
933  debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
934  tunnelState->preReadClientData.append(*in);
935  in->consume(); // ConnStateData buffer accounting after the shuffle.
936  }
937  tunnelState->copyClientBytes();
938  }
939 }
940 
946 static void
947 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
948 {
949  TunnelStateData *tunnelState = (TunnelStateData *)data;
950  debugs(26, 3, HERE << conn << ", flag=" << flag);
951  tunnelState->client.writer = NULL;
952 
953  if (flag != Comm::OK) {
954  *tunnelState->status_ptr = Http::scInternalServerError;
955  tunnelErrorComplete(conn->fd, data, 0);
956  return;
957  }
958 
959  if (auto http = tunnelState->http.get()) {
960  http->out.headers_sz += len;
961  http->out.size += len;
962  }
963 
964  tunnelStartShoveling(tunnelState);
965 }
966 
967 void
969 {
970  peerWait.finish();
971  server.len = 0;
972 
973  if (logTag_ptr)
975 
976  if (answer.peerResponseStatus != Http::scNone)
977  *status_ptr = answer.peerResponseStatus;
978 
979  auto sawProblem = false;
980 
981  if (!answer.positive()) {
982  sawProblem = true;
983  assert(!answer.conn);
984  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
985  sawProblem = true;
986  closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
987  }
988 
989  if (!sawProblem) {
990  assert(answer.positive()); // paranoid
991  // copy any post-200 OK bytes to our buffer
992  preReadServerData = answer.leftovers;
993  notePeerReadyToShovel(answer.conn);
994  return;
995  }
996 
997  ErrorState *error = nullptr;
998  if (answer.positive()) {
1000  } else {
1001  error = answer.squidError.get();
1002  Must(error);
1003  answer.squidError.clear(); // preserve error for errorSendComplete()
1004  }
1005  assert(error);
1006  saveError(error);
1007  retryOrBail("tunneler error");
1008 }
1009 
1010 void
1012 {
1013  assert(!client.dirty);
1014  retriable = false;
1015  server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1016 
1018  tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1019  else {
1021  AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1024  const auto mb = al->reply->pack();
1025  client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1026  delete mb;
1027  }
1028 }
1029 
1030 static void
1031 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1032 {
1033  TunnelStateData *tunnelState = (TunnelStateData *)data;
1034  debugs(26, 3, HERE << "FD " << fd);
1035  assert(tunnelState != NULL);
1036  /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
1037  CbcPointer<TunnelStateData> safetyLock(tunnelState);
1038 
1039  if (Comm::IsConnOpen(tunnelState->client.conn))
1040  tunnelState->client.conn->close();
1041 
1042  if (Comm::IsConnOpen(tunnelState->server.conn))
1043  tunnelState->server.conn->close();
1044 }
1045 
1046 void
1048 {
1049  transportWait.finish();
1050 
1051  ErrorState *error = nullptr;
1052  if ((error = answer.error.get())) {
1053  Must(!Comm::IsConnOpen(answer.conn));
1054  syncHierNote(answer.conn, request->url.host());
1055  answer.error.clear();
1056  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1058  closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1059  }
1060 
1061  if (error) {
1062  saveError(error);
1063  retryOrBail("tried all destinations");
1064  return;
1065  }
1066 
1067  connectDone(answer.conn, request->url.host(), answer.reused);
1068 }
1069 
1070 void
1071 TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1072 {
1074 
1075  if (reused)
1077  // else Comm::ConnOpener already applied proper/current markings
1078 
1079  syncHierNote(conn, origin);
1080 
1081 #if USE_DELAY_POOLS
1082  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1083  if (conn->getPeer() && conn->getPeer()->options.no_delay)
1085 #endif
1086 
1088 
1089  request->peer_host = conn->getPeer() ? conn->getPeer()->host : nullptr;
1090 
1091  bool toOrigin = false; // same semantics as StateFlags::toOrigin
1092  if (const auto * const peer = conn->getPeer()) {
1093  request->prepForPeering(*peer);
1094  toOrigin = peer->options.originserver;
1095  } else {
1097  toOrigin = true;
1098  }
1099 
1100  if (!toOrigin)
1102  else {
1104  }
1105 }
1106 
1107 void
1109 {
1110  debugs(26, 3, HERE);
1111  /* Create state structure. */
1112  TunnelStateData *tunnelState = NULL;
1113  ErrorState *err = NULL;
1115  char *url = http->uri;
1116 
1117  /*
1118  * client_addr.isNoAddr() indicates this is an "internal" request
1119  * from peer_digest.c, asn.c, netdb.c, etc and should always
1120  * be allowed. yuck, I know.
1121  */
1122 
1124  /*
1125  * Check if this host is allowed to fetch MISSES from us (miss_access)
1126  * default is to allow.
1127  */
1129  ch.al = http->al;
1131  ch.my_addr = request->my_addr;
1132  ch.syncAle(request, http->log_uri);
1133  if (ch.fastCheck().denied()) {
1134  debugs(26, 4, HERE << "MISS access forbidden.");
1138  return;
1139  }
1140  }
1141 
1142  debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1143  ++statCounter.server.all.requests;
1144  ++statCounter.server.other.requests;
1145 
1146  tunnelState = new TunnelStateData(http);
1147 #if USE_DELAY_POOLS
1148  tunnelState->server.setDelayId(DelayId::DelayClient(http));
1149 #endif
1150  tunnelState->startSelectingDestinations(request, http->al, nullptr);
1151 }
1152 
1153 void
1155 {
1156  if (const auto p = conn->getPeer()) {
1157  if (p->secure.encryptTransport)
1158  return advanceDestination("secure connection to peer", conn, [this,&conn] {
1160  });
1161  }
1162 
1164 }
1165 
1167 void
1169 {
1170  AsyncCall::Pointer callback = asyncCall(5,4, "TunnelStateData::noteSecurityPeerConnectorAnswer",
1172  const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1173  encryptionWait.start(connector, callback);
1174 }
1175 
1177 template <typename StepStart>
1178 void
1179 TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1180 {
1181  // TODO: Extract destination-specific handling from TunnelStateData so that
1182  // all the awkward, limited-scope advanceDestination() calls can be replaced
1183  // with a single simple try/catch,retry block.
1184  try {
1185  startStep();
1186  // now wait for the step callback
1187  } catch (...) {
1188  debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1189  closePendingConnection(conn, "connection preparation exception");
1190  if (!savedError)
1192  retryOrBail(stepDescription);
1193  }
1194 }
1195 
1197 void
1199 {
1200  encryptionWait.finish();
1201 
1202  ErrorState *error = nullptr;
1203  assert(!answer.tunneled);
1204  if ((error = answer.error.get())) {
1205  assert(!answer.conn);
1206  answer.error.clear();
1207  } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1209  closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1210  }
1211 
1212  if (error) {
1213  saveError(error);
1214  retryOrBail("TLS peer connection error");
1215  return;
1216  }
1217 
1218  connectedToPeer(answer.conn);
1219 }
1220 
1221 void
1223 {
1224  advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1226  });
1227 }
1228 
1229 void
1231 {
1232  AsyncCall::Pointer callback = asyncCall(5,4,
1233  "TunnelStateData::tunnelEstablishmentDone",
1235  const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1236 #if USE_DELAY_POOLS
1237  tunneler->setDelayId(server.delayId);
1238 #endif
1239  peerWait.start(tunneler, callback);
1240 }
1241 
1242 void
1244 {
1245  destinationsFound = true;
1246 
1247  if (!path) { // decided to use a pinned connection
1248  // We can call usePinned() without fear of clashing with an earlier
1249  // forwarding attempt because PINNED must be the first destination.
1251  usePinned();
1252  return;
1253  }
1254 
1255  destinations->addPath(path);
1256 
1257  if (usingDestination()) {
1258  // We are already using a previously opened connection but also
1259  // receiving destinations in case we need to re-forward.
1260  Must(!transportWait);
1261  return;
1262  }
1263 
1264  if (transportWait) {
1265  notifyConnOpener();
1266  return; // and continue to wait for tunnelConnectDone() callback
1267  }
1268 
1269  startConnecting();
1270 }
1271 
1272 void
1274 {
1277  if (!destinationsFound) {
1278 
1279  // XXX: Honor clientExpectsConnectResponse() before replying.
1280 
1281  if (selectionError)
1282  return sendError(selectionError, "path selection has failed");
1283 
1284  if (savedError)
1285  return sendError(savedError, "all found paths have failed");
1286 
1288  "path selection found no paths");
1289  }
1290  // else continue to use one of the previously noted destinations;
1291  // if all of them fail, tunneling as whole will fail
1292  Must(!selectionError); // finding at least one path means selection succeeded
1293 
1294  if (usingDestination()) {
1295  // We are already using a previously opened connection but also
1296  // receiving destinations in case we need to re-forward.
1297  Must(!transportWait);
1298  return;
1299  }
1300 
1301  Must(transportWait); // or we would be stuck with nothing to do or wait for
1302  notifyConnOpener();
1303 }
1304 
1305 bool
1307 {
1309 }
1310 
1312 void
1314 {
1315  debugs(26, 4, savedError << " ? " << error);
1316  assert(error);
1317  delete savedError; // may be nil
1318  savedError = error;
1319 }
1320 
1323 void
1324 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1325 {
1326  debugs(26, 3, "aborting transaction for " << reason);
1327 
1328  if (request)
1329  request->hier.stopPeerClock(false);
1330 
1331  cancelStep(reason);
1332 
1333  assert(finalError);
1334 
1335  // get rid of any cached error unless that is what the caller is sending
1336  if (savedError != finalError)
1337  delete savedError; // may be nil
1338  savedError = nullptr;
1339 
1340  // we cannot try other destinations after responding with an error
1341  PeerSelectionInitiator::subscribed = false; // may already be false
1342 
1343  *status_ptr = finalError->httpStatus;
1344  finalError->callback = tunnelErrorComplete;
1345  finalError->callback_data = this;
1346  errorSend(client.conn, finalError);
1347 }
1348 
1352 void
1353 TunnelStateData::cancelStep(const char *reason)
1354 {
1355  transportWait.cancel(reason);
1356  encryptionWait.cancel(reason);
1357  peerWait.cancel(reason);
1358 }
1359 
1360 void
1362 {
1363  if (request)
1365 
1366  assert(!destinations->empty());
1368  AsyncCall::Pointer callback = asyncCall(17, 5, "TunnelStateData::noteConnection", HappyConnOpener::CbDialer<TunnelStateData>(&TunnelStateData::noteConnection, this));
1369  const auto cs = new HappyConnOpener(destinations, callback, request, startTime, 0, al);
1370  cs->setHost(request->url.host());
1371  cs->setRetriable(false);
1372  cs->allowPersistent(false);
1373  destinations->notificationPending = true; // start() is async
1374  transportWait.start(cs, callback);
1375 }
1376 
1378 void
1380 {
1381  Must(request);
1382  const auto connManager = request->pinnedConnection();
1383  try {
1384  const auto serverConn = ConnStateData::BorrowPinnedConnection(request.getRaw(), al);
1385  debugs(26, 7, "pinned peer connection: " << serverConn);
1386 
1387  // Set HttpRequest pinned related flags for consistency even if
1388  // they are not really used by tunnel.cc code.
1389  request->flags.pinned = true;
1390  if (connManager->pinnedAuth())
1391  request->flags.auth = true;
1392 
1393  // the server may close the pinned connection before this request
1394  const auto reused = true;
1395  connectDone(serverConn, connManager->pinning.host, reused);
1396  } catch (ErrorState * const error) {
1397  syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1398  // XXX: Honor clientExpectsConnectResponse() before replying.
1399  // a PINNED path failure is fatal; do not wait for more paths
1400  sendError(error, "pinned path failure");
1401  return;
1402  }
1403 
1404 }
1405 
1407 
1408 bool
1410 {
1412 }
1413 
1414 #if USE_DELAY_POOLS
1415 void
1417 {
1418  delayId = newDelay;
1419 }
1420 
1421 #endif
1422 
1424 void
1426 {
1428  debugs(17, 7, "reusing pending notification");
1429  } else {
1431  CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
1432  }
1433 }
1434 
1442 void
1444 {
1445  Must(Comm::IsConnOpen(clientConn));
1446  Must(Comm::IsConnOpen(srvConn));
1447 
1448  debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1449 
1450  /* Create state structure. */
1451  ++statCounter.server.all.requests;
1452  ++statCounter.server.other.requests;
1453 
1455  Must(conn);
1456  Http::StreamPointer context = conn->pipeline.front();
1457  Must(context && context->http);
1458 
1459  debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1460 
1461  TunnelStateData *tunnelState = new TunnelStateData(context->http);
1462  tunnelState->retriable = false;
1463 
1464  request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1465 
1466  tunnelState->server.initConnection(srvConn, tunnelServerClosed, "tunnelServerClosed", tunnelState);
1467 
1468 #if USE_DELAY_POOLS
1469  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1470  if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1471  tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1472 #endif
1473 
1474  request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1475 
1476  debugs(26, 4, "determine post-connect handling pathway.");
1477  if (const auto peer = srvConn->getPeer())
1478  request->prepForPeering(*peer);
1479  else
1481 
1482  tunnelState->preReadServerData = preReadServerData;
1483 
1484  tunnelStartShoveling(tunnelState);
1485 }
1486 
const char * xstrerr(int error)
Definition: xstrerror.cc:83
void noteConnection(HappyConnOpenerAnswer &)
Definition: tunnel.cc:1047
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:240
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:935
JobPointer job() const
Definition: JobWait.h:76
void dial(AsyncCall &)
Definition: tunnel.cc:239
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:191
AnyP::ProtocolVersion http_ver
Definition: Message.h:73
struct SquidConfig::@97 Timeout
uint64_t payloadData
total size of payload block(s) excluding transfer encoding overheads
Definition: MessageSizes.h:24
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:184
void notePeerReadyToShovel(const Comm::ConnectionPointer &)
called when negotiations with the peer have been successfully completed
Definition: tunnel.cc:1011
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:875
CbcPointer< TunnelStateData > tunnel_
Definition: tunnel.cc:249
bool noConnections() const
Definition: tunnel.cc:1409
void clientClosed()
handles client-to-Squid connection closure; may destroy us
Definition: tunnel.cc:333
Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
Definition: tunnel.cc:230
Interface for those who need a list of peers to forward a request to.
JobWait< Http::Tunneler > peerWait
Definition: tunnel.cc:201
void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
Start using an established connection.
Definition: tunnel.cc:1071
void noteClosure()
reacts to the external closure of our connection
Definition: tunnel.cc:744
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:131
CbcPointer< ErrorState > error
problem details (nil on success)
LogTags logType
the processing tags associated with this request transaction.
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:701
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
void(TunnelStateData::* Method)(Security::EncryptorAnswer &)
Definition: tunnel.cc:232
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:947
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:1313
void copyServerBytes()
Definition: tunnel.cc:889
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:803
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:1168
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:467
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:567
#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:570
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:1243
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:336
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:551
void closeConnections()
closes both client and server connections
Definition: tunnel.cc:812
void connectToPeer(const Comm::ConnectionPointer &)
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1154
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
class AccessLogEntry::HttpDetails http
TunnelStateData(ClientHttpRequest *)
Definition: tunnel.cc:359
bool usingDestination() const
Definition: tunnel.cc:1306
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:1179
const char * checkRetry()
Definition: tunnel.cc:406
void syncHierNote(const Comm::ConnectionPointer &server, const char *origin)
Definition: tunnel.cc:491
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition: tunnel.cc:272
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:305
void update(const LogTags_ot t)
Definition: LogTags.cc:54
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition: tunnel.cc:907
void copyRead(Connection &from, IOCB *completion)
Definition: tunnel.cc:853
void tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
resumes operations after the (possibly failed) HTTP CONNECT exchange
Definition: tunnel.cc:968
Comm::ConnectionPointer conn
peer connection (secured on success)
ByteCounter kbytes_in
Definition: StatCounters.h:45
int size
Definition: ModDevPoll.cc:77
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:753
time_t read
Definition: SquidConfig.h:110
void sendError(ErrorState *finalError, const char *reason)
Definition: tunnel.cc:1324
@ scForbidden
Definition: StatusCode.h:47
void ResetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Definition: FwdState.cc:1557
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:182
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:724
bool destinationsFound
Definition: tunnel.cc:186
Security::EncryptorAnswer answer_
Definition: tunnel.cc:250
AccessLogEntryPointer al
Definition: tunnel.cc:95
void setDelayId(DelayId const &)
Definition: tunnel.cc:1416
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:638
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
AccessLogEntry::Pointer al
access.log entry
void dataSent(size_t amount)
Definition: tunnel.cc:711
void switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
Definition: tunnel.cc:1443
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:1361
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:478
#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:149
virtual void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1273
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:658
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:194
#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
HierarchyLogEntry hier
Definition: HttpRequest.h:157
bool retriable
Definition: tunnel.cc:189
MessageSizes clientRequestSz
counters for the original request received from client
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:438
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:234
char * url
Definition: tunnel.cc:92
Ip::Address my_addr
Definition: HttpRequest.h:155
virtual bool canDial(AsyncCall &)
Definition: tunnel.cc:238
@ scInternalServerError
Definition: StatusCode.h:71
JobWait< Security::PeerConnector > encryptionWait
waits for the established transport connection to be secured/encrypted
Definition: tunnel.cc:197
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:35
static CLCB tunnelServerClosed
Definition: tunnel.cc:304
#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:1230
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
LogTags * logTag_ptr
pointer for logging Squid processing code
Definition: tunnel.cc:180
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:1424
#define fd_table
Definition: fde.h:189
virtual Security::EncryptorAnswer & answer()
gives PeerConnector access to the in-dialer answer
Definition: tunnel.cc:245
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:499
static Comm::ConnectionPointer BorrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: tunnel.cc:1379
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:561
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:1353
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:648
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:595
HttpRequest::Pointer request
Definition: tunnel.cc:94
void notifyConnOpener()
makes sure connection opener knows that the destinations have changed
Definition: tunnel.cc:1425
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:1108
SBuf preReadServerData
Definition: tunnel.cc:183
void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
initiates Comm::Connection ownership, including closure monitoring
Definition: tunnel.cc:733
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
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:526
ResolvedPeersPointer destinations
paths for forwarding the request
Definition: tunnel.cc:185
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:319
@ 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:1222
void * callback_data
Definition: errorpage.h:185
void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &)
callback handler for the Security::PeerConnector encryptor
Definition: tunnel.cc:1198
#define false
Definition: GnuRegex.c:233
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: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:109
static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:516
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:346
static EVH tunnelDelayedClientRead
Definition: tunnel.cc:307

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors