2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 26 Secure Sockets Layer Proxy */
12 #include "acl/FilledChecklist.h"
13 #include "base/CbcPointer.h"
14 #include "CachePeer.h"
16 #include "client_side.h"
17 #include "client_side_request.h"
18 #include "clients/HttpTunneler.h"
20 #include "comm/Connection.h"
21 #include "comm/ConnOpener.h"
22 #include "comm/Read.h"
23 #include "comm/Write.h"
24 #include "errorpage.h"
29 #include "HappyConnOpener.h"
31 #include "http/Stream.h"
32 #include "HttpRequest.h"
33 #include "icmp/net_db.h"
34 #include "ip/QosConfig.h"
37 #include "neighbors.h"
38 #include "PeerSelectState.h"
39 #include "ResolvedPeers.h"
40 #include "sbuf/SBuf.h"
41 #include "security/BlindPeerConnector.h"
42 #include "SquidConfig.h"
43 #include "SquidTime.h"
44 #include "StatCounters.h"
47 #include "ssl/ServerBump.h"
58 * TunnelStateData is the state engine performing the tasks for
59 * setup of a TCP tunnel from an existing open client FD to a server
60 * then shuffling binary data between the resulting FD pair.
63 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
64 * of pre-formatted data. Then we can use that as the client side of the tunnel
65 * instead of re-implementing it here and occasionally getting the ConnStateData
66 * read/write state wrong.
68 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
70 class TunnelStateData
: public PeerSelectionInitiator
72 CBDATA_CHILD(TunnelStateData
);
75 TunnelStateData(ClientHttpRequest
*);
76 virtual ~TunnelStateData();
77 TunnelStateData(const TunnelStateData
&); // do not implement
78 TunnelStateData
&operator =(const TunnelStateData
&); // do not implement
81 static void ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
82 static void ReadServer(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
83 static void WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
84 static void WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
86 bool noConnections() const;
88 CbcPointer
<ClientHttpRequest
> http
;
89 HttpRequest::Pointer request
;
90 AccessLogEntryPointer al
;
92 const char * getHost() const {
93 return (server
.conn
!= NULL
&& server
.conn
->getPeer() ? server
.conn
->getPeer()->host
: request
->url
.host());
96 /// Whether the client sent a CONNECT request to us.
97 bool clientExpectsConnectResponse() const {
98 // If we are forcing a tunnel after receiving a client CONNECT, then we
99 // have already responded to that CONNECT before tunnel.cc started.
100 if (request
&& request
->flags
.forceTunnel
)
103 // We are bumping and we had already send "OK CONNECTED"
104 if (http
.valid() && http
->getConn() && http
->getConn()->serverBump() && http
->getConn()->serverBump()->at(XactionStep::tlsBump2
, XactionStep::tlsBump3
))
107 return !(request
!= NULL
&&
108 (request
->flags
.interceptTproxy
|| request
->flags
.intercepted
));
111 /// starts connecting to the next hop, either for the first time or while
112 /// recovering from the previous connect failure
113 void startConnecting();
115 /// called when negotiations with the peer have been successfully completed
116 void notePeerReadyToShovel();
122 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF
)), size_ptr(NULL
), delayedLoops(0),
123 readPending(NULL
), readPendingFunc(NULL
) {}
127 int bytesWanted(int lower
=0, int upper
= INT_MAX
) const;
128 void bytesIn(int const &);
131 void setDelayId(DelayId
const &);
134 void error(int const xerrno
);
135 int debugLevelForError(int const xerrno
) const;
137 void dataSent (size_t amount
);
138 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
139 void write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
);
142 AsyncCall::Pointer writer
; ///< pending Comm::Write callback
143 uint64_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
145 Comm::ConnectionPointer conn
; ///< The currently connected connection.
146 uint8_t delayedLoops
; ///< how many times a read on this connection has been postponed.
148 // XXX: make these an AsyncCall when event API can handle them
149 TunnelStateData
*readPending
;
150 EVH
*readPendingFunc
;
159 Connection client
, server
;
160 int *status_ptr
; ///< pointer for logging HTTP status
161 LogTags
*logTag_ptr
; ///< pointer for logging Squid processing code
163 SBuf preReadClientData
;
164 SBuf preReadServerData
;
165 time_t startTime
; ///< object creation time, before any peer selection/connection attempts
166 /// Whether we are waiting for the CONNECT request/response exchange with the peer.
167 bool waitingForConnectExchange
;
168 HappyConnOpenerPointer connOpener
; ///< current connection opening job
169 ResolvedPeersPointer destinations
; ///< paths for forwarding the request
170 bool destinationsFound
; ///< At least one candidate path found
172 // AsyncCalls which we set and may need cancelling.
174 AsyncCall::Pointer connector
; ///< a call linking us to the ConnOpener producing serverConn.
177 void copyRead(Connection
&from
, IOCB
*completion
);
179 /// continue to set up connection to a peer, going async for SSL peers
180 void connectToPeer();
182 /* PeerSelectionInitiator API */
183 virtual void noteDestination(Comm::ConnectionPointer conn
) override
;
184 virtual void noteDestinationsEnd(ErrorState
*selectionError
) override
;
186 void syncHierNote(const Comm::ConnectionPointer
&server
, const char *origin
);
188 /// called when a connection has been successfully established or
189 /// when all candidate destinations have been tried and all have failed
190 void noteConnection(HappyConnOpenerAnswer
&);
192 /// whether we are waiting for HappyConnOpener
193 /// same as calls.connector but may differ from connOpener.valid()
194 bool opening() const { return connOpener
.set(); }
196 void cancelOpening(const char *reason
);
198 /// Start using an established connection
199 void connectDone(const Comm::ConnectionPointer
&conn
, const char *origin
, const bool reused
);
201 void notifyConnOpener();
203 void saveError(ErrorState
*finalError
);
204 void sendError(ErrorState
*finalError
, const char *reason
);
207 /// Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
208 class MyAnswerDialer
: public CallDialer
, public Security::PeerConnector::CbDialer
211 typedef void (TunnelStateData::*Method
)(Security::EncryptorAnswer
&);
213 MyAnswerDialer(Method method
, TunnelStateData
*tunnel
):
214 method_(method
), tunnel_(tunnel
), answer_() {}
217 virtual bool canDial(AsyncCall
&call
) { return tunnel_
.valid(); }
218 void dial(AsyncCall
&call
) { ((&(*tunnel_
))->*method_
)(answer_
); }
219 virtual void print(std::ostream
&os
) const {
220 os
<< '(' << tunnel_
.get() << ", " << answer_
<< ')';
223 /* Security::PeerConnector::CbDialer API */
224 virtual Security::EncryptorAnswer
&answer() { return answer_
; }
228 CbcPointer
<TunnelStateData
> tunnel_
;
229 Security::EncryptorAnswer answer_
;
234 /// callback handler after connection setup (including any encryption)
235 void connectedToPeer(Security::EncryptorAnswer
&answer
);
237 /// details of the "last tunneling attempt" failure (if it failed)
238 ErrorState
*savedError
= nullptr;
240 /// resumes operations after the (possibly failed) HTTP CONNECT exchange
241 void tunnelEstablishmentDone(Http::TunnelerAnswer
&answer
);
244 bool keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
);
245 void copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*);
246 void readServer(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
247 void readClient(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
248 void writeClientDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
249 void writeServerDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
251 void copyClientBytes();
252 void copyServerBytes();
255 static ERCB tunnelErrorComplete
;
256 static CLCB tunnelServerClosed
;
257 static CLCB tunnelClientClosed
;
258 static CTCB tunnelTimeout
;
259 static EVH tunnelDelayedClientRead
;
260 static EVH tunnelDelayedServerRead
;
263 tunnelServerClosed(const CommCloseCbParams
¶ms
)
265 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
266 debugs(26, 3, HERE
<< tunnelState
->server
.conn
);
267 tunnelState
->server
.conn
= NULL
;
268 tunnelState
->server
.writer
= NULL
;
270 if (tunnelState
->request
!= NULL
)
271 tunnelState
->request
->hier
.stopPeerClock(false);
273 if (tunnelState
->noConnections()) {
274 // ConnStateData pipeline should contain the CONNECT we are performing
275 // but it may be invalid already (bug 4392)
276 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn()) {
277 auto ctx
= tunnelState
->http
->getConn()->pipeline
.front();
285 if (!tunnelState
->client
.writer
) {
286 tunnelState
->client
.conn
->close();
292 tunnelClientClosed(const CommCloseCbParams
¶ms
)
294 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
295 debugs(26, 3, HERE
<< tunnelState
->client
.conn
);
296 tunnelState
->client
.conn
= NULL
;
297 tunnelState
->client
.writer
= NULL
;
299 if (tunnelState
->noConnections()) {
300 // ConnStateData pipeline should contain the CONNECT we are performing
301 // but it may be invalid already (bug 4392)
302 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn()) {
303 auto ctx
= tunnelState
->http
->getConn()->pipeline
.front();
311 if (!tunnelState
->server
.writer
) {
312 tunnelState
->server
.conn
->close();
317 TunnelStateData::TunnelStateData(ClientHttpRequest
*clientRequest
) :
318 startTime(squid_curtime
),
319 waitingForConnectExchange(false),
320 destinations(new ResolvedPeers()),
321 destinationsFound(false)
323 debugs(26, 3, "TunnelStateData constructed this=" << this);
324 client
.readPendingFunc
= &tunnelDelayedClientRead
;
325 server
.readPendingFunc
= &tunnelDelayedServerRead
;
327 assert(clientRequest
);
328 url
= xstrdup(clientRequest
->uri
);
329 request
= clientRequest
->request
;
331 server
.size_ptr
= &clientRequest
->out
.size
;
332 client
.size_ptr
= &clientRequest
->al
->http
.clientRequestSz
.payloadData
;
333 status_ptr
= &clientRequest
->al
->http
.code
;
334 logTag_ptr
= &clientRequest
->logType
;
335 al
= clientRequest
->al
;
336 http
= clientRequest
;
338 client
.conn
= clientRequest
->getConn()->clientConnection
;
339 comm_add_close_handler(client
.conn
->fd
, tunnelClientClosed
, this);
341 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
342 CommTimeoutCbPtrFun(tunnelTimeout
, this));
343 commSetConnTimeout(client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
346 TunnelStateData::~TunnelStateData()
348 debugs(26, 3, "TunnelStateData destructed this=" << this);
349 assert(noConnections());
352 cancelOpening("~TunnelStateData");
356 TunnelStateData::Connection::~Connection()
359 eventDelete(readPendingFunc
, readPending
);
365 TunnelStateData::Connection::bytesWanted(int lowerbound
, int upperbound
) const
368 return delayId
.bytesWanted(lowerbound
, upperbound
);
376 TunnelStateData::Connection::bytesIn(int const &count
)
378 debugs(26, 3, HERE
<< "len=" << len
<< " + count=" << count
);
380 delayId
.bytesIn(count
);
386 /// update "hierarchy" annotations with a new (possibly failed) destination
387 /// \param origin the name of the origin server we were trying to reach
389 TunnelStateData::syncHierNote(const Comm::ConnectionPointer
&conn
, const char *origin
)
391 request
->hier
.resetPeerNotes(conn
, origin
);
393 al
->hier
.resetPeerNotes(conn
, origin
);
397 TunnelStateData::Connection::debugLevelForError(int const xerrno
) const
401 if (xerrno
== ECONNRESET
)
406 if (ignoreErrno(xerrno
))
412 /* Read from server side and queue it for writing to the client */
414 TunnelStateData::ReadServer(const Comm::ConnectionPointer
&c
, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
416 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
417 assert(cbdataReferenceValid(tunnelState
));
418 debugs(26, 3, HERE
<< c
);
420 tunnelState
->readServer(buf
, len
, errcode
, xerrno
);
424 TunnelStateData::readServer(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
426 debugs(26, 3, HERE
<< server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
427 server
.delayedLoops
=0;
430 * Bail out early on Comm::ERR_CLOSING
431 * - close handlers will tidy up for us
434 if (errcode
== Comm::ERR_CLOSING
)
439 statCounter
.server
.all
.kbytes_in
+= len
;
440 statCounter
.server
.other
.kbytes_in
+= len
;
441 request
->hier
.notePeerRead();
444 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
445 copy(len
, server
, client
, WriteClientDone
);
449 TunnelStateData::Connection::error(int const xerrno
)
451 debugs(50, debugLevelForError(xerrno
), HERE
<< conn
<< ": read/write failure: " << xstrerr(xerrno
));
453 if (!ignoreErrno(xerrno
))
457 /* Read from client side and queue it for writing to the server */
459 TunnelStateData::ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
461 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
462 assert (cbdataReferenceValid (tunnelState
));
464 tunnelState
->readClient(buf
, len
, errcode
, xerrno
);
468 TunnelStateData::readClient(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
470 debugs(26, 3, HERE
<< client
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
471 client
.delayedLoops
=0;
474 * Bail out early on Comm::ERR_CLOSING
475 * - close handlers will tidy up for us
478 if (errcode
== Comm::ERR_CLOSING
)
483 statCounter
.client_http
.kbytes_in
+= len
;
486 if (keepGoingAfterRead(len
, errcode
, xerrno
, client
, server
))
487 copy(len
, client
, server
, WriteServerDone
);
490 /// Updates state after reading from client or server.
491 /// Returns whether the caller should use the data just read.
493 TunnelStateData::keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
)
495 debugs(26, 3, HERE
<< "from={" << from
.conn
<< "}, to={" << to
.conn
<< "}");
497 /* I think this is to prevent free-while-in-a-callback behaviour
499 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
501 const CbcPointer
<TunnelStateData
> safetyLock(this);
503 /* Bump the source connection read timeout on any activity */
504 if (Comm::IsConnOpen(from
.conn
)) {
505 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
506 CommTimeoutCbPtrFun(tunnelTimeout
, this));
507 commSetConnTimeout(from
.conn
, Config
.Timeout
.read
, timeoutCall
);
510 /* Bump the dest connection read timeout on any activity */
511 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
512 if (Comm::IsConnOpen(to
.conn
)) {
513 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
514 CommTimeoutCbPtrFun(tunnelTimeout
, this));
515 commSetConnTimeout(to
.conn
, Config
.Timeout
.read
, timeoutCall
);
520 else if (len
== 0 || !Comm::IsConnOpen(to
.conn
)) {
521 debugs(26, 3, HERE
<< "Nothing to write or client gone. Terminate the tunnel.");
524 /* Only close the remote end if we've finished queueing data to it */
525 if (from
.len
== 0 && Comm::IsConnOpen(to
.conn
) ) {
528 } else if (cbdataReferenceValid(this)) {
536 TunnelStateData::copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*completion
)
538 debugs(26, 3, HERE
<< "Schedule Write");
539 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelBlindCopyWriteHandler",
540 CommIoCbPtrFun(completion
, this));
541 to
.write(from
.buf
, len
, call
, NULL
);
544 /* Writes data from the client buffer to the server side */
546 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
548 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
549 assert (cbdataReferenceValid (tunnelState
));
550 tunnelState
->server
.writer
= NULL
;
552 tunnelState
->writeServerDone(buf
, len
, flag
, xerrno
);
556 TunnelStateData::writeServerDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
558 debugs(26, 3, HERE
<< server
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
560 if (flag
== Comm::ERR_CLOSING
)
563 request
->hier
.notePeerWrite();
566 if (flag
!= Comm::OK
) {
567 debugs(26, 4, "to-server write failed: " << xerrno
);
568 server
.error(xerrno
); // may call comm_close
574 debugs(26, 4, HERE
<< "No read input. Closing server connection.");
575 server
.conn
->close();
580 statCounter
.server
.all
.kbytes_out
+= len
;
581 statCounter
.server
.other
.kbytes_out
+= len
;
582 client
.dataSent(len
);
584 /* If the other end has closed, so should we */
585 if (!Comm::IsConnOpen(client
.conn
)) {
586 debugs(26, 4, HERE
<< "Client gone away. Shutting down server connection.");
587 server
.conn
->close();
591 const CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
593 if (cbdataReferenceValid(this))
597 /* Writes data from the server buffer to the client side */
599 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
601 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
602 assert (cbdataReferenceValid (tunnelState
));
603 tunnelState
->client
.writer
= NULL
;
605 tunnelState
->writeClientDone(buf
, len
, flag
, xerrno
);
609 TunnelStateData::Connection::dataSent(size_t amount
)
611 debugs(26, 3, HERE
<< "len=" << len
<< " - amount=" << amount
);
612 assert(amount
== (size_t)len
);
614 /* increment total object size */
622 TunnelStateData::Connection::write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
625 Comm::Write(conn
, b
, size
, callback
, free_func
);
629 TunnelStateData::writeClientDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
631 debugs(26, 3, HERE
<< client
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
633 if (flag
== Comm::ERR_CLOSING
)
637 if (flag
!= Comm::OK
) {
638 debugs(26, 4, "from-client read failed: " << xerrno
);
639 client
.error(xerrno
); // may call comm_close
645 debugs(26, 4, HERE
<< "Closing client connection due to 0 byte read.");
646 client
.conn
->close();
651 statCounter
.client_http
.kbytes_out
+= len
;
652 server
.dataSent(len
);
654 /* If the other end has closed, so should we */
655 if (!Comm::IsConnOpen(server
.conn
)) {
656 debugs(26, 4, HERE
<< "Server has gone away. Terminating client connection.");
657 client
.conn
->close();
661 CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
663 if (cbdataReferenceValid(this))
668 tunnelTimeout(const CommTimeoutCbParams
&io
)
670 TunnelStateData
*tunnelState
= static_cast<TunnelStateData
*>(io
.data
);
671 debugs(26, 3, HERE
<< io
.conn
);
672 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
673 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
675 tunnelState
->client
.closeIfOpen();
676 tunnelState
->server
.closeIfOpen();
680 TunnelStateData::Connection::closeIfOpen()
682 if (Comm::IsConnOpen(conn
))
687 tunnelDelayedClientRead(void *data
)
692 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
693 tunnel
->client
.readPending
= NULL
;
694 static uint64_t counter
=0;
695 debugs(26, 7, "Client read(2) delayed " << ++counter
<< " times");
696 tunnel
->copyRead(tunnel
->client
, TunnelStateData::ReadClient
);
700 tunnelDelayedServerRead(void *data
)
705 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
706 tunnel
->server
.readPending
= NULL
;
707 static uint64_t counter
=0;
708 debugs(26, 7, "Server read(2) delayed " << ++counter
<< " times");
709 tunnel
->copyRead(tunnel
->server
, TunnelStateData::ReadServer
);
713 TunnelStateData::copyRead(Connection
&from
, IOCB
*completion
)
715 assert(from
.len
== 0);
716 // If only the minimum permitted read size is going to be attempted
717 // then we schedule an event to try again in a few I/O cycles.
718 // Allow at least 1 byte to be read every (0.3*10) seconds.
719 int bw
= from
.bytesWanted(1, SQUID_TCP_SO_RCVBUF
);
720 if (bw
== 1 && ++from
.delayedLoops
< 10) {
721 from
.readPending
= this;
722 eventAdd("tunnelDelayedServerRead", from
.readPendingFunc
, from
.readPending
, 0.3, true);
726 AsyncCall::Pointer call
= commCbCall(5,4, "TunnelBlindCopyReadHandler",
727 CommIoCbPtrFun(completion
, this));
728 comm_read(from
.conn
, from
.buf
, bw
, call
);
732 TunnelStateData::copyClientBytes()
734 if (preReadClientData
.length()) {
735 size_t copyBytes
= preReadClientData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadClientData
.length();
736 memcpy(client
.buf
, preReadClientData
.rawContent(), copyBytes
);
737 preReadClientData
.consume(copyBytes
);
738 client
.bytesIn(copyBytes
);
739 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, client
, server
))
740 copy(copyBytes
, client
, server
, TunnelStateData::WriteServerDone
);
742 copyRead(client
, ReadClient
);
746 TunnelStateData::copyServerBytes()
748 if (preReadServerData
.length()) {
749 size_t copyBytes
= preReadServerData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadServerData
.length();
750 memcpy(server
.buf
, preReadServerData
.rawContent(), copyBytes
);
751 preReadServerData
.consume(copyBytes
);
752 server
.bytesIn(copyBytes
);
753 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, server
, client
))
754 copy(copyBytes
, server
, client
, TunnelStateData::WriteClientDone
);
756 copyRead(server
, ReadServer
);
760 * Set the HTTP status for this request and sets the read handlers for client
761 * and server side connections.
764 tunnelStartShoveling(TunnelStateData
*tunnelState
)
766 assert(!tunnelState
->waitingForConnectExchange
);
767 *tunnelState
->status_ptr
= Http::scOkay
;
768 if (tunnelState
->logTag_ptr
)
769 tunnelState
->logTag_ptr
->update(LOG_TCP_TUNNEL
);
770 if (cbdataReferenceValid(tunnelState
)) {
772 // Shovel any payload already pushed into reply buffer by the server response
773 if (!tunnelState
->server
.len
)
774 tunnelState
->copyServerBytes();
776 debugs(26, DBG_DATA
, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState
->server
.buf
, tunnelState
->server
.len
) << "\n----------");
777 tunnelState
->copy(tunnelState
->server
.len
, tunnelState
->server
, tunnelState
->client
, TunnelStateData::WriteClientDone
);
780 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn() && !tunnelState
->http
->getConn()->inBuf
.isEmpty()) {
781 SBuf
* const in
= &tunnelState
->http
->getConn()->inBuf
;
782 debugs(26, DBG_DATA
, "Tunnel client PUSH Payload: \n" << *in
<< "\n----------");
783 tunnelState
->preReadClientData
.append(*in
);
784 in
->consume(); // ConnStateData buffer accounting after the shuffle.
786 tunnelState
->copyClientBytes();
791 * All the pieces we need to write to client and/or server connection
793 * Call the tunnelStartShoveling to start the blind pump.
796 tunnelConnectedWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t len
, Comm::Flag flag
, int, void *data
)
798 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
799 debugs(26, 3, HERE
<< conn
<< ", flag=" << flag
);
800 tunnelState
->client
.writer
= NULL
;
802 if (flag
!= Comm::OK
) {
803 *tunnelState
->status_ptr
= Http::scInternalServerError
;
804 tunnelErrorComplete(conn
->fd
, data
, 0);
808 if (auto http
= tunnelState
->http
.get()) {
809 http
->out
.headers_sz
+= len
;
810 http
->out
.size
+= len
;
813 tunnelStartShoveling(tunnelState
);
817 TunnelStateData::tunnelEstablishmentDone(Http::TunnelerAnswer
&answer
)
822 logTag_ptr
->update(LOG_TCP_TUNNEL
);
824 if (answer
.peerResponseStatus
!= Http::scNone
)
825 *status_ptr
= answer
.peerResponseStatus
;
827 waitingForConnectExchange
= false;
829 if (answer
.positive()) {
830 // copy any post-200 OK bytes to our buffer
831 preReadServerData
= answer
.leftovers
;
832 notePeerReadyToShovel();
836 // TODO: Reuse to-peer connections after a CONNECT error response.
838 // TODO: We can and, hence, should close now, but tunnelServerClosed()
839 // cannot yet tell whether ErrorState is still writing an error response.
840 // server.closeIfOpen();
842 if (!clientExpectsConnectResponse()) {
843 // closing the non-HTTP client connection is the best we can do
844 debugs(50, 3, server
.conn
<< " closing on CONNECT-to-peer error");
845 server
.closeIfOpen();
849 ErrorState
*error
= answer
.squidError
.get();
851 answer
.squidError
.clear(); // preserve error for errorSendComplete()
852 sendError(error
, "tunneler returns error");
856 TunnelStateData::notePeerReadyToShovel()
858 if (!clientExpectsConnectResponse())
859 tunnelStartShoveling(this); // ssl-bumped connection, be quiet
861 *status_ptr
= Http::scOkay
;
862 AsyncCall::Pointer call
= commCbCall(5,5, "tunnelConnectedWriteDone",
863 CommIoCbPtrFun(tunnelConnectedWriteDone
, this));
864 al
->reply
= HttpReply::MakeConnectionEstablished();
865 const auto mb
= al
->reply
->pack();
866 client
.write(mb
->content(), mb
->contentSize(), call
, mb
->freeFunc());
872 tunnelErrorComplete(int fd
/*const Comm::ConnectionPointer &*/, void *data
, size_t)
874 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
875 debugs(26, 3, HERE
<< "FD " << fd
);
876 assert(tunnelState
!= NULL
);
877 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
878 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
880 if (Comm::IsConnOpen(tunnelState
->client
.conn
))
881 tunnelState
->client
.conn
->close();
883 if (Comm::IsConnOpen(tunnelState
->server
.conn
))
884 tunnelState
->server
.conn
->close();
888 TunnelStateData::noteConnection(HappyConnOpener::Answer
&answer
)
890 calls
.connector
= nullptr;
893 if (const auto error
= answer
.error
.get()) {
894 syncHierNote(answer
.conn
, request
->url
.host());
896 answer
.error
.clear(); // savedError has it now
897 sendError(savedError
, "tried all destinations");
901 connectDone(answer
.conn
, request
->url
.host(), answer
.reused
);
905 TunnelStateData::connectDone(const Comm::ConnectionPointer
&conn
, const char *origin
, const bool reused
)
907 Must(Comm::IsConnOpen(conn
));
911 ResetMarkingsToServer(request
.getRaw(), *conn
);
912 // else Comm::ConnOpener already applied proper/current markings
914 syncHierNote(server
.conn
, request
->url
.host());
916 request
->hier
.resetPeerNotes(conn
, origin
);
918 al
->hier
.resetPeerNotes(conn
, origin
);
921 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
922 if (conn
->getPeer() && conn
->getPeer()->options
.no_delay
)
923 server
.setDelayId(DelayId());
926 netdbPingSite(request
->url
.host());
928 request
->peer_host
= conn
->getPeer() ? conn
->getPeer()->host
: nullptr;
929 comm_add_close_handler(conn
->fd
, tunnelServerClosed
, this);
931 bool toOrigin
= false; // same semantics as StateFlags::toOrigin
932 if (const auto * const peer
= conn
->getPeer()) {
933 request
->prepForPeering(*peer
);
934 toOrigin
= peer
->options
.originserver
;
936 request
->prepForDirect();
943 notePeerReadyToShovel();
946 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
947 CommTimeoutCbPtrFun(tunnelTimeout
, this));
948 commSetConnTimeout(conn
, Config
.Timeout
.read
, timeoutCall
);
952 tunnelStart(ClientHttpRequest
* http
)
955 /* Create state structure. */
956 TunnelStateData
*tunnelState
= NULL
;
957 ErrorState
*err
= NULL
;
958 HttpRequest
*request
= http
->request
;
959 char *url
= http
->uri
;
962 * client_addr.isNoAddr() indicates this is an "internal" request
963 * from peer_digest.c, asn.c, netdb.c, etc and should always
964 * be allowed. yuck, I know.
967 if (Config
.accessList
.miss
&& !request
->client_addr
.isNoAddr()) {
969 * Check if this host is allowed to fetch MISSES from us (miss_access)
970 * default is to allow.
972 ACLFilledChecklist
ch(Config
.accessList
.miss
, request
, NULL
);
974 ch
.src_addr
= request
->client_addr
;
975 ch
.my_addr
= request
->my_addr
;
976 ch
.syncAle(request
, http
->log_uri
);
977 if (ch
.fastCheck().denied()) {
978 debugs(26, 4, HERE
<< "MISS access forbidden.");
979 err
= new ErrorState(ERR_FORWARDING_DENIED
, Http::scForbidden
, request
, http
->al
);
980 http
->al
->http
.code
= Http::scForbidden
;
981 errorSend(http
->getConn()->clientConnection
, err
);
986 debugs(26, 3, request
->method
<< ' ' << url
<< ' ' << request
->http_ver
);
987 ++statCounter
.server
.all
.requests
;
988 ++statCounter
.server
.other
.requests
;
990 tunnelState
= new TunnelStateData(http
);
992 tunnelState
->server
.setDelayId(DelayId::DelayClient(http
));
994 tunnelState
->startSelectingDestinations(request
, http
->al
, nullptr);
998 TunnelStateData::connectToPeer()
1000 if (CachePeer
*p
= server
.conn
->getPeer()) {
1001 if (p
->secure
.encryptTransport
) {
1002 AsyncCall::Pointer callback
= asyncCall(5,4,
1003 "TunnelStateData::ConnectedToPeer",
1004 MyAnswerDialer(&TunnelStateData::connectedToPeer
, this));
1005 auto *connector
= new Security::BlindPeerConnector(request
, server
.conn
, callback
, al
);
1006 AsyncJob::Start(connector
); // will call our callback
1011 Security::EncryptorAnswer nil
;
1012 connectedToPeer(nil
);
1016 TunnelStateData::connectedToPeer(Security::EncryptorAnswer
&answer
)
1018 if (ErrorState
*error
= answer
.error
.get()) {
1019 answer
.error
.clear(); // sendError() will own the error
1020 sendError(error
, "TLS peer connection error");
1024 assert(!waitingForConnectExchange
);
1026 AsyncCall::Pointer callback
= asyncCall(5,4,
1027 "TunnelStateData::tunnelEstablishmentDone",
1028 Http::Tunneler::CbDialer
<TunnelStateData
>(&TunnelStateData::tunnelEstablishmentDone
, this));
1029 const auto tunneler
= new Http::Tunneler(server
.conn
, request
, callback
, Config
.Timeout
.lifetime
, al
);
1031 tunneler
->setDelayId(server
.delayId
);
1033 AsyncJob::Start(tunneler
);
1034 waitingForConnectExchange
= true;
1035 // and wait for the tunnelEstablishmentDone() call
1039 TunnelStateData::noteDestination(Comm::ConnectionPointer path
)
1041 destinationsFound
= true;
1043 if (!path
) { // decided to use a pinned connection
1044 // We can call usePinned() without fear of clashing with an earlier
1045 // forwarding attempt because PINNED must be the first destination.
1046 assert(destinations
->empty());
1051 destinations
->addPath(path
);
1053 if (Comm::IsConnOpen(server
.conn
)) {
1054 // We are already using a previously opened connection but also
1055 // receiving destinations in case we need to re-forward.
1062 return; // and continue to wait for tunnelConnectDone() callback
1069 TunnelStateData::noteDestinationsEnd(ErrorState
*selectionError
)
1071 PeerSelectionInitiator::subscribed
= false;
1072 destinations
->destinationsFinalized
= true;
1073 if (!destinationsFound
) {
1076 return sendError(selectionError
, "path selection has failed");
1079 return sendError(savedError
, "all found paths have failed");
1081 return sendError(new ErrorState(ERR_CANNOT_FORWARD
, Http::scInternalServerError
, request
.getRaw(), al
),
1082 "path selection found no paths");
1084 // else continue to use one of the previously noted destinations;
1085 // if all of them fail, tunneling as whole will fail
1086 Must(!selectionError
); // finding at least one path means selection succeeded
1088 if (Comm::IsConnOpen(server
.conn
)) {
1089 // We are already using a previously opened connection but also
1090 // receiving destinations in case we need to re-forward.
1095 Must(opening()); // or we would be stuck with nothing to do or wait for
1099 /// remembers an error to be used if there will be no more connection attempts
1101 TunnelStateData::saveError(ErrorState
*error
)
1103 debugs(26, 4, savedError
<< " ? " << error
);
1105 delete savedError
; // may be nil
1109 /// Starts sending the given error message to the client, leading to the
1110 /// eventual transaction termination. Call with savedError to send savedError.
1112 TunnelStateData::sendError(ErrorState
*finalError
, const char *reason
)
1114 debugs(26, 3, "aborting transaction for " << reason
);
1117 request
->hier
.stopPeerClock(false);
1120 cancelOpening(reason
);
1124 // get rid of any cached error unless that is what the caller is sending
1125 if (savedError
!= finalError
)
1126 delete savedError
; // may be nil
1127 savedError
= nullptr;
1129 // we cannot try other destinations after responding with an error
1130 PeerSelectionInitiator::subscribed
= false; // may already be false
1132 *status_ptr
= finalError
->httpStatus
;
1133 finalError
->callback
= tunnelErrorComplete
;
1134 finalError
->callback_data
= this;
1135 errorSend(client
.conn
, finalError
);
1138 /// Notify connOpener that we no longer need connections. We do not have to do
1139 /// this -- connOpener would eventually notice on its own, but notifying reduces
1140 /// waste and speeds up spare connection opening for other transactions (that
1141 /// could otherwise wait for this transaction to use its spare allowance).
1143 TunnelStateData::cancelOpening(const char *reason
)
1145 assert(calls
.connector
);
1146 calls
.connector
->cancel(reason
);
1147 calls
.connector
= nullptr;
1153 TunnelStateData::startConnecting()
1156 request
->hier
.startPeerClock();
1158 assert(!destinations
->empty());
1160 calls
.connector
= asyncCall(17, 5, "TunnelStateData::noteConnection", HappyConnOpener::CbDialer
<TunnelStateData
>(&TunnelStateData::noteConnection
, this));
1161 const auto cs
= new HappyConnOpener(destinations
, calls
.connector
, request
, startTime
, 0, al
);
1162 cs
->setHost(request
->url
.host());
1163 cs
->setRetriable(false);
1164 cs
->allowPersistent(false);
1165 destinations
->notificationPending
= true; // start() is async
1167 AsyncJob::Start(cs
);
1170 /// send request on an existing connection dedicated to the requesting client
1172 TunnelStateData::usePinned()
1175 const auto connManager
= request
->pinnedConnection();
1177 const auto serverConn
= ConnStateData::BorrowPinnedConnection(request
.getRaw(), al
);
1178 debugs(26, 7, "pinned peer connection: " << serverConn
);
1180 // Set HttpRequest pinned related flags for consistency even if
1181 // they are not really used by tunnel.cc code.
1182 request
->flags
.pinned
= true;
1183 if (connManager
->pinnedAuth())
1184 request
->flags
.auth
= true;
1186 // the server may close the pinned connection before this request
1187 const auto reused
= true;
1188 connectDone(serverConn
, connManager
->pinning
.host
, reused
);
1189 } catch (ErrorState
* const error
) {
1190 syncHierNote(nullptr, connManager
? connManager
->pinning
.host
: request
->url
.host());
1191 // a PINNED path failure is fatal; do not wait for more paths
1192 sendError(error
, "pinned path failure");
1198 CBDATA_CLASS_INIT(TunnelStateData
);
1201 TunnelStateData::noConnections() const
1203 return !Comm::IsConnOpen(server
.conn
) && !Comm::IsConnOpen(client
.conn
);
1208 TunnelStateData::Connection::setDelayId(DelayId
const &newDelay
)
1215 /// makes sure connOpener knows that destinations have changed
1217 TunnelStateData::notifyConnOpener()
1219 if (destinations
->notificationPending
) {
1220 debugs(17, 7, "reusing pending notification");
1222 destinations
->notificationPending
= true;
1223 CallJobHere(17, 5, connOpener
, HappyConnOpener
, noteCandidatesChange
);
1229 switchToTunnel(HttpRequest
*request
, Comm::ConnectionPointer
&clientConn
, Comm::ConnectionPointer
&srvConn
)
1231 debugs(26,5, "Revert to tunnel FD " << clientConn
->fd
<< " with FD " << srvConn
->fd
);
1233 /* Create state structure. */
1234 ++statCounter
.server
.all
.requests
;
1235 ++statCounter
.server
.other
.requests
;
1237 auto conn
= request
->clientConnectionManager
.get();
1239 Http::StreamPointer context
= conn
->pipeline
.front();
1240 Must(context
&& context
->http
);
1242 debugs(26, 3, request
->method
<< " " << context
->http
->uri
<< " " << request
->http_ver
);
1244 TunnelStateData
*tunnelState
= new TunnelStateData(context
->http
);
1246 // tunnelStartShoveling() drains any buffered from-client data (inBuf)
1247 fd_table
[clientConn
->fd
].useDefaultIo();
1249 request
->hier
.resetPeerNotes(srvConn
, tunnelState
->getHost());
1251 tunnelState
->server
.conn
= srvConn
;
1254 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1255 if (!srvConn
->getPeer() || !srvConn
->getPeer()->options
.no_delay
)
1256 tunnelState
->server
.setDelayId(DelayId::DelayClient(context
->http
));
1259 request
->peer_host
= srvConn
->getPeer() ? srvConn
->getPeer()->host
: nullptr;
1260 comm_add_close_handler(srvConn
->fd
, tunnelServerClosed
, tunnelState
);
1262 debugs(26, 4, "determine post-connect handling pathway.");
1263 if (const auto peer
= srvConn
->getPeer())
1264 request
->prepForPeering(*peer
);
1266 request
->prepForDirect();
1268 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1269 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1270 commSetConnTimeout(srvConn
, Config
.Timeout
.read
, timeoutCall
);
1272 // we drain any already buffered from-server data below (rBufData)
1273 fd_table
[srvConn
->fd
].useDefaultIo();
1275 auto ssl
= fd_table
[srvConn
->fd
].ssl
.get();
1277 BIO
*b
= SSL_get_rbio(ssl
);
1278 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(BIO_get_data(b
));
1279 tunnelState
->preReadServerData
= srvBio
->rBufData();
1280 tunnelStartShoveling(tunnelState
);
1282 #endif //USE_OPENSSL