/src/httpd/server/vhost.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | /** |
18 | | * @file vhost.c |
19 | | * @brief functions pertaining to virtual host addresses |
20 | | * (configuration and run-time) |
21 | | */ |
22 | | |
23 | | #include "apr.h" |
24 | | #include "apr_strings.h" |
25 | | #include "apr_lib.h" |
26 | | #include "apr_version.h" |
27 | | |
28 | | #define APR_WANT_STRFUNC |
29 | | #include "apr_want.h" |
30 | | |
31 | | #include "ap_config.h" |
32 | | #include "httpd.h" |
33 | | #include "http_config.h" |
34 | | #include "http_log.h" |
35 | | #include "http_vhost.h" |
36 | | #include "http_protocol.h" |
37 | | #include "http_core.h" |
38 | | #include "http_main.h" |
39 | | |
40 | | #if APR_HAVE_ARPA_INET_H |
41 | | #include <arpa/inet.h> |
42 | | #endif |
43 | | |
44 | | /* we know core's module_index is 0 */ |
45 | | #undef APLOG_MODULE_INDEX |
46 | | #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX |
47 | | |
48 | | /* |
49 | | * After all the definitions there's an explanation of how it's all put |
50 | | * together. |
51 | | */ |
52 | | |
53 | | /* meta-list of name-vhosts. Each server_rec can be in possibly multiple |
54 | | * lists of name-vhosts. |
55 | | */ |
56 | | typedef struct name_chain name_chain; |
57 | | struct name_chain { |
58 | | name_chain *next; |
59 | | server_addr_rec *sar; /* the record causing it to be in |
60 | | * this chain (needed for port comparisons) */ |
61 | | server_rec *server; /* the server to use on a match */ |
62 | | }; |
63 | | |
64 | | /* meta-list of ip addresses. Each server_rec can be in possibly multiple |
65 | | * hash chains since it can have multiple ips. |
66 | | */ |
67 | | typedef struct ipaddr_chain ipaddr_chain; |
68 | | struct ipaddr_chain { |
69 | | ipaddr_chain *next; |
70 | | server_addr_rec *sar; /* the record causing it to be in |
71 | | * this chain (need for both ip addr and port |
72 | | * comparisons) */ |
73 | | server_rec *server; /* the server to use if this matches */ |
74 | | name_chain *names; /* if non-NULL then a list of name-vhosts |
75 | | * sharing this address */ |
76 | | name_chain *initialnames; /* no runtime use, temporary storage of first |
77 | | * NVH'es names */ |
78 | | }; |
79 | | |
80 | | /* This defines the size of the hash table used for hashing ip addresses |
81 | | * of virtual hosts. It must be a power of two. |
82 | | */ |
83 | | #ifndef IPHASH_TABLE_SIZE |
84 | 0 | #define IPHASH_TABLE_SIZE 256 |
85 | | #endif |
86 | | |
87 | | /* A (n) bucket hash table, each entry has a pointer to a server rec and |
88 | | * a pointer to the other entries in that bucket. Each individual address, |
89 | | * even for virtualhosts with multiple addresses, has an entry in this hash |
90 | | * table. There are extra buckets for _default_, and name-vhost entries. |
91 | | * |
92 | | * Note that after config time this is constant, so it is thread-safe. |
93 | | */ |
94 | | static ipaddr_chain *iphash_table[IPHASH_TABLE_SIZE]; |
95 | | |
96 | | /* dump out statistics about the hash function */ |
97 | | /* #define IPHASH_STATISTICS */ |
98 | | |
99 | | /* list of the _default_ servers */ |
100 | | static ipaddr_chain *default_list; |
101 | | |
102 | | /* |
103 | | * How it's used: |
104 | | * |
105 | | * The ip address determines which chain in iphash_table is interesting, then |
106 | | * a comparison is done down that chain to find the first ipaddr_chain whose |
107 | | * sar matches the address:port pair. |
108 | | * |
109 | | * If that ipaddr_chain has names == NULL then you're done, it's an ip-vhost. |
110 | | * |
111 | | * Otherwise it's a name-vhost list, and the default is the server in the |
112 | | * ipaddr_chain record. We tuck away the ipaddr_chain record in the |
113 | | * conn_rec field vhost_lookup_data. Later on after the headers we get a |
114 | | * second chance, and we use the name_chain to figure out what name-vhost |
115 | | * matches the headers. |
116 | | * |
117 | | * If there was no ip address match in the iphash_table then do a lookup |
118 | | * in the default_list. |
119 | | * |
120 | | * How it's put together ... well you should be able to figure that out |
121 | | * from how it's used. Or something like that. |
122 | | */ |
123 | | |
124 | | |
125 | | /* called at the beginning of the config */ |
126 | | AP_DECLARE(void) ap_init_vhost_config(apr_pool_t *p) |
127 | 0 | { |
128 | 0 | memset(iphash_table, 0, sizeof(iphash_table)); |
129 | 0 | default_list = NULL; |
130 | 0 | } |
131 | | |
132 | | |
133 | | /* |
134 | | * Parses a host of the form <address>[:port] |
135 | | * paddr is used to create a list in the order of input |
136 | | * **paddr is the ->next pointer of the last entry (or s->addrs) |
137 | | * *paddr is the variable used to keep track of **paddr between calls |
138 | | * port is the default port to assume |
139 | | */ |
140 | | static const char *get_addresses(apr_pool_t *p, const char *w_, |
141 | | server_addr_rec ***paddr, |
142 | | apr_port_t default_port) |
143 | 0 | { |
144 | 0 | apr_sockaddr_t *my_addr; |
145 | 0 | server_addr_rec *sar; |
146 | 0 | char *w, *host, *scope_id; |
147 | 0 | int wild_port; |
148 | 0 | apr_size_t wlen; |
149 | 0 | apr_port_t port; |
150 | 0 | apr_status_t rv; |
151 | |
|
152 | 0 | if (*w_ == '\0') |
153 | 0 | return NULL; |
154 | | |
155 | 0 | wlen = strlen(w_); /* wlen must be > 0 at this point */ |
156 | 0 | w = apr_pstrmemdup(p, w_, wlen); |
157 | | /* apr_parse_addr_port() doesn't understand ":*" so handle that first. */ |
158 | 0 | wild_port = 0; |
159 | 0 | if (w[wlen - 1] == '*') { |
160 | 0 | if (wlen < 2) { |
161 | 0 | wild_port = 1; |
162 | 0 | } |
163 | 0 | else if (w[wlen - 2] == ':') { |
164 | 0 | w[wlen - 2] = '\0'; |
165 | 0 | wild_port = 1; |
166 | 0 | } |
167 | 0 | } |
168 | 0 | rv = apr_parse_addr_port(&host, &scope_id, &port, w, p); |
169 | | /* If the string is "80", apr_parse_addr_port() will be happy and set |
170 | | * host to NULL and port to 80, so watch out for that. |
171 | | */ |
172 | 0 | if (rv != APR_SUCCESS) { |
173 | 0 | return "The address or port is invalid"; |
174 | 0 | } |
175 | 0 | if (!host) { |
176 | 0 | return "Missing address for VirtualHost"; |
177 | 0 | } |
178 | | #if !APR_VERSION_AT_LEAST(1,7,0) |
179 | | if (scope_id) { |
180 | | return apr_pstrcat(p, |
181 | | "Scope ID in address '", w, |
182 | | "' not supported with APR " APR_VERSION_STRING, |
183 | | NULL); |
184 | | } |
185 | | #endif |
186 | 0 | if (!port && !wild_port) { |
187 | 0 | port = default_port; |
188 | 0 | } |
189 | |
|
190 | 0 | if (strcmp(host, "*") == 0 || strcasecmp(host, "_default_") == 0) { |
191 | 0 | rv = apr_sockaddr_info_get(&my_addr, NULL, APR_UNSPEC, port, 0, p); |
192 | 0 | if (rv) { |
193 | 0 | return "Could not determine a wildcard address ('0.0.0.0') -- " |
194 | 0 | "check resolver configuration."; |
195 | 0 | } |
196 | 0 | } |
197 | 0 | else { |
198 | 0 | rv = apr_sockaddr_info_get(&my_addr, host, APR_UNSPEC, port, 0, p); |
199 | 0 | if (rv != APR_SUCCESS) { |
200 | 0 | ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO(00547) |
201 | 0 | "Could not resolve host name %s -- ignoring!", host); |
202 | 0 | return NULL; |
203 | 0 | } |
204 | 0 | #if APR_VERSION_AT_LEAST(1,7,0) |
205 | 0 | if (scope_id) { |
206 | 0 | rv = apr_sockaddr_zone_set(my_addr, scope_id); |
207 | 0 | if (rv) { |
208 | 0 | ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO(10103) |
209 | 0 | "Could not set scope ID %s for %pI -- ignoring!", |
210 | 0 | scope_id, my_addr); |
211 | 0 | return NULL; |
212 | 0 | } |
213 | 0 | } |
214 | 0 | #endif |
215 | 0 | } |
216 | | |
217 | | /* Remember all addresses for the host */ |
218 | | |
219 | 0 | do { |
220 | 0 | sar = apr_pcalloc(p, sizeof(server_addr_rec)); |
221 | 0 | **paddr = sar; |
222 | 0 | *paddr = &sar->next; |
223 | 0 | sar->host_addr = my_addr; |
224 | 0 | sar->host_port = port; |
225 | 0 | sar->virthost = host; |
226 | 0 | my_addr = my_addr->next; |
227 | 0 | } while (my_addr); |
228 | |
|
229 | 0 | return NULL; |
230 | 0 | } |
231 | | |
232 | | |
233 | | /* parse the <VirtualHost> addresses */ |
234 | | AP_DECLARE(const char *)ap_parse_vhost_addrs(apr_pool_t *p, |
235 | | const char *hostname, |
236 | | server_rec *s) |
237 | 0 | { |
238 | 0 | server_addr_rec **addrs; |
239 | 0 | const char *err; |
240 | | |
241 | | /* start the list of addresses */ |
242 | 0 | addrs = &s->addrs; |
243 | 0 | while (hostname[0]) { |
244 | 0 | err = get_addresses(p, ap_getword_conf(p, &hostname), &addrs, s->port); |
245 | 0 | if (err) { |
246 | 0 | *addrs = NULL; |
247 | 0 | return err; |
248 | 0 | } |
249 | 0 | } |
250 | | /* terminate the list */ |
251 | 0 | *addrs = NULL; |
252 | 0 | if (s->addrs) { |
253 | 0 | if (s->addrs->host_port) { |
254 | | /* override the default port which is inherited from main_server */ |
255 | 0 | s->port = s->addrs->host_port; |
256 | 0 | } |
257 | 0 | } |
258 | 0 | return NULL; |
259 | 0 | } |
260 | | |
261 | | |
262 | | AP_DECLARE_NONSTD(const char *)ap_set_name_virtual_host(cmd_parms *cmd, |
263 | | void *dummy, |
264 | | const char *arg) |
265 | 0 | { |
266 | 0 | static int warnonce = 0; |
267 | 0 | if (++warnonce == 1) { |
268 | 0 | ap_log_error(APLOG_MARK, APLOG_NOTICE|APLOG_STARTUP, APR_SUCCESS, NULL, APLOGNO(00548) |
269 | 0 | "NameVirtualHost has no effect and will be removed in the " |
270 | 0 | "next release %s:%d", |
271 | 0 | cmd->directive->filename, |
272 | 0 | cmd->directive->line_num); |
273 | 0 | } |
274 | |
|
275 | 0 | return NULL; |
276 | 0 | } |
277 | | |
278 | | |
279 | | /* hash table statistics, keep this in here for the beta period so |
280 | | * we can find out if the hash function is ok |
281 | | */ |
282 | | #ifdef IPHASH_STATISTICS |
283 | | static int iphash_compare(const void *a, const void *b) |
284 | | { |
285 | | return (*(const int *) b - *(const int *) a); |
286 | | } |
287 | | |
288 | | |
289 | | static void dump_iphash_statistics(server_rec *main_s) |
290 | | { |
291 | | unsigned count[IPHASH_TABLE_SIZE]; |
292 | | int i; |
293 | | ipaddr_chain *src; |
294 | | unsigned total; |
295 | | char buf[HUGE_STRING_LEN]; |
296 | | char *p; |
297 | | |
298 | | total = 0; |
299 | | for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { |
300 | | count[i] = 0; |
301 | | for (src = iphash_table[i]; src; src = src->next) { |
302 | | ++count[i]; |
303 | | if (i < IPHASH_TABLE_SIZE) { |
304 | | /* don't count the slop buckets in the total */ |
305 | | ++total; |
306 | | } |
307 | | } |
308 | | } |
309 | | qsort(count, IPHASH_TABLE_SIZE, sizeof(count[0]), iphash_compare); |
310 | | p = buf + apr_snprintf(buf, sizeof(buf), |
311 | | APLOGNO(03235) "iphash: total hashed = %u, avg chain = %u, " |
312 | | "chain lengths (count x len):", |
313 | | total, total / IPHASH_TABLE_SIZE); |
314 | | total = 1; |
315 | | for (i = 1; i < IPHASH_TABLE_SIZE; ++i) { |
316 | | if (count[i - 1] != count[i]) { |
317 | | p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u", |
318 | | total, count[i - 1]); |
319 | | total = 1; |
320 | | } |
321 | | else { |
322 | | ++total; |
323 | | } |
324 | | } |
325 | | p += apr_snprintf(p, sizeof(buf) - (p - buf), " %ux%u", |
326 | | total, count[IPHASH_TABLE_SIZE - 1]); |
327 | | /* Intentional no APLOGNO */ |
328 | | /* buf provides APLOGNO */ |
329 | | ap_log_error(APLOG_MARK, APLOG_DEBUG, main_s, buf); |
330 | | } |
331 | | #endif |
332 | | |
333 | | |
334 | | /* This hashing function is designed to get good distribution in the cases |
335 | | * where the server is handling entire "networks" of servers. i.e. a |
336 | | * whack of /24s. This is probably the most common configuration for |
337 | | * ISPs with large virtual servers. |
338 | | * |
339 | | * NOTE: This function is symmetric (i.e. collapses all 4 octets |
340 | | * into one), so machine byte order (big/little endianness) does not matter. |
341 | | * |
342 | | * Hash function provided by David Hankins. |
343 | | */ |
344 | | static APR_INLINE unsigned hash_inaddr(unsigned key) |
345 | 0 | { |
346 | 0 | key ^= (key >> 16); |
347 | 0 | return ((key >> 8) ^ key) % IPHASH_TABLE_SIZE; |
348 | 0 | } |
349 | | |
350 | | static APR_INLINE unsigned hash_addr(struct apr_sockaddr_t *sa) |
351 | 0 | { |
352 | 0 | unsigned key; |
353 | | |
354 | | /* The key is the last four bytes of the IP address. |
355 | | * For IPv4, this is the entire address, as always. |
356 | | * For IPv6, this is usually part of the MAC address. |
357 | | */ |
358 | 0 | key = *(unsigned *)((char *)sa->ipaddr_ptr + sa->ipaddr_len - 4); |
359 | 0 | return hash_inaddr(key); |
360 | 0 | } |
361 | | |
362 | | static ipaddr_chain *new_ipaddr_chain(apr_pool_t *p, |
363 | | server_rec *s, server_addr_rec *sar) |
364 | 0 | { |
365 | 0 | ipaddr_chain *new; |
366 | |
|
367 | 0 | new = apr_palloc(p, sizeof(*new)); |
368 | 0 | new->names = NULL; |
369 | 0 | new->initialnames = NULL; |
370 | 0 | new->server = s; |
371 | 0 | new->sar = sar; |
372 | 0 | new->next = NULL; |
373 | 0 | return new; |
374 | 0 | } |
375 | | |
376 | | |
377 | | static name_chain *new_name_chain(apr_pool_t *p, |
378 | | server_rec *s, server_addr_rec *sar) |
379 | 0 | { |
380 | 0 | name_chain *new; |
381 | |
|
382 | 0 | new = apr_palloc(p, sizeof(*new)); |
383 | 0 | new->server = s; |
384 | 0 | new->sar = sar; |
385 | 0 | new->next = NULL; |
386 | 0 | return new; |
387 | 0 | } |
388 | | |
389 | | |
390 | | static APR_INLINE ipaddr_chain *find_ipaddr(apr_sockaddr_t *sa) |
391 | 0 | { |
392 | 0 | unsigned bucket; |
393 | 0 | ipaddr_chain *trav = NULL; |
394 | 0 | ipaddr_chain *wild_match = NULL; |
395 | | |
396 | | /* scan the hash table for an exact match first */ |
397 | 0 | bucket = hash_addr(sa); |
398 | 0 | for (trav = iphash_table[bucket]; trav; trav = trav->next) { |
399 | 0 | server_addr_rec *sar = trav->sar; |
400 | 0 | apr_sockaddr_t *cur = sar->host_addr; |
401 | |
|
402 | 0 | if (cur->port == sa->port) { |
403 | 0 | if (apr_sockaddr_equal(cur, sa)) { |
404 | 0 | return trav; |
405 | 0 | } |
406 | 0 | } |
407 | 0 | if (wild_match == NULL && (cur->port == 0 || sa->port == 0)) { |
408 | 0 | if (apr_sockaddr_equal(cur, sa)) { |
409 | | /* don't break, continue looking for an exact match */ |
410 | 0 | wild_match = trav; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | 0 | return wild_match; |
415 | 0 | } |
416 | | |
417 | | static ipaddr_chain *find_default_server(apr_port_t port) |
418 | 0 | { |
419 | 0 | server_addr_rec *sar; |
420 | 0 | ipaddr_chain *trav = NULL; |
421 | 0 | ipaddr_chain *wild_match = NULL; |
422 | |
|
423 | 0 | for (trav = default_list; trav; trav = trav->next) { |
424 | 0 | sar = trav->sar; |
425 | 0 | if (sar->host_port == port) { |
426 | | /* match! */ |
427 | 0 | return trav; |
428 | 0 | } |
429 | 0 | if (wild_match == NULL && sar->host_port == 0) { |
430 | | /* don't break, continue looking for an exact match */ |
431 | 0 | wild_match = trav; |
432 | 0 | } |
433 | 0 | } |
434 | 0 | return wild_match; |
435 | 0 | } |
436 | | |
437 | | #if APR_HAVE_IPV6 |
438 | 0 | #define IS_IN6_ANYADDR(ad) ((ad)->family == APR_INET6 \ |
439 | 0 | && IN6_IS_ADDR_UNSPECIFIED(&(ad)->sa.sin6.sin6_addr)) |
440 | | #else |
441 | | #define IS_IN6_ANYADDR(ad) (0) |
442 | | #endif |
443 | | |
444 | | static void dump_a_vhost(apr_file_t *f, ipaddr_chain *ic) |
445 | 0 | { |
446 | 0 | name_chain *nc; |
447 | 0 | int len; |
448 | 0 | char buf[MAX_STRING_LEN]; |
449 | 0 | apr_sockaddr_t *ha = ic->sar->host_addr; |
450 | |
|
451 | 0 | if ((ha->family == APR_INET && ha->sa.sin.sin_addr.s_addr == INADDR_ANY) |
452 | 0 | || IS_IN6_ANYADDR(ha)) { |
453 | 0 | len = apr_snprintf(buf, sizeof(buf), "*:%u", |
454 | 0 | ic->sar->host_port); |
455 | 0 | } |
456 | 0 | else { |
457 | 0 | len = apr_snprintf(buf, sizeof(buf), "%pI", ha); |
458 | 0 | } |
459 | 0 | if (ic->sar->host_port == 0) { |
460 | 0 | buf[len-1] = '*'; |
461 | 0 | } |
462 | 0 | if (ic->names == NULL) { |
463 | 0 | apr_file_printf(f, "%-22s %s (%s:%u)\n", buf, |
464 | 0 | ic->server->server_hostname, |
465 | 0 | ic->server->defn_name, ic->server->defn_line_number); |
466 | 0 | return; |
467 | 0 | } |
468 | 0 | apr_file_printf(f, "%-22s is a NameVirtualHost\n" |
469 | 0 | "%8s default server %s (%s:%u)\n", |
470 | 0 | buf, "", ic->server->server_hostname, |
471 | 0 | ic->server->defn_name, ic->server->defn_line_number); |
472 | 0 | for (nc = ic->names; nc; nc = nc->next) { |
473 | 0 | if (nc->sar->host_port) { |
474 | 0 | apr_file_printf(f, "%8s port %u ", "", nc->sar->host_port); |
475 | 0 | } |
476 | 0 | else { |
477 | 0 | apr_file_printf(f, "%8s port * ", ""); |
478 | 0 | } |
479 | 0 | apr_file_printf(f, "namevhost %s (%s:%u)\n", |
480 | 0 | nc->server->server_hostname, |
481 | 0 | nc->server->defn_name, nc->server->defn_line_number); |
482 | 0 | if (nc->server->names) { |
483 | 0 | apr_array_header_t *names = nc->server->names; |
484 | 0 | char **name = (char **)names->elts; |
485 | 0 | int i; |
486 | 0 | for (i = 0; i < names->nelts; ++i) { |
487 | 0 | if (name[i]) { |
488 | 0 | apr_file_printf(f, "%16s alias %s\n", "", name[i]); |
489 | 0 | } |
490 | 0 | } |
491 | 0 | } |
492 | 0 | if (nc->server->wild_names) { |
493 | 0 | apr_array_header_t *names = nc->server->wild_names; |
494 | 0 | char **name = (char **)names->elts; |
495 | 0 | int i; |
496 | 0 | for (i = 0; i < names->nelts; ++i) { |
497 | 0 | if (name[i]) { |
498 | 0 | apr_file_printf(f, "%16s wild alias %s\n", "", name[i]); |
499 | 0 | } |
500 | 0 | } |
501 | 0 | } |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | static void dump_vhost_config(apr_file_t *f) |
506 | 0 | { |
507 | 0 | ipaddr_chain *ic; |
508 | 0 | int i; |
509 | |
|
510 | 0 | apr_file_printf(f, "VirtualHost configuration:\n"); |
511 | | |
512 | | /* non-wildcard servers */ |
513 | 0 | for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { |
514 | 0 | for (ic = iphash_table[i]; ic; ic = ic->next) { |
515 | 0 | dump_a_vhost(f, ic); |
516 | 0 | } |
517 | 0 | } |
518 | | |
519 | | /* wildcard servers */ |
520 | 0 | for (ic = default_list; ic; ic = ic->next) { |
521 | 0 | dump_a_vhost(f, ic); |
522 | 0 | } |
523 | 0 | } |
524 | | |
525 | | |
526 | | /* |
527 | | * When a second or later virtual host maps to the same IP chain, |
528 | | * add the relevant server names to the chain. Special care is taken |
529 | | * to avoid adding ic->names until we're sure there are multiple VH'es. |
530 | | */ |
531 | | static void add_name_vhost_config(apr_pool_t *p, server_rec *main_s, |
532 | | server_rec *s, server_addr_rec *sar, |
533 | | ipaddr_chain *ic) |
534 | 0 | { |
535 | |
|
536 | 0 | name_chain *nc = new_name_chain(p, s, sar); |
537 | 0 | nc->next = ic->names; |
538 | | |
539 | | /* iterating backwards, so each one we see becomes the current default server */ |
540 | 0 | ic->server = s; |
541 | |
|
542 | 0 | if (ic->names == NULL) { |
543 | 0 | if (ic->initialnames == NULL) { |
544 | | /* first pass, set these names aside in case we see another VH. |
545 | | * Until then, this looks like an IP-based VH to runtime. |
546 | | */ |
547 | 0 | ic->initialnames = nc; |
548 | 0 | } |
549 | 0 | else { |
550 | | /* second pass through this chain -- this really is an NVH, and we |
551 | | * have two sets of names to link in. |
552 | | */ |
553 | 0 | nc->next = ic->initialnames; |
554 | 0 | ic->names = nc; |
555 | 0 | ic->initialnames = NULL; |
556 | 0 | } |
557 | 0 | } |
558 | 0 | else { |
559 | | /* 3rd or more -- just keep stacking the names */ |
560 | 0 | ic->names = nc; |
561 | 0 | } |
562 | 0 | } |
563 | | |
564 | | /* compile the tables and such we need to do the run-time vhost lookups */ |
565 | | AP_DECLARE(void) ap_fini_vhost_config(apr_pool_t *p, server_rec *main_s) |
566 | 0 | { |
567 | 0 | server_addr_rec *sar; |
568 | 0 | int has_default_vhost_addr; |
569 | 0 | server_rec *s; |
570 | 0 | int i; |
571 | 0 | ipaddr_chain **iphash_table_tail[IPHASH_TABLE_SIZE]; |
572 | | |
573 | | /* Main host first */ |
574 | 0 | s = main_s; |
575 | |
|
576 | 0 | if (!s->server_hostname) { |
577 | 0 | s->server_hostname = ap_get_local_host(p); |
578 | 0 | } |
579 | | |
580 | | /* initialize the tails */ |
581 | 0 | for (i = 0; i < IPHASH_TABLE_SIZE; ++i) { |
582 | 0 | iphash_table_tail[i] = &iphash_table[i]; |
583 | 0 | } |
584 | | |
585 | | /* The next things to go into the hash table are the virtual hosts |
586 | | * themselves. They're listed off of main_s->next in the reverse |
587 | | * order they occurred in the config file, so we insert them at |
588 | | * the iphash_table_tail but don't advance the tail. |
589 | | */ |
590 | |
|
591 | 0 | for (s = main_s->next; s; s = s->next) { |
592 | 0 | server_addr_rec *sar_prev = NULL; |
593 | 0 | has_default_vhost_addr = 0; |
594 | 0 | for (sar = s->addrs; sar; sar = sar->next) { |
595 | 0 | ipaddr_chain *ic; |
596 | 0 | char inaddr_any[16] = {0}; /* big enough to handle IPv4 or IPv6 */ |
597 | | /* XXX: this treats 0.0.0.0 as a "default" server which matches no-exact-match for IPv6 */ |
598 | 0 | if (!memcmp(sar->host_addr->ipaddr_ptr, inaddr_any, sar->host_addr->ipaddr_len)) { |
599 | 0 | ic = find_default_server(sar->host_port); |
600 | |
|
601 | 0 | if (ic && sar->host_port == ic->sar->host_port) { /* we're a match for an existing "default server" */ |
602 | 0 | if (!sar_prev || memcmp(sar_prev->host_addr->ipaddr_ptr, inaddr_any, sar_prev->host_addr->ipaddr_len) |
603 | 0 | || sar_prev->host_port != sar->host_port) { |
604 | 0 | add_name_vhost_config(p, main_s, s, sar, ic); |
605 | 0 | } |
606 | 0 | } |
607 | 0 | else { |
608 | | /* No default server, or we found a default server but |
609 | | ** exactly one of us is a wildcard port, which means we want |
610 | | ** two ip-based vhosts not an NVH with two names |
611 | | */ |
612 | 0 | ic = new_ipaddr_chain(p, s, sar); |
613 | 0 | ic->next = default_list; |
614 | 0 | default_list = ic; |
615 | 0 | add_name_vhost_config(p, main_s, s, sar, ic); |
616 | 0 | } |
617 | 0 | has_default_vhost_addr = 1; |
618 | 0 | } |
619 | 0 | else { |
620 | | /* see if it matches something we've already got */ |
621 | 0 | ic = find_ipaddr(sar->host_addr); |
622 | |
|
623 | 0 | if (!ic || sar->host_port != ic->sar->host_port) { |
624 | | /* No matching server, or we found a matching server but |
625 | | ** exactly one of us is a wildcard port, which means we want |
626 | | ** two ip-based vhosts not an NVH with two names |
627 | | */ |
628 | 0 | unsigned bucket = hash_addr(sar->host_addr); |
629 | 0 | ic = new_ipaddr_chain(p, s, sar); |
630 | 0 | ic->next = *iphash_table_tail[bucket]; |
631 | 0 | *iphash_table_tail[bucket] = ic; |
632 | 0 | } |
633 | 0 | add_name_vhost_config(p, main_s, s, sar, ic); |
634 | 0 | } |
635 | 0 | sar_prev = sar; |
636 | 0 | } |
637 | | |
638 | | /* Ok now we want to set up a server_hostname if the user was |
639 | | * silly enough to forget one. |
640 | | * XXX: This is silly we should just crash and burn. |
641 | | */ |
642 | 0 | if (!s->server_hostname) { |
643 | 0 | if (has_default_vhost_addr) { |
644 | 0 | s->server_hostname = main_s->server_hostname; |
645 | 0 | } |
646 | 0 | else if (!s->addrs) { |
647 | | /* what else can we do? at this point this vhost has |
648 | | no configured name, probably because they used |
649 | | DNS in the VirtualHost statement. It's disabled |
650 | | anyhow by the host matching code. -djg */ |
651 | 0 | s->server_hostname = |
652 | 0 | apr_pstrdup(p, "bogus_host_without_forward_dns"); |
653 | 0 | } |
654 | 0 | else { |
655 | 0 | apr_status_t rv; |
656 | 0 | char *hostname; |
657 | |
|
658 | 0 | rv = apr_getnameinfo(&hostname, s->addrs->host_addr, 0); |
659 | 0 | if (rv == APR_SUCCESS) { |
660 | 0 | s->server_hostname = apr_pstrdup(p, hostname); |
661 | 0 | } |
662 | 0 | else { |
663 | | /* again, what can we do? They didn't specify a |
664 | | ServerName, and their DNS isn't working. -djg */ |
665 | 0 | char *ipaddr_str; |
666 | |
|
667 | 0 | apr_sockaddr_ip_get(&ipaddr_str, s->addrs->host_addr); |
668 | 0 | ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_s, APLOGNO(00549) |
669 | 0 | "Failed to resolve server name " |
670 | 0 | "for %s (check DNS) -- or specify an explicit " |
671 | 0 | "ServerName", |
672 | 0 | ipaddr_str); |
673 | 0 | s->server_hostname = |
674 | 0 | apr_pstrdup(p, "bogus_host_without_reverse_dns"); |
675 | 0 | } |
676 | 0 | } |
677 | 0 | } |
678 | 0 | } |
679 | |
|
680 | | #ifdef IPHASH_STATISTICS |
681 | | dump_iphash_statistics(main_s); |
682 | | #endif |
683 | 0 | if (ap_exists_config_define("DUMP_VHOSTS")) { |
684 | 0 | apr_file_t *thefile = NULL; |
685 | 0 | apr_file_open_stdout(&thefile, p); |
686 | 0 | dump_vhost_config(thefile); |
687 | 0 | } |
688 | 0 | } |
689 | | |
690 | | /***************************************************************************** |
691 | | * run-time vhost matching functions |
692 | | */ |
693 | | |
694 | | static apr_status_t fix_hostname_v6_literal(request_rec *r, char *host) |
695 | 0 | { |
696 | 0 | char *dst; |
697 | 0 | int double_colon = 0; |
698 | |
|
699 | 0 | for (dst = host; *dst; dst++) { |
700 | 0 | if (apr_isxdigit(*dst)) { |
701 | 0 | if (apr_isupper(*dst)) { |
702 | 0 | *dst = apr_tolower(*dst); |
703 | 0 | } |
704 | 0 | } |
705 | 0 | else if (*dst == ':') { |
706 | 0 | if (*(dst + 1) == ':') { |
707 | 0 | if (double_colon) |
708 | 0 | return APR_EINVAL; |
709 | 0 | double_colon = 1; |
710 | 0 | } |
711 | 0 | else if (*(dst + 1) == '.') { |
712 | 0 | return APR_EINVAL; |
713 | 0 | } |
714 | 0 | } |
715 | 0 | else if (*dst == '.') { |
716 | | /* For IPv4-mapped IPv6 addresses like ::FFFF:129.144.52.38 */ |
717 | 0 | if (*(dst + 1) == ':' || *(dst + 1) == '.') |
718 | 0 | return APR_EINVAL; |
719 | 0 | } |
720 | 0 | else { |
721 | 0 | return APR_EINVAL; |
722 | 0 | } |
723 | 0 | } |
724 | 0 | return APR_SUCCESS; |
725 | 0 | } |
726 | | |
727 | | static apr_status_t fix_hostname_non_v6(request_rec *r, char *host) |
728 | 0 | { |
729 | 0 | char *dst; |
730 | |
|
731 | 0 | for (dst = host; *dst; dst++) { |
732 | 0 | if (apr_islower(*dst)) { |
733 | | /* leave char unchanged */ |
734 | 0 | } |
735 | 0 | else if (*dst == '.') { |
736 | 0 | if (*(dst + 1) == '.') { |
737 | 0 | return APR_EINVAL; |
738 | 0 | } |
739 | 0 | } |
740 | 0 | else if (apr_isupper(*dst)) { |
741 | 0 | *dst = apr_tolower(*dst); |
742 | 0 | } |
743 | 0 | else if (*dst == '/' || *dst == '\\') { |
744 | 0 | return APR_EINVAL; |
745 | 0 | } |
746 | 0 | } |
747 | | /* strip trailing gubbins */ |
748 | 0 | if (dst > host && dst[-1] == '.') { |
749 | 0 | dst[-1] = '\0'; |
750 | 0 | } |
751 | 0 | return APR_SUCCESS; |
752 | 0 | } |
753 | | |
754 | | /* |
755 | | * If strict mode ever becomes the default, this should be folded into |
756 | | * fix_hostname_non_v6() |
757 | | */ |
758 | | static apr_status_t strict_hostname_check(request_rec *r, char *host) |
759 | 0 | { |
760 | 0 | char *ch; |
761 | 0 | int is_dotted_decimal = 1, leading_zeroes = 0, dots = 0; |
762 | |
|
763 | 0 | for (ch = host; *ch; ch++) { |
764 | 0 | if (apr_isalpha(*ch) || *ch == '-' || *ch == '_') { |
765 | 0 | is_dotted_decimal = 0; |
766 | 0 | } |
767 | 0 | else if (ch[0] == '.') { |
768 | 0 | dots++; |
769 | 0 | if (ch[1] == '0' && apr_isdigit(ch[2])) |
770 | 0 | leading_zeroes = 1; |
771 | 0 | } |
772 | 0 | else if (!apr_isdigit(*ch)) { |
773 | | /* also takes care of multiple Host headers by denying commas */ |
774 | 0 | goto bad; |
775 | 0 | } |
776 | 0 | } |
777 | 0 | if (is_dotted_decimal) { |
778 | 0 | if (host[0] == '.' || (host[0] == '0' && apr_isdigit(host[1]))) |
779 | 0 | leading_zeroes = 1; |
780 | 0 | if (leading_zeroes || dots != 3) { |
781 | | /* RFC 3986 7.4 */ |
782 | 0 | goto bad; |
783 | 0 | } |
784 | 0 | } |
785 | 0 | else { |
786 | | /* The top-level domain must start with a letter (RFC 1123 2.1) */ |
787 | 0 | while (ch > host && *ch != '.') |
788 | 0 | ch--; |
789 | 0 | if (ch[0] == '.' && ch[1] != '\0' && !apr_isalpha(ch[1])) |
790 | 0 | goto bad; |
791 | 0 | } |
792 | 0 | return APR_SUCCESS; |
793 | | |
794 | 0 | bad: |
795 | 0 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02415) |
796 | 0 | "[strict] Invalid host name '%s'%s%.6s", |
797 | 0 | host, *ch ? ", problem near: " : "", ch); |
798 | 0 | return APR_EINVAL; |
799 | 0 | } |
800 | | |
801 | | /* Lowercase and remove any trailing dot and/or :port from the hostname, |
802 | | * and check that it is sane. |
803 | | * |
804 | | * In most configurations the exact syntax of the hostname isn't |
805 | | * important so strict sanity checking isn't necessary. However, in |
806 | | * mass hosting setups (using mod_vhost_alias or mod_rewrite) where |
807 | | * the hostname is interpolated into the filename, we need to be sure |
808 | | * that the interpolation doesn't expose parts of the filesystem. |
809 | | * We don't do strict RFC 952 / RFC 1123 syntax checking in order |
810 | | * to support iDNS and people who erroneously use underscores. |
811 | | * Instead we just check for filesystem metacharacters: directory |
812 | | * separators / and \ and sequences of more than one dot. |
813 | | */ |
814 | | static int fix_hostname(request_rec *r, const char *host_header, |
815 | | unsigned http_conformance) |
816 | 0 | { |
817 | 0 | const char *src; |
818 | 0 | char *host, *scope_id; |
819 | 0 | apr_port_t port; |
820 | 0 | apr_status_t rv; |
821 | 0 | const char *c; |
822 | 0 | int is_v6literal = 0; |
823 | 0 | int strict = (http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); |
824 | |
|
825 | 0 | src = host_header ? host_header : r->hostname; |
826 | | |
827 | | /* According to RFC 2616, Host header field CAN be blank */ |
828 | 0 | if (!*src) { |
829 | 0 | return is_v6literal; |
830 | 0 | } |
831 | | |
832 | | /* apr_parse_addr_port will interpret a bare integer as a port |
833 | | * which is incorrect in this context. So treat it separately. |
834 | | */ |
835 | 0 | for (c = src; apr_isdigit(*c); ++c); |
836 | 0 | if (!*c) { |
837 | | /* pure integer */ |
838 | 0 | if (strict) { |
839 | | /* RFC 3986 7.4 */ |
840 | 0 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02416) |
841 | 0 | "[strict] purely numeric host names not allowed: %s", |
842 | 0 | src); |
843 | 0 | goto bad_nolog; |
844 | 0 | } |
845 | 0 | r->hostname = src; |
846 | 0 | return is_v6literal; |
847 | 0 | } |
848 | | |
849 | 0 | if (host_header) { |
850 | 0 | rv = apr_parse_addr_port(&host, &scope_id, &port, src, r->pool); |
851 | 0 | if (rv != APR_SUCCESS || scope_id) |
852 | 0 | goto bad; |
853 | 0 | if (port) { |
854 | | /* Don't throw the Host: header's port number away: |
855 | | save it in parsed_uri -- ap_get_server_port() needs it! */ |
856 | | /* @@@ XXX there should be a better way to pass the port. |
857 | | * Like r->hostname, there should be a r->portno |
858 | | */ |
859 | 0 | r->parsed_uri.port = port; |
860 | 0 | r->parsed_uri.port_str = apr_itoa(r->pool, (int)port); |
861 | 0 | } |
862 | 0 | if (host_header[0] == '[') |
863 | 0 | is_v6literal = 1; |
864 | 0 | } |
865 | 0 | else { |
866 | | /* |
867 | | * Already parsed, surrounding [ ] (if IPv6 literal) and :port have |
868 | | * already been removed. |
869 | | */ |
870 | 0 | host = apr_pstrdup(r->pool, r->hostname); |
871 | 0 | if (ap_strchr(host, ':') != NULL) |
872 | 0 | is_v6literal = 1; |
873 | 0 | } |
874 | | |
875 | 0 | if (is_v6literal) { |
876 | 0 | rv = fix_hostname_v6_literal(r, host); |
877 | 0 | } |
878 | 0 | else { |
879 | 0 | rv = fix_hostname_non_v6(r, host); |
880 | 0 | if (strict && rv == APR_SUCCESS) |
881 | 0 | rv = strict_hostname_check(r, host); |
882 | 0 | } |
883 | 0 | if (rv != APR_SUCCESS) |
884 | 0 | goto bad; |
885 | | |
886 | 0 | r->hostname = host; |
887 | 0 | return is_v6literal; |
888 | | |
889 | 0 | bad: |
890 | 0 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00550) |
891 | 0 | "Client sent malformed Host header: %s", |
892 | 0 | src); |
893 | 0 | bad_nolog: |
894 | 0 | r->status = HTTP_BAD_REQUEST; |
895 | 0 | return is_v6literal; |
896 | 0 | } |
897 | | |
898 | | /* return 1 if host matches ServerName or ServerAliases */ |
899 | | static int matches_aliases(server_rec *s, const char *host) |
900 | 0 | { |
901 | 0 | int i; |
902 | 0 | apr_array_header_t *names; |
903 | | |
904 | | /* match ServerName */ |
905 | 0 | if (!strcasecmp(host, s->server_hostname)) { |
906 | 0 | return 1; |
907 | 0 | } |
908 | | |
909 | | /* search all the aliases from ServerAlias directive */ |
910 | 0 | names = s->names; |
911 | 0 | if (names) { |
912 | 0 | char **name = (char **) names->elts; |
913 | 0 | for (i = 0; i < names->nelts; ++i) { |
914 | 0 | if (!name[i]) continue; |
915 | 0 | if (!strcasecmp(host, name[i])) |
916 | 0 | return 1; |
917 | 0 | } |
918 | 0 | } |
919 | 0 | names = s->wild_names; |
920 | 0 | if (names) { |
921 | 0 | char **name = (char **) names->elts; |
922 | 0 | for (i = 0; i < names->nelts; ++i) { |
923 | 0 | if (!name[i]) continue; |
924 | 0 | if (!ap_strcasecmp_match(host, name[i])) |
925 | 0 | return 1; |
926 | 0 | } |
927 | 0 | } |
928 | 0 | return 0; |
929 | 0 | } |
930 | | |
931 | | |
932 | | /* Suppose a request came in on the same socket as this r, and included |
933 | | * a header "Host: host:port", would it map to r->server? It's more |
934 | | * than just that though. When we do the normal matches for each request |
935 | | * we don't even bother considering Host: etc on non-namevirtualhosts, |
936 | | * we just call it a match. But here we require the host:port to match |
937 | | * the ServerName and/or ServerAliases. |
938 | | */ |
939 | | AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host, |
940 | | apr_port_t port) |
941 | 0 | { |
942 | 0 | server_rec *s; |
943 | 0 | server_addr_rec *sar; |
944 | |
|
945 | 0 | s = r->server; |
946 | | |
947 | | /* search all the <VirtualHost> values */ |
948 | | /* XXX: If this is a NameVirtualHost then we may not be doing the Right Thing |
949 | | * consider: |
950 | | * |
951 | | * NameVirtualHost 10.1.1.1 |
952 | | * <VirtualHost 10.1.1.1> |
953 | | * ServerName v1 |
954 | | * </VirtualHost> |
955 | | * <VirtualHost 10.1.1.1> |
956 | | * ServerName v2 |
957 | | * </VirtualHost> |
958 | | * |
959 | | * Suppose r->server is v2, and we're asked to match "10.1.1.1". We'll say |
960 | | * "yup it's v2", when really it isn't... if a request came in for 10.1.1.1 |
961 | | * it would really go to v1. |
962 | | */ |
963 | 0 | for (sar = s->addrs; sar; sar = sar->next) { |
964 | 0 | if ((sar->host_port == 0 || port == sar->host_port) |
965 | 0 | && !strcasecmp(host, sar->virthost)) { |
966 | 0 | return 1; |
967 | 0 | } |
968 | 0 | } |
969 | | |
970 | | /* the Port has to match now, because the rest don't have ports associated |
971 | | * with them. */ |
972 | 0 | if (port != s->port) { |
973 | 0 | return 0; |
974 | 0 | } |
975 | | |
976 | 0 | return matches_aliases(s, host); |
977 | 0 | } |
978 | | |
979 | | |
980 | | /* |
981 | | * Updates r->server from ServerName/ServerAlias. Per the interaction |
982 | | * of ip and name-based vhosts, it only looks in the best match from the |
983 | | * connection-level ip-based matching. |
984 | | * Returns HTTP_BAD_REQUEST if there was no match. |
985 | | */ |
986 | | static int update_server_from_aliases(request_rec *r) |
987 | 0 | { |
988 | | /* |
989 | | * Even if the request has a Host: header containing a port we ignore |
990 | | * that port. We always use the physical port of the socket. There |
991 | | * are a few reasons for this: |
992 | | * |
993 | | * - the default of 80 or 443 for SSL is easier to handle this way |
994 | | * - there is less of a possibility of a security problem |
995 | | * - it simplifies the data structure |
996 | | * - the client may have no idea that a proxy somewhere along the way |
997 | | * translated the request to another ip:port |
998 | | * - except for the addresses from the VirtualHost line, none of the other |
999 | | * names we'll match have ports associated with them |
1000 | | */ |
1001 | 0 | const char *host = r->hostname; |
1002 | 0 | apr_port_t port; |
1003 | 0 | server_rec *s; |
1004 | 0 | server_rec *virthost_s; |
1005 | 0 | server_rec *last_s; |
1006 | 0 | name_chain *src; |
1007 | |
|
1008 | 0 | virthost_s = NULL; |
1009 | 0 | last_s = NULL; |
1010 | |
|
1011 | 0 | port = r->connection->local_addr->port; |
1012 | | |
1013 | | /* Recall that the name_chain is a list of server_addr_recs, some of |
1014 | | * whose ports may not match. Also each server may appear more than |
1015 | | * once in the chain -- specifically, it will appear once for each |
1016 | | * address from its VirtualHost line which matched. We only want to |
1017 | | * do the full ServerName/ServerAlias comparisons once for each |
1018 | | * server, fortunately we know that all the VirtualHost addresses for |
1019 | | * a single server are adjacent to each other. |
1020 | | */ |
1021 | |
|
1022 | 0 | for (src = r->connection->vhost_lookup_data; src; src = src->next) { |
1023 | 0 | server_addr_rec *sar; |
1024 | | |
1025 | | /* We only consider addresses on the name_chain which have a matching |
1026 | | * port |
1027 | | */ |
1028 | 0 | sar = src->sar; |
1029 | 0 | if (sar->host_port != 0 && port != sar->host_port) { |
1030 | 0 | continue; |
1031 | 0 | } |
1032 | | |
1033 | 0 | s = src->server; |
1034 | | |
1035 | | /* If we still need to do ServerName and ServerAlias checks for this |
1036 | | * server, do them now. |
1037 | | */ |
1038 | 0 | if (s != last_s) { |
1039 | | /* does it match any ServerName or ServerAlias directive? */ |
1040 | 0 | if (matches_aliases(s, host)) { |
1041 | 0 | goto found; |
1042 | 0 | } |
1043 | 0 | } |
1044 | | |
1045 | | /* Fallback: does it match the virthost from the sar? |
1046 | | * (only the first match is used) |
1047 | | */ |
1048 | 0 | if (virthost_s == NULL) { |
1049 | 0 | if (!strcasecmp(host, sar->virthost)) { |
1050 | 0 | virthost_s = s; |
1051 | 0 | } |
1052 | 0 | } |
1053 | |
|
1054 | 0 | last_s = s; |
1055 | 0 | } |
1056 | | |
1057 | | /* If ServerName and ServerAlias check failed, we end up here. If it |
1058 | | * matches a VirtualHost, virthost_s is set. Use that as fallback |
1059 | | */ |
1060 | 0 | if (virthost_s) { |
1061 | 0 | s = virthost_s; |
1062 | 0 | goto found; |
1063 | 0 | } |
1064 | | |
1065 | 0 | if (!r->connection->vhost_lookup_data) { |
1066 | 0 | if (matches_aliases(r->server, host)) { |
1067 | 0 | s = r->server; |
1068 | 0 | goto found; |
1069 | 0 | } |
1070 | 0 | } |
1071 | 0 | return HTTP_BAD_REQUEST; |
1072 | | |
1073 | 0 | found: |
1074 | | /* s is the first matching server, we're done */ |
1075 | 0 | r->server = s; |
1076 | 0 | return HTTP_OK; |
1077 | 0 | } |
1078 | | |
1079 | | |
1080 | | static void check_serverpath(request_rec *r) |
1081 | 0 | { |
1082 | 0 | server_rec *s; |
1083 | 0 | server_rec *last_s; |
1084 | 0 | name_chain *src; |
1085 | 0 | apr_port_t port; |
1086 | |
|
1087 | 0 | port = r->connection->local_addr->port; |
1088 | | |
1089 | | /* |
1090 | | * This is in conjunction with the ServerPath code in http_core, so we |
1091 | | * get the right host attached to a non- Host-sending request. |
1092 | | * |
1093 | | * See the comment in update_server_from_aliases about how each vhost can be |
1094 | | * listed multiple times. |
1095 | | */ |
1096 | |
|
1097 | 0 | last_s = NULL; |
1098 | 0 | for (src = r->connection->vhost_lookup_data; src; src = src->next) { |
1099 | | /* We only consider addresses on the name_chain which have a matching |
1100 | | * port |
1101 | | */ |
1102 | 0 | if (src->sar->host_port != 0 && port != src->sar->host_port) { |
1103 | 0 | continue; |
1104 | 0 | } |
1105 | | |
1106 | 0 | s = src->server; |
1107 | 0 | if (s == last_s) { |
1108 | 0 | continue; |
1109 | 0 | } |
1110 | 0 | last_s = s; |
1111 | |
|
1112 | 0 | if (s->path && !strncmp(r->uri, s->path, s->pathlen) && |
1113 | 0 | (s->path[s->pathlen - 1] == '/' || |
1114 | 0 | r->uri[s->pathlen] == '/' || |
1115 | 0 | r->uri[s->pathlen] == '\0')) { |
1116 | 0 | r->server = s; |
1117 | 0 | return; |
1118 | 0 | } |
1119 | 0 | } |
1120 | 0 | } |
1121 | | |
1122 | | static APR_INLINE const char *construct_host_header(request_rec *r, |
1123 | | int is_v6literal) |
1124 | 0 | { |
1125 | 0 | struct iovec iov[5]; |
1126 | 0 | apr_size_t nvec = 0; |
1127 | | /* |
1128 | | * We cannot use ap_get_server_name/port here, because we must |
1129 | | * ignore UseCanonicalName/Port. |
1130 | | */ |
1131 | 0 | if (is_v6literal) { |
1132 | 0 | iov[nvec].iov_base = "["; |
1133 | 0 | iov[nvec].iov_len = 1; |
1134 | 0 | nvec++; |
1135 | 0 | } |
1136 | 0 | iov[nvec].iov_base = (void *)r->hostname; |
1137 | 0 | iov[nvec].iov_len = strlen(r->hostname); |
1138 | 0 | nvec++; |
1139 | 0 | if (is_v6literal) { |
1140 | 0 | iov[nvec].iov_base = "]"; |
1141 | 0 | iov[nvec].iov_len = 1; |
1142 | 0 | nvec++; |
1143 | 0 | } |
1144 | 0 | if (r->parsed_uri.port_str) { |
1145 | 0 | iov[nvec].iov_base = ":"; |
1146 | 0 | iov[nvec].iov_len = 1; |
1147 | 0 | nvec++; |
1148 | 0 | iov[nvec].iov_base = r->parsed_uri.port_str; |
1149 | 0 | iov[nvec].iov_len = strlen(r->parsed_uri.port_str); |
1150 | 0 | nvec++; |
1151 | 0 | } |
1152 | 0 | return apr_pstrcatv(r->pool, iov, nvec, NULL); |
1153 | 0 | } |
1154 | | |
1155 | | AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) |
1156 | 0 | { |
1157 | 0 | ap_update_vhost_from_headers_ex(r, 0); |
1158 | 0 | } |
1159 | | |
1160 | | AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match) |
1161 | 0 | { |
1162 | 0 | core_server_config *conf = ap_get_core_module_config(r->server->module_config); |
1163 | 0 | const char *host_header = apr_table_get(r->headers_in, "Host"); |
1164 | 0 | int is_v6literal = 0; |
1165 | 0 | int have_hostname_from_url = 0; |
1166 | 0 | int rc = HTTP_OK; |
1167 | |
|
1168 | 0 | if (r->hostname) { |
1169 | | /* |
1170 | | * If there was a host part in the Request-URI, ignore the 'Host' |
1171 | | * header. |
1172 | | */ |
1173 | 0 | have_hostname_from_url = 1; |
1174 | 0 | is_v6literal = fix_hostname(r, NULL, conf->http_conformance); |
1175 | 0 | } |
1176 | 0 | else if (host_header != NULL) { |
1177 | 0 | is_v6literal = fix_hostname(r, host_header, conf->http_conformance); |
1178 | 0 | } |
1179 | 0 | if (!require_match && r->status != HTTP_OK) |
1180 | 0 | return HTTP_OK; |
1181 | | |
1182 | 0 | if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) { |
1183 | | /* |
1184 | | * If we have both hostname from an absoluteURI and a Host header, |
1185 | | * we must ignore the Host header (RFC 2616 5.2). |
1186 | | * To enforce this, we reset the Host header to the value from the |
1187 | | * request line. |
1188 | | */ |
1189 | 0 | if (have_hostname_from_url && host_header != NULL) { |
1190 | 0 | const char *repl = construct_host_header(r, is_v6literal); |
1191 | 0 | apr_table_setn(r->headers_in, "Host", repl); |
1192 | 0 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02417) |
1193 | 0 | "Replacing host header '%s' with host '%s' given " |
1194 | 0 | "in the request uri", host_header, repl); |
1195 | 0 | } |
1196 | 0 | } |
1197 | | |
1198 | | /* check if we tucked away a name_chain */ |
1199 | 0 | if (r->connection->vhost_lookup_data) { |
1200 | 0 | if (r->hostname) |
1201 | 0 | rc = update_server_from_aliases(r); |
1202 | 0 | else |
1203 | 0 | check_serverpath(r); |
1204 | 0 | } |
1205 | 0 | else if (require_match && r->hostname) { |
1206 | | /* check the base server config */ |
1207 | 0 | rc = update_server_from_aliases(r); |
1208 | 0 | } |
1209 | | |
1210 | 0 | return rc; |
1211 | 0 | } |
1212 | | |
1213 | | /** |
1214 | | * For every virtual host on this connection, call func_cb. |
1215 | | */ |
1216 | | AP_DECLARE(int) ap_vhost_iterate_given_conn(conn_rec *conn, |
1217 | | ap_vhost_iterate_conn_cb func_cb, |
1218 | | void* baton) |
1219 | 0 | { |
1220 | 0 | server_rec *s; |
1221 | 0 | server_rec *last_s; |
1222 | 0 | name_chain *src; |
1223 | 0 | apr_port_t port; |
1224 | 0 | int rv = 0; |
1225 | |
|
1226 | 0 | if (conn->vhost_lookup_data) { |
1227 | 0 | last_s = NULL; |
1228 | 0 | port = conn->local_addr->port; |
1229 | |
|
1230 | 0 | for (src = conn->vhost_lookup_data; src; src = src->next) { |
1231 | 0 | server_addr_rec *sar; |
1232 | | |
1233 | | /* We only consider addresses on the name_chain which have a |
1234 | | * matching port. |
1235 | | */ |
1236 | 0 | sar = src->sar; |
1237 | 0 | if (sar->host_port != 0 && port != sar->host_port) { |
1238 | 0 | continue; |
1239 | 0 | } |
1240 | | |
1241 | 0 | s = src->server; |
1242 | |
|
1243 | 0 | if (s == last_s) { |
1244 | | /* we've already done a callback for this vhost. */ |
1245 | 0 | continue; |
1246 | 0 | } |
1247 | | |
1248 | 0 | last_s = s; |
1249 | |
|
1250 | 0 | rv = func_cb(baton, conn, s); |
1251 | |
|
1252 | 0 | if (rv != 0) { |
1253 | 0 | break; |
1254 | 0 | } |
1255 | 0 | } |
1256 | 0 | } |
1257 | 0 | else { |
1258 | 0 | rv = func_cb(baton, conn, conn->base_server); |
1259 | 0 | } |
1260 | |
|
1261 | 0 | return rv; |
1262 | 0 | } |
1263 | | |
1264 | | /* Called for a new connection which has a known local_addr. Note that the |
1265 | | * new connection is assumed to have conn->server == main server. |
1266 | | */ |
1267 | | AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn) |
1268 | 0 | { |
1269 | 0 | ipaddr_chain *trav; |
1270 | 0 | apr_port_t port; |
1271 | | |
1272 | | /* scan the hash table for an exact match first */ |
1273 | 0 | trav = find_ipaddr(conn->local_addr); |
1274 | |
|
1275 | 0 | if (trav) { |
1276 | | /* save the name_chain for later in case this is a name-vhost */ |
1277 | 0 | conn->vhost_lookup_data = trav->names; |
1278 | 0 | conn->base_server = trav->server; |
1279 | 0 | return; |
1280 | 0 | } |
1281 | | |
1282 | | /* maybe there's a default server or wildcard name-based vhost |
1283 | | * matching this port |
1284 | | */ |
1285 | 0 | port = conn->local_addr->port; |
1286 | |
|
1287 | 0 | trav = find_default_server(port); |
1288 | 0 | if (trav) { |
1289 | 0 | conn->vhost_lookup_data = trav->names; |
1290 | 0 | conn->base_server = trav->server; |
1291 | 0 | return; |
1292 | 0 | } |
1293 | | |
1294 | | /* otherwise we're stuck with just the main server |
1295 | | * and no name-based vhosts |
1296 | | */ |
1297 | 0 | conn->vhost_lookup_data = NULL; |
1298 | 0 | } |