On Tue, 30 Jan 2007, Bogdan Ribic wrote:

Hi all,

I have a question - would it be possible to intercept an incomming request, figure out if it is a proxy CONNECT request for remote https server and then redirect to a local SSL site.

Specifically, can this be accomplished through a connection level filter, for example by pulling enough data from user request to figure out if it was a CONNECT request to an https url and if it is pull the request header, then make a sub-request to local https site.

Yes, it's possible, but probably not the best approach. I needed something similar, and I did it by replacing proxy_connect.c with a customized version that can redirect CONNECT requests to other hosts. I'm guessing that's the best approach to do what you need.

Attached is a diff against 2.0.54 of my new module. Should apply cleanly to any recent 2.0.x, and with a little work to 2.2.x as well.

It introduces a new server configuration directive "ConnectRedirect":

ConnectRedirect <hostname> <hostname> <port>

For example, "ConnectRedirect www.example.com localhost 4443" will redirect CONNECT requests for www.example.com to localhost, on port 4443.
Using * for the first hostname implements a wildcard redirect.


Hope this is useful.


Ernst Jan
--- httpd-2.0.54/modules/proxy/proxy_connect.c  2005-02-04 21:21:18.000000000 
+0100
+++ proxy/proxy_connect.c       2005-09-10 17:07:05.000000000 +0200
@@ -23,6 +23,16 @@
 
 module AP_MODULE_DECLARE_DATA proxy_connect_module;
 
+struct redirect_entry {
+    char *orighostname;
+    char *hostname;
+    int port;
+};
+
+typedef struct {
+    apr_array_header_t *redirects;
+} proxy_connect_server_conf;
+
 int ap_proxy_connect_canon(request_rec *r, char *url);
 int ap_proxy_connect_handler(request_rec *r, proxy_server_conf *conf, 
                              char *url, const char *proxyname, 
@@ -98,6 +108,10 @@
     const char *connectname;
     int connectport = 0;
 
+    server_rec *s = r->server;
+    proxy_connect_server_conf *cconf =
+    (proxy_connect_server_conf *) ap_get_module_config(s->module_config, 
&proxy_connect_module);
+
     /* is this for us? */
     if (r->method_number != M_CONNECT) {
         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
@@ -116,13 +130,35 @@
 
     /* we break the URL into host, port, uri */
     if (APR_SUCCESS != apr_uri_parse_hostinfo(p, url, &uri)) {
-       return ap_proxyerror(r, HTTP_BAD_REQUEST,
+        return ap_proxyerror(r, HTTP_BAD_REQUEST,
                             apr_pstrcat(p, "URI cannot be parsed: ", url, 
NULL));
     }
 
     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
                 "proxy: CONNECT: connecting %s to %s:%d", url, uri.hostname, 
uri.port);
 
+    char *hn = NULL;
+    int pn = 0;
+    struct redirect_entry *entries = (struct redirect_entry *) 
cconf->redirects->elts;
+    for(i=0; i<cconf->redirects->nelts; i++) {
+        if (!strcmp(entries[i].orighostname, "*")) {
+            hn = entries[i].hostname;
+            pn = entries[i].port;
+            continue;
+        }
+        if (!strcasecmp(entries[i].orighostname, uri.hostname)) {
+            hn = entries[i].hostname;
+            pn = entries[i].port;
+            break;
+        }
+    }
+    if (hn) {
+        uri.hostname = hn;
+        uri.port = pn;
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+                "proxy: CONNECT: redirecting %s to %s:%d", url, uri.hostname, 
uri.port);
+    }
+
     /* do a DNS lookup for the destination host */
     err = apr_sockaddr_info_get(&uri_addr, uri.hostname, APR_UNSPEC, uri.port, 
0, p);
 
@@ -366,12 +402,54 @@
     proxy_hook_canon_handler(ap_proxy_connect_canon, NULL, NULL, 
APR_HOOK_MIDDLE);
 }
 
+static const char *add_connect_redirect(cmd_parms *cmd, void *dummy, const 
char *a1, const char *a2, const char *a3)
+{
+    server_rec *s = cmd->server;
+    proxy_connect_server_conf *conf =
+    (proxy_connect_server_conf *) ap_get_module_config(s->module_config, 
&proxy_connect_module);
+    struct redirect_entry *new;
+
+    new = apr_array_push(conf->redirects);
+    new->orighostname = apr_pstrdup(cmd->pool, a1);
+    new->hostname = apr_pstrdup(cmd->pool, a2);
+    new->port = atoi(a3);
+
+    return NULL;
+}
+
+static const command_rec proxy_connect_cmds[] =
+{
+    AP_INIT_TAKE3("ConnectRedirect", add_connect_redirect, NULL, RSRC_CONF,
+        "Redirect CONNECT requests to the specified host and port"),
+    {NULL}
+};
+
+static void *create_proxy_connect_config(apr_pool_t *p, server_rec *s)
+{
+    proxy_connect_server_conf *ps = apr_pcalloc(p, 
sizeof(proxy_connect_server_conf));
+
+    ps->redirects = apr_array_make(p, 10, sizeof(struct redirect_entry));
+
+    return ps;
+}
+
+static void * merge_proxy_connect_config(apr_pool_t *p, void *basev, void 
*overridesv)
+{
+    proxy_connect_server_conf *ps = apr_pcalloc(p, 
sizeof(proxy_connect_server_conf));
+    proxy_connect_server_conf *base = (proxy_connect_server_conf *) basev;
+    proxy_connect_server_conf *overrides = (proxy_connect_server_conf *) 
overridesv;
+
+    ps->redirects = apr_array_append(p, base->redirects, overrides->redirects);
+
+    return ps;
+}
+
 module AP_MODULE_DECLARE_DATA proxy_connect_module = {
     STANDARD20_MODULE_STUFF,
-    NULL,              /* create per-directory config structure */
-    NULL,              /* merge per-directory config structures */
-    NULL,              /* create per-server config structure */
-    NULL,              /* merge per-server config structures */
-    NULL,              /* command apr_table_t */
+    NULL,                      /* create per-directory config structure */
+    NULL,                      /* merge per-directory config structures */
+    create_proxy_connect_config,/* create per-server config structure */
+    merge_proxy_connect_config, /* merge per-server config structures */
+    proxy_connect_cmds,        /* command apr_table_t */
     ap_proxy_connect_register_hook     /* register hooks */
 };

Reply via email to