tunnel.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 
220  void usePinned();
221 
224 
226  ErrorState *savedError = nullptr;
227 
228 public:
229  bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
230  void copy(size_t len, Connection &from, Connection &to, IOCB *);
231  void handleConnectResponse(const size_t chunkSize);
232  void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
233  void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
234  void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
235  void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
236 
237  static void ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
238  void readConnectResponseDone(char *buf, size_t len, Comm::Flag errcode, int xerrno);
239  void copyClientBytes();
240  void copyServerBytes();
241 };
242 
243 static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
244 
252 static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
253 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
254 
255 static void
257 {
258  TunnelStateData *tunnelState = (TunnelStateData *)params.data;
259  debugs(26, 3, HERE << tunnelState->server.conn);
260  tunnelState->server.conn = NULL;
261  tunnelState->server.writer = NULL;
262 
263  if (tunnelState->request != NULL)
264  tunnelState->request->hier.stopPeerClock(false);
265 
266  if (tunnelState->noConnections()) {
267  // ConnStateData pipeline should contain the CONNECT we are performing
268  // but it may be invalid already (bug 4392)
269  if (tunnelState->http.valid() && tunnelState->http->getConn()) {
270  auto ctx = tunnelState->http->getConn()->pipeline.front();
271  if (ctx != nullptr)
272  ctx->finished();
273  }
274  delete tunnelState;
275  return;
276  }
277 
278  if (!tunnelState->client.writer) {
279  tunnelState->client.conn->close();
280  return;
281  }
282 }
283 
284 static void
286 {
287  TunnelStateData *tunnelState = (TunnelStateData *)params.data;
288  debugs(26, 3, HERE << tunnelState->client.conn);
289  tunnelState->client.conn = NULL;
290  tunnelState->client.writer = NULL;
291 
292  if (tunnelState->noConnections()) {
293  // ConnStateData pipeline should contain the CONNECT we are performing
294  // but it may be invalid already (bug 4392)
295  if (tunnelState->http.valid() && tunnelState->http->getConn()) {
296  auto ctx = tunnelState->http->getConn()->pipeline.front();
297  if (ctx != nullptr)
298  ctx->finished();
299  }
300  delete tunnelState;
301  return;
302  }
303 
304  if (!tunnelState->server.writer) {
305  tunnelState->server.conn->close();
306  return;
307  }
308 }
309 
314 {
315  debugs(26, 3, "TunnelStateData constructed this=" << this);
318 
319  assert(clientRequest);
320  url = xstrdup(clientRequest->uri);
321  request = clientRequest->request;
322  server.size_ptr = &clientRequest->out.size;
323  client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
324  status_ptr = &clientRequest->al->http.code;
325  logTag_ptr = &clientRequest->logType;
326  al = clientRequest->al;
327  http = clientRequest;
328 
329  client.conn = clientRequest->getConn()->clientConnection;
331 
332  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
335 }
336 
338 {
339  debugs(26, 3, "TunnelStateData destructed this=" << this);
341  xfree(url);
342  serverDestinations.clear();
343  delete connectRespBuf;
344  delete savedError;
345 }
346 
348 {
349  if (readPending)
350  eventDelete(readPendingFunc, readPending);
351 
352  safe_free(buf);
353 }
354 
355 int
356 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
357 {
358 #if USE_DELAY_POOLS
359  return delayId.bytesWanted(lowerbound, upperbound);
360 #else
361 
362  return upperbound;
363 #endif
364 }
365 
366 void
368 {
369  debugs(26, 3, HERE << "len=" << len << " + count=" << count);
370 #if USE_DELAY_POOLS
371  delayId.bytesIn(count);
372 #endif
373 
374  len += count;
375 }
376 
377 int
379 {
380 #ifdef ECONNRESET
381 
382  if (xerrno == ECONNRESET)
383  return 2;
384 
385 #endif
386 
387  if (ignoreErrno(xerrno))
388  return 3;
389 
390  return 1;
391 }
392 
393 /* Read from server side and queue it for writing to the client */
394 void
395 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
396 {
397  TunnelStateData *tunnelState = (TunnelStateData *)data;
398  assert(cbdataReferenceValid(tunnelState));
399  debugs(26, 3, HERE << c);
400 
401  tunnelState->readServer(buf, len, errcode, xerrno);
402 }
403 
404 void
405 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
406 {
407  debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
409 
410  /*
411  * Bail out early on Comm::ERR_CLOSING
412  * - close handlers will tidy up for us
413  */
414 
415  if (errcode == Comm::ERR_CLOSING)
416  return;
417 
418  if (len > 0) {
419  server.bytesIn(len);
420  statCounter.server.all.kbytes_in += len;
421  statCounter.server.other.kbytes_in += len;
423  }
424 
425  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
427 }
428 
430 void
431 TunnelStateData::readConnectResponseDone(char *, size_t len, Comm::Flag errcode, int xerrno)
432 {
433  debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
435 
436  if (errcode == Comm::ERR_CLOSING)
437  return;
438 
439  if (len > 0) {
440  connectRespBuf->appended(len);
441  server.bytesIn(len);
442  statCounter.server.all.kbytes_in += len;
443  statCounter.server.other.kbytes_in += len;
445  }
446 
447  if (keepGoingAfterRead(len, errcode, xerrno, server, client))
449 }
450 
451 void
452 TunnelStateData::informUserOfPeerError(const char *errMsg, const size_t sz)
453 {
454  server.len = 0;
455 
456  if (logTag_ptr)
458 
460  // closing the connection is the best we can do here
461  debugs(50, 3, server.conn << " closing on error: " << errMsg);
462  server.conn->close();
463  return;
464  }
465 
466  // if we have no reply suitable to relay, use 502 Bad Gateway
467  if (!sz || sz > static_cast<size_t>(connectRespBuf->contentSize()))
469  "peer error without reply");
470 
471  // if we need to send back the server response. write its headers to the client
472  server.len = sz;
473  memcpy(server.buf, connectRespBuf->content(), server.len);
475  // then close the server FD to prevent any relayed keep-alive causing CVE-2015-5400
477 }
478 
479 /* Read from client side and queue it for writing to the server */
480 void
481 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
482 {
483  TunnelStateData *tunnelState = (TunnelStateData *)data;
484  assert (cbdataReferenceValid (tunnelState));
485 
486  tunnelState->readConnectResponseDone(buf, len, errcode, xerrno);
487 }
488 
492 void
494 {
496 
497  // Ideally, client and server should use MemBuf or better, but current code
498  // never accumulates more than one read when shoveling data (XXX) so it does
499  // not need to deal with MemBuf complexity. To keep it simple, we use a
500  // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
501  // is optimized, reuse server.buf for CONNEC response accumulation instead.
502 
503  /* mimic the basic parts of HttpStateData::processReplyHeader() */
504  HttpReply rep;
505  Http::StatusCode parseErr = Http::scNone;
506  const bool eof = !chunkSize;
507  connectRespBuf->terminate(); // Http::Message::parse requires terminated string
508  const bool parsed = rep.parse(connectRespBuf->content(), connectRespBuf->contentSize(), eof, &parseErr);
509  if (!parsed) {
510  if (parseErr > 0) { // unrecoverable parsing error
511  informUserOfPeerError("malformed CONNECT response from peer", 0);
512  return;
513  }
514 
515  // need more data
516  assert(!eof);
517  assert(!parseErr);
518 
519  if (!connectRespBuf->hasSpace()) {
520  informUserOfPeerError("huge CONNECT response from peer", 0);
521  return;
522  }
523 
524  // keep reading
526  return;
527  }
528 
529  // CONNECT response was successfully parsed
531 
532  // bail if we did not get an HTTP 200 (Connection Established) response
533  if (rep.sline.status() != Http::scOkay) {
534  // if we ever decide to reuse the peer connection, we must extract the error response first
535  *status_ptr = rep.sline.status(); // we are relaying peer response
536  informUserOfPeerError("unsupported CONNECT response status code", rep.hdr_sz);
537  return;
538  }
539 
540  if (rep.hdr_sz < connectRespBuf->contentSize()) {
541  // preserve bytes that the server already sent after the CONNECT response
543  memcpy(server.buf, connectRespBuf->content()+rep.hdr_sz, server.len);
544  } else {
545  // reset; delay pools were using this field to throttle CONNECT response
546  server.len = 0;
547  }
548 
549  delete connectRespBuf;
552 }
553 
554 void
556 {
557  debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerr(xerrno));
558 
559  if (!ignoreErrno(xerrno))
560  conn->close();
561 }
562 
563 /* Read from client side and queue it for writing to the server */
564 void
565 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
566 {
567  TunnelStateData *tunnelState = (TunnelStateData *)data;
568  assert (cbdataReferenceValid (tunnelState));
569 
570  tunnelState->readClient(buf, len, errcode, xerrno);
571 }
572 
573 void
574 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
575 {
576  debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
578 
579  /*
580  * Bail out early on Comm::ERR_CLOSING
581  * - close handlers will tidy up for us
582  */
583 
584  if (errcode == Comm::ERR_CLOSING)
585  return;
586 
587  if (len > 0) {
588  client.bytesIn(len);
590  }
591 
592  if (keepGoingAfterRead(len, errcode, xerrno, client, server))
594 }
595 
598 bool
600 {
601  debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
602 
603  /* I think this is to prevent free-while-in-a-callback behaviour
604  * - RBC 20030229
605  * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
606  */
607  const CbcPointer<TunnelStateData> safetyLock(this);
608 
609  /* Bump the source connection read timeout on any activity */
610  if (Comm::IsConnOpen(from.conn)) {
611  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
613  commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
614  }
615 
616  /* Bump the dest connection read timeout on any activity */
617  /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
618  if (Comm::IsConnOpen(to.conn)) {
619  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
621  commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
622  }
623 
624  if (errcode)
625  from.error (xerrno);
626  else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
627  debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
628  from.conn->close();
629 
630  /* Only close the remote end if we've finished queueing data to it */
631  if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
632  to.conn->close();
633  }
634  } else if (cbdataReferenceValid(this)) {
635  return true;
636  }
637 
638  return false;
639 }
640 
641 void
642 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
643 {
644  debugs(26, 3, HERE << "Schedule Write");
645  AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
646  CommIoCbPtrFun(completion, this));
647  to.write(from.buf, len, call, NULL);
648 }
649 
650 /* Writes data from the client buffer to the server side */
651 void
652 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
653 {
654  TunnelStateData *tunnelState = (TunnelStateData *)data;
655  assert (cbdataReferenceValid (tunnelState));
656  tunnelState->server.writer = NULL;
657 
658  tunnelState->writeServerDone(buf, len, flag, xerrno);
659 }
660 
661 void
662 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
663 {
664  debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
665 
666  if (flag == Comm::ERR_CLOSING)
667  return;
668 
670 
671  /* Error? */
672  if (flag != Comm::OK) {
673  debugs(26, 4, "to-server write failed: " << xerrno);
674  server.error(xerrno); // may call comm_close
675  return;
676  }
677 
678  /* EOF? */
679  if (len == 0) {
680  debugs(26, 4, HERE << "No read input. Closing server connection.");
681  server.conn->close();
682  return;
683  }
684 
685  /* Valid data */
686  statCounter.server.all.kbytes_out += len;
687  statCounter.server.other.kbytes_out += len;
688  client.dataSent(len);
689 
690  /* If the other end has closed, so should we */
691  if (!Comm::IsConnOpen(client.conn)) {
692  debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
693  server.conn->close();
694  return;
695  }
696 
697  const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
698 
699  if (cbdataReferenceValid(this))
700  copyClientBytes();
701 }
702 
703 /* Writes data from the server buffer to the client side */
704 void
705 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
706 {
707  TunnelStateData *tunnelState = (TunnelStateData *)data;
708  assert (cbdataReferenceValid (tunnelState));
709  tunnelState->client.writer = NULL;
710 
711  tunnelState->writeClientDone(buf, len, flag, xerrno);
712 }
713 
714 void
716 {
717  debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
718  assert(amount == (size_t)len);
719  len =0;
720  /* increment total object size */
721 
722  if (size_ptr)
723  *size_ptr += amount;
724 
725 }
726 
727 void
729 {
730  writer = callback;
731  Comm::Write(conn, b, size, callback, free_func);
732 }
733 
734 void
735 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
736 {
737  debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
738 
739  if (flag == Comm::ERR_CLOSING)
740  return;
741 
742  /* Error? */
743  if (flag != Comm::OK) {
744  debugs(26, 4, "from-client read failed: " << xerrno);
745  client.error(xerrno); // may call comm_close
746  return;
747  }
748 
749  /* EOF? */
750  if (len == 0) {
751  debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
752  client.conn->close();
753  return;
754  }
755 
756  /* Valid data */
758  server.dataSent(len);
759 
760  /* If the other end has closed, so should we */
761  if (!Comm::IsConnOpen(server.conn)) {
762  debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
763  client.conn->close();
764  return;
765  }
766 
767  CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
768 
769  if (cbdataReferenceValid(this))
770  copyServerBytes();
771 }
772 
773 static void
775 {
776  TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
777  debugs(26, 3, HERE << io.conn);
778  /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
779  CbcPointer<TunnelStateData> safetyLock(tunnelState);
780 
781  tunnelState->client.closeIfOpen();
782  tunnelState->server.closeIfOpen();
783 }
784 
785 void
787 {
788  if (Comm::IsConnOpen(conn))
789  conn->close();
790 }
791 
792 static void
794 {
795  if (!data)
796  return;
797 
798  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
799  tunnel->client.readPending = NULL;
800  static uint64_t counter=0;
801  debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
802  tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
803 }
804 
805 static void
807 {
808  if (!data)
809  return;
810 
811  TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
812  tunnel->server.readPending = NULL;
813  static uint64_t counter=0;
814  debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
815  tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
816 }
817 
818 void
820 {
821  assert(from.len == 0);
822  // If only the minimum permitted read size is going to be attempted
823  // then we schedule an event to try again in a few I/O cycles.
824  // Allow at least 1 byte to be read every (0.3*10) seconds.
825  int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
826  if (bw == 1 && ++from.delayedLoops < 10) {
827  from.readPending = this;
828  eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
829  return;
830  }
831 
832  AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
833  CommIoCbPtrFun(completion, this));
834  comm_read(from.conn, from.buf, bw, call);
835 }
836 
837 void
839 {
841 
842  AsyncCall::Pointer call = commCbCall(5,4, "readConnectResponseDone",
846 }
847 
848 void
850 {
851  if (preReadClientData.length()) {
852  size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
853  memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
854  preReadClientData.consume(copyBytes);
855  client.bytesIn(copyBytes);
856  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
858  } else
860 }
861 
862 void
864 {
865  if (preReadServerData.length()) {
866  size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
867  memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
868  preReadServerData.consume(copyBytes);
869  server.bytesIn(copyBytes);
870  if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
872  } else
874 }
875 
880 static void
882 {
883  assert(!tunnelState->waitingForConnectExchange());
884  *tunnelState->status_ptr = Http::scOkay;
885  if (tunnelState->logTag_ptr)
886  tunnelState->logTag_ptr->update(LOG_TCP_TUNNEL);
887  if (cbdataReferenceValid(tunnelState)) {
888 
889  // Shovel any payload already pushed into reply buffer by the server response
890  if (!tunnelState->server.len)
891  tunnelState->copyServerBytes();
892  else {
893  debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
894  tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
895  }
896 
897  if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
898  SBuf * const in = &tunnelState->http->getConn()->inBuf;
899  debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
900  tunnelState->preReadClientData.append(*in);
901  in->consume(); // ConnStateData buffer accounting after the shuffle.
902  }
903  tunnelState->copyClientBytes();
904  }
905 }
906 
912 static void
913 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
914 {
915  TunnelStateData *tunnelState = (TunnelStateData *)data;
916  debugs(26, 3, HERE << conn << ", flag=" << flag);
917  tunnelState->client.writer = NULL;
918 
919  if (flag != Comm::OK) {
920  *tunnelState->status_ptr = Http::scInternalServerError;
921  tunnelErrorComplete(conn->fd, data, 0);
922  return;
923  }
924 
925  if (auto http = tunnelState->http.get()) {
926  http->out.headers_sz += len;
927  http->out.size += len;
928  }
929 
930  tunnelStartShoveling(tunnelState);
931 }
932 
934 static void
935 tunnelConnectReqWriteDone(const Comm::ConnectionPointer &conn, char *, size_t ioSize, Comm::Flag flag, int, void *data)
936 {
937  TunnelStateData *tunnelState = (TunnelStateData *)data;
938  debugs(26, 3, conn << ", flag=" << flag);
939  tunnelState->server.writer = NULL;
940  assert(tunnelState->waitingForConnectRequest());
941 
942  tunnelState->request->hier.notePeerWrite();
943 
944  if (flag != Comm::OK) {
945  *tunnelState->status_ptr = Http::scInternalServerError;
946  tunnelErrorComplete(conn->fd, data, 0);
947  return;
948  }
949 
950  statCounter.server.all.kbytes_out += ioSize;
951  statCounter.server.other.kbytes_out += ioSize;
952 
953  tunnelState->connectReqWriting = false;
954  tunnelState->connectExchangeCheckpoint();
955 }
956 
957 void
959 {
961  debugs(26, 5, "still reading CONNECT response on " << server.conn);
962  } else if (waitingForConnectRequest()) {
963  debugs(26, 5, "still writing CONNECT request on " << server.conn);
964  } else {
966  debugs(26, 3, "done with CONNECT exchange on " << server.conn);
967  tunnelConnected(server.conn, this);
968  }
969 }
970 
971 /*
972  * handle the write completion from a proxy request to an upstream origin
973  */
974 static void
976 {
977  TunnelStateData *tunnelState = (TunnelStateData *)data;
978  debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
979 
980  if (!tunnelState->clientExpectsConnectResponse())
981  tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
982  else {
983  *tunnelState->status_ptr = Http::scOkay;
984  AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
986  tunnelState->client.write(conn_established, strlen(conn_established), call, NULL);
987  }
988 }
989 
990 static void
991 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
992 {
993  TunnelStateData *tunnelState = (TunnelStateData *)data;
994  debugs(26, 3, HERE << "FD " << fd);
995  assert(tunnelState != NULL);
996  /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
997  CbcPointer<TunnelStateData> safetyLock(tunnelState);
998 
999  if (Comm::IsConnOpen(tunnelState->client.conn))
1000  tunnelState->client.conn->close();
1001 
1002  if (Comm::IsConnOpen(tunnelState->server.conn))
1003  tunnelState->server.conn->close();
1004 }
1005 
1007 void
1009 {
1010  debugs(26, 4, "removing the failed one from " << serverDestinations.size() <<
1011  " destinations: " << conn);
1012 
1013  if (CachePeer *peer = conn->getPeer())
1014  peerConnectFailed(peer);
1015 
1016  assert(!serverDestinations.empty());
1017  serverDestinations.erase(serverDestinations.begin());
1018 
1019  // Since no TCP payload has been passed to client or server, we may
1020  // TCP-connect to other destinations (including alternate IPs).
1021 
1023  return sendError(savedError, "forwarding timeout");
1024 
1025  if (!serverDestinations.empty())
1026  return startConnecting();
1027 
1029  return sendError(savedError, "tried all destinations");
1030 
1031  debugs(26, 4, "wait for more destinations to try");
1032  // expect a noteDestination*() call
1033 }
1034 
1035 static void
1037 {
1038  TunnelStateData *tunnelState = (TunnelStateData *)data;
1039 
1040  if (status != Comm::OK) {
1041  const auto err = new ErrorState(ERR_CONNECT_FAIL, Http::scServiceUnavailable, tunnelState->request.getRaw(), tunnelState->al);
1042  err->xerrno = xerrno;
1043  // on timeout is this still: err->xerrno = ETIMEDOUT;
1044  err->port = conn->remote.port();
1045  tunnelState->saveError(err);
1046  tunnelState->noteConnectFailure(conn);
1047  return;
1048  }
1049 
1050 #if USE_DELAY_POOLS
1051  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1052  if (conn->getPeer() && conn->getPeer()->options.no_delay)
1053  tunnelState->server.setDelayId(DelayId());
1054 #endif
1055 
1056  netdbPingSite(tunnelState->request->url.host());
1057 
1058  tunnelState->request->hier.resetPeerNotes(conn, tunnelState->getHost());
1059 
1060  tunnelState->server.conn = conn;
1061  tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
1062  comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
1063 
1064  debugs(26, 4, HERE << "determine post-connect handling pathway.");
1065  if (conn->getPeer()) {
1066  tunnelState->request->peer_login = conn->getPeer()->login;
1067  tunnelState->request->peer_domain = conn->getPeer()->domain;
1068  tunnelState->request->flags.auth_no_keytab = conn->getPeer()->options.auth_no_keytab;
1069  tunnelState->request->flags.proxying = !(conn->getPeer()->options.originserver);
1070  } else {
1071  tunnelState->request->peer_login = NULL;
1072  tunnelState->request->peer_domain = NULL;
1073  tunnelState->request->flags.auth_no_keytab = false;
1074  tunnelState->request->flags.proxying = false;
1075  }
1076 
1077  if (tunnelState->request->flags.proxying)
1078  tunnelState->connectToPeer();
1079  else {
1080  tunnelConnected(conn, tunnelState);
1081  }
1082 
1083  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1084  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1085  commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
1086 }
1087 
1088 void
1090 {
1091  debugs(26, 3, HERE);
1092  /* Create state structure. */
1093  TunnelStateData *tunnelState = NULL;
1094  ErrorState *err = NULL;
1095  HttpRequest *request = http->request;
1096  char *url = http->uri;
1097 
1098  /*
1099  * client_addr.isNoAddr() indicates this is an "internal" request
1100  * from peer_digest.c, asn.c, netdb.c, etc and should always
1101  * be allowed. yuck, I know.
1102  */
1103 
1104  if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
1105  /*
1106  * Check if this host is allowed to fetch MISSES from us (miss_access)
1107  * default is to allow.
1108  */
1110  ch.al = http->al;
1111  ch.src_addr = request->client_addr;
1112  ch.my_addr = request->my_addr;
1113  ch.syncAle(request, http->log_uri);
1114  if (ch.fastCheck().denied()) {
1115  debugs(26, 4, HERE << "MISS access forbidden.");
1116  err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request, http->al);
1117  http->al->http.code = Http::scForbidden;
1118  errorSend(http->getConn()->clientConnection, err);
1119  return;
1120  }
1121  }
1122 
1123  debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1124  ++statCounter.server.all.requests;
1125  ++statCounter.server.other.requests;
1126 
1127  tunnelState = new TunnelStateData(http);
1128 #if USE_DELAY_POOLS
1129  //server.setDelayId called from tunnelConnectDone after server side connection established
1130 #endif
1131  tunnelState->startSelectingDestinations(request, http->al, nullptr);
1132 }
1133 
1134 void
1136 {
1137  if (CachePeer *p = server.conn->getPeer()) {
1138  if (p->secure.encryptTransport) {
1140  "TunnelStateData::ConnectedToPeer",
1142  auto *connector = new Security::BlindPeerConnector(request, server.conn, callback, al);
1143  AsyncJob::Start(connector); // will call our callback
1144  return;
1145  }
1146  }
1147 
1149  connectedToPeer(nil);
1150 }
1151 
1152 void
1154 {
1155  if (ErrorState *error = answer.error.get()) {
1156  answer.error.clear(); // sendError() will own the error
1157  sendError(error, "TLS peer connection error");
1158  return;
1159  }
1160 
1162 }
1163 
1164 static void
1166 {
1167  TunnelStateData *tunnelState = (TunnelStateData *)data;
1168  assert(!tunnelState->waitingForConnectExchange());
1169  HttpHeader hdr_out(hoRequest);
1170  Http::StateFlags flags;
1171  debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
1172  flags.proxying = tunnelState->request->flags.proxying;
1173  MemBuf mb;
1174  mb.init();
1175  mb.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
1177  NULL, /* StoreEntry */
1178  tunnelState->al, /* AccessLogEntry */
1179  &hdr_out,
1180  flags); /* flags */
1181  hdr_out.packInto(&mb);
1182  hdr_out.clean();
1183  mb.append("\r\n", 2);
1184 
1185  debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn <<
1186  ":\n----------\n" << mb.buf << "\n----------");
1187 
1188  AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
1190  tunnelState));
1191 
1192  tunnelState->server.write(mb.buf, mb.size, writeCall, mb.freeFunc());
1193  tunnelState->connectReqWriting = true;
1194 
1195  tunnelState->connectRespBuf = new MemBuf;
1196  // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1197  // can hold since any CONNECT response leftovers have to fit into server.buf.
1198  // 2*SQUID_TCP_SO_RCVBUF: Http::Message::parse() zero-terminates, which uses space.
1199  tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
1200  tunnelState->readConnectResponse();
1201 
1202  assert(tunnelState->waitingForConnectExchange());
1203 
1204  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1205  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1206  commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
1207 }
1208 
1211 {
1212  // pinned_connection may become nil after a pconn race
1213  if (ConnStateData *pinned_connection = request ? request->pinnedConnection() : nullptr) {
1214  Comm::ConnectionPointer serverConn = pinned_connection->borrowPinnedConnection(request);
1215  return serverConn;
1216  }
1217 
1218  return nullptr;
1219 }
1220 
1221 void
1223 {
1224  const bool wasBlocked = serverDestinations.empty();
1225  // XXX: Push even a nil path so that subsequent noteDestination() calls
1226  // can rely on wasBlocked to detect ongoing/concurrent attempts.
1227  // Upcoming Happy Eyeballs changes will handle this properly.
1228  serverDestinations.push_back(path);
1229 
1230  if (!path) { // decided to use a pinned connection
1231  // We can call usePinned() without fear of clashing with an earlier
1232  // forwarding attempt because PINNED must be the first destination.
1233  assert(wasBlocked);
1234  usePinned();
1235  return;
1236  }
1237 
1238  if (wasBlocked)
1239  startConnecting();
1240  // else continue to use one of the previously noted destinations;
1241  // if all of them fail, we may try this path
1242 }
1243 
1244 void
1246 {
1248  if (serverDestinations.empty()) { // was blocked, waiting for more paths
1249 
1250  if (selectionError)
1251  return sendError(selectionError, "path selection has failed");
1252 
1253  if (savedError)
1254  return sendError(savedError, "all found paths have failed");
1255 
1257  "path selection found no paths");
1258  }
1259  // else continue to use one of the previously noted destinations;
1260  // if all of them fail, tunneling as whole will fail
1261  Must(!selectionError); // finding at least one path means selection succeeded
1262 }
1263 
1265 void
1267 {
1268  debugs(26, 4, savedError << " ? " << error);
1269  assert(error);
1270  delete savedError; // may be nil
1271  savedError = error;
1272 }
1273 
1276 void
1277 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1278 {
1279  debugs(26, 3, "aborting transaction for " << reason);
1280 
1281  if (request)
1282  request->hier.stopPeerClock(false);
1283 
1284  assert(finalError);
1285 
1286  // get rid of any cached error unless that is what the caller is sending
1287  if (savedError != finalError)
1288  delete savedError; // may be nil
1289  savedError = nullptr;
1290 
1291  // we cannot try other destinations after responding with an error
1292  PeerSelectionInitiator::subscribed = false; // may already be false
1293 
1294  *status_ptr = finalError->httpStatus;
1295  finalError->callback = tunnelErrorComplete;
1296  finalError->callback_data = this;
1297  errorSend(client.conn, finalError);
1298 }
1299 
1300 void
1302 {
1303  if (request)
1305 
1306  assert(!serverDestinations.empty());
1308  debugs(26, 3, "to " << dest);
1309  assert(dest != nullptr);
1310 
1312 
1313  const time_t connectTimeout = dest->connectTimeout(startTime);
1314  AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, this));
1315  Comm::ConnOpener *cs = new Comm::ConnOpener(dest, call, connectTimeout);
1316  cs->setHost(url);
1317  AsyncJob::Start(cs);
1318 }
1319 
1321 void
1323 {
1324  const auto serverConn = borrowPinnedConnection(request.getRaw());
1325  debugs(26,7, "pinned peer connection: " << serverConn);
1326  if (!Comm::IsConnOpen(serverConn)) {
1327  // a PINNED path failure is fatal; do not wait for more paths
1329  "pinned path failure");
1330  return;
1331  }
1332 
1333  tunnelConnectDone(serverConn, Comm::OK, 0, (void *)this);
1334 }
1335 
1337 
1338 bool
1340 {
1342 }
1343 
1344 #if USE_DELAY_POOLS
1345 void
1347 {
1348  delayId = newDelay;
1349 }
1350 
1351 #endif
1352 
1353 #if USE_OPENSSL
1354 void
1356 {
1357  debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1358 
1359  /* Create state structure. */
1360  ++statCounter.server.all.requests;
1361  ++statCounter.server.other.requests;
1362 
1363  auto conn = request->clientConnectionManager.get();
1364  Must(conn);
1365  Http::StreamPointer context = conn->pipeline.front();
1366  Must(context && context->http);
1367 
1368  debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1369 
1370  TunnelStateData *tunnelState = new TunnelStateData(context->http);
1371 
1372  fd_table[clientConn->fd].read_method = &default_read_method;
1373  fd_table[clientConn->fd].write_method = &default_write_method;
1374 
1375  request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1376 
1377  tunnelState->server.conn = srvConn;
1378 
1379 #if USE_DELAY_POOLS
1380  /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1381  if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay)
1382  tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1383 #endif
1384 
1385  request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1386  comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState);
1387 
1388  debugs(26, 4, "determine post-connect handling pathway.");
1389  if (srvConn->getPeer()) {
1390  request->peer_login = srvConn->getPeer()->login;
1391  request->peer_domain = srvConn->getPeer()->domain;
1392  request->flags.auth_no_keytab = srvConn->getPeer()->options.auth_no_keytab;
1393  request->flags.proxying = !(srvConn->getPeer()->options.originserver);
1394  } else {
1395  request->peer_login = nullptr;
1396  request->peer_domain = nullptr;
1397  request->flags.auth_no_keytab = false;
1398  request->flags.proxying = false;
1399  }
1400 
1401  AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1402  CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1403  commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall);
1404  fd_table[srvConn->fd].read_method = &default_read_method;
1405  fd_table[srvConn->fd].write_method = &default_write_method;
1406 
1407  auto ssl = fd_table[srvConn->fd].ssl.get();
1408  assert(ssl);
1409  BIO *b = SSL_get_rbio(ssl);
1410  Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
1411  tunnelState->preReadServerData = srvBio->rBufData();
1412  tunnelStartShoveling(tunnelState);
1413 }
1414 #endif //USE_OPENSSL
1415 
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:395
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
void usePinned()
send request on an existing connection dedicated to the requesting client
Definition: tunnel.cc:1322
unsigned short port() const
Definition: Address.cc:778
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:565
void const char HLPCB * callback
Definition: stub_helper.cc:16
static bool EnoughTimeToReForward(const time_t fwdStart)
Definition: FwdState.cc:411
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:1165
void copyClientBytes()
Definition: tunnel.cc:849
virtual void noteDestination(Comm::ConnectionPointer conn) override
called when a new unique destination has been found
Definition: tunnel.cc:1222
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:481
int debugLevelForError(int const xerrno) const
Definition: tunnel.cc:378
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:452
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:284
Ip::Address src_addr
void copyServerBytes()
Definition: tunnel.cc:863
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:913
bool denied() const
Definition: Acl.h:147
ERCB * callback
Definition: errorpage.h:179
#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:735
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:1266
#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:245
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:180
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:226
void errorSend(const Comm::ConnectionPointer &conn, ErrorState *err)
Definition: errorpage.cc:724
bool auth_no_keytab
Definition: CachePeer.h:119
static Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request)
Definition: tunnel.cc:1210
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:1153
void noteConnectFailure(const Comm::ConnectionPointer &conn)
reacts to a failure to establish the given TCP connection
Definition: tunnel.cc:1008
static const char *const conn_established
Definition: tunnel.cc:243
void startConnecting()
Definition: tunnel.cc:1301
void GetMarkingsToServer(HttpRequest *request, Comm::Connection &conn)
Sets initial TOS value and Netfilter for the future outgoing connection.
Definition: FwdState.cc:1416
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:881
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:705
void const char HLPCB void * data
Definition: stub_helper.cc:16
LogTags logType
the processing tags associated with this request transaction.
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:248
void peerConnectFailed(CachePeer *p)
Definition: neighbors.cc:1292
#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:958
Ip::Address client_addr
Definition: HttpRequest.h:141
virtual void noteDestinationsEnd(ErrorState *selectionError) override
Definition: tunnel.cc:1245
mb_size_t size
Definition: MemBuf.h:135
static CTCB tunnelTimeout
Definition: tunnel.cc:249
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:166
bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
Definition: tunnel.cc:599
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:310
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:935
void copyRead(Connection &from, IOCB *completion)
Definition: tunnel.cc:819
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:975
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:838
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:247
void connectToPeer()
continue to set up connection to a peer, going async for SSL peers
Definition: tunnel.cc:1135
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:250
int ignoreErrno(int ierrno)
Definition: comm.cc:1477
static EVH tunnelDelayedServerRead
Definition: tunnel.cc:251
void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno)
Definition: tunnel.cc:662
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:1355
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:431
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:642
int bytesWanted(int lower=0, int upper=INT_MAX) const
Definition: tunnel.cc:356
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:112
virtual ~TunnelStateData()
Definition: tunnel.cc:337
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:1277
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:405
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:555
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:1089
HttpRequest *const request
Definition: Debug.h:184
int xerrno
Definition: errorpage.h:172
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:493
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:31
#define DBG_DATA
Definition: Debug.h:48
void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno)
Definition: tunnel.cc:574
const char * getHost() const
Definition: tunnel.cc:96
static ERCB tunnelErrorComplete
Definition: tunnel.cc:246
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:728
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:1346
bool noConnections() const
Definition: tunnel.cc:1339
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
void Controller::create() STUB void Controller Controller nil
#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:715
char * peer_domain
Definition: HttpRequest.h:165
time_t read
Definition: SquidConfig.h:106
void bytesIn(int const &)
Definition: tunnel.cc:367
#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:652
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