Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions mod_evasive24.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,25 @@ static int access_checker(request_rec *r)
}

static int is_whitelisted(const apr_sockaddr_t *client, const evasive_config *cfg) {
int client_family;
struct in_addr addrv4;
struct in6_addr addrv6;

switch (client->family) {
case AF_INET:
client_family = AF_INET;
addrv4 = client->sa.sin.sin_addr;
break;
case AF_INET6:
struct in6_addr addr = client->sa.sin6.sin6_addr;
// In dual stack environments, AF_INET6 can also be IPv4-mapped IPv6 address (::ffff:x.x.x.x)
if (IN6_IS_ADDR_V4MAPPED(&addr)) {
client_family = AF_INET;
memcpy(&addrv4, &addr.s6_addr[12], 4);
} else {
client_family = AF_INET6;
addrv6 = addr;
}
break;
default:
ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "Invalid client family 0x%x", client->family);
Expand All @@ -617,15 +633,13 @@ static int is_whitelisted(const apr_sockaddr_t *client, const evasive_config *cf
const struct ip_node *node = &cfg->ip_whitelist.data[i];
int rc;

if (node->family != client->family)
if (node->family != client_family)
continue;

if (client->family == AF_INET) {
struct in_addr addrv4 = client->sa.sin.sin_addr;
if (client_family == AF_INET) {
addrv4.s_addr &= node->mask.v4;
rc = memcmp(&node->ip.v4, &addrv4, sizeof(node->ip.v4));
} else {
struct in6_addr addrv6 = client->sa.sin6.sin6_addr;
ipv6_apply_mask(&addrv6, &node->mask.v6);
rc = memcmp(&node->ip.v6, &addrv6, sizeof(node->ip.v6));
}
Expand Down