]>
Commit | Line | Data |
---|---|---|
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 | 50 | class TunnelStateData |
62e76326 | 51 | { |
a46d2c0e | 52 | |
53 | public: | |
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 | ||
108 | private: | |
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 | 119 | static const char *const conn_established = "HTTP/1.0 200 Connection established\r\n\r\n"; |
983061ed | 120 | |
11007d4b | 121 | static CNCB tunnelConnectDone; |
122 | static ERCB tunnelErrorComplete; | |
123 | static PF tunnelServerClosed; | |
124 | static PF tunnelClientClosed; | |
125 | static PF tunnelTimeout; | |
126 | static PSC tunnelPeerSelectComplete; | |
fa34dd97 | 127 | static void tunnelStateFree(TunnelStateData * tunnelState); |
11007d4b | 128 | static void tunnelConnected(int fd, void *); |
129 | static void tunnelProxyConnected(int fd, void *); | |
30a4f2a8 | 130 | |
b8d8561b | 131 | static void |
11007d4b | 132 | tunnelServerClosed(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 | 150 | static void |
11007d4b | 151 | tunnelClientClosed(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 | 169 | static void |
fa34dd97 | 170 | tunnelStateFree(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 | 182 | TunnelStateData::Connection::~Connection() |
a46d2c0e | 183 | { |
184 | safe_free (buf); | |
185 | } | |
186 | ||
187 | int | |
fa34dd97 | 188 | TunnelStateData::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 | 198 | void |
fa34dd97 | 199 | TunnelStateData::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 | 208 | int |
fa34dd97 | 209 | TunnelStateData::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 | 225 | void |
fa34dd97 | 226 | TunnelStateData::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 | 235 | void |
fa34dd97 | 236 | TunnelStateData::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 | ||
257 | void | |
fa34dd97 | 258 | TunnelStateData::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 | 271 | void |
fa34dd97 | 272 | TunnelStateData::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 | 281 | void |
fa34dd97 | 282 | TunnelStateData::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 | 302 | void |
fa34dd97 | 303 | TunnelStateData::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 | 330 | void |
fa34dd97 | 331 | TunnelStateData::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 | 340 | void |
fa34dd97 | 341 | TunnelStateData::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 | 380 | void |
fa34dd97 | 381 | TunnelStateData::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 | ||
390 | void | |
fa34dd97 | 391 | TunnelStateData::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 | ||
401 | void | |
fa34dd97 | 402 | TunnelStateData::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 | 439 | static void |
11007d4b | 440 | tunnelTimeout(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 | 452 | void |
fa34dd97 | 453 | TunnelStateData::Connection::closeIfOpen() |
a46d2c0e | 454 | { |
11a6896c | 455 | if (!fd_closed(fd())) |
a46d2c0e | 456 | comm_close(fd()); |
457 | } | |
458 | ||
459 | void | |
fa34dd97 | 460 | TunnelStateData::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 | 466 | static void |
11007d4b | 467 | tunnelConnectTimeout(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 | 502 | static void |
11007d4b | 503 | tunnelConnectedWriteDone(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 | */ | |
521 | static void | |
11007d4b | 522 | tunnelProxyConnectedWriteDone(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 | 527 | static void |
11007d4b | 528 | tunnelConnected(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 | 537 | static void |
11007d4b | 538 | tunnelErrorComplete(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 | 555 | static void |
3ff65596 | 556 | tunnelConnectDone(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 | 604 | void |
47f6e231 | 605 | tunnelStart(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. */ |
b7ac5457 | 643 | Ip::Address 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 | 701 | static void |
11007d4b | 702 | tunnelProxyConnected(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(); |
3872be7c | 713 | mb.Printf("CONNECT %s HTTP/1.1\r\n", tunnelState->url); |
11007d4b | 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 | 729 | static void |
11007d4b | 730 | tunnelPeerSelectComplete(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 | 782 | CBDATA_CLASS_INIT(TunnelStateData); |
a46d2c0e | 783 | |
784 | void * | |
fa34dd97 | 785 | TunnelStateData::operator new (size_t) |
a46d2c0e | 786 | { |
fa34dd97 | 787 | CBDATA_INIT_TYPE(TunnelStateData); |
788 | TunnelStateData *result = cbdataAlloc(TunnelStateData); | |
a46d2c0e | 789 | return result; |
790 | } | |
791 | ||
792 | void | |
fa34dd97 | 793 | TunnelStateData::operator delete (void *address) |
a46d2c0e | 794 | { |
fa34dd97 | 795 | TunnelStateData *t = static_cast<TunnelStateData *>(address); |
a46d2c0e | 796 | cbdataFree(t); |
797 | } | |
798 | ||
a46d2c0e | 799 | void |
fa34dd97 | 800 | TunnelStateData::Connection::fd(int const newFD) |
a46d2c0e | 801 | { |
802 | fd_ = newFD; | |
803 | } | |
804 | ||
805 | bool | |
fa34dd97 | 806 | TunnelStateData::noConnections() const |
a46d2c0e | 807 | { |
11a6896c | 808 | return fd_closed(server.fd()) && fd_closed(client.fd()); |
a46d2c0e | 809 | } |
810 | ||
811 | #if DELAY_POOLS | |
812 | void | |
fa34dd97 | 813 | TunnelStateData::Connection::setDelayId(DelayId const &newDelay) |
a46d2c0e | 814 | { |
815 | delayId = newDelay; | |
816 | } | |
817 | ||
818 | #endif |