mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
Merge branch 'issue360' into 'master'
Don't apply BanIP checks to clients on the same subnet. Closes #360 See merge request openconnect/ocserv!222
This commit is contained in:
124
src/main-ban.c
124
src/main-ban.c
@@ -43,6 +43,10 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/htable/htable.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
static bool if_address_test_local(main_server_st * s, struct sockaddr_storage *addr);
|
||||
|
||||
static size_t rehash(const void *_e, void *unused)
|
||||
{
|
||||
@@ -270,6 +274,11 @@ unsigned check_if_banned(main_server_st *s, struct sockaddr_storage *addr, sockl
|
||||
|
||||
(void)(txt);
|
||||
|
||||
if (if_address_test_local(s, addr)) {
|
||||
mslog(s, NULL, LOG_DEBUG, "Not applying ban to local IP: %s", human_addr2((struct sockaddr*)addr, addr_size, txt, sizeof(txt), 0));
|
||||
return 0;
|
||||
}
|
||||
|
||||
in_size = SA_IN_SIZE(addr_size);
|
||||
if (in_size != 4 && in_size != 16) {
|
||||
mslog(s, NULL, LOG_ERR, "unknown address type for %s", human_addr2((struct sockaddr*)addr, addr_size, txt, sizeof(txt), 0));
|
||||
@@ -320,3 +329,118 @@ void cleanup_banned_entries(main_server_st *s)
|
||||
}
|
||||
}
|
||||
|
||||
int if_address_init(main_server_st *s)
|
||||
{
|
||||
struct ifaddrs * ifaddr = NULL, *ifa;
|
||||
if_address_st * local_if_addresses = NULL;
|
||||
int retval = 0;
|
||||
unsigned count = 0;
|
||||
s->if_addresses_count = 0;
|
||||
s->if_addresses = NULL;
|
||||
|
||||
if (getifaddrs(&ifaddr) < 0) {
|
||||
int err = errno;
|
||||
fprintf(stderr, "Failed to read local if address list: %s", strerror(err));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
continue;
|
||||
}
|
||||
count ++;
|
||||
}
|
||||
|
||||
local_if_addresses = talloc_array(s, if_address_st, count);
|
||||
if (local_if_addresses == NULL) {
|
||||
fprintf(stderr, "Failed to allocate");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
sa_family_t family;
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
continue;
|
||||
}
|
||||
family = ifa->ifa_addr->sa_family;
|
||||
if (family == AF_INET || family == AF_INET6) {
|
||||
memcpy(&local_if_addresses[count].if_addr, ifa->ifa_addr, sizeof(struct sockaddr));
|
||||
memcpy(&local_if_addresses[count].if_netmask, ifa->ifa_netmask, sizeof(struct sockaddr));
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
s->if_addresses = local_if_addresses;
|
||||
s->if_addresses_count = count;
|
||||
local_if_addresses = NULL;
|
||||
|
||||
retval = 1;
|
||||
|
||||
cleanup:
|
||||
if (ifaddr != NULL)
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
if (local_if_addresses != NULL)
|
||||
talloc_free(local_if_addresses);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool test_local_ipv4(struct sockaddr_in * remote, struct sockaddr_in * local, struct sockaddr_in * network)
|
||||
{
|
||||
uint32_t l = local->sin_addr.s_addr & network->sin_addr.s_addr;
|
||||
uint32_t r = remote->sin_addr.s_addr & network->sin_addr.s_addr;
|
||||
if (l != r)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool test_local_ipv6(struct sockaddr_in6 * remote, struct sockaddr_in6 * local, struct sockaddr_in6 * network)
|
||||
{
|
||||
unsigned index = 0;
|
||||
|
||||
for (index = 0; index < 4; index ++) {
|
||||
uint32_t l = local->sin6_addr.s6_addr32[index] & network->sin6_addr.s6_addr32[index];
|
||||
uint32_t r = remote->sin6_addr.s6_addr32[index] & network->sin6_addr.s6_addr32[index];
|
||||
if (l != r)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool if_address_test_local(main_server_st * s, struct sockaddr_storage *addr)
|
||||
{
|
||||
unsigned index;
|
||||
for (index = 0; index < s->if_addresses_count; index ++)
|
||||
{
|
||||
if_address_st * ifa = &s->if_addresses[index];
|
||||
if (ifa->if_addr.sa_family != addr->ss_family)
|
||||
continue;
|
||||
|
||||
switch (addr->ss_family) {
|
||||
case AF_INET:
|
||||
if (test_local_ipv4((struct sockaddr_in *)addr, (struct sockaddr_in *)&ifa->if_addr, (struct sockaddr_in *)&ifa->if_netmask))
|
||||
return true;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (test_local_ipv6((struct sockaddr_in6 *)addr, (struct sockaddr_in6 *)&ifa->if_addr, (struct sockaddr_in6 *)&ifa->if_netmask))
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void if_address_cleanup(main_server_st * s)
|
||||
{
|
||||
if (s->if_addresses)
|
||||
talloc_free(s->if_addresses);
|
||||
|
||||
s->if_addresses = NULL;
|
||||
s->if_addresses_count = 0;
|
||||
}
|
||||
@@ -44,4 +44,7 @@ unsigned main_ban_db_elems(main_server_st *s);
|
||||
void main_ban_db_deinit(main_server_st *s);
|
||||
void *main_ban_db_init(main_server_st *s);
|
||||
|
||||
int if_address_init(main_server_st *s);
|
||||
void if_address_cleanup(main_server_st * s);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -542,6 +542,7 @@ void clear_lists(main_server_st *s)
|
||||
proc_table_deinit(s);
|
||||
ctl_handler_deinit(s);
|
||||
main_ban_db_deinit(s);
|
||||
if_address_cleanup(s);
|
||||
|
||||
/* clear libev state */
|
||||
if (loop) {
|
||||
@@ -1441,6 +1442,11 @@ int main(int argc, char** argv)
|
||||
ip_lease_init(&s->ip_leases);
|
||||
proc_table_init(s);
|
||||
main_ban_db_init(s);
|
||||
if (if_address_init(s) == 0)
|
||||
{
|
||||
fprintf(stderr, "failed to initialize local addresses\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sigemptyset(&sig_default_set);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <vpn.h>
|
||||
@@ -261,6 +262,11 @@ typedef struct sec_mod_instance_st {
|
||||
|
||||
} sec_mod_instance_st;
|
||||
|
||||
typedef struct if_address_st {
|
||||
struct sockaddr if_addr;
|
||||
struct sockaddr if_netmask;
|
||||
} if_address_st;
|
||||
|
||||
typedef struct main_server_st {
|
||||
/* virtual hosts are only being added to that list, never removed */
|
||||
struct list_head *vconfig;
|
||||
@@ -301,6 +307,9 @@ typedef struct main_server_st {
|
||||
#ifdef RLIMIT_NOFILE
|
||||
struct rlimit fd_limits_default_set;
|
||||
#endif
|
||||
|
||||
struct if_address_st * if_addresses;
|
||||
unsigned int if_addresses_count;
|
||||
} main_server_st;
|
||||
|
||||
void clear_lists(main_server_st *s);
|
||||
|
||||
@@ -57,10 +57,10 @@ if ENABLE_ROOT_TESTS
|
||||
#other root requiring tests
|
||||
dist_check_SCRIPTS += haproxy-connect test-iroute test-multi-cookie test-pass-script \
|
||||
test-cookie-timeout test-cookie-timeout-2 test-explicit-ip \
|
||||
test-cookie-invalidation test-user-config test-append-routes test-ban \
|
||||
test-cookie-invalidation test-user-config test-append-routes test-ban \
|
||||
multiple-routes json test-udp-listen-host test-max-same-1 test-script-multi-user \
|
||||
apple-ios ipv6-iface test-namespace-listen disconnect-user disconnect-user2 \
|
||||
ping-leases
|
||||
ping-leases test-ban-local
|
||||
|
||||
if RADIUS_ENABLED
|
||||
dist_check_SCRIPTS += radius-group radius-otp
|
||||
|
||||
94
tests/test-ban-local
Executable file
94
tests/test-ban-local
Executable file
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2015 Red Hat
|
||||
#
|
||||
# This file is part of ocserv.
|
||||
#
|
||||
# ocserv is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the
|
||||
# Free Software Foundation; either version 2 of the License, or (at
|
||||
# your option) any later version.
|
||||
#
|
||||
# ocserv is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with GnuTLS; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
OCCTL="${OCCTL:-../src/occtl/occtl}"
|
||||
SERV="${SERV:-../src/ocserv}"
|
||||
srcdir=${srcdir:-.}
|
||||
OCCTL_SOCKET=./occtl-ban-$$.socket
|
||||
PIDFILE=ocserv-pid.$$.tmp
|
||||
OUTFILE=ban.$$.tmp
|
||||
|
||||
ADDRESS=127.0.0.1
|
||||
VPNNET=172.17.215.0/24
|
||||
VPNADDR=172.17.215.1
|
||||
VPNNET6=fc39:d561:62c6:861b:9f38:9734:9fa1:0/112
|
||||
VPNADDR6=fc39:d561:62c6:861b:9f38:9734:9fa1:0
|
||||
|
||||
|
||||
. `dirname $0`/common.sh
|
||||
|
||||
eval "${GETPORT}"
|
||||
|
||||
update_config test-ban.config
|
||||
if test "$VERBOSE" = 1;then
|
||||
DEBUG="-d 3"
|
||||
fi
|
||||
|
||||
function finish {
|
||||
set +e
|
||||
echo " * Cleaning up..."
|
||||
test -n "${PID}" && kill ${PID} >/dev/null 2>&1
|
||||
test -n "${PIDFILE}" && rm -f ${PIDFILE} >/dev/null 2>&1
|
||||
test -n "${CONFIG}" && rm -f ${CONFIG} >/dev/null 2>&1
|
||||
test -n "${OUTFILE}" && rm -f ${OUTFILE} >/dev/null 2>&1
|
||||
}
|
||||
trap finish EXIT
|
||||
|
||||
echo "Testing whether ban operates as expected on a local subnet ... "
|
||||
|
||||
echo $PORT
|
||||
|
||||
${SERV} -p ${PIDFILE} -f -c ${CONFIG} ${DEBUG} & PID=$!
|
||||
|
||||
sleep 4
|
||||
|
||||
echo "Connecting with wrong password 5 times... "
|
||||
echo "notest" | ${OPENCONNECT} --passwd-on-stdin -q ${ADDRESS}:${PORT} -u test --authenticate --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3
|
||||
echo "notest" | ${OPENCONNECT} --passwd-on-stdin -q ${ADDRESS}:${PORT} -u test --authenticate --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3
|
||||
echo "notest" | ${OPENCONNECT} --passwd-on-stdin -q ${ADDRESS}:${PORT} -u test --authenticate --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3
|
||||
echo "notest" | ${OPENCONNECT} --passwd-on-stdin -q ${ADDRESS}:${PORT} -u test --authenticate --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3
|
||||
echo "notest" | ${OPENCONNECT} --passwd-on-stdin -q ${ADDRESS}:${PORT} -u test --authenticate --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3
|
||||
|
||||
echo ""
|
||||
echo "Connecting with correct password... "
|
||||
eval `echo "test" | ${OPENCONNECT} --passwd-on-stdin -q ${ADDRESS}:${PORT} -u test --authenticate --servercert=d66b507ae074d03b02eafca40d35f87dd81049d3`
|
||||
|
||||
if [ -z "$COOKIE" ];then
|
||||
fail $PID "Could not obtain cookie even though client should be exempt"
|
||||
fi
|
||||
|
||||
${OCCTL} -s ${OCCTL_SOCKET} show status >${OUTFILE}
|
||||
if test $? != 0;then
|
||||
echo "occtl couldn't run!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
grep "IPs in ban list: 1$" ${OUTFILE}
|
||||
if test $? != 0;then
|
||||
echo "The banned list didn't contain the expected (1) entries!"
|
||||
cat ${OUTFILE}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
kill $PID
|
||||
wait
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user