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