Line
Link Here
|
0 |
-- a/modules/proxy/mod_proxy_connect.c |
0 |
++ b/modules/proxy/mod_proxy_connect.c |
Lines 21-26
Link Here
|
21 |
#include "mod_proxy.h" |
21 |
#include "mod_proxy.h" |
22 |
#include "apr_poll.h" |
22 |
#include "apr_poll.h" |
23 |
|
23 |
|
|
|
24 |
#define CONN_BLKSZ AP_IOBUFSIZE |
25 |
|
24 |
module AP_MODULE_DECLARE_DATA proxy_connect_module; |
26 |
module AP_MODULE_DECLARE_DATA proxy_connect_module; |
25 |
|
27 |
|
26 |
/* |
28 |
/* |
Lines 71-76
Link Here
|
71 |
return OK; |
73 |
return OK; |
72 |
} |
74 |
} |
73 |
|
75 |
|
|
|
76 |
/* read available data (in blocks of CONN_BLKSZ) from c_i and copy to c_o */ |
77 |
static int proxy_connect_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o, |
78 |
apr_bucket_brigade *bb, char *name) |
79 |
{ |
80 |
int rv; |
81 |
#ifdef DEBUGGING |
82 |
apr_off_t len; |
83 |
#endif |
84 |
|
85 |
do { |
86 |
apr_brigade_cleanup(bb); |
87 |
rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES, |
88 |
APR_NONBLOCK_READ, CONN_BLKSZ); |
89 |
if (rv == APR_SUCCESS) { |
90 |
if (APR_BRIGADE_EMPTY(bb)) |
91 |
break; |
92 |
#ifdef DEBUGGING |
93 |
len = -1; |
94 |
apr_brigade_length(bb, 0, &len); |
95 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
96 |
"proxy: CONNECT: read %" APR_OFF_T_FMT |
97 |
" bytes from %s", len, name); |
98 |
#endif |
99 |
rv = ap_pass_brigade(c_o->output_filters, bb); |
100 |
if (rv == APR_SUCCESS) { |
101 |
ap_fflush(c_o->output_filters, bb); |
102 |
} else { |
103 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
104 |
"proxy: CONNECT: error on %s - ap_pass_brigade", |
105 |
name); |
106 |
} |
107 |
} else if (!APR_STATUS_IS_EAGAIN(rv)) { |
108 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, |
109 |
"proxy: CONNECT: error on %s - ap_get_brigade", |
110 |
name); |
111 |
} |
112 |
} while (rv == APR_SUCCESS); |
113 |
|
114 |
if (APR_STATUS_IS_EAGAIN(rv)) { |
115 |
rv = APR_SUCCESS; |
116 |
} |
117 |
return rv; |
118 |
} |
119 |
|
74 |
/* CONNECT handler */ |
120 |
/* CONNECT handler */ |
75 |
static int proxy_connect_handler(request_rec *r, proxy_worker *worker, |
121 |
static int proxy_connect_handler(request_rec *r, proxy_worker *worker, |
76 |
proxy_server_conf *conf, |
122 |
proxy_server_conf *conf, |
Lines 79-89
Link Here
|
79 |
{ |
125 |
{ |
80 |
apr_pool_t *p = r->pool; |
126 |
apr_pool_t *p = r->pool; |
81 |
apr_socket_t *sock; |
127 |
apr_socket_t *sock; |
|
|
128 |
conn_rec *c = r->connection; |
129 |
conn_rec *backconn; |
130 |
|
131 |
apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); |
82 |
apr_status_t err, rv; |
132 |
apr_status_t err, rv; |
83 |
apr_size_t i, o, nbytes; |
133 |
apr_size_t i, o, nbytes; |
84 |
char buffer[HUGE_STRING_LEN]; |
134 |
char buffer[HUGE_STRING_LEN]; |
85 |
apr_socket_t *client_socket = ap_get_module_config(r->connection->conn_config, &core_module); |
135 |
apr_socket_t *client_socket = ap_get_module_config(c->conn_config, &core_module); |
86 |
int failed; |
136 |
int failed, rc; |
87 |
apr_pollset_t *pollset; |
137 |
apr_pollset_t *pollset; |
88 |
apr_pollfd_t pollfd; |
138 |
apr_pollfd_t pollfd; |
89 |
const apr_pollfd_t *signalled; |
139 |
const apr_pollfd_t *signalled; |
Lines 158-169
Link Here
|
158 |
case APR_URI_SNEWS_DEFAULT_PORT: |
208 |
case APR_URI_SNEWS_DEFAULT_PORT: |
159 |
break; |
209 |
break; |
160 |
default: |
210 |
default: |
161 |
/* XXX can we call ap_proxyerror() here to get a nice log message? */ |
211 |
return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); |
162 |
return HTTP_FORBIDDEN; |
|
|
163 |
} |
212 |
} |
164 |
} else if(!allowed_port(conf, uri.port)) { |
213 |
} else if(!allowed_port(conf, uri.port)) { |
165 |
/* XXX can we call ap_proxyerror() here to get a nice log message? */ |
214 |
return ap_proxyerror(r, HTTP_FORBIDDEN, "Connect to remote machine blocked"); |
166 |
return HTTP_FORBIDDEN; |
|
|
167 |
} |
215 |
} |
168 |
|
216 |
|
169 |
/* |
217 |
/* |
Lines 205-222
Link Here
|
205 |
} |
253 |
} |
206 |
} |
254 |
} |
207 |
|
255 |
|
|
|
256 |
/* setup polling for connection */ |
257 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
258 |
"proxy: CONNECT: setting up poll()"); |
259 |
|
260 |
if ((rv = apr_pollset_create(&pollset, 2, r->pool, 0)) != APR_SUCCESS) { |
261 |
apr_socket_close(sock); |
262 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
263 |
"proxy: CONNECT: error apr_pollset_create()"); |
264 |
return HTTP_INTERNAL_SERVER_ERROR; |
265 |
} |
266 |
|
267 |
/* Add client side to the poll */ |
268 |
pollfd.p = r->pool; |
269 |
pollfd.desc_type = APR_POLL_SOCKET; |
270 |
pollfd.reqevents = APR_POLLIN; |
271 |
pollfd.desc.s = client_socket; |
272 |
pollfd.client_data = NULL; |
273 |
apr_pollset_add(pollset, &pollfd); |
274 |
|
275 |
/* Add the server side to the poll */ |
276 |
pollfd.desc.s = sock; |
277 |
apr_pollset_add(pollset, &pollfd); |
278 |
|
208 |
/* |
279 |
/* |
209 |
* Step Three: Send the Request |
280 |
* Step Three: Send the Request |
210 |
* |
281 |
* |
211 |
* Send the HTTP/1.1 CONNECT request to the remote server |
282 |
* Send the HTTP/1.1 CONNECT request to the remote server |
212 |
*/ |
283 |
*/ |
213 |
|
284 |
|
214 |
/* we are acting as a tunnel - the output filter stack should |
285 |
backconn = ap_run_create_connection(c->pool, r->server, sock, |
215 |
* be completely empty, because when we are done here we are done completely. |
286 |
c->id, c->sbh, c->bucket_alloc); |
216 |
* We add the NULL filter to the stack to do this... |
287 |
if (!backconn) { |
217 |
*/ |
288 |
/* peer reset */ |
218 |
r->output_filters = NULL; |
289 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, |
219 |
r->connection->output_filters = NULL; |
290 |
"proxy: an error occurred creating a new connection " |
|
|
291 |
"to %pI (%s)", connect_addr, connectname); |
292 |
apr_socket_close(sock); |
293 |
return HTTP_INTERNAL_SERVER_ERROR; |
294 |
} |
295 |
ap_proxy_ssl_disable(backconn); |
296 |
rc = ap_run_pre_connection(backconn, sock); |
297 |
if (rc != OK && rc != DONE) { |
298 |
backconn->aborted = 1; |
299 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
300 |
"proxy: CONNECT: pre_connection setup failed (%d)", rc); |
301 |
return HTTP_INTERNAL_SERVER_ERROR; |
302 |
} |
303 |
|
304 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
305 |
"proxy: CONNECT: connection complete to %pI (%s)", |
306 |
connect_addr, connectname); |
220 |
|
307 |
|
221 |
|
308 |
|
222 |
/* If we are connecting through a remote proxy, we need to pass |
309 |
/* If we are connecting through a remote proxy, we need to pass |
Lines 227-238
Link Here
|
227 |
*/ |
314 |
*/ |
228 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
315 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
229 |
"proxy: CONNECT: sending the CONNECT request to the remote proxy"); |
316 |
"proxy: CONNECT: sending the CONNECT request to the remote proxy"); |
230 |
nbytes = apr_snprintf(buffer, sizeof(buffer), |
317 |
ap_fprintf(backconn->output_filters, bb, |
231 |
"CONNECT %s HTTP/1.0" CRLF, r->uri); |
318 |
"CONNECT %s HTTP/1.0" CRLF, r->uri); |
232 |
apr_socket_send(sock, buffer, &nbytes); |
319 |
ap_fprintf(backconn->output_filters, bb, |
233 |
nbytes = apr_snprintf(buffer, sizeof(buffer), |
320 |
"Proxy-agent: %s" CRLF CRLF, ap_get_server_version()); |
234 |
"Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); |
321 |
ap_fflush(backconn->output_filters, bb); |
235 |
apr_socket_send(sock, buffer, &nbytes); |
|
|
236 |
} |
322 |
} |
237 |
else { |
323 |
else { |
238 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
324 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
Lines 240-250
Link Here
|
240 |
nbytes = apr_snprintf(buffer, sizeof(buffer), |
326 |
nbytes = apr_snprintf(buffer, sizeof(buffer), |
241 |
"HTTP/1.0 200 Connection Established" CRLF); |
327 |
"HTTP/1.0 200 Connection Established" CRLF); |
242 |
ap_xlate_proto_to_ascii(buffer, nbytes); |
328 |
ap_xlate_proto_to_ascii(buffer, nbytes); |
243 |
apr_socket_send(client_socket, buffer, &nbytes); |
329 |
ap_fwrite(c->output_filters, bb, buffer, nbytes); |
244 |
nbytes = apr_snprintf(buffer, sizeof(buffer), |
330 |
nbytes = apr_snprintf(buffer, sizeof(buffer), |
245 |
"Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); |
331 |
"Proxy-agent: %s" CRLF CRLF, ap_get_server_banner()); |
246 |
ap_xlate_proto_to_ascii(buffer, nbytes); |
332 |
ap_xlate_proto_to_ascii(buffer, nbytes); |
247 |
apr_socket_send(client_socket, buffer, &nbytes); |
333 |
ap_fwrite(c->output_filters, bb, buffer, nbytes); |
|
|
334 |
ap_fflush(c->output_filters, bb); |
248 |
#if 0 |
335 |
#if 0 |
249 |
/* This is safer code, but it doesn't work yet. I'm leaving it |
336 |
/* This is safer code, but it doesn't work yet. I'm leaving it |
250 |
* here so that I can fix it later. |
337 |
* here so that I can fix it later. |
Lines 265-291
Link Here
|
265 |
* Handle two way transfer of data over the socket (this is a tunnel). |
352 |
* Handle two way transfer of data over the socket (this is a tunnel). |
266 |
*/ |
353 |
*/ |
267 |
|
354 |
|
|
|
355 |
/* we are now acting as a tunnel - the input/output filter stacks should |
356 |
* not contain any non-connection filters. |
357 |
*/ |
358 |
r->output_filters = c->output_filters; |
359 |
r->proto_output_filters = c->output_filters; |
360 |
r->input_filters = c->input_filters; |
361 |
r->proto_input_filters = c->input_filters; |
268 |
/* r->sent_bodyct = 1;*/ |
362 |
/* r->sent_bodyct = 1;*/ |
269 |
|
363 |
|
270 |
if ((rv = apr_pollset_create(&pollset, 2, r->pool, 0)) != APR_SUCCESS) { |
|
|
271 |
apr_socket_close(sock); |
272 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, |
273 |
"proxy: CONNECT: error apr_pollset_create()"); |
274 |
return HTTP_INTERNAL_SERVER_ERROR; |
275 |
} |
276 |
|
277 |
/* Add client side to the poll */ |
278 |
pollfd.p = r->pool; |
279 |
pollfd.desc_type = APR_POLL_SOCKET; |
280 |
pollfd.reqevents = APR_POLLIN; |
281 |
pollfd.desc.s = client_socket; |
282 |
pollfd.client_data = NULL; |
283 |
apr_pollset_add(pollset, &pollfd); |
284 |
|
285 |
/* Add the server side to the poll */ |
286 |
pollfd.desc.s = sock; |
287 |
apr_pollset_add(pollset, &pollfd); |
288 |
|
289 |
while (1) { /* Infinite loop until error (one side closes the connection) */ |
364 |
while (1) { /* Infinite loop until error (one side closes the connection) */ |
290 |
if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) { |
365 |
if ((rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled)) != APR_SUCCESS) { |
291 |
if (APR_STATUS_IS_EINTR(rv)) { |
366 |
if (APR_STATUS_IS_EINTR(rv)) { |
Lines 297-303
Link Here
|
297 |
} |
372 |
} |
298 |
#ifdef DEBUGGING |
373 |
#ifdef DEBUGGING |
299 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
374 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
300 |
"proxy: CONNECT: woke from select(), i=%d", pollcnt); |
375 |
"proxy: CONNECT: woke from poll(), i=%d", pollcnt); |
301 |
#endif |
376 |
#endif |
302 |
|
377 |
|
303 |
for (pi = 0; pi < pollcnt; pi++) { |
378 |
for (pi = 0; pi < pollcnt; pi++) { |
Lines 307-378
Link Here
|
307 |
pollevent = cur->rtnevents; |
382 |
pollevent = cur->rtnevents; |
308 |
if (pollevent & APR_POLLIN) { |
383 |
if (pollevent & APR_POLLIN) { |
309 |
#ifdef DEBUGGING |
384 |
#ifdef DEBUGGING |
310 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
385 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
311 |
"proxy: CONNECT: sock was set"); |
386 |
"proxy: CONNECT: sock was readable"); |
312 |
#endif |
387 |
#endif |
313 |
nbytes = sizeof(buffer); |
388 |
rv = proxy_connect_transfer(r, backconn, c, bb, "sock"); |
314 |
rv = apr_socket_recv(sock, buffer, &nbytes); |
|
|
315 |
if (rv == APR_SUCCESS) { |
316 |
o = 0; |
317 |
i = nbytes; |
318 |
while(i > 0) |
319 |
{ |
320 |
nbytes = i; |
321 |
/* This is just plain wrong. No module should ever write directly |
322 |
* to the client. For now, this works, but this is high on my list of |
323 |
* things to fix. The correct line is: |
324 |
* if ((nbytes = ap_rwrite(buffer + o, nbytes, r)) < 0) |
325 |
* rbb |
326 |
*/ |
327 |
rv = apr_socket_send(client_socket, buffer + o, &nbytes); |
328 |
if (rv != APR_SUCCESS) |
329 |
break; |
330 |
o += nbytes; |
331 |
i -= nbytes; |
332 |
} |
333 |
} |
389 |
} |
334 |
else |
390 |
else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) { |
335 |
break; |
391 |
rv = APR_EPIPE; |
|
|
392 |
ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "proxy: CONNECT: err/hup on backconn"); |
336 |
} |
393 |
} |
337 |
else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) |
|
|
338 |
break; |
339 |
} |
394 |
} |
340 |
else if (cur->desc.s == client_socket) { |
395 |
else if (cur->desc.s == client_socket) { |
341 |
pollevent = cur->rtnevents; |
396 |
pollevent = cur->rtnevents; |
342 |
if (pollevent & APR_POLLIN) { |
397 |
if (pollevent & APR_POLLIN) { |
343 |
#ifdef DEBUGGING |
398 |
#ifdef DEBUGGING |
344 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
399 |
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, |
345 |
"proxy: CONNECT: client was set"); |
400 |
"proxy: CONNECT: client was readable"); |
346 |
#endif |
|
|
347 |
nbytes = sizeof(buffer); |
348 |
rv = apr_socket_recv(client_socket, buffer, &nbytes); |
349 |
if (rv == APR_SUCCESS) { |
350 |
o = 0; |
351 |
i = nbytes; |
352 |
#ifdef DEBUGGING |
353 |
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, |
354 |
"proxy: CONNECT: read %d from client", i); |
355 |
#endif |
401 |
#endif |
356 |
while(i > 0) |
402 |
rv = proxy_connect_transfer(r, c, backconn, bb, "client"); |
357 |
{ |
|
|
358 |
nbytes = i; |
359 |
rv = apr_socket_send(sock, buffer + o, &nbytes); |
360 |
if (rv != APR_SUCCESS) |
361 |
break; |
362 |
o += nbytes; |
363 |
i -= nbytes; |
364 |
} |
365 |
} |
366 |
else |
367 |
break; |
368 |
} |
403 |
} |
369 |
else if ((pollevent & APR_POLLERR) || (pollevent & APR_POLLHUP)) { |
|
|
370 |
rv = APR_EOF; |
371 |
break; |
372 |
} |
404 |
} |
|
|
405 |
else { |
406 |
rv = APR_EBADF; |
407 |
ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, |
408 |
"proxy: CONNECT: unknown socket in pollset"); |
373 |
} |
409 |
} |
374 |
else |
410 |
|
375 |
break; |
|
|
376 |
} |
411 |
} |
377 |
if (rv != APR_SUCCESS) { |
412 |
if (rv != APR_SUCCESS) { |
378 |
break; |
413 |
break; |
Lines 388-394
Link Here
|
388 |
* Close the socket and clean up |
423 |
* Close the socket and clean up |
389 |
*/ |
424 |
*/ |
390 |
|
425 |
|
391 |
apr_socket_close(sock); |
426 |
ap_lingering_close(backconn); |
|
|
427 |
|
428 |
c->aborted = 1; |
392 |
|
429 |
|
393 |
return OK; |
430 |
return OK; |
394 |
} |
431 |
} |