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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors