2 * Copyright (C) 1996-2015 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"
19 #include "comm/Connection.h"
20 #include "comm/ConnOpener.h"
21 #include "comm/Read.h"
22 #include "comm/Write.h"
23 #include "errorpage.h"
28 #include "HttpRequest.h"
29 #include "HttpStateFlags.h"
30 #include "ip/QosConfig.h"
33 #include "PeerSelectState.h"
35 #include "SquidConfig.h"
36 #include "SquidTime.h"
37 #include "StatCounters.h"
40 #include "ssl/PeerConnector.h"
41 #include "ssl/ServerBump.h"
43 #include "security/EncryptorAnswer.h"
54 * TunnelStateData is the state engine performing the tasks for
55 * setup of a TCP tunnel from an existing open client FD to a server
56 * then shuffling binary data between the resulting FD pair.
59 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
60 * of pre-formatted data. Then we can use that as the client side of the tunnel
61 * instead of re-implementing it here and occasionally getting the ConnStateData
62 * read/write state wrong.
64 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
68 CBDATA_CLASS(TunnelStateData
);
73 TunnelStateData(const TunnelStateData
&); // do not implement
74 TunnelStateData
&operator =(const TunnelStateData
&); // do not implement
77 static void ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
78 static void ReadServer(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
79 static void WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
80 static void WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
82 /// Starts reading peer response to our CONNECT request.
83 void readConnectResponse();
85 /// Called when we may be done handling a CONNECT exchange with the peer.
86 void connectExchangeCheckpoint();
88 bool noConnections() const;
90 CbcPointer
<ClientHttpRequest
> http
;
91 HttpRequest::Pointer request
;
92 AccessLogEntryPointer al
;
93 Comm::ConnectionList serverDestinations
;
95 const char * getHost() const {
96 return (server
.conn
!= NULL
&& server
.conn
->getPeer() ? server
.conn
->getPeer()->host
: request
->url
.host());
99 /// Whether we are writing a CONNECT request to a peer.
100 bool waitingForConnectRequest() const { return connectReqWriting
; }
101 /// Whether we are reading a CONNECT response from a peer.
102 bool waitingForConnectResponse() const { return connectRespBuf
; }
103 /// Whether we are waiting for the CONNECT request/response exchange with the peer.
104 bool waitingForConnectExchange() const { return waitingForConnectRequest() || waitingForConnectResponse(); }
106 /// Whether the client sent a CONNECT request to us.
107 bool clientExpectsConnectResponse() const {
109 // We are bumping and we had already send "OK CONNECTED"
110 if (http
.valid() && http
->getConn() && http
->getConn()->serverBump() && http
->getConn()->serverBump()->step
> Ssl::bumpStep1
)
113 return !(request
!= NULL
&&
114 (request
->flags
.interceptTproxy
|| request
->flags
.intercepted
));
117 /// Sends "502 Bad Gateway" error response to the client,
118 /// if it is waiting for Squid CONNECT response, closing connections.
119 void informUserOfPeerError(const char *errMsg
);
125 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF
)), size_ptr(NULL
), delayedLoops(0),
126 readPending(NULL
), readPendingFunc(NULL
) {}
130 int bytesWanted(int lower
=0, int upper
= INT_MAX
) const;
131 void bytesIn(int const &);
134 void setDelayId(DelayId
const &);
137 void error(int const xerrno
);
138 int debugLevelForError(int const xerrno
) const;
140 void dataSent (size_t amount
);
141 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
142 void write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
);
145 AsyncCall::Pointer writer
; ///< pending Comm::Write callback
146 int64_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
148 Comm::ConnectionPointer conn
; ///< The currently connected connection.
149 uint8_t delayedLoops
; ///< how many times a read on this connection has been postponed.
151 // XXX: make these an AsyncCall when event API can handle them
152 TunnelStateData
*readPending
;
153 EVH
*readPendingFunc
;
162 Connection client
, server
;
163 int *status_ptr
; ///< pointer for logging HTTP status
164 LogTags
*logTag_ptr
; ///< pointer for logging Squid processing code
165 MemBuf
*connectRespBuf
; ///< accumulates peer CONNECT response when we need it
166 bool connectReqWriting
; ///< whether we are writing a CONNECT request to a peer
167 SBuf preReadClientData
;
168 time_t started
; ///< when this tunnel was initiated.
170 void copyRead(Connection
&from
, IOCB
*completion
);
172 /// continue to set up connection to a peer, going async for SSL peers
173 void connectToPeer();
177 /// Gives PeerConnector access to Answer in the TunnelStateData callback dialer.
178 class MyAnswerDialer
: public CallDialer
, public Ssl::PeerConnector::CbDialer
181 typedef void (TunnelStateData::*Method
)(Security::EncryptorAnswer
&);
183 MyAnswerDialer(Method method
, TunnelStateData
*tunnel
):
184 method_(method
), tunnel_(tunnel
), answer_() {}
187 virtual bool canDial(AsyncCall
&call
) { return tunnel_
.valid(); }
188 void dial(AsyncCall
&call
) { ((&(*tunnel_
))->*method_
)(answer_
); }
189 virtual void print(std::ostream
&os
) const {
190 os
<< '(' << tunnel_
.get() << ", " << answer_
<< ')';
193 /* Ssl::PeerConnector::CbDialer API */
194 virtual Security::EncryptorAnswer
&answer() { return answer_
; }
198 CbcPointer
<TunnelStateData
> tunnel_
;
199 Security::EncryptorAnswer answer_
;
203 /// callback handler after connection setup (including any encryption)
204 void connectedToPeer(Security::EncryptorAnswer
&answer
);
207 bool keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
);
208 void copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*);
209 void handleConnectResponse(const size_t chunkSize
);
210 void readServer(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
211 void readClient(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
212 void writeClientDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
213 void writeServerDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
215 static void ReadConnectResponseDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
216 void readConnectResponseDone(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
217 void copyClientBytes();
220 static const char *const conn_established
= "HTTP/1.1 200 Connection established\r\n\r\n";
222 static CNCB tunnelConnectDone
;
223 static ERCB tunnelErrorComplete
;
224 static CLCB tunnelServerClosed
;
225 static CLCB tunnelClientClosed
;
226 static CTCB tunnelTimeout
;
227 static PSC tunnelPeerSelectComplete
;
228 static EVH tunnelDelayedClientRead
;
229 static EVH tunnelDelayedServerRead
;
230 static void tunnelConnected(const Comm::ConnectionPointer
&server
, void *);
231 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer
&server
, void *);
234 tunnelServerClosed(const CommCloseCbParams
¶ms
)
236 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
237 debugs(26, 3, HERE
<< tunnelState
->server
.conn
);
238 tunnelState
->server
.conn
= NULL
;
239 tunnelState
->server
.writer
= NULL
;
241 if (tunnelState
->request
!= NULL
)
242 tunnelState
->request
->hier
.stopPeerClock(false);
244 if (tunnelState
->noConnections()) {
249 if (!tunnelState
->client
.writer
) {
250 tunnelState
->client
.conn
->close();
256 tunnelClientClosed(const CommCloseCbParams
¶ms
)
258 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
259 debugs(26, 3, HERE
<< tunnelState
->client
.conn
);
260 tunnelState
->client
.conn
= NULL
;
261 tunnelState
->client
.writer
= NULL
;
263 if (tunnelState
->noConnections()) {
268 if (!tunnelState
->server
.writer
) {
269 tunnelState
->server
.conn
->close();
274 TunnelStateData::TunnelStateData() :
280 connectRespBuf(NULL
),
281 connectReqWriting(false),
282 started(squid_curtime
)
284 debugs(26, 3, "TunnelStateData constructed this=" << this);
285 client
.readPendingFunc
= &tunnelDelayedClientRead
;
286 server
.readPendingFunc
= &tunnelDelayedServerRead
;
289 TunnelStateData::~TunnelStateData()
291 debugs(26, 3, "TunnelStateData destructed this=" << this);
292 assert(noConnections());
294 serverDestinations
.clear();
295 delete connectRespBuf
;
298 TunnelStateData::Connection::~Connection()
301 eventDelete(readPendingFunc
, readPending
);
307 TunnelStateData::Connection::bytesWanted(int lowerbound
, int upperbound
) const
310 return delayId
.bytesWanted(lowerbound
, upperbound
);
318 TunnelStateData::Connection::bytesIn(int const &count
)
320 debugs(26, 3, HERE
<< "len=" << len
<< " + count=" << count
);
322 delayId
.bytesIn(count
);
329 TunnelStateData::Connection::debugLevelForError(int const xerrno
) const
333 if (xerrno
== ECONNRESET
)
338 if (ignoreErrno(xerrno
))
344 /* Read from server side and queue it for writing to the client */
346 TunnelStateData::ReadServer(const Comm::ConnectionPointer
&c
, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
348 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
349 assert(cbdataReferenceValid(tunnelState
));
350 debugs(26, 3, HERE
<< c
);
352 tunnelState
->readServer(buf
, len
, errcode
, xerrno
);
356 TunnelStateData::readServer(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
358 debugs(26, 3, HERE
<< server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
359 server
.delayedLoops
=0;
362 * Bail out early on Comm::ERR_CLOSING
363 * - close handlers will tidy up for us
366 if (errcode
== Comm::ERR_CLOSING
)
371 kb_incr(&(statCounter
.server
.all
.kbytes_in
), len
);
372 kb_incr(&(statCounter
.server
.other
.kbytes_in
), len
);
375 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
376 copy(len
, server
, client
, WriteClientDone
);
379 /// Called when we read [a part of] CONNECT response from the peer
381 TunnelStateData::readConnectResponseDone(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
383 debugs(26, 3, server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
384 assert(waitingForConnectResponse());
386 if (errcode
== Comm::ERR_CLOSING
)
390 connectRespBuf
->appended(len
);
392 kb_incr(&(statCounter
.server
.all
.kbytes_in
), len
);
393 kb_incr(&(statCounter
.server
.other
.kbytes_in
), len
);
396 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
397 handleConnectResponse(len
);
401 TunnelStateData::informUserOfPeerError(const char *errMsg
)
404 if (!clientExpectsConnectResponse()) {
405 // closing the connection is the best we can do here
406 debugs(50, 3, server
.conn
<< " closing on error: " << errMsg
);
407 server
.conn
->close();
410 ErrorState
*err
= new ErrorState(ERR_CONNECT_FAIL
, Http::scBadGateway
, request
.getRaw());
411 err
->callback
= tunnelErrorComplete
;
412 err
->callback_data
= this;
413 *status_ptr
= Http::scBadGateway
;
414 errorSend(http
->getConn()->clientConnection
, err
);
417 /* Read from client side and queue it for writing to the server */
419 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
421 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
422 assert (cbdataReferenceValid (tunnelState
));
424 tunnelState
->readConnectResponseDone(buf
, len
, errcode
, xerrno
);
427 /// Parses [possibly incomplete] CONNECT response and reacts to it.
428 /// If the tunnel is being closed or more response data is needed, returns false.
429 /// Otherwise, the caller should handle the remaining read data, if any.
431 TunnelStateData::handleConnectResponse(const size_t chunkSize
)
433 assert(waitingForConnectResponse());
435 // Ideally, client and server should use MemBuf or better, but current code
436 // never accumulates more than one read when shoveling data (XXX) so it does
437 // not need to deal with MemBuf complexity. To keep it simple, we use a
438 // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
439 // is optimized, reuse server.buf for CONNEC response accumulation instead.
441 /* mimic the basic parts of HttpStateData::processReplyHeader() */
443 Http::StatusCode parseErr
= Http::scNone
;
444 const bool eof
= !chunkSize
;
445 connectRespBuf
->terminate(); // HttpMsg::parse requires terminated string
446 const bool parsed
= rep
.parse(connectRespBuf
->content(), connectRespBuf
->contentSize(), eof
, &parseErr
);
448 if (parseErr
> 0) { // unrecoverable parsing error
449 informUserOfPeerError("malformed CONNECT response from peer");
457 if (!connectRespBuf
->hasSpace()) {
458 informUserOfPeerError("huge CONNECT response from peer");
463 readConnectResponse();
467 // CONNECT response was successfully parsed
468 *status_ptr
= rep
.sline
.status();
470 // bail if we did not get an HTTP 200 (Connection Established) response
471 if (rep
.sline
.status() != Http::scOkay
) {
472 // if we ever decide to reuse the peer connection, we must extract the error response first
473 informUserOfPeerError("unsupported CONNECT response status code");
477 if (rep
.hdr_sz
< connectRespBuf
->contentSize()) {
478 // preserve bytes that the server already sent after the CONNECT response
479 server
.len
= connectRespBuf
->contentSize() - rep
.hdr_sz
;
480 memcpy(server
.buf
, connectRespBuf
->content()+rep
.hdr_sz
, server
.len
);
482 // reset; delay pools were using this field to throttle CONNECT response
486 delete connectRespBuf
;
487 connectRespBuf
= NULL
;
488 connectExchangeCheckpoint();
492 TunnelStateData::Connection::error(int const xerrno
)
494 /* XXX fixme xstrerror and xerrno... */
497 debugs(50, debugLevelForError(xerrno
), HERE
<< conn
<< ": read/write failure: " << xstrerror());
499 if (!ignoreErrno(xerrno
))
503 /* Read from client side and queue it for writing to the server */
505 TunnelStateData::ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
507 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
508 assert (cbdataReferenceValid (tunnelState
));
510 tunnelState
->readClient(buf
, len
, errcode
, xerrno
);
514 TunnelStateData::readClient(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
516 debugs(26, 3, HERE
<< client
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
517 client
.delayedLoops
=0;
520 * Bail out early on Comm::ERR_CLOSING
521 * - close handlers will tidy up for us
524 if (errcode
== Comm::ERR_CLOSING
)
529 kb_incr(&(statCounter
.client_http
.kbytes_in
), len
);
532 if (keepGoingAfterRead(len
, errcode
, xerrno
, client
, server
))
533 copy(len
, client
, server
, WriteServerDone
);
536 /// Updates state after reading from client or server.
537 /// Returns whether the caller should use the data just read.
539 TunnelStateData::keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
)
541 debugs(26, 3, HERE
<< "from={" << from
.conn
<< "}, to={" << to
.conn
<< "}");
543 /* I think this is to prevent free-while-in-a-callback behaviour
545 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
547 const CbcPointer
<TunnelStateData
> safetyLock(this);
549 /* Bump the source connection read timeout on any activity */
550 if (Comm::IsConnOpen(from
.conn
)) {
551 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
552 CommTimeoutCbPtrFun(tunnelTimeout
, this));
553 commSetConnTimeout(from
.conn
, Config
.Timeout
.read
, timeoutCall
);
556 /* Bump the dest connection read timeout on any activity */
557 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
558 if (Comm::IsConnOpen(to
.conn
)) {
559 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
560 CommTimeoutCbPtrFun(tunnelTimeout
, this));
561 commSetConnTimeout(to
.conn
, Config
.Timeout
.read
, timeoutCall
);
566 else if (len
== 0 || !Comm::IsConnOpen(to
.conn
)) {
567 debugs(26, 3, HERE
<< "Nothing to write or client gone. Terminate the tunnel.");
570 /* Only close the remote end if we've finished queueing data to it */
571 if (from
.len
== 0 && Comm::IsConnOpen(to
.conn
) ) {
574 } else if (cbdataReferenceValid(this)) {
582 TunnelStateData::copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*completion
)
584 debugs(26, 3, HERE
<< "Schedule Write");
585 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelBlindCopyWriteHandler",
586 CommIoCbPtrFun(completion
, this));
587 to
.write(from
.buf
, len
, call
, NULL
);
590 /* Writes data from the client buffer to the server side */
592 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
594 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
595 assert (cbdataReferenceValid (tunnelState
));
596 tunnelState
->server
.writer
= NULL
;
598 tunnelState
->writeServerDone(buf
, len
, flag
, xerrno
);
602 TunnelStateData::writeServerDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
604 debugs(26, 3, HERE
<< server
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
607 if (flag
!= Comm::OK
) {
608 if (flag
!= Comm::ERR_CLOSING
) {
609 debugs(26, 4, HERE
<< "calling TunnelStateData::server.error(" << xerrno
<<")");
610 server
.error(xerrno
); // may call comm_close
617 debugs(26, 4, HERE
<< "No read input. Closing server connection.");
618 server
.conn
->close();
623 kb_incr(&(statCounter
.server
.all
.kbytes_out
), len
);
624 kb_incr(&(statCounter
.server
.other
.kbytes_out
), len
);
625 client
.dataSent(len
);
627 /* If the other end has closed, so should we */
628 if (!Comm::IsConnOpen(client
.conn
)) {
629 debugs(26, 4, HERE
<< "Client gone away. Shutting down server connection.");
630 server
.conn
->close();
634 const CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
636 if (cbdataReferenceValid(this))
640 /* Writes data from the server buffer to the client side */
642 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
644 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
645 assert (cbdataReferenceValid (tunnelState
));
646 tunnelState
->client
.writer
= NULL
;
648 tunnelState
->writeClientDone(buf
, len
, flag
, xerrno
);
652 TunnelStateData::Connection::dataSent(size_t amount
)
654 debugs(26, 3, HERE
<< "len=" << len
<< " - amount=" << amount
);
655 assert(amount
== (size_t)len
);
657 /* increment total object size */
664 TunnelStateData::Connection::write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
667 Comm::Write(conn
, b
, size
, callback
, free_func
);
671 TunnelStateData::writeClientDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
673 debugs(26, 3, HERE
<< client
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
676 if (flag
!= Comm::OK
) {
677 if (flag
!= Comm::ERR_CLOSING
) {
678 debugs(26, 4, HERE
<< "Closing client connection due to comm flags.");
679 client
.error(xerrno
); // may call comm_close
686 debugs(26, 4, HERE
<< "Closing client connection due to 0 byte read.");
687 client
.conn
->close();
692 kb_incr(&(statCounter
.client_http
.kbytes_out
), len
);
693 server
.dataSent(len
);
695 /* If the other end has closed, so should we */
696 if (!Comm::IsConnOpen(server
.conn
)) {
697 debugs(26, 4, HERE
<< "Server has gone away. Terminating client connection.");
698 client
.conn
->close();
702 CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
704 if (cbdataReferenceValid(this))
705 copyRead(server
, ReadServer
);
709 tunnelTimeout(const CommTimeoutCbParams
&io
)
711 TunnelStateData
*tunnelState
= static_cast<TunnelStateData
*>(io
.data
);
712 debugs(26, 3, HERE
<< io
.conn
);
713 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
714 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
716 tunnelState
->client
.closeIfOpen();
717 tunnelState
->server
.closeIfOpen();
721 TunnelStateData::Connection::closeIfOpen()
723 if (Comm::IsConnOpen(conn
))
728 tunnelDelayedClientRead(void *data
)
733 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
734 tunnel
->client
.readPending
= NULL
;
735 static uint64_t counter
=0;
736 debugs(26, 7, "Client read(2) delayed " << ++counter
<< " times");
737 tunnel
->copyRead(tunnel
->client
, TunnelStateData::ReadClient
);
741 tunnelDelayedServerRead(void *data
)
746 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
747 tunnel
->server
.readPending
= NULL
;
748 static uint64_t counter
=0;
749 debugs(26, 7, "Server read(2) delayed " << ++counter
<< " times");
750 tunnel
->copyRead(tunnel
->server
, TunnelStateData::ReadServer
);
754 TunnelStateData::copyRead(Connection
&from
, IOCB
*completion
)
756 assert(from
.len
== 0);
757 // If only the minimum permitted read size is going to be attempted
758 // then we schedule an event to try again in a few I/O cycles.
759 // Allow at least 1 byte to be read every (0.3*10) seconds.
760 int bw
= from
.bytesWanted(1, SQUID_TCP_SO_RCVBUF
);
761 if (bw
== 1 && ++from
.delayedLoops
< 10) {
762 from
.readPending
= this;
763 eventAdd("tunnelDelayedServerRead", from
.readPendingFunc
, from
.readPending
, 0.3, true);
767 AsyncCall::Pointer call
= commCbCall(5,4, "TunnelBlindCopyReadHandler",
768 CommIoCbPtrFun(completion
, this));
769 comm_read(from
.conn
, from
.buf
, bw
, call
);
773 TunnelStateData::readConnectResponse()
775 assert(waitingForConnectResponse());
777 AsyncCall::Pointer call
= commCbCall(5,4, "readConnectResponseDone",
778 CommIoCbPtrFun(ReadConnectResponseDone
, this));
779 comm_read(server
.conn
, connectRespBuf
->space(),
780 server
.bytesWanted(1, connectRespBuf
->spaceSize()), call
);
784 TunnelStateData::copyClientBytes()
786 if (preReadClientData
.length()) {
787 size_t copyBytes
= preReadClientData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadClientData
.length();
788 memcpy(client
.buf
, preReadClientData
.rawContent(), copyBytes
);
789 preReadClientData
.consume(copyBytes
);
790 client
.bytesIn(copyBytes
);
791 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, client
, server
))
792 copy(copyBytes
, client
, server
, TunnelStateData::WriteServerDone
);
794 copyRead(client
, ReadClient
);
798 * Set the HTTP status for this request and sets the read handlers for client
799 * and server side connections.
802 tunnelStartShoveling(TunnelStateData
*tunnelState
)
804 assert(!tunnelState
->waitingForConnectExchange());
805 *tunnelState
->status_ptr
= Http::scOkay
;
806 if (tunnelState
->logTag_ptr
)
807 *tunnelState
->logTag_ptr
= LOG_TCP_TUNNEL
;
808 if (cbdataReferenceValid(tunnelState
)) {
810 // Shovel any payload already pushed into reply buffer by the server response
811 if (!tunnelState
->server
.len
)
812 tunnelState
->copyRead(tunnelState
->server
, TunnelStateData::ReadServer
);
814 debugs(26, DBG_DATA
, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState
->server
.buf
, tunnelState
->server
.len
) << "\n----------");
815 tunnelState
->copy(tunnelState
->server
.len
, tunnelState
->server
, tunnelState
->client
, TunnelStateData::WriteClientDone
);
818 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn() && !tunnelState
->http
->getConn()->in
.buf
.isEmpty()) {
819 struct ConnStateData::In
*in
= &tunnelState
->http
->getConn()->in
;
820 debugs(26, DBG_DATA
, "Tunnel client PUSH Payload: \n" << in
->buf
<< "\n----------");
821 tunnelState
->preReadClientData
.append(in
->buf
);
822 in
->buf
.consume(); // ConnStateData buffer accounting after the shuffle.
824 tunnelState
->copyClientBytes();
829 * All the pieces we need to write to client and/or server connection
831 * Call the tunnelStartShoveling to start the blind pump.
834 tunnelConnectedWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t, Comm::Flag flag
, int, void *data
)
836 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
837 debugs(26, 3, HERE
<< conn
<< ", flag=" << flag
);
838 tunnelState
->client
.writer
= NULL
;
840 if (flag
!= Comm::OK
) {
841 *tunnelState
->status_ptr
= Http::scInternalServerError
;
842 tunnelErrorComplete(conn
->fd
, data
, 0);
846 tunnelStartShoveling(tunnelState
);
849 /// Called when we are done writing CONNECT request to a peer.
851 tunnelConnectReqWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t, Comm::Flag flag
, int, void *data
)
853 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
854 debugs(26, 3, conn
<< ", flag=" << flag
);
855 tunnelState
->server
.writer
= NULL
;
856 assert(tunnelState
->waitingForConnectRequest());
858 if (flag
!= Comm::OK
) {
859 *tunnelState
->status_ptr
= Http::scInternalServerError
;
860 tunnelErrorComplete(conn
->fd
, data
, 0);
864 tunnelState
->connectReqWriting
= false;
865 tunnelState
->connectExchangeCheckpoint();
869 TunnelStateData::connectExchangeCheckpoint()
871 if (waitingForConnectResponse()) {
872 debugs(26, 5, "still reading CONNECT response on " << server
.conn
);
873 } else if (waitingForConnectRequest()) {
874 debugs(26, 5, "still writing CONNECT request on " << server
.conn
);
876 assert(!waitingForConnectExchange());
877 debugs(26, 3, "done with CONNECT exchange on " << server
.conn
);
878 tunnelConnected(server
.conn
, this);
883 * handle the write completion from a proxy request to an upstream origin
886 tunnelConnected(const Comm::ConnectionPointer
&server
, void *data
)
888 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
889 debugs(26, 3, HERE
<< server
<< ", tunnelState=" << tunnelState
);
891 if (!tunnelState
->clientExpectsConnectResponse())
892 tunnelStartShoveling(tunnelState
); // ssl-bumped connection, be quiet
894 AsyncCall::Pointer call
= commCbCall(5,5, "tunnelConnectedWriteDone",
895 CommIoCbPtrFun(tunnelConnectedWriteDone
, tunnelState
));
896 tunnelState
->client
.write(conn_established
, strlen(conn_established
), call
, NULL
);
901 tunnelErrorComplete(int fd
/*const Comm::ConnectionPointer &*/, void *data
, size_t)
903 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
904 debugs(26, 3, HERE
<< "FD " << fd
);
905 assert(tunnelState
!= NULL
);
906 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
907 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
909 if (Comm::IsConnOpen(tunnelState
->client
.conn
))
910 tunnelState
->client
.conn
->close();
912 if (Comm::IsConnOpen(tunnelState
->server
.conn
))
913 tunnelState
->server
.conn
->close();
917 tunnelConnectDone(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
919 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
921 if (status
!= Comm::OK
) {
922 debugs(26, 4, HERE
<< conn
<< ", comm failure recovery.");
923 /* At this point only the TCP handshake has failed. no data has been passed.
924 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
926 debugs(26, 4, "removing server 1 of " << tunnelState
->serverDestinations
.size() <<
927 " from destinations (" << tunnelState
->serverDestinations
[0] << ")");
928 tunnelState
->serverDestinations
.erase(tunnelState
->serverDestinations
.begin());
929 time_t fwdTimeout
= tunnelState
->started
+ Config
.Timeout
.forward
;
930 if (fwdTimeout
> squid_curtime
&& tunnelState
->serverDestinations
.size() > 0) {
931 // find remaining forward_timeout available for this attempt
932 fwdTimeout
-= squid_curtime
;
933 if (fwdTimeout
> Config
.Timeout
.connect
)
934 fwdTimeout
= Config
.Timeout
.connect
;
935 /* Try another IP of this destination host */
936 GetMarkingsToServer(tunnelState
->request
.getRaw(), *tunnelState
->serverDestinations
[0]);
937 debugs(26, 4, HERE
<< "retry with : " << tunnelState
->serverDestinations
[0]);
938 AsyncCall::Pointer call
= commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone
, tunnelState
));
939 Comm::ConnOpener
*cs
= new Comm::ConnOpener(tunnelState
->serverDestinations
[0], call
, fwdTimeout
);
940 cs
->setHost(tunnelState
->url
);
943 debugs(26, 4, HERE
<< "terminate with error.");
944 ErrorState
*err
= new ErrorState(ERR_CONNECT_FAIL
, Http::scServiceUnavailable
, tunnelState
->request
.getRaw());
945 *tunnelState
->status_ptr
= Http::scServiceUnavailable
;
946 err
->xerrno
= xerrno
;
947 // on timeout is this still: err->xerrno = ETIMEDOUT;
948 err
->port
= conn
->remote
.port();
949 err
->callback
= tunnelErrorComplete
;
950 err
->callback_data
= tunnelState
;
951 errorSend(tunnelState
->client
.conn
, err
);
952 if (tunnelState
->request
!= NULL
)
953 tunnelState
->request
->hier
.stopPeerClock(false);
959 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
960 if (conn
->getPeer() && conn
->getPeer()->options
.no_delay
)
961 tunnelState
->server
.setDelayId(DelayId());
964 tunnelState
->request
->hier
.note(conn
, tunnelState
->getHost());
966 tunnelState
->server
.conn
= conn
;
967 tunnelState
->request
->peer_host
= conn
->getPeer() ? conn
->getPeer()->host
: NULL
;
968 comm_add_close_handler(conn
->fd
, tunnelServerClosed
, tunnelState
);
970 debugs(26, 4, HERE
<< "determine post-connect handling pathway.");
971 if (conn
->getPeer()) {
972 tunnelState
->request
->peer_login
= conn
->getPeer()->login
;
973 tunnelState
->request
->flags
.proxying
= !(conn
->getPeer()->options
.originserver
);
975 tunnelState
->request
->peer_login
= NULL
;
976 tunnelState
->request
->flags
.proxying
= false;
979 if (tunnelState
->request
->flags
.proxying
)
980 tunnelState
->connectToPeer();
982 tunnelConnected(conn
, tunnelState
);
985 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
986 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
987 commSetConnTimeout(conn
, Config
.Timeout
.read
, timeoutCall
);
991 tunnelStart(ClientHttpRequest
* http
, int64_t * size_ptr
, int *status_ptr
, const AccessLogEntryPointer
&al
)
994 /* Create state structure. */
995 TunnelStateData
*tunnelState
= NULL
;
996 ErrorState
*err
= NULL
;
997 HttpRequest
*request
= http
->request
;
998 char *url
= http
->uri
;
1001 * client_addr.isNoAddr() indicates this is an "internal" request
1002 * from peer_digest.c, asn.c, netdb.c, etc and should always
1003 * be allowed. yuck, I know.
1006 if (Config
.accessList
.miss
&& !request
->client_addr
.isNoAddr()) {
1008 * Check if this host is allowed to fetch MISSES from us (miss_access)
1009 * default is to allow.
1011 ACLFilledChecklist
ch(Config
.accessList
.miss
, request
, NULL
);
1012 ch
.src_addr
= request
->client_addr
;
1013 ch
.my_addr
= request
->my_addr
;
1014 if (ch
.fastCheck() == ACCESS_DENIED
) {
1015 debugs(26, 4, HERE
<< "MISS access forbidden.");
1016 err
= new ErrorState(ERR_FORWARDING_DENIED
, Http::scForbidden
, request
);
1017 *status_ptr
= Http::scForbidden
;
1018 errorSend(http
->getConn()->clientConnection
, err
);
1023 debugs(26, 3, request
->method
<< ' ' << url
<< ' ' << request
->http_ver
);
1024 ++statCounter
.server
.all
.requests
;
1025 ++statCounter
.server
.other
.requests
;
1027 tunnelState
= new TunnelStateData
;
1029 tunnelState
->server
.setDelayId(DelayId::DelayClient(http
));
1031 tunnelState
->url
= xstrdup(url
);
1032 tunnelState
->request
= request
;
1033 tunnelState
->server
.size_ptr
= size_ptr
;
1034 tunnelState
->status_ptr
= status_ptr
;
1035 tunnelState
->logTag_ptr
= &http
->logType
;
1036 tunnelState
->client
.conn
= http
->getConn()->clientConnection
;
1037 tunnelState
->http
= http
;
1038 tunnelState
->al
= al
;
1039 //tunnelState->started is set in TunnelStateData ctor
1041 comm_add_close_handler(tunnelState
->client
.conn
->fd
,
1045 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1046 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1047 commSetConnTimeout(tunnelState
->client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
1049 peerSelect(&(tunnelState
->serverDestinations
), request
, al
,
1051 tunnelPeerSelectComplete
,
1056 TunnelStateData::connectToPeer()
1059 if (CachePeer
*p
= server
.conn
->getPeer()) {
1060 if (p
->secure
.encryptTransport
) {
1061 AsyncCall::Pointer callback
= asyncCall(5,4,
1062 "TunnelStateData::ConnectedToPeer",
1063 MyAnswerDialer(&TunnelStateData::connectedToPeer
, this));
1064 Ssl::BlindPeerConnector
*connector
=
1065 new Ssl::BlindPeerConnector(request
, server
.conn
, callback
);
1066 AsyncJob::Start(connector
); // will call our callback
1072 Security::EncryptorAnswer nil
;
1073 connectedToPeer(nil
);
1077 TunnelStateData::connectedToPeer(Security::EncryptorAnswer
&answer
)
1079 if (ErrorState
*error
= answer
.error
.get()) {
1080 *status_ptr
= error
->httpStatus
;
1081 error
->callback
= tunnelErrorComplete
;
1082 error
->callback_data
= this;
1083 errorSend(client
.conn
, error
);
1084 answer
.error
.clear(); // preserve error for errorSendComplete()
1088 tunnelRelayConnectRequest(server
.conn
, this);
1092 tunnelRelayConnectRequest(const Comm::ConnectionPointer
&srv
, void *data
)
1094 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1095 assert(!tunnelState
->waitingForConnectExchange());
1096 HttpHeader
hdr_out(hoRequest
);
1097 HttpStateFlags flags
;
1098 debugs(26, 3, HERE
<< srv
<< ", tunnelState=" << tunnelState
);
1099 memset(&flags
, '\0', sizeof(flags
));
1100 flags
.proxying
= tunnelState
->request
->flags
.proxying
;
1103 mb
.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState
->url
);
1104 HttpStateData::httpBuildRequestHeader(tunnelState
->request
.getRaw(),
1105 NULL
, /* StoreEntry */
1106 tunnelState
->al
, /* AccessLogEntry */
1109 hdr_out
.packInto(&mb
);
1111 mb
.append("\r\n", 2);
1113 debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState
->server
.conn
<< ":\n----------\n" <<
1114 Raw("tunnelRelayConnectRequest", mb
.content(), mb
.contentSize()) << "\n----------");
1116 AsyncCall::Pointer writeCall
= commCbCall(5,5, "tunnelConnectReqWriteDone",
1117 CommIoCbPtrFun(tunnelConnectReqWriteDone
,
1120 tunnelState
->server
.write(mb
.buf
, mb
.size
, writeCall
, mb
.freeFunc());
1121 tunnelState
->connectReqWriting
= true;
1123 tunnelState
->connectRespBuf
= new MemBuf
;
1124 // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1125 // can hold since any CONNECT response leftovers have to fit into server.buf.
1126 // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
1127 tunnelState
->connectRespBuf
->init(SQUID_TCP_SO_RCVBUF
, 2*SQUID_TCP_SO_RCVBUF
);
1128 tunnelState
->readConnectResponse();
1130 assert(tunnelState
->waitingForConnectExchange());
1132 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1133 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1134 commSetConnTimeout(srv
, Config
.Timeout
.read
, timeoutCall
);
1138 tunnelPeerSelectComplete(Comm::ConnectionList
*peer_paths
, ErrorState
*err
, void *data
)
1140 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1142 if (peer_paths
== NULL
|| peer_paths
->size() < 1) {
1143 debugs(26, 3, HERE
<< "No paths found. Aborting CONNECT");
1145 err
= new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, tunnelState
->request
.getRaw());
1147 *tunnelState
->status_ptr
= err
->httpStatus
;
1148 err
->callback
= tunnelErrorComplete
;
1149 err
->callback_data
= tunnelState
;
1150 errorSend(tunnelState
->client
.conn
, err
);
1155 GetMarkingsToServer(tunnelState
->request
.getRaw(), *tunnelState
->serverDestinations
[0]);
1157 if (tunnelState
->request
!= NULL
)
1158 tunnelState
->request
->hier
.startPeerClock();
1160 debugs(26, 3, HERE
<< "paths=" << peer_paths
->size() << ", p[0]={" << (*peer_paths
)[0] << "}, serverDest[0]={" <<
1161 tunnelState
->serverDestinations
[0] << "}");
1163 AsyncCall::Pointer call
= commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone
, tunnelState
));
1164 Comm::ConnOpener
*cs
= new Comm::ConnOpener(tunnelState
->serverDestinations
[0], call
, Config
.Timeout
.connect
);
1165 cs
->setHost(tunnelState
->url
);
1166 AsyncJob::Start(cs
);
1169 CBDATA_CLASS_INIT(TunnelStateData
);
1172 TunnelStateData::noConnections() const
1174 return !Comm::IsConnOpen(server
.conn
) && !Comm::IsConnOpen(client
.conn
);
1179 TunnelStateData::Connection::setDelayId(DelayId
const &newDelay
)
1188 switchToTunnel(HttpRequest
*request
, Comm::ConnectionPointer
&clientConn
, Comm::ConnectionPointer
&srvConn
)
1190 debugs(26,5, "Revert to tunnel FD " << clientConn
->fd
<< " with FD " << srvConn
->fd
);
1191 /* Create state structure. */
1192 TunnelStateData
*tunnelState
= NULL
;
1193 const SBuf
url(request
->effectiveRequestUri());
1195 debugs(26, 3, request
->method
<< " " << url
<< " " << request
->http_ver
);
1196 ++statCounter
.server
.all
.requests
;
1197 ++statCounter
.server
.other
.requests
;
1199 tunnelState
= new TunnelStateData
;
1200 tunnelState
->url
= xstrndup(url
.rawContent(), url
.length()+1);
1201 tunnelState
->request
= request
;
1202 tunnelState
->server
.size_ptr
= NULL
; //Set later if ClientSocketContext is available
1204 // Temporary static variable to store the unneeded for our case status code
1205 static int status_code
= 0;
1206 tunnelState
->status_ptr
= &status_code
;
1207 tunnelState
->client
.conn
= clientConn
;
1209 ConnStateData
*conn
;
1210 if ((conn
= request
->clientConnectionManager
.get())) {
1211 ClientSocketContext::Pointer context
= conn
->getCurrentContext();
1212 if (context
!= NULL
&& context
->http
!= NULL
) {
1213 tunnelState
->logTag_ptr
= &context
->http
->logType
;
1214 tunnelState
->server
.size_ptr
= &context
->http
->out
.size
;
1217 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1218 if (srvConn
->getPeer() && srvConn
->getPeer()->options
.no_delay
)
1219 tunnelState
->server
.setDelayId(DelayId::DelayClient(context
->http
));
1224 comm_add_close_handler(tunnelState
->client
.conn
->fd
,
1228 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1229 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1230 commSetConnTimeout(tunnelState
->client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
1231 fd_table
[clientConn
->fd
].read_method
= &default_read_method
;
1232 fd_table
[clientConn
->fd
].write_method
= &default_write_method
;
1234 tunnelState
->request
->hier
.note(srvConn
, tunnelState
->getHost());
1236 tunnelState
->server
.conn
= srvConn
;
1237 tunnelState
->request
->peer_host
= srvConn
->getPeer() ? srvConn
->getPeer()->host
: NULL
;
1238 comm_add_close_handler(srvConn
->fd
, tunnelServerClosed
, tunnelState
);
1240 debugs(26, 4, "determine post-connect handling pathway.");
1241 if (srvConn
->getPeer()) {
1242 tunnelState
->request
->peer_login
= srvConn
->getPeer()->login
;
1243 tunnelState
->request
->flags
.proxying
= !(srvConn
->getPeer()->options
.originserver
);
1245 tunnelState
->request
->peer_login
= NULL
;
1246 tunnelState
->request
->flags
.proxying
= false;
1249 timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1250 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1251 commSetConnTimeout(srvConn
, Config
.Timeout
.read
, timeoutCall
);
1252 fd_table
[srvConn
->fd
].read_method
= &default_read_method
;
1253 fd_table
[srvConn
->fd
].write_method
= &default_write_method
;
1255 auto ssl
= fd_table
[srvConn
->fd
].ssl
;
1257 BIO
*b
= SSL_get_rbio(ssl
);
1258 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(b
->ptr
);
1259 const MemBuf
&buf
= srvBio
->rBufData();
1261 AsyncCall::Pointer call
= commCbCall(5,5, "tunnelConnectedWriteDone",
1262 CommIoCbPtrFun(tunnelConnectedWriteDone
, tunnelState
));
1263 tunnelState
->client
.write(buf
.content(), buf
.contentSize(), call
, NULL
);
1265 #endif //USE_OPENSSL