You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by Dean Gaudet <dg...@hyperreal.org> on 1997/07/19 10:58:38 UTC

cvs commit: apache/src/modules/proxy mod_proxy.c mod_proxy.h proxy_ftp.c proxy_http.c proxy_util.c

dgaudet     97/07/19 01:58:37

  Modified:    htdocs/manual  new_features_1_3.html
               htdocs/manual/mod  mod_proxy.html
               src       CHANGES
               src/modules/proxy  mod_proxy.c mod_proxy.h proxy_ftp.c
                        proxy_http.c proxy_util.c
  Log:
  NoProxy and ProxyDomain directives.
  
  Submitted by:	Martin Kraemer <Ma...@mch.sni.de>
  Reviewed by:	Dean Gaudet
  
  Revision  Changes    Path
  1.9       +4 -0      apache/htdocs/manual/new_features_1_3.html
  
  Index: new_features_1_3.html
  ===================================================================
  RCS file: /export/home/cvs/apache/htdocs/manual/new_features_1_3.html,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -C3 -r1.8 -r1.9
  *** new_features_1_3.html	1997/07/18 21:01:31	1.8
  --- new_features_1_3.html	1997/07/19 08:58:31	1.9
  ***************
  *** 105,110 ****
  --- 105,114 ----
    before any requests are handled. This allows the module to set up
    anything that need to be done once per processes. For example,
    connections to databases.
  + 
  + <li><strong><a href="mod/mod_proxy.html#noproxy">NoProxy</a></strong>
  + and <strong><a href="mod/mod_proxy.html#proxydomain">ProxyDomain</a>
  + </strong> directives added to proxy, useful for intranets.
        
    </ul>
    
  
  
  
  1.26      +148 -0    apache/htdocs/manual/mod/mod_proxy.html
  
  Index: mod_proxy.html
  ===================================================================
  RCS file: /export/home/cvs/apache/htdocs/manual/mod/mod_proxy.html,v
  retrieving revision 1.25
  retrieving revision 1.26
  diff -C3 -r1.25 -r1.26
  *** mod_proxy.html	1997/07/06 17:19:18	1.25
  --- mod_proxy.html	1997/07/19 08:58:32	1.26
  ***************
  *** 42,47 ****
  --- 42,49 ----
    <li><a href="#proxyremote">ProxyRemote</a>
    <li><a href="#proxypass">ProxyPass</a>
    <li><a href="#proxyblock">ProxyBlock</a>
  + <li><a href="#noproxy">NoProxy</a>
  + <li><a href="#proxydomain">ProxyDomain</a>
    <li><a href="#cacheroot">CacheRoot</a>
    <li><a href="#cachesize">CacheSize</a>
    <li><a href="#cachemaxexpire">CacheMaxExpire</a>
  ***************
  *** 150,155 ****
  --- 152,284 ----
    
    blocks connections to all sites.
    
  + <A name="noproxy"><h2>NoProxy</h2></A>
  + <strong>Syntax:</strong> NoProxy { <A HREF="#domain"><em>&lt;Domain&gt;</em></A>
  +                                  | <A HREF="#subnet"><em>&lt;SubNet&gt;</em></A>
  + 				 | <A HREF="#ipaddr"><em>&lt;IpAddr&gt;</em></A>
  + 				 | <A HREF="#hostname"><em>&lt;Hostname&gt;</em></A>
  + 				 } <br>
  + <strong>Context:</strong> server config<br>
  + <strong>Status:</strong> Base<br>
  + <strong>Module:</strong> mod_proxy<br>
  + <strong>Compatibility:</strong> NoProxy is only available in a patch to
  + Apache 1.2.1 and later.<p>
  + 
  + This directive is only useful for apache proxy servers within intranets.
  + The NoProxy directive specifies a list of subnets, IP addresses, hosts
  + and/or domains, separated by spaces. A request to a host which matches
  + one or more of these is always served directly, without forwarding to
  + the configured ProxyRemote proxy server(s).<br>Example:
  + 
  + <pre>
  +   ProxyRemote  *  http://firewall.mycompany.com:81
  +   NoProxy         .mycompany.com 192.168.112.0/21 
  + </pre>
  + The arguments to the NoProxy directive are one of the following type list:
  +    <DL>
  +     <!-- ===================== Domain ======================= -->
  +     <A NAME="domain">
  +     <DT><EM>Domain</EM>
  +     <DD>A <EM>Domain</EM> is a partially qualified DNS domain name, preceded
  +         by a period.
  +         It represents a list of hosts which logically belong to the same DNS
  +         domain or zone (i.e. the suffixes of the hostnames are all ending in 
  +         <EM>Domain</EM>).<BR>
  + 		Examples: <SAMP>.com</SAMP>   <SAMP>.apache.org.</SAMP>    <SAMP>.sni.de</SAMP><BR>
  +         To distinguish <EM>Domain</EM>s from <A HREF="#hostname"><EM>Hostname</EM></A>s (both
  +         syntactically and semantically; a DNS domain can have a DNS A record,
  +         too!), <EM>Domain</EM>s are always written
  +         with a leading period.<BR>
  +         Note: Domain name comparisons are done without regard to the case,
  +         and <EM>Domain</EM>s are always assumed to be anchored in the root 
  +         of the DNS tree, therefore two domains <SAMP>.MyDomain.com</SAMP> and
  +         <SAMP>.mydomain.com.</SAMP> (note the trailing period) are
  +         considered equal. Since a domain comparison does not involve a DNS
  + 	lookup, it is much more efficient than subnet comparison.
  + 
  +     <!-- ===================== SubNet ======================= -->
  +     <A NAME="subnet">
  +     <DT><EM>SubNet</EM>
  +     <DD>A <EM>SubNet</EM> is a partially qualified internet address in
  +         numeric (dotted quad) form, optionally followed by a slash and the
  +         netmask, specified as the number of significant bits in the
  +         <EM>SubNet</EM>. It is used to represent a subnet of hosts which can
  +         be reached over a common network interface. In the absence of the
  +         explicit net mask it is assumed that omitted (or zero valued)
  +         trailing digits specify the mask. (In this case, the netmask can
  +         only be multiples of 8 bits wide.)<BR>
  +         Examples:
  +         <DL>
  +          <DT><SAMP>192.168</SAMP> or <SAMP>192.168.0.0</SAMP>
  +          <DD>the subnet 192.168.0.0 with a netmask of 16 valid bits
  +              (sometimes used in the netmask form <SAMP>255.255.0.0</SAMP>)
  +          <DT><SAMP>139.25.112.0/21</SAMP>
  +          <DD>the subnet <SAMP>139.25.112.0/21</SAMP> with a netmask of 21
  +              valid bits (also used in the form 255.255.248.0)
  +         </DL>
  + 		As a degenerate case, a <EM>SubNet</EM> with 32 valid bits is the
  +         equivalent to an <EM>IPAddr</EM>, while a <EM>SubNet</EM> with zero
  +         valid bits (e.g., 0.0.0.0/0) is the same as the constant
  +         <EM>_Default_</EM>, matching any IP address. 
  + 
  +     <!-- ===================== IPAddr ======================= -->
  +     <A NAME="ipaddr">
  +     <DT><EM>IPAddr</EM>
  +     <DD>A <EM>IPAddr</EM> represents a fully qualified internet address in
  +         numeric (dotted quad) form. Usually, this address represents a
  +         host, but there need not necessarily be a DNS domain name
  +         connected with the address.<BR>
  + 		Example: 139.25.113.10<BR>
  +         Note: An <EM>IPAddr</EM> does not need to be resolved by the DNS system, so
  +               it can result in more effective apache performance.<BR>
  + <p><strong>See Also:</strong>
  + <a href="../dns-caveats.html">DNS Issues</a></p>
  + 
  +     <!-- ===================== Hostname ======================= -->
  +     <A NAME="hostname">
  +     <DT><EM>Hostname</EM>
  +     <DD>A <EM>Hostname</EM> is a fully qualified DNS domain name which can
  +         be resolved to one or more <A HREF="#ipaddr"><EM>IPAddrs</EM></A> via the DNS domain name service.
  +         It represents a logical host (in contrast to <A HREF="#domain"><EM>Domain</EM></A>s, see
  +         above) and must be resolvable to at least one <A HREF="#ipaddr"><EM>IPAddr</EM></A> (or
  +         often to a list of hosts with different <A HREF="#ipaddr"><EM>IPAddr</EM></A>'s).<BR>
  + 		Examples: <SAMP>prep.ai.mit.edu</SAMP>
  +                   <SAMP>www.apache.org.</SAMP><BR>
  +         Note: In many situations, it is more effective to specify an
  +         <A HREF="#ipaddr"><EM>IPAddr</EM></A> in place of a <EM>Hostname</EM> since a DNS lookup
  +         can be avoided. Name resolution in Apache can take a remarkable deal
  +         of time when the connection to the name server uses a slow PPP
  +         link.<BR>
  +         Note: <EM>Hostname</EM> comparisons are done without regard to the case,
  +         and <EM>Hostname</EM>s are always assumed to be anchored in the root
  +         of the DNS tree, therefore two hosts <SAMP>WWW.MyDomain.com</SAMP>
  +         and <SAMP>www.mydomain.com.</SAMP> (note the trailing period) are
  +         considered equal.<BR>
  + <p><strong>See Also:</strong>
  + <a href="../dns-caveats.html">DNS Issues</a></p>
  +    </DL>
  + 
  + <A name="proxydomain"><h2>ProxyDomain</h2></A>
  + <strong>Syntax:</strong> ProxyDomain <em>&lt;Domain&gt;</em><br>
  + <strong>Context:</strong> server config<br>
  + <strong>Status:</strong> Base<br>
  + <strong>Module:</strong> mod_proxy<br>
  + <strong>Compatibility:</strong> ProxyDomain is only available in a patch to
  + Apache 1.2.1 and later.<p>
  + 
  + This directive is only useful for apache proxy servers within intranets.
  + The ProxyDomain directive specifies the default domain which the apache
  + proxy server will belong to. If a request to a host without a domain name
  + is encountered, a redirection response to the same host
  + with the configured <em>Domain</em> appended will be generated. 
  + <br>Example:
  + 
  + <pre>
  +   ProxyRemote  *  http://firewall.mycompany.com:81
  +   NoProxy         .mycompany.com 192.168.112.0/21 
  +   ProxyDomain     .mycompany.com
  + </pre>
  + 
    <A name="cacheroot"><h2>CacheRoot</h2></A>
    <strong>Syntax:</strong> CacheRoot <em>&lt;directory&gt;</em><br>
    <strong>Context:</strong> server config<br>
  ***************
  *** 299,304 ****
  --- 428,434 ----
    <li><a href="#startup">Why does Apache start more slowly when using the
            proxy module?</a>
    <li><a href="#socks">Can I use the Apache proxy module with my SOCKS proxy?</a>
  + <li><a href="#intranet">What other functions are useful for an intranet proxy server?</a>
    </ul>
    
    <h2><a name="access">Controlling access to your proxy</a></h2>
  ***************
  *** 359,364 ****
  --- 489,512 ----
    Remember that you'll also have to grant access to your Apache proxy machine by
    permitting connections on the appropriate ports in your SOCKS daemon's
    configuration.<p>
  + 
  + <h2><a name="intranet">What other functions are useful for an intranet proxy server?</a></h2>
  + 
  + <p>An Apache proxy server situated in an intranet needs to forward external
  + requests through the company's firewall. However, when it has to access
  + resources within the intranet, it can bypass the firewall when accessing
  + hosts. The <A HREF="#noproxy">NoProxy</A> directive is useful for specifying
  + which hosts belong to the intranet and should be accessed directly.</p>
  + 
  + <p>Users within an intranet tend to omit the local domain name from their
  + WWW requests, thus requesting "http://somehost/" instead of
  + "http://somehost.my.dom.ain/". Some commercial proxy servers let them get
  + away with this and simply serve the request, implying a configured
  + local domain. When the <A HREF="#proxydomain">ProxyDomain</A> directive
  + is used and the server is <A HREF="#proxyrequests">configured for
  + proxy service</A>, Apache can return a redirect response and send the client
  + to the correct, fully qualified, server address. This is the preferred method
  + since the user's bookmark files will then contain fully qualified hosts.</p>
    
    <!--#include virtual="footer.html" -->
    </BODY>
  
  
  
  1.346     +5 -0      apache/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache/src/CHANGES,v
  retrieving revision 1.345
  retrieving revision 1.346
  diff -C3 -r1.345 -r1.346
  *** CHANGES	1997/07/19 06:20:42	1.345
  --- CHANGES	1997/07/19 08:58:33	1.346
  ***************
  *** 1,5 ****
  --- 1,10 ----
    Changes with Apache 1.3
    
  +   *) Added NoProxy directive to avoid using ProxyRemote for selected
  +      addresses.  Added ProxyDomain directive to cause unqualified
  +      names to be qualified by redirection.
  +      [Martin Kraemer <Ma...@mch.sni.de>]
  + 
      *) Support Proxy Authentication, and don't pass the Proxy-Authorize
         header to the remote host in the proxy. [Sameer Parekh and
         Wallace]
  
  
  
  1.16      +182 -1    apache/src/modules/proxy/mod_proxy.c
  
  Index: mod_proxy.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/modules/proxy/mod_proxy.c,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -C3 -r1.15 -r1.16
  *** mod_proxy.c	1997/07/17 22:28:01	1.15
  --- mod_proxy.c	1997/07/19 08:58:34	1.16
  ***************
  *** 51,56 ****
  --- 51,57 ----
     */
    
    #include "mod_proxy.h"
  + #include "http_log.h"
    
    /* Some WWW schemes and their default ports; this is basically /etc/services */
    /* This will become global when the protocol abstraction comes */
  ***************
  *** 186,191 ****
  --- 187,262 ----
    } 
    
    
  + 
  + /* Send a redirection if the request contains a hostname which is not */
  + /* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
  + /* servers like Netscape's allow this and access hosts from the local */
  + /* domain in this case. I think it is better to redirect to a FQDN, since */
  + /* these will later be found in the bookmarks files. */
  + /* The "ProxyDomain" directive determines what domain will be appended */
  + int
  + proxy_needsdomain(request_rec *r, const char *url, const char *domain)
  + {
  +     char *scheme = pstrdup (r->pool, url);
  +     char *url_copy, *user = NULL, *password = NULL, *path, *err, *host;
  +     int port = -1;
  + 
  +     /* We only want to worry about GETs */
  +     if (r->method_number != M_GET) return DECLINED;
  + 
  +     /* Set url to the first char after "scheme://" */
  +     if ((url_copy = strchr(scheme,':')) == NULL
  + 	|| url_copy[1] != '/' || url_copy[2] != '/')
  + 	return DECLINED;
  + 
  +     *url_copy++ = '\0';	/* delimit scheme, make url_copy point to "//", which is what proxy_canon_netloc expects */
  + 
  +     /* Save the path - it will be re-appended for the redirection later */
  +     path = strchr(&url_copy[2], '/');
  +     if (path != NULL)
  + 	++path;	    /* leading '/' will be overwritten by proxy_canon_netloc */
  +     else
  + 	path = "";
  + 
  +     /* Split request into user, password, host, port */
  +     err = proxy_canon_netloc(r->pool, &url_copy, &user, &password, &host, &port);
  + 
  +     if (err != NULL)
  +     {
  + 	log_error(err, r->server);
  + 	return DECLINED;
  +     }
  + 
  +     /* If host does contain a dot already, or it is "localhost", decline */
  +     if (strchr (host, '.') != NULL || strcasecmp(host, "localhost") == 0)
  + 	return DECLINED;	/* host name has a dot already */
  +     else
  +     {
  + 	char *nuri;
  + 	char *ref = table_get(r->headers_in, "Referer");
  + 	char strport[10];
  + 
  + 	/* now, rebuild URL */
  + 	if (port == -1)
  + 	    strcpy (strport, "");
  + 	else
  + 	    ap_snprintf(strport, sizeof(strport), ":%d", port);
  + 
  + 	/* Reassemble the request, but insert the domain after the host name */
  + 	nuri = pstrcat(r->pool, scheme, "://", (user != NULL) ? user : "",
  + 		       (password != NULL) ? ":" : "",
  + 		       (password != NULL) ? password : "",
  + 		       (user != NULL) ? "@" : "",
  + 		       host, domain, strport, "/", path,
  + 		       NULL);
  + 
  + 	table_set(r->headers_out, "Location", nuri);
  + 	log_error(pstrcat(r->pool, "Domain missing: ", r->uri, " sent to ", nuri,
  + 		      ref ? " from " : NULL, ref, NULL), r->server);
  + 	return REDIRECT;
  +     }
  + }
  + 
    /* -------------------------------------------------------------- */
    /* Invoke handler */
     
  ***************
  *** 200,205 ****
  --- 271,277 ----
        struct proxy_remote *ents=(struct proxy_remote *)proxies->elts;
        int i, rc;
        struct cache_req *cr;
  +     int direct_connect = 0;
    
        if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
    
  ***************
  *** 213,224 ****
        rc = proxy_cache_check(r, url, &conf->cache, &cr);
        if (rc != DECLINED) return rc;
    
        *p = '\0';
        scheme = pstrdup(r->pool, url);
        *p = ':';
    
  ! /* firstly, try a proxy */
    
        for (i=0; i < proxies->nelts; i++)
        {
    	p = strchr(ents[i].scheme, ':');  /* is it a partial URL? */
  --- 285,328 ----
        rc = proxy_cache_check(r, url, &conf->cache, &cr);
        if (rc != DECLINED) return rc;
    
  +     /* If the host doesn't have a domain name, add one and redirect. */
  +     if (conf->domain != NULL
  + 	&& proxy_needsdomain(r, url, conf->domain) == REDIRECT)
  + 	return REDIRECT;
  + 
        *p = '\0';
        scheme = pstrdup(r->pool, url);
        *p = ':';
    
  !     /* Check URI's destination host against NoProxy hosts */
  !     /* Bypass ProxyRemote server lookup if configured as NoProxy */
  !     /* we only know how to handle communication to a proxy via http */
  !     /*if (strcmp(scheme, "http") == 0)*/
  !     {
  ! 	int i;
  ! 	struct dirconn_entry *list=(struct dirconn_entry*)conf->dirconn->elts;
  ! 
  ! /*        if (*++p == '/' && *++p == '/')   */
  ! 
  ! 	for (direct_connect=i=0; i < conf->dirconn->nelts && !direct_connect; i++)
  ! 	{
  ! 	    direct_connect = list[i].matcher (&list[i], r);
  ! 	    /*log_error("URI and NoProxy:", r->server);*/
  ! 	    /*log_error(r->uri, r->server);*/
  ! 	    /*log_error(list[i].name, r->server);*/
  ! 	}
  ! #if DEBUGGING
  ! 	{
  ! 	    char msg[256];
  ! 	    sprintf (msg, (direct_connect)?"NoProxy for %s":"UseProxy for %s", r->uri);
  ! 	    log_error(msg, r->server);
  ! 	}
  ! #endif
  !     }
  ! 	
  ! /* firstly, try a proxy, unless a NoProxy directive is active */
    
  +     if (!direct_connect)
        for (i=0; i < proxies->nelts; i++)
        {
    	p = strchr(ents[i].scheme, ':');  /* is it a partial URL? */
  ***************
  *** 264,270 ****
  --- 368,376 ----
      ps->proxies = make_array(p, 10, sizeof(struct proxy_remote));
      ps->aliases = make_array(p, 10, sizeof(struct proxy_alias));
      ps->noproxies = make_array(p, 10, sizeof(struct noproxy_entry));
  +   ps->dirconn = make_array(p, 10, sizeof(struct dirconn_entry));
      ps->nocaches = make_array(p, 10, sizeof(struct nocache_entry));
  +   ps->domain = NULL;
      ps->req = 0;
    
      ps->cache.root = NULL;
  ***************
  *** 366,371 ****
  --- 472,548 ----
        return NULL;
    }
    
  + /* Similar to set_proxy_exclude(), but defining directly connected hosts,
  +  * which should never be accessed via the configured ProxyRemote servers
  +  */
  + static const char *
  + set_proxy_dirconn(cmd_parms *parms, void *dummy, char *arg)
  + {
  +     server_rec *s = parms->server;
  +     proxy_server_conf *conf =
  + 	get_module_config (s->module_config, &proxy_module);
  +     struct dirconn_entry *New;
  +     struct dirconn_entry *list=(struct dirconn_entry*)conf->dirconn->elts;
  +     int found = 0;
  +     int i;
  + 
  +     /* Don't duplicate entries */
  +     for (i=0; i < conf->dirconn->nelts; i++)
  +     {
  + 	if (strcasecmp(arg, list[i].name) == 0)
  + 	    found = 1;
  +     }
  + 
  +     if (!found)
  +     {
  + 	New = push_array (conf->dirconn);
  + 	New->name = arg;
  + 
  + 	if (proxy_is_ipaddr(New))
  + 	{
  + #if DEBUGGING
  + 	    fprintf(stderr,"Parsed addr %s\n", inet_ntoa(New->addr));
  + 	    fprintf(stderr,"Parsed mask %s\n", inet_ntoa(New->mask));
  + #endif
  + 	}
  + 	else if (proxy_is_domainname(New))
  + 	{
  + 	    str_tolower(New->name);
  + #if DEBUGGING
  + 	    fprintf(stderr,"Parsed domain %s\n", New->name);
  + #endif
  + 	}
  + 	else if (proxy_is_hostname(New))
  + 	{
  + 	    str_tolower(New->name);
  + #if DEBUGGING
  + 	    fprintf(stderr,"Parsed host %s\n", New->name);
  + #endif
  + 	}
  + 	else
  + 	{
  + 	    proxy_is_word(New);
  + #if DEBUGGING
  + 	    fprintf(stderr,"Parsed word %s\n", New->name);
  + #endif
  + 	}
  +     }
  +     return NULL;
  + }
  + 
  + static const char *
  + set_proxy_domain(cmd_parms *parms, void *dummy, char *arg)
  + {
  +     proxy_server_conf *psf =
  + 	get_module_config (parms->server->module_config, &proxy_module);
  + 
  +     if (arg[0] != '.')
  + 	return "Domain name must start with a dot.";
  + 
  +     psf->domain = arg;
  +     return NULL;
  + }
  + 
    static const char *
    set_proxy_req(cmd_parms *parms, void *dummy, int flag)
    {
  ***************
  *** 519,524 ****
  --- 696,705 ----
        "a virtual path and a URL"},
    { "ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, ITERATE,
        "A list of names, hosts or domains to which the proxy will not connect" },
  + { "NoProxy", set_proxy_dirconn, NULL, RSRC_CONF, ITERATE,
  +     "A list of domains, hosts, or subnets to which the proxy will connect directly" },
  + { "ProxyDomain", set_proxy_domain, NULL, RSRC_CONF, TAKE1,
  +     "The default intranet domain name (in absence of a domain in the URL)" },
    { "CacheRoot", set_cache_root, NULL, RSRC_CONF, TAKE1,
          "The directory to store cache files"},
    { "CacheSize", set_cache_size, NULL, RSRC_CONF, TAKE1,
  
  
  
  1.13      +13 -0     apache/src/modules/proxy/mod_proxy.h
  
  Index: mod_proxy.h
  ===================================================================
  RCS file: /export/home/cvs/apache/src/modules/proxy/mod_proxy.h,v
  retrieving revision 1.12
  retrieving revision 1.13
  diff -C3 -r1.12 -r1.13
  *** mod_proxy.h	1997/06/15 19:22:47	1.12
  --- mod_proxy.h	1997/07/19 08:58:35	1.13
  ***************
  *** 151,156 ****
  --- 151,163 ----
        char *fake;
    };
    
  + struct dirconn_entry {
  +     char *name;
  +     struct in_addr addr,mask;
  +     struct hostent hostlist;
  +     int (*matcher)(struct dirconn_entry *This, request_rec *r);
  + };
  + 
    struct noproxy_entry {
        char *name;
        struct in_addr addr;
  ***************
  *** 185,191 ****
  --- 192,200 ----
        array_header *proxies;
        array_header *aliases;
        array_header *noproxies;
  +     array_header *dirconn;
        array_header *nocaches;
  +     char         *domain;    /* domain name to use in absence of a domain name in the request */
        int req;                 /* true if proxy requests are enabled */
    } proxy_server_conf;
    
  ***************
  *** 269,274 ****
  --- 278,287 ----
    BUFF *proxy_cache_error(struct cache_req *r);
    int proxyerror(request_rec *r, const char *message);
    const char *proxy_host2addr(const char *host, struct hostent *reqhp);
  + int proxy_is_ipaddr(struct dirconn_entry *This);
  + int proxy_is_domainname(struct dirconn_entry *This);
  + int proxy_is_hostname(struct dirconn_entry *This);
  + int proxy_is_word(struct dirconn_entry *This);
    int proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r);
    int proxy_garbage_init(server_rec *, pool *);
    
  
  
  
  1.24      +12 -0     apache/src/modules/proxy/proxy_ftp.c
  
  Index: proxy_ftp.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/modules/proxy/proxy_ftp.c,v
  retrieving revision 1.23
  retrieving revision 1.24
  diff -C3 -r1.23 -r1.24
  *** proxy_ftp.c	1997/06/16 19:32:53	1.23
  --- proxy_ftp.c	1997/07/19 08:58:35	1.24
  ***************
  *** 508,513 ****
  --- 508,524 ----
    	return SERVER_ERROR;
        }
    
  + #ifdef SINIX_D_RESOLVER_BUG
  +     { struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list;
  + 
  + 	for ( ; ip_addr->s_addr != 0; ++ip_addr) {
  + 	    memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr));
  + 	    i = proxy_doconnect(sock, &server, r);
  + 	    if (i == 0)
  + 		break;
  + 	}
  +     }
  + #else
        j = 0;
        while (server_hp.h_addr_list[j] != NULL) {
            memcpy(&server.sin_addr, server_hp.h_addr_list[j],
  ***************
  *** 517,522 ****
  --- 528,534 ----
                break; 
            j++;
        }   
  + #endif
        if (i == -1)
    	return proxyerror(r, "Could not connect to remote machine");
    
  
  
  
  1.22      +12 -0     apache/src/modules/proxy/proxy_http.c
  
  Index: proxy_http.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/modules/proxy/proxy_http.c,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -C3 -r1.21 -r1.22
  *** proxy_http.c	1997/07/19 06:20:49	1.21
  --- proxy_http.c	1997/07/19 08:58:35	1.22
  ***************
  *** 227,232 ****
  --- 227,243 ----
        note_cleanups_for_socket(pool, sock);
    
        
  + #ifdef SINIX_D_RESOLVER_BUG
  +     { struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list;
  + 
  + 	for ( ; ip_addr->s_addr != 0; ++ip_addr) {
  + 	    memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr));
  + 	    i = proxy_doconnect(sock, &server, r);
  + 	    if (i == 0)
  + 		break;
  + 	}
  +     }
  + #else
        j = 0;
        while (server_hp.h_addr_list[j] != NULL) {
    	memcpy(&server.sin_addr, server_hp.h_addr_list[j],
  ***************
  *** 236,241 ****
  --- 247,253 ----
    	    break;
    	j++;
        }
  + #endif
        if (i == -1)
        {
    	if (proxyhost != NULL) return DECLINED; /* try again another way */
  
  
  
  1.20      +357 -0    apache/src/modules/proxy/proxy_util.c
  
  Index: proxy_util.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/modules/proxy/proxy_util.c,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -C3 -r1.19 -r1.20
  *** proxy_util.c	1997/06/16 15:16:28	1.19
  --- proxy_util.c	1997/07/19 08:58:35	1.20
  ***************
  *** 56,61 ****
  --- 56,67 ----
    #include "http_main.h"
    #include "md5.h"
    #include "multithread.h"
  + #include "http_log.h"
  + 
  + static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r);
  + static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r);
  + static int proxy_match_hostname(struct dirconn_entry *This, request_rec *r);
  + static int proxy_match_word(struct dirconn_entry *This, request_rec *r);
    
    /* already called in the knowledge that the characters are hex digits */
    int
  ***************
  *** 245,250 ****
  --- 251,259 ----
    	    return "Bad IP address in URL";
        }
    
  + /*    if (strchr(host,'.') == NULL && domain != NULL)
  + 	host = pstrcat(pool, host, domain, NULL);
  + */
        *urlp = url;
        *hostp = host;
    
  ***************
  *** 796,801 ****
  --- 805,1158 ----
        }
        memcpy(reqhp, hp, sizeof(struct hostent));
        return NULL;
  + }
  + 
  + char *
  + proxy_get_host_of_request(request_rec *r)
  + {
  +     char *url, *user = NULL, *password = NULL, *err, *host;
  +     int port = -1;
  + 
  +     if (r->hostname != NULL)
  + 	return r->hostname;
  + 
  +     /* Set url to the first char after "scheme://" */
  +     if ((url = strchr(r->uri,':')) == NULL
  + 	|| url[1] != '/' || url[2] != '/')
  + 	return NULL;
  + 
  +     url = pstrdup(r->pool, &url[1]); /* make it point to "//", which is what proxy_canon_netloc expects */
  + 
  +     err = proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
  + 
  +     if (err != NULL)
  + 	log_error(err, r->server);
  + 
  +     r->hostname = host;
  + 
  +     return host;        /* ought to return the port, too */
  + }
  + 
  + /* Return TRUE if addr represents an IP address (or an IP network address)*/
  + int
  + proxy_is_ipaddr(struct dirconn_entry *This)
  + {
  +     const char *addr = This->name;
  +     unsigned long ip_addr[4];
  +     int i,quads;
  +     unsigned long bits;
  + 
  +     /* if the address is given with an explicit netmask, use that */
  +     /* Due to a deficiency in inet_addr(), it is impossible to parse */
  +     /* "partial" addresses (with less than 4 quads) correctly, i.e.  */
  +     /* 192.168.123 is parsed as 192.168.0.123, which is not what I want. */
  +     /* I therefore have to parse the IP address manually: */
  +     /*if (proxy_readmask(This->name, &This->addr.s_addr, &This->mask.s_addr) == 0)*/
  + 	/* addr and mask were set by proxy_readmask() */
  + 	/*return 1;*/
  + 
  +     /* Parse IP addr manually, optionally allowing */
  +     /* abbreviated net addresses like 192.168. */
  + 
  + /*    quads = sscanf(what, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1],
  + 				  &ip_addr[2], &ip_addr[3]);
  +     commented out: use of strtok() allows arbitrary base, like in:
  +     139.25.113.10 == 0x8b.0x19.0x71.0x0a
  +     (yes, inet_addr() can parse that, too!)
  +  */
  + 
  +     /* Iterate over up to 4 (dotted) quads. */
  +     for (quads=0; quads<4 && *addr != '\0'; ++quads)
  +     {
  + 	char *tmp;
  + 
  + 	if (*addr == '/' && quads > 0)  /* netmask starts here. */
  + 	    break;
  + 
  + 	if (!isdigit(*addr))
  + 	    return 0;       /* no digit at start of quad */
  + 
  + 	ip_addr[quads] = strtoul(addr, &tmp, 0);
  + 
  + 	if (tmp == addr)    /* expected a digit, found something else */
  + 	    return 0;
  + 
  + 	addr = tmp;
  + 
  + 	if (*addr == '.' && quads != 3)
  + 	    ++addr;            /* after the 4th quad, a dot would be illegal */
  +     }
  + 
  +     for (This->addr.s_addr = 0, i=0; i<quads; ++i)
  + 	This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8*i));
  + 
  +     if (addr[0] == '/' && isdigit(addr[1]))    /* net mask follows: */
  +     {
  + 	char *tmp;
  + 
  + 	++addr;
  + 
  + 	bits = strtoul(addr, &tmp, 0);
  + 
  + 	if (tmp == addr)    /* expected a digit, found something else */
  + 	    return 0;
  + 
  + 	addr = tmp;
  + 
  + 	if (bits > 32)    /* netmask must be between 0 and 32 */
  + 	    return 0;
  + 
  +     }
  +     else
  +     {
  + 	/* Determine (i.e., "guess") netmask by counting the */
  + 	/* number of trailing .0's; reduce #quads appropriately */
  + 	/* (so that 192.168.0.0 is equivalent to 192.168.)        */
  + 	while (quads > 0 && ip_addr[quads-1] == 0)
  + 	    --quads;
  + 
  + 	/* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
  + 	if (quads < 1)
  + 	    return 0;
  + 
  + 	/* every zero-byte counts as 8 zero-bits */
  + 	bits = 8*quads;
  + 
  + 	if (bits != 32)  /* no warning for fully qualified IP address */
  + 	    fprintf(stderr,"Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld\n",
  + 			   inet_ntoa(This->addr), bits);
  +     }
  + 
  +     This->mask.s_addr = htonl(INADDR_NONE << (32 - bits));
  + 
  +     if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0)
  +     {
  + 	fprintf(stderr,"Warning: NetMask and IP-Addr disagree in %s/%ld\n",
  + 		       inet_ntoa(This->addr), bits);
  + 	This->addr.s_addr &= This->mask.s_addr;
  + 	fprintf(stderr,"         Set to %s/%ld\n",
  + 		       inet_ntoa(This->addr), bits);
  +     }
  + 
  +     if (*addr == '\0')
  +     {
  + 	This->matcher = proxy_match_ipaddr;
  + 	return 1;
  +     }
  +     else
  +     return (*addr == '\0');   /* okay iff we've parsed the whole string */
  + }
  + 
  + /* Return TRUE if addr represents an IP address (or an IP network address)*/
  + static int
  + proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r)
  + {
  +     int i;
  +     int ip_addr[4];
  +     struct in_addr addr;
  +     struct in_addr *ip_list;
  +     const char *found;
  +     const char *host = proxy_get_host_of_request(r);
  + 
  +     memset (&addr, '\0', sizeof addr);
  +     memset (ip_addr, '\0', sizeof ip_addr);
  + 
  +     if ( 4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3]))
  +     {
  + 	for (addr.s_addr = 0, i=0; i<4; ++i)
  + 	    addr.s_addr |= htonl(ip_addr[i] << (24 - 8*i));
  + 
  + 	if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr))
  + 	{
  + #if DEBUGGING
  + 	    fprintf(stderr,"1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
  + 	    fprintf(stderr,"%s/", inet_ntoa(This->addr));
  + 	    fprintf(stderr,"%s\n", inet_ntoa(This->mask));
  + #endif
  + 	    return 1;
  + 	}
  + #if DEBUGGING
  + 	else
  + 	{
  + 	    fprintf(stderr,"1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
  + 	    fprintf(stderr,"%s/", inet_ntoa(This->addr));
  + 	    fprintf(stderr,"%s\n", inet_ntoa(This->mask));
  + 	}
  + #endif
  +     }
  +     else
  +     {
  + 	struct hostent the_host;
  + 
  + 	memset (&the_host, '\0', sizeof the_host);
  + 	found = proxy_host2addr(host, &the_host);
  + 
  + 	if ( found != NULL )
  + 	{
  + #if DEBUGGING
  + 	    fprintf(stderr,"2)IP-NoMatch: hostname=%s msg=%s\n", host, found);
  + #endif
  + 	    return 0;
  + 	}
  + 
  + 	if (the_host.h_name != NULL)
  + 	    found = the_host.h_name;
  + 	else
  + 	    found = host;
  + 
  + 	/* Try to deal with multiple IP addr's for a host */
  + 	for (ip_list = (struct in_addr *) *the_host.h_addr_list; ip_list->s_addr != 0UL; ++ip_list)
  + 	    if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr))
  + 	    {
  + #if DEBUGGING
  + 		fprintf(stderr,"3)IP-Match: %s[%s] <-> ", found, inet_ntoa(*ip_list));
  + 		fprintf(stderr,"%s/", inet_ntoa(This->addr));
  + 		fprintf(stderr,"%s\n", inet_ntoa(This->mask));
  + #endif
  + 		return 1;
  + 	    }
  + #if DEBUGGING
  + 	    else
  + 	    {
  + 		fprintf(stderr,"3)IP-NoMatch: %s[%s] <-> ", found, inet_ntoa(*ip_list));
  + 		fprintf(stderr,"%s/", inet_ntoa(This->addr));
  + 		fprintf(stderr,"%s\n", inet_ntoa(This->mask));
  + 	    }
  + #endif
  +     }
  + 
  +     /* Use net math to determine if a host lies in a subnet */
  +     /*return This->addr.s_addr == (r->connection->remote_addr.sin_addr.s_addr & This->mask.s_addr);*/
  +     return 0;
  + }
  + 
  + /* Return TRUE if addr represents a domain name */
  + int
  + proxy_is_domainname(struct dirconn_entry *This)
  + {
  +     char *addr = This->name;
  +     int i;
  + 
  +     /* Domain name must start with a '.' */
  +     if (addr[0] != '.')
  + 	return 0;
  + 
  +     /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
  +     for (i=0; isalnum(addr[i]) || addr[i]=='-' || addr[i]=='.'; ++i)
  + 	;
  + 
  +     if (addr[i] == ':')
  +     {
  + 	fprintf(stderr,"@@@@ handle optional port in proxy_is_domainname()\n");
  + 	/* @@@@ handle optional port */
  +     }
  + 
  +     if (addr[i] != '\0')
  + 	return 0;
  + 
  +     /* Strip trailing dots */
  +     for (i=strlen(addr)-1; i>0 && addr[i] == '.'; --i)
  + 	addr[i] = '\0';
  + 
  +     This->matcher = proxy_match_domainname;
  +     return 1;
  + }
  + 
  + /* Return TRUE if host "host" is in domain "domain" */
  + static int
  + proxy_match_domainname(struct dirconn_entry *This, request_rec *r)
  + {
  +     const char *host = proxy_get_host_of_request(r);
  +     int d_len=strlen(This->name), h_len;
  + 
  +     if (host == NULL)   /* some error was logged already */
  + 	return 0;
  + 
  +     h_len = strlen(host);
  + 
  +     /* @@@ do this within the setup? */
  +     /* Ignore trailing dots in domain comparison: */
  +     while (d_len > 0 && This->name[d_len-1] == '.')
  + 	--d_len;
  +     while (h_len > 0 && host[h_len-1] == '.')
  + 	--h_len;
  +     return h_len > d_len
  + 	&& strncasecmp(&host[h_len-d_len], This->name, d_len) == 0;
  + }
  + 
  + /* Return TRUE if addr represents a host name */
  + int
  + proxy_is_hostname(struct dirconn_entry *This)
  + {
  +     char *addr = This->name;
  +     int i;
  + 
  +     /* Host names must not start with a '.' */
  +     if (addr[0] == '.')
  + 	return 0;
  + 
  +     /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
  +     for (i=0; isalnum(addr[i]) || addr[i]=='-' || addr[i]=='.'; ++i)
  + 	;
  + 
  +     if (addr[i] == ':')
  +     {
  + 	fprintf(stderr,"@@@@ handle optional port in proxy_is_hostname()\n");
  + 	/* @@@@ handle optional port */
  +     }
  + 
  +     if (addr[i] != '\0' || proxy_host2addr(addr, &This->hostlist) != NULL)
  + 	return 0;
  + 
  +     /* Strip trailing dots */
  +     for (i=strlen(addr)-1; i>0 && addr[i] == '.'; --i)
  + 	addr[i] = '\0';
  + 
  +     This->matcher = proxy_match_hostname;
  +     return 1;
  + }
  + 
  + /* Return TRUE if host "host" is equal to host2 "host2" */
  + static int
  + proxy_match_hostname(struct dirconn_entry *This, request_rec *r)
  + {
  +     char *host = This->name;
  +     char *host2 = proxy_get_host_of_request(r);
  +     int h2_len=strlen(host2);
  +     int h1_len=strlen(host);
  + 
  + #if 0
  +     unsigned long *ip_list;
  + 
  +     /* Try to deal with multiple IP addr's for a host */
  +     for (ip_list = *This->hostlist.h_addr_list; *ip_list != 0UL; ++ip_list)
  + 	if (*ip_list == ?????????????)
  + 	    return 1;
  + #endif
  + 
  +     /* Ignore trailing dots in host2 comparison: */
  +     while (h2_len > 0 && host2[h2_len-1] == '.')
  + 	--h2_len;
  +     while (h1_len > 0 && host[h1_len-1] == '.')
  + 	--h1_len;
  +     return h1_len == h2_len
  + 	&& strncasecmp(host, host2, h1_len) == 0;
  + }
  + 
  + /* Return TRUE if addr is to be matched as a word */
  + int
  + proxy_is_word(struct dirconn_entry *This)
  + {
  +     This->matcher = proxy_match_word;
  +     return 1;
  + }
  + 
  + /* Return TRUE if string "str2" occurs literally in "str1" */
  + static int
  + proxy_match_word(struct dirconn_entry *This, request_rec *r)
  + {
  +     char *host = proxy_get_host_of_request(r);
  +     return host != NULL  &&  strstr(host, This->name) != NULL;
    }
    
    int