1

I am trying to route one users traffic through openvpn. Their traffic should be denied if the vpn goes down. I want to do this with a script attached to openvpn.

In my testing, this works for routing user through vpn until i use the DROP iptable... then the user loses all connectivity and the other rules are ignored..

this is all on debian stretch.

i found a nice comprehensive howto here: https://www.niftiestsoftware.com/2011/08/28/making-all-network-traffic-for-a-linux-user-use-a-specific-network-interface/comment-page-1/

and it works well, for the most part, except that I have the same problem as before. I can route traffic for a user to the vpn, but if the vpn is not present it falls back to eth0 or whatever.

if I try to prevent this with the equivalent of "allow on tun0, don't allow eth0" I end up blocking tun0 as well as eth0"

iptables -A OUTPUT -o eth0 -m owner --uid-owner $VPNUSER -j REJECT conflicts with

iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT
iptables -A OUTPUT -o tun0 -m owner --uid-owner $VPNUSER -j ACCEPT

what am I doing wrong here?

below was my first attempt, but now I am following the format of the link above:

iptables -F OUTPUT
iptables -I OUTPUT -m owner --uid-owner foo -j MARK --set-mark 42
iptables -I OUTPUT -d 10.20.0.0/24 -m owner --uid-owner foo
iptables -I OUTPUT -d VPNSERVERIP -p udp -j ACCEPT -m owner --uid-owner foo
iptables -I OUTPUT -j DROP -m owner --uid-owner foo
iptables -t nat -I POSTROUTING -o tun0 -j MASQUERADE

and then some other stuff to get the routing working...

ip rule add fwmark 42 table 42

for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
    echo 0 > $f
    done;
ip route add default via $(ifconfig -a tun0 | grep -o 'destination [^ ]*' | cut -d \  -f 2) table 42

after all this iptables -L OUTPUT looks like this:

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DROP       all  --  anywhere             anywhere             owner UID match foo
ACCEPT     udp  --  anywhere             VPNSERVERIP       owner UID match foo
           all  --  anywhere             10.20.0.0/24         owner UID match foo
MARK       all  --  anywhere             anywhere             owner UID match foo MARK set 0x2a
0

This may be of some help:

https://www.privateinternetaccess.com/forum/discussion/3615/howto-ubuntu-debian-block-all-traffic-on-the-eth-card-and-use-only-the-vpn-updated

They've blocked all traffic to eth0, then allowed some to pass later (DNS, ping)

goldsztajn

August 2014 in General Privacy Discussion

Posts: 4

(UPDATED)

Hi everybody,

I have tried to build a solution that will transform a Debian or Ubuntu machine to be able to access the Internet ONLY via the VPN (to avoid any mistake if you are disconnected or if OpenVPN crashes).

For your information, I use OpenVPN configured with the PIA config files and I assume you have only the eth0 on your computer.

1/ When the interfaces goes up, disable the trafic

/etc/network/interfaces

   auto eth0

   iface eth0 inet dhcp

       pre-up iptables-restore < /etc/iptables.rules

Then : /etc/iptables.rules

   *filter

   # Default Policy

   :INPUT DROP [0:0]

   :FORWARD DROP [0:0]

   :OUTPUT DROP [0:0]

   # Broadcast without logging

   -A INPUT -m pkttype --pkt-type broadcast -j DROP -m comment --comment "Block Broadcast INPUT (No log)"

   -A INPUT -m pkttype --pkt-type multicast -j DROP -m comment --comment "Block Multicast INPUT (No Log)"

   # Allow localhost

   -A INPUT  -i lo -m comment --comment "Accept localhost Input" -j ACCEPT

   -A OUTPUT -o lo -m comment --comment "Accept localhost Output" -j ACCEPT

   ## Allow to connect to upd 1194 (openvpn)

   -A OUTPUT -p udp --dport 1194 -j ACCEPT -m comment --comment "Allow my computer to query the DNS server"

   -A INPUT  -p udp --sport 1194 -m state --state ESTABLISHED -j ACCEPT  -m comment --comment "Allow the server to reply (related to lport)"

   # Allow DNS

   -A OUTPUT -p udp -d 209.222.18.222 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT -m comment --comment "Allow my machine to connect to the DNS1"

    -A INPUT  -p udp -s 209.222.18.222 --sport 53 -m state --state ESTABLISHED     -j ACCEPT -m comment --comment "Allow the DNS1 to answer"

   -A OUTPUT -p udp -d 209.222.18.218 --dport 53 -m state --state NEW,ESTABLISHED -j ACCEPT -m comment --comment "Allow my machine to connect to the DNS2"

   -A INPUT  -p udp -s 209.222.18.218 --sport 53 -m state --state ESTABLISHED     -j ACCEPT -m comment --comment "Allow the DNS2 to answer"

   # Logging

   -A INPUT -m limit --limit 10/min -j LOG --log-prefix "FW DROP INPUT: " --log-level 7 -m comment --comment "Log Input"

   -A FORWARD -m limit --limit 10/min -j LOG --log-prefix "FW DROP FORWARD: " --log-level 7 -m comment --comment "Log Forward"

   -A OUTPUT -m limit --limit 10/min -j LOG --log-prefix "FW DROP OUTPUT: " --log-level 7 -m comment --comment "Log Output"

   # Ping

   -A OUTPUT -p icmp --icmp-type 0 -m state --state ESTABLISHED,RELATED -j ACCEPT -m comment --comment "Allow ping to Outside"

   COMMIT

Then if you don't start your VPN, you have ... nothing, except localhost, DNS and OpenVPN

To apply the changes :

   # ifdown eth0

   # ifup eth0

When you start your VPN, to avoid DNS Leak I launch a script

I had to "hack" the /etc/default/openvpn file to add on top:

   # A pre script for Private Internet Access

/etc/openvpn/before_start.sh

That /etc/openvpn/before_start.sh contains:

   #!/bin/bash

   DNS1=209.222.18.222

   DNS2=209.222.18.218

   ## Change the DNS to avoid DNS Leak

   echo "nameserver $DNS1" > /etc/resolv.conf

   echo "nameserver $DNS2" >> /etc/resolv.conf

Then into /etc/openvpn/vpn.conf, I added at the end (don't forget to remove nobind, because I force the local port)

   lport 1194

   ipchange up_script.sh

   down down_script.sh

Look up_script.sh (I have improved it with logs and drop of all broadcast address, but I don't have the file right now). The firewall rules are there because I don't know the public IP before. The Gateway allowance is only for my personal needs, you can remove it

   #!/bin/bash

   # Firewall Rules

   IP=$(echo $1 | sed 's/\[AF_INET\]//g')

   GW=$(/sbin/ip route | awk '/default/ { print $3 }')

   IPT=iptables

   # Start

   logger "ovpn: Got public IP $IP"

   # tun interfaces (VPN)

   $IPT -A INPUT  -i tun+ -j ACCEPT -m comment --comment "Accept TUN Input"

   $IPT -A OUTPUT -o tun+ -j ACCEPT -m comment --comment "Accept TUN Output"

   # Allow traffic with my VPN server

   $IPT -A INPUT  -s $IP -j ACCEPT -m comment --comment "Accept PIA Input"

   $IPT -A OUTPUT -d $IP -j ACCEPT -m comment --comment "Accept PIA Output"

   # Allow my gateway on eth0

   $IPT -A OUTPUT -d $GW -o eth+ -j ACCEPT -m comment --comment "Accept My Gateway"

Then down_script.sh

   #!/bin/bash

   GW=$(/sbin/ip route | awk '/default/ { print $3 }')

   IPT=iptables

   # Push DNS again

   echo "nameserver 127.0.0.1" > /etc/resolv.conf

   # Restart my interface !

   ifdown -a

   ifup -a

So what do you think about that ?

G.

  • doing this drops output for all users. if i try to drop output only for the one user, it drops all ouput. – jakethedog Jul 21 '17 at 6:51
0

I got this working using the following configuration:

-P INPUT DROP
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N f2b-sshd
-A INPUT -p tcp -m multiport --dports 22 -j f2b-sshd
-A INPUT -i tun0 -m conntrack --ctstate ESTABLISHED -j ACCEPT
-A INPUT -m pkttype --pkt-type broadcast -m comment --comment "Block Broadcast INPUT (No log)" -j DROP
-A INPUT -m pkttype --pkt-type multicast -m comment --comment "Block Multicast INPUT (No Log)" -j DROP
-A INPUT -i lo -m comment --comment "Accept localhost Input" -j ACCEPT
-A INPUT -p udp -m udp --sport 1194 -m state --state ESTABLISHED -m comment --comment "Allow the server to reply (related to lport)" -j ACCEPT
-A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
-A INPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -s 8.8.8.8/32 -p udp -m udp --sport 53 -m state --state ESTABLISHED -m comment --comment "Allow the DNS1 to answer" -j ACCEPT
-A INPUT -s 8.8.4.4/32 -p udp -m udp --sport 53 -m state --state ESTABLISHED -m comment --comment "Allow the DNS2 to answer" -j ACCEPT
-A INPUT -m limit --limit 10/min -m comment --comment "Log Input" -j LOG --log-prefix "FW DROP INPUT: " --log-level 7
-A INPUT -i tun+ -m comment --comment "Accept TUN Input" -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -m limit --limit 10/min -m comment --comment "Log Forward" -j LOG --log-prefix "FW DROP FORWARD: " --log-level 7
-A OUTPUT -o lo -m owner --uid-owner 1001 -j ACCEPT
-A OUTPUT -o tun0 -m owner --uid-owner 1001 -j ACCEPT
-A OUTPUT ! -s $EXTERNALIP -o $EXT_INT -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -o lo -m owner --uid-owner 1002 -j ACCEPT
-A OUTPUT -o tun0 -m owner --uid-owner 1002 -j ACCEPT
-A OUTPUT ! -s $EXTERNALIP/32 -o $EXT_INT -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -o lo -m owner --uid-owner 1003 -j ACCEPT
-A OUTPUT -o tun0 -m owner --uid-owner 1003 -j ACCEPT
-A OUTPUT ! -s $EXTERNALIP/32 -o $EXT_INT -j REJECT --reject-with icmp-port-unreachable
-A OUTPUT -o lo -m comment --comment "Accept localhost Output" -j ACCEPT
-A OUTPUT -p udp -m udp --dport 1194 -m comment --comment "Allow my computer to query the DNS server" -j ACCEPT
-A OUTPUT -p tcp -m multiport --sports 22,80,443 -j ACCEPT
-A OUTPUT -p tcp -m state --state RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -o $EXT_INT -p tcp -m multiport --dports 80,443 -m state --state NEW -j ACCEPT
-A OUTPUT -o $EXT_INT -p tcp -m tcp --dport 22 -m state --state NEW -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A OUTPUT -d 8.8.8.8/32 -p udp -m udp --dport 53 -m state --state NEW,ESTABLISHED -m comment --comment "Allow my machine to connect to the DNS1" -j ACCEPT
-A OUTPUT -d 8.8.4.4/32 -p udp -m udp --dport 53 -m state --state NEW,ESTABLISHED -m comment --comment "Allow my machine to connect to the DNS2" -j ACCEPT
-A OUTPUT -m limit --limit 10/min -m comment --comment "Log Output" -j LOG --log-prefix "FW DROP OUTPUT: " --log-level 7
-A OUTPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -m comment --comment "Allow ping to Outside" -j ACCEPT
-A OUTPUT -o tun+ -m comment --comment "Accept TUN Output" -j ACCEPT
-A f2b-sshd -j RETURN

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.