]> git.ipfire.org Git - thirdparty/squid.git/blob - src/tunnel.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / tunnel.cc
1 /*
2 * Copyright (C) 1996-2015 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 "client_side.h"
16 #include "client_side_request.h"
17 #include "comm.h"
18 #include "comm/Connection.h"
19 #include "comm/ConnOpener.h"
20 #include "comm/Read.h"
21 #include "comm/Write.h"
22 #include "errorpage.h"
23 #include "fde.h"
24 #include "FwdState.h"
25 #include "globals.h"
26 #include "http.h"
27 #include "HttpRequest.h"
28 #include "HttpStateFlags.h"
29 #include "ip/QosConfig.h"
30 #include "LogTags.h"
31 #include "MemBuf.h"
32 #include "PeerSelectState.h"
33 #include "SquidConfig.h"
34 #include "SquidTime.h"
35 #include "StatCounters.h"
36 #if USE_OPENSSL
37 #include "ssl/bio.h"
38 #include "ssl/PeerConnector.h"
39 #include "ssl/ServerBump.h"
40 #endif
41 #include "tools.h"
42 #if USE_DELAY_POOLS
43 #include "DelayId.h"
44 #endif
45
46 #include <climits>
47 #include <cerrno>
48
49 /**
50 * TunnelStateData is the state engine performing the tasks for
51 * setup of a TCP tunnel from an existing open client FD to a server
52 * then shuffling binary data between the resulting FD pair.
53 */
54 /*
55 * TODO 1: implement a read/write API on ConnStateData to send/receive blocks
56 * of pre-formatted data. Then we can use that as the client side of the tunnel
57 * instead of re-implementing it here and occasionally getting the ConnStateData
58 * read/write state wrong.
59 *
60 * TODO 2: then convert this into a AsyncJob, possibly a child of 'Server'
61 */
62 class TunnelStateData
63 {
64 CBDATA_CLASS(TunnelStateData);
65
66 public:
67 TunnelStateData();
68 ~TunnelStateData();
69 TunnelStateData(const TunnelStateData &); // do not implement
70 TunnelStateData &operator =(const TunnelStateData &); // do not implement
71
72 class Connection;
73 static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
74 static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
75 static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
76 static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data);
77
78 /// Starts reading peer response to our CONNECT request.
79 void readConnectResponse();
80
81 /// Called when we may be done handling a CONNECT exchange with the peer.
82 void connectExchangeCheckpoint();
83
84 bool noConnections() const;
85 char *url;
86 CbcPointer<ClientHttpRequest> http;
87 HttpRequest::Pointer request;
88 AccessLogEntryPointer al;
89 Comm::ConnectionList serverDestinations;
90
91 const char * getHost() const {
92 return (server.conn != NULL && server.conn->getPeer() ? server.conn->getPeer()->host : request->GetHost());
93 };
94
95 /// Whether we are writing a CONNECT request to a peer.
96 bool waitingForConnectRequest() const { return connectReqWriting; }
97 /// Whether we are reading a CONNECT response from a peer.
98 bool waitingForConnectResponse() const { return connectRespBuf; }
99 /// Whether we are waiting for the CONNECT request/response exchange with the peer.
100 bool waitingForConnectExchange() const { return waitingForConnectRequest() || waitingForConnectResponse(); }
101
102 /// Whether the client sent a CONNECT request to us.
103 bool clientExpectsConnectResponse() const {
104 #if USE_OPENSSL
105 // We are bumping and we had already send "OK CONNECTED"
106 if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->step > Ssl::bumpStep1)
107 return false;
108 #endif
109 return !(request != NULL &&
110 (request->flags.interceptTproxy || request->flags.intercepted));
111 }
112
113 class Connection
114 {
115
116 public:
117 Connection() : len (0), buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL) {}
118
119 ~Connection();
120
121 int bytesWanted(int lower=0, int upper = INT_MAX) const;
122 void bytesIn(int const &);
123 #if USE_DELAY_POOLS
124
125 void setDelayId(DelayId const &);
126 #endif
127
128 void error(int const xerrno);
129 int debugLevelForError(int const xerrno) const;
130 /// handles a non-I/O error associated with this Connection
131 void logicError(const char *errMsg);
132 void closeIfOpen();
133 void dataSent (size_t amount);
134 int len;
135 char *buf;
136 int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
137
138 Comm::ConnectionPointer conn; ///< The currently connected connection.
139
140 private:
141 #if USE_DELAY_POOLS
142
143 DelayId delayId;
144 #endif
145
146 };
147
148 Connection client, server;
149 int *status_ptr; ///< pointer for logging HTTP status
150 LogTags *logTag_ptr; ///< pointer for logging Squid processing code
151 MemBuf *connectRespBuf; ///< accumulates peer CONNECT response when we need it
152 bool connectReqWriting; ///< whether we are writing a CONNECT request to a peer
153
154 void copyRead(Connection &from, IOCB *completion);
155
156 /// continue to set up connection to a peer, going async for SSL peers
157 void connectToPeer();
158
159 private:
160 #if USE_OPENSSL
161 /// Gives PeerConnector access to Answer in the TunnelStateData callback dialer.
162 class MyAnswerDialer: public CallDialer, public Ssl::PeerConnector::CbDialer
163 {
164 public:
165 typedef void (TunnelStateData::*Method)(Ssl::PeerConnectorAnswer &);
166
167 MyAnswerDialer(Method method, TunnelStateData *tunnel):
168 method_(method), tunnel_(tunnel), answer_() {}
169
170 /* CallDialer API */
171 virtual bool canDial(AsyncCall &call) { return tunnel_.valid(); }
172 void dial(AsyncCall &call) { ((&(*tunnel_))->*method_)(answer_); }
173 virtual void print(std::ostream &os) const {
174 os << '(' << tunnel_.get() << ", " << answer_ << ')';
175 }
176
177 /* Ssl::PeerConnector::CbDialer API */
178 virtual Ssl::PeerConnectorAnswer &answer() { return answer_; }
179
180 private:
181 Method method_;
182 CbcPointer<TunnelStateData> tunnel_;
183 Ssl::PeerConnectorAnswer answer_;
184 };
185
186 void connectedToPeer(Ssl::PeerConnectorAnswer &answer);
187 #endif
188
189 public:
190 bool keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to);
191 void copy(size_t len, Connection &from, Connection &to, IOCB *);
192 void handleConnectResponse(const size_t chunkSize);
193 void readServer(char *buf, size_t len, Comm::Flag errcode, int xerrno);
194 void readClient(char *buf, size_t len, Comm::Flag errcode, int xerrno);
195 void writeClientDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
196 void writeServerDone(char *buf, size_t len, Comm::Flag flag, int xerrno);
197
198 static void ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
199 void readConnectResponseDone(char *buf, size_t len, Comm::Flag errcode, int xerrno);
200 };
201
202 static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
203
204 static CNCB tunnelConnectDone;
205 static ERCB tunnelErrorComplete;
206 static CLCB tunnelServerClosed;
207 static CLCB tunnelClientClosed;
208 static CTCB tunnelTimeout;
209 static PSC tunnelPeerSelectComplete;
210 static void tunnelConnected(const Comm::ConnectionPointer &server, void *);
211 static void tunnelRelayConnectRequest(const Comm::ConnectionPointer &server, void *);
212
213 static void
214 tunnelServerClosed(const CommCloseCbParams &params)
215 {
216 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
217 debugs(26, 3, HERE << tunnelState->server.conn);
218 tunnelState->server.conn = NULL;
219
220 if (tunnelState->request != NULL)
221 tunnelState->request->hier.stopPeerClock(false);
222
223 if (tunnelState->noConnections()) {
224 delete tunnelState;
225 return;
226 }
227
228 if (!tunnelState->server.len) {
229 tunnelState->client.conn->close();
230 return;
231 }
232 }
233
234 static void
235 tunnelClientClosed(const CommCloseCbParams &params)
236 {
237 TunnelStateData *tunnelState = (TunnelStateData *)params.data;
238 debugs(26, 3, HERE << tunnelState->client.conn);
239 tunnelState->client.conn = NULL;
240
241 if (tunnelState->noConnections()) {
242 delete tunnelState;
243 return;
244 }
245
246 if (!tunnelState->client.len) {
247 tunnelState->server.conn->close();
248 return;
249 }
250 }
251
252 TunnelStateData::TunnelStateData() :
253 url(NULL),
254 http(),
255 request(NULL),
256 status_ptr(NULL),
257 logTag_ptr(NULL),
258 connectRespBuf(NULL),
259 connectReqWriting(false)
260 {
261 debugs(26, 3, "TunnelStateData constructed this=" << this);
262 }
263
264 TunnelStateData::~TunnelStateData()
265 {
266 debugs(26, 3, "TunnelStateData destructed this=" << this);
267 assert(noConnections());
268 xfree(url);
269 serverDestinations.clear();
270 delete connectRespBuf;
271 }
272
273 TunnelStateData::Connection::~Connection()
274 {
275 safe_free(buf);
276 }
277
278 int
279 TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
280 {
281 #if USE_DELAY_POOLS
282 return delayId.bytesWanted(lowerbound, upperbound);
283 #else
284
285 return upperbound;
286 #endif
287 }
288
289 void
290 TunnelStateData::Connection::bytesIn(int const &count)
291 {
292 debugs(26, 3, HERE << "len=" << len << " + count=" << count);
293 #if USE_DELAY_POOLS
294 delayId.bytesIn(count);
295 #endif
296
297 len += count;
298 }
299
300 int
301 TunnelStateData::Connection::debugLevelForError(int const xerrno) const
302 {
303 #ifdef ECONNRESET
304
305 if (xerrno == ECONNRESET)
306 return 2;
307
308 #endif
309
310 if (ignoreErrno(xerrno))
311 return 3;
312
313 return 1;
314 }
315
316 /* Read from server side and queue it for writing to the client */
317 void
318 TunnelStateData::ReadServer(const Comm::ConnectionPointer &c, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
319 {
320 TunnelStateData *tunnelState = (TunnelStateData *)data;
321 assert(cbdataReferenceValid(tunnelState));
322 debugs(26, 3, HERE << c);
323
324 tunnelState->readServer(buf, len, errcode, xerrno);
325 }
326
327 void
328 TunnelStateData::readServer(char *, size_t len, Comm::Flag errcode, int xerrno)
329 {
330 debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
331
332 /*
333 * Bail out early on Comm::ERR_CLOSING
334 * - close handlers will tidy up for us
335 */
336
337 if (errcode == Comm::ERR_CLOSING)
338 return;
339
340 if (len > 0) {
341 server.bytesIn(len);
342 kb_incr(&(statCounter.server.all.kbytes_in), len);
343 kb_incr(&(statCounter.server.other.kbytes_in), len);
344 }
345
346 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
347 copy(len, server, client, WriteClientDone);
348 }
349
350 /// Called when we read [a part of] CONNECT response from the peer
351 void
352 TunnelStateData::readConnectResponseDone(char *, size_t len, Comm::Flag errcode, int xerrno)
353 {
354 debugs(26, 3, server.conn << ", read " << len << " bytes, err=" << errcode);
355 assert(waitingForConnectResponse());
356
357 if (errcode == Comm::ERR_CLOSING)
358 return;
359
360 if (len > 0) {
361 connectRespBuf->appended(len);
362 server.bytesIn(len);
363 kb_incr(&(statCounter.server.all.kbytes_in), len);
364 kb_incr(&(statCounter.server.other.kbytes_in), len);
365 }
366
367 if (keepGoingAfterRead(len, errcode, xerrno, server, client))
368 handleConnectResponse(len);
369 }
370
371 /* Read from client side and queue it for writing to the server */
372 void
373 TunnelStateData::ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
374 {
375 TunnelStateData *tunnelState = (TunnelStateData *)data;
376 assert (cbdataReferenceValid (tunnelState));
377
378 tunnelState->readConnectResponseDone(buf, len, errcode, xerrno);
379 }
380
381 /// Parses [possibly incomplete] CONNECT response and reacts to it.
382 /// If the tunnel is being closed or more response data is needed, returns false.
383 /// Otherwise, the caller should handle the remaining read data, if any.
384 void
385 TunnelStateData::handleConnectResponse(const size_t chunkSize)
386 {
387 assert(waitingForConnectResponse());
388
389 // Ideally, client and server should use MemBuf or better, but current code
390 // never accumulates more than one read when shoveling data (XXX) so it does
391 // not need to deal with MemBuf complexity. To keep it simple, we use a
392 // dedicated MemBuf for accumulating CONNECT responses. TODO: When shoveling
393 // is optimized, reuse server.buf for CONNEC response accumulation instead.
394
395 /* mimic the basic parts of HttpStateData::processReplyHeader() */
396 HttpReply rep;
397 Http::StatusCode parseErr = Http::scNone;
398 const bool eof = !chunkSize;
399 const bool parsed = rep.parse(connectRespBuf, eof, &parseErr);
400 if (!parsed) {
401 if (parseErr > 0) { // unrecoverable parsing error
402 server.logicError("malformed CONNECT response from peer");
403 return;
404 }
405
406 // need more data
407 assert(!eof);
408 assert(!parseErr);
409
410 if (!connectRespBuf->hasSpace()) {
411 server.logicError("huge CONNECT response from peer");
412 return;
413 }
414
415 // keep reading
416 readConnectResponse();
417 return;
418 }
419
420 // CONNECT response was successfully parsed
421 *status_ptr = rep.sline.status();
422
423 // bail if we did not get an HTTP 200 (Connection Established) response
424 if (rep.sline.status() != Http::scOkay) {
425 server.logicError("unsupported CONNECT response status code");
426 return;
427 }
428
429 if (rep.hdr_sz < connectRespBuf->contentSize()) {
430 // preserve bytes that the server already sent after the CONNECT response
431 server.len = connectRespBuf->contentSize() - rep.hdr_sz;
432 memcpy(server.buf, connectRespBuf->content()+rep.hdr_sz, server.len);
433 } else {
434 // reset; delay pools were using this field to throttle CONNECT response
435 server.len = 0;
436 }
437
438 delete connectRespBuf;
439 connectRespBuf = NULL;
440 connectExchangeCheckpoint();
441 }
442
443 void
444 TunnelStateData::Connection::logicError(const char *errMsg)
445 {
446 debugs(50, 3, conn << " closing on error: " << errMsg);
447 conn->close();
448 }
449
450 void
451 TunnelStateData::Connection::error(int const xerrno)
452 {
453 /* XXX fixme xstrerror and xerrno... */
454 errno = xerrno;
455
456 debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror());
457
458 if (!ignoreErrno(xerrno))
459 conn->close();
460 }
461
462 /* Read from client side and queue it for writing to the server */
463 void
464 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data)
465 {
466 TunnelStateData *tunnelState = (TunnelStateData *)data;
467 assert (cbdataReferenceValid (tunnelState));
468
469 tunnelState->readClient(buf, len, errcode, xerrno);
470 }
471
472 void
473 TunnelStateData::readClient(char *, size_t len, Comm::Flag errcode, int xerrno)
474 {
475 debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
476
477 /*
478 * Bail out early on Comm::ERR_CLOSING
479 * - close handlers will tidy up for us
480 */
481
482 if (errcode == Comm::ERR_CLOSING)
483 return;
484
485 if (len > 0) {
486 client.bytesIn(len);
487 kb_incr(&(statCounter.client_http.kbytes_in), len);
488 }
489
490 if (keepGoingAfterRead(len, errcode, xerrno, client, server))
491 copy(len, client, server, WriteServerDone);
492 }
493
494 /// Updates state after reading from client or server.
495 /// Returns whether the caller should use the data just read.
496 bool
497 TunnelStateData::keepGoingAfterRead(size_t len, Comm::Flag errcode, int xerrno, Connection &from, Connection &to)
498 {
499 debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
500
501 /* I think this is to prevent free-while-in-a-callback behaviour
502 * - RBC 20030229
503 * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
504 */
505 const CbcPointer<TunnelStateData> safetyLock(this);
506
507 /* Bump the source connection read timeout on any activity */
508 if (Comm::IsConnOpen(from.conn)) {
509 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
510 CommTimeoutCbPtrFun(tunnelTimeout, this));
511 commSetConnTimeout(from.conn, Config.Timeout.read, timeoutCall);
512 }
513
514 /* Bump the dest connection read timeout on any activity */
515 /* see Bug 3659: tunnels can be weird, with very long one-way transfers */
516 if (Comm::IsConnOpen(to.conn)) {
517 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
518 CommTimeoutCbPtrFun(tunnelTimeout, this));
519 commSetConnTimeout(to.conn, Config.Timeout.read, timeoutCall);
520 }
521
522 if (errcode)
523 from.error (xerrno);
524 else if (len == 0 || !Comm::IsConnOpen(to.conn)) {
525 debugs(26, 3, HERE << "Nothing to write or client gone. Terminate the tunnel.");
526 from.conn->close();
527
528 /* Only close the remote end if we've finished queueing data to it */
529 if (from.len == 0 && Comm::IsConnOpen(to.conn) ) {
530 to.conn->close();
531 }
532 } else if (cbdataReferenceValid(this)) {
533 return true;
534 }
535
536 return false;
537 }
538
539 void
540 TunnelStateData::copy(size_t len, Connection &from, Connection &to, IOCB *completion)
541 {
542 debugs(26, 3, HERE << "Schedule Write");
543 AsyncCall::Pointer call = commCbCall(5,5, "TunnelBlindCopyWriteHandler",
544 CommIoCbPtrFun(completion, this));
545 Comm::Write(to.conn, from.buf, len, call, NULL);
546 }
547
548 /* Writes data from the client buffer to the server side */
549 void
550 TunnelStateData::WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag flag, int xerrno, void *data)
551 {
552 TunnelStateData *tunnelState = (TunnelStateData *)data;
553 assert (cbdataReferenceValid (tunnelState));
554
555 tunnelState->writeServerDone(buf, len, flag, xerrno);
556 }
557
558 void
559 TunnelStateData::writeServerDone(char *, size_t len, Comm::Flag flag, int xerrno)
560 {
561 debugs(26, 3, HERE << server.conn << ", " << len << " bytes written, flag=" << flag);
562
563 /* Error? */
564 if (flag != Comm::OK) {
565 if (flag != Comm::ERR_CLOSING) {
566 debugs(26, 4, HERE << "calling TunnelStateData::server.error(" << xerrno <<")");
567 server.error(xerrno); // may call comm_close
568 }
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 kb_incr(&(statCounter.server.all.kbytes_out), len);
581 kb_incr(&(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 copyRead(client, ReadClient);
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
604 tunnelState->writeClientDone(buf, len, flag, xerrno);
605 }
606
607 void
608 TunnelStateData::Connection::dataSent(size_t amount)
609 {
610 debugs(26, 3, HERE << "len=" << len << " - amount=" << amount);
611 assert(amount == (size_t)len);
612 len =0;
613 /* increment total object size */
614
615 if (size_ptr)
616 *size_ptr += amount;
617 }
618
619 void
620 TunnelStateData::writeClientDone(char *, size_t len, Comm::Flag flag, int xerrno)
621 {
622 debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
623
624 /* Error? */
625 if (flag != Comm::OK) {
626 if (flag != Comm::ERR_CLOSING) {
627 debugs(26, 4, HERE << "Closing client connection due to comm flags.");
628 client.error(xerrno); // may call comm_close
629 }
630 return;
631 }
632
633 /* EOF? */
634 if (len == 0) {
635 debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
636 client.conn->close();
637 return;
638 }
639
640 /* Valid data */
641 kb_incr(&(statCounter.client_http.kbytes_out), len);
642 server.dataSent(len);
643
644 /* If the other end has closed, so should we */
645 if (!Comm::IsConnOpen(server.conn)) {
646 debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
647 client.conn->close();
648 return;
649 }
650
651 CbcPointer<TunnelStateData> safetyLock(this); /* ??? should be locked by the caller... */
652
653 if (cbdataReferenceValid(this))
654 copyRead(server, ReadServer);
655 }
656
657 static void
658 tunnelTimeout(const CommTimeoutCbParams &io)
659 {
660 TunnelStateData *tunnelState = static_cast<TunnelStateData *>(io.data);
661 debugs(26, 3, HERE << io.conn);
662 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
663 CbcPointer<TunnelStateData> safetyLock(tunnelState);
664
665 tunnelState->client.closeIfOpen();
666 tunnelState->server.closeIfOpen();
667 }
668
669 void
670 TunnelStateData::Connection::closeIfOpen()
671 {
672 if (Comm::IsConnOpen(conn))
673 conn->close();
674 }
675
676 void
677 TunnelStateData::copyRead(Connection &from, IOCB *completion)
678 {
679 assert(from.len == 0);
680 AsyncCall::Pointer call = commCbCall(5,4, "TunnelBlindCopyReadHandler",
681 CommIoCbPtrFun(completion, this));
682 comm_read(from.conn, from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), call);
683 }
684
685 void
686 TunnelStateData::readConnectResponse()
687 {
688 assert(waitingForConnectResponse());
689
690 AsyncCall::Pointer call = commCbCall(5,4, "readConnectResponseDone",
691 CommIoCbPtrFun(ReadConnectResponseDone, this));
692 comm_read(server.conn, connectRespBuf->space(),
693 server.bytesWanted(1, connectRespBuf->spaceSize()), call);
694 }
695
696 /**
697 * Set the HTTP status for this request and sets the read handlers for client
698 * and server side connections.
699 */
700 static void
701 tunnelStartShoveling(TunnelStateData *tunnelState)
702 {
703 assert(!tunnelState->waitingForConnectExchange());
704 *tunnelState->status_ptr = Http::scOkay;
705 if (tunnelState->logTag_ptr)
706 *tunnelState->logTag_ptr = LOG_TCP_TUNNEL;
707 if (cbdataReferenceValid(tunnelState)) {
708
709 // Shovel any payload already pushed into reply buffer by the server response
710 if (!tunnelState->server.len)
711 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
712 else {
713 debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
714 tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
715 }
716
717 // Bug 3371: shovel any payload already pushed into ConnStateData by the client request
718 if (tunnelState->http.valid() && tunnelState->http->getConn() && !tunnelState->http->getConn()->in.buf.isEmpty()) {
719 struct ConnStateData::In *in = &tunnelState->http->getConn()->in;
720 debugs(26, DBG_DATA, "Tunnel client PUSH Payload: \n" << in->buf << "\n----------");
721
722 // We just need to ensure the bytes from ConnStateData are in client.buf already to deliver
723 memcpy(tunnelState->client.buf, in->buf.rawContent(), in->buf.length());
724 // NP: readClient() takes care of buffer length accounting.
725 tunnelState->readClient(tunnelState->client.buf, in->buf.length(), Comm::OK, 0);
726 in->buf.consume(); // ConnStateData buffer accounting after the shuffle.
727 } else
728 tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
729 }
730 }
731
732 /**
733 * All the pieces we need to write to client and/or server connection
734 * have been written.
735 * Call the tunnelStartShoveling to start the blind pump.
736 */
737 static void
738 tunnelConnectedWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
739 {
740 TunnelStateData *tunnelState = (TunnelStateData *)data;
741 debugs(26, 3, HERE << conn << ", flag=" << flag);
742
743 if (flag != Comm::OK) {
744 *tunnelState->status_ptr = Http::scInternalServerError;
745 tunnelErrorComplete(conn->fd, data, 0);
746 return;
747 }
748
749 tunnelStartShoveling(tunnelState);
750 }
751
752 /// Called when we are done writing CONNECT request to a peer.
753 static void
754 tunnelConnectReqWriteDone(const Comm::ConnectionPointer &conn, char *, size_t, Comm::Flag flag, int, void *data)
755 {
756 TunnelStateData *tunnelState = (TunnelStateData *)data;
757 debugs(26, 3, conn << ", flag=" << flag);
758 assert(tunnelState->waitingForConnectRequest());
759
760 if (flag != Comm::OK) {
761 *tunnelState->status_ptr = Http::scInternalServerError;
762 tunnelErrorComplete(conn->fd, data, 0);
763 return;
764 }
765
766 tunnelState->connectReqWriting = false;
767 tunnelState->connectExchangeCheckpoint();
768 }
769
770 void
771 TunnelStateData::connectExchangeCheckpoint()
772 {
773 if (waitingForConnectResponse()) {
774 debugs(26, 5, "still reading CONNECT response on " << server.conn);
775 } else if (waitingForConnectRequest()) {
776 debugs(26, 5, "still writing CONNECT request on " << server.conn);
777 } else {
778 assert(!waitingForConnectExchange());
779 debugs(26, 3, "done with CONNECT exchange on " << server.conn);
780 tunnelConnected(server.conn, this);
781 }
782 }
783
784 /*
785 * handle the write completion from a proxy request to an upstream origin
786 */
787 static void
788 tunnelConnected(const Comm::ConnectionPointer &server, void *data)
789 {
790 TunnelStateData *tunnelState = (TunnelStateData *)data;
791 debugs(26, 3, HERE << server << ", tunnelState=" << tunnelState);
792
793 if (!tunnelState->clientExpectsConnectResponse())
794 tunnelStartShoveling(tunnelState); // ssl-bumped connection, be quiet
795 else {
796 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
797 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
798 Comm::Write(tunnelState->client.conn, conn_established, strlen(conn_established), call, NULL);
799 }
800 }
801
802 static void
803 tunnelErrorComplete(int fd/*const Comm::ConnectionPointer &*/, void *data, size_t)
804 {
805 TunnelStateData *tunnelState = (TunnelStateData *)data;
806 debugs(26, 3, HERE << "FD " << fd);
807 assert(tunnelState != NULL);
808 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
809 CbcPointer<TunnelStateData> safetyLock(tunnelState);
810
811 if (Comm::IsConnOpen(tunnelState->client.conn))
812 tunnelState->client.conn->close();
813
814 if (Comm::IsConnOpen(tunnelState->server.conn))
815 tunnelState->server.conn->close();
816 }
817
818 static void
819 tunnelConnectDone(const Comm::ConnectionPointer &conn, Comm::Flag status, int xerrno, void *data)
820 {
821 TunnelStateData *tunnelState = (TunnelStateData *)data;
822
823 if (status != Comm::OK) {
824 debugs(26, 4, HERE << conn << ", comm failure recovery.");
825 /* At this point only the TCP handshake has failed. no data has been passed.
826 * we are allowed to re-try the TCP-level connection to alternate IPs for CONNECT.
827 */
828 tunnelState->serverDestinations.erase(tunnelState->serverDestinations.begin());
829 if (status != Comm::TIMEOUT && tunnelState->serverDestinations.size() > 0) {
830 /* Try another IP of this destination host */
831 GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
832 debugs(26, 4, HERE << "retry with : " << tunnelState->serverDestinations[0]);
833 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
834 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
835 cs->setHost(tunnelState->url);
836 AsyncJob::Start(cs);
837 } else {
838 debugs(26, 4, HERE << "terminate with error.");
839 ErrorState *err = new ErrorState(ERR_CONNECT_FAIL, Http::scServiceUnavailable, tunnelState->request.getRaw());
840 *tunnelState->status_ptr = Http::scServiceUnavailable;
841 err->xerrno = xerrno;
842 // on timeout is this still: err->xerrno = ETIMEDOUT;
843 err->port = conn->remote.port();
844 err->callback = tunnelErrorComplete;
845 err->callback_data = tunnelState;
846 errorSend(tunnelState->client.conn, err);
847 if (tunnelState->request != NULL)
848 tunnelState->request->hier.stopPeerClock(false);
849 }
850 return;
851 }
852
853 #if USE_DELAY_POOLS
854 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
855 if (conn->getPeer() && conn->getPeer()->options.no_delay)
856 tunnelState->server.setDelayId(DelayId());
857 #endif
858
859 tunnelState->request->hier.note(conn, tunnelState->getHost());
860
861 tunnelState->server.conn = conn;
862 tunnelState->request->peer_host = conn->getPeer() ? conn->getPeer()->host : NULL;
863 comm_add_close_handler(conn->fd, tunnelServerClosed, tunnelState);
864
865 debugs(26, 4, HERE << "determine post-connect handling pathway.");
866 if (conn->getPeer()) {
867 tunnelState->request->peer_login = conn->getPeer()->login;
868 tunnelState->request->flags.proxying = !(conn->getPeer()->options.originserver);
869 } else {
870 tunnelState->request->peer_login = NULL;
871 tunnelState->request->flags.proxying = false;
872 }
873
874 if (tunnelState->request->flags.proxying)
875 tunnelState->connectToPeer();
876 else {
877 tunnelConnected(conn, tunnelState);
878 }
879
880 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
881 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
882 commSetConnTimeout(conn, Config.Timeout.read, timeoutCall);
883 }
884
885 void
886 tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr, const AccessLogEntryPointer &al)
887 {
888 debugs(26, 3, HERE);
889 /* Create state structure. */
890 TunnelStateData *tunnelState = NULL;
891 ErrorState *err = NULL;
892 HttpRequest *request = http->request;
893 char *url = http->uri;
894
895 /*
896 * client_addr.isNoAddr() indicates this is an "internal" request
897 * from peer_digest.c, asn.c, netdb.c, etc and should always
898 * be allowed. yuck, I know.
899 */
900
901 if (Config.accessList.miss && !request->client_addr.isNoAddr()) {
902 /*
903 * Check if this host is allowed to fetch MISSES from us (miss_access)
904 * default is to allow.
905 */
906 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
907 ch.src_addr = request->client_addr;
908 ch.my_addr = request->my_addr;
909 if (ch.fastCheck() == ACCESS_DENIED) {
910 debugs(26, 4, HERE << "MISS access forbidden.");
911 err = new ErrorState(ERR_FORWARDING_DENIED, Http::scForbidden, request);
912 *status_ptr = Http::scForbidden;
913 errorSend(http->getConn()->clientConnection, err);
914 return;
915 }
916 }
917
918 debugs(26, 3, request->method << ' ' << url << ' ' << request->http_ver);
919 ++statCounter.server.all.requests;
920 ++statCounter.server.other.requests;
921
922 tunnelState = new TunnelStateData;
923 #if USE_DELAY_POOLS
924 tunnelState->server.setDelayId(DelayId::DelayClient(http));
925 #endif
926 tunnelState->url = xstrdup(url);
927 tunnelState->request = request;
928 tunnelState->server.size_ptr = size_ptr;
929 tunnelState->status_ptr = status_ptr;
930 tunnelState->logTag_ptr = &http->logType;
931 tunnelState->client.conn = http->getConn()->clientConnection;
932 tunnelState->http = http;
933 tunnelState->al = al;
934
935 comm_add_close_handler(tunnelState->client.conn->fd,
936 tunnelClientClosed,
937 tunnelState);
938
939 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
940 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
941 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
942
943 peerSelect(&(tunnelState->serverDestinations), request, al,
944 NULL,
945 tunnelPeerSelectComplete,
946 tunnelState);
947 }
948
949 void
950 TunnelStateData::connectToPeer()
951 {
952 const Comm::ConnectionPointer &srv = server.conn;
953
954 #if USE_OPENSSL
955 if (CachePeer *p = srv->getPeer()) {
956 if (p->use_ssl) {
957 AsyncCall::Pointer callback = asyncCall(5,4,
958 "TunnelStateData::ConnectedToPeer",
959 MyAnswerDialer(&TunnelStateData::connectedToPeer, this));
960 Ssl::PeerConnector *connector =
961 new Ssl::PeerConnector(request, srv, client.conn, callback);
962 AsyncJob::Start(connector); // will call our callback
963 return;
964 }
965 }
966 #endif
967
968 tunnelRelayConnectRequest(srv, this);
969 }
970
971 #if USE_OPENSSL
972 /// Ssl::PeerConnector callback
973 void
974 TunnelStateData::connectedToPeer(Ssl::PeerConnectorAnswer &answer)
975 {
976 if (ErrorState *error = answer.error.get()) {
977 *status_ptr = error->httpStatus;
978 error->callback = tunnelErrorComplete;
979 error->callback_data = this;
980 errorSend(client.conn, error);
981 answer.error.clear(); // preserve error for errorSendComplete()
982 return;
983 }
984
985 tunnelRelayConnectRequest(server.conn, this);
986 }
987 #endif
988
989 static void
990 tunnelRelayConnectRequest(const Comm::ConnectionPointer &srv, void *data)
991 {
992 TunnelStateData *tunnelState = (TunnelStateData *)data;
993 assert(!tunnelState->waitingForConnectExchange());
994 HttpHeader hdr_out(hoRequest);
995 Packer p;
996 HttpStateFlags flags;
997 debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState);
998 memset(&flags, '\0', sizeof(flags));
999 flags.proxying = tunnelState->request->flags.proxying;
1000 MemBuf mb;
1001 mb.init();
1002 mb.Printf("CONNECT %s HTTP/1.1\r\n", tunnelState->url);
1003 HttpStateData::httpBuildRequestHeader(tunnelState->request.getRaw(),
1004 NULL, /* StoreEntry */
1005 tunnelState->al, /* AccessLogEntry */
1006 &hdr_out,
1007 flags); /* flags */
1008 packerToMemInit(&p, &mb);
1009 hdr_out.packInto(&p);
1010 hdr_out.clean();
1011 packerClean(&p);
1012 mb.append("\r\n", 2);
1013
1014 debugs(11, 2, "Tunnel Server REQUEST: " << tunnelState->server.conn << ":\n----------\n" <<
1015 Raw("tunnelRelayConnectRequest", mb.content(), mb.contentSize()) << "\n----------");
1016
1017 if (tunnelState->clientExpectsConnectResponse()) {
1018 // hack: blindly tunnel peer response (to our CONNECT request) to the client as ours.
1019 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectedWriteDone",
1020 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
1021 Comm::Write(srv, &mb, writeCall);
1022 } else {
1023 // we have to eat the connect response from the peer (so that the client
1024 // does not see it) and only then start shoveling data to the client
1025 AsyncCall::Pointer writeCall = commCbCall(5,5, "tunnelConnectReqWriteDone",
1026 CommIoCbPtrFun(tunnelConnectReqWriteDone,
1027 tunnelState));
1028 Comm::Write(srv, &mb, writeCall);
1029 tunnelState->connectReqWriting = true;
1030
1031 tunnelState->connectRespBuf = new MemBuf;
1032 // SQUID_TCP_SO_RCVBUF: we should not accumulate more than regular I/O buffer
1033 // can hold since any CONNECT response leftovers have to fit into server.buf.
1034 // 2*SQUID_TCP_SO_RCVBUF: HttpMsg::parse() zero-terminates, which uses space.
1035 tunnelState->connectRespBuf->init(SQUID_TCP_SO_RCVBUF, 2*SQUID_TCP_SO_RCVBUF);
1036 tunnelState->readConnectResponse();
1037
1038 assert(tunnelState->waitingForConnectExchange());
1039 }
1040
1041 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1042 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1043 commSetConnTimeout(srv, Config.Timeout.read, timeoutCall);
1044 }
1045
1046 static void
1047 tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, ErrorState *err, void *data)
1048 {
1049 TunnelStateData *tunnelState = (TunnelStateData *)data;
1050
1051 if (peer_paths == NULL || peer_paths->size() < 1) {
1052 debugs(26, 3, HERE << "No paths found. Aborting CONNECT");
1053 if (!err) {
1054 err = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, tunnelState->request.getRaw());
1055 }
1056 *tunnelState->status_ptr = err->httpStatus;
1057 err->callback = tunnelErrorComplete;
1058 err->callback_data = tunnelState;
1059 errorSend(tunnelState->client.conn, err);
1060 return;
1061 }
1062 delete err;
1063
1064 GetMarkingsToServer(tunnelState->request.getRaw(), *tunnelState->serverDestinations[0]);
1065
1066 if (tunnelState->request != NULL)
1067 tunnelState->request->hier.startPeerClock();
1068
1069 debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
1070 tunnelState->serverDestinations[0] << "}");
1071
1072 AsyncCall::Pointer call = commCbCall(26,3, "tunnelConnectDone", CommConnectCbPtrFun(tunnelConnectDone, tunnelState));
1073 Comm::ConnOpener *cs = new Comm::ConnOpener(tunnelState->serverDestinations[0], call, Config.Timeout.connect);
1074 cs->setHost(tunnelState->url);
1075 AsyncJob::Start(cs);
1076 }
1077
1078 CBDATA_CLASS_INIT(TunnelStateData);
1079
1080 bool
1081 TunnelStateData::noConnections() const
1082 {
1083 return !Comm::IsConnOpen(server.conn) && !Comm::IsConnOpen(client.conn);
1084 }
1085
1086 #if USE_DELAY_POOLS
1087 void
1088 TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
1089 {
1090 delayId = newDelay;
1091 }
1092
1093 #endif
1094
1095 #if USE_OPENSSL
1096 void
1097 switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn)
1098 {
1099 debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd);
1100 /* Create state structure. */
1101 TunnelStateData *tunnelState = NULL;
1102 const char *url = urlCanonical(request);
1103
1104 debugs(26, 3, request->method << " " << url << " " << request->http_ver);
1105 ++statCounter.server.all.requests;
1106 ++statCounter.server.other.requests;
1107
1108 tunnelState = new TunnelStateData;
1109 tunnelState->url = xstrdup(url);
1110 tunnelState->request = request;
1111 tunnelState->server.size_ptr = NULL; //Set later if ClientSocketContext is available
1112
1113 // Temporary static variable to store the unneeded for our case status code
1114 static int status_code = 0;
1115 tunnelState->status_ptr = &status_code;
1116 tunnelState->client.conn = clientConn;
1117
1118 ConnStateData *conn;
1119 if ((conn = request->clientConnectionManager.get())) {
1120 ClientSocketContext::Pointer context = conn->getCurrentContext();
1121 if (context != NULL && context->http != NULL) {
1122 tunnelState->logTag_ptr = &context->http->logType;
1123 tunnelState->server.size_ptr = &context->http->out.size;
1124
1125 #if USE_DELAY_POOLS
1126 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
1127 if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay)
1128 tunnelState->server.setDelayId(DelayId::DelayClient(context->http));
1129 #endif
1130 }
1131 }
1132
1133 comm_add_close_handler(tunnelState->client.conn->fd,
1134 tunnelClientClosed,
1135 tunnelState);
1136
1137 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1138 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1139 commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall);
1140 fd_table[clientConn->fd].read_method = &default_read_method;
1141 fd_table[clientConn->fd].write_method = &default_write_method;
1142
1143 tunnelState->request->hier.note(srvConn, tunnelState->getHost());
1144
1145 tunnelState->server.conn = srvConn;
1146 tunnelState->request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : NULL;
1147 comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState);
1148
1149 debugs(26, 4, "determine post-connect handling pathway.");
1150 if (srvConn->getPeer()) {
1151 tunnelState->request->peer_login = srvConn->getPeer()->login;
1152 tunnelState->request->flags.proxying = !(srvConn->getPeer()->options.originserver);
1153 } else {
1154 tunnelState->request->peer_login = NULL;
1155 tunnelState->request->flags.proxying = false;
1156 }
1157
1158 timeoutCall = commCbCall(5, 4, "tunnelTimeout",
1159 CommTimeoutCbPtrFun(tunnelTimeout, tunnelState));
1160 commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall);
1161 fd_table[srvConn->fd].read_method = &default_read_method;
1162 fd_table[srvConn->fd].write_method = &default_write_method;
1163
1164 SSL *ssl = fd_table[srvConn->fd].ssl;
1165 assert(ssl);
1166 BIO *b = SSL_get_rbio(ssl);
1167 Ssl::ServerBio *srvBio = static_cast<Ssl::ServerBio *>(b->ptr);
1168 const MemBuf &buf = srvBio->rBufData();
1169
1170 AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
1171 CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
1172 Comm::Write(tunnelState->client.conn, buf.content(), buf.contentSize(), call, NULL);
1173 }
1174 #endif //USE_OPENSSL
1175