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