Blame server/vhost.c

Packit 90a5c9
/* Licensed to the Apache Software Foundation (ASF) under one or more
Packit 90a5c9
 * contributor license agreements.  See the NOTICE file distributed with
Packit 90a5c9
 * this work for additional information regarding copyright ownership.
Packit 90a5c9
 * The ASF licenses this file to You under the Apache License, Version 2.0
Packit 90a5c9
 * (the "License"); you may not use this file except in compliance with
Packit 90a5c9
 * the License.  You may obtain a copy of the License at
Packit 90a5c9
 *
Packit 90a5c9
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 90a5c9
 *
Packit 90a5c9
 * Unless required by applicable law or agreed to in writing, software
Packit 90a5c9
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 90a5c9
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 90a5c9
 * See the License for the specific language governing permissions and
Packit 90a5c9
 * limitations under the License.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * @file  vhost.c
Packit 90a5c9
 * @brief functions pertaining to virtual host addresses
Packit 90a5c9
 *        (configuration and run-time)
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
#include "apr.h"
Packit 90a5c9
#include "apr_strings.h"
Packit 90a5c9
#include "apr_lib.h"
Packit 90a5c9
Packit 90a5c9
#define APR_WANT_STRFUNC
Packit 90a5c9
#include "apr_want.h"
Packit 90a5c9
Packit 90a5c9
#include "ap_config.h"
Packit 90a5c9
#include "httpd.h"
Packit 90a5c9
#include "http_config.h"
Packit 90a5c9
#include "http_log.h"
Packit 90a5c9
#include "http_vhost.h"
Packit 90a5c9
#include "http_protocol.h"
Packit 90a5c9
#include "http_core.h"
Packit 90a5c9
Packit 90a5c9
#if APR_HAVE_ARPA_INET_H
Packit 90a5c9
#include <arpa/inet.h>
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/* we know core's module_index is 0 */
Packit 90a5c9
#undef APLOG_MODULE_INDEX
Packit 90a5c9
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * After all the definitions there's an explanation of how it's all put
Packit 90a5c9
 * together.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
/* meta-list of name-vhosts.  Each server_rec can be in possibly multiple
Packit 90a5c9
 * lists of name-vhosts.
Packit 90a5c9
 */
Packit 90a5c9
typedef struct name_chain name_chain;
Packit 90a5c9
struct name_chain {
Packit 90a5c9
    name_chain *next;
Packit 90a5c9
    server_addr_rec *sar;       /* the record causing it to be in
Packit 90a5c9
                                 * this chain (needed for port comparisons) */
Packit 90a5c9
    server_rec *server;         /* the server to use on a match */
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
/* meta-list of ip addresses.  Each server_rec can be in possibly multiple
Packit 90a5c9
 * hash chains since it can have multiple ips.
Packit 90a5c9
 */
Packit 90a5c9
typedef struct ipaddr_chain ipaddr_chain;
Packit 90a5c9
struct ipaddr_chain {
Packit 90a5c9
    ipaddr_chain *next;
Packit 90a5c9
    server_addr_rec *sar;       /* the record causing it to be in
Packit 90a5c9
                                 * this chain (need for both ip addr and port
Packit 90a5c9
                                 * comparisons) */
Packit 90a5c9
    server_rec *server;         /* the server to use if this matches */
Packit 90a5c9
    name_chain *names;          /* if non-NULL then a list of name-vhosts
Packit 90a5c9
                                 * sharing this address */
Packit 90a5c9
    name_chain *initialnames;   /* no runtime use, temporary storage of first
Packit 90a5c9
                                 * NVH'es names */
Packit 90a5c9
};
Packit 90a5c9
Packit 90a5c9
/* This defines the size of the hash table used for hashing ip addresses
Packit 90a5c9
 * of virtual hosts.  It must be a power of two.
Packit 90a5c9
 */
Packit 90a5c9
#ifndef IPHASH_TABLE_SIZE
Packit 90a5c9
#define IPHASH_TABLE_SIZE 256
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
/* A (n) bucket hash table, each entry has a pointer to a server rec and
Packit 90a5c9
 * a pointer to the other entries in that bucket.  Each individual address,
Packit 90a5c9
 * even for virtualhosts with multiple addresses, has an entry in this hash
Packit 90a5c9
 * table.  There are extra buckets for _default_, and name-vhost entries.
Packit 90a5c9
 *
Packit 90a5c9
 * Note that after config time this is constant, so it is thread-safe.
Packit 90a5c9
 */
Packit 90a5c9
static ipaddr_chain *iphash_table[IPHASH_TABLE_SIZE];
Packit 90a5c9
Packit 90a5c9
/* dump out statistics about the hash function */
Packit 90a5c9
/* #define IPHASH_STATISTICS */
Packit 90a5c9
Packit 90a5c9
/* list of the _default_ servers */
Packit 90a5c9
static ipaddr_chain *default_list;
Packit 90a5c9
Packit 90a5c9
/* whether a config error was seen */
Packit 90a5c9
static int config_error = 0;
Packit 90a5c9
Packit 90a5c9
/* config check function */
Packit 90a5c9
static int vhost_check_config(apr_pool_t *p, apr_pool_t *plog,
Packit 90a5c9
                              apr_pool_t *ptemp, server_rec *s);
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * How it's used:
Packit 90a5c9
 *
Packit 90a5c9
 * The ip address determines which chain in iphash_table is interesting, then
Packit 90a5c9
 * a comparison is done down that chain to find the first ipaddr_chain whose
Packit 90a5c9
 * sar matches the address:port pair.
Packit 90a5c9
 *
Packit 90a5c9
 * If that ipaddr_chain has names == NULL then you're done, it's an ip-vhost.
Packit 90a5c9
 *
Packit 90a5c9
 * Otherwise it's a name-vhost list, and the default is the server in the
Packit 90a5c9
 * ipaddr_chain record.  We tuck away the ipaddr_chain record in the
Packit 90a5c9
 * conn_rec field vhost_lookup_data.  Later on after the headers we get a
Packit 90a5c9
 * second chance, and we use the name_chain to figure out what name-vhost
Packit 90a5c9
 * matches the headers.
Packit 90a5c9
 *
Packit 90a5c9
 * If there was no ip address match in the iphash_table then do a lookup
Packit 90a5c9
 * in the default_list.
Packit 90a5c9
 *
Packit 90a5c9
 * How it's put together ... well you should be able to figure that out
Packit 90a5c9
 * from how it's used.  Or something like that.
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* called at the beginning of the config */
Packit 90a5c9
AP_DECLARE(void) ap_init_vhost_config(apr_pool_t *p)
Packit 90a5c9
{
Packit 90a5c9
    memset(iphash_table, 0, sizeof(iphash_table));
Packit 90a5c9
    default_list = NULL;
Packit 90a5c9
    ap_hook_check_config(vhost_check_config, NULL, NULL, APR_HOOK_MIDDLE);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * Parses a host of the form <address>[:port]
Packit 90a5c9
 * paddr is used to create a list in the order of input
Packit 90a5c9
 * **paddr is the ->next pointer of the last entry (or s->addrs)
Packit 90a5c9
 * *paddr is the variable used to keep track of **paddr between calls
Packit 90a5c9
 * port is the default port to assume
Packit 90a5c9
 */
Packit 90a5c9
static const char *get_addresses(apr_pool_t *p, const char *w_,
Packit 90a5c9
                                 server_addr_rec ***paddr,
Packit 90a5c9
                                 apr_port_t default_port)
Packit 90a5c9
{
Packit 90a5c9
    apr_sockaddr_t *my_addr;
Packit 90a5c9
    server_addr_rec *sar;
Packit 90a5c9
    char *w, *host, *scope_id;
Packit 90a5c9
    int wild_port;
Packit 90a5c9
    apr_size_t wlen;
Packit 90a5c9
    apr_port_t port;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
Packit 90a5c9
    if (*w_ == '\0')
Packit 90a5c9
        return NULL;
Packit 90a5c9
Packit 90a5c9
    wlen = strlen(w_);                   /* wlen must be > 0 at this point */
Packit 90a5c9
    w = apr_pstrmemdup(p, w_, wlen);
Packit 90a5c9
    /* apr_parse_addr_port() doesn't understand ":*" so handle that first. */
Packit 90a5c9
    wild_port = 0;
Packit 90a5c9
    if (w[wlen - 1] == '*') {
Packit 90a5c9
        if (wlen < 2) {
Packit 90a5c9
            wild_port = 1;
Packit 90a5c9
        }
Packit 90a5c9
        else if (w[wlen - 2] == ':') {
Packit 90a5c9
            w[wlen - 2] = '\0';
Packit 90a5c9
            wild_port = 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    rv = apr_parse_addr_port(&host, &scope_id, &port, w, p);
Packit 90a5c9
    /* If the string is "80", apr_parse_addr_port() will be happy and set
Packit 90a5c9
     * host to NULL and port to 80, so watch out for that.
Packit 90a5c9
     */
Packit 90a5c9
    if (rv != APR_SUCCESS) {
Packit 90a5c9
        return "The address or port is invalid";
Packit 90a5c9
    }
Packit 90a5c9
    if (!host) {
Packit 90a5c9
        return "Missing address for VirtualHost";
Packit 90a5c9
    }
Packit 90a5c9
    if (scope_id) {
Packit 90a5c9
        return "Scope ids are not supported";
Packit 90a5c9
    }
Packit 90a5c9
    if (!port && !wild_port) {
Packit 90a5c9
        port = default_port;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (strcmp(host, "*") == 0 || strcasecmp(host, "_default_") == 0) {
Packit 90a5c9
        rv = apr_sockaddr_info_get(&my_addr, NULL, APR_UNSPEC, port, 0, p);
Packit 90a5c9
        if (rv) {
Packit 90a5c9
            return "Could not determine a wildcard address ('0.0.0.0') -- "
Packit 90a5c9
                "check resolver configuration.";
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        rv = apr_sockaddr_info_get(&my_addr, host, APR_UNSPEC, port, 0, p);
Packit 90a5c9
        if (rv != APR_SUCCESS) {
Packit 90a5c9
            ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO(00547)
Packit 90a5c9
                "Could not resolve host name %s -- ignoring!", host);
Packit 90a5c9
            return NULL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* Remember all addresses for the host */
Packit 90a5c9
Packit 90a5c9
    do {
Packit 90a5c9
        sar = apr_pcalloc(p, sizeof(server_addr_rec));
Packit 90a5c9
        **paddr = sar;
Packit 90a5c9
        *paddr = &sar->next;
Packit 90a5c9
        sar->host_addr = my_addr;
Packit 90a5c9
        sar->host_port = port;
Packit 90a5c9
        sar->virthost = host;
Packit 90a5c9
        my_addr = my_addr->next;
Packit 90a5c9
    } while (my_addr);
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* parse the <VirtualHost> addresses */
Packit 90a5c9
const char *ap_parse_vhost_addrs(apr_pool_t *p,
Packit 90a5c9
                                 const char *hostname,
Packit 90a5c9
                                 server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    server_addr_rec **addrs;
Packit 90a5c9
    const char *err;
Packit 90a5c9
Packit 90a5c9
    /* start the list of addresses */
Packit 90a5c9
    addrs = &s->addrs;
Packit 90a5c9
    while (hostname[0]) {
Packit 90a5c9
        err = get_addresses(p, ap_getword_conf(p, &hostname), &addrs, s->port);
Packit 90a5c9
        if (err) {
Packit 90a5c9
            *addrs = NULL;
Packit 90a5c9
            return err;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    /* terminate the list */
Packit 90a5c9
    *addrs = NULL;
Packit 90a5c9
    if (s->addrs) {
Packit 90a5c9
        if (s->addrs->host_port) {
Packit 90a5c9
            /* override the default port which is inherited from main_server */
Packit 90a5c9
            s->port = s->addrs->host_port;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
AP_DECLARE_NONSTD(const char *)ap_set_name_virtual_host(cmd_parms *cmd,
Packit 90a5c9
                                                        void *dummy,
Packit 90a5c9
                                                        const char *arg)
Packit 90a5c9
{
Packit 90a5c9
    static int warnonce = 0;
Packit 90a5c9
    if (++warnonce == 1) {
Packit 90a5c9
        ap_log_error(APLOG_MARK, APLOG_NOTICE|APLOG_STARTUP, APR_SUCCESS, NULL, APLOGNO(00548)
Packit 90a5c9
                     "NameVirtualHost has no effect and will be removed in the "
Packit 90a5c9
                     "next release %s:%d",
Packit 90a5c9
                     cmd->directive->filename,
Packit 90a5c9
                     cmd->directive->line_num);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return NULL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* hash table statistics, keep this in here for the beta period so
Packit 90a5c9
 * we can find out if the hash function is ok
Packit 90a5c9
 */
Packit 90a5c9
#ifdef IPHASH_STATISTICS
Packit 90a5c9
static int iphash_compare(const void *a, const void *b)
Packit 90a5c9
{
Packit 90a5c9
    return (*(const int *) b - *(const int *) a);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static void dump_iphash_statistics(server_rec *main_s)
Packit 90a5c9
{
Packit 90a5c9
    unsigned count[IPHASH_TABLE_SIZE];
Packit 90a5c9
    int i;
Packit 90a5c9
    ipaddr_chain *src;
Packit 90a5c9
    unsigned total;
Packit 90a5c9
    char buf[HUGE_STRING_LEN];
Packit 90a5c9
    char *p;
Packit 90a5c9
Packit 90a5c9
    total = 0;
Packit 90a5c9
    for (i = 0; i < IPHASH_TABLE_SIZE; ++i) {
Packit 90a5c9
        count[i] = 0;
Packit 90a5c9
        for (src = iphash_table[i]; src; src = src->next) {
Packit 90a5c9
            ++count[i];
Packit 90a5c9
            if (i < IPHASH_TABLE_SIZE) {
Packit 90a5c9
                /* don't count the slop buckets in the total */
Packit 90a5c9
                ++total;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    qsort(count, IPHASH_TABLE_SIZE, sizeof(count[0]), iphash_compare);
Packit 90a5c9
    p = buf + apr_snprintf(buf, sizeof(buf),
Packit 90a5c9
                           APLOGNO(03235) "iphash: total hashed = %u, avg chain = %u, "
Packit 90a5c9
                           "chain lengths (count x len):",
Packit 90a5c9
                           total, total / IPHASH_TABLE_SIZE);
Packit 90a5c9
    total = 1;
Packit 90a5c9
    for (i = 1; i < IPHASH_TABLE_SIZE; ++i) {
Packit 90a5c9
        if (count[i - 1] != count[i]) {
Packit 90a5c9
            p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u",
Packit 90a5c9
                              total, count[i - 1]);
Packit 90a5c9
            total = 1;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            ++total;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u",
Packit 90a5c9
                      total, count[IPHASH_TABLE_SIZE - 1]);
Packit 90a5c9
    /* Intentional no APLOGNO */
Packit 90a5c9
    /* buf provides APLOGNO */
Packit 90a5c9
    ap_log_error(APLOG_MARK, APLOG_DEBUG, main_s, buf);
Packit 90a5c9
}
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* This hashing function is designed to get good distribution in the cases
Packit 90a5c9
 * where the server is handling entire "networks" of servers.  i.e. a
Packit 90a5c9
 * whack of /24s.  This is probably the most common configuration for
Packit 90a5c9
 * ISPs with large virtual servers.
Packit 90a5c9
 *
Packit 90a5c9
 * NOTE: This function is symmetric (i.e. collapses all 4 octets
Packit 90a5c9
 * into one), so machine byte order (big/little endianness) does not matter.
Packit 90a5c9
 *
Packit 90a5c9
 * Hash function provided by David Hankins.
Packit 90a5c9
 */
Packit 90a5c9
static APR_INLINE unsigned hash_inaddr(unsigned key)
Packit 90a5c9
{
Packit 90a5c9
    key ^= (key >> 16);
Packit 90a5c9
    return ((key >> 8) ^ key) % IPHASH_TABLE_SIZE;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static APR_INLINE unsigned hash_addr(struct apr_sockaddr_t *sa)
Packit 90a5c9
{
Packit 90a5c9
    unsigned key;
Packit 90a5c9
Packit 90a5c9
    /* The key is the last four bytes of the IP address.
Packit 90a5c9
     * For IPv4, this is the entire address, as always.
Packit 90a5c9
     * For IPv6, this is usually part of the MAC address.
Packit 90a5c9
     */
Packit 90a5c9
    key = *(unsigned *)((char *)sa->ipaddr_ptr + sa->ipaddr_len - 4);
Packit 90a5c9
    return hash_inaddr(key);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static ipaddr_chain *new_ipaddr_chain(apr_pool_t *p,
Packit 90a5c9
                                      server_rec *s, server_addr_rec *sar)
Packit 90a5c9
{
Packit 90a5c9
    ipaddr_chain *new;
Packit 90a5c9
Packit 90a5c9
    new = apr_palloc(p, sizeof(*new));
Packit 90a5c9
    new->names = NULL;
Packit 90a5c9
    new->initialnames = NULL;
Packit 90a5c9
    new->server = s;
Packit 90a5c9
    new->sar = sar;
Packit 90a5c9
    new->next = NULL;
Packit 90a5c9
    return new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static name_chain *new_name_chain(apr_pool_t *p,
Packit 90a5c9
                                  server_rec *s, server_addr_rec *sar)
Packit 90a5c9
{
Packit 90a5c9
    name_chain *new;
Packit 90a5c9
Packit 90a5c9
    new = apr_palloc(p, sizeof(*new));
Packit 90a5c9
    new->server = s;
Packit 90a5c9
    new->sar = sar;
Packit 90a5c9
    new->next = NULL;
Packit 90a5c9
    return new;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static APR_INLINE ipaddr_chain *find_ipaddr(apr_sockaddr_t *sa)
Packit 90a5c9
{
Packit 90a5c9
    unsigned bucket;
Packit 90a5c9
    ipaddr_chain *trav = NULL;
Packit 90a5c9
    ipaddr_chain *wild_match = NULL;
Packit 90a5c9
Packit 90a5c9
    /* scan the hash table for an exact match first */
Packit 90a5c9
    bucket = hash_addr(sa);
Packit 90a5c9
    for (trav = iphash_table[bucket]; trav; trav = trav->next) {
Packit 90a5c9
        server_addr_rec *sar = trav->sar;
Packit 90a5c9
        apr_sockaddr_t *cur = sar->host_addr;
Packit 90a5c9
Packit 90a5c9
        if (cur->port == sa->port) {
Packit 90a5c9
            if (apr_sockaddr_equal(cur, sa)) {
Packit 90a5c9
                return trav;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        if (wild_match == NULL && (cur->port == 0 || sa->port == 0)) {
Packit 90a5c9
            if (apr_sockaddr_equal(cur, sa)) {
Packit 90a5c9
                /* don't break, continue looking for an exact match */
Packit 90a5c9
                wild_match = trav;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return wild_match;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static ipaddr_chain *find_default_server(apr_port_t port)
Packit 90a5c9
{
Packit 90a5c9
    server_addr_rec *sar;
Packit 90a5c9
    ipaddr_chain *trav = NULL;
Packit 90a5c9
    ipaddr_chain *wild_match = NULL;
Packit 90a5c9
Packit 90a5c9
    for (trav = default_list; trav; trav = trav->next) {
Packit 90a5c9
        sar = trav->sar;
Packit 90a5c9
        if (sar->host_port == port) {
Packit 90a5c9
            /* match! */
Packit 90a5c9
            return trav;
Packit 90a5c9
        }
Packit 90a5c9
        if (wild_match == NULL && sar->host_port == 0) {
Packit 90a5c9
            /* don't break, continue looking for an exact match */
Packit 90a5c9
            wild_match = trav;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return wild_match;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
#if APR_HAVE_IPV6
Packit 90a5c9
#define IS_IN6_ANYADDR(ad) ((ad)->family == APR_INET6                   \
Packit 90a5c9
                            && IN6_IS_ADDR_UNSPECIFIED(&(ad)->sa.sin6.sin6_addr))
Packit 90a5c9
#else
Packit 90a5c9
#define IS_IN6_ANYADDR(ad) (0)
Packit 90a5c9
#endif
Packit 90a5c9
Packit 90a5c9
static void dump_a_vhost(apr_file_t *f, ipaddr_chain *ic)
Packit 90a5c9
{
Packit 90a5c9
    name_chain *nc;
Packit 90a5c9
    int len;
Packit 90a5c9
    char buf[MAX_STRING_LEN];
Packit 90a5c9
    apr_sockaddr_t *ha = ic->sar->host_addr;
Packit 90a5c9
Packit 90a5c9
    if ((ha->family == APR_INET && ha->sa.sin.sin_addr.s_addr == INADDR_ANY)
Packit 90a5c9
        || IS_IN6_ANYADDR(ha)) {
Packit 90a5c9
        len = apr_snprintf(buf, sizeof(buf), "*:%u",
Packit 90a5c9
                           ic->sar->host_port);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        len = apr_snprintf(buf, sizeof(buf), "%pI", ha);
Packit 90a5c9
    }
Packit 90a5c9
    if (ic->sar->host_port == 0) {
Packit 90a5c9
        buf[len-1] = '*';
Packit 90a5c9
    }
Packit 90a5c9
    if (ic->names == NULL) {
Packit 90a5c9
        apr_file_printf(f, "%-22s %s (%s:%u)\n", buf,
Packit 90a5c9
                        ic->server->server_hostname,
Packit 90a5c9
                        ic->server->defn_name, ic->server->defn_line_number);
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
    apr_file_printf(f, "%-22s is a NameVirtualHost\n"
Packit 90a5c9
                    "%8s default server %s (%s:%u)\n",
Packit 90a5c9
                    buf, "", ic->server->server_hostname,
Packit 90a5c9
                    ic->server->defn_name, ic->server->defn_line_number);
Packit 90a5c9
    for (nc = ic->names; nc; nc = nc->next) {
Packit 90a5c9
        if (nc->sar->host_port) {
Packit 90a5c9
            apr_file_printf(f, "%8s port %u ", "", nc->sar->host_port);
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            apr_file_printf(f, "%8s port * ", "");
Packit 90a5c9
        }
Packit 90a5c9
        apr_file_printf(f, "namevhost %s (%s:%u)\n",
Packit 90a5c9
                        nc->server->server_hostname,
Packit 90a5c9
                        nc->server->defn_name, nc->server->defn_line_number);
Packit 90a5c9
        if (nc->server->names) {
Packit 90a5c9
            apr_array_header_t *names = nc->server->names;
Packit 90a5c9
            char **name = (char **)names->elts;
Packit 90a5c9
            int i;
Packit 90a5c9
            for (i = 0; i < names->nelts; ++i) {
Packit 90a5c9
                if (name[i]) {
Packit 90a5c9
                    apr_file_printf(f, "%16s alias %s\n", "", name[i]);
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        if (nc->server->wild_names) {
Packit 90a5c9
            apr_array_header_t *names = nc->server->wild_names;
Packit 90a5c9
            char **name = (char **)names->elts;
Packit 90a5c9
            int i;
Packit 90a5c9
            for (i = 0; i < names->nelts; ++i) {
Packit 90a5c9
                if (name[i]) {
Packit 90a5c9
                    apr_file_printf(f, "%16s wild alias %s\n", "", name[i]);
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static void dump_vhost_config(apr_file_t *f)
Packit 90a5c9
{
Packit 90a5c9
    ipaddr_chain *ic;
Packit 90a5c9
    int i;
Packit 90a5c9
Packit 90a5c9
    apr_file_printf(f, "VirtualHost configuration:\n");
Packit 90a5c9
Packit 90a5c9
    /* non-wildcard servers */
Packit 90a5c9
    for (i = 0; i < IPHASH_TABLE_SIZE; ++i) {
Packit 90a5c9
        for (ic = iphash_table[i]; ic; ic = ic->next) {
Packit 90a5c9
            dump_a_vhost(f, ic);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* wildcard servers */
Packit 90a5c9
    for (ic = default_list; ic; ic = ic->next) {
Packit 90a5c9
        dump_a_vhost(f, ic);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * When a second or later virtual host maps to the same IP chain,
Packit 90a5c9
 * add the relevant server names to the chain.  Special care is taken
Packit 90a5c9
 * to avoid adding ic->names until we're sure there are multiple VH'es.
Packit 90a5c9
 */
Packit 90a5c9
static void add_name_vhost_config(apr_pool_t *p, server_rec *main_s,
Packit 90a5c9
                                 server_rec *s, server_addr_rec *sar,
Packit 90a5c9
                                 ipaddr_chain *ic)
Packit 90a5c9
{
Packit 90a5c9
Packit 90a5c9
   name_chain *nc = new_name_chain(p, s, sar);
Packit 90a5c9
   nc->next = ic->names;
Packit 90a5c9
Packit 90a5c9
   /* iterating backwards, so each one we see becomes the current default server */
Packit 90a5c9
   ic->server = s;
Packit 90a5c9
Packit 90a5c9
   if (ic->names == NULL) {
Packit 90a5c9
       if (ic->initialnames == NULL) {
Packit 90a5c9
           /* first pass, set these names aside in case we see another VH.
Packit 90a5c9
            * Until then, this looks like an IP-based VH to runtime.
Packit 90a5c9
            */
Packit 90a5c9
           ic->initialnames = nc;
Packit 90a5c9
       }
Packit 90a5c9
       else {
Packit 90a5c9
           /* second pass through this chain -- this really is an NVH, and we
Packit 90a5c9
            * have two sets of names to link in.
Packit 90a5c9
            */
Packit 90a5c9
           nc->next = ic->initialnames;
Packit 90a5c9
           ic->names = nc;
Packit 90a5c9
           ic->initialnames = NULL;
Packit 90a5c9
       }
Packit 90a5c9
   }
Packit 90a5c9
   else {
Packit 90a5c9
       /* 3rd or more -- just keep stacking the names */
Packit 90a5c9
       ic->names = nc;
Packit 90a5c9
   }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* compile the tables and such we need to do the run-time vhost lookups */
Packit 90a5c9
AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s)
Packit 90a5c9
{
Packit 90a5c9
    server_addr_rec *sar;
Packit 90a5c9
    int has_default_vhost_addr;
Packit 90a5c9
    server_rec *s;
Packit 90a5c9
    int i;
Packit 90a5c9
    ipaddr_chain **iphash_table_tail[IPHASH_TABLE_SIZE];
Packit 90a5c9
Packit 90a5c9
    /* Main host first */
Packit 90a5c9
    s = main_s;
Packit 90a5c9
Packit 90a5c9
    if (!s->server_hostname) {
Packit 90a5c9
        s->server_hostname = ap_get_local_host(p);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* initialize the tails */
Packit 90a5c9
    for (i = 0; i < IPHASH_TABLE_SIZE; ++i) {
Packit 90a5c9
        iphash_table_tail[i] = &iphash_table[i];
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* The next things to go into the hash table are the virtual hosts
Packit 90a5c9
     * themselves.  They're listed off of main_s->next in the reverse
Packit 90a5c9
     * order they occurred in the config file, so we insert them at
Packit 90a5c9
     * the iphash_table_tail but don't advance the tail.
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    for (s = main_s->next; s; s = s->next) {
Packit 90a5c9
        server_addr_rec *sar_prev = NULL;
Packit 90a5c9
        has_default_vhost_addr = 0;
Packit 90a5c9
        for (sar = s->addrs; sar; sar = sar->next) {
Packit 90a5c9
            ipaddr_chain *ic;
Packit 90a5c9
            char inaddr_any[16] = {0}; /* big enough to handle IPv4 or IPv6 */
Packit 90a5c9
            /* XXX: this treats 0.0.0.0 as a "default" server which matches no-exact-match for IPv6 */
Packit 90a5c9
            if (!memcmp(sar->host_addr->ipaddr_ptr, inaddr_any, sar->host_addr->ipaddr_len)) {
Packit 90a5c9
                ic = find_default_server(sar->host_port);
Packit 90a5c9
Packit 90a5c9
                if (ic && sar->host_port == ic->sar->host_port) { /* we're a match for an existing "default server"  */
Packit 90a5c9
                    if (!sar_prev || memcmp(sar_prev->host_addr->ipaddr_ptr, inaddr_any, sar_prev->host_addr->ipaddr_len)
Packit 90a5c9
                                  || sar_prev->host_port != sar->host_port) { 
Packit 90a5c9
                        add_name_vhost_config(p, main_s, s, sar, ic);
Packit 90a5c9
                    }
Packit 90a5c9
                }
Packit 90a5c9
                else { 
Packit 90a5c9
                    /* No default server, or we found a default server but
Packit 90a5c9
                    ** exactly one of us is a wildcard port, which means we want
Packit 90a5c9
                    ** two ip-based vhosts not an NVH with two names
Packit 90a5c9
                    */
Packit 90a5c9
                    ic = new_ipaddr_chain(p, s, sar);
Packit 90a5c9
                    ic->next = default_list;
Packit 90a5c9
                    default_list = ic;
Packit 90a5c9
                    add_name_vhost_config(p, main_s, s, sar, ic);
Packit 90a5c9
                }
Packit 90a5c9
                has_default_vhost_addr = 1;
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                /* see if it matches something we've already got */
Packit 90a5c9
                ic = find_ipaddr(sar->host_addr);
Packit 90a5c9
Packit 90a5c9
                if (!ic || sar->host_port != ic->sar->host_port) {
Packit 90a5c9
                    /* No matching server, or we found a matching server but
Packit 90a5c9
                    ** exactly one of us is a wildcard port, which means we want
Packit 90a5c9
                    ** two ip-based vhosts not an NVH with two names
Packit 90a5c9
                    */
Packit 90a5c9
                    unsigned bucket = hash_addr(sar->host_addr);
Packit 90a5c9
                    ic = new_ipaddr_chain(p, s, sar);
Packit 90a5c9
                    ic->next = *iphash_table_tail[bucket];
Packit 90a5c9
                    *iphash_table_tail[bucket] = ic;
Packit 90a5c9
                }
Packit 90a5c9
                add_name_vhost_config(p, main_s, s, sar, ic);
Packit 90a5c9
            }
Packit 90a5c9
            sar_prev = sar;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        /* Ok now we want to set up a server_hostname if the user was
Packit 90a5c9
         * silly enough to forget one.
Packit 90a5c9
         * XXX: This is silly we should just crash and burn.
Packit 90a5c9
         */
Packit 90a5c9
        if (!s->server_hostname) {
Packit 90a5c9
            if (has_default_vhost_addr) {
Packit 90a5c9
                s->server_hostname = main_s->server_hostname;
Packit 90a5c9
            }
Packit 90a5c9
            else if (!s->addrs) {
Packit 90a5c9
                /* what else can we do?  at this point this vhost has
Packit 90a5c9
                    no configured name, probably because they used
Packit 90a5c9
                    DNS in the VirtualHost statement.  It's disabled
Packit 90a5c9
                    anyhow by the host matching code.  -djg */
Packit 90a5c9
                s->server_hostname =
Packit 90a5c9
                    apr_pstrdup(p, "bogus_host_without_forward_dns");
Packit 90a5c9
            }
Packit 90a5c9
            else {
Packit 90a5c9
                apr_status_t rv;
Packit 90a5c9
                char *hostname;
Packit 90a5c9
Packit 90a5c9
                rv = apr_getnameinfo(&hostname, s->addrs->host_addr, 0);
Packit 90a5c9
                if (rv == APR_SUCCESS) {
Packit 90a5c9
                    s->server_hostname = apr_pstrdup(p, hostname);
Packit 90a5c9
                }
Packit 90a5c9
                else {
Packit 90a5c9
                    /* again, what can we do?  They didn't specify a
Packit 90a5c9
                       ServerName, and their DNS isn't working. -djg */
Packit 90a5c9
                    char *ipaddr_str;
Packit 90a5c9
Packit 90a5c9
                    apr_sockaddr_ip_get(&ipaddr_str, s->addrs->host_addr);
Packit 90a5c9
                    ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_s, APLOGNO(00549)
Packit 90a5c9
                                 "Failed to resolve server name "
Packit 90a5c9
                                 "for %s (check DNS) -- or specify an explicit "
Packit 90a5c9
                                 "ServerName",
Packit 90a5c9
                                 ipaddr_str);
Packit 90a5c9
                    s->server_hostname =
Packit 90a5c9
                        apr_pstrdup(p, "bogus_host_without_reverse_dns");
Packit 90a5c9
                }
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
#ifdef IPHASH_STATISTICS
Packit 90a5c9
    dump_iphash_statistics(main_s);
Packit 90a5c9
#endif
Packit 90a5c9
    if (ap_exists_config_define("DUMP_VHOSTS")) {
Packit 90a5c9
        apr_file_t *thefile = NULL;
Packit 90a5c9
        apr_file_open_stdout(&thefile, p);
Packit 90a5c9
        dump_vhost_config(thefile);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static int vhost_check_config(apr_pool_t *p, apr_pool_t *plog,
Packit 90a5c9
                              apr_pool_t *ptemp, server_rec *s)
Packit 90a5c9
{
Packit 90a5c9
    return config_error ? !OK : OK;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*****************************************************************************
Packit 90a5c9
 * run-time vhost matching functions
Packit 90a5c9
 */
Packit 90a5c9
Packit 90a5c9
static apr_status_t fix_hostname_v6_literal(request_rec *r, char *host)
Packit 90a5c9
{
Packit 90a5c9
    char *dst;
Packit 90a5c9
    int double_colon = 0;
Packit 90a5c9
Packit 90a5c9
    for (dst = host; *dst; dst++) {
Packit 90a5c9
        if (apr_isxdigit(*dst)) {
Packit 90a5c9
            if (apr_isupper(*dst)) {
Packit 90a5c9
                *dst = apr_tolower(*dst);
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else if (*dst == ':') {
Packit 90a5c9
            if (*(dst + 1) == ':') {
Packit 90a5c9
                if (double_colon)
Packit 90a5c9
                    return APR_EINVAL;
Packit 90a5c9
                double_colon = 1;
Packit 90a5c9
            }
Packit 90a5c9
            else if (*(dst + 1) == '.') {
Packit 90a5c9
                return APR_EINVAL;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else if (*dst == '.') {
Packit 90a5c9
            /* For IPv4-mapped IPv6 addresses like ::FFFF:129.144.52.38 */
Packit 90a5c9
            if (*(dst + 1) == ':' || *(dst + 1) == '.')
Packit 90a5c9
                return APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
        else {
Packit 90a5c9
            return APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static apr_status_t fix_hostname_non_v6(request_rec *r, char *host)
Packit 90a5c9
{
Packit 90a5c9
    char *dst;
Packit 90a5c9
Packit 90a5c9
    for (dst = host; *dst; dst++) {
Packit 90a5c9
        if (apr_islower(*dst)) {
Packit 90a5c9
            /* leave char unchanged */
Packit 90a5c9
        }
Packit 90a5c9
        else if (*dst == '.') {
Packit 90a5c9
            if (*(dst + 1) == '.') {
Packit 90a5c9
                return APR_EINVAL;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        else if (apr_isupper(*dst)) {
Packit 90a5c9
            *dst = apr_tolower(*dst);
Packit 90a5c9
        }
Packit 90a5c9
        else if (*dst == '/' || *dst == '\\') {
Packit 90a5c9
            return APR_EINVAL;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    /* strip trailing gubbins */
Packit 90a5c9
    if (dst > host && dst[-1] == '.') {
Packit 90a5c9
        dst[-1] = '\0';
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/*
Packit 90a5c9
 * If strict mode ever becomes the default, this should be folded into
Packit 90a5c9
 * fix_hostname_non_v6()
Packit 90a5c9
 */
Packit 90a5c9
static apr_status_t strict_hostname_check(request_rec *r, char *host)
Packit 90a5c9
{
Packit 90a5c9
    char *ch;
Packit 90a5c9
    int is_dotted_decimal = 1, leading_zeroes = 0, dots = 0;
Packit 90a5c9
Packit 90a5c9
    for (ch = host; *ch; ch++) {
Packit 90a5c9
        if (apr_isalpha(*ch) || *ch == '-' || *ch == '_') {
Packit 90a5c9
            is_dotted_decimal = 0;
Packit 90a5c9
        }
Packit 90a5c9
        else if (ch[0] == '.') {
Packit 90a5c9
            dots++;
Packit 90a5c9
            if (ch[1] == '0' && apr_isdigit(ch[2]))
Packit 90a5c9
                leading_zeroes = 1;
Packit 90a5c9
        }
Packit 90a5c9
        else if (!apr_isdigit(*ch)) {
Packit 90a5c9
           /* also takes care of multiple Host headers by denying commas */
Packit 90a5c9
            goto bad;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    if (is_dotted_decimal) {
Packit 90a5c9
        if (host[0] == '.' || (host[0] == '0' && apr_isdigit(host[1])))
Packit 90a5c9
            leading_zeroes = 1;
Packit 90a5c9
        if (leading_zeroes || dots != 3) {
Packit 90a5c9
            /* RFC 3986 7.4 */
Packit 90a5c9
            goto bad;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        /* The top-level domain must start with a letter (RFC 1123 2.1) */
Packit 90a5c9
        while (ch > host && *ch != '.')
Packit 90a5c9
            ch--;
Packit 90a5c9
        if (ch[0] == '.' && ch[1] != '\0' && !apr_isalpha(ch[1]))
Packit 90a5c9
            goto bad;
Packit 90a5c9
    }
Packit 90a5c9
    return APR_SUCCESS;
Packit 90a5c9
Packit 90a5c9
bad:
Packit 90a5c9
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02415)
Packit 90a5c9
                  "[strict] Invalid host name '%s'%s%.6s",
Packit 90a5c9
                  host, *ch ? ", problem near: " : "", ch);
Packit 90a5c9
    return APR_EINVAL;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Lowercase and remove any trailing dot and/or :port from the hostname,
Packit 90a5c9
 * and check that it is sane.
Packit 90a5c9
 *
Packit 90a5c9
 * In most configurations the exact syntax of the hostname isn't
Packit 90a5c9
 * important so strict sanity checking isn't necessary. However, in
Packit 90a5c9
 * mass hosting setups (using mod_vhost_alias or mod_rewrite) where
Packit 90a5c9
 * the hostname is interpolated into the filename, we need to be sure
Packit 90a5c9
 * that the interpolation doesn't expose parts of the filesystem.
Packit 90a5c9
 * We don't do strict RFC 952 / RFC 1123 syntax checking in order
Packit 90a5c9
 * to support iDNS and people who erroneously use underscores.
Packit 90a5c9
 * Instead we just check for filesystem metacharacters: directory
Packit 90a5c9
 * separators / and \ and sequences of more than one dot.
Packit 90a5c9
 */
Packit 90a5c9
static int fix_hostname(request_rec *r, const char *host_header,
Packit 90a5c9
                        unsigned http_conformance)
Packit 90a5c9
{
Packit 90a5c9
    const char *src;
Packit 90a5c9
    char *host, *scope_id;
Packit 90a5c9
    apr_port_t port;
Packit 90a5c9
    apr_status_t rv;
Packit 90a5c9
    const char *c;
Packit 90a5c9
    int is_v6literal = 0;
Packit 90a5c9
    int strict = (http_conformance != AP_HTTP_CONFORMANCE_UNSAFE);
Packit 90a5c9
Packit 90a5c9
    src = host_header ? host_header : r->hostname;
Packit 90a5c9
Packit 90a5c9
    /* According to RFC 2616, Host header field CAN be blank */
Packit 90a5c9
    if (!*src) {
Packit 90a5c9
        return is_v6literal;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* apr_parse_addr_port will interpret a bare integer as a port
Packit 90a5c9
     * which is incorrect in this context.  So treat it separately.
Packit 90a5c9
     */
Packit 90a5c9
    for (c = src; apr_isdigit(*c); ++c);
Packit 90a5c9
    if (!*c) {
Packit 90a5c9
        /* pure integer */
Packit 90a5c9
        if (strict) {
Packit 90a5c9
            /* RFC 3986 7.4 */
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02416)
Packit 90a5c9
                         "[strict] purely numeric host names not allowed: %s",
Packit 90a5c9
                         src);
Packit 90a5c9
            goto bad_nolog;
Packit 90a5c9
        }
Packit 90a5c9
        r->hostname = src;
Packit 90a5c9
        return is_v6literal;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (host_header) {
Packit 90a5c9
        rv = apr_parse_addr_port(&host, &scope_id, &port, src, r->pool);
Packit 90a5c9
        if (rv != APR_SUCCESS || scope_id)
Packit 90a5c9
            goto bad;
Packit 90a5c9
        if (port) {
Packit 90a5c9
            /* Don't throw the Host: header's port number away:
Packit 90a5c9
               save it in parsed_uri -- ap_get_server_port() needs it! */
Packit 90a5c9
            /* @@@ XXX there should be a better way to pass the port.
Packit 90a5c9
             *         Like r->hostname, there should be a r->portno
Packit 90a5c9
             */
Packit 90a5c9
            r->parsed_uri.port = port;
Packit 90a5c9
            r->parsed_uri.port_str = apr_itoa(r->pool, (int)port);
Packit 90a5c9
        }
Packit 90a5c9
        if (host_header[0] == '[')
Packit 90a5c9
            is_v6literal = 1;
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        /*
Packit 90a5c9
         * Already parsed, surrounding [ ] (if IPv6 literal) and :port have
Packit 90a5c9
         * already been removed.
Packit 90a5c9
         */
Packit 90a5c9
        host = apr_pstrdup(r->pool, r->hostname);
Packit 90a5c9
        if (ap_strchr(host, ':') != NULL)
Packit 90a5c9
            is_v6literal = 1;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    if (is_v6literal) {
Packit 90a5c9
        rv = fix_hostname_v6_literal(r, host);
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        rv = fix_hostname_non_v6(r, host);
Packit 90a5c9
        if (strict && rv == APR_SUCCESS)
Packit 90a5c9
            rv = strict_hostname_check(r, host);
Packit 90a5c9
    }
Packit 90a5c9
    if (rv != APR_SUCCESS)
Packit 90a5c9
        goto bad;
Packit 90a5c9
Packit 90a5c9
    r->hostname = host;
Packit 90a5c9
    return is_v6literal;
Packit 90a5c9
Packit 90a5c9
bad:
Packit 90a5c9
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00550)
Packit 90a5c9
                  "Client sent malformed Host header: %s",
Packit 90a5c9
                  src);
Packit 90a5c9
bad_nolog:
Packit 90a5c9
    r->status = HTTP_BAD_REQUEST;
Packit 90a5c9
    return is_v6literal;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* return 1 if host matches ServerName or ServerAliases */
Packit 90a5c9
static int matches_aliases(server_rec *s, const char *host)
Packit 90a5c9
{
Packit 90a5c9
    int i;
Packit 90a5c9
    apr_array_header_t *names;
Packit 90a5c9
Packit 90a5c9
    /* match ServerName */
Packit 90a5c9
    if (!strcasecmp(host, s->server_hostname)) {
Packit 90a5c9
        return 1;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* search all the aliases from ServerAlias directive */
Packit 90a5c9
    names = s->names;
Packit 90a5c9
    if (names) {
Packit 90a5c9
        char **name = (char **) names->elts;
Packit 90a5c9
        for (i = 0; i < names->nelts; ++i) {
Packit 90a5c9
            if (!name[i]) continue;
Packit 90a5c9
            if (!strcasecmp(host, name[i]))
Packit 90a5c9
                return 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    names = s->wild_names;
Packit 90a5c9
    if (names) {
Packit 90a5c9
        char **name = (char **) names->elts;
Packit 90a5c9
        for (i = 0; i < names->nelts; ++i) {
Packit 90a5c9
            if (!name[i]) continue;
Packit 90a5c9
            if (!ap_strcasecmp_match(host, name[i]))
Packit 90a5c9
                return 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    return 0;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
/* Suppose a request came in on the same socket as this r, and included
Packit 90a5c9
 * a header "Host: host:port", would it map to r->server?  It's more
Packit 90a5c9
 * than just that though.  When we do the normal matches for each request
Packit 90a5c9
 * we don't even bother considering Host: etc on non-namevirtualhosts,
Packit 90a5c9
 * we just call it a match.  But here we require the host:port to match
Packit 90a5c9
 * the ServerName and/or ServerAliases.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host,
Packit 90a5c9
                                         apr_port_t port)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s;
Packit 90a5c9
    server_addr_rec *sar;
Packit 90a5c9
Packit 90a5c9
    s = r->server;
Packit 90a5c9
Packit 90a5c9
    /* search all the <VirtualHost> values */
Packit 90a5c9
    /* XXX: If this is a NameVirtualHost then we may not be doing the Right Thing
Packit 90a5c9
     * consider:
Packit 90a5c9
     *
Packit 90a5c9
     *     NameVirtualHost 10.1.1.1
Packit 90a5c9
     *     <VirtualHost 10.1.1.1>
Packit 90a5c9
     *     ServerName v1
Packit 90a5c9
     *     </VirtualHost>
Packit 90a5c9
     *     <VirtualHost 10.1.1.1>
Packit 90a5c9
     *     ServerName v2
Packit 90a5c9
     *     </VirtualHost>
Packit 90a5c9
     *
Packit 90a5c9
     * Suppose r->server is v2, and we're asked to match "10.1.1.1".  We'll say
Packit 90a5c9
     * "yup it's v2", when really it isn't... if a request came in for 10.1.1.1
Packit 90a5c9
     * it would really go to v1.
Packit 90a5c9
     */
Packit 90a5c9
    for (sar = s->addrs; sar; sar = sar->next) {
Packit 90a5c9
        if ((sar->host_port == 0 || port == sar->host_port)
Packit 90a5c9
            && !strcasecmp(host, sar->virthost)) {
Packit 90a5c9
            return 1;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* the Port has to match now, because the rest don't have ports associated
Packit 90a5c9
     * with them. */
Packit 90a5c9
    if (port != s->port) {
Packit 90a5c9
        return 0;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return matches_aliases(s, host);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static void check_hostalias(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    /*
Packit 90a5c9
     * Even if the request has a Host: header containing a port we ignore
Packit 90a5c9
     * that port.  We always use the physical port of the socket.  There
Packit 90a5c9
     * are a few reasons for this:
Packit 90a5c9
     *
Packit 90a5c9
     * - the default of 80 or 443 for SSL is easier to handle this way
Packit 90a5c9
     * - there is less of a possibility of a security problem
Packit 90a5c9
     * - it simplifies the data structure
Packit 90a5c9
     * - the client may have no idea that a proxy somewhere along the way
Packit 90a5c9
     *   translated the request to another ip:port
Packit 90a5c9
     * - except for the addresses from the VirtualHost line, none of the other
Packit 90a5c9
     *   names we'll match have ports associated with them
Packit 90a5c9
     */
Packit 90a5c9
    const char *host = r->hostname;
Packit 90a5c9
    apr_port_t port;
Packit 90a5c9
    server_rec *s;
Packit 90a5c9
    server_rec *virthost_s;
Packit 90a5c9
    server_rec *last_s;
Packit 90a5c9
    name_chain *src;
Packit 90a5c9
Packit 90a5c9
    virthost_s = NULL;
Packit 90a5c9
    last_s = NULL;
Packit 90a5c9
Packit 90a5c9
    port = r->connection->local_addr->port;
Packit 90a5c9
Packit 90a5c9
    /* Recall that the name_chain is a list of server_addr_recs, some of
Packit 90a5c9
     * whose ports may not match.  Also each server may appear more than
Packit 90a5c9
     * once in the chain -- specifically, it will appear once for each
Packit 90a5c9
     * address from its VirtualHost line which matched.  We only want to
Packit 90a5c9
     * do the full ServerName/ServerAlias comparisons once for each
Packit 90a5c9
     * server, fortunately we know that all the VirtualHost addresses for
Packit 90a5c9
     * a single server are adjacent to each other.
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    for (src = r->connection->vhost_lookup_data; src; src = src->next) {
Packit 90a5c9
        server_addr_rec *sar;
Packit 90a5c9
Packit 90a5c9
        /* We only consider addresses on the name_chain which have a matching
Packit 90a5c9
         * port
Packit 90a5c9
         */
Packit 90a5c9
        sar = src->sar;
Packit 90a5c9
        if (sar->host_port != 0 && port != sar->host_port) {
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        s = src->server;
Packit 90a5c9
Packit 90a5c9
        /* If we still need to do ServerName and ServerAlias checks for this
Packit 90a5c9
         * server, do them now.
Packit 90a5c9
         */
Packit 90a5c9
        if (s != last_s) {
Packit 90a5c9
            /* does it match any ServerName or ServerAlias directive? */
Packit 90a5c9
            if (matches_aliases(s, host)) {
Packit 90a5c9
                goto found;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
        last_s = s;
Packit 90a5c9
Packit 90a5c9
        /* Fallback: does it match the virthost from the sar? */
Packit 90a5c9
        if (!strcasecmp(host, sar->virthost)) {
Packit 90a5c9
            /* only the first match is used */
Packit 90a5c9
            if (virthost_s == NULL) {
Packit 90a5c9
                virthost_s = s;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* If ServerName and ServerAlias check failed, we end up here.  If it
Packit 90a5c9
     * matches a VirtualHost, virthost_s is set. Use that as fallback
Packit 90a5c9
     */
Packit 90a5c9
    if (virthost_s) {
Packit 90a5c9
        s = virthost_s;
Packit 90a5c9
        goto found;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return;
Packit 90a5c9
Packit 90a5c9
found:
Packit 90a5c9
    /* s is the first matching server, we're done */
Packit 90a5c9
    r->server = s;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
Packit 90a5c9
static void check_serverpath(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s;
Packit 90a5c9
    server_rec *last_s;
Packit 90a5c9
    name_chain *src;
Packit 90a5c9
    apr_port_t port;
Packit 90a5c9
Packit 90a5c9
    port = r->connection->local_addr->port;
Packit 90a5c9
Packit 90a5c9
    /*
Packit 90a5c9
     * This is in conjunction with the ServerPath code in http_core, so we
Packit 90a5c9
     * get the right host attached to a non- Host-sending request.
Packit 90a5c9
     *
Packit 90a5c9
     * See the comment in check_hostalias about how each vhost can be
Packit 90a5c9
     * listed multiple times.
Packit 90a5c9
     */
Packit 90a5c9
Packit 90a5c9
    last_s = NULL;
Packit 90a5c9
    for (src = r->connection->vhost_lookup_data; src; src = src->next) {
Packit 90a5c9
        /* We only consider addresses on the name_chain which have a matching
Packit 90a5c9
         * port
Packit 90a5c9
         */
Packit 90a5c9
        if (src->sar->host_port != 0 && port != src->sar->host_port) {
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
Packit 90a5c9
        s = src->server;
Packit 90a5c9
        if (s == last_s) {
Packit 90a5c9
            continue;
Packit 90a5c9
        }
Packit 90a5c9
        last_s = s;
Packit 90a5c9
Packit 90a5c9
        if (s->path && !strncmp(r->uri, s->path, s->pathlen) &&
Packit 90a5c9
            (s->path[s->pathlen - 1] == '/' ||
Packit 90a5c9
             r->uri[s->pathlen] == '/' ||
Packit 90a5c9
             r->uri[s->pathlen] == '\0')) {
Packit 90a5c9
            r->server = s;
Packit 90a5c9
            return;
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
static APR_INLINE const char *construct_host_header(request_rec *r,
Packit 90a5c9
                                                    int is_v6literal)
Packit 90a5c9
{
Packit 90a5c9
    struct iovec iov[5];
Packit 90a5c9
    apr_size_t nvec = 0;
Packit 90a5c9
    /*
Packit 90a5c9
     * We cannot use ap_get_server_name/port here, because we must
Packit 90a5c9
     * ignore UseCanonicalName/Port.
Packit 90a5c9
     */
Packit 90a5c9
    if (is_v6literal) {
Packit 90a5c9
        iov[nvec].iov_base = "[";
Packit 90a5c9
        iov[nvec].iov_len = 1;
Packit 90a5c9
        nvec++;
Packit 90a5c9
    }
Packit 90a5c9
    iov[nvec].iov_base = (void *)r->hostname;
Packit 90a5c9
    iov[nvec].iov_len = strlen(r->hostname);
Packit 90a5c9
    nvec++;
Packit 90a5c9
    if (is_v6literal) {
Packit 90a5c9
        iov[nvec].iov_base = "]";
Packit 90a5c9
        iov[nvec].iov_len = 1;
Packit 90a5c9
        nvec++;
Packit 90a5c9
    }
Packit 90a5c9
    if (r->parsed_uri.port_str) {
Packit 90a5c9
        iov[nvec].iov_base = ":";
Packit 90a5c9
        iov[nvec].iov_len = 1;
Packit 90a5c9
        nvec++;
Packit 90a5c9
        iov[nvec].iov_base = r->parsed_uri.port_str;
Packit 90a5c9
        iov[nvec].iov_len = strlen(r->parsed_uri.port_str);
Packit 90a5c9
        nvec++;
Packit 90a5c9
    }
Packit 90a5c9
    return apr_pstrcatv(r->pool, iov, nvec, NULL);
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r)
Packit 90a5c9
{
Packit 90a5c9
    core_server_config *conf = ap_get_core_module_config(r->server->module_config);
Packit 90a5c9
    const char *host_header = apr_table_get(r->headers_in, "Host");
Packit 90a5c9
    int is_v6literal = 0;
Packit 90a5c9
    int have_hostname_from_url = 0;
Packit 90a5c9
Packit 90a5c9
    if (r->hostname) {
Packit 90a5c9
        /*
Packit 90a5c9
         * If there was a host part in the Request-URI, ignore the 'Host'
Packit 90a5c9
         * header.
Packit 90a5c9
         */
Packit 90a5c9
        have_hostname_from_url = 1;
Packit 90a5c9
        is_v6literal = fix_hostname(r, NULL, conf->http_conformance);
Packit 90a5c9
    }
Packit 90a5c9
    else if (host_header != NULL) {
Packit 90a5c9
        is_v6literal = fix_hostname(r, host_header, conf->http_conformance);
Packit 90a5c9
    }
Packit 90a5c9
    if (r->status != HTTP_OK)
Packit 90a5c9
        return;
Packit 90a5c9
Packit 90a5c9
    if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) {
Packit 90a5c9
        /*
Packit 90a5c9
         * If we have both hostname from an absoluteURI and a Host header,
Packit 90a5c9
         * we must ignore the Host header (RFC 2616 5.2).
Packit 90a5c9
         * To enforce this, we reset the Host header to the value from the
Packit 90a5c9
         * request line.
Packit 90a5c9
         */
Packit 90a5c9
        if (have_hostname_from_url && host_header != NULL) {
Packit 90a5c9
            const char *repl = construct_host_header(r, is_v6literal);
Packit 90a5c9
            apr_table_setn(r->headers_in, "Host", repl);
Packit 90a5c9
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02417)
Packit 90a5c9
                          "Replacing host header '%s' with host '%s' given "
Packit 90a5c9
                          "in the request uri", host_header, repl);
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* check if we tucked away a name_chain */
Packit 90a5c9
    if (r->connection->vhost_lookup_data) {
Packit 90a5c9
        if (r->hostname)
Packit 90a5c9
            check_hostalias(r);
Packit 90a5c9
        else
Packit 90a5c9
            check_serverpath(r);
Packit 90a5c9
    }
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/**
Packit 90a5c9
 * For every virtual host on this connection, call func_cb.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(int) ap_vhost_iterate_given_conn(conn_rec *conn,
Packit 90a5c9
                                            ap_vhost_iterate_conn_cb func_cb,
Packit 90a5c9
                                            void* baton)
Packit 90a5c9
{
Packit 90a5c9
    server_rec *s;
Packit 90a5c9
    server_rec *last_s;
Packit 90a5c9
    name_chain *src;
Packit 90a5c9
    apr_port_t port;
Packit 90a5c9
    int rv = 0;
Packit 90a5c9
Packit 90a5c9
    if (conn->vhost_lookup_data) {
Packit 90a5c9
        last_s = NULL;
Packit 90a5c9
        port = conn->local_addr->port;
Packit 90a5c9
Packit 90a5c9
        for (src = conn->vhost_lookup_data; src; src = src->next) {
Packit 90a5c9
            server_addr_rec *sar;
Packit 90a5c9
Packit 90a5c9
            /* We only consider addresses on the name_chain which have a
Packit 90a5c9
             * matching port.
Packit 90a5c9
             */
Packit 90a5c9
            sar = src->sar;
Packit 90a5c9
            if (sar->host_port != 0 && port != sar->host_port) {
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            s = src->server;
Packit 90a5c9
Packit 90a5c9
            if (s == last_s) {
Packit 90a5c9
                /* we've already done a callback for this vhost. */
Packit 90a5c9
                continue;
Packit 90a5c9
            }
Packit 90a5c9
Packit 90a5c9
            last_s = s;
Packit 90a5c9
Packit 90a5c9
            rv = func_cb(baton, conn, s);
Packit 90a5c9
Packit 90a5c9
            if (rv != 0) {
Packit 90a5c9
                break;
Packit 90a5c9
            }
Packit 90a5c9
        }
Packit 90a5c9
    }
Packit 90a5c9
    else {
Packit 90a5c9
        rv = func_cb(baton, conn, conn->base_server);
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    return rv;
Packit 90a5c9
}
Packit 90a5c9
Packit 90a5c9
/* Called for a new connection which has a known local_addr.  Note that the
Packit 90a5c9
 * new connection is assumed to have conn->server == main server.
Packit 90a5c9
 */
Packit 90a5c9
AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn)
Packit 90a5c9
{
Packit 90a5c9
    ipaddr_chain *trav;
Packit 90a5c9
    apr_port_t port;
Packit 90a5c9
Packit 90a5c9
    /* scan the hash table for an exact match first */
Packit 90a5c9
    trav = find_ipaddr(conn->local_addr);
Packit 90a5c9
Packit 90a5c9
    if (trav) {
Packit 90a5c9
        /* save the name_chain for later in case this is a name-vhost */
Packit 90a5c9
        conn->vhost_lookup_data = trav->names;
Packit 90a5c9
        conn->base_server = trav->server;
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* maybe there's a default server or wildcard name-based vhost
Packit 90a5c9
     * matching this port
Packit 90a5c9
     */
Packit 90a5c9
    port = conn->local_addr->port;
Packit 90a5c9
Packit 90a5c9
    trav = find_default_server(port);
Packit 90a5c9
    if (trav) {
Packit 90a5c9
        conn->vhost_lookup_data = trav->names;
Packit 90a5c9
        conn->base_server = trav->server;
Packit 90a5c9
        return;
Packit 90a5c9
    }
Packit 90a5c9
Packit 90a5c9
    /* otherwise we're stuck with just the main server
Packit 90a5c9
     * and no name-based vhosts
Packit 90a5c9
     */
Packit 90a5c9
    conn->vhost_lookup_data = NULL;
Packit 90a5c9
}