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