]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
CI: Remove unnecessary test-functionality test wrappers (#1393)
[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
25d2603f
EB
263 void deleteThis();
264
2b6b1bcb
AR
265 void cancelStep(const char *reason);
266
a98270b0 267 bool exhaustedTries() const;
e7a9b7a8 268 void updateAttempts(int);
a98270b0 269
5c2f68b7 270public:
c8407295 271 bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
3ed5793b 272 void copy(size_t len, Connection &from, Connection &to, IOCB *);
c8407295
AJ
273 void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
274 void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
275 void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
276 void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
3ed5793b 277
3248e962 278 void copyClientBytes();
6821c276 279 void copyServerBytes();
25d2603f
EB
280
281 /// handles client-to-Squid connection closure; may destroy us
282 void clientClosed();
283
284 /// handles Squid-to-server connection closure; may destroy us
285 void serverClosed();
286
287 /// tries connecting to another destination, if available,
288 /// otherwise, initiates the transaction termination
289 void retryOrBail(const char *context);
a46d2c0e 290};
983061ed 291
11007d4b 292static ERCB tunnelErrorComplete;
575d05c4
AJ
293static CLCB tunnelServerClosed;
294static CLCB tunnelClientClosed;
8d77a37c 295static CTCB tunnelTimeout;
215c41fa
AJ
296static EVH tunnelDelayedClientRead;
297static EVH tunnelDelayedServerRead;
30a4f2a8 298
25d2603f 299/// TunnelStateData::serverClosed() wrapper
b8d8561b 300static void
575d05c4 301tunnelServerClosed(const CommCloseCbParams &params)
30a4f2a8 302{
25d2603f
EB
303 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
304 tunnelState->serverClosed();
305}
26ac0430 306
25d2603f
EB
307void
308TunnelStateData::serverClosed()
309{
310 server.noteClosure();
752fa208
AR
311
312 retryOrBail(__FUNCTION__);
30a4f2a8 313}
314
25d2603f 315/// TunnelStateData::clientClosed() wrapper
b177367b 316static void
575d05c4 317tunnelClientClosed(const CommCloseCbParams &params)
30a4f2a8 318{
25d2603f
EB
319 const auto tunnelState = reinterpret_cast<TunnelStateData *>(params.data);
320 tunnelState->clientClosed();
321}
62e76326 322
25d2603f
EB
323void
324TunnelStateData::clientClosed()
325{
326 client.noteClosure();
26ac0430 327
25d2603f
EB
328 if (noConnections())
329 return deleteThis();
330
331 if (!server.writer)
332 server.conn->close();
333}
334
335/// destroys the tunnel (after performing potentially-throwing cleanup)
336void
337TunnelStateData::deleteThis()
338{
339 assert(noConnections());
340 // ConnStateData pipeline should contain the CONNECT we are performing
341 // but it may be invalid already (bug 4392)
342 if (const auto h = http.valid()) {
343 if (const auto c = h->getConn())
344 if (const auto ctx = c->pipeline.front())
345 ctx->finished();
71a2ced6 346 }
25d2603f 347 delete this;
30a4f2a8 348}
983061ed 349
6b2b6cfe 350TunnelStateData::TunnelStateData(ClientHttpRequest *clientRequest) :
f5e17947 351 startTime(squid_curtime),
55622953 352 destinations(new ResolvedPeers()),
5106d639 353 destinationsFound(false),
e2bbd3b3 354 committedToServer(false),
a98270b0
EB
355 n_tries(0),
356 banRetries(nullptr),
5106d639 357 codeContext(CodeContext::Current())
8ca1d33d
AJ
358{
359 debugs(26, 3, "TunnelStateData constructed this=" << this);
215c41fa
AJ
360 client.readPendingFunc = &tunnelDelayedClientRead;
361 server.readPendingFunc = &tunnelDelayedServerRead;
6b2b6cfe
CT
362
363 assert(clientRequest);
364 url = xstrdup(clientRequest->uri);
365 request = clientRequest->request;
55622953 366 Must(request);
6b2b6cfe
CT
367 server.size_ptr = &clientRequest->out.size;
368 client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData;
369 status_ptr = &clientRequest->al->http.code;
6b2b6cfe
CT
370 al = clientRequest->al;
371 http = clientRequest;
372
c6aa169d
AR
373 al->cache.code.update(LOG_TCP_TUNNEL);
374
25d2603f 375 client.initConnection(clientRequest->getConn()->clientConnection, tunnelClientClosed, "tunnelClientClosed", this);
6b2b6cfe
CT
376
377 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
378 CommTimeoutCbPtrFun(tunnelTimeout, this));
379 commSetConnTimeout(client.conn, Config.Timeout.lifetime, timeoutCall);
8ca1d33d
AJ
380}
381
382TunnelStateData::~TunnelStateData()
983061ed 383{
8ca1d33d
AJ
384 debugs(26, 3, "TunnelStateData destructed this=" << this);
385 assert(noConnections());
386 xfree(url);
2b6b1bcb 387 cancelStep("~TunnelStateData");
6043e368 388 delete savedError;
983061ed 389}
390
8a467c4b
AJ
391TunnelStateData::Connection::~Connection()
392{
215c41fa
AJ
393 if (readPending)
394 eventDelete(readPendingFunc, readPending);
395
8a467c4b
AJ
396 safe_free(buf);
397}
398
25d2603f
EB
399const char *
400TunnelStateData::checkRetry()
401{
402 if (shutting_down)
403 return "shutting down";
a98270b0
EB
404 if (exhaustedTries())
405 return "exhausted tries";
25d2603f
EB
406 if (!FwdState::EnoughTimeToReForward(startTime))
407 return "forwarding timeout";
a98270b0
EB
408 if (banRetries)
409 return banRetries;
25d2603f
EB
410 if (noConnections())
411 return "no connections";
a98270b0 412
09835feb 413 // TODO: Use std::optional for peer_reply_status to avoid treating zero value specially.
a98270b0
EB
414 if (request->hier.peer_reply_status != Http::scNone && !Http::IsReforwardableStatus(request->hier.peer_reply_status))
415 return "received HTTP status code is not reforwardable";
416
417 // TODO: check pinned connections; see FwdState::pinnedCanRetry()
25d2603f
EB
418 return nullptr;
419}
420
421void
422TunnelStateData::retryOrBail(const char *context)
423{
25d2603f
EB
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
a46d2c0e 465int
8a467c4b 466TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
447e176b 467{
9a0a18de 468#if USE_DELAY_POOLS
8a467c4b 469 return delayId.bytesWanted(lowerbound, upperbound);
a46d2c0e 470#else
8b082ed9 471 (void)lowerbound;
8a467c4b 472 return upperbound;
a46d2c0e 473#endif
474}
62e76326 475
a46d2c0e 476void
fa34dd97 477TunnelStateData::Connection::bytesIn(int const &count)
a46d2c0e 478{
bf95c10a 479 debugs(26, 3, "len=" << len << " + count=" << count);
9a0a18de 480#if USE_DELAY_POOLS
a46d2c0e 481 delayId.bytesIn(count);
482#endif
62e76326 483
a46d2c0e 484 len += count;
447e176b 485}
62e76326 486
55622953
CT
487/// update "hierarchy" annotations with a new (possibly failed) destination
488/// \param origin the name of the origin server we were trying to reach
489void
490TunnelStateData::syncHierNote(const Comm::ConnectionPointer &conn, const char *origin)
491{
492 request->hier.resetPeerNotes(conn, origin);
12f5a662 493 al->hier.resetPeerNotes(conn, origin);
55622953
CT
494}
495
e7a9b7a8
EB
496/// sets n_tries to the given value (while keeping ALE in sync)
497void
498TunnelStateData::updateAttempts(const int newValue)
499{
500 Assure(n_tries <= newValue); // n_tries cannot decrease
501
502 // Squid probably creates at most one FwdState/TunnelStateData object per
503 // ALE, but, unlike an assignment would, this increment logic works even if
504 // Squid uses multiple such objects for a given ALE in some esoteric cases.
505 al->requestAttempts += (newValue - n_tries);
506
507 n_tries = newValue;
508 debugs(26, 5, n_tries);
509}
510
a46d2c0e 511int
fa34dd97 512TunnelStateData::Connection::debugLevelForError(int const xerrno) const
a46d2c0e 513{
514#ifdef ECONNRESET
515
516 if (xerrno == ECONNRESET)
517 return 2;
518
447e176b 519#endif
520
a46d2c0e 521 if (ignoreErrno(xerrno))
522 return 3;
523
524 return 1;
525}
adb78bd4 526
983061ed 527/* Read from server side and queue it for writing to the client */
a46d2c0e 528void
c8407295 529TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
983061ed 530{
fa34dd97 531 TunnelStateData *tunnelState = (TunnelStateData *)data;
e0d28505 532 assert(cbdataReferenceValid(tunnelState));
bf95c10a 533 debugs(26, 3, c);
c4b7a5a9 534
11007d4b 535 tunnelState->readServer(buf, len, errcode, xerrno);
a46d2c0e 536}
62e76326 537
a46d2c0e 538void
ced8def3 539TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
a46d2c0e 540{
bf95c10a 541 debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
9fe3d316 542 server.delayedLoops=0;
d01053a2 543
a46d2c0e 544 /*
c8407295 545 * Bail out early on Comm::ERR_CLOSING
26ac0430 546 * - close handlers will tidy up for us
a46d2c0e 547 */
a55f4cea 548
c8407295 549 if (errcode == Comm::ERR_CLOSING)
a46d2c0e 550 return;
62e76326 551
ee1679df 552 if (len > 0) {
a46d2c0e 553 server.bytesIn(len);
a0864754
AJ
554 statCounter.server.all.kbytes_in += len;
555 statCounter.server.other.kbytes_in += len;
d8165775 556 request->hier.notePeerRead();
ee1679df 557 }
62e76326 558
3ed5793b
AR
559 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
560 copy(len, server, client, WriteClientDone);
561}
562
a46d2c0e 563void
fa34dd97 564TunnelStateData::Connection::error(int const xerrno)
a46d2c0e 565{
bf95c10a 566 debugs(50, debugLevelForError(xerrno), conn << ": read/write failure: " << xstrerr(xerrno));
62e76326 567
a46d2c0e 568 if (!ignoreErrno(xerrno))
fb046c1b 569 conn->close();
983061ed 570}
571
572/* Read from client side and queue it for writing to the server */
a46d2c0e 573void
c8407295 574TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
983061ed 575{
fa34dd97 576 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 577 assert (cbdataReferenceValid (tunnelState));
62e76326 578
11007d4b 579 tunnelState->readClient(buf, len, errcode, xerrno);
a46d2c0e 580}
62e76326 581
a46d2c0e 582void
ced8def3 583TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
a46d2c0e 584{
bf95c10a 585 debugs(26, 3, client.conn << ", read " << len << " bytes, err=" << errcode);
9fe3d316 586 client.delayedLoops=0;
d01053a2 587
a46d2c0e 588 /*
c8407295 589 * Bail out early on Comm::ERR_CLOSING
26ac0430 590 * - close handlers will tidy up for us
a46d2c0e 591 */
a55f4cea 592
c8407295 593 if (errcode == Comm::ERR_CLOSING)
a46d2c0e 594 return;
a55f4cea 595
a46d2c0e 596 if (len > 0) {
597 client.bytesIn(len);
a0864754 598 statCounter.client_http.kbytes_in += len;
a46d2c0e 599 }
62e76326 600
3ed5793b
AR
601 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
602 copy(len, client, server, WriteServerDone);
a46d2c0e 603}
62e76326 604
3ed5793b
AR
605/// Updates state after reading from client or server.
606/// Returns whether the caller should use the data just read.
607bool
c8407295 608TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
a46d2c0e 609{
bf95c10a 610 debugs(26, 3, "from={" << from.conn << "}, to={" << to.conn << "}");
fd54d9b2 611
a46d2c0e 612 /* I think this is to prevent free-while-in-a-callback behaviour
26ac0430 613 * - RBC 20030229
fb046c1b 614 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
a46d2c0e 615 */
83564ee7 616 const CbcPointer<TunnelStateData> safetyLock(this);
62e76326 617
60dafd5e 618 /* Bump the source connection read timeout on any activity */
8d77a37c
AJ
619 if (Comm::IsConnOpen(from.conn)) {
620 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
dc49061a 621 CommTimeoutCbPtrFun(tunnelTimeout, this));
8d77a37c
AJ
622 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
623 }
99c02c10 624
2677c3b1
JPM
625 /* Bump the dest connection read timeout on any activity */
626 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
627 if (Comm::IsConnOpen(to.conn)) {
628 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
629 CommTimeoutCbPtrFun(tunnelTimeout, this));
630 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
631 }
632
58c0b17d 633 if (errcode)
a46d2c0e 634 from.error (xerrno);
60dafd5e 635 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
bf95c10a 636 debugs(26, 3, "Nothing to write or client gone. Terminate the tunnel.");
fb046c1b 637 from.conn->close();
62e76326 638
60dafd5e 639 /* Only close the remote end if we've finished queueing data to it */
97c81191 640 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
fb046c1b 641 to.conn->close();
c4b7a5a9 642 }
ec41b64c 643 } else if (cbdataReferenceValid(this)) {
3ed5793b
AR
644 return true;
645 }
646
647 return false;
648}
649
650void
651TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
652{
bf95c10a 653 debugs(26, 3, "Schedule Write");
1c8fc082
A
654 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
655 CommIoCbPtrFun(completion, this));
aee3523a 656 to.write(from.buf, len, call, nullptr);
983061ed 657}
658
659/* Writes data from the client buffer to the server side */
a46d2c0e 660void
c8407295 661TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
983061ed 662{
fa34dd97 663 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 664 assert (cbdataReferenceValid (tunnelState));
aee3523a 665 tunnelState->server.writer = nullptr;
a46d2c0e 666
11007d4b 667 tunnelState->writeServerDone(buf, len, flag, xerrno);
a46d2c0e 668}
a55f4cea 669
a46d2c0e 670void
ced8def3 671TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
a46d2c0e 672{
bf95c10a 673 debugs(26, 3, server.conn << ", " << len << " bytes written, flag=" << flag);
62e76326 674
d8165775
AR
675 if (flag == Comm::ERR_CLOSING)
676 return;
677
678 request->hier.notePeerWrite();
679
5dacdf3f 680 /* Error? */
c8407295 681 if (flag != Comm::OK) {
d8165775
AR
682 debugs(26, 4, "to-server write failed: " << xerrno);
683 server.error(xerrno); // may call comm_close
5dacdf3f 684 return;
c4b7a5a9 685 }
62e76326 686
5dacdf3f 687 /* EOF? */
a46d2c0e 688 if (len == 0) {
bf95c10a 689 debugs(26, 4, "No read input. Closing server connection.");
fb046c1b 690 server.conn->close();
a46d2c0e 691 return;
692 }
62e76326 693
5dacdf3f 694 /* Valid data */
a0864754
AJ
695 statCounter.server.all.kbytes_out += len;
696 statCounter.server.other.kbytes_out += len;
5dacdf3f 697 client.dataSent(len);
698
a46d2c0e 699 /* If the other end has closed, so should we */
97c81191 700 if (!Comm::IsConnOpen(client.conn)) {
bf95c10a 701 debugs(26, 4, "Client gone away. Shutting down server connection.");
fb046c1b 702 server.conn->close();
a55f4cea 703 return;
c4b7a5a9 704 }
62e76326 705
f53969cc 706 const CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
a46d2c0e 707
5dacdf3f 708 if (cbdataReferenceValid(this))
3248e962 709 copyClientBytes();
983061ed 710}
711
712/* Writes data from the server buffer to the client side */
a46d2c0e 713void
c8407295 714TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
983061ed 715{
fa34dd97 716 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 717 assert (cbdataReferenceValid (tunnelState));
aee3523a 718 tunnelState->client.writer = nullptr;
a46d2c0e 719
11007d4b 720 tunnelState->writeClientDone(buf, len, flag, xerrno);
a46d2c0e 721}
722
723void
e0d28505 724TunnelStateData::Connection::dataSent(size_t amount)
a46d2c0e 725{
bf95c10a 726 debugs(26, 3, "len=" << len << " - amount=" << amount);
a46d2c0e 727 assert(amount == (size_t)len);
728 len =0;
729 /* increment total object size */
730
731 if (size_ptr)
732 *size_ptr += amount;
d8165775 733
a46d2c0e 734}
735
74f35ca8
AR
736void
737TunnelStateData::Connection::write(const char *b, int size, AsyncCall::Pointer &callback, FREE * free_func)
738{
739 writer = callback;
25d2603f 740 dirty = true;
74f35ca8
AR
741 Comm::Write(conn, b, size, callback, free_func);
742}
743
25d2603f
EB
744template <typename Method>
745void
746TunnelStateData::Connection::initConnection(const Comm::ConnectionPointer &aConn, Method method, const char *name, TunnelStateData *tunnelState)
747{
748 Must(!Comm::IsConnOpen(conn));
749 Must(!closer);
750 Must(Comm::IsConnOpen(aConn));
751 conn = aConn;
752 closer = commCbCall(5, 4, name, CommCloseCbPtrFun(method, tunnelState));
753 comm_add_close_handler(conn->fd, closer);
754}
755
756void
757TunnelStateData::Connection::noteClosure()
758{
759 debugs(26, 3, conn);
760 conn = nullptr;
761 closer = nullptr;
762 writer = nullptr; // may already be nil
763}
764
a46d2c0e 765void
ced8def3 766TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
a46d2c0e 767{
bf95c10a 768 debugs(26, 3, client.conn << ", " << len << " bytes written, flag=" << flag);
62e76326 769
d8165775
AR
770 if (flag == Comm::ERR_CLOSING)
771 return;
772
5dacdf3f 773 /* Error? */
c8407295 774 if (flag != Comm::OK) {
d8165775
AR
775 debugs(26, 4, "from-client read failed: " << xerrno);
776 client.error(xerrno); // may call comm_close
5dacdf3f 777 return;
c4b7a5a9 778 }
62e76326 779
5dacdf3f 780 /* EOF? */
a46d2c0e 781 if (len == 0) {
bf95c10a 782 debugs(26, 4, "Closing client connection due to 0 byte read.");
fb046c1b 783 client.conn->close();
62e76326 784 return;
983061ed 785 }
62e76326 786
5dacdf3f 787 /* Valid data */
a0864754 788 statCounter.client_http.kbytes_out += len;
5dacdf3f 789 server.dataSent(len);
790
a46d2c0e 791 /* If the other end has closed, so should we */
97c81191 792 if (!Comm::IsConnOpen(server.conn)) {
bf95c10a 793 debugs(26, 4, "Server has gone away. Terminating client connection.");
fb046c1b 794 client.conn->close();
a55f4cea 795 return;
983061ed 796 }
62e76326 797
f53969cc 798 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
a55f4cea 799
5dacdf3f 800 if (cbdataReferenceValid(this))
6821c276 801 copyServerBytes();
983061ed 802}
803
b8d8561b 804static void
8d77a37c 805tunnelTimeout(const CommTimeoutCbParams &io)
983061ed 806{
8d77a37c 807 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
bf95c10a 808 debugs(26, 3, io.conn);
11007d4b 809 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
83564ee7 810 CbcPointer<TunnelStateData> safetyLock(tunnelState);
a55f4cea 811
25d2603f 812 tunnelState->closeConnections();
a46d2c0e 813}
62e76326 814
25b0ce45
CT
815void
816TunnelStateData::closePendingConnection(const Comm::ConnectionPointer &conn, const char *reason)
817{
818 debugs(26, 3, "because " << reason << "; " << conn);
819 assert(!server.conn);
820 if (IsConnOpen(conn))
821 conn->close();
822}
823
a46d2c0e 824void
25d2603f 825TunnelStateData::closeConnections()
a46d2c0e 826{
25d2603f
EB
827 if (Comm::IsConnOpen(server.conn))
828 server.conn->close();
829 if (Comm::IsConnOpen(client.conn))
830 client.conn->close();
a46d2c0e 831}
832
9fe3d316
AJ
833static void
834tunnelDelayedClientRead(void *data)
835{
836 if (!data)
837 return;
4846303f 838
215c41fa 839 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
5106d639
EB
840 const auto savedContext = CodeContext::Current();
841 CodeContext::Reset(tunnel->codeContext);
aee3523a 842 tunnel->client.readPending = nullptr;
9fe3d316 843 static uint64_t counter=0;
215c41fa 844 debugs(26, 7, "Client read(2) delayed " << ++counter << " times");
9fe3d316 845 tunnel->copyRead(tunnel->client, TunnelStateData::ReadClient);
5106d639 846 CodeContext::Reset(savedContext);
9fe3d316
AJ
847}
848
849static void
850tunnelDelayedServerRead(void *data)
851{
852 if (!data)
853 return;
4846303f 854
215c41fa 855 TunnelStateData *tunnel = static_cast<TunnelStateData*>(data);
5106d639
EB
856 const auto savedContext = CodeContext::Current();
857 CodeContext::Reset(tunnel->codeContext);
aee3523a 858 tunnel->server.readPending = nullptr;
9fe3d316 859 static uint64_t counter=0;
215c41fa 860 debugs(26, 7, "Server read(2) delayed " << ++counter << " times");
9fe3d316 861 tunnel->copyRead(tunnel->server, TunnelStateData::ReadServer);
5106d639 862 CodeContext::Reset(savedContext);
9fe3d316
AJ
863}
864
a46d2c0e 865void
fa34dd97 866TunnelStateData::copyRead(Connection &from, IOCB *completion)
a46d2c0e 867{
868 assert(from.len == 0);
9fe3d316
AJ
869 // If only the minimum permitted read size is going to be attempted
870 // then we schedule an event to try again in a few I/O cycles.
871 // Allow at least 1 byte to be read every (0.3*10) seconds.
872 int bw = from.bytesWanted(1, SQUID_TCP_SO_RCVBUF);
5106d639
EB
873 // XXX: Delay pools must not delay client-to-Squid traffic (i.e. when
874 // from.readPendingFunc is tunnelDelayedClientRead()).
a928fdfd 875 // XXX: Bug #4913: For delay pools, use delayRead() API instead.
9fe3d316 876 if (bw == 1 && ++from.delayedLoops < 10) {
215c41fa
AJ
877 from.readPending = this;
878 eventAdd("tunnelDelayedServerRead", from.readPendingFunc, from.readPending, 0.3, true);
9fe3d316
AJ
879 return;
880 }
881
fd54d9b2 882 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
abd8f140 883 CommIoCbPtrFun(completion, this));
9fe3d316 884 comm_read(from.conn, from.buf, bw, call);
983061ed 885}
886
3248e962
CT
887void
888TunnelStateData::copyClientBytes()
889{
890 if (preReadClientData.length()) {
891 size_t copyBytes = preReadClientData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadClientData.length();
892 memcpy(client.buf, preReadClientData.rawContent(), copyBytes);
893 preReadClientData.consume(copyBytes);
894 client.bytesIn(copyBytes);
895 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, client, server))
896 copy(copyBytes, client, server, TunnelStateData::WriteServerDone);
897 } else
898 copyRead(client, ReadClient);
899}
900
6821c276
CT
901void
902TunnelStateData::copyServerBytes()
903{
904 if (preReadServerData.length()) {
905 size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
906 memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
907 preReadServerData.consume(copyBytes);
908 server.bytesIn(copyBytes);
909 if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
910 copy(copyBytes, server, client, TunnelStateData::WriteClientDone);
911 } else
912 copyRead(server, ReadServer);
913}
914
379e8c1c 915/**
87f237a9 916 * Set the HTTP status for this request and sets the read handlers for client
379e8c1c
AR
917 * and server side connections.
918 */
919static void
920tunnelStartShoveling(TunnelStateData *tunnelState)
921{
2b6b1bcb
AR
922 assert(!tunnelState->transportWait);
923 assert(!tunnelState->encryptionWait);
924 assert(!tunnelState->peerWait);
925
25b0ce45
CT
926 assert(tunnelState->server.conn);
927 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
928 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
929 commSetConnTimeout(tunnelState->server.conn, Config.Timeout.read, timeoutCall);
930
955394ce 931 *tunnelState->status_ptr = Http::scOkay;
379e8c1c 932 if (cbdataReferenceValid(tunnelState)) {
6c420975 933
5eedd56a 934 // Shovel any payload already pushed into reply buffer by the server response
3ed5793b 935 if (!tunnelState->server.len)
6821c276 936 tunnelState->copyServerBytes();
6c420975
AJ
937 else {
938 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
3ed5793b 939 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
6c420975
AJ
940 }
941
fcc444e3
AJ
942 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->inBuf.isEmpty()) {
943 SBuf * const in = &tunnelState->http->getConn()->inBuf;
944 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << *in << "\n----------");
945 tunnelState->preReadClientData.append(*in);
946 in->consume(); // ConnStateData buffer accounting after the shuffle.
3248e962
CT
947 }
948 tunnelState->copyClientBytes();
379e8c1c
AR
949 }
950}
951
b0388924
AJ
952/**
953 * All the pieces we need to write to client and/or server connection
1b76e6c1 954 * have been written.
379e8c1c 955 * Call the tunnelStartShoveling to start the blind pump.
b0388924 956 */
c4b7a5a9 957static void
c6f9a0ff 958tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t len, Comm::Flag flag, int, void *data)
c4b7a5a9 959{
fa34dd97 960 TunnelStateData *tunnelState = (TunnelStateData *)data;
bf95c10a 961 debugs(26, 3, conn << ", flag=" << flag);
aee3523a 962 tunnelState->client.writer = nullptr;
62e76326 963
c8407295 964 if (flag != Comm::OK) {
955394ce 965 *tunnelState->status_ptr = Http::scInternalServerError;
e0d28505 966 tunnelErrorComplete(conn->fd, data, 0);
62e76326 967 return;
968 }
969
c6f9a0ff
CT
970 if (auto http = tunnelState->http.get()) {
971 http->out.headers_sz += len;
972 http->out.size += len;
973 }
974
379e8c1c 975 tunnelStartShoveling(tunnelState);
c4b7a5a9 976}
977
f5e17947
CT
978void
979TunnelStateData::tunnelEstablishmentDone(Http::TunnelerAnswer &answer)
3ed5793b 980{
2b6b1bcb 981 peerWait.finish();
f5e17947 982 server.len = 0;
3ed5793b 983
a98270b0
EB
984 // XXX: al->http.code (i.e. *status_ptr) should not be (re)set
985 // until we actually start responding to the client. Right here/now, we only
986 // know how this cache_peer has responded to us.
f5e17947
CT
987 if (answer.peerResponseStatus != Http::scNone)
988 *status_ptr = answer.peerResponseStatus;
989
25b0ce45
CT
990 auto sawProblem = false;
991
992 if (!answer.positive()) {
993 sawProblem = true;
2b6b1bcb 994 assert(!answer.conn);
25b0ce45
CT
995 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
996 sawProblem = true;
997 closePendingConnection(answer.conn, "conn was closed while waiting for tunnelEstablishmentDone");
998 }
999
1000 if (!sawProblem) {
1001 assert(answer.positive()); // paranoid
f5e17947
CT
1002 // copy any post-200 OK bytes to our buffer
1003 preReadServerData = answer.leftovers;
25b0ce45 1004 notePeerReadyToShovel(answer.conn);
3ed5793b
AR
1005 return;
1006 }
1007
25b0ce45
CT
1008 ErrorState *error = nullptr;
1009 if (answer.positive()) {
1010 error = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request.getRaw(), al);
1011 } else {
1012 error = answer.squidError.get();
1013 Must(error);
1014 answer.squidError.clear(); // preserve error for errorSendComplete()
1015 }
1016 assert(error);
1017 saveError(error);
25d2603f 1018 retryOrBail("tunneler error");
3ed5793b
AR
1019}
1020
f5e17947 1021void
25b0ce45 1022TunnelStateData::notePeerReadyToShovel(const Comm::ConnectionPointer &conn)
983061ed 1023{
25d2603f 1024 assert(!client.dirty);
e2bbd3b3 1025 commitToServer(conn);
25b0ce45 1026
f5e17947
CT
1027 if (!clientExpectsConnectResponse())
1028 tunnelStartShoveling(this); // ssl-bumped connection, be quiet
379e8c1c 1029 else {
f5e17947 1030 *status_ptr = Http::scOkay;
379e8c1c 1031 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
f5e17947 1032 CommIoCbPtrFun(tunnelConnectedWriteDone, this));
ea55799d
EB
1033 al->reply = HttpReply::MakeConnectionEstablished();
1034 const auto mb = al->reply->pack();
1035 client.write(mb->content(), mb->contentSize(), call, mb->freeFunc());
1036 delete mb;
379e8c1c 1037 }
983061ed 1038}
1039
e2bbd3b3
AR
1040void
1041TunnelStateData::commitToServer(const Comm::ConnectionPointer &conn)
1042{
1043 committedToServer = true;
a98270b0 1044 banRetries = "committed to server";
e2bbd3b3
AR
1045 PeerSelectionInitiator::subscribed = false; // may already be false
1046 server.initConnection(conn, tunnelServerClosed, "tunnelServerClosed", this);
1047}
1048
b8d8561b 1049static void
fd54d9b2 1050tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
30a4f2a8 1051{
fa34dd97 1052 TunnelStateData *tunnelState = (TunnelStateData *)data;
bf95c10a 1053 debugs(26, 3, "FD " << fd);
aee3523a 1054 assert(tunnelState != nullptr);
11007d4b 1055 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
83564ee7 1056 CbcPointer<TunnelStateData> safetyLock(tunnelState);
62e76326 1057
97c81191 1058 if (Comm::IsConnOpen(tunnelState->client.conn))
fb046c1b 1059 tunnelState->client.conn->close();
62e76326 1060
97c81191 1061 if (Comm::IsConnOpen(tunnelState->server.conn))
fb046c1b 1062 tunnelState->server.conn->close();
30a4f2a8 1063}
1064
6043e368 1065void
55622953 1066TunnelStateData::noteConnection(HappyConnOpener::Answer &answer)
6043e368 1067{
2b6b1bcb 1068 transportWait.finish();
55622953 1069
e7a9b7a8 1070 updateAttempts(answer.n_tries);
a98270b0 1071
25b0ce45
CT
1072 ErrorState *error = nullptr;
1073 if ((error = answer.error.get())) {
a98270b0 1074 banRetries = "HappyConnOpener gave up";
25b0ce45 1075 Must(!Comm::IsConnOpen(answer.conn));
55622953 1076 syncHierNote(answer.conn, request->url.host());
25b0ce45
CT
1077 answer.error.clear();
1078 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1079 error = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request.getRaw(), al);
1080 closePendingConnection(answer.conn, "conn was closed while waiting for noteConnection");
1081 }
1082
1083 if (error) {
55622953 1084 saveError(error);
25d2603f 1085 retryOrBail("tried all destinations");
55622953
CT
1086 return;
1087 }
6043e368 1088
55622953 1089 connectDone(answer.conn, request->url.host(), answer.reused);
6043e368
AR
1090}
1091
55622953
CT
1092void
1093TunnelStateData::connectDone(const Comm::ConnectionPointer &conn, const char *origin, const bool reused)
983061ed 1094{
55622953 1095 Must(Comm::IsConnOpen(conn));
cfd66529 1096
55622953
CT
1097 if (reused)
1098 ResetMarkingsToServer(request.getRaw(), *conn);
1099 // else Comm::ConnOpener already applied proper/current markings
1100
a98270b0
EB
1101 // TODO: add pconn race state tracking
1102
25b0ce45 1103 syncHierNote(conn, origin);
cfd66529 1104
4beb4bab
AJ
1105#if USE_DELAY_POOLS
1106 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1107 if (conn->getPeer() && conn->getPeer()->options.no_delay)
55622953 1108 server.setDelayId(DelayId());
4beb4bab
AJ
1109#endif
1110
55622953 1111 netdbPingSite(request->url.host());
4beb4bab 1112
55622953 1113 request->peer_host = conn->getPeer() ? conn->getPeer()->host : nullptr;
cfd66529 1114
f5e17947
CT
1115 bool toOrigin = false; // same semantics as StateFlags::toOrigin
1116 if (const auto * const peer = conn->getPeer()) {
55622953 1117 request->prepForPeering(*peer);
f5e17947 1118 toOrigin = peer->options.originserver;
fe40a877 1119 } else {
55622953 1120 request->prepForDirect();
f5e17947 1121 toOrigin = true;
cfd66529 1122 }
62e76326 1123
f5e17947 1124 if (!toOrigin)
25b0ce45 1125 connectToPeer(conn);
cfd66529 1126 else {
25b0ce45 1127 notePeerReadyToShovel(conn);
983061ed 1128 }
983061ed 1129}
30a4f2a8 1130
a98270b0
EB
1131/// whether we have used up all permitted forwarding attempts
1132bool
1133TunnelStateData::exhaustedTries() const
1134{
1135 return n_tries >= Config.forward_max_tries;
1136}
1137
770f051d 1138void
ac9f46af 1139tunnelStart(ClientHttpRequest * http)
30a4f2a8 1140{
bf95c10a 1141 debugs(26, 3, MYNAME);
30a4f2a8 1142 /* Create state structure. */
aee3523a
AR
1143 TunnelStateData *tunnelState = nullptr;
1144 ErrorState *err = nullptr;
190154cf 1145 HttpRequest *request = http->request;
d5964d58 1146 char *url = http->uri;
fb046c1b 1147
f1003989 1148 /*
4dd643d5 1149 * client_addr.isNoAddr() indicates this is an "internal" request
a4b8110e 1150 * from peer_digest.c, asn.c, netdb.c, etc and should always
1151 * be allowed. yuck, I know.
1152 */
62e76326 1153
4dd643d5 1154 if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
62e76326 1155 /*
1156 * Check if this host is allowed to fetch MISSES from us (miss_access)
b50e327b 1157 * default is to allow.
62e76326 1158 */
aee3523a 1159 ACLFilledChecklist ch(Config.accessList.miss, request, nullptr);
cb365059 1160 ch.al = http->al;
62e76326 1161 ch.src_addr = request->client_addr;
1162 ch.my_addr = request->my_addr;
cb365059 1163 ch.syncAle(request, http->log_uri);
06bf5384 1164 if (ch.fastCheck().denied()) {
bf95c10a 1165 debugs(26, 4, "MISS access forbidden.");
c6aa169d 1166 http->updateLoggingTags(LOG_TCP_TUNNEL);
7e6eabbc 1167 err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request, http->al);
ac9f46af 1168 http->al->http.code = Http::scForbidden;
73c36fd9 1169 errorSend(http->getConn()->clientConnection, err);
62e76326 1170 return;
1171 }
f1003989 1172 }
62e76326 1173
7f06a3d8 1174 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
5db6bf73
FC
1175 ++statCounter.server.all.requests;
1176 ++statCounter.server.other.requests;
62e76326 1177
6b2b6cfe 1178 tunnelState = new TunnelStateData(http);
9a0a18de 1179#if USE_DELAY_POOLS
f5e17947 1180 tunnelState->server.setDelayId(DelayId::DelayClient(http));
59715b38 1181#endif
6043e368 1182 tunnelState->startSelectingDestinations(request, http->al, nullptr);
30a4f2a8 1183}
98ffb7e4 1184
a23223bf 1185void
25b0ce45 1186TunnelStateData::connectToPeer(const Comm::ConnectionPointer &conn)
e2849af8 1187{
25b0ce45
CT
1188 if (const auto p = conn->getPeer()) {
1189 if (p->secure.encryptTransport)
1190 return advanceDestination("secure connection to peer", conn, [this,&conn] {
1c2b4465
CT
1191 secureConnectionToPeer(conn);
1192 });
a23223bf 1193 }
a23223bf 1194
25b0ce45 1195 connectedToPeer(conn);
a23223bf
CT
1196}
1197
25b0ce45 1198/// encrypts an established TCP connection to peer
a23223bf 1199void
25b0ce45
CT
1200TunnelStateData::secureConnectionToPeer(const Comm::ConnectionPointer &conn)
1201{
e5ddd4ce 1202 const auto callback = asyncCallback(5, 4, TunnelStateData::noteSecurityPeerConnectorAnswer, this);
25b0ce45 1203 const auto connector = new Security::BlindPeerConnector(request, conn, callback, al);
2b6b1bcb 1204 encryptionWait.start(connector, callback);
25b0ce45
CT
1205}
1206
1207/// starts a preparation step for an established connection; retries on failures
1208template <typename StepStart>
1209void
1210TunnelStateData::advanceDestination(const char *stepDescription, const Comm::ConnectionPointer &conn, const StepStart &startStep)
1211{
1212 // TODO: Extract destination-specific handling from TunnelStateData so that
1213 // all the awkward, limited-scope advanceDestination() calls can be replaced
1214 // with a single simple try/catch,retry block.
1215 try {
1216 startStep();
1217 // now wait for the step callback
1218 } catch (...) {
1219 debugs (26, 2, "exception while trying to " << stepDescription << ": " << CurrentException);
1220 closePendingConnection(conn, "connection preparation exception");
1221 if (!savedError)
1222 saveError(new ErrorState(ERR_CANNOT_FORWARD, Http::scInternalServerError, request.getRaw(), al));
25d2603f 1223 retryOrBail(stepDescription);
25b0ce45
CT
1224 }
1225}
1226
1227/// callback handler for the connection encryptor
1228void
1229TunnelStateData::noteSecurityPeerConnectorAnswer(Security::EncryptorAnswer &answer)
a23223bf 1230{
2b6b1bcb
AR
1231 encryptionWait.finish();
1232
25d2603f 1233 ErrorState *error = nullptr;
2b6b1bcb 1234 assert(!answer.tunneled);
25d2603f 1235 if ((error = answer.error.get())) {
2b6b1bcb 1236 assert(!answer.conn);
25d2603f
EB
1237 answer.error.clear();
1238 } else if (!Comm::IsConnOpen(answer.conn) || fd_table[answer.conn->fd].closing()) {
1239 error = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, request.getRaw(), al);
1240 closePendingConnection(answer.conn, "conn was closed while waiting for noteSecurityPeerConnectorAnswer");
a23223bf
CT
1241 }
1242
25d2603f
EB
1243 if (error) {
1244 saveError(error);
1245 retryOrBail("TLS peer connection error");
25b0ce45
CT
1246 return;
1247 }
1248
1249 connectedToPeer(answer.conn);
1250}
1251
1252void
1253TunnelStateData::connectedToPeer(const Comm::ConnectionPointer &conn)
1254{
1255 advanceDestination("establish tunnel through proxy", conn, [this,&conn] {
1256 establishTunnelThruProxy(conn);
1257 });
1258}
1259
1260void
1261TunnelStateData::establishTunnelThruProxy(const Comm::ConnectionPointer &conn)
1262{
e5ddd4ce 1263 const auto callback = asyncCallback(5, 4, TunnelStateData::tunnelEstablishmentDone, this);
25b0ce45 1264 const auto tunneler = new Http::Tunneler(conn, request, callback, Config.Timeout.lifetime, al);
f5e17947
CT
1265#if USE_DELAY_POOLS
1266 tunneler->setDelayId(server.delayId);
1267#endif
2b6b1bcb 1268 peerWait.start(tunneler, callback);
98ffb7e4 1269}
33ea9fff 1270
6043e368
AR
1271void
1272TunnelStateData::noteDestination(Comm::ConnectionPointer path)
33ea9fff 1273{
55622953 1274 destinationsFound = true;
3dde9e52
CT
1275
1276 if (!path) { // decided to use a pinned connection
1277 // We can call usePinned() without fear of clashing with an earlier
1278 // forwarding attempt because PINNED must be the first destination.
55622953 1279 assert(destinations->empty());
3dde9e52
CT
1280 usePinned();
1281 return;
1282 }
1283
55622953
CT
1284 destinations->addPath(path);
1285
2b6b1bcb 1286 if (transportWait) {
e2bbd3b3 1287 assert(!transporting());
55622953
CT
1288 notifyConnOpener();
1289 return; // and continue to wait for tunnelConnectDone() callback
1290 }
1291
e2bbd3b3
AR
1292 if (transporting())
1293 return; // and continue to receive destinations for backup
1294
55622953 1295 startConnecting();
6043e368 1296}
62e76326 1297
6043e368
AR
1298void
1299TunnelStateData::noteDestinationsEnd(ErrorState *selectionError)
1300{
1301 PeerSelectionInitiator::subscribed = false;
55622953
CT
1302 destinations->destinationsFinalized = true;
1303 if (!destinationsFound) {
6b2b6cfe 1304
25d2603f
EB
1305 // XXX: Honor clientExpectsConnectResponse() before replying.
1306
6043e368
AR
1307 if (selectionError)
1308 return sendError(selectionError, "path selection has failed");
6b2b6cfe 1309
e2bbd3b3 1310 // TODO: Merge with FwdState and remove this likely unnecessary check.
6043e368 1311 if (savedError)
e2bbd3b3 1312 return sendError(savedError, "path selection found no paths (with an impossible early error)");
6043e368 1313
0d55f01c 1314 return sendError(new ErrorState(ERR_CANNOT_FORWARD, Http::scInternalServerError, request.getRaw(), al),
6043e368 1315 "path selection found no paths");
db1cd23c 1316 }
6043e368
AR
1317 // else continue to use one of the previously noted destinations;
1318 // if all of them fail, tunneling as whole will fail
1319 Must(!selectionError); // finding at least one path means selection succeeded
55622953 1320
e2bbd3b3
AR
1321 if (transportWait) {
1322 assert(!transporting());
1323 notifyConnOpener();
1324 return; // and continue to wait for the noteConnection() callback
1325 }
1326
1327 if (transporting()) {
1328 // We are already using a previously opened connection (but were also
1329 // receiving more destinations in case we need to re-forward).
1330 debugs(17, 7, "keep transporting");
55622953
CT
1331 return;
1332 }
1333
e2bbd3b3
AR
1334 // destinationsFound, but none of them worked, and we were waiting for more
1335 assert(savedError);
1336 // XXX: Honor clientExpectsConnectResponse() before replying.
1337 sendError(savedError, "all found paths have failed");
6043e368 1338}
a37fdd8a 1339
e2bbd3b3
AR
1340/// Whether a tunneling attempt to some selected destination X is in progress
1341/// (after successfully opening/reusing a transport connection to X).
1342/// \sa transportWait
2b6b1bcb 1343bool
e2bbd3b3 1344TunnelStateData::transporting() const
2b6b1bcb 1345{
e2bbd3b3 1346 return encryptionWait || peerWait || committedToServer;
2b6b1bcb
AR
1347}
1348
6043e368
AR
1349/// remembers an error to be used if there will be no more connection attempts
1350void
1351TunnelStateData::saveError(ErrorState *error)
1352{
1353 debugs(26, 4, savedError << " ? " << error);
1354 assert(error);
1355 delete savedError; // may be nil
1356 savedError = error;
1357}
1358
1359/// Starts sending the given error message to the client, leading to the
1360/// eventual transaction termination. Call with savedError to send savedError.
1361void
1362TunnelStateData::sendError(ErrorState *finalError, const char *reason)
1363{
1364 debugs(26, 3, "aborting transaction for " << reason);
1365
1366 if (request)
1367 request->hier.stopPeerClock(false);
1368
2b6b1bcb 1369 cancelStep(reason);
55622953 1370
6043e368 1371 assert(finalError);
16b70e2a 1372
6043e368
AR
1373 // get rid of any cached error unless that is what the caller is sending
1374 if (savedError != finalError)
1375 delete savedError; // may be nil
1376 savedError = nullptr;
62e76326 1377
6043e368
AR
1378 // we cannot try other destinations after responding with an error
1379 PeerSelectionInitiator::subscribed = false; // may already be false
1380
1381 *status_ptr = finalError->httpStatus;
1382 finalError->callback = tunnelErrorComplete;
1383 finalError->callback_data = this;
1384 errorSend(client.conn, finalError);
0ce8e93b
EB
1385}
1386
2b6b1bcb
AR
1387/// Notify a pending subtask, if any, that we no longer need its help. We do not
1388/// have to do this -- the subtask job will eventually end -- but ending it
1389/// earlier reduces waste and may reduce DoS attack surface.
55622953 1390void
2b6b1bcb 1391TunnelStateData::cancelStep(const char *reason)
55622953 1392{
2b6b1bcb
AR
1393 transportWait.cancel(reason);
1394 encryptionWait.cancel(reason);
1395 peerWait.cancel(reason);
55622953
CT
1396}
1397
0ce8e93b
EB
1398void
1399TunnelStateData::startConnecting()
1400{
6043e368
AR
1401 if (request)
1402 request->hier.startPeerClock();
1403
55622953 1404 assert(!destinations->empty());
e2bbd3b3 1405 assert(!transporting());
a98270b0
EB
1406
1407 delete savedError; // may still be nil
1408 savedError = nullptr;
1409 request->hier.peer_reply_status = Http::scNone; // TODO: Move to startPeerClock()?
1410
e5ddd4ce 1411 const auto callback = asyncCallback(17, 5, TunnelStateData::noteConnection, this);
a98270b0 1412 const auto cs = new HappyConnOpener(destinations, callback, request, startTime, n_tries, al);
55622953
CT
1413 cs->setHost(request->url.host());
1414 cs->setRetriable(false);
1415 cs->allowPersistent(false);
1416 destinations->notificationPending = true; // start() is async
2b6b1bcb 1417 transportWait.start(cs, callback);
33ea9fff 1418}
a46d2c0e 1419
3dde9e52
CT
1420/// send request on an existing connection dedicated to the requesting client
1421void
1422TunnelStateData::usePinned()
1423{
55622953
CT
1424 Must(request);
1425 const auto connManager = request->pinnedConnection();
daf80700
CT
1426 try {
1427 const auto serverConn = ConnStateData::BorrowPinnedConnection(request.getRaw(), al);
1428 debugs(26, 7, "pinned peer connection: " << serverConn);
1429
e7a9b7a8 1430 updateAttempts(n_tries + 1);
a98270b0 1431
daf80700
CT
1432 // Set HttpRequest pinned related flags for consistency even if
1433 // they are not really used by tunnel.cc code.
1434 request->flags.pinned = true;
1435 if (connManager->pinnedAuth())
1436 request->flags.auth = true;
1437
1438 // the server may close the pinned connection before this request
1439 const auto reused = true;
1440 connectDone(serverConn, connManager->pinning.host, reused);
1441 } catch (ErrorState * const error) {
1442 syncHierNote(nullptr, connManager ? connManager->pinning.host : request->url.host());
25d2603f 1443 // XXX: Honor clientExpectsConnectResponse() before replying.
3dde9e52 1444 // a PINNED path failure is fatal; do not wait for more paths
daf80700 1445 sendError(error, "pinned path failure");
3dde9e52
CT
1446 return;
1447 }
1448
3dde9e52
CT
1449}
1450
fa34dd97 1451CBDATA_CLASS_INIT(TunnelStateData);
a46d2c0e 1452
a46d2c0e 1453bool
fa34dd97 1454TunnelStateData::noConnections() const
a46d2c0e 1455{
97c81191 1456 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
a46d2c0e 1457}
1458
9a0a18de 1459#if USE_DELAY_POOLS
a46d2c0e 1460void
fa34dd97 1461TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
a46d2c0e 1462{
1463 delayId = newDelay;
1464}
1465
1466#endif
93ead3fd 1467
2b6b1bcb 1468/// makes sure connection opener knows that the destinations have changed
55622953
CT
1469void
1470TunnelStateData::notifyConnOpener()
1471{
1472 if (destinations->notificationPending) {
1473 debugs(17, 7, "reusing pending notification");
1474 } else {
1475 destinations->notificationPending = true;
2b6b1bcb 1476 CallJobHere(17, 5, transportWait.job(), HappyConnOpener, noteCandidatesChange);
55622953
CT
1477 }
1478}
1479
1c2b4465
CT
1480/**
1481 * Sets up a TCP tunnel through Squid and starts shoveling traffic.
1482 * \param request the request that initiated/caused this tunnel
1483 * \param clientConn the already accepted client-to-Squid TCP connection
1484 * \param srvConn the already established Squid-to-server TCP connection
1485 * \param preReadServerData server-sent bytes to be forwarded to the client
1486 */
93ead3fd 1487void
1c2b4465 1488switchToTunnel(HttpRequest *request, const Comm::ConnectionPointer &clientConn, const Comm::ConnectionPointer &srvConn, const SBuf &preReadServerData)
93ead3fd 1489{
25b0ce45
CT
1490 Must(Comm::IsConnOpen(clientConn));
1491 Must(Comm::IsConnOpen(srvConn));
1492
c91d4d4e 1493 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
93ead3fd 1494
6b2b6cfe 1495 /* Create state structure. */
93ead3fd
CT
1496 ++statCounter.server.all.requests;
1497 ++statCounter.server.other.requests;
1498
6b2b6cfe
CT
1499 auto conn = request->clientConnectionManager.get();
1500 Must(conn);
1501 Http::StreamPointer context = conn->pipeline.front();
1502 Must(context && context->http);
a95989ed 1503
6b2b6cfe 1504 debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver);
a95989ed 1505
6b2b6cfe 1506 TunnelStateData *tunnelState = new TunnelStateData(context->http);
e2bbd3b3 1507 tunnelState->commitToServer(srvConn);
93ead3fd 1508
d8165775 1509 request->hier.resetPeerNotes(srvConn, tunnelState->getHost());
93ead3fd 1510
6b2b6cfe
CT
1511#if USE_DELAY_POOLS
1512 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
f5e17947 1513 if (!srvConn->getPeer() || !srvConn->getPeer()->options.no_delay)
6b2b6cfe
CT
1514 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1515#endif
1516
f53e6e84 1517 request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr;
93ead3fd 1518
e4f14091 1519 debugs(26, 4, "determine post-connect handling pathway.");
f5e17947
CT
1520 if (const auto peer = srvConn->getPeer())
1521 request->prepForPeering(*peer);
1522 else
1523 request->prepForDirect();
93ead3fd 1524
1c2b4465 1525 tunnelState->preReadServerData = preReadServerData;
93ead3fd 1526
6821c276 1527 tunnelStartShoveling(tunnelState);
93ead3fd 1528}
f53969cc 1529