LXC Openvpn TUN/TAP issue

Hi guys, I’ve been trying to get openvpn client set up in an LXC container. Initially, I ran into a problem, error: cannot open TUN/TAP device. I’ve got an ubuntu container, and I figured I’d post this in case someone has the same issue. To get around it, you have to:

  1. edit /srv/lxc/[containername]/config as follows:

systemd within the lxc

lxc.autodev = 1
lxc.hook.autodev = /srv/lxc/[containername]/autodev
lxc.pts = 1024
lxc.kmsg = 0

for openvpn

lxc.cgroup.devices.allow = c 10:200 rwm

Then you need to create, in that same directory (/srv/lxc/[containername]/) a script called ‘autodev’ (which was referred to in the above changes):

#!/bin/bash

cd ${LXC_ROOTFS_MOUNT}/dev
mkdir net
mknod net/tun c 10 200
chmod 0666 net/tun

Finally, you need to make that script executable by chmod +x autodev.

By the way, I’ve noticed that the posting window makes a line like #!/bin/bash appear bold, and eliminates the “#”–you’re going to need to put it back in on all of these bolded lines. Sorry.

Don’t forget to reboot your container for this to take effect.

Anyway, that’s what I’ve got so far–it’s running. Now I need to actually test to make sure it’s working and not dns leaking. I’ll update this thread as I progress, but others are welcome to join in. I’m pretty sure that I’m not the only one who’d like to be able to run openvpn in a container, but I couldn’t find any other topics on point.

To do: configure to autostart and run in background (as daemon, or something)

Cheers!

Chris

Update

To autostart openvpn (at least on Ubuntu 16, which uses systemd), do the following:

First of all, copy the .ovpn that you’re going to use over to /etc/openvpn/[whatever-name-you-want].conf (note the change in extension–you’re copying but renaming the file to whatever.conf).

For example, rename it /etc/openvpn/turris.conf

Secondly, edit /etc/default/openvpn and either add or change an AUTOSTART line to read AUTOSTART=“turris” (if you use the example above)

Third, you’re going to want to edit turris.conf to change the line that reads auth-users-pass to auth-users-pass .secrets (or .banana if you want, just pick a file name, and it doesn’t have to be hidden with the “.”, but hey, we’re holding secret passwords here.)

In that same directory, create your file .secrets (or .banana :yum:) and on the first line have your login, and on the second line your password. Save and exit. Probably want to chmod 600 .secrets.

You can then reboot your container, or if you don’t want to for some reason, make systemd reload settings by entering systemctl daemon-reload, then service openvpn restart.

If you run into trouble, call the script by entering openvpn --config /etc/openvpn/turris.conf directly, and it should give you some indication what’s going wrong.

Fix DNS leak: append the following lines to the end of turris.conf (or whatever you called it), and the VPN’s DNS servers should be used, instead of yours:

script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

IPtables to ensure that if VPN is down, network doesn’t revert to local network for internet:

Create a script in /root directory, call it firewall-setup.sh, as follows:

#!/bin/bash

Clear any existing iptables rules

iptables -F

Allow anything in and out the vpn interface

iptables -A INPUT -i tun0 -j ACCEPT
iptables -A OUTPUT -o tun0 -j ACCEPT

Allow in and out traffic from the VPN endpoint.

Replace aaa.bbb.ccc.ddd with the IP endpoint of the VPN

this can be taken from the ovpn file.

iptables -A INPUT -s aaa.bbb.ccc.ddd -j ACCEPT
iptables -A OUTPUT -d aaa.bbb.ccc.ddd -j ACCEPT

Allow in and out traffic to localhost

iptables -A INPUT -s 127.0.0.1 -j ACCEPT
iptables -A OUTPUT -d 127.0.0.1 -j ACCEPT

Allow DHCP traffic

iptables -A OUTPUT -p UDP --dport 67:68 -j ACCEPT

Allow in and out traffic to a tcp port from the host’s LAN subnetwork

iptables -A INPUT -s 10.0.0.0/24 -p tcp --dport XX -j ACCEPT

iptables -A OUTPUT -d 10.0.0.0/24 -p tcp --sport XX -j ACCEPT

Reject anything else

iptables -A INPUT -j DROP
iptables -A OUTPUT -j DROP

Reject any IPv6 traffic

ip6tables -A OUTPUT -j DROP
ip6tables -A INPUT -j DROP
ip6tables -A FORWARD -j DROP

Remember, see my note about the bolded lines, above.

Anyway, once that script is created, add the following line at the end of your /etc/network/interfaces file (in the container, not the host):

post-up /root/firewall-setup.sh.

This post updated to reflect DNS leaking tips (seen above, involves adding lines to “turris.conf”, as in our example.)

Out of curiousity why did you try to run this in lxc rather than directly on openwrt?

I did something similar with softether vpn bridge. I need the vpn (and the container) to start only when failover wan starts and i do not want to mess up with the host openwrt with softether for the moment.
In my case, xc.cgroup.devices.allow = c 10:200 rwm is not needed. Maybe it is not needed in your case also.
This is because we are already using a vitrual interface. So the local bridge is performed through the eth0 in the container.
In my case also the folder net already exists
I am also exploring the firewall and dns settings now

PS: i have already these settings in the container config
lxc.network.ipv4 = 10.0.10.2/24
lxc.network.ipv4.gateway = 10.0.10.1

Sorry, I stupidly replied in my email, it probably didn’t go through: I wanted them in a container to isolate the VPN for a particular program, but not constrain all of my traffic through the VPN.

Thanks! Your tutorial/help helped me a great deal to set up tinc inside of lxc container. tinc also uses tap/tun.

Glad my stumbling around has helped somebody! I’m like a bull in a china shop. If you learn some useful things like I did, please take some time to update the forums. We’re all in this together!

cannot figure out however how to make turris autostart my container:

this does not seem to have any effect:

lxc.start.auto = 1
lxc.start.delay = 5
lxc.start.order = 100

Ironically, I’ve done that… and promptly forgot how I did it. I’m searching through my web history, trying to figure that out myself, lol.

I think I may have found it:

lxc-auto needs to be enabled as a service to start via luci GUI or manually

Yes, that was it, thanks. It was driving me nuts! Edit /etc/config/lxc-auto, as follows:

config container
option name [name of container]
option timeout 60

And you should be all set.

–Chris

thanks, it wasn’t enough I needed to add your config options, now it works like a charm. As simple as it sounds it may be worth to write a “small” how to on this. Perhaps I will do this tomorrow in this forum for other poor souls wondering how to do this.

Ok, I guess I progressed to another level of this, I would like to make the need tap/tun interface to be visible in the parent (turris omnia root) so that I can access this. Any idea how to make this work? I went through many options in docs.

Are you asking how to make the container itself visible on your LAN?

no, container creates a new network interface (tun/tap), I would like to access this network interface on the router itself. I am using TINC actually inside of container.

I’m still not sure what you’re trying to do, but I’m certainly no expert. I don’t really know to much about tun/tap, but from what I understand, that’s basically a software ethernet device–so it sounds like you’re trying to do the equivalent of accessing another machine’s network device–which may be possible, but is certainly beyond me.

If you’re talking about being able to communicate with the container while over the LAN, while it’s connected through the tun/tap to a VPN, that should still be possible with the above setup. I have no problem accessing my container from my LAN, even though it’s fortified behind the DNS and iptables.