mirror of
https://github.com/apache/httpd.git
synced 2025-08-15 23:27:39 +00:00
Merge of GH PR #440
*) core: Support zone/scope in IPv6 link-local addresses in Listen and VirtualHost directives (requires APR 1.7.x or later). PR 59396 [Joe Orton] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1918539 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
3
changes-entries/pr59396.txt
Normal file
3
changes-entries/pr59396.txt
Normal file
@ -0,0 +1,3 @@
|
||||
*) core: Support zone/scope in IPv6 link-local addresses in Listen and
|
||||
VirtualHost directives (requires APR 1.7.x or later). PR 59396
|
||||
[Joe Orton]
|
@ -19,6 +19,7 @@
|
||||
|
||||
#define APR_WANT_STRFUNC
|
||||
#include "apr_want.h"
|
||||
#include "apr_version.h"
|
||||
|
||||
#include "ap_config.h"
|
||||
#include "httpd.h"
|
||||
@ -277,8 +278,32 @@ static apr_status_t close_listeners_on_exec(void *v)
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/* Returns non-zero if socket address SA matches hostname, port and
|
||||
* scope_id. p is used for temporary allocations. */
|
||||
static int match_address(const apr_sockaddr_t *sa,
|
||||
const char *hostname, apr_port_t port,
|
||||
const char *scope_id, apr_pool_t *p)
|
||||
{
|
||||
const char *old_scope = NULL;
|
||||
|
||||
#if APR_VERSION_AT_LEAST(1,7,0)
|
||||
/* To be clever here we could correctly match numeric and
|
||||
* non-numeric zone ids. Ignore failure, old_scope will be left
|
||||
* as NULL. */
|
||||
(void) apr_sockaddr_zone_get(sa, &old_scope, NULL, p);
|
||||
#endif
|
||||
|
||||
return port == sa->port
|
||||
&& ((!hostname && !sa->hostname)
|
||||
|| (hostname && sa->hostname && !strcmp(sa->hostname, hostname)))
|
||||
&& ((!scope_id && !old_scope)
|
||||
|| (scope_id && old_scope && !strcmp(scope_id, old_scope)));
|
||||
}
|
||||
|
||||
/* ### This logic doesn't cope with DNS changes across a restart. */
|
||||
static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
|
||||
const char *addr, apr_port_t port)
|
||||
const char *addr, apr_port_t port,
|
||||
const char *scope_id, apr_pool_t *temp_pool)
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
@ -288,15 +313,10 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
|
||||
/* Some listeners are not real so they will not have a bind_addr. */
|
||||
if (sa) {
|
||||
ap_listen_rec *new;
|
||||
apr_port_t oldport;
|
||||
|
||||
oldport = sa->port;
|
||||
/* If both ports are equivalent, then if their names are equivalent,
|
||||
* then we will re-use the existing record.
|
||||
*/
|
||||
if (port == oldport &&
|
||||
((!addr && !sa->hostname) ||
|
||||
((addr && sa->hostname) && !strcmp(sa->hostname, addr)))) {
|
||||
/* Re-use the existing record if it matches completely
|
||||
* against an existing listener. */
|
||||
if (match_address(sa, addr, port, scope_id, temp_pool)) {
|
||||
found = 1;
|
||||
if (!to) {
|
||||
break;
|
||||
@ -317,19 +337,21 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
|
||||
|
||||
static const char *alloc_listener(process_rec *process, const char *addr,
|
||||
apr_port_t port, const char* proto,
|
||||
void *slave)
|
||||
const char *scope_id, void *slave,
|
||||
apr_pool_t *temp_pool)
|
||||
{
|
||||
ap_listen_rec *last;
|
||||
apr_status_t status;
|
||||
apr_sockaddr_t *sa;
|
||||
|
||||
/* see if we've got a listener for this address:port, which is an error */
|
||||
if (find_listeners(&ap_listeners, NULL, addr, port)) {
|
||||
if (find_listeners(&ap_listeners, NULL, addr, port, scope_id, temp_pool)) {
|
||||
return "Cannot define multiple Listeners on the same IP:port";
|
||||
}
|
||||
|
||||
/* see if we've got an old listener for this address:port */
|
||||
if (find_listeners(&old_listeners, &ap_listeners, addr, port)) {
|
||||
if (find_listeners(&old_listeners, &ap_listeners, addr, port,
|
||||
scope_id, temp_pool)) {
|
||||
if (ap_listeners->slave != slave) {
|
||||
return "Cannot define a slave on the same IP:port as a Listener";
|
||||
}
|
||||
@ -383,6 +405,18 @@ static const char *alloc_listener(process_rec *process, const char *addr,
|
||||
return "Listen setup failed";
|
||||
}
|
||||
|
||||
#if APR_VERSION_AT_LEAST(1,7,0)
|
||||
if (scope_id) {
|
||||
status = apr_sockaddr_zone_set(new->bind_addr, scope_id);
|
||||
if (status) {
|
||||
ap_log_perror(APLOG_MARK, APLOG_CRIT, status, process->pool, APLOGNO(10102)
|
||||
"alloc_listener: failed to set scope for %pI to %s",
|
||||
new->bind_addr, scope_id);
|
||||
return "Listen step failed";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We need to preserve the order returned by getaddrinfo() */
|
||||
if (last == NULL) {
|
||||
ap_listeners = last = new;
|
||||
@ -835,10 +869,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
host = NULL;
|
||||
}
|
||||
|
||||
#if !APR_VERSION_AT_LEAST(1,7,0)
|
||||
if (scope_id) {
|
||||
/* XXX scope id support is useful with link-local IPv6 addresses */
|
||||
return "Scope id is not supported";
|
||||
return apr_pstrcat(cmd->pool,
|
||||
"Scope ID in address '", argv[0],
|
||||
"' not supported with APR " APR_VERSION_STRING,
|
||||
NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!port) {
|
||||
return "Port must be specified";
|
||||
@ -856,7 +894,8 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
|
||||
ap_str_tolower(proto);
|
||||
}
|
||||
|
||||
return alloc_listener(cmd->server->process, host, port, proto, NULL);
|
||||
return alloc_listener(cmd->server->process, host, port, proto,
|
||||
scope_id, NULL, cmd->temp_pool);
|
||||
}
|
||||
|
||||
AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd,
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "apr.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_lib.h"
|
||||
#include "apr_version.h"
|
||||
|
||||
#define APR_WANT_STRFUNC
|
||||
#include "apr_want.h"
|
||||
@ -182,9 +183,14 @@ static const char *get_addresses(apr_pool_t *p, const char *w_,
|
||||
if (!host) {
|
||||
return "Missing address for VirtualHost";
|
||||
}
|
||||
#if !APR_VERSION_AT_LEAST(1,7,0)
|
||||
if (scope_id) {
|
||||
return "Scope ids are not supported";
|
||||
return apr_pstrcat(p,
|
||||
"Scope ID in address '", w,
|
||||
"' not supported with APR " APR_VERSION_STRING,
|
||||
NULL);
|
||||
}
|
||||
#endif
|
||||
if (!port && !wild_port) {
|
||||
port = default_port;
|
||||
}
|
||||
@ -203,6 +209,17 @@ static const char *get_addresses(apr_pool_t *p, const char *w_,
|
||||
"Could not resolve host name %s -- ignoring!", host);
|
||||
return NULL;
|
||||
}
|
||||
#if APR_VERSION_AT_LEAST(1,7,0)
|
||||
if (scope_id) {
|
||||
rv = apr_sockaddr_zone_set(my_addr, scope_id);
|
||||
if (rv) {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO(10103)
|
||||
"Could not set scope ID %s for %pI -- ignoring!",
|
||||
scope_id, my_addr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Remember all addresses for the host */
|
||||
|
Reference in New Issue
Block a user