You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by rj...@apache.org on 2010/02/12 10:58:49 UTC

svn commit: r909323 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy.xml docs/manual/mod/mod_proxy_connect.xml docs/manual/mod/mod_proxy_http.xml include/ap_mmn.h modules/proxy/mod_proxy.h modules/proxy/proxy_util.c

Author: rjung
Date: Fri Feb 12 09:58:48 2010
New Revision: 909323

URL: http://svn.apache.org/viewvc?rev=909323&view=rev
Log:
Support remote https proxies by using HTTP CONNECT.
PR: 19188
Submitted by: Philippe Dutrueux <lilas evidian.com>
Reviewed by: rjung

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
    httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml
    httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml
    httpd/httpd/trunk/include/ap_mmn.h
    httpd/httpd/trunk/modules/proxy/mod_proxy.h
    httpd/httpd/trunk/modules/proxy/proxy_util.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Fri Feb 12 09:58:48 2010
@@ -1,5 +1,11 @@
                                                         -*- coding: utf-8 -*-
 
+Changes with Apache 2.3.7
+
+  *) mod_proxy, mod_proxy_http: Support remote https proxies
+     by using HTTP CONNECT.
+     PR 19188.  [Philippe Dutrueux <lilas evidian.com>, Rainer Jung]
+
 Changes with Apache 2.3.6
 
   *) worker: Don't report server has reached MaxClients until it has.

Modified: httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml Fri Feb 12 09:58:48 2010
@@ -465,8 +465,9 @@
     </example>
 
     <p><var>scheme</var> is effectively the protocol that should be used to
-    communicate with the remote server; only <code>http</code> is supported by
-    this module.</p>
+    communicate with the remote server; only <code>http</code> and <code>https</code>
+    are supported by this module. When using <code>https</code>, the requests
+    are forwarded through the remote proxy using the HTTP CONNECT method.</p>
 
     <example><title>Example</title>
       ProxyRemote http://goodguys.example.com/ http://mirrorguys.example.com:8000<br />

Modified: httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml Fri Feb 12 09:58:48 2010
@@ -39,6 +39,11 @@
     requests, <module>mod_proxy</module> and
     <module>mod_proxy_connect</module> have to be present in the server.</p>
 
+    <p>CONNECT is also used, when the server needs to send an HTTPS request
+    through a forward proxy. In this case the server acts as a CONNECT client.
+    This functionality is part of <module>mod_proxy</module> and
+    <module>mod_proxy_connect</module> is not needed in this case.</p>
+
     <note type="warning"><title>Warning</title>
       <p>Do not enable proxying until you have <a
       href="mod_proxy.html#access">secured your server</a>. Open proxy

Modified: httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml Fri Feb 12 09:58:48 2010
@@ -32,7 +32,7 @@
 <summary>
     <p>This module <em>requires</em> the service of <module
     >mod_proxy</module>. It provides the features used for
-    proxying HTTP requests. <module>mod_proxy_http</module>
+    proxying HTTP and HTTPS requests. <module>mod_proxy_http</module>
     supports HTTP/0.9, HTTP/1.0 and HTTP/1.1. It does <em>not</em>
     provide any caching abilities. If you want to set up a caching
     proxy, you might want to use the additional service of the

Modified: httpd/httpd/trunk/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/include/ap_mmn.h?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/include/ap_mmn.h (original)
+++ httpd/httpd/trunk/include/ap_mmn.h Fri Feb 12 09:58:48 2010
@@ -215,6 +215,7 @@
  * 20091230.3 (2.3.6-dev)  add ap_parse_log_level()
  * 20091230.4 (2.3.6-dev)  export ap_process_request_after_handler() for mod_serf
  * 20100208.0 (2.3.6-dev)  ap_socache_provider_t API changes to store and iterate
+ * 20100208.1 (2.3.6-dev)  Added forward member to proxy_conn_rec
  *
  */
 
@@ -223,7 +224,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20100208
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 0                     /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 1                     /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/trunk/modules/proxy/mod_proxy.h
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/mod_proxy.h?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/mod_proxy.h (original)
+++ httpd/httpd/trunk/modules/proxy/mod_proxy.h Fri Feb 12 09:58:48 2010
@@ -232,6 +232,7 @@
                              * which the backend currently answers. */
     int          need_flush;/* Flag to decide whether we need to flush the
                              * filter chain or not */
+    void         *forward;  /* opaque forward proxy data */
 } proxy_conn_rec;
 
 typedef struct {

Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=909323&r1=909322&r2=909323&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
+++ httpd/httpd/trunk/modules/proxy/proxy_util.c Fri Feb 12 09:58:48 2010
@@ -29,6 +29,18 @@
 #define apr_socket_create apr_socket_create_ex
 #endif
 
+/*
+ * Opaque structure containing target server info when
+ * using a forward proxy.
+ * Up to now only used in combination with HTTP CONNECT.
+ */
+typedef struct {
+    int          use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */
+    const char   *target_host;     /* Target hostname */
+    apr_port_t   target_port;      /* Target port */
+    const char   *proxy_auth;      /* Proxy authorization */
+} forward_info;
+
 /* Global balancer counter */
 int PROXY_DECLARE_DATA proxy_lb_workers = 0;
 static int lb_workers_limit = 0;
@@ -2109,6 +2121,34 @@
         if (proxyname) {
             conn->hostname = apr_pstrdup(conn->pool, proxyname);
             conn->port = proxyport;
+            /*
+             * If we have a forward proxy and the protocol is HTTPS,
+             * then we need to prepend a HTTP CONNECT request before
+             * sending our actual HTTPS requests.
+             * Save our real backend data for using it later during HTTP CONNECT.
+             */
+            if (conn->is_ssl) {
+                const char *proxy_auth;
+
+                forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info));
+                conn->forward = forward;
+                forward->use_http_connect = 1;
+                forward->target_host = uri->hostname;
+                forward->target_port = uri->port;
+                /* Do we want to pass Proxy-Authorization along?
+                 * If we haven't used it, then YES
+                 * If we have used it then MAYBE: RFC2616 says we MAY propagate it.
+                 * So let's make it configurable by env.
+                 * The logic here is the same used in mod_proxy_http.
+                 */
+                proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
+                if (proxy_auth != NULL &&
+                    proxy_auth[0] != '\0' &&
+                    r->user == NULL && /* we haven't yet authenticated */
+                    apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) {
+                    forward->proxy_auth = proxy_auth;
+                }
+            }
         }
         else {
             conn->hostname = apr_pstrdup(conn->pool, uri->hostname);
@@ -2250,6 +2290,83 @@
 }
 #endif /* USE_ALTERNATE_IS_CONNECTED */
 
+
+/*
+ * Send a HTTP CONNECT request to a forward proxy.
+ * The proxy is given by "backend", the target server
+ * is contained in the "forward" member of "backend".
+ */
+static apr_status_t send_http_connect(proxy_conn_rec *backend,
+                                      server_rec *s)
+{
+    int status;
+    apr_size_t nbytes;
+    char buffer[HUGE_STRING_LEN];
+    forward_info *forward = (forward_info *)backend->forward;
+    int len = 0;
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                 "proxy: CONNECT: sending the CONNECT request for %s:%d "
+                 "to the remote proxy %pI (%s)",
+                 forward->target_host, forward->target_port,
+                 backend->addr, backend->hostname);
+    /* Create the CONNECT request */
+    nbytes = apr_snprintf(buffer, sizeof(buffer),
+                          "CONNECT %s:%d HTTP/1.0" CRLF,
+                          forward->target_host, forward->target_port);
+    /* Add proxy authorization from the initial request if necessary */
+    if (forward->proxy_auth != NULL) {
+        nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
+                               "Proxy-Authorization: %s" CRLF,
+                               forward->proxy_auth);
+    }
+    /* Set a reasonable agent and send everything */
+    nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
+                           "Proxy-agent: %s" CRLF CRLF,
+                           ap_get_server_banner());
+    apr_socket_send(backend->sock, buffer, &nbytes);
+
+    /* Receive the whole CONNECT response */
+    nbytes = sizeof(buffer) - 1;
+    status = apr_socket_recv(backend->sock, buffer, &nbytes);
+    while (status == APR_SUCCESS) {
+        len += nbytes;
+        buffer[len] = '\0';
+        if (strstr(buffer, "\r\n\r\n") != NULL) {
+            break;
+        }
+        nbytes = sizeof(buffer) - 1 - len;
+        status = apr_socket_recv(backend->sock, buffer + len, &nbytes);
+    }
+
+    /* Check for HTTP_OK response status */
+    if (status == APR_SUCCESS) {
+        int major, minor;
+        char code_str[10];
+
+        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+                     "send_http_connect: response from the forward proxy: %s",
+                     buffer);
+
+        /* Extract the returned code */
+        if (sscanf(buffer, "HTTP/%u.%u %s", &major, &minor, code_str) == 3) {
+            status = atoi(code_str);
+            if (status == HTTP_OK) {
+                status = APR_SUCCESS;
+            }
+            else {
+                ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+                             "send_http_connect: the forward proxy returned code is %s",
+                             code_str);
+            status = APR_INCOMPLETE;
+            }
+        }
+    }
+
+    return(status);
+}
+
+
 PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function,
                                             proxy_conn_rec *conn,
                                             proxy_worker *worker,
@@ -2360,7 +2477,33 @@
              apr_socket_timeout_set(newsock, s->timeout);
         }
 
-        conn->sock   = newsock;
+        conn->sock = newsock;
+
+        if (conn->forward) {
+            forward_info *forward = (forward_info *)conn->forward;
+            /*
+             * For HTTP CONNECT we need to prepend CONNECT request before
+             * sending our actual HTTPS requests.
+             */
+            if (forward->use_http_connect) {
+                rv = send_http_connect(conn, s);
+                /* If an error occurred, loop round and try again */
+                if (rv != APR_SUCCESS) {
+                    conn->sock = NULL;
+                    apr_socket_close(newsock);
+                    loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR;
+                    ap_log_error(APLOG_MARK, loglevel, rv, s,
+                                 "proxy: %s: attempt to connect to %s:%d "
+                                 "via http CONNECT through %pI (%s) failed",
+                                 proxy_function,
+                                 forward->target_host, forward->target_port,
+                                 backend_addr, worker->hostname);
+                    backend_addr = backend_addr->next;
+                    continue;
+                }
+            }
+        }
+
         connected    = 1;
     }
     /*
@@ -2547,4 +2690,3 @@
     }
     return rv;
 }
-



Re: svn commit: r909323 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy.xml docs/manual/mod/mod_proxy_connect.xml docs/manual/mod/mod_proxy_http.xml include/ap_mmn.h modules/proxy/mod_proxy.h modules/proxy/proxy_util.c

Posted by Rainer Jung <ra...@kippdata.de>.
On 14.02.2010 17:19, Ruediger Pluem wrote:
> On 12.02.2010 10:58, rjung@apache.org wrote:
>> Author: rjung
>> Date: Fri Feb 12 09:58:48 2010
>> New Revision: 909323
>>
>> URL: http://svn.apache.org/viewvc?rev=909323&view=rev
>> Log:
>> Support remote https proxies by using HTTP CONNECT.
>> PR: 19188
>> Submitted by: Philippe Dutrueux<lilas evidian.com>
>> Reviewed by: rjung
>>
>> Modified:
>>      httpd/httpd/trunk/CHANGES
>>      httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
>>      httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml
>>      httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml
>>      httpd/httpd/trunk/include/ap_mmn.h
>>      httpd/httpd/trunk/modules/proxy/mod_proxy.h
>>      httpd/httpd/trunk/modules/proxy/proxy_util.c
>>
>
>> Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
>> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=909323&r1=909322&r2=909323&view=diff
>> ==============================================================================
>> --- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
>> +++ httpd/httpd/trunk/modules/proxy/proxy_util.c Fri Feb 12 09:58:48 2010
...
>> +        /* Extract the returned code */
>> +        if (sscanf(buffer, "HTTP/%u.%u %s",&major,&minor, code_str) == 3) {
>
> Doesn't this introduce a buffer overflow if I am an evil backend and respond
> with e.g. HTTP/1.1 Someeviloverflowlongerthen10chars ?

Thanks RĂ¼diger. Fixed in r910079. I added another fix in r910081
  and one more hardening type change in 910124. Will update the STATUS 
file entry for 2.2.x tomorrow.

Regards,

Rainer



Re: svn commit: r909323 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/mod_proxy.xml docs/manual/mod/mod_proxy_connect.xml docs/manual/mod/mod_proxy_http.xml include/ap_mmn.h modules/proxy/mod_proxy.h modules/proxy/proxy_util.c

Posted by Ruediger Pluem <rp...@apache.org>.
On 12.02.2010 10:58, rjung@apache.org wrote:
> Author: rjung
> Date: Fri Feb 12 09:58:48 2010
> New Revision: 909323
> 
> URL: http://svn.apache.org/viewvc?rev=909323&view=rev
> Log:
> Support remote https proxies by using HTTP CONNECT.
> PR: 19188
> Submitted by: Philippe Dutrueux <lilas evidian.com>
> Reviewed by: rjung
> 
> Modified:
>     httpd/httpd/trunk/CHANGES
>     httpd/httpd/trunk/docs/manual/mod/mod_proxy.xml
>     httpd/httpd/trunk/docs/manual/mod/mod_proxy_connect.xml
>     httpd/httpd/trunk/docs/manual/mod/mod_proxy_http.xml
>     httpd/httpd/trunk/include/ap_mmn.h
>     httpd/httpd/trunk/modules/proxy/mod_proxy.h
>     httpd/httpd/trunk/modules/proxy/proxy_util.c
> 

> Modified: httpd/httpd/trunk/modules/proxy/proxy_util.c
> URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/proxy/proxy_util.c?rev=909323&r1=909322&r2=909323&view=diff
> ==============================================================================
> --- httpd/httpd/trunk/modules/proxy/proxy_util.c (original)
> +++ httpd/httpd/trunk/modules/proxy/proxy_util.c Fri Feb 12 09:58:48 2010
> @@ -29,6 +29,18 @@

> @@ -2250,6 +2290,83 @@
>  }
>  #endif /* USE_ALTERNATE_IS_CONNECTED */
>  
> +
> +/*
> + * Send a HTTP CONNECT request to a forward proxy.
> + * The proxy is given by "backend", the target server
> + * is contained in the "forward" member of "backend".
> + */
> +static apr_status_t send_http_connect(proxy_conn_rec *backend,
> +                                      server_rec *s)
> +{
> +    int status;
> +    apr_size_t nbytes;
> +    char buffer[HUGE_STRING_LEN];
> +    forward_info *forward = (forward_info *)backend->forward;
> +    int len = 0;
> +
> +    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                 "proxy: CONNECT: sending the CONNECT request for %s:%d "
> +                 "to the remote proxy %pI (%s)",
> +                 forward->target_host, forward->target_port,
> +                 backend->addr, backend->hostname);
> +    /* Create the CONNECT request */
> +    nbytes = apr_snprintf(buffer, sizeof(buffer),
> +                          "CONNECT %s:%d HTTP/1.0" CRLF,
> +                          forward->target_host, forward->target_port);
> +    /* Add proxy authorization from the initial request if necessary */
> +    if (forward->proxy_auth != NULL) {
> +        nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
> +                               "Proxy-Authorization: %s" CRLF,
> +                               forward->proxy_auth);
> +    }
> +    /* Set a reasonable agent and send everything */
> +    nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
> +                           "Proxy-agent: %s" CRLF CRLF,
> +                           ap_get_server_banner());
> +    apr_socket_send(backend->sock, buffer, &nbytes);
> +
> +    /* Receive the whole CONNECT response */
> +    nbytes = sizeof(buffer) - 1;
> +    status = apr_socket_recv(backend->sock, buffer, &nbytes);
> +    while (status == APR_SUCCESS) {
> +        len += nbytes;
> +        buffer[len] = '\0';
> +        if (strstr(buffer, "\r\n\r\n") != NULL) {
> +            break;
> +        }
> +        nbytes = sizeof(buffer) - 1 - len;
> +        status = apr_socket_recv(backend->sock, buffer + len, &nbytes);
> +    }
> +
> +    /* Check for HTTP_OK response status */
> +    if (status == APR_SUCCESS) {
> +        int major, minor;
> +        char code_str[10];
> +
> +        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
> +                     "send_http_connect: response from the forward proxy: %s",
> +                     buffer);
> +
> +        /* Extract the returned code */
> +        if (sscanf(buffer, "HTTP/%u.%u %s", &major, &minor, code_str) == 3) {

Doesn't this introduce a buffer overflow if I am an evil backend and respond
with e.g. HTTP/1.1 Someeviloverflowlongerthen10chars ?

Regards

RĂ¼diger