1

I've seen some questions referring to static DNSs, openVPN server pushes etc, but none of them really apply or they require GUI tools and I am using a headless Ubuntu Core that I SSH into.

root@redacted:~# lsb_release -a
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.3 LTS
Release:        14.04
Codename:       trusty

When the machine is only connected through eth0 to the local network, everything works fine. I can ping IPs directly (8.8.8.8) and resolved Domain Names (google.com).

wget -q -O - ipecho.net/plain #Shows my ISPs provided Public IP

When the machine is connected through tun0 using the VPN network, I can ping IPs directly (8.8.8.8) and resolved Domain Names (google.com).

wget -q -O - ipecho.net/plain #Shows my VPNs provided Public IP

All as expected so far...

Now the problem comes in... I add the following iptables rules to force a specific user to only be able to use the tun0 adapter:

sudo iptables -A OUTPUT -m owner --gid-owner vpnonly -o lo -j ACCEPT
sudo iptables -A OUTPUT -m owner --gid-owner vpnonly -o eth0 -p tcp -d 192.168.x.x/24 --sport xxxx -j ACCEPT
sudo iptables -A OUTPUT -m owner --gid-owner vpnonly \! -o tun0 -j REJECT

In case you're curious, the second rule permits a web based UI to be accessible on my local network that is run as the user vpnonly.

So now when I run processes that I don't want to be able to communicate over my public IP, thus preventing leaks if the VPN goes down/disconnects/etc, I simply run them under vpnonly, whom's only group is vpnonly. HOWEVER when I run a process as vpnonly, I can ping IPs directly (8.8.8.8) but I cannot resolve Domain Names (google.com).

root@redacted:~# sudo -u vpnonly ping -c 2 google.com
ping: unknown host google.com

Even if I could get it to resolve domain names again period, that would be satisfactory, but what I would REALLY like to do is set JUST the VPN to use a separate, specific DNS, while leaving eth0 to use 8.8.8.8, 8.8.4.4.

I've googled everything I can think of related to this and cannot solve it... I hope I've added enough detail, but will happily add more upon request

EDIT 1: Full iptables

root@redacted:~# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             owner GID match vpnonly
ACCEPT     tcp  --  anywhere             192.168.x.x/24       owner GID match vpnonly tcp spt:xxxx
REJECT     all  --  anywhere             anywhere             owner GID match vpnonly reject-with icmp-port-unreachable

-

root@redacted:~# iptables -L -v
Chain INPUT (policy ACCEPT 16407 packets, 12M bytes)
 pkts bytes target     prot opt in     out     source               destination   

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination   

Chain OUTPUT (policy ACCEPT 6230 packets, 675K bytes)
 pkts bytes target     prot opt in     out     source               destination   
 3751 2800K ACCEPT     all  --  any    lo      anywhere             anywhere             owner GID match vpnonly
 6635 3332K ACCEPT     tcp  --  any    eth0    anywhere             192.168.x.x/24       owner GID match vpnonly tcp spt:xxxx
    4   224 REJECT     all  --  any    !tun0   anywhere             anywhere             owner GID match vpnonly reject-with icmp-port-unreachable

Edit 2:

Everything functions properly until the iptables rules are added, at which point the only problem I suffer is domain name resolution. My vpn also provides non-logging DNS. Would the solution to this be to change my /etc/network/interfaces nameserver entry from 192.168.x.1 to the DNS IP address provided by my VPN and then allow all connections to that DNS IP prior to the reject? I wanted to ask before trying it, one to make sure it was as safe as I believe it to be logically, and two I'm offering a bounty anyways. I want to make sure there are no leaks, and don't want to introduce one via DNS...

After further enlightenment, rather than modifying interfaces, should I simply allow 192.168.x.1 and the VPN DNS IP explicitly prior to the reject?

What I would REALLY like to do is force those DNS queries through the tun0 adapter, make ANY communication with the outside world from user "vpnonly" go through the VPN, if at all possible.

  • 1
    It doesn't look like there's an 'accept' condition for the vpnonly user. Just "if not using the tunnel, reject." I'm assuming this is followed in the chain by a blanket reject? – Rick Chatham Nov 4 '15 at 0:02
  • I updated the question with the complete IP tables @RickChatham – DeeJayh Nov 4 '15 at 0:19
  • Based on the output you pasted above it doesn't look like much/any traffic is making it to the final rule. Why not try this: Make the 3rd rule one accepting all traffic from anywhere to anywhere through the tunnel adapter, then put in a 4th rule that rejects all traffic? That would help us see if the !tun0 logic is tripping up the system somehow. – Rick Chatham Nov 11 '15 at 23:47
0

First question, is can you access your DNS server? If you're blocking access to all except the tun0, you may well be blocking DNS access.

If you're running some kind of DNS server locally be that full on Bind, or something like dnsmasq, that service, will also need to be able to access the internet.

I would suggest adding a log entry to your iptables, before reject, to see what traffic is being rejected.

Using port 53 is a standard way to defeat security, so opening *:53 is probably unwise, so you'll be best of specifically nominating your DNS server (local and upstream) as acceptable targets for traffic. I assume by --sport xxxx you meant you're using a non-standard port instead of :80 for your web service. If not you should specify that on your 192.168 rule (ditto for the IP, it should be a full on /32 address).

Also don't forget, if you want to use ping to test, you'll need to setup iptable entries for ICMP. ICMP 8 (echo) is a ping, ICMP 0 is a ping reply.

It's also worth considering what routes you have, as you'll need to ensure the default route for traffic is tun0. If tun0 is the only permissible interface, you need to ensure all the routes you need send traffic that way.

If that doesn't diagnose your problems, use ethtool to do some network sniffing, to see what conversations are making it and what are not. It could be something wierd, like the REQ is allowed but the ACK is not getting back.

  • Everything functions properly until the iptables rules are added, at which point the only problem I suffer is domain name resolution. My vpn also provides non-logging DNS. Would the solution to this be to change my /etc/network/interfaces nameserver entry from 192.168.x.1 to the DNS IP address provided by my VPN and then allow all connections to that DNS IP prior to the reject? I wanted to ask before trying it, one to make sure it was as safe as I believe it to be logically, and two I'm offering a bounty anyways. I want to make sure there are no leaks, and don't want to introduce one via DNS – DeeJayh Nov 6 '15 at 18:45
  • I re-read your answer. rather than modifying interfaces I should simply allow 192.168.x.1 and the VPN DNS IP explicitly prior to the reject, rather than my previous comment? Thanks so much in advance! – DeeJayh Nov 6 '15 at 18:55
  • Sorry for all the comments, won't let you edit after a certain amount of time? What I would REALLY like to do is force those DNS queries through the tun0 adapter, make ANY communication with the outside world from user "vpnonly" go through the VPN, if at all possible. – DeeJayh Nov 6 '15 at 20:08
  • First thing, is don't go changing interfaces or any other config, until you're sure it'll work. /etc/resolv.conf is the location of the dns resolver. It needs to be somewhere, that you can communicate with, accepting your firewall rules. Having remote DNS servers, is only sensible, if you also have local satelite caching DNS servers, which send all their queries to a master server. Like I said, I'd suggest installing a local bind, on 127.0.0.1. Get that working, then if it works, yes change interfaces. But get it working first (remember you will still need fw access to <master DNS>:53) – sibaz Nov 9 '15 at 14:02
0

An easy way is to create a service .conf that will persist any iptables rules you like.

You can install a package to do this, but the manual way is as such:

sudo vi /etc/init/persist-iptables.conf

You can name it whatever you like, just make sure it's in /etc/init/ and ends with .conf

Then you want to insert the following lines:

description "Persist IPTables on Boot"

start on runlevel [2345]

script
        # Accept all loopback traffic localhost or 127.0.0.1
        iptables -A INPUT -i lo -j ACCEPT
        iptables -A OUTPUT -o lo -j ACCEPT

        # Accept any DNS traffic, I use a DD-WRT router with
        # Force DNS Redirection to a non-logging DNS
        iptables -A OUTPUT -d 255.255.255.255 -j ACCEPT
        iptables -A INPUT -s 255.255.255.255 -j ACCEPT

        # Accept all local traffic from 192.168.1.1-192.168.1.255
        iptables -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT
        iptables -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j ACCEPT

        # Forward all eth0, eth1, etc through tun interfaces
        iptables -A FORWARD -i eth+ -o tun+ -j ACCEPT
        iptables -A FORWARD -i tun+ -o eth+ -j ACCEPT

        # Postroute masquerade through tun interfaces
        iptables -t nat -A POSTROUTING -o tun+ -j MASQUERADE

        # Drop any other traffic through eth adapters
        iptables -A OUTPUT -o eth+ ! -d a.b.c.d -j DROP
end script

Now when your system reboots (which clears your IP tables) this will run automatically to update the iptables again. You can also call it yourself with sudo service persist-iptables start

This file will allow all localhost traffic, allow all DNS traffic (it's up to you to make sure it's the RIGHT dns coming from your router), allow all local traffic, forward traffic from eth adapters to tun adapter and postroute masq it, and finally drop any other traffic.

  • The iptables-persistent package will load/save iptable rules on reboot. Best to have a script in ~ to setup the iptables rules, then use standard system tools (like iptables-persistent) to save them. – sibaz Nov 11 '15 at 15:47
  • Fully aware of iptables-persistent, however this is on a minimal-footprint server (I actually built it from Ubuntu Core), and adding iptables-persistent is more costly that creating a .conf for the already available init. – DeeJayh Nov 15 '15 at 6:22

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.