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