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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors