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