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