]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Some code rewriting in ap_proxy_connect_handler():
authorGraham Leggett <minfrin@apache.org>
Wed, 4 Apr 2001 18:47:42 +0000 (18:47 +0000)
committerGraham Leggett <minfrin@apache.org>
Wed, 4 Apr 2001 18:47:42 +0000 (18:47 +0000)
*) Fixed bug where a hostname without a "." in it (such as "localhost")
would not trigger an IP address check with ProxyBlock.
*) Fixed ProxyBlock bugs with ap_proxy_http_handler() and
ap_proxy_connect_handler().
*) Updated ap_proxy_connect_handler() to support APR, while
moving some common code between http_handler and connect_handler
to proxy_util.c.
PR:
Obtained from:
Reviewed by:

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@88721 13f79535-47bb-0310-9956-ffa450edef68

modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
modules/proxy/proxy_connect.c
modules/proxy/proxy_http.c
modules/proxy/proxy_util.c

index 5db5eb92d67a69796bc29dfe95f9ce4db03e3370..9e53bf2b77f9393555c17559d89cf0bce1ed5f45 100644 (file)
@@ -553,16 +553,15 @@ static const char *
 
     /* Don't duplicate entries */
     for (i = 0; i < conf->noproxies->nelts; i++) {
-       if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
+       if (apr_strnatcasecmp(arg, list[i].name) == 0) { /* ignore case for host names */
            found = 1;
+       }
     }
 
     if (!found) {
        new = apr_array_push(conf->noproxies);
        new->name = arg;
-       /* Don't do name lookups on things that aren't dotted */
-        if (ap_strchr_c(arg, '.') != NULL &&
-           apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
+       if (APR_SUCCESS == apr_sockaddr_info_get(&addr, new->name, APR_UNSPEC, 0, 0, parms->pool)) {
            new->addr = addr;
        }
        else {
index b151e4c91dc79a73171bf031ceb8ebd70f25d687..c321dc5c9959ddb1eb56e4d6738902e059f5c82d 100644 (file)
@@ -156,6 +156,7 @@ struct proxy_alias {
 
 struct dirconn_entry {
     char *name;
+//    struct apr_sockaddr_t *addr;
     struct in_addr addr, mask;
     struct hostent *hostentry;
     int (*matcher) (struct dirconn_entry * This, request_rec *r);
@@ -250,6 +251,7 @@ int ap_proxy_is_ipaddr(struct dirconn_entry *This, apr_pool_t *p);
 int ap_proxy_is_domainname(struct dirconn_entry *This, apr_pool_t *p);
 int ap_proxy_is_hostname(struct dirconn_entry *This, apr_pool_t *p);
 int ap_proxy_is_word(struct dirconn_entry *This, apr_pool_t *p);
+int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, apr_sockaddr_t *uri_addr);
 apr_status_t ap_proxy_doconnect(apr_socket_t *sock, char *host, apr_uint32_t port, request_rec *r);
 /* This function is called by ap_table_do() for all header lines */
 int ap_proxy_send_hdr_line(void *p, const char *key, const char *value);
index f75c193a79049340061a20ef7a57eedcfe0daceb..35f6ae74e35c271945536bde6c5a09077bfbf3be 100644 (file)
@@ -112,94 +112,166 @@ allowed_port(proxy_server_conf *conf, int port)
 
 
 int ap_proxy_connect_handler(request_rec *r, char *url,
-                         const char *proxyhost, int proxyport)
+                         const char *proxyname, int proxyport)
 {
-    const char *host;
-    char *p;
-    int port;
+    apr_pool_t *p = r->pool;
     apr_socket_t *sock;
     char buffer[HUGE_STRING_LEN];
-    int nbytes, i;
+    int nbytes, i, err;
 
     apr_socket_t *client_sock = NULL;
     apr_pollfd_t *pollfd;
     apr_int32_t pollcnt;
     apr_int16_t pollevent;
-    
+    apr_sockaddr_t *uri_addr, *connect_addr;
+
+    uri_components uri;
+    const char *connectname;
+    int connectport = 0;
+
     void *sconf = r->server->module_config;
     proxy_server_conf *conf =
     (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
-    struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
 
-    /* Break the URL into host:port pairs */
-    host = url;
-    p = strchr(url, ':');
-    if (p == NULL)
-       port = DEFAULT_HTTPS_PORT;
+
+    /*
+     * Step One: Determine Who To Connect To
+     *
+     * Break up the URL to determine the host to connect to
+     */
+
+    /* we break the URL into host, port, uri */
+    if (HTTP_OK != ap_parse_uri_components(p, url, &uri)) {
+       return ap_proxyerror(r, HTTP_BAD_REQUEST,
+                            apr_pstrcat(p, "URI cannot be parsed: ", url, NULL));
+    }
+
+    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                "proxy: CONNECT connecting %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);
+
+    /* are we connecting directly, or via a proxy? */
+    if (proxyname) {
+       connectname = proxyname;
+       connectport = proxyport;
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+            "CONNECT to remote proxy %s on port %d", proxyname, proxyport);
+        err = apr_sockaddr_info_get(&connect_addr, proxyname, APR_UNSPEC, proxyport, 0, p);
+    }
     else {
-       port = atoi(p + 1);
-       *p = '\0';
+       connectname = uri.hostname;
+       connectport = uri.port;
+       connect_addr = uri_addr;
+        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
+            "CONNECT to %s on port %d", connectname, connectport);
     }
 
-/* check if ProxyBlock directive on this host */
-/* XXX FIXME */
-/*    destaddr.s_addr = ap_inet_addr(host); */
-    for (i = 0; i < conf->noproxies->nelts; i++) {
-       if ((npent[i].name != NULL && ap_strstr_c(host, npent[i].name) != NULL)
-/*         || destaddr.s_addr == npent[i].addr.s_addr */
-           || npent[i].name[0] == '*')
-           return ap_proxyerror(r, HTTP_FORBIDDEN,
-                "Connect to remote machine blocked");
+    /* check if ProxyBlock directive on this host */
+    if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
+       return ap_proxyerror(r, HTTP_FORBIDDEN,
+                            "Connect to remote machine blocked");
     }
 
     /* Check if it is an allowed port */
     if (conf->allowed_connect_ports->nelts == 0) {
        /* Default setting if not overridden by AllowCONNECT */
-       switch (port) {
+       switch (uri.port) {
            case DEFAULT_HTTPS_PORT:
            case DEFAULT_SNEWS_PORT:
                break;
            default:
                return HTTP_FORBIDDEN;
        }
-    } else if(!allowed_port(conf, port))
+    } else if(!allowed_port(conf, uri.port))
        return HTTP_FORBIDDEN;
 
-    if (proxyhost) {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-            "CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
-    }
-    else {
-        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
-            "CONNECT to %s on port %d", host, port);
+
+    /*
+     * Step Two: Make the Connection
+     *
+     * We have determined who to connect to. Now make the connection.
+     */
+
+    /* get all the possible IP addresses for the destname and loop through them
+     * until we get a successful connection
+     */
+    if (APR_SUCCESS != err) {
+       return ap_proxyerror(r, HTTP_BAD_GATEWAY, apr_pstrcat(p,
+                             "DNS lookup failure for: ",
+                             connectname, NULL));
     }
 
+    /* create a new socket */
     if ((apr_socket_create(&sock, APR_INET, SOCK_STREAM, r->pool)) != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
             "proxy: error creating socket");
         return HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host),
-      proxyport ? proxyport : port, r) != APR_SUCCESS) {
-        apr_socket_close(sock);
-        return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
-            apr_pstrcat(r->pool, "Could not connect to remote machine:<br>",
-            proxyhost, NULL));
+       /*
+        * At this point we have a list of one or more IP addresses of
+        * the machine to connect to. If configured, reorder this
+        * list so that the "best candidate" is first try. "best
+        * candidate" could mean the least loaded server, the fastest
+        * responding server, whatever.
+         *
+         * For now we do nothing, ie we get DNS round robin.
+        * XXX FIXME
+        */
+
+
+    /* try each IP address until we connect successfully */
+    {
+       int failed = 1;
+       while (connect_addr) {
+
+           /* make the connection out of the socket */
+           err = apr_connect(sock, connect_addr);
+
+           /* if an error occurred, loop round and try again */
+            if (err != APR_SUCCESS) {
+               ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server,
+                            "proxy: attempt to connect to %pI (%s) failed", connect_addr, connectname);
+               connect_addr = connect_addr->next;
+               continue;
+            }
+
+           /* if we get here, all is well */
+           failed = 0;
+           break;
+       }
+
+       /* handle a permanent error from the above loop */
+       if (failed) {
+           if (proxyname) {
+               return DECLINED;
+           }
+           else {
+               return HTTP_BAD_GATEWAY;
+           }
+       }
     }
 
+
+    /*
+     * Step Three: Send the Request
+     *
+     * Send the HTTP/1.1 CONNECT request to the remote server
+     */
+
     /* If we are connecting through a remote proxy, we need to pass
      * the CONNECT request on to it.
      */
     if (proxyport) {
-       /* FIXME: We should not be calling write() directly, but we currently
-        * have no alternative.  Error checking ignored.  Also, we force
+       /* FIXME: Error checking ignored.  Also, we force
         * a HTTP/1.0 request to keep things simple.
         */
         ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
              "Sending the CONNECT request to the remote proxy");
         nbytes = apr_snprintf(buffer, sizeof(buffer),
-             "CONNECT %s HTTP/1.0" CRLF, r->uri);
+             "CONNECT %s HTTP/1.1" CRLF, r->uri);
         apr_send(sock, buffer, &nbytes);
         nbytes = apr_snprintf(buffer, sizeof(buffer),
              "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
@@ -213,6 +285,13 @@ int ap_proxy_connect_handler(request_rec *r, char *url,
         ap_rflush(r);
     }
 
+
+    /*
+     * Step Four: Handle Data Transfer
+     *
+     * Handle two way transfer of data over the socket (this is a tunnel).
+     */
+
     if(apr_poll_setup(&pollfd, 2, r->pool) != APR_SUCCESS)
     {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -297,6 +376,13 @@ int ap_proxy_connect_handler(request_rec *r, char *url,
             break;
     }
 
+
+    /*
+     * Step Five: Clean Up
+     *
+     * Close the socket and clean up
+     */
+
     apr_socket_close(sock);
 
     return OK;
index e61ab5a10be212fb4eb1dc67e587e50e95179264..afa45964888ac296dbe2e2b84e82e9de6588b352 100644 (file)
@@ -187,7 +187,7 @@ int ap_proxy_http_handler(request_rec *r, char *url,
     apr_sockaddr_t *connect_addr;
     char server_portstr[32];
     apr_socket_t *sock;
-    int i, j, len, backasswards, close=0, failed=0, new=0;
+    int i, len, backasswards, close=0, failed=0, new=0;
     apr_status_t err;
     apr_array_header_t *headers_in_array;
     apr_table_entry_t *headers_in;
@@ -249,31 +249,9 @@ int ap_proxy_http_handler(request_rec *r, char *url,
     }
 
     /* check if ProxyBlock directive on this host */
-    /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
-    for (j = 0; j < conf->noproxies->nelts; j++) {
-        struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
-       struct apr_sockaddr_t *conf_addr = npent[j].addr;
-       if ((npent[j].name && ap_strstr_c(uri.hostname, npent[j].name))
-            || npent[j].name[0] == '*') {
-           return ap_proxyerror(r, HTTP_FORBIDDEN,
-                                "Connect to remote machine blocked (by name)");
-       }
-       while (conf_addr) {
-           while (uri_addr) {
-               char *conf_ip;
-               char *uri_ip;
-               apr_sockaddr_ip_get(&conf_ip, conf_addr);
-               apr_sockaddr_ip_get(&uri_ip, uri_addr);
-/*             ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
-                            "Testing %s and %s", conf_ip, uri_ip); */
-               if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
-                   return ap_proxyerror(r, HTTP_FORBIDDEN,
-                                        "Connect to remote machine blocked (by IP address)");
-               }
-               uri_addr = uri_addr->next;
-           }
-           conf_addr = conf_addr->next;
-       }
+    if (OK != ap_proxy_checkproxyblock(r, conf, uri_addr)) {
+       return ap_proxyerror(r, HTTP_FORBIDDEN,
+                            "Connect to remote machine blocked");
     }
 
 
index cd4806125c73e2938f342cb732ea982981a0e8df..27acb4da11806b84e701d3eef348242725fdefab 100644 (file)
@@ -1071,6 +1071,44 @@ static int proxy_match_word(struct dirconn_entry *This, request_rec *r)
     return host != NULL && ap_strstr_c(host, This->name) != NULL;
 }
 
+/* checks whether a host in uri_addr matches proxyblock */
+int ap_proxy_checkproxyblock(request_rec *r, proxy_server_conf *conf, 
+                             apr_sockaddr_t *uri_addr)
+{
+    int j;
+    /* XXX FIXME: conf->noproxies->elts is part of an opaque structure */
+    for (j = 0; j < conf->noproxies->nelts; j++) {
+        struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
+       struct apr_sockaddr_t *conf_addr = npent[j].addr;
+       ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                    "proxy: checking remote machine [%s] against [%s]", uri_addr->hostname, npent[j].name);
+       if ((npent[j].name && ap_strstr_c(uri_addr->hostname, npent[j].name))
+            || npent[j].name[0] == '*') {
+           ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
+                        "proxy: connect to remote machine %s blocked: name %s matched", uri_addr->hostname, npent[j].name);
+           return HTTP_FORBIDDEN;
+       }
+       while (conf_addr) {
+           while (uri_addr) {
+               char *conf_ip;
+               char *uri_ip;
+               apr_sockaddr_ip_get(&conf_ip, conf_addr);
+               apr_sockaddr_ip_get(&uri_ip, uri_addr);
+               ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
+                            "proxy: ProxyBlock comparing %s and %s", conf_ip, uri_ip);
+               if (!apr_strnatcasecmp(conf_ip, uri_ip)) {
+                   ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
+                                "proxy: connect to remote machine %s blocked: IP %s matched", uri_addr->hostname, conf_ip);
+                   return HTTP_FORBIDDEN;
+               }
+               uri_addr = uri_addr->next;
+           }
+           conf_addr = conf_addr->next;
+       }
+    }
+    return OK;
+}
+
 apr_status_t ap_proxy_doconnect(apr_socket_t *sock, char *host, apr_uint32_t port, request_rec *r)
 {
     apr_status_t rv;