]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tunnel.cc
Bug #2089: Fails to warn about invalid netmasks
[thirdparty/squid.git] / src / tunnel.cc
CommitLineData
95d659f0 1
983061ed 2/*
47f6e231 3 * $Id: tunnel.cc,v 1.173 2007/08/13 17:20:51 hno Exp $
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.
24 *
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.
29 *
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"
4fb35c3c 42#include "ACLChecklist.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:
74 Connection() : len (0),buf ((char *)xmalloc(SQUID_TCP_SO_RCVBUF)), size_ptr(NULL), fd_(-1){}
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
0ee4272b 117static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n";
983061ed 118
11007d4b 119static CNCB tunnelConnectDone;
120static ERCB tunnelErrorComplete;
121static PF tunnelServerClosed;
122static PF tunnelClientClosed;
123static PF tunnelTimeout;
124static PSC tunnelPeerSelectComplete;
fa34dd97 125static void tunnelStateFree(TunnelStateData * tunnelState);
11007d4b 126static void tunnelConnected(int fd, void *);
127static void tunnelProxyConnected(int fd, void *);
30a4f2a8 128
b8d8561b 129static void
11007d4b 130tunnelServerClosed(int fd, void *data)
30a4f2a8 131{
fa34dd97 132 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 133 debugs(26, 3, "tunnelServerClosed: FD " << fd);
134 assert(fd == tunnelState->server.fd());
135 tunnelState->server.fd(-1);
62e76326 136
11007d4b 137 if (tunnelState->noConnections())
138 tunnelStateFree(tunnelState);
30a4f2a8 139}
140
b177367b 141static void
11007d4b 142tunnelClientClosed(int fd, void *data)
30a4f2a8 143{
fa34dd97 144 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 145 debugs(26, 3, "tunnelClientClosed: FD " << fd);
146 assert(fd == tunnelState->client.fd());
147 tunnelState->client.fd(-1);
62e76326 148
11007d4b 149 if (tunnelState->noConnections())
150 tunnelStateFree(tunnelState);
30a4f2a8 151}
983061ed 152
b177367b 153static void
fa34dd97 154tunnelStateFree(TunnelStateData * tunnelState)
983061ed 155{
11007d4b 156 debugs(26, 3, "tunnelStateFree: tunnelState=" << tunnelState);
157 assert(tunnelState != NULL);
158 assert(tunnelState->noConnections());
159 safe_free(tunnelState->url);
160 FwdState::serversFree(&tunnelState->servers);
161 tunnelState->host = NULL;
162 HTTPMSGUNLOCK(tunnelState->request);
163 delete tunnelState;
983061ed 164}
165
fa34dd97 166TunnelStateData::Connection::~Connection()
a46d2c0e 167{
168 safe_free (buf);
169}
170
171int
fa34dd97 172TunnelStateData::Connection::bytesWanted(int lowerbound, int upperbound) const
447e176b 173{
a46d2c0e 174#if DELAY_POOLS
175 return delayId.bytesWanted(lowerbound, upperbound);
176#else
62e76326 177
6b13136a 178 return upperbound;
a46d2c0e 179#endif
180}
62e76326 181
a46d2c0e 182void
fa34dd97 183TunnelStateData::Connection::bytesIn(int const &count)
a46d2c0e 184{
185#if DELAY_POOLS
186 delayId.bytesIn(count);
187#endif
62e76326 188
a46d2c0e 189 len += count;
447e176b 190}
62e76326 191
a46d2c0e 192int
fa34dd97 193TunnelStateData::Connection::debugLevelForError(int const xerrno) const
a46d2c0e 194{
195#ifdef ECONNRESET
196
197 if (xerrno == ECONNRESET)
198 return 2;
199
447e176b 200#endif
201
a46d2c0e 202 if (ignoreErrno(xerrno))
203 return 3;
204
205 return 1;
206}
adb78bd4 207
983061ed 208/* Read from server side and queue it for writing to the client */
a46d2c0e 209void
fa34dd97 210TunnelStateData::ReadServer(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 211{
fa34dd97 212 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 213 assert (cbdataReferenceValid (tunnelState));
c4b7a5a9 214
11007d4b 215 assert(fd == tunnelState->server.fd());
216 tunnelState->readServer(buf, len, errcode, xerrno);
a46d2c0e 217}
62e76326 218
a46d2c0e 219void
fa34dd97 220TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 221{
222 /*
223 * Bail out early on COMM_ERR_CLOSING
224 * - close handlers will tidy up for us
225 */
a55f4cea 226
a46d2c0e 227 if (errcode == COMM_ERR_CLOSING)
228 return;
62e76326 229
11007d4b 230 debugs(26, 3, "tunnelReadServer: FD " << server.fd() << ", read " << len << " bytes");
62e76326 231
ee1679df 232 if (len > 0) {
a46d2c0e 233 server.bytesIn(len);
62e76326 234 kb_incr(&statCounter.server.all.kbytes_in, len);
235 kb_incr(&statCounter.server.other.kbytes_in, len);
ee1679df 236 }
62e76326 237
a46d2c0e 238 copy (len, errcode, xerrno, server, client, WriteClientDone);
239}
240
241void
fa34dd97 242TunnelStateData::Connection::error(int const xerrno)
a46d2c0e 243{
244 /* XXX fixme xstrerror and xerrno... */
245 errno = xerrno;
246
247 if (xerrno == COMM_ERR_CLOSING)
a55f4cea 248 return;
62e76326 249
11007d4b 250 debugs(50, debugLevelForError(xerrno), "tunnelReadServer: FD " << fd() <<
bf8fe701 251 ": read failure: " << xstrerror());
62e76326 252
a46d2c0e 253 if (!ignoreErrno(xerrno))
254 comm_close(fd());
983061ed 255}
256
257/* Read from client side and queue it for writing to the server */
a46d2c0e 258void
fa34dd97 259TunnelStateData::ReadClient(int fd, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
983061ed 260{
fa34dd97 261 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 262 assert (cbdataReferenceValid (tunnelState));
62e76326 263
11007d4b 264 assert(fd == tunnelState->client.fd());
265 tunnelState->readClient(buf, len, errcode, xerrno);
a46d2c0e 266}
62e76326 267
a46d2c0e 268void
fa34dd97 269TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno)
a46d2c0e 270{
271 /*
272 * Bail out early on COMM_ERR_CLOSING
273 * - close handlers will tidy up for us
274 */
a55f4cea 275
a46d2c0e 276 if (errcode == COMM_ERR_CLOSING)
277 return;
a55f4cea 278
11007d4b 279 debugs(26, 3, "tunnelReadClient: FD " << client.fd() << ", read " << len << " bytes");
62e76326 280
a46d2c0e 281 if (len > 0) {
282 client.bytesIn(len);
283 kb_incr(&statCounter.client_http.kbytes_in, len);
284 }
62e76326 285
a46d2c0e 286 copy (len, errcode, xerrno, client, server, WriteServerDone);
287}
62e76326 288
a46d2c0e 289void
fa34dd97 290TunnelStateData::copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *completion)
a46d2c0e 291{
292 /* I think this is to prevent free-while-in-a-callback behaviour
293 * - RBC 20030229
294 */
295 cbdataInternalLock(this); /* ??? should be locked by the caller... */
62e76326 296
99c02c10 297 /* Bump the server connection timeout on any activity */
298 if (server.fd() != -1)
299 commSetTimeout(server.fd(), Config.Timeout.read, tunnelTimeout, this);
300
a46d2c0e 301 if (len < 0 || errcode)
302 from.error (xerrno);
303 else if (len == 0 || to.fd() == -1) {
304 comm_close(from.fd());
62e76326 305 /* Only close the remote end if we've finished queueing data to it */
306
a46d2c0e 307 if (from.len == 0 && to.fd() != -1) {
308 comm_close(to.fd());
c4b7a5a9 309 }
a46d2c0e 310 } else if (cbdataReferenceValid(this))
2b663917 311 comm_write(to.fd(), from.buf, len, completion, this, NULL);
a55f4cea 312
a46d2c0e 313 cbdataInternalUnlock(this); /* ??? */
983061ed 314}
315
316/* Writes data from the client buffer to the server side */
a46d2c0e 317void
fa34dd97 318TunnelStateData::WriteServerDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 319{
fa34dd97 320 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 321 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 322
11007d4b 323 assert(fd == tunnelState->server.fd());
324 tunnelState->writeServerDone(buf, len, flag, xerrno);
a46d2c0e 325}
a55f4cea 326
a46d2c0e 327void
fa34dd97 328TunnelStateData::writeServerDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 329{
11007d4b 330 debugs(26, 3, "tunnelWriteServer: FD " << server.fd() << ", " << len << " bytes written");
62e76326 331
5dacdf3f 332 /* Error? */
333 if (len < 0 || flag != COMM_OK) {
334 server.error(xerrno); // may call comm_close
335 return;
c4b7a5a9 336 }
62e76326 337
5dacdf3f 338 /* EOF? */
a46d2c0e 339 if (len == 0) {
340 comm_close(server.fd());
341 return;
342 }
62e76326 343
5dacdf3f 344 /* Valid data */
345 kb_incr(&statCounter.server.all.kbytes_out, len);
346 kb_incr(&statCounter.server.other.kbytes_out, len);
347 client.dataSent(len);
348
a46d2c0e 349 /* If the other end has closed, so should we */
350 if (client.fd() == -1) {
351 comm_close(server.fd());
a55f4cea 352 return;
c4b7a5a9 353 }
62e76326 354
a46d2c0e 355 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a46d2c0e 356
5dacdf3f 357 if (cbdataReferenceValid(this))
a46d2c0e 358 copyRead(client, ReadClient);
359
360 cbdataInternalUnlock(this); /* ??? */
983061ed 361}
362
363/* Writes data from the server buffer to the client side */
a46d2c0e 364void
fa34dd97 365TunnelStateData::WriteClientDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
983061ed 366{
fa34dd97 367 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 368 assert (cbdataReferenceValid (tunnelState));
a46d2c0e 369
11007d4b 370 assert(fd == tunnelState->client.fd());
371 tunnelState->writeClientDone(buf, len, flag, xerrno);
a46d2c0e 372}
373
374void
fa34dd97 375TunnelStateData::Connection::dataSent (size_t amount)
a46d2c0e 376{
377 assert(amount == (size_t)len);
378 len =0;
379 /* increment total object size */
380
381 if (size_ptr)
382 *size_ptr += amount;
383}
384
385void
fa34dd97 386TunnelStateData::writeClientDone(char *buf, size_t len, comm_err_t flag, int xerrno)
a46d2c0e 387{
11007d4b 388 debugs(26, 3, "tunnelWriteClient: FD " << client.fd() << ", " << len << " bytes written");
62e76326 389
5dacdf3f 390 /* Error? */
391 if (len < 0 || flag != COMM_OK) {
392 client.error(xerrno); // may call comm_close
393 return;
c4b7a5a9 394 }
62e76326 395
5dacdf3f 396 /* EOF? */
a46d2c0e 397 if (len == 0) {
398 comm_close(client.fd());
62e76326 399 return;
983061ed 400 }
62e76326 401
5dacdf3f 402 /* Valid data */
403 kb_incr(&statCounter.client_http.kbytes_out, len);
404 server.dataSent(len);
405
a46d2c0e 406 /* If the other end has closed, so should we */
407 if (server.fd() == -1) {
408 comm_close(client.fd());
a55f4cea 409 return;
983061ed 410 }
62e76326 411
a46d2c0e 412 cbdataInternalLock(this); /* ??? should be locked by the caller... */
a55f4cea 413
5dacdf3f 414 if (cbdataReferenceValid(this))
a46d2c0e 415 copyRead(server, ReadServer);
2c202d66 416
a46d2c0e 417 cbdataInternalUnlock(this); /* ??? */
983061ed 418}
419
b8d8561b 420static void
11007d4b 421tunnelTimeout(int fd, void *data)
983061ed 422{
fa34dd97 423 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 424 debugs(26, 3, "tunnelTimeout: FD " << fd);
425 /* Temporary lock to protect our own feets (comm_close -> tunnelClientClosed -> Free) */
426 cbdataInternalLock(tunnelState);
a55f4cea 427
11007d4b 428 tunnelState->client.closeIfOpen();
429 tunnelState->server.closeIfOpen();
430 cbdataInternalUnlock(tunnelState);
a46d2c0e 431}
62e76326 432
a46d2c0e 433void
fa34dd97 434TunnelStateData::Connection::closeIfOpen()
a46d2c0e 435{
436 if (fd() != -1)
437 comm_close(fd());
438}
439
440void
fa34dd97 441TunnelStateData::copyRead(Connection &from, IOCB *completion)
a46d2c0e 442{
443 assert(from.len == 0);
444 comm_read(from.fd(), from.buf, from.bytesWanted(1, SQUID_TCP_SO_RCVBUF), completion, this);
983061ed 445}
446
380963c2 447static void
11007d4b 448tunnelConnectTimeout(int fd, void *data)
380963c2 449{
fa34dd97 450 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 451 HttpRequest *request = tunnelState->request;
380963c2 452 ErrorState *err = NULL;
453
11007d4b 454 if (tunnelState->servers->_peer)
455 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
456 tunnelState->servers->_peer->host);
380963c2 457 else if (Config.onoff.log_ip_on_direct)
11007d4b 458 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
459 fd_table[tunnelState->server.fd()].ipaddr);
380963c2 460 else
11007d4b 461 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
462 tunnelState->host);
380963c2 463
464 comm_close(fd);
465
2cc81f1f 466 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
380963c2 467
11007d4b 468 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
380963c2 469
470 err->xerrno = ETIMEDOUT;
471
11007d4b 472 err->port = tunnelState->port;
380963c2 473
11007d4b 474 err->callback = tunnelErrorComplete;
380963c2 475
11007d4b 476 err->callback_data = tunnelState;
380963c2 477
11007d4b 478 errorSend(tunnelState->client.fd(), err);
380963c2 479}
a46d2c0e 480
c4b7a5a9 481static void
11007d4b 482tunnelConnectedWriteDone(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 483{
fa34dd97 484 TunnelStateData *tunnelState = (TunnelStateData *)data;
62e76326 485
486 if (flag != COMM_OK) {
11007d4b 487 tunnelErrorComplete(fd, data, 0);
62e76326 488 return;
489 }
490
11007d4b 491 if (cbdataReferenceValid(tunnelState)) {
fa34dd97 492 tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
493 tunnelState->copyRead(tunnelState->client, TunnelStateData::ReadClient);
62e76326 494 }
c4b7a5a9 495}
496
c4b7a5a9 497/*
498 * handle the write completion from a proxy request to an upstream proxy
499 */
500static void
11007d4b 501tunnelProxyConnectedWriteDone(int fd, char *buf, size_t size, comm_err_t flag, int xerrno, void *data)
c4b7a5a9 502{
11007d4b 503 tunnelConnectedWriteDone(fd, buf, size, flag, xerrno, data);
c4b7a5a9 504}
505
b8d8561b 506static void
11007d4b 507tunnelConnected(int fd, void *data)
983061ed 508{
fa34dd97 509 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 510 debugs(26, 3, "tunnelConnected: FD " << fd << " tunnelState=" << tunnelState);
511 *tunnelState->status_ptr = HTTP_OK;
512 comm_write(tunnelState->client.fd(), conn_established, strlen(conn_established),
513 tunnelConnectedWriteDone, tunnelState, NULL);
983061ed 514}
515
b8d8561b 516static void
11007d4b 517tunnelErrorComplete(int fdnotused, void *data, size_t sizenotused)
30a4f2a8 518{
fa34dd97 519 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 520 assert(tunnelState != NULL);
521 /* temporary lock to save our own feets (comm_close -> tunnelClientClosed -> Free) */
522 cbdataInternalLock(tunnelState);
62e76326 523
11007d4b 524 if (tunnelState->client.fd() > -1)
525 comm_close(tunnelState->client.fd());
62e76326 526
11007d4b 527 if (tunnelState->server.fd() > -1)
528 comm_close(tunnelState->server.fd());
380963c2 529
11007d4b 530 cbdataInternalUnlock(tunnelState);
30a4f2a8 531}
532
983061ed 533
b8d8561b 534static void
11007d4b 535tunnelConnectDone(int fdnotused, comm_err_t status, int xerrno, void *data)
983061ed 536{
fa34dd97 537 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 538 HttpRequest *request = tunnelState->request;
9b312a19 539 ErrorState *err = NULL;
62e76326 540
11007d4b 541 if (tunnelState->servers->_peer)
542 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
543 tunnelState->servers->_peer->host);
890b0fa8 544 else if (Config.onoff.log_ip_on_direct)
11007d4b 545 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
546 fd_table[tunnelState->server.fd()].ipaddr);
890b0fa8 547 else
11007d4b 548 hierarchyNote(&tunnelState->request->hier, tunnelState->servers->code,
549 tunnelState->host);
62e76326 550
edeb28fd 551 if (status == COMM_ERR_DNS) {
11007d4b 552 debugs(26, 4, "tunnelConnect: Unknown host: " << tunnelState->host);
2cc81f1f 553 err = errorCon(ERR_DNS_FAIL, HTTP_NOT_FOUND, request);
11007d4b 554 *tunnelState->status_ptr = HTTP_NOT_FOUND;
62e76326 555 err->dnsserver_msg = xstrdup(dns_error_message);
11007d4b 556 err->callback = tunnelErrorComplete;
557 err->callback_data = tunnelState;
558 errorSend(tunnelState->client.fd(), err);
edeb28fd 559 } else if (status != COMM_OK) {
2cc81f1f 560 err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
11007d4b 561 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
f3400a93 562 err->xerrno = xerrno;
11007d4b 563 err->port = tunnelState->port;
564 err->callback = tunnelErrorComplete;
565 err->callback_data = tunnelState;
566 errorSend(tunnelState->client.fd(), err);
fe40a877 567 } else {
11007d4b 568 if (tunnelState->servers->_peer)
569 tunnelProxyConnected(tunnelState->server.fd(), tunnelState);
62e76326 570 else {
11007d4b 571 tunnelConnected(tunnelState->server.fd(), tunnelState);
62e76326 572 }
573
11007d4b 574 commSetTimeout(tunnelState->server.fd(),
62e76326 575 Config.Timeout.read,
11007d4b 576 tunnelTimeout,
577 tunnelState);
983061ed 578 }
983061ed 579}
30a4f2a8 580
770f051d 581void
47f6e231 582tunnelStart(ClientHttpRequest * http, int64_t * size_ptr, int *status_ptr)
30a4f2a8 583{
584 /* Create state structure. */
fa34dd97 585 TunnelStateData *tunnelState = NULL;
30a4f2a8 586 int sock;
9b312a19 587 ErrorState *err = NULL;
f1003989 588 int answer;
98242069 589 int fd = http->getConn()->fd;
190154cf 590 HttpRequest *request = http->request;
d5964d58 591 char *url = http->uri;
f1003989 592 /*
a4b8110e 593 * client_addr == no_addr indicates this is an "internal" request
594 * from peer_digest.c, asn.c, netdb.c, etc and should always
595 * be allowed. yuck, I know.
596 */
62e76326 597
f1003989 598 if (request->client_addr.s_addr != no_addr.s_addr) {
62e76326 599 /*
600 * Check if this host is allowed to fetch MISSES from us (miss_access)
601 */
602 ACLChecklist ch;
603 ch.src_addr = request->client_addr;
604 ch.my_addr = request->my_addr;
605 ch.my_port = request->my_port;
6dd9f4bd 606 ch.request = HTTPMSGLOCK(request);
506768d9 607 ch.accessList = cbdataReference(Config.accessList.miss);
108d65b2 608 /* cbdataReferenceDone() happens in either fastCheck() or ~ACLCheckList */
b448c119 609 answer = ch.fastCheck();
62e76326 610
611 if (answer == 0) {
2cc81f1f 612 err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN, request);
62e76326 613 *status_ptr = HTTP_FORBIDDEN;
62e76326 614 errorSend(fd, err);
615 return;
616 }
f1003989 617 }
62e76326 618
11007d4b 619 debugs(26, 3, "tunnelStart: '" << RequestMethodStr[request->method] << " " << url << "'");
83704487 620 statCounter.server.all.requests++;
621 statCounter.server.other.requests++;
30a4f2a8 622 /* Create socket. */
d6827718 623 sock = comm_openex(SOCK_STREAM,
bdb741f4 624 IPPROTO_TCP,
62e76326 625 getOutgoingAddr(request),
626 0,
627 COMM_NONBLOCKING,
628 getOutgoingTOS(request),
629 url);
630
30a4f2a8 631 if (sock == COMM_ERROR) {
11007d4b 632 debugs(26, 4, "tunnelStart: Failed because we're out of sockets.");
2cc81f1f 633 err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
62e76326 634 *status_ptr = HTTP_INTERNAL_SERVER_ERROR;
635 err->xerrno = errno;
62e76326 636 errorSend(fd, err);
637 return;
30a4f2a8 638 }
62e76326 639
fa34dd97 640 tunnelState = new TunnelStateData;
59715b38 641#if DELAY_POOLS
62e76326 642
11007d4b 643 tunnelState->server.setDelayId(DelayId::DelayClient(http));
59715b38 644#endif
62e76326 645
11007d4b 646 tunnelState->url = xstrdup(url);
647 tunnelState->request = HTTPMSGLOCK(request);
648 tunnelState->server.size_ptr = size_ptr;
649 tunnelState->status_ptr = status_ptr;
650 tunnelState->client.fd(fd);
651 tunnelState->server.fd(sock);
652 comm_add_close_handler(tunnelState->server.fd(),
653 tunnelServerClosed,
654 tunnelState);
655 comm_add_close_handler(tunnelState->client.fd(),
656 tunnelClientClosed,
657 tunnelState);
658 commSetTimeout(tunnelState->client.fd(),
62e76326 659 Config.Timeout.lifetime,
11007d4b 660 tunnelTimeout,
661 tunnelState);
662 commSetTimeout(tunnelState->server.fd(),
62e76326 663 Config.Timeout.connect,
11007d4b 664 tunnelConnectTimeout,
665 tunnelState);
b6c0e933 666 peerSelect(request,
62e76326 667 NULL,
11007d4b 668 tunnelPeerSelectComplete,
669 tunnelState);
adb78bd4 670 /*
671 * Disable the client read handler until peer selection is complete
672 * Take control away from client_side.c.
673 */
11007d4b 674 commSetSelect(tunnelState->client.fd(), COMM_SELECT_READ, NULL, NULL, 0);
30a4f2a8 675}
98ffb7e4 676
b8d8561b 677static void
11007d4b 678tunnelProxyConnected(int fd, void *data)
98ffb7e4 679{
fa34dd97 680 TunnelStateData *tunnelState = (TunnelStateData *)data;
75faaa7a 681 HttpHeader hdr_out(hoRequest);
e1e72f06 682 Packer p;
b4b5fd95 683 http_state_flags flags;
11007d4b 684 debugs(26, 3, "tunnelProxyConnected: FD " << fd << " tunnelState=" << tunnelState);
b4b5fd95 685 memset(&flags, '\0', sizeof(flags));
11007d4b 686 flags.proxying = tunnelState->request->flags.proxying;
032785bf 687 MemBuf mb;
2fe7eff9 688 mb.init();
11007d4b 689 mb.Printf("CONNECT %s HTTP/1.0\r\n", tunnelState->url);
690 HttpStateData::httpBuildRequestHeader(tunnelState->request,
691 tunnelState->request,
e5ee81f0 692 NULL, /* StoreEntry */
693 &hdr_out,
694 flags); /* flags */
e1e72f06 695 packerToMemInit(&p, &mb);
a9925b40 696 hdr_out.packInto(&p);
519e0948 697 hdr_out.clean();
e1e72f06 698 packerClean(&p);
2fe7eff9 699 mb.append("\r\n", 2);
c4b7a5a9 700
11007d4b 701 comm_write_mbuf(tunnelState->server.fd(), &mb, tunnelProxyConnectedWriteDone, tunnelState);
702 commSetTimeout(tunnelState->server.fd(), Config.Timeout.read, tunnelTimeout, tunnelState);
98ffb7e4 703}
33ea9fff 704
33ea9fff 705static void
11007d4b 706tunnelPeerSelectComplete(FwdServer * fs, void *data)
33ea9fff 707{
fa34dd97 708 TunnelStateData *tunnelState = (TunnelStateData *)data;
11007d4b 709 HttpRequest *request = tunnelState->request;
deb79f06 710 peer *g = NULL;
62e76326 711
db1cd23c 712 if (fs == NULL) {
62e76326 713 ErrorState *err;
2cc81f1f 714 err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, request);
11007d4b 715 *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
716 err->callback = tunnelErrorComplete;
717 err->callback_data = tunnelState;
718 errorSend(tunnelState->client.fd(), err);
62e76326 719 return;
db1cd23c 720 }
62e76326 721
11007d4b 722 tunnelState->servers = fs;
723 tunnelState->host = fs->_peer ? fs->_peer->host : request->host;
62e76326 724
29b8d8d6 725 if (fs->_peer == NULL) {
11007d4b 726 tunnelState->port = request->port;
29b8d8d6 727 } else if (fs->_peer->http_port != 0) {
11007d4b 728 tunnelState->port = fs->_peer->http_port;
29b8d8d6 729 } else if ((g = peerFindByName(fs->_peer->host))) {
11007d4b 730 tunnelState->port = g->http_port;
33ea9fff 731 } else {
11007d4b 732 tunnelState->port = CACHE_HTTP_PORT;
33ea9fff 733 }
62e76326 734
29b8d8d6 735 if (fs->_peer) {
11007d4b 736 tunnelState->request->peer_login = fs->_peer->login;
737 tunnelState->request->flags.proxying = 1;
1f38f50a 738 } else {
11007d4b 739 tunnelState->request->peer_login = NULL;
740 tunnelState->request->flags.proxying = 0;
1f38f50a 741 }
62e76326 742
59715b38 743#if DELAY_POOLS
11007d4b 744 /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */
a46d2c0e 745 if (g && g->options.no_delay)
11007d4b 746 tunnelState->server.setDelayId(DelayId());
62e76326 747
59715b38 748#endif
a46d2c0e 749
11007d4b 750 commConnectStart(tunnelState->server.fd(),
751 tunnelState->host,
752 tunnelState->port,
753 tunnelConnectDone,
754 tunnelState);
33ea9fff 755}
a46d2c0e 756
fa34dd97 757CBDATA_CLASS_INIT(TunnelStateData);
a46d2c0e 758
759void *
fa34dd97 760TunnelStateData::operator new (size_t)
a46d2c0e 761{
fa34dd97 762 CBDATA_INIT_TYPE(TunnelStateData);
763 TunnelStateData *result = cbdataAlloc(TunnelStateData);
a46d2c0e 764 return result;
765}
766
767void
fa34dd97 768TunnelStateData::operator delete (void *address)
a46d2c0e 769{
fa34dd97 770 TunnelStateData *t = static_cast<TunnelStateData *>(address);
a46d2c0e 771 cbdataFree(t);
772}
773
a46d2c0e 774void
fa34dd97 775TunnelStateData::Connection::fd(int const newFD)
a46d2c0e 776{
777 fd_ = newFD;
778}
779
780bool
fa34dd97 781TunnelStateData::noConnections() const
a46d2c0e 782{
783 return (server.fd() == -1) && (client.fd() == -1);
784}
785
786#if DELAY_POOLS
787void
fa34dd97 788TunnelStateData::Connection::setDelayId(DelayId const &newDelay)
a46d2c0e 789{
790 delayId = newDelay;
791}
792
793#endif