tunnel.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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 "comm.h"
19 #include "comm/Connection.h"
20 #include "comm/ConnOpener.h"
21 #include "comm/Read.h"
22 #include "comm/Write.h"
23 #include "errorpage.h"
24 #include "fd.h"
25 #include "fde.h"
26 #include "FwdState.h"
27 #include "globals.h"
28 #include "http.h"
29 #include "http/Stream.h"
30 #include "HttpRequest.h"
31 #include "icmp/net_db.h"
32 #include "ip/QosConfig.h"
33 #include "LogTags.h"
34 #include "MemBuf.h"
35 #include "neighbors.h"
36 #include "PeerSelectState.h"
37 #include "sbuf/SBuf.h"
39 #include "SquidConfig.h"
40 #include "SquidTime.h"
41 #include "StatCounters.h"
42 #if USE_OPENSSL
43 #include "ssl/bio.h"
44 #include "ssl/ServerBump.h"
45 #endif
46 #include "tools.h"
47 #if USE_DELAY_POOLS
48 #include "DelayId.h"
49 #endif
50 
51 #include <climits>
52 #include <cerrno>
53 
59 /*
60  * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
61  * of pre-formatted data. Then we can use that as the client side of the tunnel
62  * instead of re-implementing it here and occasionally getting the ConnStateData
63  * read/write state wrong.
64  *
65  * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
66  */
68 {
70 
71 public:
73  virtual ~TunnelStateData();
74  TunnelStateData(const TunnelStateData &); // do not implement
75  TunnelStateData &operator =(const TunnelStateData &); // do not implement
76 
77  class Connection;
78  static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
79  static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
80  static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
81  static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
82 
84  void readConnectResponse();
85 
88 
89  bool noConnections() const;
90  char *url;
95 
96  const char * getHost() const {
97  return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->url.host());
98  };
99 
103  bool waitingForConnectResponse() const { return connectRespBuf; }
106 
109  // If we are forcing a tunnel after receiving a client CONNECT, then we
110  // have already responded to that CONNECT before tunnel.cc started.
111  if (request && request->flags.forceTunnel)
112  return false;
113 #if USE_OPENSSL
114  // We are bumping and we had already send "OK CONNECTED"
115  if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->step > Ssl::bumpStep1)
116  return false;
117 #endif
118  return !(request != NULL &&
119  (request->flags.interceptTproxy || request->flags.intercepted));
120  }
121 
124  void informUserOfPeerError(const char *errMsg, size_t);
125 
128  void startConnecting();
129 
131 
133  {
134 
135  public:
136  Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), delayedLoops(0),
138 
139  ~Connection();
140 
141  int bytesWanted(int lower=0, int upper = INT_MAX) const;
142  void bytesIn(int const &);
143 #if USE_DELAY_POOLS
144 
145  void setDelayId(DelayId const &);
146 #endif
147 
148  void error(int const xerrno);
149  int debugLevelForError(int const xerrno) const;
150  void closeIfOpen();
151  void dataSent (size_t amount);
153  void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
154  int len;
155  char *buf;
157  uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
158 
160  uint8_t delayedLoops;
161 
162  // XXX: make these an AsyncCall when event API can handle them
165  private:
166 #if USE_DELAY_POOLS
167 
169 #endif
170 
171  };
172 
174  int *status_ptr;
180  time_t startTime;
181 
182  void copyRead(Connection &from, IOCB *completion);
183 
185  void connectToPeer();
186 
187  /* PeerSelectionInitiator API */
188  virtual void noteDestination(Comm::ConnectionPointer conn) override;
189  virtual void noteDestinationsEnd(ErrorState *selectionError) override;
190 
191  void saveError(ErrorState *finalError);
192  void sendError(ErrorState *finalError, const char *reason);
193 
194 private:
197  {
198  public:
200 
202  method_(method), tunnel_(tunnel), answer_() {}
203 
204  /* CallDialer API */
205  virtual bool canDial(AsyncCall &call) { return tunnel_.valid(); }
206  void dial(AsyncCall &call) { ((&(*tunnel_))->*method_)(answer_); }
207  virtual void print(std::ostream &os) const {
208  os << '(' << tunnel_.get() << ", " << answer_ << ')';
209  }
210 
211  /* Security::PeerConnector::CbDialer API */
212  virtual Security::EncryptorAnswer &answer() { return answer_; }
213 
214  private:
218  };
219 
222 
224  ErrorState *savedError = nullptr;
225 
226 public:
227  bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
228  void copy(size_t len, Connection &from, Connection &to, IOCB *);
229  void handleConnectResponse(const size_t chunkSize);
230  void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
231  void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
232  void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
233  void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
234 
235  static void ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
236  void readConnectResponseDone(char *buf, size_t len, Comm::Flag errcode, int xerrno);
237  void copyClientBytes();
238  void copyServerBytes();
239 };
240 
241 static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
242 
250 static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
251 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
252 
253 static void
255 {
256  TunnelStateData *tunnelState = (TunnelStateData *)params.data;
257  debugs(26, 3, HERE << tunnelState->server.conn);
258  tunnelState->server.conn = NULL;
259  tunnelState->server.writer = NULL;
260 
261  if (tunnelState->request != NULL)
262  tunnelState->request->hier.stopPeerClock(false);
263 
264  if (tunnelState->noConnections()) {
265  // ConnStateData pipeline should contain the CONNECT we are performing
266  // but it may be invalid already (bug 4392)
267  if (tunnelState->http.valid() && tunnelState->http->getConn()) {
268  auto ctx = tunnelState->http->getConn()->pipeline.front();
269  if (ctx != nullptr)
270  ctx->finished();
271  }
272  delete tunnelState;
273  return;
274  }
275 
276  if (!tunnelState->client.writer) {
277  tunnelState->client.conn->close();
278  return;
279  }
280 }
281 
282 static void
284 {
285  TunnelStateData *tunnelState = (TunnelStateData *)params.data;
286  debugs(26, 3, HERE << tunnelState->client.conn);
287  tunnelState->client.conn = NULL;
288  tunnelState->client.writer = NULL;
289 
290  if (tunnelState->noConnections()) {
291  // ConnStateData pipeline should contain the CONNECT we are performing
292  // but it may be invalid already (bug 4392)
293  if (tunnelState->http.valid() && tunnelState->http->getConn()) {
294  auto ctx = tunnelState->http->getConn()->pipeline.front();
295  if (ctx != nullptr)
296  ctx->finished();
297  }
298  delete tunnelState;
299  return;
300  }
301 
302  if (!tunnelState->server.writer) {
303  tunnelState->server.conn->close();
304  return;
305  }
306 }
307 
312 {
313  debugs(26, 3, "TunnelStateData constructed this=" << this);
316 
317  assert(clientRequest);
318  url = xstrdup(clientRequest->uri);
319  request = clientRequest->request;
320  server.size_ptr = &clientRequest->out.size;
321  client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
322  status_ptr = &clientRequest->al->http.code;
323  logTag_ptr = &clientRequest->logType;
324  al = clientRequest->al;
325  http = clientRequest;
326 
327  client.conn = clientRequest->getConn()->clientConnection;
329 
330  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
333 }
334 
336 {
337  debugs(26, 3, "TunnelStateData destructed this=" << this);
339  xfree(url);
340  serverDestinations.clear();
341  delete connectRespBuf;
342  delete savedError;
343 }
344 
346 {
347  if (readPending)
348  eventDelete(readPendingFunc, readPending);
349 
350  safe_free(buf);
351 }
352 
353 int
354 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
355 {
356 #if USE_DELAY_POOLS
357  return delayId.bytesWanted(lowerbound, upperbound);
358 #else
359 
360  return upperbound;
361 #endif
362 }
363 
364 void
366 {
367  debugs(26, 3, HERE << "len=" << len << " + count=" << count);
368 #if USE_DELAY_POOLS
369  delayId.bytesIn(count);
370 #endif
371 
372  len += count;
373 }
374 
375 int
377 {
378 #ifdef ECONNRESET
379 
380  if (xerrno == ECONNRESET)
381  return 2;
382 
383 #endif
384 
385  if (ignoreErrno(xerrno))
386  return 3;
387 
388  return 1;
389 }
390 
391 /* Read from server side and queue it for writing to the client */
392 void
393 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
394 {
395  TunnelStateData *tunnelState = (TunnelStateData *)data;
396  assert(cbdataReferenceValid(tunnelState));
397  debugs(26, 3, HERE << c);
398 
399  tunnelState->readServer(buf, len, errcode, xerrno);
400 }
401 
402 void
403 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
404 {
405  debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
407 
408  /*
409  * Bail out early on Comm::ERR_CLOSING
410  * - close handlers will tidy up for us
411  */
412 
413  if (errcode == Comm::ERR_CLOSING)
414  return;
415 
416  if (len > 0) {
417  server.bytesIn(len);
418  statCounter.server.all.kbytes_in += len;
419  statCounter.server.other.kbytes_in += len;
421  }
422 
423  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
425 }
426 
428 void
429 TunnelStateData::readConnectResponseDone(char *, size_t len, Comm::Flag errcode, int xerrno)
430 {
431  debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
433 
434  if (errcode == Comm::ERR_CLOSING)
435  return;
436 
437  if (len > 0) {
438  connectRespBuf->appended(len);
439  server.bytesIn(len);
440  statCounter.server.all.kbytes_in += len;
441  statCounter.server.other.kbytes_in += len;
443  }
444 
445  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
447 }
448 
449 void
450 TunnelStateData::informUserOfPeerError(const char *errMsg, const size_t sz)
451 {
452  server.len = 0;
453 
454  if (logTag_ptr)
456 
458  // closing the connection is the best we can do here
459  debugs(50, 3, server.conn << " closing on error: " << errMsg);
460  server.conn->close();
461  return;
462  }
463 
464  // if we have no reply suitable to relay, use 502 Bad Gateway
465  if (!sz || sz > static_cast<size_t>(connectRespBuf->contentSize()))
467  "peer error without reply");
468 
469  // if we need to send back the server response. write its headers to the client
470  server.len = sz;
471  memcpy(server.buf, connectRespBuf->content(), server.len);
473  // then close the server FD to prevent any relayed keep-alive causing CVE-2015-5400
475 }
476 
477 /* Read from client side and queue it for writing to the server */
478 void
479 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
480 {
481  TunnelStateData *tunnelState = (TunnelStateData *)data;
482  assert (cbdataReferenceValid (tunnelState));
483 
484  tunnelState->readConnectResponseDone(buf, len, errcode, xerrno);
485 }
486 
490 void
492 {
494 
495  // Ideally, client and server should use MemBuf or better, but current code
496  // never accumulates more than one read when shoveling data (XXX) so it does
497  // not need to deal with MemBuf complexity. To keep it simple, we use a
498  // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
499  // is optimized, reuse server.buf for CONNEC response accumulation instead.
500 
501  /* mimic the basic parts of HttpStateData::processReplyHeader() */
502  HttpReply rep;
503  Http::StatusCode parseErr = Http::scNone;
504  const bool eof = !chunkSize;
505  connectRespBuf->terminate(); // Http::Message::parse requires terminated string
506  const bool parsed = rep.parse(connectRespBuf->content(), connectRespBuf->contentSize(), eof, &parseErr);
507  if (!parsed) {
508  if (parseErr > 0) { // unrecoverable parsing error
509  informUserOfPeerError("malformed CONNECT response from peer", 0);
510  return;
511  }
512 
513  // need more data
514  assert(!eof);
515  assert(!parseErr);
516 
517  if (!connectRespBuf->hasSpace()) {
518  informUserOfPeerError("huge CONNECT response from peer", 0);
519  return;
520  }
521 
522  // keep reading
524  return;
525  }
526 
527  // CONNECT response was successfully parsed
529 
530  // bail if we did not get an HTTP 200 (Connection Established) response
531  if (rep.sline.status() != Http::scOkay) {
532  // if we ever decide to reuse the peer connection, we must extract the error response first
533  *status_ptr = rep.sline.status(); // we are relaying peer response
534  informUserOfPeerError("unsupported CONNECT response status code", rep.hdr_sz);
535  return;
536  }
537 
538  if (rep.hdr_sz < connectRespBuf->contentSize()) {
539  // preserve bytes that the server already sent after the CONNECT response
541  memcpy(server.buf, connectRespBuf->content()+rep.hdr_sz, server.len);
542  } else {
543  // reset; delay pools were using this field to throttle CONNECT response
544  server.len = 0;
545  }
546 
547  delete connectRespBuf;
550 }
551 
552 void
554 {
555  debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerr(xerrno));
556 
557  if (!ignoreErrno(xerrno))
558  conn->close();
559 }
560 
561 /* Read from client side and queue it for writing to the server */
562 void
563 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
564 {
565  TunnelStateData *tunnelState = (TunnelStateData *)data;
566  assert (cbdataReferenceValid (tunnelState));
567 
568  tunnelState->readClient(buf, len, errcode, xerrno);
569 }
570 
571 void
572 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
573 {
574  debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
576 
577  /*
578  * Bail out early on Comm::ERR_CLOSING
579  * - close handlers will tidy up for us
580  */
581 
582  if (errcode == Comm::ERR_CLOSING)
583  return;
584 
585  if (len > 0) {
586  client.bytesIn(len);
588  }
589 
590  if (keepGoingAfterRead(len, errcode, xerrno, client, server))
592 }
593 
596 bool
598 {
599  debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
600 
601  /* I think this is to prevent free-while-in-a-callback behaviour
602  * - RBC 20030229
603  * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
604  */
605  const CbcPointer<TunnelStateData> safetyLock(this);
606 
607  /* Bump the source connection read timeout on any activity */
608  if (Comm::IsConnOpen(from.conn)) {
609  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
611  commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
612  }
613 
614  /* Bump the dest connection read timeout on any activity */
615  /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
616  if (Comm::IsConnOpen(to.conn)) {
617  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
619  commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
620  }
621 
622  if (errcode)
623  from.error (xerrno);
624  else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
625  debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
626  from.conn->close();
627 
628  /* Only close the remote end if we've finished queueing data to it */
629  if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
630  to.conn->close();
631  }
632  } else if (cbdataReferenceValid(this)) {
633  return true;
634  }
635 
636  return false;
637 }
638 
639 void
640 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
641 {
642  debugs(26, 3, HERE << "Schedule Write");
643  AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
644  CommIoCbPtrFun(completion, this));
645  to.write(from.buf, len, call, NULL);
646 }
647 
648 /* Writes data from the client buffer to the server side */
649 void
650 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
651 {
652  TunnelStateData *tunnelState = (TunnelStateData *)data;
653  assert (cbdataReferenceValid (tunnelState));
654  tunnelState->server.writer = NULL;
655 
656  tunnelState->writeServerDone(buf, len, flag, xerrno);
657 }
658 
659 void
660 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
661 {
662  debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
663 
664  if (flag == Comm::ERR_CLOSING)
665  return;
666 
668 
669  /* Error? */
670  if (flag != Comm::OK) {
671  debugs(26, 4, "to-server write failed: " << xerrno);
672  server.error(xerrno); // may call comm_close
673  return;
674  }
675 
676  /* EOF? */
677  if (len == 0) {
678  debugs(26, 4, HERE << "No read input. Closing server connection.");
679  server.conn->close();
680  return;
681  }
682 
683  /* Valid data */
684  statCounter.server.all.kbytes_out += len;
685  statCounter.server.other.kbytes_out += len;
686  client.dataSent(len);
687 
688  /* If the other end has closed, so should we */
689  if (!Comm::IsConnOpen(client.conn)) {
690  debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
691  server.conn->close();
692  return;
693  }
694 
695  const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
696 
697  if (cbdataReferenceValid(this))
698  copyClientBytes();
699 }
700 
701 /* Writes data from the server buffer to the client side */
702 void
703 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
704 {
705  TunnelStateData *tunnelState = (TunnelStateData *)data;
706  assert (cbdataReferenceValid (tunnelState));
707  tunnelState->client.writer = NULL;
708 
709  tunnelState->writeClientDone(buf, len, flag, xerrno);
710 }
711 
712 void
714 {
715  debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
716  assert(amount == (size_t)len);
717  len =0;
718  /* increment total object size */
719 
720  if (size_ptr)
721  *size_ptr += amount;
722 
723 }
724 
725 void
727 {
728  writer = callback;
729  Comm::Write(conn, b, size, callback, free_func);
730 }
731 
732 void
733 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
734 {
735  debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
736 
737  if (flag == Comm::ERR_CLOSING)
738  return;
739 
740  /* Error? */
741  if (flag != Comm::OK) {
742  debugs(26, 4, "from-client read failed: " << xerrno);
743  client.error(xerrno); // may call comm_close
744  return;
745  }
746 
747  /* EOF? */
748  if (len == 0) {
749  debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
750  client.conn->close();
751  return;
752  }
753 
754  /* Valid data */
756  server.dataSent(len);
757 
758  /* If the other end has closed, so should we */
759  if (!Comm::IsConnOpen(server.conn)) {
760  debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
761  client.conn->close();
762  return;
763  }
764 
765  CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
766 
767  if (cbdataReferenceValid(this))
768  copyServerBytes();
769 }
770 
771 static void
773 {
774  TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
775  debugs(26, 3, HERE << io.conn);
776  /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
777  CbcPointer<TunnelStateData> safetyLock(tunnelState);
778 
779  tunnelState->client.closeIfOpen();
780  tunnelState->server.closeIfOpen();
781 }
782 
783 void
785 {
786  if (Comm::IsConnOpen(conn))
787  conn->close();
788 }
789 
790 static void
792 {
793  if (!data)
794  return;
795 
796  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
797  tunnel->client.readPending = NULL;
798  static uint64_t counter=0;
799  debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
800  tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
801 }
802 
803 static void
805 {
806  if (!data)
807  return;
808 
809  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
810  tunnel->server.readPending = NULL;
811  static uint64_t counter=0;
812  debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
813  tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
814 }
815 
816 void
818 {
819  assert(from.len == 0);
820  // If only the minimum permitted read size is going to be attempted
821  // then we schedule an event to try again in a few I/O cycles.
822  // Allow at least 1 byte to be read every (0.3*10) seconds.
823  int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
824  if (bw == 1 && ++from.delayedLoops < 10) {
825  from.readPending = this;
826  eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
827  return;
828  }
829 
830  AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
831  CommIoCbPtrFun(completion, this));
832  comm_read(from.conn, from.buf, bw, call);
833 }
834 
835 void
837 {
839 
840  AsyncCall::Pointer call = commCbCall(5,4, "readConnectResponseDone",
844 }
845 
846 void
848 {
849  if (preReadClientData.length()) {
850  size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
851  memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
852  preReadClientData.consume(copyBytes);
853  client.bytesIn(copyBytes);
854  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
856  } else
858 }
859 
860 void
862 {
863  if (preReadServerData.length()) {
864  size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
865  memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
866  preReadServerData.consume(copyBytes);
867  server.bytesIn(copyBytes);
868  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
870  } else
872 }
873 
878 static void
880 {
881  assert(!tunnelState->waitingForConnectExchange());
882  *tunnelState->status_ptr = Http::scOkay;
883  if (tunnelState->logTag_ptr)
884  tunnelState->logTag_ptr->update(LOG_TCP_TUNNEL);
885  if (cbdataReferenceValid(tunnelState)) {
886 
887  // Shovel any payload already pushed into reply buffer by the server response
888  if (!tunnelState->server.len)
889  tunnelState->copyServerBytes();
890  else {
891  debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
892  tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
893  }
894 
895  if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
896  SBuf * const in = &tunnelState->http->getConn()->inBuf;
897  debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
898  tunnelState->preReadClientData.append(*in);
899  in->consume(); // ConnStateData buffer accounting after the shuffle.
900  }
901  tunnelState->copyClientBytes();
902  }
903 }
904 
910 static void
911 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
912 {
913  TunnelStateData *tunnelState = (TunnelStateData *)data;
914  debugs(26, 3, HERE << conn << ", flag=" << flag);
915  tunnelState->client.writer = NULL;
916 
917  if (flag != Comm::OK) {
918  *tunnelState->status_ptr = Http::scInternalServerError;
919  tunnelErrorComplete(conn->fd, data, 0);
920  return;
921  }
922 
923  if (auto http = tunnelState->http.get()) {
924  http->out.headers_sz += len;
925  http->out.size += len;
926  }
927 
928  tunnelStartShoveling(tunnelState);
929 }
930 
932 static void
933 tunnelConnectReqWriteDone(const Comm::ConnectionPointer &conn, char *, size_t ioSize, Comm::Flag flag, int, void *data)
934 {
935  TunnelStateData *tunnelState = (TunnelStateData *)data;
936  debugs(26, 3, conn << ", flag=" << flag);
937  tunnelState->server.writer = NULL;
938  assert(tunnelState->waitingForConnectRequest());
939 
940  tunnelState->request->hier.notePeerWrite();
941 
942  if (flag != Comm::OK) {
943  *tunnelState->status_ptr = Http::scInternalServerError;
944  tunnelErrorComplete(conn->fd, data, 0);
945  return;
946  }
947 
948  statCounter.server.all.kbytes_out += ioSize;
949  statCounter.server.other.kbytes_out += ioSize;
950 
951  tunnelState->connectReqWriting = false;
952  tunnelState->connectExchangeCheckpoint();
953 }
954 
955 void
957 {
959  debugs(26, 5, "still reading CONNECT response on " << server.conn);
960  } else if (waitingForConnectRequest()) {
961  debugs(26, 5, "still writing CONNECT request on " << server.conn);
962  } else {
964  debugs(26, 3, "done with CONNECT exchange on " << server.conn);
965  tunnelConnected(server.conn, this);
966  }
967 }
968 
969 /*
970  * handle the write completion from a proxy request to an upstream origin
971  */
972 static void
974 {
975  TunnelStateData *tunnelState = (TunnelStateData *)data;
976  debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
977 
978  if (!tunnelState->clientExpectsConnectResponse())
979  tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
980  else {
981  *tunnelState->status_ptr = Http::scOkay;
982  AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
984  tunnelState->client.write(conn_established, strlen(conn_established), call, NULL);
985  }
986 }
987 
988 static void
989 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
990 {
991  TunnelStateData *tunnelState = (TunnelStateData *)data;
992  debugs(26, 3, HERE << "FD " << fd);
993  assert(tunnelState != NULL);
994  /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
995  CbcPointer<TunnelStateData> safetyLock(tunnelState);
996 
997  if (Comm::IsConnOpen(tunnelState->client.conn))
998  tunnelState->client.conn->close();
999 
1000  if (Comm::IsConnOpen(tunnelState->server.conn))
1001  tunnelState->server.conn->close();
1002 }
1003 
1005 void
1007 {
1008  debugs(26, 4, "removing the failed one from " << serverDestinations.size() <<
1009  " destinations: " << conn);
1010 
1011  if (CachePeer *peer = conn->getPeer())
1012  peerConnectFailed(peer);
1013 
1014  assert(!serverDestinations.empty());
1015  serverDestinations.erase(serverDestinations.begin());
1016 
1017  // Since no TCP payload has been passed to client or server, we may
1018  // TCP-connect to other destinations (including alternate IPs).
1019 
1021  return sendError(savedError, "forwarding timeout");
1022 
1023  if (!serverDestinations.empty())
1024  return startConnecting();
1025 
1027  return sendError(savedError, "tried all destinations");
1028 
1029  debugs(26, 4, "wait for more destinations to try");
1030  // expect a noteDestination*() call
1031 }
1032 
1033 static void
1035 {
1036  TunnelStateData *tunnelState = (TunnelStateData *)data;
1037 
1038  if (status != Comm::OK) {
1040  err->xerrno = xerrno;
1041  // on timeout is this still: err->xerrno = ETIMEDOUT;
1042  err->port = conn->remote.port();
1043  tunnelState->saveError(err);
1044  tunnelState->noteConnectFailure(conn);
1045  return;
1046  }
1047 
1048 #if USE_DELAY_POOLS
1049  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1050  if (conn->getPeer() && conn->getPeer()->options.no_delay)
1051  tunnelState->server.setDelayId(DelayId());
1052 #endif
1053 
1054  netdbPingSite(tunnelState->request->url.host());
1055 
1056  tunnelState->request->hier.resetPeerNotes(conn, tunnelState->getHost());
1057 
1058  tunnelState->server.conn = conn;
1059  tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
1060  comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
1061 
1062  debugs(26, 4, HERE << "determine post-connect handling pathway.");
1063  if (conn->getPeer()) {
1064  tunnelState->request->peer_login = conn->getPeer()->login;
1065  tunnelState->request->peer_domain = conn->getPeer()->domain;
1066  tunnelState->request->flags.auth_no_keytab = conn->getPeer()->options.auth_no_keytab;
1067  tunnelState->request->flags.proxying = !(conn->getPeer()->options.originserver);
1068  } else {
1069  tunnelState->request->peer_login = NULL;
1070  tunnelState->request->peer_domain = NULL;
1071  tunnelState->request->flags.auth_no_keytab = false;
1072  tunnelState->request->flags.proxying = false;
1073  }
1074 
1075  if (tunnelState->request->flags.proxying)
1076  tunnelState->connectToPeer();
1077  else {
1078  tunnelConnected(conn, tunnelState);
1079  }
1080 
1081  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1082  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1083  commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
1084 }
1085 
1086 void
1088 {
1089  debugs(26, 3, HERE);
1090  /* Create state structure. */
1091  TunnelStateData *tunnelState = NULL;
1092  ErrorState *err = NULL;
1093  HttpRequest *request = http->request;
1094  char *url = http->uri;
1095 
1096  /*
1097  * client_addr.isNoAddr() indicates this is an "internal" request
1098  * from peer_digest.c, asn.c, netdb.c, etc and should always
1099  * be allowed. yuck, I know.
1100  */
1101 
1102  if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
1103  /*
1104  * Check if this host is allowed to fetch MISSES from us (miss_access)
1105  * default is to allow.
1106  */
1108  ch.al = http->al;
1109  ch.src_addr = request->client_addr;
1110  ch.my_addr = request->my_addr;
1111  ch.syncAle(request, http->log_uri);
1112  if (ch.fastCheck().denied()) {
1113  debugs(26, 4, HERE << "MISS access forbidden.");
1114  err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request);
1115  http->al->http.code = Http::scForbidden;
1116  errorSend(http->getConn()->clientConnection, err);
1117  return;
1118  }
1119  }
1120 
1121  debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1122  ++statCounter.server.all.requests;
1123  ++statCounter.server.other.requests;
1124 
1125  tunnelState = new TunnelStateData(http);
1126 #if USE_DELAY_POOLS
1127  //server.setDelayId called from tunnelConnectDone after server side connection established
1128 #endif
1129  tunnelState->startSelectingDestinations(request, http->al, nullptr);
1130 }
1131 
1132 void
1134 {
1135  if (CachePeer *p = server.conn->getPeer()) {
1136  if (p->secure.encryptTransport) {
1138  "TunnelStateData::ConnectedToPeer",
1140  auto *connector = new Security::BlindPeerConnector(request, server.conn, callback, al);
1141  AsyncJob::Start(connector); // will call our callback
1142  return;
1143  }
1144  }
1145 
1147  connectedToPeer(nil);
1148 }
1149 
1150 void
1152 {
1153  if (ErrorState *error = answer.error.get()) {
1154  answer.error.clear(); // sendError() will own the error
1155  sendError(error, "TLS peer connection error");
1156  return;
1157  }
1158 
1160 }
1161 
1162 static void
1164 {
1165  TunnelStateData *tunnelState = (TunnelStateData *)data;
1166  assert(!tunnelState->waitingForConnectExchange());
1167  HttpHeader hdr_out(hoRequest);
1168  Http::StateFlags flags;
1169  debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
1170  flags.proxying = tunnelState->request->flags.proxying;
1171  MemBuf mb;
1172  mb.init();
1173  mb.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
1175  NULL, /* StoreEntry */
1176  tunnelState->al, /* AccessLogEntry */
1177  &hdr_out,
1178  flags); /* flags */
1179  hdr_out.packInto(&mb);
1180  hdr_out.clean();
1181  mb.append("\r\n", 2);
1182 
1183  debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn <<
1184  ":\n----------\n" << mb.buf << "\n----------");
1185 
1186  AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
1188  tunnelState));
1189 
1190  tunnelState->server.write(mb.buf, mb.size, writeCall, mb.freeFunc());
1191  tunnelState->connectReqWriting = true;
1192 
1193  tunnelState->connectRespBuf = new MemBuf;
1194  // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1195  // can hold since any CONNECT response leftovers have to fit into server.buf.
1196  // 2*SQUID_TCP_SO_RCVBUF: Http::Message::parse() zero-terminates, which uses space.
1197  tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
1198  tunnelState->readConnectResponse();
1199 
1200  assert(tunnelState->waitingForConnectExchange());
1201 
1202  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1203  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1204  commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
1205 }
1206 
1209 {
1210  // pinned_connection may become nil after a pconn race
1211  if (ConnStateData *pinned_connection = request ? request->pinnedConnection() : nullptr) {
1212  Comm::ConnectionPointer serverConn = pinned_connection->borrowPinnedConnection(request, serverDestination->getPeer());
1213  return serverConn;
1214  }
1215 
1216  return nullptr;
1217 }
1218 
1219 void
1221 {
1222  const bool wasBlocked = serverDestinations.empty();
1223  serverDestinations.push_back(path);
1224  if (wasBlocked)
1225  startConnecting();
1226  // else continue to use one of the previously noted destinations;
1227  // if all of them fail, we may try this path
1228 }
1229 
1230 void
1232 {
1234  if (serverDestinations.empty()) { // was blocked, waiting for more paths
1235 
1236  if (selectionError)
1237  return sendError(selectionError, "path selection has failed");
1238 
1239  if (savedError)
1240  return sendError(savedError, "all found paths have failed");
1241 
1243  "path selection found no paths");
1244  }
1245  // else continue to use one of the previously noted destinations;
1246  // if all of them fail, tunneling as whole will fail
1247  Must(!selectionError); // finding at least one path means selection succeeded
1248 }
1249 
1251 void
1253 {
1254  debugs(26, 4, savedError << " ? " << error);
1255  assert(error);
1256  delete savedError; // may be nil
1257  savedError = error;
1258 }
1259 
1262 void
1263 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1264 {
1265  debugs(26, 3, "aborting transaction for " << reason);
1266 
1267  if (request)
1268  request->hier.stopPeerClock(false);
1269 
1270  assert(finalError);
1271 
1272  // get rid of any cached error unless that is what the caller is sending
1273  if (savedError != finalError)
1274  delete savedError; // may be nil
1275  savedError = nullptr;
1276 
1277  // we cannot try other destinations after responding with an error
1278  PeerSelectionInitiator::subscribed = false; // may already be false
1279 
1280  *status_ptr = finalError->httpStatus;
1281  finalError->callback = tunnelErrorComplete;
1282  finalError->callback_data = this;
1283  errorSend(client.conn, finalError);
1284 }
1285 
1286 void
1288 {
1289  if (request)
1291 
1292  assert(!serverDestinations.empty());
1294  debugs(26, 3, "to " << dest);
1295 
1296  if (dest->peerType == PINNED) {
1298  debugs(26,7, "pinned peer connection: " << serverConn);
1299  if (Comm::IsConnOpen(serverConn)) {
1300  tunnelConnectDone(serverConn, Comm::OK, 0, (void *)this);
1301  return;
1302  }
1303  // a PINNED path failure is fatal; do not wait for more paths
1305  "pinned path failure");
1306  return;
1307  }
1308 
1310 
1311  const time_t connectTimeout = dest->connectTimeout(startTime);
1312  AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, this));
1313  Comm::ConnOpener *cs = new Comm::ConnOpener(dest, call, connectTimeout);
1314  cs->setHost(url);
1315  AsyncJob::Start(cs);
1316 }
1317 
1319 
1320 bool
1322 {
1324 }
1325 
1326 #if USE_DELAY_POOLS
1327 void
1329 {
1330  delayId = newDelay;
1331 }
1332 
1333 #endif
1334 
1335 #if USE_OPENSSL
1336 void
1338 {
1339  debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1340 
1341  /* Create state structure. */
1342  ++statCounter.server.all.requests;
1343  ++statCounter.server.other.requests;
1344 
1345  auto conn = request->clientConnectionManager.get();
1346  Must(conn);
1347  Http::StreamPointer context = conn->pipeline.front();
1348  Must(context && context->http);
1349 
1350  debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1351 
1352  TunnelStateData *tunnelState = new TunnelStateData(context->http);
1353 
1354  fd_table[clientConn->fd].read_method = &default_read_method;
1355  fd_table[clientConn->fd].write_method = &default_write_method;
1356 
1357  request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1358 
1359  tunnelState->server.conn = srvConn;
1360 
1361 #if USE_DELAY_POOLS
1362  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1363  if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay)
1364  tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1365 #endif
1366 
1367  request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1368  comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState);
1369 
1370  debugs(26, 4, "determine post-connect handling pathway.");
1371  if (srvConn->getPeer()) {
1372  request->peer_login = srvConn->getPeer()->login;
1373  request->peer_domain = srvConn->getPeer()->domain;
1374  request->flags.auth_no_keytab = srvConn->getPeer()->options.auth_no_keytab;
1375  request->flags.proxying = !(srvConn->getPeer()->options.originserver);
1376  } else {
1377  request->peer_login = nullptr;
1378  request->peer_domain = nullptr;
1379  request->flags.auth_no_keytab = false;
1380  request->flags.proxying = false;
1381  }
1382 
1383  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1384  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1385  commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall);
1386  fd_table[srvConn->fd].read_method = &default_read_method;
1387  fd_table[srvConn->fd].write_method = &default_write_method;
1388 
1389  auto ssl = fd_table[srvConn->fd].ssl.get();
1390  assert(ssl);
1391  BIO *b = SSL_get_rbio(ssl);
1392  Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
1393  tunnelState->preReadServerData = srvBio->rBufData();
1394  tunnelStartShoveling(tunnelState);
1395 }
1396 #endif //USE_OPENSSL
1397 
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:404
FREE * freeFunc()
Definition: MemBuf.cc:312
HierarchyLogEntry hier
Definition: HttpRequest.h:149
bool interceptTproxy
Set for requests handled by a "tproxy" port.
Definition: RequestFlags.h:68
char * login
Definition: CachePeer.h:171
static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:393
struct StatCounters::@129 server
#define fd_table
Definition: fde.h:157
Ssl::ServerBump * serverBump()
Definition: client_side.h:253
ConnStateData * pinnedConnection()
Definition: HttpRequest.cc:668
unsigned short port() const
Definition: Address.cc:771
StatCounters statCounter
Definition: StatCounters.cc:12
struct StatCounters::@129::@138 other
#define assert(EX)
Definition: assert.h:17
Ip::Address my_addr
Definition: HttpRequest.h:147
static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:563
void const char HLPCB * callback
Definition: stub_helper.cc:16
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:418
Comm::ConnectionPointer conn
The currently connected connection.
Definition: tunnel.cc:159
int * status_ptr
pointer for logging HTTP status
Definition: tunnel.cc:174
Security::EncryptorAnswer answer_
Definition: tunnel.cc:217
static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *)
Definition: tunnel.cc:1163
void copyClientBytes()
Definition: tunnel.cc:847
virtual void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: tunnel.cc:1220
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:216
void startPeerClock()
Start recording total time spent communicating with peers.
Definition: access_log.cc:296
const SBuf & rBufData()
The buffered input data.
Definition: bio.h:61
CbcPointer< ClientHttpRequest > http
Definition: tunnel.cc:91
void CTCB(const CommTimeoutCbParams &params)
Definition: CommCalls.h:39
static void ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
Definition: tunnel.cc:479
int debugLevelForError(int const xerrno) const
Definition: tunnel.cc:376
int hdr_sz
Definition: Message.h:82
CbcPointer< ErrorState > error
problem details (nil on success)
void informUserOfPeerError(const char *errMsg, size_t)
Definition: tunnel.cc:450
MyAnswerDialer(Method method, TunnelStateData *tunnel)
Definition: tunnel.cc:201
Definition: SBuf.h:86
char * domain
Forced domain.
Definition: CachePeer.h:184
struct StatCounters::@128 client_http
bool isNoAddr() const
Definition: Address.cc:277
Ip::Address src_addr
void copyServerBytes()
Definition: tunnel.cc:861
HttpRequestMethod method
Definition: HttpRequest.h:106
void setHost(const char *)
set the hostname note for this connection
Definition: ConnOpener.cc:89
void error(char *format,...)
int default_read_method(int, char *, int)
Definition: fd.cc:146
#define xstrdup
SBuf & append(const SBuf &S)
Definition: SBuf.cc:195
ConnStateData * getConn() const
static void tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
Definition: tunnel.cc:911
bool denied() const
Definition: Acl.h:147
ERCB * callback
Definition: errorpage.h:156
#define safe_free(x)
Definition: xalloc.h:73
std::vector< Comm::ConnectionPointer > ConnectionList
Definition: forward.h:29
Definition: Flag.h:16
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:733
time_t startTime
object creation time, before any peer selection/connection attempts
Definition: tunnel.cc:180
CachePeer * getPeer() const
Definition: Connection.cc:98
void saveError(ErrorState *finalError)
remembers an error to be used if there will be no more connection attempts
Definition: tunnel.cc:1252
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
bool isEmpty() const
Definition: SBuf.h:420
Interface for those who need a list of peers to forward a request to.
AccessLogEntryPointer al
Definition: tunnel.cc:93
AnyP::ProtocolVersion http_ver
Definition: Message.h:73
MemBuf * connectRespBuf
accumulates peer CONNECT response when we need it
Definition: tunnel.cc:176
char * p
Definition: membanger.c:43
void FREE(void *)
Definition: forward.h:36
int conn
the current server connection FD
Definition: Transport.cc:26
static CNCB tunnelConnectDone
Definition: tunnel.cc:243
static void httpBuildRequestHeader(HttpRequest *request, StoreEntry *entry, const AccessLogEntryPointer &al, HttpHeader *hdr_out, const Http::StateFlags &flags)
Definition: http.cc:1757
void * callback_data
Definition: errorpage.h:157
int default_write_method(int, const char *, int)
Definition: fd.cc:156
Connection server
Definition: tunnel.cc:173
time_t squid_curtime
Definition: stub_time.cc:17
ErrorState * savedError
details of the "last tunneling attempt" failure (if it failed)
Definition: tunnel.cc:224
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:608
bool auth_no_keytab
Definition: CachePeer.h:119
SBuf preReadClientData
Definition: tunnel.cc:178
ByteCounter kbytes_in
Definition: StatCounters.h:45
char * url
Definition: tunnel.cc:90
void * BIO_get_data(BIO *table)
Definition: openssl.h:60
AsyncCall * asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition: AsyncCall.h:156
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
void connectedToPeer(Security::EncryptorAnswer &answer)
callback handler after connection setup (including any encryption)
Definition: tunnel.cc:1151
void noteConnectFailure(const Comm::ConnectionPointer &conn)
reacts to a failure to establish the given TCP connection
Definition: tunnel.cc:1006
static const char *const conn_established
Definition: tunnel.cc:241
void startConnecting()
Definition: tunnel.cc:1287
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Sets initial TOS value and Netfilter for the future outgoing connection.
Definition: FwdState.cc:1369
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
static void tunnelStartShoveling(TunnelStateData *tunnelState)
Definition: tunnel.cc:879
time_t lifetime
Definition: SquidConfig.h:108
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:24
Http::StreamPointer front() const
get the first request context in the pipeline
Definition: Pipeline.cc:28
static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:703
void const char HLPCB void * data
Definition: stub_helper.cc:16
LogTags logType
the processing tags associated with this request transaction.
unsigned short port
Definition: errorpage.h:150
StatusCode
Definition: StatusCode.h:20
void EVH(void *)
Definition: event.h:19
bool subscribed
whether noteDestination() and noteDestinationsEnd() calls are allowed
static CLCB tunnelClientClosed
Definition: tunnel.cc:246
void peerConnectFailed(CachePeer *p)
Definition: neighbors.cc:1292
static Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request, Comm::ConnectionPointer &serverDestination)
Definition: tunnel.cc:1208
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
char * space()
returns buffer after data; does not check space existence
Definition: MemBuf.h:57
Cbc * valid() const
was set and is valid
Definition: CbcPointer.h:41
CbcPointer< TunnelStateData > tunnel_
Definition: tunnel.cc:216
bool auth_no_keytab
Definition: RequestFlags.h:30
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
void const char int sz
Definition: stub_cbdata.cc:16
void update(const LogTags_ot t)
Definition: LogTags.cc:44
void connectExchangeCheckpoint()
Called when we may be done handling a CONNECT exchange with the peer.
Definition: tunnel.cc:956
Ip::Address client_addr
Definition: HttpRequest.h:141
virtual void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1231
mb_size_t size
Definition: MemBuf.h:135
static CTCB tunnelTimeout
Definition: tunnel.cc:247
bool clientExpectsConnectResponse() const
Whether the client sent a CONNECT request to us.
Definition: tunnel.cc:108
char * peer_host
Definition: HttpRequest.h:158
void comm_read(const Comm::ConnectionPointer &conn, char *buf, int len, AsyncCall::Pointer &callback)
Definition: Read.h:57
AnyP::Uri url
the request URI
Definition: HttpRequest.h:107
void clear()
make pointer not set; does not invalidate cbdata
Definition: CbcPointer.h:144
CbcPointer< ConnStateData > clientConnectionManager
Definition: HttpRequest.h:222
bool waitingForConnectResponse() const
Whether we are reading a CONNECT response from a peer.
Definition: tunnel.cc:103
struct SquidConfig::@113 accessList
acl_access * miss
Definition: SquidConfig.h:361
Http::StatusCode httpStatus
Definition: errorpage.h:143
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:597
bool waitingForConnectExchange() const
Whether we are waiting for the CONNECT request/response exchange with the peer.
Definition: tunnel.cc:105
TunnelStateData(ClientHttpRequest *)
Definition: tunnel.cc:308
AccessLogEntry::Pointer al
access.log entry
static void tunnelConnectReqWriteDone(const Comm::ConnectionPointer &conn, char *, size_t ioSize, Comm::Flag flag, int, void *data)
Called when we are done writing CONNECT request to a peer.
Definition: tunnel.cc:933
void copyRead(Connection &from, IOCB *completion)
Definition: tunnel.cc:817
Http::StatusLine sline
Definition: HttpReply.h:60
LogTags * logTag_ptr
pointer for logging Squid processing code
Definition: tunnel.cc:175
class AccessLogEntry::HttpDetails http
void host(const char *src)
Definition: Uri.cc:47
void dial(AsyncCall &call)
Definition: tunnel.cc:206
virtual void print(std::ostream &os) const
Definition: tunnel.cc:207
SBuf consume(size_type n=npos)
Definition: SBuf.cc:491
bool connectReqWriting
whether we are writing a CONNECT request to a peer
Definition: tunnel.cc:177
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
char * content()
start of the added data
Definition: MemBuf.h:41
struct ClientHttpRequest::Out out
CBDATA_CHILD(TunnelStateData)
static void tunnelConnected(const Comm::ConnectionPointer &server, void *)
Definition: tunnel.cc:973
void appended(mb_size_t sz)
updates content size after external append
Definition: MemBuf.cc:235
void CLCB(const CommCloseCbParams &params)
Definition: CommCalls.h:42
void const char * buf
Definition: stub_helper.cc:16
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
void IOCB(const Comm::ConnectionPointer &conn, char *, size_t size, Comm::Flag flag, int xerrno, void *data)
Definition: CommCalls.h:36
void eventDelete(EVH *func, void *arg)
Definition: event.cc:131
void readConnectResponse()
Starts reading peer response to our CONNECT request.
Definition: tunnel.cc:836
Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
Definition: tunnel.cc:196
Flag
Definition: Flag.h:15
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
static CLCB tunnelServerClosed
Definition: tunnel.cc:245
void connectToPeer()
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1133
void resetPeerNotes(const Comm::ConnectionPointer &server, const char *requestedHost)
Definition: access_log.cc:250
void stopPeerClock(const bool force)
Definition: access_log.cc:303
static EVH tunnelDelayedClientRead
Definition: tunnel.cc:248
int ignoreErrno(int ierrno)
Definition: comm.cc:1477
static EVH tunnelDelayedServerRead
Definition: tunnel.cc:249
void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:660
void eventAdd(const char *name, EVH *func, void *arg, double when, int weight, bool cbdata)
Definition: event.cc:109
char * buf
Definition: MemBuf.h:134
RequestFlags flags
Definition: HttpRequest.h:133
void switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn)
Definition: tunnel.cc:1337
struct StatCounters::@129::@138 all
Ip::Address remote
Definition: Connection.h:138
void Comm::ConnectionPointer & clientConn
Definition: stub_tunnel.cc:19
mb_size_t spaceSize() const
Definition: MemBuf.cc:158
#define xmalloc
Cbc * get() const
a temporary valid raw Cbc pointer or NULL
Definition: CbcPointer.h:162
void readConnectResponseDone(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Called when we read [a part of] CONNECT response from the peer.
Definition: tunnel.cc:429
bool intercepted
Definition: RequestFlags.h:64
bool no_delay
Definition: CachePeer.h:98
#define CBDATA_CLASS_INIT(type)
Definition: cbdata.h:318
void copy(size_t len, Connection &from, Connection &to, IOCB *)
Definition: tunnel.cc:640
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:354
A simple PeerConnector for SSL/TLS cache_peers. No SslBump capabilities.
bool hasSpace() const
Definition: MemBuf.h:72
Callback dialer API to allow PeerConnector to set the answer.
Definition: PeerConnector.h:71
AsyncCall::Pointer writer
pending Comm::Write callback
Definition: tunnel.cc:156
C * getRaw() const
Definition: RefCount.h:74
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
size_t HttpReply *STUB StoreEntry const KeyScope scope const HttpRequestMethod & method
Definition: stub_store.cc:122
virtual ~TunnelStateData()
Definition: tunnel.cc:335
SBuf inBuf
read I/O buffer for the client connection
Definition: Server.h:110
Definition: MemBuf.h:23
void CNCB(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
Definition: CommCalls.h:35
void sendError(ErrorState *finalError, const char *reason)
Definition: tunnel.cc:1263
Comm::ConnectionPointer clientConnection
Definition: Server.h:97
struct CachePeer::@31 options
void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:403
struct SquidConfig::@98 Timeout
allow_t const & fastCheck()
Definition: Checklist.cc:336
TunnelStateData * readPending
Definition: tunnel.cc:163
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
Http::StatusCode status() const
retrieve the status code for this status line
Definition: StatusLine.h:45
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:412
void error(int const xerrno)
Definition: tunnel.cc:553
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:961
#define INT_MAX
Definition: types.h:76
void tunnelStart(ClientHttpRequest *http)
Definition: tunnel.cc:1087
HttpRequest *const request
Definition: Debug.h:184
int xerrno
Definition: errorpage.h:149
bool parse(const char *buf, const size_t sz, bool eol, Http::StatusCode *error)
Definition: Message.cc:80
void startSelectingDestinations(HttpRequest *request, const AccessLogEntry::Pointer &ale, StoreEntry *entry)
Definition: peer_select.cc:193
Ssl::BumpStep step
The SSL bumping step.
Definition: ServerBump.h:53
void handleConnectResponse(const size_t chunkSize)
Definition: tunnel.cc:491
bool waitingForConnectRequest() const
Whether we are writing a CONNECT request to a peer.
Definition: tunnel.cc:101
void netdbPingSite(const char *hostname)
Definition: net_db.cc:909
void ERCB(int fd, void *, size_t)
error page callback
Definition: errorpage.h:29
#define DBG_DATA
Definition: Debug.h:48
void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:572
const char * getHost() const
Definition: tunnel.cc:96
static ERCB tunnelErrorComplete
Definition: tunnel.cc:244
ByteCounter kbytes_out
Definition: StatCounters.h:46
HttpRequest::Pointer request
Definition: tunnel.cc:92
TunnelStateData & operator=(const TunnelStateData &)
#define xfree
void write(const char *b, int size, AsyncCall::Pointer &callback, FREE *free_func)
writes &#39;b&#39; buffer, setting the &#39;writer&#39; member to &#39;callback&#39;.
Definition: tunnel.cc:726
SBuf preReadServerData
Definition: tunnel.cc:179
char * peer_login
Definition: HttpRequest.h:156
uint64_t payloadData
total size of payload block(s) excluding transfer encoding overheads
Definition: MessageSizes.h:24
static DelayId DelayClient(ClientHttpRequest *, HttpReply *reply=nullptr)
Definition: DelayId.cc:67
MessageSizes clientRequestSz
counters for the original request received from client
void setDelayId(DelayId const &)
Definition: tunnel.cc:1328
bool noConnections() const
Definition: tunnel.cc:1321
bool originserver
Definition: CachePeer.h:114
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:552
class SquidConfig Config
Definition: SquidConfig.cc:12
#define NULL
Definition: types.h:166
Connection client
Definition: tunnel.cc:173
Http::StatusCode peer_reply_status
last HTTP status code received
virtual Security::EncryptorAnswer & answer()
gives PeerConnector access to the in-dialer answer
Definition: tunnel.cc:212
int size
Definition: ModDevPoll.cc:77
const char * rawContent() const
Definition: SBuf.cc:519
void dataSent(size_t amount)
Definition: tunnel.cc:713
char * peer_domain
Definition: HttpRequest.h:165
time_t read
Definition: SquidConfig.h:106
void bytesIn(int const &)
Definition: tunnel.cc:365
#define false
Definition: GnuRegex.c:233
char * host
Definition: CachePeer.h:37
void Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE *free_func)
Definition: Write.cc:35
static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
Definition: tunnel.cc:650
virtual bool canDial(AsyncCall &call)
Definition: tunnel.cc:205
Comm::ConnectionList serverDestinations
Definition: tunnel.cc:94
Pipeline pipeline
set of requests waiting to be serviced
Definition: Server.h:115
bool forceTunnel
whether to forward via TunnelStateData (instead of FwdState)
Definition: RequestFlags.h:113
uint8_t delayedLoops
how many times a read on this connection has been postponed.
Definition: tunnel.cc:160
void terminate()
Definition: MemBuf.cc:250

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors