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