Enhanced configuration option 'restrict-user-to-ports'

This enhancement allows to negate the rules and allow the user connecting
to all ports except the specified.
This commit is contained in:
Nikos Mavrogiannopoulos
2015-12-07 11:15:54 +01:00
parent 8019490511
commit 14d19b3e9a
7 changed files with 104 additions and 11 deletions

View File

@@ -480,6 +480,9 @@ no-route = 192.168.5.0/255.255.255.0
# or in the per-user configuration.
#restrict-user-to-ports = "tcp(443), tcp(80), udp(443), sctp(99), tcp(583), icmp(), icmpv6()"
# You could also use negation, i.e., block the user from accessing these ports only.
#restrict-user-to-ports = "!(tcp(443), tcp(80))"
# When set to true, all client's iroutes are made visible to all
# connecting clients except for the ones offering them. This option
# only makes sense if config-per-user is set.

View File

@@ -27,7 +27,7 @@
#include <vpn.h>
static int append_port(void *pool, FwPortSt ***fw_ports, size_t *n_fw_ports, int port, fw_proto_t proto)
static int append_port(void *pool, FwPortSt ***fw_ports, size_t *n_fw_ports, int port, fw_proto_t proto, unsigned negate)
{
FwPortSt *current;
@@ -45,6 +45,7 @@ static int append_port(void *pool, FwPortSt ***fw_ports, size_t *n_fw_ports, int
current->port = port;
current->proto = proto;
current->negate = negate;
(*fw_ports)[*n_fw_ports] = current;
(*n_fw_ports)++;
@@ -61,13 +62,33 @@ int cfg_parse_ports(void *pool, FwPortSt ***fw_ports, size_t *n_fw_ports, const
unsigned finish = 0;
int port, ret;
fw_proto_t proto;
int negate = 0, bracket_start = 0;
if (str == NULL)
return 0;
p = str;
while (c_isspace(*p))
p++;
if (*p == '!') {
negate = 1;
p++;
while (c_isspace(*p) || (*p == '(')) {
if (*p == '(')
bracket_start = 1;
p++;
}
if (bracket_start == 0) {
syslog(LOG_ERR, "no bracket following negation at %d '%s'", (int)(ptrdiff_t)(p-str), str);
return -1;
}
}
do {
while (c_isspace(*p))
p++;
@@ -105,7 +126,7 @@ int cfg_parse_ports(void *pool, FwPortSt ***fw_ports, size_t *n_fw_ports, const
p++;
port = atoi(p);
ret = append_port(pool, fw_ports, n_fw_ports, port, proto);
ret = append_port(pool, fw_ports, n_fw_ports, port, proto, negate);
if (ret < 0) {
syslog(LOG_ERR, "memory error");
return -1;
@@ -121,7 +142,7 @@ int cfg_parse_ports(void *pool, FwPortSt ***fw_ports, size_t *n_fw_ports, const
while (c_isspace(*p2))
p2++;
if (*p2 == 0) {
if (*p2 == 0 || (negate != 0 && *p2 == ')')) {
finish = 1;
} else if (*p2 != ',') {
syslog(LOG_ERR, "expected comma or end of line on restrict-user-to-ports at %d '%s'", (int)(ptrdiff_t)(p2-str), str);

View File

@@ -18,6 +18,8 @@ message fw_port_st
required uint32 port = 1;
/* fw_proto_t */
required uint32 proto = 2;
/* negative rule, i.e., if non zero reject this port */
required uint32 negate = 3;
}
/* This is a structure for per-user/group supplemental configuration.

View File

@@ -62,7 +62,7 @@ static void export_fw_info(main_server_st *s, struct proc_st* proc)
str_st str4;
str_st str6;
str_st str_common;
unsigned i;
unsigned i, negate = 0;
int ret;
str_init(&str4, proc);
@@ -188,6 +188,9 @@ static void export_fw_info(main_server_st *s, struct proc_st* proc)
if (proc->config->n_fw_ports > 0) {
for (i=0;i<proc->config->n_fw_ports;i++) {
if (proc->config->fw_ports[i]->negate)
negate = 1;
switch(proc->config->fw_ports[i]->proto) {
case PROTO_UDP:
ret = str_append_printf(&str_common, "udp %u ", proc->config->fw_ports[i]->port);
@@ -216,9 +219,18 @@ static void export_fw_info(main_server_st *s, struct proc_st* proc)
}
}
if (str_common.length > 0 && setenv("OCSERV_PORTS", (char*)str_common.data, 1) == -1) {
mslog(s, proc, LOG_ERR, "could not export PORTS\n");
exit(1);
if (str_common.length > 0) {
if (negate) {
if (setenv("OCSERV_DENY_PORTS", (char*)str_common.data, 1) == -1) {
mslog(s, proc, LOG_ERR, "could not export DENY_PORTS\n");
exit(1);
}
} else {
if (setenv("OCSERV_ALLOW_PORTS", (char*)str_common.data, 1) == -1) {
mslog(s, proc, LOG_ERR, "could not export ALLOW_PORTS\n");
exit(1);
}
}
}
str_clear(&str_common);

View File

@@ -568,6 +568,9 @@ no-route = 192.168.5.0/255.255.255.0
# or in the per-user configuration.
#restrict-user-to-ports = "tcp(443), tcp(80), udp(443), sctp(99), tcp(583), icmp(), icmpv6()"
# You could also use negation, i.e., block the user from accessing these ports only.
#restrict-user-to-ports = "!(tcp(443), tcp(80))"
# When set to true, all client's iroutes are made visible to all
# connecting clients except for the ones offering them. This option
# only makes sense if config-per-user is set.

View File

@@ -124,6 +124,24 @@ allow_port() {
esac
}
deny_port() {
proto=$1
port=$2
case "$proto" in
icmp)
iptables -A INPUT -i ${DEVICE} -p $proto -j REJECT --match comment --comment "${COMMENT}"
;;
icmpv6)
ip6tables -A INPUT -i ${DEVICE} -p $proto -j REJECT --match comment --comment "${COMMENT}"
;;
*)
iptables -A INPUT -i ${DEVICE} -p $proto --dport $port -j REJECT --match comment --comment "${COMMENT}"
ip6tables -A INPUT -i ${DEVICE} -p $proto --dport $port -j REJECT --match comment --comment "${COMMENT}"
;;
esac
}
disallow_all_ports() {
iptables -A INPUT -i ${DEVICE} -j REJECT --match comment --comment "${COMMENT}"
ip6tables -A INPUT -i ${DEVICE} -j REJECT --match comment --comment "${COMMENT}"
@@ -140,24 +158,43 @@ for i in $OCSERV_DNS6;do
done
# block ports - if needed
if test -n "${OCSERV_PORTS}";then
if test -n "${OCSERV_DENY_PORTS}";then
INPUT_CHAIN="${SEC_INPUT_CHAIN}"
iptables -N "${INPUT_CHAIN}"
ip6tables -N "${INPUT_CHAIN}"
set ${OCSERV_PORTS}
set ${OCSERV_DENY_PORTS}
while test $# -gt 1; do
proto=$1
port=$2
allow_port $proto $port
deny_port $proto $port
if test $# -gt 1;then
shift 2
else
break
fi
done
disallow_all_ports
else
if test -n "${OCSERV_ALLOW_PORTS}";then
INPUT_CHAIN="${SEC_INPUT_CHAIN}"
iptables -N "${INPUT_CHAIN}"
ip6tables -N "${INPUT_CHAIN}"
set ${OCSERV_ALLOW_PORTS}
while test $# -gt 1; do
proto=$1
port=$2
allow_port $proto $port
if test $# -gt 1;then
shift 2
else
break
fi
done
disallow_all_ports
fi
fi
if test "${OCSERV_RESTRICT_TO_ROUTES}" = "1";then

View File

@@ -108,5 +108,20 @@ int main()
exit(1);
}
reset(fw_ports, n_fw_ports);
strcpy(p, "!(icmp(), tcp(88), udp(90), sctp(70), tcp(443), udp(80), icmpv6())");
ret = cfg_parse_ports(NULL, &fw_ports, &n_fw_ports, p);
if (ret < 0) {
fprintf(stderr, "error in %d\n", __LINE__);
exit(1);
}
check_vals(fw_ports, n_fw_ports);
if (fw_ports[0]->negate == 0) {
fprintf(stderr, "error in %d\n", __LINE__);
exit(1);
}
return 0;
}