2 * Copyright (C) 1996-2016 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"
29 #include "http/Stream.h"
30 #include "HttpRequest.h"
31 #include "ip/QosConfig.h"
34 #include "PeerSelectState.h"
35 #include "sbuf/SBuf.h"
36 #include "security/BlindPeerConnector.h"
37 #include "SquidConfig.h"
38 #include "SquidTime.h"
39 #include "StatCounters.h"
42 #include "ssl/ServerBump.h"
53 * TunnelStateData is the state engine performing the tasks for
54 * setup of a TCP tunnel from an existing open client FD to a server
55 * then shuffling binary data between the resulting FD pair.
58 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
59 * of pre-formatted data. Then we can use that as the client side of the tunnel
60 * instead of re-implementing it here and occasionally getting the ConnStateData
61 * read/write state wrong.
63 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
67 CBDATA_CLASS(TunnelStateData
);
70 TunnelStateData(ClientHttpRequest
*);
72 TunnelStateData(const TunnelStateData
&); // do not implement
73 TunnelStateData
&operator =(const TunnelStateData
&); // do not implement
76 static void ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
77 static void ReadServer(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
78 static void WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
79 static void WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
);
81 /// Starts reading peer response to our CONNECT request.
82 void readConnectResponse();
84 /// Called when we may be done handling a CONNECT exchange with the peer.
85 void connectExchangeCheckpoint();
87 bool noConnections() const;
89 CbcPointer
<ClientHttpRequest
> http
;
90 HttpRequest::Pointer request
;
91 AccessLogEntryPointer al
;
92 Comm::ConnectionList serverDestinations
;
94 const char * getHost() const {
95 return (server
.conn
!= NULL
&& server
.conn
->getPeer() ? server
.conn
->getPeer()->host
: request
->url
.host());
98 /// Whether we are writing a CONNECT request to a peer.
99 bool waitingForConnectRequest() const { return connectReqWriting
; }
100 /// Whether we are reading a CONNECT response from a peer.
101 bool waitingForConnectResponse() const { return connectRespBuf
; }
102 /// Whether we are waiting for the CONNECT request/response exchange with the peer.
103 bool waitingForConnectExchange() const { return waitingForConnectRequest() || waitingForConnectResponse(); }
105 /// Whether the client sent a CONNECT request to us.
106 bool clientExpectsConnectResponse() const {
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.
109 if (request
&& request
->flags
.forceTunnel
)
112 // We are bumping and we had already send "OK CONNECTED"
113 if (http
.valid() && http
->getConn() && http
->getConn()->serverBump() && http
->getConn()->serverBump()->step
> Ssl::bumpStep1
)
116 return !(request
!= NULL
&&
117 (request
->flags
.interceptTproxy
|| request
->flags
.intercepted
));
120 /// Sends "502 Bad Gateway" error response to the client,
121 /// if it is waiting for Squid CONNECT response, closing connections.
122 void informUserOfPeerError(const char *errMsg
, size_t);
128 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF
)), size_ptr(NULL
), delayedLoops(0),
129 readPending(NULL
), readPendingFunc(NULL
) {}
133 int bytesWanted(int lower
=0, int upper
= INT_MAX
) const;
134 void bytesIn(int const &);
137 void setDelayId(DelayId
const &);
140 void error(int const xerrno
);
141 int debugLevelForError(int const xerrno
) const;
143 void dataSent (size_t amount
);
144 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
145 void write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
);
148 AsyncCall::Pointer writer
; ///< pending Comm::Write callback
149 uint64_t *size_ptr
; /* pointer to size in an ConnStateData for logging */
151 Comm::ConnectionPointer conn
; ///< The currently connected connection.
152 uint8_t delayedLoops
; ///< how many times a read on this connection has been postponed.
154 // XXX: make these an AsyncCall when event API can handle them
155 TunnelStateData
*readPending
;
156 EVH
*readPendingFunc
;
165 Connection client
, server
;
166 int *status_ptr
; ///< pointer for logging HTTP status
167 LogTags
*logTag_ptr
; ///< pointer for logging Squid processing code
168 MemBuf
*connectRespBuf
; ///< accumulates peer CONNECT response when we need it
169 bool connectReqWriting
; ///< whether we are writing a CONNECT request to a peer
170 SBuf preReadClientData
;
171 SBuf preReadServerData
;
172 time_t started
; ///< when this tunnel was initiated.
174 void copyRead(Connection
&from
, IOCB
*completion
);
176 /// continue to set up connection to a peer, going async for SSL peers
177 void connectToPeer();
180 /// Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
181 class MyAnswerDialer
: public CallDialer
, public Security::PeerConnector::CbDialer
184 typedef void (TunnelStateData::*Method
)(Security::EncryptorAnswer
&);
186 MyAnswerDialer(Method method
, TunnelStateData
*tunnel
):
187 method_(method
), tunnel_(tunnel
), answer_() {}
190 virtual bool canDial(AsyncCall
&call
) { return tunnel_
.valid(); }
191 void dial(AsyncCall
&call
) { ((&(*tunnel_
))->*method_
)(answer_
); }
192 virtual void print(std::ostream
&os
) const {
193 os
<< '(' << tunnel_
.get() << ", " << answer_
<< ')';
196 /* Security::PeerConnector::CbDialer API */
197 virtual Security::EncryptorAnswer
&answer() { return answer_
; }
201 CbcPointer
<TunnelStateData
> tunnel_
;
202 Security::EncryptorAnswer answer_
;
205 /// callback handler after connection setup (including any encryption)
206 void connectedToPeer(Security::EncryptorAnswer
&answer
);
209 bool keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
);
210 void copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*);
211 void handleConnectResponse(const size_t chunkSize
);
212 void readServer(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
213 void readClient(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
214 void writeClientDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
215 void writeServerDone(char *buf
, size_t len
, Comm::Flag flag
, int xerrno
);
217 static void ReadConnectResponseDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
);
218 void readConnectResponseDone(char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
);
219 void copyClientBytes();
220 void copyServerBytes();
223 static const char *const conn_established
= "HTTP/1.1 200 Connection established\r\n\r\n";
225 static CNCB tunnelConnectDone
;
226 static ERCB tunnelErrorComplete
;
227 static CLCB tunnelServerClosed
;
228 static CLCB tunnelClientClosed
;
229 static CTCB tunnelTimeout
;
230 static PSC tunnelPeerSelectComplete
;
231 static EVH tunnelDelayedClientRead
;
232 static EVH tunnelDelayedServerRead
;
233 static void tunnelConnected(const Comm::ConnectionPointer
&server
, void *);
234 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer
&server
, void *);
237 tunnelServerClosed(const CommCloseCbParams
¶ms
)
239 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
240 debugs(26, 3, HERE
<< tunnelState
->server
.conn
);
241 tunnelState
->server
.conn
= NULL
;
242 tunnelState
->server
.writer
= NULL
;
244 if (tunnelState
->request
!= NULL
)
245 tunnelState
->request
->hier
.stopPeerClock(false);
247 if (tunnelState
->noConnections()) {
248 // ConnStateData pipeline should contain the CONNECT we are performing
249 // but it may be invalid already (bug 4392)
250 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn()) {
251 auto ctx
= tunnelState
->http
->getConn()->pipeline
.front();
259 if (!tunnelState
->client
.writer
) {
260 tunnelState
->client
.conn
->close();
266 tunnelClientClosed(const CommCloseCbParams
¶ms
)
268 TunnelStateData
*tunnelState
= (TunnelStateData
*)params
.data
;
269 debugs(26, 3, HERE
<< tunnelState
->client
.conn
);
270 tunnelState
->client
.conn
= NULL
;
271 tunnelState
->client
.writer
= NULL
;
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
->server
.writer
) {
286 tunnelState
->server
.conn
->close();
291 TunnelStateData::TunnelStateData(ClientHttpRequest
*clientRequest
) :
292 connectRespBuf(NULL
),
293 connectReqWriting(false),
294 started(squid_curtime
)
296 debugs(26, 3, "TunnelStateData constructed this=" << this);
297 client
.readPendingFunc
= &tunnelDelayedClientRead
;
298 server
.readPendingFunc
= &tunnelDelayedServerRead
;
300 assert(clientRequest
);
301 url
= xstrdup(clientRequest
->uri
);
302 request
= clientRequest
->request
;
303 server
.size_ptr
= &clientRequest
->out
.size
;
304 client
.size_ptr
= &clientRequest
->al
->http
.clientRequestSz
.payloadData
;
305 status_ptr
= &clientRequest
->al
->http
.code
;
306 logTag_ptr
= &clientRequest
->logType
;
307 al
= clientRequest
->al
;
308 http
= clientRequest
;
310 client
.conn
= clientRequest
->getConn()->clientConnection
;
311 comm_add_close_handler(client
.conn
->fd
, tunnelClientClosed
, this);
313 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
314 CommTimeoutCbPtrFun(tunnelTimeout
, this));
315 commSetConnTimeout(client
.conn
, Config
.Timeout
.lifetime
, timeoutCall
);
318 TunnelStateData::~TunnelStateData()
320 debugs(26, 3, "TunnelStateData destructed this=" << this);
321 assert(noConnections());
323 serverDestinations
.clear();
324 delete connectRespBuf
;
327 TunnelStateData::Connection::~Connection()
330 eventDelete(readPendingFunc
, readPending
);
336 TunnelStateData::Connection::bytesWanted(int lowerbound
, int upperbound
) const
339 return delayId
.bytesWanted(lowerbound
, upperbound
);
347 TunnelStateData::Connection::bytesIn(int const &count
)
349 debugs(26, 3, HERE
<< "len=" << len
<< " + count=" << count
);
351 delayId
.bytesIn(count
);
358 TunnelStateData::Connection::debugLevelForError(int const xerrno
) const
362 if (xerrno
== ECONNRESET
)
367 if (ignoreErrno(xerrno
))
373 /* Read from server side and queue it for writing to the client */
375 TunnelStateData::ReadServer(const Comm::ConnectionPointer
&c
, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
377 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
378 assert(cbdataReferenceValid(tunnelState
));
379 debugs(26, 3, HERE
<< c
);
381 tunnelState
->readServer(buf
, len
, errcode
, xerrno
);
385 TunnelStateData::readServer(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
387 debugs(26, 3, HERE
<< server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
388 server
.delayedLoops
=0;
391 * Bail out early on Comm::ERR_CLOSING
392 * - close handlers will tidy up for us
395 if (errcode
== Comm::ERR_CLOSING
)
400 statCounter
.server
.all
.kbytes_in
+= len
;
401 statCounter
.server
.other
.kbytes_in
+= len
;
404 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
405 copy(len
, server
, client
, WriteClientDone
);
408 /// Called when we read [a part of] CONNECT response from the peer
410 TunnelStateData::readConnectResponseDone(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
412 debugs(26, 3, server
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
413 assert(waitingForConnectResponse());
415 if (errcode
== Comm::ERR_CLOSING
)
419 connectRespBuf
->appended(len
);
421 statCounter
.server
.all
.kbytes_in
+= len
;
422 statCounter
.server
.other
.kbytes_in
+= len
;
425 if (keepGoingAfterRead(len
, errcode
, xerrno
, server
, client
))
426 handleConnectResponse(len
);
430 TunnelStateData::informUserOfPeerError(const char *errMsg
, const size_t sz
)
435 *logTag_ptr
= LOG_TCP_TUNNEL
;
437 if (!clientExpectsConnectResponse()) {
438 // closing the connection is the best we can do here
439 debugs(50, 3, server
.conn
<< " closing on error: " << errMsg
);
440 server
.conn
->close();
444 // if we have no reply suitable to relay, use 502 Bad Gateway
445 if (!sz
|| sz
> static_cast<size_t>(connectRespBuf
->contentSize())) {
446 ErrorState
*err
= new ErrorState(ERR_CONNECT_FAIL
, Http::scBadGateway
, request
.getRaw());
447 *status_ptr
= Http::scBadGateway
;
448 err
->callback
= tunnelErrorComplete
;
449 err
->callback_data
= this;
450 errorSend(http
->getConn()->clientConnection
, err
);
454 // if we need to send back the server response. write its headers to the client
456 memcpy(server
.buf
, connectRespBuf
->content(), server
.len
);
457 copy(server
.len
, server
, client
, TunnelStateData::WriteClientDone
);
458 // then close the server FD to prevent any relayed keep-alive causing CVE-2015-5400
459 server
.closeIfOpen();
462 /* Read from client side and queue it for writing to the server */
464 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
466 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
467 assert (cbdataReferenceValid (tunnelState
));
469 tunnelState
->readConnectResponseDone(buf
, len
, errcode
, xerrno
);
472 /// Parses [possibly incomplete] CONNECT response and reacts to it.
473 /// If the tunnel is being closed or more response data is needed, returns false.
474 /// Otherwise, the caller should handle the remaining read data, if any.
476 TunnelStateData::handleConnectResponse(const size_t chunkSize
)
478 assert(waitingForConnectResponse());
480 // Ideally, client and server should use MemBuf or better, but current code
481 // never accumulates more than one read when shoveling data (XXX) so it does
482 // not need to deal with MemBuf complexity. To keep it simple, we use a
483 // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
484 // is optimized, reuse server.buf for CONNEC response accumulation instead.
486 /* mimic the basic parts of HttpStateData::processReplyHeader() */
488 Http::StatusCode parseErr
= Http::scNone
;
489 const bool eof
= !chunkSize
;
490 connectRespBuf
->terminate(); // HttpMsg::parse requires terminated string
491 const bool parsed
= rep
.parse(connectRespBuf
->content(), connectRespBuf
->contentSize(), eof
, &parseErr
);
493 if (parseErr
> 0) { // unrecoverable parsing error
494 informUserOfPeerError("malformed CONNECT response from peer", 0);
502 if (!connectRespBuf
->hasSpace()) {
503 informUserOfPeerError("huge CONNECT response from peer", 0);
508 readConnectResponse();
512 // CONNECT response was successfully parsed
513 *status_ptr
= rep
.sline
.status();
515 // we need to relay the 401/407 responses when login=PASS(THRU)
516 const char *pwd
= server
.conn
->getPeer()->login
;
517 const bool relay
= pwd
&& (strcmp(pwd
, "PASS") == 0 || strcmp(pwd
, "PASSTHRU") == 0) &&
518 (*status_ptr
== Http::scProxyAuthenticationRequired
||
519 *status_ptr
== Http::scUnauthorized
);
521 // bail if we did not get an HTTP 200 (Connection Established) response
522 if (rep
.sline
.status() != Http::scOkay
) {
523 // if we ever decide to reuse the peer connection, we must extract the error response first
524 informUserOfPeerError("unsupported CONNECT response status code", (relay
? rep
.hdr_sz
: 0));
528 if (rep
.hdr_sz
< connectRespBuf
->contentSize()) {
529 // preserve bytes that the server already sent after the CONNECT response
530 server
.len
= connectRespBuf
->contentSize() - rep
.hdr_sz
;
531 memcpy(server
.buf
, connectRespBuf
->content()+rep
.hdr_sz
, server
.len
);
533 // reset; delay pools were using this field to throttle CONNECT response
537 delete connectRespBuf
;
538 connectRespBuf
= NULL
;
539 connectExchangeCheckpoint();
543 TunnelStateData::Connection::error(int const xerrno
)
545 debugs(50, debugLevelForError(xerrno
), HERE
<< conn
<< ": read/write failure: " << xstrerr(xerrno
));
547 if (!ignoreErrno(xerrno
))
551 /* Read from client side and queue it for writing to the server */
553 TunnelStateData::ReadClient(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag errcode
, int xerrno
, void *data
)
555 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
556 assert (cbdataReferenceValid (tunnelState
));
558 tunnelState
->readClient(buf
, len
, errcode
, xerrno
);
562 TunnelStateData::readClient(char *, size_t len
, Comm::Flag errcode
, int xerrno
)
564 debugs(26, 3, HERE
<< client
.conn
<< ", read " << len
<< " bytes, err=" << errcode
);
565 client
.delayedLoops
=0;
568 * Bail out early on Comm::ERR_CLOSING
569 * - close handlers will tidy up for us
572 if (errcode
== Comm::ERR_CLOSING
)
577 statCounter
.client_http
.kbytes_in
+= len
;
580 if (keepGoingAfterRead(len
, errcode
, xerrno
, client
, server
))
581 copy(len
, client
, server
, WriteServerDone
);
584 /// Updates state after reading from client or server.
585 /// Returns whether the caller should use the data just read.
587 TunnelStateData::keepGoingAfterRead(size_t len
, Comm::Flag errcode
, int xerrno
, Connection
&from
, Connection
&to
)
589 debugs(26, 3, HERE
<< "from={" << from
.conn
<< "}, to={" << to
.conn
<< "}");
591 /* I think this is to prevent free-while-in-a-callback behaviour
593 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
595 const CbcPointer
<TunnelStateData
> safetyLock(this);
597 /* Bump the source connection read timeout on any activity */
598 if (Comm::IsConnOpen(from
.conn
)) {
599 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
600 CommTimeoutCbPtrFun(tunnelTimeout
, this));
601 commSetConnTimeout(from
.conn
, Config
.Timeout
.read
, timeoutCall
);
604 /* Bump the dest connection read timeout on any activity */
605 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
606 if (Comm::IsConnOpen(to
.conn
)) {
607 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
608 CommTimeoutCbPtrFun(tunnelTimeout
, this));
609 commSetConnTimeout(to
.conn
, Config
.Timeout
.read
, timeoutCall
);
614 else if (len
== 0 || !Comm::IsConnOpen(to
.conn
)) {
615 debugs(26, 3, HERE
<< "Nothing to write or client gone. Terminate the tunnel.");
618 /* Only close the remote end if we've finished queueing data to it */
619 if (from
.len
== 0 && Comm::IsConnOpen(to
.conn
) ) {
622 } else if (cbdataReferenceValid(this)) {
630 TunnelStateData::copy(size_t len
, Connection
&from
, Connection
&to
, IOCB
*completion
)
632 debugs(26, 3, HERE
<< "Schedule Write");
633 AsyncCall::Pointer call
= commCbCall(5,5, "TunnelBlindCopyWriteHandler",
634 CommIoCbPtrFun(completion
, this));
635 to
.write(from
.buf
, len
, call
, NULL
);
638 /* Writes data from the client buffer to the server side */
640 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
642 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
643 assert (cbdataReferenceValid (tunnelState
));
644 tunnelState
->server
.writer
= NULL
;
646 tunnelState
->writeServerDone(buf
, len
, flag
, xerrno
);
650 TunnelStateData::writeServerDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
652 debugs(26, 3, HERE
<< server
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
655 if (flag
!= Comm::OK
) {
656 if (flag
!= Comm::ERR_CLOSING
) {
657 debugs(26, 4, HERE
<< "calling TunnelStateData::server.error(" << xerrno
<<")");
658 server
.error(xerrno
); // may call comm_close
665 debugs(26, 4, HERE
<< "No read input. Closing server connection.");
666 server
.conn
->close();
671 statCounter
.server
.all
.kbytes_out
+= len
;
672 statCounter
.server
.other
.kbytes_out
+= len
;
673 client
.dataSent(len
);
675 /* If the other end has closed, so should we */
676 if (!Comm::IsConnOpen(client
.conn
)) {
677 debugs(26, 4, HERE
<< "Client gone away. Shutting down server connection.");
678 server
.conn
->close();
682 const CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
684 if (cbdataReferenceValid(this))
688 /* Writes data from the server buffer to the client side */
690 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer
&, char *buf
, size_t len
, Comm::Flag flag
, int xerrno
, void *data
)
692 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
693 assert (cbdataReferenceValid (tunnelState
));
694 tunnelState
->client
.writer
= NULL
;
696 tunnelState
->writeClientDone(buf
, len
, flag
, xerrno
);
700 TunnelStateData::Connection::dataSent(size_t amount
)
702 debugs(26, 3, HERE
<< "len=" << len
<< " - amount=" << amount
);
703 assert(amount
== (size_t)len
);
705 /* increment total object size */
712 TunnelStateData::Connection::write(const char *b
, int size
, AsyncCall::Pointer
&callback
, FREE
* free_func
)
715 Comm::Write(conn
, b
, size
, callback
, free_func
);
719 TunnelStateData::writeClientDone(char *, size_t len
, Comm::Flag flag
, int xerrno
)
721 debugs(26, 3, HERE
<< client
.conn
<< ", " << len
<< " bytes written, flag=" << flag
);
724 if (flag
!= Comm::OK
) {
725 if (flag
!= Comm::ERR_CLOSING
) {
726 debugs(26, 4, HERE
<< "Closing client connection due to comm flags.");
727 client
.error(xerrno
); // may call comm_close
734 debugs(26, 4, HERE
<< "Closing client connection due to 0 byte read.");
735 client
.conn
->close();
740 statCounter
.client_http
.kbytes_out
+= len
;
741 server
.dataSent(len
);
743 /* If the other end has closed, so should we */
744 if (!Comm::IsConnOpen(server
.conn
)) {
745 debugs(26, 4, HERE
<< "Server has gone away. Terminating client connection.");
746 client
.conn
->close();
750 CbcPointer
<TunnelStateData
> safetyLock(this); /* ??? should be locked by the caller... */
752 if (cbdataReferenceValid(this))
757 tunnelTimeout(const CommTimeoutCbParams
&io
)
759 TunnelStateData
*tunnelState
= static_cast<TunnelStateData
*>(io
.data
);
760 debugs(26, 3, HERE
<< io
.conn
);
761 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
762 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
764 tunnelState
->client
.closeIfOpen();
765 tunnelState
->server
.closeIfOpen();
769 TunnelStateData::Connection::closeIfOpen()
771 if (Comm::IsConnOpen(conn
))
776 tunnelDelayedClientRead(void *data
)
781 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
782 tunnel
->client
.readPending
= NULL
;
783 static uint64_t counter
=0;
784 debugs(26, 7, "Client read(2) delayed " << ++counter
<< " times");
785 tunnel
->copyRead(tunnel
->client
, TunnelStateData::ReadClient
);
789 tunnelDelayedServerRead(void *data
)
794 TunnelStateData
*tunnel
= static_cast<TunnelStateData
*>(data
);
795 tunnel
->server
.readPending
= NULL
;
796 static uint64_t counter
=0;
797 debugs(26, 7, "Server read(2) delayed " << ++counter
<< " times");
798 tunnel
->copyRead(tunnel
->server
, TunnelStateData::ReadServer
);
802 TunnelStateData::copyRead(Connection
&from
, IOCB
*completion
)
804 assert(from
.len
== 0);
805 // If only the minimum permitted read size is going to be attempted
806 // then we schedule an event to try again in a few I/O cycles.
807 // Allow at least 1 byte to be read every (0.3*10) seconds.
808 int bw
= from
.bytesWanted(1, SQUID_TCP_SO_RCVBUF
);
809 if (bw
== 1 && ++from
.delayedLoops
< 10) {
810 from
.readPending
= this;
811 eventAdd("tunnelDelayedServerRead", from
.readPendingFunc
, from
.readPending
, 0.3, true);
815 AsyncCall::Pointer call
= commCbCall(5,4, "TunnelBlindCopyReadHandler",
816 CommIoCbPtrFun(completion
, this));
817 comm_read(from
.conn
, from
.buf
, bw
, call
);
821 TunnelStateData::readConnectResponse()
823 assert(waitingForConnectResponse());
825 AsyncCall::Pointer call
= commCbCall(5,4, "readConnectResponseDone",
826 CommIoCbPtrFun(ReadConnectResponseDone
, this));
827 comm_read(server
.conn
, connectRespBuf
->space(),
828 server
.bytesWanted(1, connectRespBuf
->spaceSize()), call
);
832 TunnelStateData::copyClientBytes()
834 if (preReadClientData
.length()) {
835 size_t copyBytes
= preReadClientData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadClientData
.length();
836 memcpy(client
.buf
, preReadClientData
.rawContent(), copyBytes
);
837 preReadClientData
.consume(copyBytes
);
838 client
.bytesIn(copyBytes
);
839 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, client
, server
))
840 copy(copyBytes
, client
, server
, TunnelStateData::WriteServerDone
);
842 copyRead(client
, ReadClient
);
846 TunnelStateData::copyServerBytes()
848 if (preReadServerData
.length()) {
849 size_t copyBytes
= preReadServerData
.length() > SQUID_TCP_SO_RCVBUF
? SQUID_TCP_SO_RCVBUF
: preReadServerData
.length();
850 memcpy(server
.buf
, preReadServerData
.rawContent(), copyBytes
);
851 preReadServerData
.consume(copyBytes
);
852 server
.bytesIn(copyBytes
);
853 if (keepGoingAfterRead(copyBytes
, Comm::OK
, 0, server
, client
))
854 copy(copyBytes
, server
, client
, TunnelStateData::WriteClientDone
);
856 copyRead(server
, ReadServer
);
860 * Set the HTTP status for this request and sets the read handlers for client
861 * and server side connections.
864 tunnelStartShoveling(TunnelStateData
*tunnelState
)
866 assert(!tunnelState
->waitingForConnectExchange());
867 *tunnelState
->status_ptr
= Http::scOkay
;
868 if (tunnelState
->logTag_ptr
)
869 *tunnelState
->logTag_ptr
= LOG_TCP_TUNNEL
;
870 if (cbdataReferenceValid(tunnelState
)) {
872 // Shovel any payload already pushed into reply buffer by the server response
873 if (!tunnelState
->server
.len
)
874 tunnelState
->copyServerBytes();
876 debugs(26, DBG_DATA
, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState
->server
.buf
, tunnelState
->server
.len
) << "\n----------");
877 tunnelState
->copy(tunnelState
->server
.len
, tunnelState
->server
, tunnelState
->client
, TunnelStateData::WriteClientDone
);
880 if (tunnelState
->http
.valid() && tunnelState
->http
->getConn() && !tunnelState
->http
->getConn()->inBuf
.isEmpty()) {
881 SBuf
* const in
= &tunnelState
->http
->getConn()->inBuf
;
882 debugs(26, DBG_DATA
, "Tunnel client PUSH Payload: \n" << *in
<< "\n----------");
883 tunnelState
->preReadClientData
.append(*in
);
884 in
->consume(); // ConnStateData buffer accounting after the shuffle.
886 tunnelState
->copyClientBytes();
891 * All the pieces we need to write to client and/or server connection
893 * Call the tunnelStartShoveling to start the blind pump.
896 tunnelConnectedWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t, Comm::Flag flag
, int, void *data
)
898 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
899 debugs(26, 3, HERE
<< conn
<< ", flag=" << flag
);
900 tunnelState
->client
.writer
= NULL
;
902 if (flag
!= Comm::OK
) {
903 *tunnelState
->status_ptr
= Http::scInternalServerError
;
904 tunnelErrorComplete(conn
->fd
, data
, 0);
908 tunnelStartShoveling(tunnelState
);
911 /// Called when we are done writing CONNECT request to a peer.
913 tunnelConnectReqWriteDone(const Comm::ConnectionPointer
&conn
, char *, size_t, Comm::Flag flag
, int, void *data
)
915 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
916 debugs(26, 3, conn
<< ", flag=" << flag
);
917 tunnelState
->server
.writer
= NULL
;
918 assert(tunnelState
->waitingForConnectRequest());
920 if (flag
!= Comm::OK
) {
921 *tunnelState
->status_ptr
= Http::scInternalServerError
;
922 tunnelErrorComplete(conn
->fd
, data
, 0);
926 tunnelState
->connectReqWriting
= false;
927 tunnelState
->connectExchangeCheckpoint();
931 TunnelStateData::connectExchangeCheckpoint()
933 if (waitingForConnectResponse()) {
934 debugs(26, 5, "still reading CONNECT response on " << server
.conn
);
935 } else if (waitingForConnectRequest()) {
936 debugs(26, 5, "still writing CONNECT request on " << server
.conn
);
938 assert(!waitingForConnectExchange());
939 debugs(26, 3, "done with CONNECT exchange on " << server
.conn
);
940 tunnelConnected(server
.conn
, this);
945 * handle the write completion from a proxy request to an upstream origin
948 tunnelConnected(const Comm::ConnectionPointer
&server
, void *data
)
950 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
951 debugs(26, 3, HERE
<< server
<< ", tunnelState=" << tunnelState
);
953 if (!tunnelState
->clientExpectsConnectResponse())
954 tunnelStartShoveling(tunnelState
); // ssl-bumped connection, be quiet
956 AsyncCall::Pointer call
= commCbCall(5,5, "tunnelConnectedWriteDone",
957 CommIoCbPtrFun(tunnelConnectedWriteDone
, tunnelState
));
958 tunnelState
->client
.write(conn_established
, strlen(conn_established
), call
, NULL
);
963 tunnelErrorComplete(int fd
/*const Comm::ConnectionPointer &*/, void *data
, size_t)
965 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
966 debugs(26, 3, HERE
<< "FD " << fd
);
967 assert(tunnelState
!= NULL
);
968 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
969 CbcPointer
<TunnelStateData
> safetyLock(tunnelState
);
971 if (Comm::IsConnOpen(tunnelState
->client
.conn
))
972 tunnelState
->client
.conn
->close();
974 if (Comm::IsConnOpen(tunnelState
->server
.conn
))
975 tunnelState
->server
.conn
->close();
979 tunnelConnectDone(const Comm::ConnectionPointer
&conn
, Comm::Flag status
, int xerrno
, void *data
)
981 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
983 if (status
!= Comm::OK
) {
984 debugs(26, 4, HERE
<< conn
<< ", comm failure recovery.");
985 /* At this point only the TCP handshake has failed. no data has been passed.
986 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
988 debugs(26, 4, "removing server 1 of " << tunnelState
->serverDestinations
.size() <<
989 " from destinations (" << tunnelState
->serverDestinations
[0] << ")");
990 tunnelState
->serverDestinations
.erase(tunnelState
->serverDestinations
.begin());
991 time_t fwdTimeout
= tunnelState
->started
+ Config
.Timeout
.forward
;
992 if (fwdTimeout
> squid_curtime
&& tunnelState
->serverDestinations
.size() > 0) {
993 // find remaining forward_timeout available for this attempt
994 fwdTimeout
-= squid_curtime
;
995 if (fwdTimeout
> Config
.Timeout
.connect
)
996 fwdTimeout
= Config
.Timeout
.connect
;
997 /* Try another IP of this destination host */
998 GetMarkingsToServer(tunnelState
->request
.getRaw(), *tunnelState
->serverDestinations
[0]);
999 debugs(26, 4, HERE
<< "retry with : " << tunnelState
->serverDestinations
[0]);
1000 AsyncCall::Pointer call
= commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone
, tunnelState
));
1001 Comm::ConnOpener
*cs
= new Comm::ConnOpener(tunnelState
->serverDestinations
[0], call
, fwdTimeout
);
1002 cs
->setHost(tunnelState
->url
);
1003 AsyncJob::Start(cs
);
1005 debugs(26, 4, HERE
<< "terminate with error.");
1006 ErrorState
*err
= new ErrorState(ERR_CONNECT_FAIL
, Http::scServiceUnavailable
, tunnelState
->request
.getRaw());
1007 *tunnelState
->status_ptr
= Http::scServiceUnavailable
;
1008 err
->xerrno
= xerrno
;
1009 // on timeout is this still: err->xerrno = ETIMEDOUT;
1010 err
->port
= conn
->remote
.port();
1011 err
->callback
= tunnelErrorComplete
;
1012 err
->callback_data
= tunnelState
;
1013 errorSend(tunnelState
->client
.conn
, err
);
1014 if (tunnelState
->request
!= NULL
)
1015 tunnelState
->request
->hier
.stopPeerClock(false);
1021 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1022 if (conn
->getPeer() && conn
->getPeer()->options
.no_delay
)
1023 tunnelState
->server
.setDelayId(DelayId());
1026 tunnelState
->request
->hier
.note(conn
, tunnelState
->getHost());
1028 tunnelState
->server
.conn
= conn
;
1029 tunnelState
->request
->peer_host
= conn
->getPeer() ? conn
->getPeer()->host
: NULL
;
1030 comm_add_close_handler(conn
->fd
, tunnelServerClosed
, tunnelState
);
1032 debugs(26, 4, HERE
<< "determine post-connect handling pathway.");
1033 if (conn
->getPeer()) {
1034 tunnelState
->request
->peer_login
= conn
->getPeer()->login
;
1035 tunnelState
->request
->peer_domain
= conn
->getPeer()->domain
;
1036 tunnelState
->request
->flags
.auth_no_keytab
= conn
->getPeer()->options
.auth_no_keytab
;
1037 tunnelState
->request
->flags
.proxying
= !(conn
->getPeer()->options
.originserver
);
1039 tunnelState
->request
->peer_login
= NULL
;
1040 tunnelState
->request
->peer_domain
= NULL
;
1041 tunnelState
->request
->flags
.auth_no_keytab
= false;
1042 tunnelState
->request
->flags
.proxying
= false;
1045 if (tunnelState
->request
->flags
.proxying
)
1046 tunnelState
->connectToPeer();
1048 tunnelConnected(conn
, tunnelState
);
1051 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1052 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1053 commSetConnTimeout(conn
, Config
.Timeout
.read
, timeoutCall
);
1057 tunnelStart(ClientHttpRequest
* http
)
1059 debugs(26, 3, HERE
);
1060 /* Create state structure. */
1061 TunnelStateData
*tunnelState
= NULL
;
1062 ErrorState
*err
= NULL
;
1063 HttpRequest
*request
= http
->request
;
1064 char *url
= http
->uri
;
1067 * client_addr.isNoAddr() indicates this is an "internal" request
1068 * from peer_digest.c, asn.c, netdb.c, etc and should always
1069 * be allowed. yuck, I know.
1072 if (Config
.accessList
.miss
&& !request
->client_addr
.isNoAddr()) {
1074 * Check if this host is allowed to fetch MISSES from us (miss_access)
1075 * default is to allow.
1077 ACLFilledChecklist
ch(Config
.accessList
.miss
, request
, NULL
);
1078 ch
.src_addr
= request
->client_addr
;
1079 ch
.my_addr
= request
->my_addr
;
1080 if (ch
.fastCheck() == ACCESS_DENIED
) {
1081 debugs(26, 4, HERE
<< "MISS access forbidden.");
1082 err
= new ErrorState(ERR_FORWARDING_DENIED
, Http::scForbidden
, request
);
1083 http
->al
->http
.code
= Http::scForbidden
;
1084 errorSend(http
->getConn()->clientConnection
, err
);
1089 debugs(26, 3, request
->method
<< ' ' << url
<< ' ' << request
->http_ver
);
1090 ++statCounter
.server
.all
.requests
;
1091 ++statCounter
.server
.other
.requests
;
1093 tunnelState
= new TunnelStateData(http
);
1095 //server.setDelayId called from tunnelConnectDone after server side connection established
1098 peerSelect(&(tunnelState
->serverDestinations
), request
, http
->al
,
1100 tunnelPeerSelectComplete
,
1105 TunnelStateData::connectToPeer()
1107 if (CachePeer
*p
= server
.conn
->getPeer()) {
1108 if (p
->secure
.encryptTransport
) {
1109 AsyncCall::Pointer callback
= asyncCall(5,4,
1110 "TunnelStateData::ConnectedToPeer",
1111 MyAnswerDialer(&TunnelStateData::connectedToPeer
, this));
1112 auto *connector
= new Security::BlindPeerConnector(request
, server
.conn
, callback
, al
);
1113 AsyncJob::Start(connector
); // will call our callback
1118 Security::EncryptorAnswer nil
;
1119 connectedToPeer(nil
);
1123 TunnelStateData::connectedToPeer(Security::EncryptorAnswer
&answer
)
1125 if (ErrorState
*error
= answer
.error
.get()) {
1126 *status_ptr
= error
->httpStatus
;
1127 error
->callback
= tunnelErrorComplete
;
1128 error
->callback_data
= this;
1129 errorSend(client
.conn
, error
);
1130 answer
.error
.clear(); // preserve error for errorSendComplete()
1134 tunnelRelayConnectRequest(server
.conn
, this);
1138 tunnelRelayConnectRequest(const Comm::ConnectionPointer
&srv
, void *data
)
1140 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1141 assert(!tunnelState
->waitingForConnectExchange());
1142 HttpHeader
hdr_out(hoRequest
);
1143 Http::StateFlags flags
;
1144 debugs(26, 3, HERE
<< srv
<< ", tunnelState=" << tunnelState
);
1145 memset(&flags
, '\0', sizeof(flags
));
1146 flags
.proxying
= tunnelState
->request
->flags
.proxying
;
1149 mb
.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState
->url
);
1150 HttpStateData::httpBuildRequestHeader(tunnelState
->request
.getRaw(),
1151 NULL
, /* StoreEntry */
1152 tunnelState
->al
, /* AccessLogEntry */
1155 hdr_out
.packInto(&mb
);
1157 mb
.append("\r\n", 2);
1159 debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState
->server
.conn
<<
1160 ":\n----------\n" << mb
.buf
<< "\n----------");
1162 AsyncCall::Pointer writeCall
= commCbCall(5,5, "tunnelConnectReqWriteDone",
1163 CommIoCbPtrFun(tunnelConnectReqWriteDone
,
1166 tunnelState
->server
.write(mb
.buf
, mb
.size
, writeCall
, mb
.freeFunc());
1167 tunnelState
->connectReqWriting
= true;
1169 tunnelState
->connectRespBuf
= new MemBuf
;
1170 // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1171 // can hold since any CONNECT response leftovers have to fit into server.buf.
1172 // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
1173 tunnelState
->connectRespBuf
->init(SQUID_TCP_SO_RCVBUF
, 2*SQUID_TCP_SO_RCVBUF
);
1174 tunnelState
->readConnectResponse();
1176 assert(tunnelState
->waitingForConnectExchange());
1178 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1179 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1180 commSetConnTimeout(srv
, Config
.Timeout
.read
, timeoutCall
);
1183 static Comm::ConnectionPointer
1184 borrowPinnedConnection(HttpRequest
*request
, Comm::ConnectionPointer
&serverDestination
)
1186 // pinned_connection may become nil after a pconn race
1187 if (ConnStateData
*pinned_connection
= request
? request
->pinnedConnection() : nullptr) {
1188 Comm::ConnectionPointer serverConn
= pinned_connection
->borrowPinnedConnection(request
, serverDestination
->getPeer());
1196 tunnelPeerSelectComplete(Comm::ConnectionList
*peer_paths
, ErrorState
*err
, void *data
)
1198 TunnelStateData
*tunnelState
= (TunnelStateData
*)data
;
1201 if (!peer_paths
|| peer_paths
->empty()) {
1202 debugs(26, 3, HERE
<< "No paths found. Aborting CONNECT");
1206 if (!bail
&& tunnelState
->serverDestinations
[0]->peerType
== PINNED
) {
1207 Comm::ConnectionPointer serverConn
= borrowPinnedConnection(tunnelState
->request
.getRaw(), tunnelState
->serverDestinations
[0]);
1208 debugs(26,7, "pinned peer connection: " << serverConn
);
1209 if (Comm::IsConnOpen(serverConn
)) {
1210 tunnelConnectDone(serverConn
, Comm::OK
, 0, (void *)tunnelState
);
1218 err
= new ErrorState(ERR_CANNOT_FORWARD
, Http::scServiceUnavailable
, tunnelState
->request
.getRaw());
1220 *tunnelState
->status_ptr
= err
->httpStatus
;
1221 err
->callback
= tunnelErrorComplete
;
1222 err
->callback_data
= tunnelState
;
1223 errorSend(tunnelState
->client
.conn
, err
);
1228 GetMarkingsToServer(tunnelState
->request
.getRaw(), *tunnelState
->serverDestinations
[0]);
1230 if (tunnelState
->request
!= NULL
)
1231 tunnelState
->request
->hier
.startPeerClock();
1233 debugs(26, 3, HERE
<< "paths=" << peer_paths
->size() << ", p[0]={" << (*peer_paths
)[0] << "}, serverDest[0]={" <<
1234 tunnelState
->serverDestinations
[0] << "}");
1236 AsyncCall::Pointer call
= commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone
, tunnelState
));
1237 Comm::ConnOpener
*cs
= new Comm::ConnOpener(tunnelState
->serverDestinations
[0], call
, Config
.Timeout
.connect
);
1238 cs
->setHost(tunnelState
->url
);
1239 AsyncJob::Start(cs
);
1242 CBDATA_CLASS_INIT(TunnelStateData
);
1245 TunnelStateData::noConnections() const
1247 return !Comm::IsConnOpen(server
.conn
) && !Comm::IsConnOpen(client
.conn
);
1252 TunnelStateData::Connection::setDelayId(DelayId
const &newDelay
)
1261 switchToTunnel(HttpRequest
*request
, Comm::ConnectionPointer
&clientConn
, Comm::ConnectionPointer
&srvConn
)
1263 debugs(26,5, "Revert to tunnel FD " << clientConn
->fd
<< " with FD " << srvConn
->fd
);
1265 /* Create state structure. */
1266 ++statCounter
.server
.all
.requests
;
1267 ++statCounter
.server
.other
.requests
;
1269 auto conn
= request
->clientConnectionManager
.get();
1271 Http::StreamPointer context
= conn
->pipeline
.front();
1272 Must(context
&& context
->http
);
1274 debugs(26, 3, request
->method
<< " " << context
->http
->uri
<< " " << request
->http_ver
);
1276 TunnelStateData
*tunnelState
= new TunnelStateData(context
->http
);
1278 fd_table
[clientConn
->fd
].read_method
= &default_read_method
;
1279 fd_table
[clientConn
->fd
].write_method
= &default_write_method
;
1281 request
->hier
.note(srvConn
, tunnelState
->getHost());
1283 tunnelState
->server
.conn
= srvConn
;
1286 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1287 if (srvConn
->getPeer() && srvConn
->getPeer()->options
.no_delay
)
1288 tunnelState
->server
.setDelayId(DelayId::DelayClient(context
->http
));
1291 request
->peer_host
= srvConn
->getPeer() ? srvConn
->getPeer()->host
: nullptr;
1292 comm_add_close_handler(srvConn
->fd
, tunnelServerClosed
, tunnelState
);
1294 debugs(26, 4, "determine post-connect handling pathway.");
1295 if (srvConn
->getPeer()) {
1296 request
->peer_login
= srvConn
->getPeer()->login
;
1297 request
->peer_domain
= srvConn
->getPeer()->domain
;
1298 request
->flags
.auth_no_keytab
= srvConn
->getPeer()->options
.auth_no_keytab
;
1299 request
->flags
.proxying
= !(srvConn
->getPeer()->options
.originserver
);
1301 request
->peer_login
= nullptr;
1302 request
->peer_domain
= nullptr;
1303 request
->flags
.auth_no_keytab
= false;
1304 request
->flags
.proxying
= false;
1307 AsyncCall::Pointer timeoutCall
= commCbCall(5, 4, "tunnelTimeout",
1308 CommTimeoutCbPtrFun(tunnelTimeout
, tunnelState
));
1309 commSetConnTimeout(srvConn
, Config
.Timeout
.read
, timeoutCall
);
1310 fd_table
[srvConn
->fd
].read_method
= &default_read_method
;
1311 fd_table
[srvConn
->fd
].write_method
= &default_write_method
;
1313 auto ssl
= fd_table
[srvConn
->fd
].ssl
.get();
1315 BIO
*b
= SSL_get_rbio(ssl
);
1316 Ssl::ServerBio
*srvBio
= static_cast<Ssl::ServerBio
*>(b
->ptr
);
1317 tunnelState
->preReadServerData
= srvBio
->rBufData();
1318 tunnelStartShoveling(tunnelState
);
1320 #endif //USE_OPENSSL