]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tunnel.cc
Maintenance: Update astyle version to 3.1 (#841)
[thirdparty/squid.git] / src / tunnel.cc
1 /*
2 * Copyright (C) 1996-2021 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 "clients/HttpTunneler.h"
19 #include "comm.h"
20 #include "comm/Connection.h"
21 #include "comm/ConnOpener.h"
22 #include "comm/Read.h"
23 #include "comm/Write.h"
24 #include "errorpage.h"
25 #include "fd.h"
26 #include "fde.h"
27 #include "FwdState.h"
28 #include "globals.h"
29 #include "HappyConnOpener.h"
30 #include "http.h"
31 #include "http/Stream.h"
32 #include "HttpRequest.h"
33 #include "icmp/net_db.h"
34 #include "ip/QosConfig.h"
35 #include "LogTags.h"
36 #include "MemBuf.h"
37 #include "neighbors.h"
38 #include "PeerSelectState.h"
39 #include "ResolvedPeers.h"
40 #include "sbuf/SBuf.h"
41 #include "security/BlindPeerConnector.h"
42 #include "SquidConfig.h"
43 #include "SquidTime.h"
44 #include "StatCounters.h"
45 #if USE_OPENSSL
46 #include "ssl/bio.h"
47 #include "ssl/ServerBump.h"
48 #endif
49 #include "tools.h"
50 #if USE_DELAY_POOLS
51 #include "DelayId.h"
52 #endif
53
54 #include <climits>
55 #include <cerrno>
56
57 /**
58 * TunnelStateData is the state engine performing the tasks for
59 * setup of a TCP tunnel from an existing open client FD to a server
60 * then shuffling binary data between the resulting FD pair.
61 */
62 /*
63 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
64 * of pre-formatted data. Then we can use that as the client side of the tunnel
65 * instead of re-implementing it here and occasionally getting the ConnStateData
66 * read/write state wrong.
67 *
68 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
69 */
70 class TunnelStateData: public PeerSelectionInitiator
71 {
72 CBDATA_CHILD(TunnelStateData);
73
74 public:
75 TunnelStateData(ClientHttpRequest *);
76 virtual ~TunnelStateData();
77 TunnelStateData(const TunnelStateData &); // do not implement
78 TunnelStateData &operator =(const TunnelStateData &); // do not implement
79
80 class Connection;
81 static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
82 static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
83 static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
84 static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
85
86 bool noConnections() const;
87 /// closes both client and server connections
88 void closeConnections();
89
90 char *url;
91 CbcPointer<ClientHttpRequest> http;
92 HttpRequest::Pointer request;
93 AccessLogEntryPointer al;
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 the client sent a CONNECT request to us.
100 bool clientExpectsConnectResponse() const {
101 // If we are forcing a tunnel after receiving a client CONNECT, then we
102 // have already responded to that CONNECT before tunnel.cc started.
103 if (request && request->flags.forceTunnel)
104 return false;
105 #if USE_OPENSSL
106 // We are bumping and we had already send "OK CONNECTED"
107 if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->at(XactionStep::tlsBump2, XactionStep::tlsBump3))
108 return false;
109 #endif
110 return !(request != NULL &&
111 (request->flags.interceptTproxy || request->flags.intercepted));
112 }
113
114 /// starts connecting to the next hop, either for the first time or while
115 /// recovering from the previous connect failure
116 void startConnecting();
117 void closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason);
118
119 /// called when negotiations with the peer have been successfully completed
120 void notePeerReadyToShovel(const Comm::ConnectionPointer &);
121
122 class Connection
123 {
124
125 public:
126 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), delayedLoops(0),
127 dirty(false),
128 readPending(NULL), readPendingFunc(NULL) {}
129
130 ~Connection();
131
132 /// initiates Comm::Connection ownership, including closure monitoring
133 template <typename Method>
134 void initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState);
135
136 /// reacts to the external closure of our connection
137 void noteClosure();
138
139 int bytesWanted(int lower=0, int upper = INT_MAX) const;
140 void bytesIn(int const &);
141 #if USE_DELAY_POOLS
142
143 void setDelayId(DelayId const &);
144 #endif
145
146 void error(int const xerrno);
147 int debugLevelForError(int const xerrno) const;
148
149 void dataSent (size_t amount);
150 /// writes 'b' buffer, setting the 'writer' member to 'callback'.
151 void write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func);
152 int len;
153 char *buf;
154 AsyncCall::Pointer writer; ///< pending Comm::Write callback
155 uint64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
156
157 Comm::ConnectionPointer conn; ///< The currently connected connection.
158 uint8_t delayedLoops; ///< how many times a read on this connection has been postponed.
159
160 bool dirty; ///< whether write() has been called (at least once)
161
162 // XXX: make these an AsyncCall when event API can handle them
163 TunnelStateData *readPending;
164 EVH *readPendingFunc;
165
166 #if USE_DELAY_POOLS
167
168 DelayId delayId;
169 #endif
170
171 private:
172 /// the registered close handler for the connection
173 AsyncCall::Pointer closer;
174 };
175
176 Connection client, server;
177 int *status_ptr; ///< pointer for logging HTTP status
178 LogTags *logTag_ptr; ///< pointer for logging Squid processing code
179
180 SBuf preReadClientData;
181 SBuf preReadServerData;
182 time_t startTime; ///< object creation time, before any peer selection/connection attempts
183 /// Whether we are waiting for the CONNECT request/response exchange with the peer.
184 bool waitingForConnectExchange;
185 HappyConnOpenerPointer connOpener; ///< current connection opening job
186 ResolvedPeersPointer destinations; ///< paths for forwarding the request
187 bool destinationsFound; ///< At least one candidate path found
188 /// whether another destination may be still attempted if the TCP connection
189 /// was unexpectedly closed
190 bool retriable;
191 // TODO: remove after fixing deferred reads in TunnelStateData::copyRead()
192 CodeContext::Pointer codeContext; ///< our creator context
193
194 // AsyncCalls which we set and may need cancelling.
195 struct {
196 AsyncCall::Pointer connector; ///< a call linking us to the ConnOpener producing serverConn.
197 } calls;
198
199 void copyRead(Connection &from, IOCB *completion);
200
201 /// continue to set up connection to a peer, going async for SSL peers
202 void connectToPeer(const Comm::ConnectionPointer &);
203 void secureConnectionToPeer(const Comm::ConnectionPointer &);
204
205 /* PeerSelectionInitiator API */
206 virtual void noteDestination(Comm::ConnectionPointer conn) override;
207 virtual void noteDestinationsEnd(ErrorState *selectionError) override;
208
209 void syncHierNote(const Comm::ConnectionPointer &server, const char *origin);
210
211 /// called when a connection has been successfully established or
212 /// when all candidate destinations have been tried and all have failed
213 void noteConnection(HappyConnOpenerAnswer &);
214
215 /// whether we are waiting for HappyConnOpener
216 /// same as calls.connector but may differ from connOpener.valid()
217 bool opening() const { return connOpener.set(); }
218
219 void cancelOpening(const char *reason);
220
221 /// Start using an established connection
222 void connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused);
223
224 void notifyConnOpener();
225
226 void saveError(ErrorState *finalError);
227 void sendError(ErrorState *finalError, const char *reason);
228
229 private:
230 /// Gives Security::PeerConnector access to Answer in the TunnelStateData callback dialer.
231 class MyAnswerDialer: public CallDialer, public Security::PeerConnector::CbDialer
232 {
233 public:
234 typedef void (TunnelStateData::*Method)(Security::EncryptorAnswer &);
235
236 MyAnswerDialer(Method method, TunnelStateData *tunnel):
237 method_(method), tunnel_(tunnel), answer_() {}
238
239 /* CallDialer API */
240 virtual bool canDial(AsyncCall &call) { return tunnel_.valid(); }
241 void dial(AsyncCall &call) { ((&(*tunnel_))->*method_)(answer_); }
242 virtual void print(std::ostream &os) const {
243 os << '(' << tunnel_.get() << ", " << answer_ << ')';
244 }
245
246 /* Security::PeerConnector::CbDialer API */
247 virtual Security::EncryptorAnswer &answer() { return answer_; }
248
249 private:
250 Method method_;
251 CbcPointer<TunnelStateData> tunnel_;
252 Security::EncryptorAnswer answer_;
253 };
254
255 void usePinned();
256
257 /// callback handler for the Security::PeerConnector encryptor
258 void noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &);
259
260 /// called after connection setup (including any encryption)
261 void connectedToPeer(const Comm::ConnectionPointer &);
262 void establishTunnelThruProxy(const Comm::ConnectionPointer &);
263
264 template <typename StepStart>
265 void advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep);
266
267 /// \returns whether the request should be retried (nil) or the description why it should not
268 const char *checkRetry();
269
270 /// details of the "last tunneling attempt" failure (if it failed)
271 ErrorState *savedError = nullptr;
272
273 /// resumes operations after the (possibly failed) HTTP CONNECT exchange
274 void tunnelEstablishmentDone(Http::TunnelerAnswer &answer);
275
276 void deleteThis();
277
278 public:
279 bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
280 void copy(size_t len, Connection &from, Connection &to, IOCB *);
281 void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
282 void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
283 void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
284 void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
285
286 void copyClientBytes();
287 void copyServerBytes();
288
289 /// handles client-to-Squid connection closure; may destroy us
290 void clientClosed();
291
292 /// handles Squid-to-server connection closure; may destroy us
293 void serverClosed();
294
295 /// tries connecting to another destination, if available,
296 /// otherwise, initiates the transaction termination
297 void retryOrBail(const char *context);
298 };
299
300 static ERCB tunnelErrorComplete;
301 static CLCB tunnelServerClosed;
302 static CLCB tunnelClientClosed;
303 static CTCB tunnelTimeout;
304 static EVH tunnelDelayedClientRead;
305 static EVH tunnelDelayedServerRead;
306
307 /// TunnelStateData::serverClosed() wrapper
308 static void
309 tunnelServerClosed(const CommCloseCbParams &params)
310 {
311 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
312 tunnelState->serverClosed();
313 }
314
315 void
316 TunnelStateData::serverClosed()
317 {
318 server.noteClosure();
319 }
320
321 /// TunnelStateData::clientClosed() wrapper
322 static void
323 tunnelClientClosed(const CommCloseCbParams &params)
324 {
325 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
326 tunnelState->clientClosed();
327 }
328
329 void
330 TunnelStateData::clientClosed()
331 {
332 client.noteClosure();
333
334 if (noConnections())
335 return deleteThis();
336
337 if (!server.writer)
338 server.conn->close();
339 }
340
341 /// destroys the tunnel (after performing potentially-throwing cleanup)
342 void
343 TunnelStateData::deleteThis()
344 {
345 assert(noConnections());
346 // ConnStateData pipeline should contain the CONNECT we are performing
347 // but it may be invalid already (bug 4392)
348 if (const auto h = http.valid()) {
349 if (const auto c = h->getConn())
350 if (const auto ctx = c->pipeline.front())
351 ctx->finished();
352 }
353 delete this;
354 }
355
356 TunnelStateData::TunnelStateData(ClientHttpRequest *clientRequest) :
357 startTime(squid_curtime),
358 waitingForConnectExchange(false),
359 destinations(new ResolvedPeers()),
360 destinationsFound(false),
361 retriable(true),
362 codeContext(CodeContext::Current())
363 {
364 debugs(26, 3, "TunnelStateData constructed this=" << this);
365 client.readPendingFunc = &tunnelDelayedClientRead;
366 server.readPendingFunc = &tunnelDelayedServerRead;
367
368 assert(clientRequest);
369 url = xstrdup(clientRequest->uri);
370 request = clientRequest->request;
371 Must(request);
372 server.size_ptr = &clientRequest->out.size;
373 client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
374 status_ptr = &clientRequest->al->http.code;
375 logTag_ptr = &clientRequest->logType;
376 al = clientRequest->al;
377 http = clientRequest;
378
379 client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
380
381 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
382 CommTimeoutCbPtrFun(tunnelTimeout, this));
383 commSetConnTimeout(client.conn, Config.Timeout.lifetime, timeoutCall);
384 }
385
386 TunnelStateData::~TunnelStateData()
387 {
388 debugs(26, 3, "TunnelStateData destructed this=" << this);
389 assert(noConnections());
390 xfree(url);
391 if (opening())
392 cancelOpening("~TunnelStateData");
393 delete savedError;
394 }
395
396 TunnelStateData::Connection::~Connection()
397 {
398 if (readPending)
399 eventDelete(readPendingFunc, readPending);
400
401 safe_free(buf);
402 }
403
404 const char *
405 TunnelStateData::checkRetry()
406 {
407 if (shutting_down)
408 return "shutting down";
409 if (!FwdState::EnoughTimeToReForward(startTime))
410 return "forwarding timeout";
411 if (!retriable)
412 return "not retriable";
413 if (noConnections())
414 return "no connections";
415 return nullptr;
416 }
417
418 void
419 TunnelStateData::retryOrBail(const char *context)
420 {
421 // Since no TCP payload has been passed to client or server, we may
422 // TCP-connect to other destinations (including alternate IPs).
423
424 assert(!server.conn);
425
426 const auto *bailDescription = checkRetry();
427 if (!bailDescription) {
428 if (!destinations->empty())
429 return startConnecting(); // try connecting to another destination
430
431 if (subscribed) {
432 debugs(26, 4, "wait for more destinations to try");
433 return; // expect a noteDestination*() call
434 }
435
436 // fall through to bail
437 }
438
439 /* bail */
440
441 if (request)
442 request->hier.stopPeerClock(false);
443
444 // TODO: Add sendSavedErrorOr(err_type type, Http::StatusCode, context).
445 // Then, the remaining method code (below) should become the common part of
446 // sendNewError() and sendSavedErrorOr(), used in "error detected" cases.
447 if (!savedError)
448 saveError(new ErrorState(ERR_CANNOT_FORWARD, Http::scInternalServerError, request.getRaw(), al));
449 const auto canSendError = Comm::IsConnOpen(client.conn) && !client.dirty &&
450 clientExpectsConnectResponse();
451 if (canSendError)
452 return sendError(savedError, bailDescription ? bailDescription : context);
453 *status_ptr = savedError->httpStatus;
454
455 if (noConnections())
456 return deleteThis();
457
458 // This is a "Comm::IsConnOpen(client.conn) but !canSendError" case.
459 // Closing the connection (after finishing writing) is the best we can do.
460 if (!client.writer)
461 client.conn->close();
462 // else writeClientDone() must notice a closed server and close the client
463 }
464
465 int
466 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
467 {
468 #if USE_DELAY_POOLS
469 return delayId.bytesWanted(lowerbound, upperbound);
470 #else
471
472 return upperbound;
473 #endif
474 }
475
476 void
477 TunnelStateData::Connection::bytesIn(int const &count)
478 {
479 debugs(26, 3, HERE << "len=" << len << " + count=" << count);
480 #if USE_DELAY_POOLS
481 delayId.bytesIn(count);
482 #endif
483
484 len += count;
485 }
486
487 /// update "hierarchy" annotations with a new (possibly failed) destination
488 /// \param origin the name of the origin server we were trying to reach
489 void
490 TunnelStateData::syncHierNote(const Comm::ConnectionPointer &conn, const char *origin)
491 {
492 request->hier.resetPeerNotes(conn, origin);
493 if (al)
494 al->hier.resetPeerNotes(conn, origin);
495 }
496
497 int
498 TunnelStateData::Connection::debugLevelForError(int const xerrno) const
499 {
500 #ifdef ECONNRESET
501
502 if (xerrno == ECONNRESET)
503 return 2;
504
505 #endif
506
507 if (ignoreErrno(xerrno))
508 return 3;
509
510 return 1;
511 }
512
513 /* Read from server side and queue it for writing to the client */
514 void
515 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
516 {
517 TunnelStateData *tunnelState = (TunnelStateData *)data;
518 assert(cbdataReferenceValid(tunnelState));
519 debugs(26, 3, HERE << c);
520
521 tunnelState->readServer(buf, len, errcode, xerrno);
522 }
523
524 void
525 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
526 {
527 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
528 server.delayedLoops=0;
529
530 /*
531 * Bail out early on Comm::ERR_CLOSING
532 * - close handlers will tidy up for us
533 */
534
535 if (errcode == Comm::ERR_CLOSING)
536 return;
537
538 if (len > 0) {
539 server.bytesIn(len);
540 statCounter.server.all.kbytes_in += len;
541 statCounter.server.other.kbytes_in += len;
542 request->hier.notePeerRead();
543 }
544
545 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
546 copy(len, server, client, WriteClientDone);
547 }
548
549 void
550 TunnelStateData::Connection::error(int const xerrno)
551 {
552 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerr(xerrno));
553
554 if (!ignoreErrno(xerrno))
555 conn->close();
556 }
557
558 /* Read from client side and queue it for writing to the server */
559 void
560 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
561 {
562 TunnelStateData *tunnelState = (TunnelStateData *)data;
563 assert (cbdataReferenceValid (tunnelState));
564
565 tunnelState->readClient(buf, len, errcode, xerrno);
566 }
567
568 void
569 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
570 {
571 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
572 client.delayedLoops=0;
573
574 /*
575 * Bail out early on Comm::ERR_CLOSING
576 * - close handlers will tidy up for us
577 */
578
579 if (errcode == Comm::ERR_CLOSING)
580 return;
581
582 if (len > 0) {
583 client.bytesIn(len);
584 statCounter.client_http.kbytes_in += len;
585 }
586
587 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
588 copy(len, client, server, WriteServerDone);
589 }
590
591 /// Updates state after reading from client or server.
592 /// Returns whether the caller should use the data just read.
593 bool
594 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
595 {
596 debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
597
598 /* I think this is to prevent free-while-in-a-callback behaviour
599 * - RBC 20030229
600 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
601 */
602 const CbcPointer<TunnelStateData> safetyLock(this);
603
604 /* Bump the source connection read timeout on any activity */
605 if (Comm::IsConnOpen(from.conn)) {
606 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
607 CommTimeoutCbPtrFun(tunnelTimeout, this));
608 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
609 }
610
611 /* Bump the dest connection read timeout on any activity */
612 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
613 if (Comm::IsConnOpen(to.conn)) {
614 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
615 CommTimeoutCbPtrFun(tunnelTimeout, this));
616 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
617 }
618
619 if (errcode)
620 from.error (xerrno);
621 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
622 debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
623 from.conn->close();
624
625 /* Only close the remote end if we've finished queueing data to it */
626 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
627 to.conn->close();
628 }
629 } else if (cbdataReferenceValid(this)) {
630 return true;
631 }
632
633 return false;
634 }
635
636 void
637 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
638 {
639 debugs(26, 3, HERE << "Schedule Write");
640 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
641 CommIoCbPtrFun(completion, this));
642 to.write(from.buf, len, call, NULL);
643 }
644
645 /* Writes data from the client buffer to the server side */
646 void
647 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
648 {
649 TunnelStateData *tunnelState = (TunnelStateData *)data;
650 assert (cbdataReferenceValid (tunnelState));
651 tunnelState->server.writer = NULL;
652
653 tunnelState->writeServerDone(buf, len, flag, xerrno);
654 }
655
656 void
657 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
658 {
659 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
660
661 if (flag == Comm::ERR_CLOSING)
662 return;
663
664 request->hier.notePeerWrite();
665
666 /* Error? */
667 if (flag != Comm::OK) {
668 debugs(26, 4, "to-server write failed: " << xerrno);
669 server.error(xerrno); // may call comm_close
670 return;
671 }
672
673 /* EOF? */
674 if (len == 0) {
675 debugs(26, 4, HERE << "No read input. Closing server connection.");
676 server.conn->close();
677 return;
678 }
679
680 /* Valid data */
681 statCounter.server.all.kbytes_out += len;
682 statCounter.server.other.kbytes_out += len;
683 client.dataSent(len);
684
685 /* If the other end has closed, so should we */
686 if (!Comm::IsConnOpen(client.conn)) {
687 debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
688 server.conn->close();
689 return;
690 }
691
692 const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
693
694 if (cbdataReferenceValid(this))
695 copyClientBytes();
696 }
697
698 /* Writes data from the server buffer to the client side */
699 void
700 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
701 {
702 TunnelStateData *tunnelState = (TunnelStateData *)data;
703 assert (cbdataReferenceValid (tunnelState));
704 tunnelState->client.writer = NULL;
705
706 tunnelState->writeClientDone(buf, len, flag, xerrno);
707 }
708
709 void
710 TunnelStateData::Connection::dataSent(size_t amount)
711 {
712 debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
713 assert(amount == (size_t)len);
714 len =0;
715 /* increment total object size */
716
717 if (size_ptr)
718 *size_ptr += amount;
719
720 }
721
722 void
723 TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
724 {
725 writer = callback;
726 dirty = true;
727 Comm::Write(conn, b, size, callback, free_func);
728 }
729
730 template <typename Method>
731 void
732 TunnelStateData::Connection::initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
733 {
734 Must(!Comm::IsConnOpen(conn));
735 Must(!closer);
736 Must(Comm::IsConnOpen(aConn));
737 conn = aConn;
738 closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
739 comm_add_close_handler(conn->fd, closer);
740 }
741
742 void
743 TunnelStateData::Connection::noteClosure()
744 {
745 debugs(26, 3, conn);
746 conn = nullptr;
747 closer = nullptr;
748 writer = nullptr; // may already be nil
749 }
750
751 void
752 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
753 {
754 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
755
756 if (flag == Comm::ERR_CLOSING)
757 return;
758
759 /* Error? */
760 if (flag != Comm::OK) {
761 debugs(26, 4, "from-client read failed: " << xerrno);
762 client.error(xerrno); // may call comm_close
763 return;
764 }
765
766 /* EOF? */
767 if (len == 0) {
768 debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
769 client.conn->close();
770 return;
771 }
772
773 /* Valid data */
774 statCounter.client_http.kbytes_out += len;
775 server.dataSent(len);
776
777 /* If the other end has closed, so should we */
778 if (!Comm::IsConnOpen(server.conn)) {
779 debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
780 client.conn->close();
781 return;
782 }
783
784 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
785
786 if (cbdataReferenceValid(this))
787 copyServerBytes();
788 }
789
790 static void
791 tunnelTimeout(const CommTimeoutCbParams &io)
792 {
793 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
794 debugs(26, 3, HERE << io.conn);
795 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
796 CbcPointer<TunnelStateData> safetyLock(tunnelState);
797
798 tunnelState->closeConnections();
799 }
800
801 void
802 TunnelStateData::closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
803 {
804 debugs(26, 3, "because " << reason << "; " << conn);
805 assert(!server.conn);
806 if (IsConnOpen(conn))
807 conn->close();
808 }
809
810 void
811 TunnelStateData::closeConnections()
812 {
813 if (Comm::IsConnOpen(server.conn))
814 server.conn->close();
815 if (Comm::IsConnOpen(client.conn))
816 client.conn->close();
817 }
818
819 static void
820 tunnelDelayedClientRead(void *data)
821 {
822 if (!data)
823 return;
824
825 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
826 const auto savedContext = CodeContext::Current();
827 CodeContext::Reset(tunnel->codeContext);
828 tunnel->client.readPending = NULL;
829 static uint64_t counter=0;
830 debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
831 tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
832 CodeContext::Reset(savedContext);
833 }
834
835 static void
836 tunnelDelayedServerRead(void *data)
837 {
838 if (!data)
839 return;
840
841 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
842 const auto savedContext = CodeContext::Current();
843 CodeContext::Reset(tunnel->codeContext);
844 tunnel->server.readPending = NULL;
845 static uint64_t counter=0;
846 debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
847 tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
848 CodeContext::Reset(savedContext);
849 }
850
851 void
852 TunnelStateData::copyRead(Connection &from, IOCB *completion)
853 {
854 assert(from.len == 0);
855 // If only the minimum permitted read size is going to be attempted
856 // then we schedule an event to try again in a few I/O cycles.
857 // Allow at least 1 byte to be read every (0.3*10) seconds.
858 int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
859 // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
860 // from.readPendingFunc is tunnelDelayedClientRead()).
861 // XXX: Bug #4913: Use DeferredRead instead.
862 if (bw == 1 && ++from.delayedLoops < 10) {
863 from.readPending = this;
864 eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
865 return;
866 }
867
868 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
869 CommIoCbPtrFun(completion, this));
870 comm_read(from.conn, from.buf, bw, call);
871 }
872
873 void
874 TunnelStateData::copyClientBytes()
875 {
876 if (preReadClientData.length()) {
877 size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
878 memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
879 preReadClientData.consume(copyBytes);
880 client.bytesIn(copyBytes);
881 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
882 copy(copyBytes, client, server, TunnelStateData::WriteServerDone);
883 } else
884 copyRead(client, ReadClient);
885 }
886
887 void
888 TunnelStateData::copyServerBytes()
889 {
890 if (preReadServerData.length()) {
891 size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
892 memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
893 preReadServerData.consume(copyBytes);
894 server.bytesIn(copyBytes);
895 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
896 copy(copyBytes, server, client, TunnelStateData::WriteClientDone);
897 } else
898 copyRead(server, ReadServer);
899 }
900
901 /**
902 * Set the HTTP status for this request and sets the read handlers for client
903 * and server side connections.
904 */
905 static void
906 tunnelStartShoveling(TunnelStateData *tunnelState)
907 {
908 assert(!tunnelState->waitingForConnectExchange);
909 assert(tunnelState->server.conn);
910 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
911 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
912 commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
913
914 *tunnelState->status_ptr = Http::scOkay;
915 if (tunnelState->logTag_ptr)
916 tunnelState->logTag_ptr->update(LOG_TCP_TUNNEL);
917 if (cbdataReferenceValid(tunnelState)) {
918
919 // Shovel any payload already pushed into reply buffer by the server response
920 if (!tunnelState->server.len)
921 tunnelState->copyServerBytes();
922 else {
923 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
924 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
925 }
926
927 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
928 SBuf * const in = &tunnelState->http->getConn()->inBuf;
929 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
930 tunnelState->preReadClientData.append(*in);
931 in->consume(); // ConnStateData buffer accounting after the shuffle.
932 }
933 tunnelState->copyClientBytes();
934 }
935 }
936
937 /**
938 * All the pieces we need to write to client and/or server connection
939 * have been written.
940 * Call the tunnelStartShoveling to start the blind pump.
941 */
942 static void
943 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
944 {
945 TunnelStateData *tunnelState = (TunnelStateData *)data;
946 debugs(26, 3, HERE << conn << ", flag=" << flag);
947 tunnelState->client.writer = NULL;
948
949 if (flag != Comm::OK) {
950 *tunnelState->status_ptr = Http::scInternalServerError;
951 tunnelErrorComplete(conn->fd, data, 0);
952 return;
953 }
954
955 if (auto http = tunnelState->http.get()) {
956 http->out.headers_sz += len;
957 http->out.size += len;
958 }
959
960 tunnelStartShoveling(tunnelState);
961 }
962
963 void
964 TunnelStateData::tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
965 {
966 server.len = 0;
967
968 if (logTag_ptr)
969 logTag_ptr->update(LOG_TCP_TUNNEL);
970
971 if (answer.peerResponseStatus != Http::scNone)
972 *status_ptr = answer.peerResponseStatus;
973
974 waitingForConnectExchange = false;
975
976 auto sawProblem = false;
977
978 if (!answer.positive()) {
979 sawProblem = true;
980 Must(!Comm::IsConnOpen(answer.conn));
981 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
982 sawProblem = true;
983 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
984 }
985
986 if (!sawProblem) {
987 assert(answer.positive()); // paranoid
988 // copy any post-200 OK bytes to our buffer
989 preReadServerData = answer.leftovers;
990 notePeerReadyToShovel(answer.conn);
991 return;
992 }
993
994 ErrorState *error = nullptr;
995 if (answer.positive()) {
996 error = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request.getRaw(), al);
997 } else {
998 error = answer.squidError.get();
999 Must(error);
1000 answer.squidError.clear(); // preserve error for errorSendComplete()
1001 }
1002 assert(error);
1003 saveError(error);
1004 retryOrBail("tunneler error");
1005 }
1006
1007 void
1008 TunnelStateData::notePeerReadyToShovel(const Comm::ConnectionPointer &conn)
1009 {
1010 assert(!client.dirty);
1011 retriable = false;
1012 server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1013
1014 if (!clientExpectsConnectResponse())
1015 tunnelStartShoveling(this); // ssl-bumped connection, be quiet
1016 else {
1017 *status_ptr = Http::scOkay;
1018 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1019 CommIoCbPtrFun(tunnelConnectedWriteDone, this));
1020 al->reply = HttpReply::MakeConnectionEstablished();
1021 const auto mb = al->reply->pack();
1022 client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1023 delete mb;
1024 }
1025 }
1026
1027 static void
1028 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
1029 {
1030 TunnelStateData *tunnelState = (TunnelStateData *)data;
1031 debugs(26, 3, HERE << "FD " << fd);
1032 assert(tunnelState != NULL);
1033 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
1034 CbcPointer<TunnelStateData> safetyLock(tunnelState);
1035
1036 if (Comm::IsConnOpen(tunnelState->client.conn))
1037 tunnelState->client.conn->close();
1038
1039 if (Comm::IsConnOpen(tunnelState->server.conn))
1040 tunnelState->server.conn->close();
1041 }
1042
1043 void
1044 TunnelStateData::noteConnection(HappyConnOpener::Answer &answer)
1045 {
1046 calls.connector = nullptr;
1047 connOpener.clear();
1048
1049 ErrorState *error = nullptr;
1050 if ((error = answer.error.get())) {
1051 Must(!Comm::IsConnOpen(answer.conn));
1052 syncHierNote(answer.conn, request->url.host());
1053 answer.error.clear();
1054 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1055 error = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request.getRaw(), al);
1056 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1057 }
1058
1059 if (error) {
1060 saveError(error);
1061 retryOrBail("tried all destinations");
1062 return;
1063 }
1064
1065 connectDone(answer.conn, request->url.host(), answer.reused);
1066 }
1067
1068 void
1069 TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
1070 {
1071 Must(Comm::IsConnOpen(conn));
1072
1073 if (reused)
1074 ResetMarkingsToServer(request.getRaw(), *conn);
1075 // else Comm::ConnOpener already applied proper/current markings
1076
1077 syncHierNote(conn, origin);
1078
1079 #if USE_DELAY_POOLS
1080 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1081 if (conn->getPeer() && conn->getPeer()->options.no_delay)
1082 server.setDelayId(DelayId());
1083 #endif
1084
1085 netdbPingSite(request->url.host());
1086
1087 request->peer_host = conn->getPeer() ? conn->getPeer()->host : nullptr;
1088
1089 bool toOrigin = false; // same semantics as StateFlags::toOrigin
1090 if (const auto * const peer = conn->getPeer()) {
1091 request->prepForPeering(*peer);
1092 toOrigin = peer->options.originserver;
1093 } else {
1094 request->prepForDirect();
1095 toOrigin = true;
1096 }
1097
1098 if (!toOrigin)
1099 connectToPeer(conn);
1100 else {
1101 notePeerReadyToShovel(conn);
1102 }
1103 }
1104
1105 void
1106 tunnelStart(ClientHttpRequest * http)
1107 {
1108 debugs(26, 3, HERE);
1109 /* Create state structure. */
1110 TunnelStateData *tunnelState = NULL;
1111 ErrorState *err = NULL;
1112 HttpRequest *request = http->request;
1113 char *url = http->uri;
1114
1115 /*
1116 * client_addr.isNoAddr() indicates this is an "internal" request
1117 * from peer_digest.c, asn.c, netdb.c, etc and should always
1118 * be allowed. yuck, I know.
1119 */
1120
1121 if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
1122 /*
1123 * Check if this host is allowed to fetch MISSES from us (miss_access)
1124 * default is to allow.
1125 */
1126 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
1127 ch.al = http->al;
1128 ch.src_addr = request->client_addr;
1129 ch.my_addr = request->my_addr;
1130 ch.syncAle(request, http->log_uri);
1131 if (ch.fastCheck().denied()) {
1132 debugs(26, 4, HERE << "MISS access forbidden.");
1133 err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request, http->al);
1134 http->al->http.code = Http::scForbidden;
1135 errorSend(http->getConn()->clientConnection, err);
1136 return;
1137 }
1138 }
1139
1140 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
1141 ++statCounter.server.all.requests;
1142 ++statCounter.server.other.requests;
1143
1144 tunnelState = new TunnelStateData(http);
1145 #if USE_DELAY_POOLS
1146 tunnelState->server.setDelayId(DelayId::DelayClient(http));
1147 #endif
1148 tunnelState->startSelectingDestinations(request, http->al, nullptr);
1149 }
1150
1151 void
1152 TunnelStateData::connectToPeer(const Comm::ConnectionPointer &conn)
1153 {
1154 if (const auto p = conn->getPeer()) {
1155 if (p->secure.encryptTransport)
1156 return advanceDestination("secure connection to peer", conn, [this,&conn] {
1157 secureConnectionToPeer(conn);
1158 });
1159 }
1160
1161 connectedToPeer(conn);
1162 }
1163
1164 /// encrypts an established TCP connection to peer
1165 void
1166 TunnelStateData::secureConnectionToPeer(const Comm::ConnectionPointer &conn)
1167 {
1168 AsyncCall::Pointer callback = asyncCall(5,4, "TunnelStateData::noteSecurityPeerConnectorAnswer",
1169 MyAnswerDialer(&TunnelStateData::noteSecurityPeerConnectorAnswer, this));
1170 const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
1171 AsyncJob::Start(connector); // will call our callback
1172 }
1173
1174 /// starts a preparation step for an established connection; retries on failures
1175 template <typename StepStart>
1176 void
1177 TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1178 {
1179 // TODO: Extract destination-specific handling from TunnelStateData so that
1180 // all the awkward, limited-scope advanceDestination() calls can be replaced
1181 // with a single simple try/catch,retry block.
1182 try {
1183 startStep();
1184 // now wait for the step callback
1185 } catch (...) {
1186 debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1187 closePendingConnection(conn, "connection preparation exception");
1188 if (!savedError)
1189 saveError(new ErrorState(ERR_CANNOT_FORWARD, Http::scInternalServerError, request.getRaw(), al));
1190 retryOrBail(stepDescription);
1191 }
1192 }
1193
1194 /// callback handler for the connection encryptor
1195 void
1196 TunnelStateData::noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &answer)
1197 {
1198 ErrorState *error = nullptr;
1199 if ((error = answer.error.get())) {
1200 Must(!Comm::IsConnOpen(answer.conn));
1201 answer.error.clear();
1202 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1203 error = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request.getRaw(), al);
1204 closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
1205 }
1206
1207 if (error) {
1208 saveError(error);
1209 retryOrBail("TLS peer connection error");
1210 return;
1211 }
1212
1213 connectedToPeer(answer.conn);
1214 }
1215
1216 void
1217 TunnelStateData::connectedToPeer(const Comm::ConnectionPointer &conn)
1218 {
1219 advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1220 establishTunnelThruProxy(conn);
1221 });
1222 }
1223
1224 void
1225 TunnelStateData::establishTunnelThruProxy(const Comm::ConnectionPointer &conn)
1226 {
1227 assert(!waitingForConnectExchange);
1228
1229 AsyncCall::Pointer callback = asyncCall(5,4,
1230 "TunnelStateData::tunnelEstablishmentDone",
1231 Http::Tunneler::CbDialer<TunnelStateData>(&TunnelStateData::tunnelEstablishmentDone, this));
1232 const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
1233 #if USE_DELAY_POOLS
1234 tunneler->setDelayId(server.delayId);
1235 #endif
1236 AsyncJob::Start(tunneler);
1237 waitingForConnectExchange = true;
1238 // and wait for the tunnelEstablishmentDone() call
1239 }
1240
1241 void
1242 TunnelStateData::noteDestination(Comm::ConnectionPointer path)
1243 {
1244 destinationsFound = true;
1245
1246 if (!path) { // decided to use a pinned connection
1247 // We can call usePinned() without fear of clashing with an earlier
1248 // forwarding attempt because PINNED must be the first destination.
1249 assert(destinations->empty());
1250 usePinned();
1251 return;
1252 }
1253
1254 destinations->addPath(path);
1255
1256 if (Comm::IsConnOpen(server.conn)) {
1257 // We are already using a previously opened connection but also
1258 // receiving destinations in case we need to re-forward.
1259 Must(!opening());
1260 return;
1261 }
1262
1263 if (opening()) {
1264 notifyConnOpener();
1265 return; // and continue to wait for tunnelConnectDone() callback
1266 }
1267
1268 startConnecting();
1269 }
1270
1271 void
1272 TunnelStateData::noteDestinationsEnd(ErrorState *selectionError)
1273 {
1274 PeerSelectionInitiator::subscribed = false;
1275 destinations->destinationsFinalized = true;
1276 if (!destinationsFound) {
1277
1278 // XXX: Honor clientExpectsConnectResponse() before replying.
1279
1280 if (selectionError)
1281 return sendError(selectionError, "path selection has failed");
1282
1283 if (savedError)
1284 return sendError(savedError, "all found paths have failed");
1285
1286 return sendError(new ErrorState(ERR_CANNOT_FORWARD, Http::scInternalServerError, request.getRaw(), al),
1287 "path selection found no paths");
1288 }
1289 // else continue to use one of the previously noted destinations;
1290 // if all of them fail, tunneling as whole will fail
1291 Must(!selectionError); // finding at least one path means selection succeeded
1292
1293 if (Comm::IsConnOpen(server.conn)) {
1294 // We are already using a previously opened connection but also
1295 // receiving destinations in case we need to re-forward.
1296 Must(!opening());
1297 return;
1298 }
1299
1300 Must(opening()); // or we would be stuck with nothing to do or wait for
1301 notifyConnOpener();
1302 }
1303
1304 /// remembers an error to be used if there will be no more connection attempts
1305 void
1306 TunnelStateData::saveError(ErrorState *error)
1307 {
1308 debugs(26, 4, savedError << " ? " << error);
1309 assert(error);
1310 delete savedError; // may be nil
1311 savedError = error;
1312 }
1313
1314 /// Starts sending the given error message to the client, leading to the
1315 /// eventual transaction termination. Call with savedError to send savedError.
1316 void
1317 TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1318 {
1319 debugs(26, 3, "aborting transaction for " << reason);
1320
1321 if (request)
1322 request->hier.stopPeerClock(false);
1323
1324 if (opening())
1325 cancelOpening(reason);
1326
1327 assert(finalError);
1328
1329 // get rid of any cached error unless that is what the caller is sending
1330 if (savedError != finalError)
1331 delete savedError; // may be nil
1332 savedError = nullptr;
1333
1334 // we cannot try other destinations after responding with an error
1335 PeerSelectionInitiator::subscribed = false; // may already be false
1336
1337 *status_ptr = finalError->httpStatus;
1338 finalError->callback = tunnelErrorComplete;
1339 finalError->callback_data = this;
1340 errorSend(client.conn, finalError);
1341 }
1342
1343 /// Notify connOpener that we no longer need connections. We do not have to do
1344 /// this -- connOpener would eventually notice on its own, but notifying reduces
1345 /// waste and speeds up spare connection opening for other transactions (that
1346 /// could otherwise wait for this transaction to use its spare allowance).
1347 void
1348 TunnelStateData::cancelOpening(const char *reason)
1349 {
1350 assert(calls.connector);
1351 calls.connector->cancel(reason);
1352 calls.connector = nullptr;
1353 notifyConnOpener();
1354 connOpener.clear();
1355 }
1356
1357 void
1358 TunnelStateData::startConnecting()
1359 {
1360 if (request)
1361 request->hier.startPeerClock();
1362
1363 assert(!destinations->empty());
1364 assert(!opening());
1365 calls.connector = asyncCall(17, 5, "TunnelStateData::noteConnection", HappyConnOpener::CbDialer<TunnelStateData>(&TunnelStateData::noteConnection, this));
1366 const auto cs = new HappyConnOpener(destinations, calls.connector, request, startTime, 0, al);
1367 cs->setHost(request->url.host());
1368 cs->setRetriable(false);
1369 cs->allowPersistent(false);
1370 destinations->notificationPending = true; // start() is async
1371 connOpener = cs;
1372 AsyncJob::Start(cs);
1373 }
1374
1375 /// send request on an existing connection dedicated to the requesting client
1376 void
1377 TunnelStateData::usePinned()
1378 {
1379 Must(request);
1380 const auto connManager = request->pinnedConnection();
1381 try {
1382 const auto serverConn = ConnStateData::BorrowPinnedConnection(request.getRaw(), al);
1383 debugs(26, 7, "pinned peer connection: " << serverConn);
1384
1385 // Set HttpRequest pinned related flags for consistency even if
1386 // they are not really used by tunnel.cc code.
1387 request->flags.pinned = true;
1388 if (connManager->pinnedAuth())
1389 request->flags.auth = true;
1390
1391 // the server may close the pinned connection before this request
1392 const auto reused = true;
1393 connectDone(serverConn, connManager->pinning.host, reused);
1394 } catch (ErrorState * const error) {
1395 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
1396 // XXX: Honor clientExpectsConnectResponse() before replying.
1397 // a PINNED path failure is fatal; do not wait for more paths
1398 sendError(error, "pinned path failure");
1399 return;
1400 }
1401
1402 }
1403
1404 CBDATA_CLASS_INIT(TunnelStateData);
1405
1406 bool
1407 TunnelStateData::noConnections() const
1408 {
1409 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
1410 }
1411
1412 #if USE_DELAY_POOLS
1413 void
1414 TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
1415 {
1416 delayId = newDelay;
1417 }
1418
1419 #endif
1420
1421 /// makes sure connOpener knows that destinations have changed
1422 void
1423 TunnelStateData::notifyConnOpener()
1424 {
1425 if (destinations->notificationPending) {
1426 debugs(17, 7, "reusing pending notification");
1427 } else {
1428 destinations->notificationPending = true;
1429 CallJobHere(17, 5, connOpener, HappyConnOpener, noteCandidatesChange);
1430 }
1431 }
1432
1433 /**
1434 * Sets up a TCP tunnel through Squid and starts shoveling traffic.
1435 * \param request the request that initiated/caused this tunnel
1436 * \param clientConn the already accepted client-to-Squid TCP connection
1437 * \param srvConn the already established Squid-to-server TCP connection
1438 * \param preReadServerData server-sent bytes to be forwarded to the client
1439 */
1440 void
1441 switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
1442 {
1443 Must(Comm::IsConnOpen(clientConn));
1444 Must(Comm::IsConnOpen(srvConn));
1445
1446 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1447
1448 /* Create state structure. */
1449 ++statCounter.server.all.requests;
1450 ++statCounter.server.other.requests;
1451
1452 auto conn = request->clientConnectionManager.get();
1453 Must(conn);
1454 Http::StreamPointer context = conn->pipeline.front();
1455 Must(context && context->http);
1456
1457 debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
1458
1459 TunnelStateData *tunnelState = new TunnelStateData(context->http);
1460 tunnelState->retriable = false;
1461
1462 request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
1463
1464 tunnelState->server.initConnection(srvConn, tunnelServerClosed, "tunnelServerClosed", tunnelState);
1465
1466 #if USE_DELAY_POOLS
1467 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1468 if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
1469 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1470 #endif
1471
1472 request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
1473
1474 debugs(26, 4, "determine post-connect handling pathway.");
1475 if (const auto peer = srvConn->getPeer())
1476 request->prepForPeering(*peer);
1477 else
1478 request->prepForDirect();
1479
1480 tunnelState->preReadServerData = preReadServerData;
1481
1482 tunnelStartShoveling(tunnelState);
1483 }
1484