mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 08:46:58 +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 <arpa/inet.h>
|
||||||
#include <ccan/hash/hash.h>
|
#include <ccan/hash/hash.h>
|
||||||
#include <ccan/htable/htable.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)
|
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);
|
(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);
|
in_size = SA_IN_SIZE(addr_size);
|
||||||
if (in_size != 4 && in_size != 16) {
|
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));
|
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_deinit(main_server_st *s);
|
||||||
void *main_ban_db_init(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
|
#endif
|
||||||
|
|||||||
@@ -542,6 +542,7 @@ void clear_lists(main_server_st *s)
|
|||||||
proc_table_deinit(s);
|
proc_table_deinit(s);
|
||||||
ctl_handler_deinit(s);
|
ctl_handler_deinit(s);
|
||||||
main_ban_db_deinit(s);
|
main_ban_db_deinit(s);
|
||||||
|
if_address_cleanup(s);
|
||||||
|
|
||||||
/* clear libev state */
|
/* clear libev state */
|
||||||
if (loop) {
|
if (loop) {
|
||||||
@@ -1441,6 +1442,11 @@ int main(int argc, char** argv)
|
|||||||
ip_lease_init(&s->ip_leases);
|
ip_lease_init(&s->ip_leases);
|
||||||
proc_table_init(s);
|
proc_table_init(s);
|
||||||
main_ban_db_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);
|
sigemptyset(&sig_default_set);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <vpn.h>
|
#include <vpn.h>
|
||||||
@@ -261,6 +262,11 @@ typedef struct sec_mod_instance_st {
|
|||||||
|
|
||||||
} 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 {
|
typedef struct main_server_st {
|
||||||
/* virtual hosts are only being added to that list, never removed */
|
/* virtual hosts are only being added to that list, never removed */
|
||||||
struct list_head *vconfig;
|
struct list_head *vconfig;
|
||||||
@@ -301,6 +307,9 @@ typedef struct main_server_st {
|
|||||||
#ifdef RLIMIT_NOFILE
|
#ifdef RLIMIT_NOFILE
|
||||||
struct rlimit fd_limits_default_set;
|
struct rlimit fd_limits_default_set;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct if_address_st * if_addresses;
|
||||||
|
unsigned int if_addresses_count;
|
||||||
} main_server_st;
|
} main_server_st;
|
||||||
|
|
||||||
void clear_lists(main_server_st *s);
|
void clear_lists(main_server_st *s);
|
||||||
|
|||||||
@@ -57,10 +57,10 @@ if ENABLE_ROOT_TESTS
|
|||||||
#other root requiring tests
|
#other root requiring tests
|
||||||
dist_check_SCRIPTS += haproxy-connect test-iroute test-multi-cookie test-pass-script \
|
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-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 \
|
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 \
|
apple-ios ipv6-iface test-namespace-listen disconnect-user disconnect-user2 \
|
||||||
ping-leases
|
ping-leases test-ban-local
|
||||||
|
|
||||||
if RADIUS_ENABLED
|
if RADIUS_ENABLED
|
||||||
dist_check_SCRIPTS += radius-group radius-otp
|
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