From d91d28abc6ac125271e897b8c45ef00efcf450dc Mon Sep 17 00:00:00 2001 From: Christos Pollalis Date: Mon, 9 Jan 2017 16:05:25 +0200 Subject: [PATCH 1/3] Wait for xtables lock to be released in case another process is modifying IPtables --- vpn-proxy/app/tunnels.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/vpn-proxy/app/tunnels.py b/vpn-proxy/app/tunnels.py index 3567371..704a06a 100644 --- a/vpn-proxy/app/tunnels.py +++ b/vpn-proxy/app/tunnels.py @@ -297,22 +297,28 @@ def check_iptables(forwarding, job='-C', rule=''): DNAT incoming packets in order to force forwarding --> private host (IP, PORT) MASQUERADE packets routed via the virtual interface""" - mangle_rule = ['iptables', '-t', 'mangle', job, 'PREROUTING', - '-p', 'tcp', '-i', str(IN_IFACE), '-s', str(SOURCE_CIDRS), + mangle_rule = ['iptables', '-w', '-t', 'mangle', job, 'PREROUTING', + '-p', 'tcp', + '-i', str(IN_IFACE), + '-s', str(SOURCE_CIDRS), '--destination-port', str(forwarding.loc_port), '-j', 'MARK', '--set-mark', str(forwarding.tunnel.id)] - nat_rule = ['iptables', '-t', 'nat', job, 'PREROUTING', - '-p', 'tcp', '-i', str(IN_IFACE), '-s', str(SOURCE_CIDRS), + nat_rule = ['iptables', '-w', '-t', 'nat', job, 'PREROUTING', + '-p', 'tcp', + '-i', str(IN_IFACE), + '-s', str(SOURCE_CIDRS), '--destination-port', str(forwarding.loc_port), '-j', 'DNAT', '--to-destination', str(forwarding.destination)] - mask_rule = ['iptables', '-t', 'nat', job, 'POSTROUTING', - '-p', 'tcp', '-o', str(forwarding.tunnel.name), + mask_rule = ['iptables', '-w', '-t', 'nat', job, 'POSTROUTING', + '-p', 'tcp', + '-o', str(forwarding.tunnel.name), '-s', str(SOURCE_CIDRS), '-d', str(forwarding.dst_addr), '--destination-port', str(forwarding.dst_port), '-j', 'MASQUERADE'] + rules = {'mangle': mangle_rule, 'nat': nat_rule, 'mask': mask_rule} if job == '-C' and rule == '': exitcodes = {} From 070535069b7b1286f2d6e362b2fdeb902199cf17 Mon Sep 17 00:00:00 2001 From: Christos Pollalis Date: Mon, 9 Jan 2017 16:10:20 +0200 Subject: [PATCH 2/3] Added cronjob for IPtables retention which, by default, deletes IPtables rules that have not been updated the last 24h. --- cronjobs/README.md | 10 ++++++++ cronjobs/iptables.sh | 22 +++++++++++++++++ .../management/commands/retain_iptables.py | 24 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 cronjobs/README.md create mode 100755 cronjobs/iptables.sh create mode 100644 vpn-proxy/app/management/commands/retain_iptables.py diff --git a/cronjobs/README.md b/cronjobs/README.md new file mode 100644 index 0000000..2450cf3 --- /dev/null +++ b/cronjobs/README.md @@ -0,0 +1,10 @@ +# Cronjob directory for vpn-proxy + +Executables contained in this directory are used to create cronjobs. + +## IPtables Retention + +In order to minimize the overhead of parsing large IPtables chains, we are +applying an IPtables retention policy. The `iptables.sh` appends a daily +cronjob under /etc/cron.daily/ in order to take care of disabling IPtables +rules, which have not been updated the last 24h. diff --git a/cronjobs/iptables.sh b/cronjobs/iptables.sh new file mode 100755 index 0000000..9004527 --- /dev/null +++ b/cronjobs/iptables.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )" +LOG="$DIR/iptables-retention.log" + +cat > /etc/cron.daily/vpn-proxy-iptables << EOF +#!/bin/sh + +main () { + echo + echo "=========== IPtables Retention ===========" + echo "Triggered at: `date`" + echo "==========================================" + echo + cd $DIR/vpn-proxy && ./manage.py retain_iptables +} + +main >> $LOG 2>&1 +EOF +chmod +x /etc/cron.daily/vpn-proxy-iptables + +echo "Cronjob for IPtables retention added under /etc/cron.daily/" diff --git a/vpn-proxy/app/management/commands/retain_iptables.py b/vpn-proxy/app/management/commands/retain_iptables.py new file mode 100644 index 0000000..323016d --- /dev/null +++ b/vpn-proxy/app/management/commands/retain_iptables.py @@ -0,0 +1,24 @@ +from django.core.management.base import BaseCommand +from app.models import Forwarding + +import datetime + + +class Command(BaseCommand): + help = "Trigger IPtables retention." + + def add_arguments(self, parser): + parser.add_argument('tunnel', nargs='*', type=int) + parser.add_argument('--time', default=(60 * 60 * 24), type=int) + + def handle(self, *args, **kwargs): + query = {} + query['updated_at__lt'] = ( + datetime.datetime.utcnow() - + datetime.timedelta(seconds=kwargs['time']) + ) + if kwargs['tunnel']: + query['tunnel_id__in'] = kwargs['tunnel'] + for frule in Forwarding.objects.filter(**query): + self.stdout.write("Disabling %s..." % frule) + frule.disable() From 9f66a655615800ab931e3ed59ca71b937800f0dd Mon Sep 17 00:00:00 2001 From: Christos Pollalis Date: Mon, 9 Jan 2017 16:12:54 +0200 Subject: [PATCH 3/3] Fixed help message --- vpn-proxy/app/management/commands/reset_tunnels.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpn-proxy/app/management/commands/reset_tunnels.py b/vpn-proxy/app/management/commands/reset_tunnels.py index 7ae1bad..8fd65c0 100644 --- a/vpn-proxy/app/management/commands/reset_tunnels.py +++ b/vpn-proxy/app/management/commands/reset_tunnels.py @@ -3,7 +3,7 @@ class Command(BaseCommand): - help = "Create superuser if missing (Non Interactive)." + help = "Reset Tunnel(s)" def add_arguments(self, parser): parser.add_argument('tunnel', nargs='*', type=int)