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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors