]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
Merge from trunk
[thirdparty/squid.git] / src / tunnel.cc
CommitLineData
95d659f0 1
983061ed 2/*
262a0e14 3 * $Id$
983061ed 4 *
30a4f2a8 5 * DEBUG: section 26 Secure Sockets Layer Proxy
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
26ac0430 24 *
30a4f2a8 25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
26ac0430 29 *
30a4f2a8 30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
983061ed 34 */
983061ed 35
30a4f2a8 36#include "squid.h"
aa839030 37#include "errorpage.h"
528b2c61 38#include "HttpRequest.h"
39#include "fde.h"
9f518b4a 40#include "comm.h"
528b2c61 41#include "client_side_request.h"
c0941a6a 42#include "acl/FilledChecklist.h"
b67e2c8c 43#if DELAY_POOLS
44#include "DelayId.h"
45#endif
a46d2c0e 46#include "client_side.h"
0eb49b6d 47#include "MemBuf.h"
e5ee81f0 48#include "http.h"
983061ed 49
fa34dd97 50class TunnelStateData
62e76326 51{
a46d2c0e 52
53public:
54
55 class Connection;
56 void *operator new(size_t);
57 void operator delete (void *);
a46d2c0e 58 static void ReadClient(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
59 static void ReadServer(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
60 static void WriteClientDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
61 static void WriteServerDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
62
63 bool noConnections() const;
983061ed 64 char *url;
98ffb7e4 65 char *host; /* either request->host or proxy host */
66 u_short port;
190154cf 67 HttpRequest *request;
64d8034e 68 FwdServer *servers;
62e76326 69
a46d2c0e 70 class Connection
62e76326 71 {
a46d2c0e 72
73 public:
26ac0430 74 Connection() : len (0),buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), fd_(-1) {}
a46d2c0e 75
76 ~Connection();
77 int const & fd() const { return fd_;}
78
79 void fd(int const newFD);
80 int bytesWanted(int lower=0, int upper = INT_MAX) const;
81 void bytesIn(int const &);
82#if DELAY_POOLS
83
84 void setDelayId(DelayId const &);
85#endif
86
87 void error(int const xerrno);
5c926411 88 int debugLevelForError(int const xerrno) const;
a46d2c0e 89 void closeIfOpen();
90 void dataSent (size_t amount);
62e76326 91 int len;
92 char *buf;
47f6e231 93 int64_t *size_ptr; /* pointer to size in an ConnStateData for logging */
62e76326 94
a46d2c0e 95 private:
96 int fd_;
59715b38 97#if DELAY_POOLS
62e76326 98
a46d2c0e 99 DelayId delayId;
59715b38 100#endif
62e76326 101
a46d2c0e 102 };
103
104 Connection client, server;
105 int *status_ptr; /* pointer to status for logging */
106 void copyRead(Connection &from, IOCB *completion);
107
108private:
fa34dd97 109 CBDATA_CLASS(TunnelStateData);
2b663917 110 void copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *);
a46d2c0e 111 void readServer(char *buf, size_t len, comm_err_t errcode, int xerrno);
112 void readClient(char *buf, size_t len, comm_err_t errcode, int xerrno);
113 void writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno);
114 void writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno);
115};
983061ed 116
11a6896c
AJ
117#define fd_closed(fd) (fd == -1 || fd_table[fd].closing())
118
0ee4272b 119static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
983061ed 120
11007d4b 121static CNCB tunnelConnectDone;
122static ERCB tunnelErrorComplete;
123static PF tunnelServerClosed;
124static PF tunnelClientClosed;
125static PF tunnelTimeout;
126static PSC tunnelPeerSelectComplete;
fa34dd97 127static void tunnelStateFree(TunnelStateData * tunnelState);
11007d4b 128static void tunnelConnected(int fd, void *);
129static void tunnelProxyConnected(int fd, void *);
30a4f2a8 130
b8d8561b 131static void
11007d4b 132tunnelServerClosed(int fd, void *data)
30a4f2a8 133{
fa34dd97 134 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 135 debugs(26, 3, "tunnelServerClosed: FD " << fd);
136 assert(fd == tunnelState->server.fd());
137 tunnelState->server.fd(-1);
62e76326 138
71a2ced6 139 if (tunnelState->noConnections()) {
11007d4b 140 tunnelStateFree(tunnelState);
26ac0430 141 return;
71a2ced6 142 }
26ac0430 143
71a2ced6 144 if (!tunnelState->server.len) {
26ac0430
AJ
145 comm_close(tunnelState->client.fd());
146 return;
71a2ced6 147 }
30a4f2a8 148}
149
b177367b 150static void
11007d4b 151tunnelClientClosed(int fd, void *data)
30a4f2a8 152{
fa34dd97 153 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 154 debugs(26, 3, "tunnelClientClosed: FD " << fd);
155 assert(fd == tunnelState->client.fd());
156 tunnelState->client.fd(-1);
62e76326 157
71a2ced6 158 if (tunnelState->noConnections()) {
11007d4b 159 tunnelStateFree(tunnelState);
26ac0430 160 return;
71a2ced6 161 }
26ac0430 162
71a2ced6 163 if (!tunnelState->client.len) {
26ac0430
AJ
164 comm_close(tunnelState->server.fd());
165 return;
71a2ced6 166 }
30a4f2a8 167}
983061ed 168
b177367b 169static void
fa34dd97 170tunnelStateFree(TunnelStateData * tunnelState)
983061ed 171{
11007d4b 172 debugs(26, 3, "tunnelStateFree: tunnelState=" << tunnelState);
173 assert(tunnelState != NULL);
174 assert(tunnelState->noConnections());
175 safe_free(tunnelState->url);
176 FwdState::serversFree(&tunnelState->servers);
177 tunnelState->host = NULL;
178 HTTPMSGUNLOCK(tunnelState->request);
179 delete tunnelState;
983061ed 180}
181
fa34dd97 182TunnelStateData::Connection::~Connection()
a46d2c0e 183{
184 safe_free (buf);
185}
186
187int
fa34dd97 188TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
447e176b 189{
a46d2c0e 190#if DELAY_POOLS
191 return delayId.bytesWanted(lowerbound, upperbound);
192#else
62e76326 193
6b13136a 194 return upperbound;
a46d2c0e 195#endif
196}
62e76326 197
a46d2c0e 198void
fa34dd97 199TunnelStateData::Connection::bytesIn(int const &count)
a46d2c0e 200{
201#if DELAY_POOLS
202 delayId.bytesIn(count);
203#endif
62e76326 204
a46d2c0e 205 len += count;
447e176b 206}
62e76326 207
a46d2c0e 208int
fa34dd97 209TunnelStateData::Connection::debugLevelForError(int const xerrno) const
a46d2c0e 210{
211#ifdef ECONNRESET
212
213 if (xerrno == ECONNRESET)
214 return 2;
215
447e176b 216#endif
217
a46d2c0e 218 if (ignoreErrno(xerrno))
219 return 3;
220
221 return 1;
222}
adb78bd4 223
983061ed 224/* Read from server side and queue it for writing to the client */
a46d2c0e 225void
fa34dd97 226TunnelStateData::ReadServer(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 227{
fa34dd97 228 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 229 assert (cbdataReferenceValid (tunnelState));
c4b7a5a9 230
11007d4b 231 assert(fd == tunnelState->server.fd());
232 tunnelState->readServer(buf, len, errcode, xerrno);
a46d2c0e 233}
62e76326 234
a46d2c0e 235void
fa34dd97 236TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 237{
238 /*
239 * Bail out early on COMM_ERR_CLOSING
26ac0430 240 * - close handlers will tidy up for us
a46d2c0e 241 */
a55f4cea 242
a46d2c0e 243 if (errcode == COMM_ERR_CLOSING)
244 return;
62e76326 245
11007d4b 246 debugs(26, 3, "tunnelReadServer: FD " << server.fd() << ", read " << len << " bytes");
62e76326 247
ee1679df 248 if (len > 0) {
a46d2c0e 249 server.bytesIn(len);
62e76326 250 kb_incr(&statCounter.server.all.kbytes_in, len);
251 kb_incr(&statCounter.server.other.kbytes_in, len);
ee1679df 252 }
62e76326 253
a46d2c0e 254 copy (len, errcode, xerrno, server, client, WriteClientDone);
255}
256
257void
fa34dd97 258TunnelStateData::Connection::error(int const xerrno)
a46d2c0e 259{
260 /* XXX fixme xstrerror and xerrno... */
261 errno = xerrno;
262
4af6d488
AJ
263 debugs(50, debugLevelForError(xerrno), "TunnelStateData::Connection::error: FD " << fd() <<
264 ": read/write failure: " << xstrerror());
62e76326 265
a46d2c0e 266 if (!ignoreErrno(xerrno))
267 comm_close(fd());
983061ed 268}
269
270/* Read from client side and queue it for writing to the server */
a46d2c0e 271void
fa34dd97 272TunnelStateData::ReadClient(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 273{
fa34dd97 274 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 275 assert (cbdataReferenceValid (tunnelState));
62e76326 276
11007d4b 277 assert(fd == tunnelState->client.fd());
278 tunnelState->readClient(buf, len, errcode, xerrno);
a46d2c0e 279}
62e76326 280
a46d2c0e 281void
fa34dd97 282TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 283{
284 /*
285 * Bail out early on COMM_ERR_CLOSING
26ac0430 286 * - close handlers will tidy up for us
a46d2c0e 287 */
a55f4cea 288
a46d2c0e 289 if (errcode == COMM_ERR_CLOSING)
290 return;
a55f4cea 291
11007d4b 292 debugs(26, 3, "tunnelReadClient: FD " << client.fd() << ", read " << len << " bytes");
62e76326 293
a46d2c0e 294 if (len > 0) {
295 client.bytesIn(len);
296 kb_incr(&statCounter.client_http.kbytes_in, len);
297 }
62e76326 298
a46d2c0e 299 copy (len, errcode, xerrno, client, server, WriteServerDone);
300}
62e76326 301
a46d2c0e 302void
fa34dd97 303TunnelStateData::copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *completion)
a46d2c0e 304{
305 /* I think this is to prevent free-while-in-a-callback behaviour
26ac0430 306 * - RBC 20030229
a46d2c0e 307 */
308 cbdataInternalLock(this); /* ??? should be locked by the caller... */
62e76326 309
99c02c10 310 /* Bump the server connection timeout on any activity */
11a6896c 311 if (!fd_closed(server.fd()))
26ac0430 312 commSetTimeout(server.fd(), Config.Timeout.read, tunnelTimeout, this);
99c02c10 313
a46d2c0e 314 if (len < 0 || errcode)
315 from.error (xerrno);
11a6896c 316 else if (len == 0 || fd_closed(to.fd())) {
a46d2c0e 317 comm_close(from.fd());
62e76326 318 /* Only close the remote end if we've finished queueing data to it */
319
11a6896c 320 if (from.len == 0 && !fd_closed(to.fd()) ) {
a46d2c0e 321 comm_close(to.fd());
c4b7a5a9 322 }
a46d2c0e 323 } else if (cbdataReferenceValid(this))
2b663917 324 comm_write(to.fd(), from.buf, len, completion, this, NULL);
a55f4cea 325
a46d2c0e 326 cbdataInternalUnlock(this); /* ??? */
983061ed 327}
328
329/* Writes data from the client buffer to the server side */
a46d2c0e 330void
fa34dd97 331TunnelStateData::WriteServerDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 332{
fa34dd97 333 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 334 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 335
11007d4b 336 assert(fd == tunnelState->server.fd());
337 tunnelState->writeServerDone(buf, len, flag, xerrno);
a46d2c0e 338}
a55f4cea 339
a46d2c0e 340void
fa34dd97 341TunnelStateData::writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 342{
11007d4b 343 debugs(26, 3, "tunnelWriteServer: FD " << server.fd() << ", " << len << " bytes written");
62e76326 344
04f7fd38 345 if (flag == COMM_ERR_CLOSING)
4a62c542
CT
346 return;
347
5dacdf3f 348 /* Error? */
349 if (len < 0 || flag != COMM_OK) {
350 server.error(xerrno); // may call comm_close
351 return;
c4b7a5a9 352 }
62e76326 353
5dacdf3f 354 /* EOF? */
a46d2c0e 355 if (len == 0) {
356 comm_close(server.fd());
357 return;
358 }
62e76326 359
5dacdf3f 360 /* Valid data */
361 kb_incr(&statCounter.server.all.kbytes_out, len);
362 kb_incr(&statCounter.server.other.kbytes_out, len);
363 client.dataSent(len);
364
a46d2c0e 365 /* If the other end has closed, so should we */
11a6896c 366 if (fd_closed(client.fd())) {
a46d2c0e 367 comm_close(server.fd());
a55f4cea 368 return;
c4b7a5a9 369 }
62e76326 370
a46d2c0e 371 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a46d2c0e 372
5dacdf3f 373 if (cbdataReferenceValid(this))
a46d2c0e 374 copyRead(client, ReadClient);
375
376 cbdataInternalUnlock(this); /* ??? */
983061ed 377}
378
379/* Writes data from the server buffer to the client side */
a46d2c0e 380void
fa34dd97 381TunnelStateData::WriteClientDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 382{
fa34dd97 383 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 384 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 385
11007d4b 386 assert(fd == tunnelState->client.fd());
387 tunnelState->writeClientDone(buf, len, flag, xerrno);
a46d2c0e 388}
389
390void
fa34dd97 391TunnelStateData::Connection::dataSent (size_t amount)
a46d2c0e 392{
393 assert(amount == (size_t)len);
394 len =0;
395 /* increment total object size */
396
397 if (size_ptr)
398 *size_ptr += amount;
399}
400
401void
fa34dd97 402TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 403{
11007d4b 404 debugs(26, 3, "tunnelWriteClient: FD " << client.fd() << ", " << len << " bytes written");
62e76326 405
04f7fd38 406 if (flag == COMM_ERR_CLOSING)
4a62c542
CT
407 return;
408
5dacdf3f 409 /* Error? */
410 if (len < 0 || flag != COMM_OK) {
411 client.error(xerrno); // may call comm_close
412 return;
c4b7a5a9 413 }
62e76326 414
5dacdf3f 415 /* EOF? */
a46d2c0e 416 if (len == 0) {
417 comm_close(client.fd());
62e76326 418 return;
983061ed 419 }
62e76326 420
5dacdf3f 421 /* Valid data */
422 kb_incr(&statCounter.client_http.kbytes_out, len);
423 server.dataSent(len);
424
a46d2c0e 425 /* If the other end has closed, so should we */
11a6896c 426 if (fd_closed(server.fd())) {
a46d2c0e 427 comm_close(client.fd());
a55f4cea 428 return;
983061ed 429 }
62e76326 430
a46d2c0e 431 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a55f4cea 432
5dacdf3f 433 if (cbdataReferenceValid(this))
a46d2c0e 434 copyRead(server, ReadServer);
2c202d66 435
a46d2c0e 436 cbdataInternalUnlock(this); /* ??? */
983061ed 437}
438
b8d8561b 439static void
11007d4b 440tunnelTimeout(int fd, void *data)
983061ed 441{
fa34dd97 442 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 443 debugs(26, 3, "tunnelTimeout: FD " << fd);
444 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
445 cbdataInternalLock(tunnelState);
a55f4cea 446
11007d4b 447 tunnelState->client.closeIfOpen();
448 tunnelState->server.closeIfOpen();
449 cbdataInternalUnlock(tunnelState);
a46d2c0e 450}
62e76326 451
a46d2c0e 452void
fa34dd97 453TunnelStateData::Connection::closeIfOpen()
a46d2c0e 454{
11a6896c 455 if (!fd_closed(fd()))
a46d2c0e 456 comm_close(fd());
457}
458
459void
fa34dd97 460TunnelStateData::copyRead(Connection &from, IOCB *completion)
a46d2c0e 461{
462 assert(from.len == 0);
463 comm_read(from.fd(), from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), completion, this);
983061ed 464}
465
380963c2 466static void
11007d4b 467tunnelConnectTimeout(int fd, void *data)
380963c2 468{
fa34dd97 469 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 470 HttpRequest *request = tunnelState->request;
380963c2 471 ErrorState *err = NULL;
472
ebbfd6f2
AJ
473 if (tunnelState->servers) {
474 if (tunnelState->servers->_peer)
475 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
476 tunnelState->servers->_peer->host);
477 else if (Config.onoff.log_ip_on_direct)
478 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
479 fd_table[tunnelState->server.fd()].ipaddr);
480 else
481 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
482 tunnelState->host);
483 } else
26ac0430 484 debugs(26, 1, "tunnelConnectTimeout(): tunnelState->servers is NULL");
380963c2 485
2cc81f1f 486 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
380963c2 487
11007d4b 488 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
380963c2 489
490 err->xerrno = ETIMEDOUT;
491
11007d4b 492 err->port = tunnelState->port;
380963c2 493
11007d4b 494 err->callback = tunnelErrorComplete;
380963c2 495
11007d4b 496 err->callback_data = tunnelState;
380963c2 497
11007d4b 498 errorSend(tunnelState->client.fd(), err);
54e3f327 499 comm_close(fd);
380963c2 500}
a46d2c0e 501
c4b7a5a9 502static void
11007d4b 503tunnelConnectedWriteDone(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 504{
fa34dd97 505 TunnelStateData *tunnelState = (TunnelStateData *)data;
62e76326 506
507 if (flag != COMM_OK) {
11007d4b 508 tunnelErrorComplete(fd, data, 0);
62e76326 509 return;
510 }
511
11007d4b 512 if (cbdataReferenceValid(tunnelState)) {
fa34dd97 513 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
514 tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
62e76326 515 }
c4b7a5a9 516}
517
c4b7a5a9 518/*
519 * handle the write completion from a proxy request to an upstream proxy
520 */
521static void
11007d4b 522tunnelProxyConnectedWriteDone(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 523{
11007d4b 524 tunnelConnectedWriteDone(fd, buf, size, flag, xerrno, data);
c4b7a5a9 525}
526
b8d8561b 527static void
11007d4b 528tunnelConnected(int fd, void *data)
983061ed 529{
fa34dd97 530 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 531 debugs(26, 3, "tunnelConnected: FD " << fd << " tunnelState=" << tunnelState);
532 *tunnelState->status_ptr = HTTP_OK;
533 comm_write(tunnelState->client.fd(), conn_established, strlen(conn_established),
534 tunnelConnectedWriteDone, tunnelState, NULL);
983061ed 535}
536
b8d8561b 537static void
11007d4b 538tunnelErrorComplete(int fdnotused, void *data, size_t sizenotused)
30a4f2a8 539{
fa34dd97 540 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 541 assert(tunnelState != NULL);
542 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
543 cbdataInternalLock(tunnelState);
62e76326 544
11a6896c 545 if (!fd_closed(tunnelState->client.fd()))
11007d4b 546 comm_close(tunnelState->client.fd());
62e76326 547
11a6896c 548 if (fd_closed(tunnelState->server.fd()))
11007d4b 549 comm_close(tunnelState->server.fd());
380963c2 550
11007d4b 551 cbdataInternalUnlock(tunnelState);
30a4f2a8 552}
553
983061ed 554
b8d8561b 555static void
3ff65596 556tunnelConnectDone(int fdnotused, const DnsLookupDetails &dns, comm_err_t status, int xerrno, void *data)
983061ed 557{
fa34dd97 558 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 559 HttpRequest *request = tunnelState->request;
9b312a19 560 ErrorState *err = NULL;
62e76326 561
3ff65596
AR
562 request->recordLookup(dns);
563
11007d4b 564 if (tunnelState->servers->_peer)
565 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
566 tunnelState->servers->_peer->host);
890b0fa8 567 else if (Config.onoff.log_ip_on_direct)
11007d4b 568 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
569 fd_table[tunnelState->server.fd()].ipaddr);
890b0fa8 570 else
11007d4b 571 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
572 tunnelState->host);
62e76326 573
edeb28fd 574 if (status == COMM_ERR_DNS) {
11007d4b 575 debugs(26, 4, "tunnelConnect: Unknown host: " << tunnelState->host);
2cc81f1f 576 err = errorCon(ERR_DNS_FAIL, HTTP_NOT_FOUND, request);
11007d4b 577 *tunnelState->status_ptr = HTTP_NOT_FOUND;
3ff65596 578 err->dnsError = dns.error;
11007d4b 579 err->callback = tunnelErrorComplete;
580 err->callback_data = tunnelState;
581 errorSend(tunnelState->client.fd(), err);
edeb28fd 582 } else if (status != COMM_OK) {
2cc81f1f 583 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
11007d4b 584 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
f3400a93 585 err->xerrno = xerrno;
11007d4b 586 err->port = tunnelState->port;
587 err->callback = tunnelErrorComplete;
588 err->callback_data = tunnelState;
589 errorSend(tunnelState->client.fd(), err);
fe40a877 590 } else {
11007d4b 591 if (tunnelState->servers->_peer)
592 tunnelProxyConnected(tunnelState->server.fd(), tunnelState);
62e76326 593 else {
11007d4b 594 tunnelConnected(tunnelState->server.fd(), tunnelState);
62e76326 595 }
596
11007d4b 597 commSetTimeout(tunnelState->server.fd(),
62e76326 598 Config.Timeout.read,
11007d4b 599 tunnelTimeout,
600 tunnelState);
983061ed 601 }
983061ed 602}
30a4f2a8 603
770f051d 604void
47f6e231 605tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
30a4f2a8 606{
607 /* Create state structure. */
fa34dd97 608 TunnelStateData *tunnelState = NULL;
30a4f2a8 609 int sock;
9b312a19 610 ErrorState *err = NULL;
f1003989 611 int answer;
98242069 612 int fd = http->getConn()->fd;
190154cf 613 HttpRequest *request = http->request;
d5964d58 614 char *url = http->uri;
f1003989 615 /*
cc192b50 616 * client_addr.IsNoAddr() indicates this is an "internal" request
a4b8110e 617 * from peer_digest.c, asn.c, netdb.c, etc and should always
618 * be allowed. yuck, I know.
619 */
62e76326 620
b50e327b 621 if (!request->client_addr.IsNoAddr() && Config.accessList.miss) {
62e76326 622 /*
623 * Check if this host is allowed to fetch MISSES from us (miss_access)
b50e327b 624 * default is to allow.
62e76326 625 */
c0941a6a 626 ACLFilledChecklist ch(Config.accessList.miss, request, NULL);
62e76326 627 ch.src_addr = request->client_addr;
628 ch.my_addr = request->my_addr;
b448c119 629 answer = ch.fastCheck();
62e76326 630
631 if (answer == 0) {
2cc81f1f 632 err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN, request);
62e76326 633 *status_ptr = HTTP_FORBIDDEN;
62e76326 634 errorSend(fd, err);
635 return;
636 }
f1003989 637 }
62e76326 638
60745f24 639 debugs(26, 3, "tunnelStart: '" << RequestMethodStr(request->method) << " " << url << "'");
83704487 640 statCounter.server.all.requests++;
641 statCounter.server.other.requests++;
30a4f2a8 642 /* Create socket. */
ad61a2b4 643 IpAddress temp = getOutgoingAddr(request,NULL);
232820e2
AJ
644 int flags = COMM_NONBLOCKING;
645 if (request->flags.spoof_client_ip) {
646 flags |= COMM_TRANSPARENT;
647 }
d6827718 648 sock = comm_openex(SOCK_STREAM,
bdb741f4 649 IPPROTO_TCP,
cc192b50 650 temp,
232820e2 651 flags,
62e76326 652 getOutgoingTOS(request),
653 url);
654
30a4f2a8 655 if (sock == COMM_ERROR) {
11007d4b 656 debugs(26, 4, "tunnelStart: Failed because we're out of sockets.");
2cc81f1f 657 err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
62e76326 658 *status_ptr = HTTP_INTERNAL_SERVER_ERROR;
659 err->xerrno = errno;
62e76326 660 errorSend(fd, err);
661 return;
30a4f2a8 662 }
62e76326 663
fa34dd97 664 tunnelState = new TunnelStateData;
59715b38 665#if DELAY_POOLS
62e76326 666
11007d4b 667 tunnelState->server.setDelayId(DelayId::DelayClient(http));
59715b38 668#endif
62e76326 669
11007d4b 670 tunnelState->url = xstrdup(url);
671 tunnelState->request = HTTPMSGLOCK(request);
672 tunnelState->server.size_ptr = size_ptr;
673 tunnelState->status_ptr = status_ptr;
674 tunnelState->client.fd(fd);
675 tunnelState->server.fd(sock);
676 comm_add_close_handler(tunnelState->server.fd(),
677 tunnelServerClosed,
678 tunnelState);
679 comm_add_close_handler(tunnelState->client.fd(),
680 tunnelClientClosed,
681 tunnelState);
682 commSetTimeout(tunnelState->client.fd(),
62e76326 683 Config.Timeout.lifetime,
11007d4b 684 tunnelTimeout,
685 tunnelState);
686 commSetTimeout(tunnelState->server.fd(),
62e76326 687 Config.Timeout.connect,
11007d4b 688 tunnelConnectTimeout,
689 tunnelState);
b6c0e933 690 peerSelect(request,
62e76326 691 NULL,
11007d4b 692 tunnelPeerSelectComplete,
693 tunnelState);
adb78bd4 694 /*
695 * Disable the client read handler until peer selection is complete
696 * Take control away from client_side.c.
697 */
11007d4b 698 commSetSelect(tunnelState->client.fd(), COMM_SELECT_READ, NULL, NULL, 0);
30a4f2a8 699}
98ffb7e4 700
b8d8561b 701static void
11007d4b 702tunnelProxyConnected(int fd, void *data)
98ffb7e4 703{
fa34dd97 704 TunnelStateData *tunnelState = (TunnelStateData *)data;
75faaa7a 705 HttpHeader hdr_out(hoRequest);
e1e72f06 706 Packer p;
b4b5fd95 707 http_state_flags flags;
11007d4b 708 debugs(26, 3, "tunnelProxyConnected: FD " << fd << " tunnelState=" << tunnelState);
b4b5fd95 709 memset(&flags, '\0', sizeof(flags));
11007d4b 710 flags.proxying = tunnelState->request->flags.proxying;
032785bf 711 MemBuf mb;
2fe7eff9 712 mb.init();
11007d4b 713 mb.Printf("CONNECT %s HTTP/1.0\r\n", tunnelState->url);
714 HttpStateData::httpBuildRequestHeader(tunnelState->request,
715 tunnelState->request,
e5ee81f0 716 NULL, /* StoreEntry */
717 &hdr_out,
718 flags); /* flags */
e1e72f06 719 packerToMemInit(&p, &mb);
a9925b40 720 hdr_out.packInto(&p);
519e0948 721 hdr_out.clean();
e1e72f06 722 packerClean(&p);
2fe7eff9 723 mb.append("\r\n", 2);
c4b7a5a9 724
11007d4b 725 comm_write_mbuf(tunnelState->server.fd(), &mb, tunnelProxyConnectedWriteDone, tunnelState);
726 commSetTimeout(tunnelState->server.fd(), Config.Timeout.read, tunnelTimeout, tunnelState);
98ffb7e4 727}
33ea9fff 728
33ea9fff 729static void
11007d4b 730tunnelPeerSelectComplete(FwdServer * fs, void *data)
33ea9fff 731{
fa34dd97 732 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 733 HttpRequest *request = tunnelState->request;
deb79f06 734 peer *g = NULL;
62e76326 735
db1cd23c 736 if (fs == NULL) {
62e76326 737 ErrorState *err;
2cc81f1f 738 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, request);
11007d4b 739 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
740 err->callback = tunnelErrorComplete;
741 err->callback_data = tunnelState;
742 errorSend(tunnelState->client.fd(), err);
62e76326 743 return;
db1cd23c 744 }
62e76326 745
11007d4b 746 tunnelState->servers = fs;
cc192b50 747 tunnelState->host = fs->_peer ? fs->_peer->host : xstrdup(request->GetHost());
9ca29d23 748 request->peer_host = fs->_peer ? fs->_peer->host : NULL;
62e76326 749
29b8d8d6 750 if (fs->_peer == NULL) {
11007d4b 751 tunnelState->port = request->port;
29b8d8d6 752 } else if (fs->_peer->http_port != 0) {
11007d4b 753 tunnelState->port = fs->_peer->http_port;
29b8d8d6 754 } else if ((g = peerFindByName(fs->_peer->host))) {
11007d4b 755 tunnelState->port = g->http_port;
33ea9fff 756 } else {
11007d4b 757 tunnelState->port = CACHE_HTTP_PORT;
33ea9fff 758 }
62e76326 759
29b8d8d6 760 if (fs->_peer) {
11007d4b 761 tunnelState->request->peer_login = fs->_peer->login;
762 tunnelState->request->flags.proxying = 1;
1f38f50a 763 } else {
11007d4b 764 tunnelState->request->peer_login = NULL;
765 tunnelState->request->flags.proxying = 0;
1f38f50a 766 }
62e76326 767
59715b38 768#if DELAY_POOLS
11007d4b 769 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
a46d2c0e 770 if (g && g->options.no_delay)
11007d4b 771 tunnelState->server.setDelayId(DelayId());
62e76326 772
59715b38 773#endif
a46d2c0e 774
11007d4b 775 commConnectStart(tunnelState->server.fd(),
776 tunnelState->host,
777 tunnelState->port,
778 tunnelConnectDone,
779 tunnelState);
33ea9fff 780}
a46d2c0e 781
fa34dd97 782CBDATA_CLASS_INIT(TunnelStateData);
a46d2c0e 783
784void *
fa34dd97 785TunnelStateData::operator new (size_t)
a46d2c0e 786{
fa34dd97 787 CBDATA_INIT_TYPE(TunnelStateData);
788 TunnelStateData *result = cbdataAlloc(TunnelStateData);
a46d2c0e 789 return result;
790}
791
792void
fa34dd97 793TunnelStateData::operator delete (void *address)
a46d2c0e 794{
fa34dd97 795 TunnelStateData *t = static_cast<TunnelStateData *>(address);
a46d2c0e 796 cbdataFree(t);
797}
798
a46d2c0e 799void
fa34dd97 800TunnelStateData::Connection::fd(int const newFD)
a46d2c0e 801{
802 fd_ = newFD;
803}
804
805bool
fa34dd97 806TunnelStateData::noConnections() const
a46d2c0e 807{
11a6896c 808 return fd_closed(server.fd()) && fd_closed(client.fd());
a46d2c0e 809}
810
811#if DELAY_POOLS
812void
fa34dd97 813TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
a46d2c0e 814{
815 delayId = newDelay;
816}
817
818#endif