httpd-modules-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ray Morris <supp...@bettercgi.com>
Subject Re: secure use of ap_get_server_name/port
Date Thu, 06 Mar 2008 22:32:09 GMT
On 03/06/2008 01:09:37 PM, Nebergall, Christopher wrote:
> I'm looking for secure versions of ap_get_server_name and
> ap_get_server_port which can be trusted to always evaluate 
> to the correct host and port for re-constructing the original
> URL the user requested.   

  The text part of your question seems to contradict itself
regarding what you're actually wanting, then the code gives
a third result.  Let's be sure exactly what you want.  If
you really do want to reconstruct the orginal URL requested,
the hostname will be found in headers_in:


host = apr_pstrdup( r->pool, apr_table_get(r->main->headers_in, "Host")
);
if (host == NULL) {
    # The client didn't specify a hostname, so punt:
    host = apr_pstrdup( r->pool, ap_get_server_name(r) );
    if (host == NULL) return 0;
}


> I've removed all of the code below which seemed to 
> rely on DNS, or info sent from the client. 

  I thought you wanted to reconstruct what the client sent, 
but now you say you want to remove any reference to what
the client sent?  You're asking for two opposite things.  



> It seems that if the ServerName directive is there 
> it should return a value and that would be it.  

   The ServerName may have no relationship at all to
the original URL requested by the client, which is what
you said you wanted.

ServerName foo.com
ServerAlias bob.smith.bar.com

GET http://bob.smith.bar.com/
   

> I'm confused why there are so many different ways to 
> get the hostname or port. 

  Assume this configuration and no other hosts on the 
server for the four following requests:

ServerName foo.com
ServerAlias bob.smith.bar.com *.jones.com

CASE 1
Assume this request:
GET http://bob.smith.bar.com/

  There are at least two "correct" answers for the hostname - 
one can get the value of ServerName, as you mentioned, or
one cause use the ServerAlias which matched the request.
So we need to functions to do the two different things.
Given the possibility of UseCanonicalName, we may want 
three functions - one for the first answer, one for the 
second answer, and one that respects that silly UseCanonicalName
directive.

CASE 2
Assume this request:
GET http://joe.jones.com/

  Now we have three hostnames you be interested in -
the specified ServerName, foo.com, the alias that matched, 
*.jones.com, and the actual hostname requested,
joe.jones.com.  Throw in the fact that UseCanonicalName
may be on or off and you need four functions in order
to be able to get whichever answer you seek.

CASE 3
Assume noname.com resolves to 123.123.123.123, 
an IP on this server.

Assume this request:
GET http://noname.com/

  Now we have four possible answers - the value of ServerName, 
the the requested host name, or the match, which is just the
IP - or is it an empty name?

  I could go on and on, but I think the point is clear -
there are a lot of ways to get different hostnames, 
depending on what you're looking for.  You say you are
confused about why there are so many ways to get the
host name, but then again you're also confused about 
which hostname you want - the one from the original 
request or the one from the ServerName directive.  
One could also throw in the possibility that this 
request isn't the orginal request, but is a sub-request.
In that case there could up to twelve different answers 
you may be interested in - the four answers from case 4,
each regarding THIS request, it's parent, or the main 
original request.

   In most cases, the best one to use is probably the
hostname that was actually requested for this request:
apr_table_get(r->headers_in, "Host")
There may be a better way to get that information. I'm
somewhat new to Apache module programming.
--
Ray B. Morris
support@bettercgi.com

Strongbox - The next generation in site security:
http://www.bettercgi.com/strongbox/




On 03/06/2008 01:09:37 PM, Nebergall, Christopher wrote:
> I'm looking for secure versions of ap_get_server_name and
> ap_get_server_port which can be trusted to always evaluate to the
> correct host and port for re-constructing the original URL the user
> requested.   I've removed all of the code below which seemed to rely
> on DNS, or info sent from the client.  Is the code below a sufficient
> minimal set to get working secure versions of those functions?  I'm
> confused why there are so many different ways to get the hostname or
> port.  It seems that if the ServerName directive is there it should
> return a value and that would be it.   Also why would code like cport
> below ever be zero?
> 
> API_EXPORT(const char *) ap_get_server_name2(request_rec *r)
> {
>         return r->hostname?r->hostname:r->server->server_hostname;
> }
> 
> API_EXPORT(unsigned) ap_get_server_port2(const request_rec *r)
> {
>     unsigned port;
>     unsigned cport = ntohs(r->connection->local_addr.sin_port);
>     port = cport ? cport : r->server->port ? r->server->port :
> ap_default_port(r);
>     return port;
> }
> 
> -Christopher
> 
> Original apache 1.3 code
> 
> -----------------------------------------------------------------------------------------------------------------
> API_EXPORT(const char *) ap_get_server_name(request_rec *r)
> {
>     conn_rec *conn = r->connection;
>     core_dir_config *d;
> 
>     d = (core_dir_config *)ap_get_module_config(r->per_dir_config,
>                                                 &core_module);
> 
>     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
>         return r->hostname ? r->hostname :
> r->server->server_hostname;
>     }
>     if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
>         if (conn->local_host == NULL) {
>             struct in_addr *iaddr;
>             struct hostent *hptr;
>             int old_stat;
>             old_stat = ap_update_child_status(conn->child_num,
>                                               SERVER_BUSY_DNS, r);
>             iaddr = &(conn->local_addr.sin_addr);
>             hptr = gethostbyaddr((char *)iaddr, sizeof(struct
> in_addr),
>                                  AF_INET);
>             if (hptr != NULL) {
>                 conn->local_host = ap_pstrdup(conn->pool,
>                                               (void *)hptr->h_name);
>                 ap_str_tolower(conn->local_host);
>             }
>             else {
>                 conn->local_host = ap_pstrdup(conn->pool,
> 
> r->server->server_hostname);
>             }
>             (void) ap_update_child_status(conn->child_num, old_stat,
> r);
>         }
>         return conn->local_host;
>     }
>     /* default */
>     return r->server->server_hostname;
> }
> 
> API_EXPORT(unsigned) ap_get_server_port(const request_rec *r)
> {
>     unsigned port;
>     unsigned cport = ntohs(r->connection->local_addr.sin_port);
>     core_dir_config *d =
>       (core_dir_config *)ap_get_module_config(r->per_dir_config,
> &core_module);
> 
>     if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
>         || d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
> 
>         /* With UseCanonicalName Off Apache will form
> self-referential
>          * URLs using the hostname and port supplied by the client if
>          * any are supplied (otherwise it will use the canonical
> name).
>          */
>         port = r->parsed_uri.port_str ? r->parsed_uri.port :
>           cport ? cport :
>             r->server->port ? r->server->port :
>               ap_default_port(r);
>     } else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
>         port = r->server->port ? r->server->port :
>           cport ? cport :
>             ap_default_port(r);
>     }
> 
>     /* default */
>     return port;
> }
> 
> 


Mime
View raw message