]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tunnel.cc
abece760fe381b0a3cdd362f959d0ad1e72a690e
[thirdparty/squid.git] / src / tunnel.cc
1 /*
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 26 Secure Sockets Layer Proxy */
10
11 #include "squid.h"
12 #include "acl/FilledChecklist.h"
13 #include "base/CbcPointer.h"
14 #include "CachePeer.h"
15 #include "cbdata.h"
16 #include "client_side.h"
17 #include "client_side_request.h"
18 #include "comm.h"
19 #include "comm/Connection.h"
20 #include "comm/ConnOpener.h"
21 #include "comm/Read.h"
22 #include "comm/Write.h"
23 #include "errorpage.h"
24 #include "fd.h"
25 #include "fde.h"
26 #include "FwdState.h"
27 #include "globals.h"
28 #include "http.h"
29 #include "http/Stream.h"
30 #include "HttpRequest.h"
31 #include "ip/QosConfig.h"
32 #include "LogTags.h"
33 #include "MemBuf.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"
40 #if USE_OPENSSL
41 #include "ssl/bio.h"
42 #include "ssl/ServerBump.h"
43 #endif
44 #include "tools.h"
45 #if USE_DELAY_POOLS
46 #include "DelayId.h"
47 #endif
48
49 #include <climits>
50 #include <cerrno>
51
52 /**
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.
56 */
57 /*
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.
62 *
63 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
64 */
65 class TunnelStateData
66 {
67 CBDATA_CLASS(TunnelStateData);
68
69 public:
70 TunnelStateData(ClientHttpRequest *);
71 ~TunnelStateData();
72 TunnelStateData(const TunnelStateData &); // do not implement
73 TunnelStateData &operator =(const TunnelStateData &); // do not implement
74
75 class Connection;
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);
80
81 /// Starts reading peer response to our CONNECT request.
82 void readConnectResponse();
83
84 /// Called when we may be done handling a CONNECT exchange with the peer.
85 void connectExchangeCheckpoint();
86
87 bool noConnections() const;
88 char *url;
89 CbcPointer<ClientHttpRequest> http;
90 HttpRequest::Pointer request;
91 AccessLogEntryPointer al;
92 Comm::ConnectionList serverDestinations;
93
94 const char * getHost() const {
95 return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->url.host());
96 };
97
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(); }
104
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)
110 return false;
111 #if USE_OPENSSL
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)
114 return false;
115 #endif
116 return !(request != NULL &&
117 (request->flags.interceptTproxy || request->flags.intercepted));
118 }
119
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);
123
124 class Connection
125 {
126
127 public:
128 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), delayedLoops(0),
129 readPending(NULL), readPendingFunc(NULL) {}
130
131 ~Connection();
132
133 int bytesWanted(int lower=0, int upper = INT_MAX) const;
134 void bytesIn(int const &);
135 #if USE_DELAY_POOLS
136
137 void setDelayId(DelayId const &);
138 #endif
139
140 void error(int const xerrno);
141 int debugLevelForError(int const xerrno) const;
142 void closeIfOpen();
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);
146 int len;
147 char *buf;
148 AsyncCall::Pointer writer; ///< pending Comm::Write callback
149 uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
150
151 Comm::ConnectionPointer conn; ///< The currently connected connection.
152 uint8_t delayedLoops; ///< how many times a read on this connection has been postponed.
153
154 // XXX: make these an AsyncCall when event API can handle them
155 TunnelStateData *readPending;
156 EVH *readPendingFunc;
157 private:
158 #if USE_DELAY_POOLS
159
160 DelayId delayId;
161 #endif
162
163 };
164
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.
173
174 void copyRead(Connection &from, IOCB *completion);
175
176 /// continue to set up connection to a peer, going async for SSL peers
177 void connectToPeer();
178
179 private:
180 /// Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
181 class MyAnswerDialer: public CallDialer, public Security::PeerConnector::CbDialer
182 {
183 public:
184 typedef void (TunnelStateData::*Method)(Security::EncryptorAnswer &);
185
186 MyAnswerDialer(Method method, TunnelStateData *tunnel):
187 method_(method), tunnel_(tunnel), answer_() {}
188
189 /* CallDialer API */
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_ << ')';
194 }
195
196 /* Security::PeerConnector::CbDialer API */
197 virtual Security::EncryptorAnswer &answer() { return answer_; }
198
199 private:
200 Method method_;
201 CbcPointer<TunnelStateData> tunnel_;
202 Security::EncryptorAnswer answer_;
203 };
204
205 /// callback handler after connection setup (including any encryption)
206 void connectedToPeer(Security::EncryptorAnswer &answer);
207
208 public:
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);
216
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();
221 };
222
223 static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
224
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 *);
235
236 static void
237 tunnelServerClosed(const CommCloseCbParams &params)
238 {
239 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
240 debugs(26, 3, HERE << tunnelState->server.conn);
241 tunnelState->server.conn = NULL;
242 tunnelState->server.writer = NULL;
243
244 if (tunnelState->request != NULL)
245 tunnelState->request->hier.stopPeerClock(false);
246
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();
252 if (ctx != nullptr)
253 ctx->finished();
254 }
255 delete tunnelState;
256 return;
257 }
258
259 if (!tunnelState->client.writer) {
260 tunnelState->client.conn->close();
261 return;
262 }
263 }
264
265 static void
266 tunnelClientClosed(const CommCloseCbParams &params)
267 {
268 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
269 debugs(26, 3, HERE << tunnelState->client.conn);
270 tunnelState->client.conn = NULL;
271 tunnelState->client.writer = NULL;
272
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();
278 if (ctx != nullptr)
279 ctx->finished();
280 }
281 delete tunnelState;
282 return;
283 }
284
285 if (!tunnelState->server.writer) {
286 tunnelState->server.conn->close();
287 return;
288 }
289 }
290
291 TunnelStateData::TunnelStateData(ClientHttpRequest *clientRequest) :
292 connectRespBuf(NULL),
293 connectReqWriting(false),
294 started(squid_curtime)
295 {
296 debugs(26, 3, "TunnelStateData constructed this=" << this);
297 client.readPendingFunc = &tunnelDelayedClientRead;
298 server.readPendingFunc = &tunnelDelayedServerRead;
299
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;
309
310 client.conn = clientRequest->getConn()->clientConnection;
311 comm_add_close_handler(client.conn->fd, tunnelClientClosed, this);
312
313 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
314 CommTimeoutCbPtrFun(tunnelTimeout, this));
315 commSetConnTimeout(client.conn, Config.Timeout.lifetime, timeoutCall);
316 }
317
318 TunnelStateData::~TunnelStateData()
319 {
320 debugs(26, 3, "TunnelStateData destructed this=" << this);
321 assert(noConnections());
322 xfree(url);
323 serverDestinations.clear();
324 delete connectRespBuf;
325 }
326
327 TunnelStateData::Connection::~Connection()
328 {
329 if (readPending)
330 eventDelete(readPendingFunc, readPending);
331
332 safe_free(buf);
333 }
334
335 int
336 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
337 {
338 #if USE_DELAY_POOLS
339 return delayId.bytesWanted(lowerbound, upperbound);
340 #else
341
342 return upperbound;
343 #endif
344 }
345
346 void
347 TunnelStateData::Connection::bytesIn(int const &count)
348 {
349 debugs(26, 3, HERE << "len=" << len << " + count=" << count);
350 #if USE_DELAY_POOLS
351 delayId.bytesIn(count);
352 #endif
353
354 len += count;
355 }
356
357 int
358 TunnelStateData::Connection::debugLevelForError(int const xerrno) const
359 {
360 #ifdef ECONNRESET
361
362 if (xerrno == ECONNRESET)
363 return 2;
364
365 #endif
366
367 if (ignoreErrno(xerrno))
368 return 3;
369
370 return 1;
371 }
372
373 /* Read from server side and queue it for writing to the client */
374 void
375 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
376 {
377 TunnelStateData *tunnelState = (TunnelStateData *)data;
378 assert(cbdataReferenceValid(tunnelState));
379 debugs(26, 3, HERE << c);
380
381 tunnelState->readServer(buf, len, errcode, xerrno);
382 }
383
384 void
385 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
386 {
387 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
388 server.delayedLoops=0;
389
390 /*
391 * Bail out early on Comm::ERR_CLOSING
392 * - close handlers will tidy up for us
393 */
394
395 if (errcode == Comm::ERR_CLOSING)
396 return;
397
398 if (len > 0) {
399 server.bytesIn(len);
400 statCounter.server.all.kbytes_in += len;
401 statCounter.server.other.kbytes_in += len;
402 }
403
404 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
405 copy(len, server, client, WriteClientDone);
406 }
407
408 /// Called when we read [a part of] CONNECT response from the peer
409 void
410 TunnelStateData::readConnectResponseDone(char *, size_t len, Comm::Flag errcode, int xerrno)
411 {
412 debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
413 assert(waitingForConnectResponse());
414
415 if (errcode == Comm::ERR_CLOSING)
416 return;
417
418 if (len > 0) {
419 connectRespBuf->appended(len);
420 server.bytesIn(len);
421 statCounter.server.all.kbytes_in += len;
422 statCounter.server.other.kbytes_in += len;
423 }
424
425 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
426 handleConnectResponse(len);
427 }
428
429 void
430 TunnelStateData::informUserOfPeerError(const char *errMsg, const size_t sz)
431 {
432 server.len = 0;
433
434 if (logTag_ptr)
435 *logTag_ptr = LOG_TCP_TUNNEL;
436
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();
441 return;
442 }
443
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);
451 return;
452 }
453
454 // if we need to send back the server response. write its headers to the client
455 server.len = sz;
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();
460 }
461
462 /* Read from client side and queue it for writing to the server */
463 void
464 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
465 {
466 TunnelStateData *tunnelState = (TunnelStateData *)data;
467 assert (cbdataReferenceValid (tunnelState));
468
469 tunnelState->readConnectResponseDone(buf, len, errcode, xerrno);
470 }
471
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.
475 void
476 TunnelStateData::handleConnectResponse(const size_t chunkSize)
477 {
478 assert(waitingForConnectResponse());
479
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.
485
486 /* mimic the basic parts of HttpStateData::processReplyHeader() */
487 HttpReply rep;
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);
492 if (!parsed) {
493 if (parseErr > 0) { // unrecoverable parsing error
494 informUserOfPeerError("malformed CONNECT response from peer", 0);
495 return;
496 }
497
498 // need more data
499 assert(!eof);
500 assert(!parseErr);
501
502 if (!connectRespBuf->hasSpace()) {
503 informUserOfPeerError("huge CONNECT response from peer", 0);
504 return;
505 }
506
507 // keep reading
508 readConnectResponse();
509 return;
510 }
511
512 // CONNECT response was successfully parsed
513 *status_ptr = rep.sline.status();
514
515 // we need to relay the 401/407 responses when login=PASS(THRU)
516 const CachePeer *peer = server.conn->getPeer();
517 const char *pwd = (peer ? peer->login : nullptr);
518 const bool relay = pwd && (strcmp(pwd, "PASS") == 0 || strcmp(pwd, "PASSTHRU") == 0) &&
519 (*status_ptr == Http::scProxyAuthenticationRequired ||
520 *status_ptr == Http::scUnauthorized);
521
522 // bail if we did not get an HTTP 200 (Connection Established) response
523 if (rep.sline.status() != Http::scOkay) {
524 // if we ever decide to reuse the peer connection, we must extract the error response first
525 informUserOfPeerError("unsupported CONNECT response status code", (relay ? rep.hdr_sz : 0));
526 return;
527 }
528
529 if (rep.hdr_sz < connectRespBuf->contentSize()) {
530 // preserve bytes that the server already sent after the CONNECT response
531 server.len = connectRespBuf->contentSize() - rep.hdr_sz;
532 memcpy(server.buf, connectRespBuf->content()+rep.hdr_sz, server.len);
533 } else {
534 // reset; delay pools were using this field to throttle CONNECT response
535 server.len = 0;
536 }
537
538 delete connectRespBuf;
539 connectRespBuf = NULL;
540 connectExchangeCheckpoint();
541 }
542
543 void
544 TunnelStateData::Connection::error(int const xerrno)
545 {
546 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerr(xerrno));
547
548 if (!ignoreErrno(xerrno))
549 conn->close();
550 }
551
552 /* Read from client side and queue it for writing to the server */
553 void
554 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
555 {
556 TunnelStateData *tunnelState = (TunnelStateData *)data;
557 assert (cbdataReferenceValid (tunnelState));
558
559 tunnelState->readClient(buf, len, errcode, xerrno);
560 }
561
562 void
563 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
564 {
565 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
566 client.delayedLoops=0;
567
568 /*
569 * Bail out early on Comm::ERR_CLOSING
570 * - close handlers will tidy up for us
571 */
572
573 if (errcode == Comm::ERR_CLOSING)
574 return;
575
576 if (len > 0) {
577 client.bytesIn(len);
578 statCounter.client_http.kbytes_in += len;
579 }
580
581 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
582 copy(len, client, server, WriteServerDone);
583 }
584
585 /// Updates state after reading from client or server.
586 /// Returns whether the caller should use the data just read.
587 bool
588 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
589 {
590 debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
591
592 /* I think this is to prevent free-while-in-a-callback behaviour
593 * - RBC 20030229
594 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
595 */
596 const CbcPointer<TunnelStateData> safetyLock(this);
597
598 /* Bump the source connection read timeout on any activity */
599 if (Comm::IsConnOpen(from.conn)) {
600 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
601 CommTimeoutCbPtrFun(tunnelTimeout, this));
602 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
603 }
604
605 /* Bump the dest connection read timeout on any activity */
606 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
607 if (Comm::IsConnOpen(to.conn)) {
608 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
609 CommTimeoutCbPtrFun(tunnelTimeout, this));
610 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
611 }
612
613 if (errcode)
614 from.error (xerrno);
615 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
616 debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
617 from.conn->close();
618
619 /* Only close the remote end if we've finished queueing data to it */
620 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
621 to.conn->close();
622 }
623 } else if (cbdataReferenceValid(this)) {
624 return true;
625 }
626
627 return false;
628 }
629
630 void
631 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
632 {
633 debugs(26, 3, HERE << "Schedule Write");
634 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
635 CommIoCbPtrFun(completion, this));
636 to.write(from.buf, len, call, NULL);
637 }
638
639 /* Writes data from the client buffer to the server side */
640 void
641 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
642 {
643 TunnelStateData *tunnelState = (TunnelStateData *)data;
644 assert (cbdataReferenceValid (tunnelState));
645 tunnelState->server.writer = NULL;
646
647 tunnelState->writeServerDone(buf, len, flag, xerrno);
648 }
649
650 void
651 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
652 {
653 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
654
655 /* Error? */
656 if (flag != Comm::OK) {
657 if (flag != Comm::ERR_CLOSING) {
658 debugs(26, 4, HERE << "calling TunnelStateData::server.error(" << xerrno <<")");
659 server.error(xerrno); // may call comm_close
660 }
661 return;
662 }
663
664 /* EOF? */
665 if (len == 0) {
666 debugs(26, 4, HERE << "No read input. Closing server connection.");
667 server.conn->close();
668 return;
669 }
670
671 /* Valid data */
672 statCounter.server.all.kbytes_out += len;
673 statCounter.server.other.kbytes_out += len;
674 client.dataSent(len);
675
676 /* If the other end has closed, so should we */
677 if (!Comm::IsConnOpen(client.conn)) {
678 debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
679 server.conn->close();
680 return;
681 }
682
683 const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
684
685 if (cbdataReferenceValid(this))
686 copyClientBytes();
687 }
688
689 /* Writes data from the server buffer to the client side */
690 void
691 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
692 {
693 TunnelStateData *tunnelState = (TunnelStateData *)data;
694 assert (cbdataReferenceValid (tunnelState));
695 tunnelState->client.writer = NULL;
696
697 tunnelState->writeClientDone(buf, len, flag, xerrno);
698 }
699
700 void
701 TunnelStateData::Connection::dataSent(size_t amount)
702 {
703 debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
704 assert(amount == (size_t)len);
705 len =0;
706 /* increment total object size */
707
708 if (size_ptr)
709 *size_ptr += amount;
710 }
711
712 void
713 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
714 {
715 writer = callback;
716 Comm::Write(conn, b, size, callback, free_func);
717 }
718
719 void
720 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
721 {
722 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
723
724 /* Error? */
725 if (flag != Comm::OK) {
726 if (flag != Comm::ERR_CLOSING) {
727 debugs(26, 4, HERE << "Closing client connection due to comm flags.");
728 client.error(xerrno); // may call comm_close
729 }
730 return;
731 }
732
733 /* EOF? */
734 if (len == 0) {
735 debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
736 client.conn->close();
737 return;
738 }
739
740 /* Valid data */
741 statCounter.client_http.kbytes_out += len;
742 server.dataSent(len);
743
744 /* If the other end has closed, so should we */
745 if (!Comm::IsConnOpen(server.conn)) {
746 debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
747 client.conn->close();
748 return;
749 }
750
751 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
752
753 if (cbdataReferenceValid(this))
754 copyServerBytes();
755 }
756
757 static void
758 tunnelTimeout(const CommTimeoutCbParams &io)
759 {
760 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
761 debugs(26, 3, HERE << io.conn);
762 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
763 CbcPointer<TunnelStateData> safetyLock(tunnelState);
764
765 tunnelState->client.closeIfOpen();
766 tunnelState->server.closeIfOpen();
767 }
768
769 void
770 TunnelStateData::Connection::closeIfOpen()
771 {
772 if (Comm::IsConnOpen(conn))
773 conn->close();
774 }
775
776 static void
777 tunnelDelayedClientRead(void *data)
778 {
779 if (!data)
780 return;
781
782 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
783 tunnel->client.readPending = NULL;
784 static uint64_t counter=0;
785 debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
786 tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
787 }
788
789 static void
790 tunnelDelayedServerRead(void *data)
791 {
792 if (!data)
793 return;
794
795 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
796 tunnel->server.readPending = NULL;
797 static uint64_t counter=0;
798 debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
799 tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
800 }
801
802 void
803 TunnelStateData::copyRead(Connection &from, IOCB *completion)
804 {
805 assert(from.len == 0);
806 // If only the minimum permitted read size is going to be attempted
807 // then we schedule an event to try again in a few I/O cycles.
808 // Allow at least 1 byte to be read every (0.3*10) seconds.
809 int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
810 if (bw == 1 && ++from.delayedLoops < 10) {
811 from.readPending = this;
812 eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
813 return;
814 }
815
816 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
817 CommIoCbPtrFun(completion, this));
818 comm_read(from.conn, from.buf, bw, call);
819 }
820
821 void
822 TunnelStateData::readConnectResponse()
823 {
824 assert(waitingForConnectResponse());
825
826 AsyncCall::Pointer call = commCbCall(5,4, "readConnectResponseDone",
827 CommIoCbPtrFun(ReadConnectResponseDone, this));
828 comm_read(server.conn, connectRespBuf->space(),
829 server.bytesWanted(1, connectRespBuf->spaceSize()), call);
830 }
831
832 void
833 TunnelStateData::copyClientBytes()
834 {
835 if (preReadClientData.length()) {
836 size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
837 memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
838 preReadClientData.consume(copyBytes);
839 client.bytesIn(copyBytes);
840 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
841 copy(copyBytes, client, server, TunnelStateData::WriteServerDone);
842 } else
843 copyRead(client, ReadClient);
844 }
845
846 void
847 TunnelStateData::copyServerBytes()
848 {
849 if (preReadServerData.length()) {
850 size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
851 memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
852 preReadServerData.consume(copyBytes);
853 server.bytesIn(copyBytes);
854 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
855 copy(copyBytes, server, client, TunnelStateData::WriteClientDone);
856 } else
857 copyRead(server, ReadServer);
858 }
859
860 /**
861 * Set the HTTP status for this request and sets the read handlers for client
862 * and server side connections.
863 */
864 static void
865 tunnelStartShoveling(TunnelStateData *tunnelState)
866 {
867 assert(!tunnelState->waitingForConnectExchange());
868 *tunnelState->status_ptr = Http::scOkay;
869 if (tunnelState->logTag_ptr)
870 *tunnelState->logTag_ptr = LOG_TCP_TUNNEL;
871 if (cbdataReferenceValid(tunnelState)) {
872
873 // Shovel any payload already pushed into reply buffer by the server response
874 if (!tunnelState->server.len)
875 tunnelState->copyServerBytes();
876 else {
877 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
878 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
879 }
880
881 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
882 SBuf * const in = &tunnelState->http->getConn()->inBuf;
883 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
884 tunnelState->preReadClientData.append(*in);
885 in->consume(); // ConnStateData buffer accounting after the shuffle.
886 }
887 tunnelState->copyClientBytes();
888 }
889 }
890
891 /**
892 * All the pieces we need to write to client and/or server connection
893 * have been written.
894 * Call the tunnelStartShoveling to start the blind pump.
895 */
896 static void
897 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
898 {
899 TunnelStateData *tunnelState = (TunnelStateData *)data;
900 debugs(26, 3, HERE << conn << ", flag=" << flag);
901 tunnelState->client.writer = NULL;
902
903 if (flag != Comm::OK) {
904 *tunnelState->status_ptr = Http::scInternalServerError;
905 tunnelErrorComplete(conn->fd, data, 0);
906 return;
907 }
908
909 tunnelStartShoveling(tunnelState);
910 }
911
912 /// Called when we are done writing CONNECT request to a peer.
913 static void
914 tunnelConnectReqWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
915 {
916 TunnelStateData *tunnelState = (TunnelStateData *)data;
917 debugs(26, 3, conn << ", flag=" << flag);
918 tunnelState->server.writer = NULL;
919 assert(tunnelState->waitingForConnectRequest());
920
921 if (flag != Comm::OK) {
922 *tunnelState->status_ptr = Http::scInternalServerError;
923 tunnelErrorComplete(conn->fd, data, 0);
924 return;
925 }
926
927 tunnelState->connectReqWriting = false;
928 tunnelState->connectExchangeCheckpoint();
929 }
930
931 void
932 TunnelStateData::connectExchangeCheckpoint()
933 {
934 if (waitingForConnectResponse()) {
935 debugs(26, 5, "still reading CONNECT response on " << server.conn);
936 } else if (waitingForConnectRequest()) {
937 debugs(26, 5, "still writing CONNECT request on " << server.conn);
938 } else {
939 assert(!waitingForConnectExchange());
940 debugs(26, 3, "done with CONNECT exchange on " << server.conn);
941 tunnelConnected(server.conn, this);
942 }
943 }
944
945 /*
946 * handle the write completion from a proxy request to an upstream origin
947 */
948 static void
949 tunnelConnected(const Comm::ConnectionPointer &server, void *data)
950 {
951 TunnelStateData *tunnelState = (TunnelStateData *)data;
952 debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
953
954 if (!tunnelState->clientExpectsConnectResponse())
955 tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
956 else {
957 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
958 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
959 tunnelState->client.write(conn_established, strlen(conn_established), call, NULL);
960 }
961 }
962
963 static void
964 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
965 {
966 TunnelStateData *tunnelState = (TunnelStateData *)data;
967 debugs(26, 3, HERE << "FD " << fd);
968 assert(tunnelState != NULL);
969 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
970 CbcPointer<TunnelStateData> safetyLock(tunnelState);
971
972 if (Comm::IsConnOpen(tunnelState->client.conn))
973 tunnelState->client.conn->close();
974
975 if (Comm::IsConnOpen(tunnelState->server.conn))
976 tunnelState->server.conn->close();
977 }
978
979 static void
980 tunnelConnectDone(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
981 {
982 TunnelStateData *tunnelState = (TunnelStateData *)data;
983
984 if (status != Comm::OK) {
985 debugs(26, 4, HERE << conn << ", comm failure recovery.");
986 /* At this point only the TCP handshake has failed. no data has been passed.
987 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
988 */
989 debugs(26, 4, "removing server 1 of " << tunnelState->serverDestinations.size() <<
990 " from destinations (" << tunnelState->serverDestinations[0] << ")");
991 tunnelState->serverDestinations.erase(tunnelState->serverDestinations.begin());
992 time_t fwdTimeout = tunnelState->started + Config.Timeout.forward;
993 if (fwdTimeout > squid_curtime && tunnelState->serverDestinations.size() > 0) {
994 // find remaining forward_timeout available for this attempt
995 fwdTimeout -= squid_curtime;
996 if (fwdTimeout > Config.Timeout.connect)
997 fwdTimeout = Config.Timeout.connect;
998 /* Try another IP of this destination host */
999 GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
1000 debugs(26, 4, HERE << "retry with : " << tunnelState->serverDestinations[0]);
1001 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
1002 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, fwdTimeout);
1003 cs->setHost(tunnelState->url);
1004 AsyncJob::Start(cs);
1005 } else {
1006 debugs(26, 4, HERE << "terminate with error.");
1007 ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, Http::scServiceUnavailable, tunnelState->request.getRaw());
1008 *tunnelState->status_ptr = Http::scServiceUnavailable;
1009 err->xerrno = xerrno;
1010 // on timeout is this still: err->xerrno = ETIMEDOUT;
1011 err->port = conn->remote.port();
1012 err->callback = tunnelErrorComplete;
1013 err->callback_data = tunnelState;
1014 errorSend(tunnelState->client.conn, err);
1015 if (tunnelState->request != NULL)
1016 tunnelState->request->hier.stopPeerClock(false);
1017 }
1018 return;
1019 }
1020
1021 #if USE_DELAY_POOLS
1022 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1023 if (conn->getPeer() && conn->getPeer()->options.no_delay)
1024 tunnelState->server.setDelayId(DelayId());
1025 #endif
1026
1027 tunnelState->request->hier.note(conn, tunnelState->getHost());
1028
1029 tunnelState->server.conn = conn;
1030 tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
1031 comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
1032
1033 debugs(26, 4, HERE << "determine post-connect handling pathway.");
1034 if (conn->getPeer()) {
1035 tunnelState->request->peer_login = conn->getPeer()->login;
1036 tunnelState->request->peer_domain = conn->getPeer()->domain;
1037 tunnelState->request->flags.auth_no_keytab = conn->getPeer()->options.auth_no_keytab;
1038 tunnelState->request->flags.proxying = !(conn->getPeer()->options.originserver);
1039 } else {
1040 tunnelState->request->peer_login = NULL;
1041 tunnelState->request->peer_domain = NULL;
1042 tunnelState->request->flags.auth_no_keytab = false;
1043 tunnelState->request->flags.proxying = false;
1044 }
1045
1046 if (tunnelState->request->flags.proxying)
1047 tunnelState->connectToPeer();
1048 else {
1049 tunnelConnected(conn, tunnelState);
1050 }
1051
1052 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1053 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1054 commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
1055 }
1056
1057 void
1058 tunnelStart(ClientHttpRequest * http)
1059 {
1060 debugs(26, 3, HERE);
1061 /* Create state structure. */
1062 TunnelStateData *tunnelState = NULL;
1063 ErrorState *err = NULL;
1064 HttpRequest *request = http->request;
1065 char *url = http->uri;
1066
1067 /*
1068 * client_addr.isNoAddr() indicates this is an "internal" request
1069 * from peer_digest.c, asn.c, netdb.c, etc and should always
1070 * be allowed. yuck, I know.
1071 */
1072
1073 if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
1074 /*
1075 * Check if this host is allowed to fetch MISSES from us (miss_access)
1076 * default is to allow.
1077 */
1078 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
1079 ch.src_addr = request->client_addr;
1080 ch.my_addr = request->my_addr;
1081 if (ch.fastCheck() == ACCESS_DENIED) {
1082 debugs(26, 4, HERE << "MISS access forbidden.");
1083 err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request);
1084 http->al->http.code = Http::scForbidden;
1085 errorSend(http->getConn()->clientConnection, err);
1086 return;
1087 }
1088 }
1089
1090 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1091 ++statCounter.server.all.requests;
1092 ++statCounter.server.other.requests;
1093
1094 tunnelState = new TunnelStateData(http);
1095 #if USE_DELAY_POOLS
1096 //server.setDelayId called from tunnelConnectDone after server side connection established
1097 #endif
1098
1099 peerSelect(&(tunnelState->serverDestinations), request, http->al,
1100 NULL,
1101 tunnelPeerSelectComplete,
1102 tunnelState);
1103 }
1104
1105 void
1106 TunnelStateData::connectToPeer()
1107 {
1108 if (CachePeer *p = server.conn->getPeer()) {
1109 if (p->secure.encryptTransport) {
1110 AsyncCall::Pointer callback = asyncCall(5,4,
1111 "TunnelStateData::ConnectedToPeer",
1112 MyAnswerDialer(&TunnelStateData::connectedToPeer, this));
1113 auto *connector = new Security::BlindPeerConnector(request, server.conn, callback, al);
1114 AsyncJob::Start(connector); // will call our callback
1115 return;
1116 }
1117 }
1118
1119 Security::EncryptorAnswer nil;
1120 connectedToPeer(nil);
1121 }
1122
1123 void
1124 TunnelStateData::connectedToPeer(Security::EncryptorAnswer &answer)
1125 {
1126 if (ErrorState *error = answer.error.get()) {
1127 *status_ptr = error->httpStatus;
1128 error->callback = tunnelErrorComplete;
1129 error->callback_data = this;
1130 errorSend(client.conn, error);
1131 answer.error.clear(); // preserve error for errorSendComplete()
1132 return;
1133 }
1134
1135 tunnelRelayConnectRequest(server.conn, this);
1136 }
1137
1138 static void
1139 tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
1140 {
1141 TunnelStateData *tunnelState = (TunnelStateData *)data;
1142 assert(!tunnelState->waitingForConnectExchange());
1143 HttpHeader hdr_out(hoRequest);
1144 Http::StateFlags flags;
1145 debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
1146 memset(&flags, '\0', sizeof(flags));
1147 flags.proxying = tunnelState->request->flags.proxying;
1148 MemBuf mb;
1149 mb.init();
1150 mb.appendf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
1151 HttpStateData::httpBuildRequestHeader(tunnelState->request.getRaw(),
1152 NULL, /* StoreEntry */
1153 tunnelState->al, /* AccessLogEntry */
1154 &hdr_out,
1155 flags); /* flags */
1156 hdr_out.packInto(&mb);
1157 hdr_out.clean();
1158 mb.append("\r\n", 2);
1159
1160 debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn <<
1161 ":\n----------\n" << mb.buf << "\n----------");
1162
1163 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
1164 CommIoCbPtrFun(tunnelConnectReqWriteDone,
1165 tunnelState));
1166
1167 tunnelState->server.write(mb.buf, mb.size, writeCall, mb.freeFunc());
1168 tunnelState->connectReqWriting = true;
1169
1170 tunnelState->connectRespBuf = new MemBuf;
1171 // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1172 // can hold since any CONNECT response leftovers have to fit into server.buf.
1173 // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
1174 tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
1175 tunnelState->readConnectResponse();
1176
1177 assert(tunnelState->waitingForConnectExchange());
1178
1179 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1180 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1181 commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
1182 }
1183
1184 static Comm::ConnectionPointer
1185 borrowPinnedConnection(HttpRequest *request, Comm::ConnectionPointer &serverDestination)
1186 {
1187 // pinned_connection may become nil after a pconn race
1188 if (ConnStateData *pinned_connection = request ? request->pinnedConnection() : nullptr) {
1189 Comm::ConnectionPointer serverConn = pinned_connection->borrowPinnedConnection(request, serverDestination->getPeer());
1190 return serverConn;
1191 }
1192
1193 return nullptr;
1194 }
1195
1196 static void
1197 tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, ErrorState *err, void *data)
1198 {
1199 TunnelStateData *tunnelState = (TunnelStateData *)data;
1200
1201 bool bail = false;
1202 if (!peer_paths || peer_paths->empty()) {
1203 debugs(26, 3, HERE << "No paths found. Aborting CONNECT");
1204 bail = true;
1205 }
1206
1207 if (!bail && tunnelState->serverDestinations[0]->peerType == PINNED) {
1208 Comm::ConnectionPointer serverConn = borrowPinnedConnection(tunnelState->request.getRaw(), tunnelState->serverDestinations[0]);
1209 debugs(26,7, "pinned peer connection: " << serverConn);
1210 if (Comm::IsConnOpen(serverConn)) {
1211 tunnelConnectDone(serverConn, Comm::OK, 0, (void *)tunnelState);
1212 return;
1213 }
1214 bail = true;
1215 }
1216
1217 if (bail) {
1218 if (!err) {
1219 err = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, tunnelState->request.getRaw());
1220 }
1221 *tunnelState->status_ptr = err->httpStatus;
1222 err->callback = tunnelErrorComplete;
1223 err->callback_data = tunnelState;
1224 errorSend(tunnelState->client.conn, err);
1225 return;
1226 }
1227 delete err;
1228
1229 GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
1230
1231 if (tunnelState->request != NULL)
1232 tunnelState->request->hier.startPeerClock();
1233
1234 debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
1235 tunnelState->serverDestinations[0] << "}");
1236
1237 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
1238 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
1239 cs->setHost(tunnelState->url);
1240 AsyncJob::Start(cs);
1241 }
1242
1243 CBDATA_CLASS_INIT(TunnelStateData);
1244
1245 bool
1246 TunnelStateData::noConnections() const
1247 {
1248 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
1249 }
1250
1251 #if USE_DELAY_POOLS
1252 void
1253 TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
1254 {
1255 delayId = newDelay;
1256 }
1257
1258 #endif
1259
1260 #if USE_OPENSSL
1261 void
1262 switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn)
1263 {
1264 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1265
1266 /* Create state structure. */
1267 ++statCounter.server.all.requests;
1268 ++statCounter.server.other.requests;
1269
1270 auto conn = request->clientConnectionManager.get();
1271 Must(conn);
1272 Http::StreamPointer context = conn->pipeline.front();
1273 Must(context && context->http);
1274
1275 debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1276
1277 TunnelStateData *tunnelState = new TunnelStateData(context->http);
1278
1279 fd_table[clientConn->fd].read_method = &default_read_method;
1280 fd_table[clientConn->fd].write_method = &default_write_method;
1281
1282 request->hier.note(srvConn, tunnelState->getHost());
1283
1284 tunnelState->server.conn = srvConn;
1285
1286 #if USE_DELAY_POOLS
1287 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1288 if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay)
1289 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1290 #endif
1291
1292 request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1293 comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState);
1294
1295 debugs(26, 4, "determine post-connect handling pathway.");
1296 if (srvConn->getPeer()) {
1297 request->peer_login = srvConn->getPeer()->login;
1298 request->peer_domain = srvConn->getPeer()->domain;
1299 request->flags.auth_no_keytab = srvConn->getPeer()->options.auth_no_keytab;
1300 request->flags.proxying = !(srvConn->getPeer()->options.originserver);
1301 } else {
1302 request->peer_login = nullptr;
1303 request->peer_domain = nullptr;
1304 request->flags.auth_no_keytab = false;
1305 request->flags.proxying = false;
1306 }
1307
1308 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1309 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1310 commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall);
1311 fd_table[srvConn->fd].read_method = &default_read_method;
1312 fd_table[srvConn->fd].write_method = &default_write_method;
1313
1314 auto ssl = fd_table[srvConn->fd].ssl.get();
1315 assert(ssl);
1316 BIO *b = SSL_get_rbio(ssl);
1317 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(BIO_get_data(b));
1318 tunnelState->preReadServerData = srvBio->rBufData();
1319 tunnelStartShoveling(tunnelState);
1320 }
1321 #endif //USE_OPENSSL
1322