Apache HTTPD
mod_proxy_connect.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* CONNECT method for Apache proxy */
18
19#include "mod_proxy.h"
20#include "apr_poll.h"
21
22#define CONN_BLKSZ AP_IOBUFSIZE
23
24module AP_MODULE_DECLARE_DATA proxy_connect_module;
25
26/*
27 * This handles Netscape CONNECT method secure proxy requests.
28 * A connection is opened to the specified host and data is
29 * passed through between the WWW site and the browser.
30 *
31 * This code is based on the INTERNET-DRAFT document
32 * "Tunneling SSL Through a WWW Proxy" currently at
33 * http://www.mcom.com/newsref/std/tunneling_ssl.html.
34 *
35 * If proxyhost and proxyport are set, we send a CONNECT to
36 * the specified proxy..
37 *
38 * FIXME: this doesn't log the number of bytes sent, but
39 * that may be okay, since the data is supposed to
40 * be transparent. In fact, this doesn't log at all
41 * yet. 8^)
42 * FIXME: doesn't check any headers initially sent from the
43 * client.
44 * FIXME: should allow authentication, but hopefully the
45 * generic proxy authentication is good enough.
46 * FIXME: no check for r->assbackwards, whatever that is.
47 */
48
52
53typedef struct {
54 int first;
55 int last;
57
59{
61 c->allowed_connect_ports = apr_array_make(p, 10, sizeof(port_range));
62 return c;
63}
64
65static void *merge_config(apr_pool_t *p, void *basev, void *overridesv)
66{
70
71 c->allowed_connect_ports = apr_array_append(p,
72 base->allowed_connect_ports,
73 overrides->allowed_connect_ports);
74
75 return c;
76}
77
78
79/*
80 * Set the ports CONNECT can use
81 */
82static const char *
84{
85 server_rec *s = parms->server;
86 int first, last;
87 connect_conf *conf =
88 ap_get_module_config(s->module_config, &proxy_connect_module);
90 char *endptr;
91 const char *p = arg;
92
93 if (!apr_isdigit(arg[0]))
94 return "AllowCONNECT: port numbers must be numeric";
95
96 first = strtol(p, &endptr, 10);
97 if (*endptr == '-') {
98 p = endptr + 1;
99 last = strtol(p, &endptr, 10);
100 }
101 else {
102 last = first;
103 }
104
105 if (endptr == p || *endptr != '\0') {
106 return apr_psprintf(parms->temp_pool,
107 "Cannot parse '%s' as port number", p);
108 }
109
111 New->first = first;
112 New->last = last;
113 return NULL;
114}
115
116
117static int allowed_port(connect_conf *conf, int port)
118{
119 int i;
121
125 }
126
127 for (i = 0; i < conf->allowed_connect_ports->nelts; i++) {
128 if (port >= list[i].first && port <= list[i].last)
129 return 1;
130 }
131 return 0;
132}
133
134/* canonicalise CONNECT URLs. */
136{
137
138 if (r->method_number != M_CONNECT) {
139 return DECLINED;
140 }
141 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "canonicalising URL %s", url);
142
143 return OK;
144}
145
146/* CONNECT handler */
148 proxy_server_conf *conf,
149 char *url, const char *proxyname,
151{
153 ap_get_module_config(r->server->module_config, &proxy_connect_module);
154
155 apr_pool_t *p = r->pool;
159
160 apr_status_t rv;
163
166 int failed, rc;
167
169 const char *connectname;
172
174
175 /* is this for us? */
176 if (r->method_number != M_CONNECT) {
177 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "declining URL %s", url);
178 return DECLINED;
179 }
180 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "serving URL %s", url);
181
182
183 /*
184 * Step One: Determine Who To Connect To
185 *
186 * Break up the URL to determine the host to connect to
187 */
188
189 /* we break the URL into host, port, uri */
192 apr_pstrcat(p, "URI cannot be parsed: ", url,
193 NULL));
194 }
195
197 "connecting %s to %s:%d", url, uri.hostname, uri.port);
198
199 /* Determine host/port of next hop; from request URI or of a proxy. */
200 connectname = proxyname ? proxyname : uri.hostname;
202
203 /* Do a DNS lookup for the next hop */
205 connectport, 0, p);
206 if (rv != APR_SUCCESS) {
208 "failed to resolve hostname '%s'", connectname);
210 apr_pstrcat(p, "DNS lookup failure for: ",
211 connectname, NULL));
212 }
213
214 /* Check ProxyBlock directive on the hostname/address. */
215 if (ap_proxy_checkproxyblock2(r, conf, uri.hostname,
216 proxyname ? NULL : nexthop) != OK) {
218 "Connect to remote machine blocked");
219 }
220
222 "connecting to remote proxy %s on port %d",
224
225 /* Check if it is an allowed port */
226 if (!allowed_port(c_conf, uri.port)) {
228 "Connect to remote machine blocked");
229 }
230
231 /*
232 * Step Two: Make the Connection
233 *
234 * We have determined who to connect to. Now make the connection.
235 */
236
237 /*
238 * At this point we have a list of one or more IP addresses of
239 * the machine to connect to. If configured, reorder this
240 * list so that the "best candidate" is first try. "best
241 * candidate" could mean the least loaded server, the fastest
242 * responding server, whatever.
243 *
244 * For now we do nothing, ie we get DNS round robin.
245 * XXX FIXME
246 */
247 failed = ap_proxy_connect_to_backend(&sock, "CONNECT", nexthop,
248 connectname, conf, r);
249
250 /* handle a permanent error from the above loop */
251 if (failed) {
252 if (proxyname) {
253 return DECLINED;
254 }
255 else {
257 }
258 }
259
260 /*
261 * Step Three: Send the Request
262 *
263 * Send the HTTP/1.1 CONNECT request to the remote server
264 */
265
267 c->id, c->sbh, c->bucket_alloc);
268 if (!backconn) {
269 /* peer reset */
271 "an error occurred creating a new connection "
272 "to %pI (%s)", nexthop, connectname);
275 }
277
278 /*
279 * save the timeout of the socket because core_pre_connection
280 * will set it to base_server->timeout
281 * (core TimeOut directive).
282 */
285 if (rc != OK && rc != DONE) {
286 backconn->aborted = 1;
288 "pre_connection setup failed (%d)", rc);
291 }
293
295 "connection complete to %pI (%s)",
297 apr_table_setn(r->notes, "proxy-source-port", apr_psprintf(r->pool, "%hu",
298 backconn->local_addr->port));
299
300 bb = apr_brigade_create(p, c->bucket_alloc);
301
302 /* If we are connecting through a remote proxy, we need to pass
303 * the CONNECT request on to it.
304 */
305 if (proxyport) {
306 /* FIXME: Error checking ignored.
307 */
309 "sending the CONNECT request to the remote proxy");
310 ap_fprintf(backconn->output_filters, bb,
311 "CONNECT %s HTTP/1.0" CRLF, r->uri);
312 ap_fprintf(backconn->output_filters, bb,
313 "Proxy-agent: %s" CRLF CRLF, ap_get_server_banner());
314 ap_fflush(backconn->output_filters, bb);
315 }
316 else {
317 ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "Returning 200 OK");
318 nbytes = apr_snprintf(buffer, sizeof(buffer),
319 "HTTP/1.0 200 Connection Established" CRLF);
321 ap_fwrite(c->output_filters, bb, buffer, nbytes);
322 nbytes = apr_snprintf(buffer, sizeof(buffer),
323 "Proxy-agent: %s" CRLF CRLF,
326 ap_fwrite(c->output_filters, bb, buffer, nbytes);
327 ap_fflush(c->output_filters, bb);
328#if 0
329 /* This is safer code, but it doesn't work yet. I'm leaving it
330 * here so that I can fix it later.
331 */
332 r->status = HTTP_OK;
333 r->header_only = 1;
334 apr_table_set(r->headers_out, "Proxy-agent: %s", ap_get_server_banner());
335 ap_rflush(r);
336#endif
337 }
339
340 /*
341 * Step Four: Handle Data Transfer
342 *
343 * Handle two way transfer of data over the socket (this is a tunnel).
344 */
345
346 /* r->sent_bodyct = 1; */
347
348 rv = ap_proxy_tunnel_create(&tunnel, r, backconn, "CONNECT");
349 if (rv != APR_SUCCESS) {
351 "can't create tunnel for %pI (%s)",
354 }
355
357 if (ap_is_HTTP_ERROR(rc)) {
358 if (rc == HTTP_GATEWAY_TIME_OUT) {
359 /* ap_proxy_tunnel_run() didn't log this */
361 "tunnel timed out");
362 }
363 /* Don't send an error page if we sent data already */
364 if (proxyport && !tunnel->replied) {
365 return rc;
366 }
367 }
368
369 /*
370 * Step Five: Clean Up
371 *
372 * Close the socket and clean up
373 */
374
375 if (backconn->aborted)
377 else
379
380 return OK;
381}
382
388
389static const command_rec cmds[] =
390{
392 "A list of ports or port ranges which CONNECT may connect to"),
393 {NULL}
394};
395
398 NULL, /* create per-directory config structure */
399 NULL, /* merge per-directory config structures */
400 create_config, /* create per-server config structure */
401 merge_config, /* merge per-server config structures */
402 cmds, /* command apr_table_t */
403 ap_proxy_connect_register_hook /* register hooks */
404};
APR Poll interface.
apr_array_append(apr_pool_t *p, const apr_array_header_t *first, const apr_array_header_t *second)
Definition apr_tables.c:213
int ap_run_pre_connection(conn_rec *c, void *csd)
Definition connection.c:43
void ap_lingering_close(conn_rec *c)
Definition connection.c:149
conn_rec * ap_run_create_connection(apr_pool_t *p, server_rec *server, apr_socket_t *csd, long conn_id, void *sbh, apr_bucket_alloc_t *alloc)
Definition connection.c:41
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
ap_conf_vector_t * base
#define AP_INIT_ITERATE(directive, func, mconfig, where, help)
request_rec * r
#define HUGE_STRING_LEN
Definition httpd.h:303
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define DONE
Definition httpd.h:458
const char * ap_get_server_banner(void)
Definition core.c:3593
#define ap_xlate_proto_to_ascii(x, y)
Definition util_ebcdic.h:80
#define ap_fwrite(f, bb, data, nbyte)
apr_status_t ap_fflush(ap_filter_t *f, apr_bucket_brigade *bb)
apr_status_t ap_fprintf(ap_filter_t *f, apr_bucket_brigade *bb, const char *fmt,...) __attribute__((format(printf
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_INFO
Definition http_log.h:70
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_TRACE3
Definition http_log.h:74
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_TRACE2
Definition http_log.h:73
#define APLOG_TRACE1
Definition http_log.h:72
#define APLOG_DEBUG
Definition http_log.h:71
int int ap_rflush(request_rec *r)
Definition protocol.c:2253
const char apr_port_t port
Definition http_vhost.h:125
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
#define CRLF
Definition httpd.h:724
const char * url
Definition apr_escape.h:120
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_redis_t * rc
Definition apr_redis.h:173
#define APR_URI_SNEWS_DEFAULT_PORT
Definition apr_uri.h:56
const char * uri
Definition apr_uri.h:159
#define APR_URI_HTTPS_DEFAULT_PORT
Definition apr_uri.h:54
#define RSRC_CONF
#define HTTP_OK
Definition httpd.h:490
#define HTTP_BAD_REQUEST
Definition httpd.h:508
#define HTTP_SERVICE_UNAVAILABLE
Definition httpd.h:538
#define HTTP_BAD_GATEWAY
Definition httpd.h:537
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define ap_is_HTTP_ERROR(x)
Definition httpd.h:554
#define HTTP_FORBIDDEN
Definition httpd.h:511
#define HTTP_GATEWAY_TIME_OUT
Definition httpd.h:539
int ap_proxy_ssl_engine(conn_rec *c, ap_conf_vector_t *per_dir_config, int enable)
Definition mod_proxy.c:3061
int ap_proxy_tunnel_run(proxy_tunnel_rec *tunnel)
apr_status_t ap_proxy_tunnel_create(proxy_tunnel_rec **tunnel, request_rec *r, conn_rec *c_o, const char *scheme)
int ap_proxy_checkproxyblock2(request_rec *r, proxy_server_conf *conf, const char *hostname, apr_sockaddr_t *addr)
Definition proxy_util.c:824
int ap_proxy_connect_to_backend(apr_socket_t **, const char *, apr_sockaddr_t *, const char *, proxy_server_conf *, request_rec *)
void proxy_hook_canon_handler(proxy_HOOK_canon_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3412
int ap_proxyerror(request_rec *r, int statuscode, const char *message)
Definition proxy_util.c:432
void proxy_hook_scheme_handler(proxy_HOOK_scheme_handler_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_proxy.c:3406
#define M_CONNECT
Definition httpd.h:596
#define STANDARD20_MODULE_STUFF
apr_size_t size
const apr_array_header_t * list
Definition apr_cstr.h:105
#define apr_isdigit(c)
Definition apr_lib.h:209
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void apr_size_t * nbytes
char * buffer
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_socket_t * sock
apr_uint16_t apr_port_t
#define APR_UNSPEC
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** last
const char * s
Definition apr_strings.h:95
const apr_array_header_t * first
Definition apr_tables.h:207
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_pool_t * p
Definition md_event.c:32
Proxy Extension Module for Apache.
static int proxy_connect_handler(request_rec *r, proxy_worker *worker, proxy_server_conf *conf, char *url, const char *proxyname, apr_port_t proxyport)
static int allowed_port(connect_conf *conf, int port)
static const char * set_allowed_ports(cmd_parms *parms, void *dummy, const char *arg)
static void * merge_config(apr_pool_t *p, void *basev, void *overridesv)
static void * create_config(apr_pool_t *p, server_rec *s)
static const command_rec cmds[]
static void ap_proxy_connect_register_hook(apr_pool_t *p)
static int proxy_connect_canon(request_rec *r, char *url)
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
Structure to store things which are per connection.
Definition httpd.h:1152
apr_array_header_t * allowed_connect_ports
A structure that represents the current request.
Definition httpd.h:845
int status
Definition httpd.h:891
char * uri
Definition httpd.h:1016
int header_only
Definition httpd.h:875
apr_table_t * notes
Definition httpd.h:985
const char * hostname
Definition httpd.h:883
int method_number
Definition httpd.h:898
apr_pool_t * pool
Definition httpd.h:847
conn_rec * connection
Definition httpd.h:849
server_rec * server
Definition httpd.h:851
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
struct ap_conf_vector_t * module_config
Definition httpd.h:1341
apr_status_t apr_socket_close(apr_socket_t *thesocket)
Definition sockets.c:211
apr_status_t apr_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
Definition sockopt.c:75
apr_status_t apr_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
Definition sockopt.c:355