I have an OpenVPN client on Linux connecting to an OpenVPN server. The server assigns IPs via DHCP, thus I connect using the tap interface rather than the tun interface.
OpenVPN connects, authenticates, chats with the server, and grabs a cup of coffee, but neglects to bring up the tap0 interface. After it connects, I have to manually run ifup tap0
to bring up the interface and get an IP.
I tried adding an up script in the config file that ran
ip link set tap0 up
dhclient tap0
but it only brought up the device, it didn't get the IP.
sanitized client.conf:
# Openvpn config to connect to <DOMAIN>
tls-client
dev tap0
; dev tap ; this didn't work either
; run script after init (supposedly)
; script-security 2 ; to run up script
; up /etc/openvpn/tap0up.sh ; bring up tap0
; up-delay ; Didn't work with or without this;
proto udp
remote <DOMAIN> 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert monkey.crt
key monkey.key
ns-cert-type server
comp-lzo
verb 3
And ifcfg-tap0, because I refuse to believe in NetworkManager
DEVICE=tap0
BOOTPROTO=dhcp
ONBOOT=yes
PEERDNS=no
ZONE=trusted
Thanks in advance!
Edit: Fun fact: it adds the correct static routes to my routing table for the network it forgot to bring up.
Edit2: OpenVPN Server config, by request:
local <my.ext.ip>
port 1194
mode server
tls-server
proto udp
dev tap0
; dev tap
ca keys/ca.crt
cert keys/zombie.crt
key keys/zombie.key
dh keys/dh2048.pem
keepalive 10 120
comp-lzo
persist-key
persist-tun
status zombievpn-status.log
verb 3
Best Answer
Getting TAP devices to work well on Ubuntu 17.10 and upwards (and other OS's that use systemd-resolved and/or network-manager) is no picknick in my experience, but after a lot of experimenting I've arrived at a setup which works well.
Before I will describe my solution, here's my situation and requirements. I run OpenVPN server on a router (Asus RT-AC87U with Asus Merlin firmware) in a home network, which also runs a DHCP server. The DHCP server is configured to hand out IP's for the TAP interface, and also pushes a DNS search domain. This allows discovery of connected systems by hostname (so for example a system with hostname "desktop" is discoverable as "desktop" which expands to "desktop.mydomain.com" because of the search domain "mydomain.com"). I use a TAP-network so that I can use wake-on-lan straight over the tunnel (wake-on-lan magic packets must be broadcasted on the x.x.x.255 address to the MAC-address of the network adapter that should wake the system, something a TUN-device cannot do because it operates at the wrong networking layer to allow broadcasting level 2 packages). The server has to be able to push DNS options to the client. I do NOT want all internet traffic to be routed through the tunnel - this is not that kind of VPN (I run a separate TUN-server on another port for that use case, but that's out-of-scope for this answer). Finally, when I close the tunnel, I need everything to return to the original state (which does not happen automatically).
It turns out that it was all of the experimentation that was difficult. The solution is not very complicated to configure at all, in the end. I installed OpenVPN from Ubuntu repositories, the version is 2.4.4 at the time of writing.
The OpenVPN server uses the following configuration (the server runs DNSMasq at 10.75.233.1 (the gateway IP as well) which functions as the DHCP server):
All of which is not that interesting. This is the client config:
Which is not that interesting either, apart from one thing - there are no up/down scripts [blow mind gif here].
The reason for this is that I think it is most elegant to let existing operating system services handle as much as possible - to move with the grain of the OS and not against it, in other words. The default up/down scripts that are installed are for manipulating
/etc/resolv.conf
, which Ubuntu 18.04 does not use (directly) anymore. It uses systemd-resolved. Directly manipulating resolv.conf shall lead to many tears, young jedi. This has not, however, lead to the Ubuntu devs installing up/down scripts for systemd-resolved by default either. This is left up to you (sudo apt install openvpn-systemd-resolved
- the scripts will be located in/etc/openvpn
). They work fine for TUN-devices, but don't get the job done properly for TAP-devices either, in my experience.What does work very well, is explicitly adding the tap0 device to your network interfaces (
/etc/network/interfaces
):Restart your networking stack using:
BOOM! The OS will now query the DHCP server all by itself and bring up the adapter, just like a normal interface. When you connect to your server,
ifconfig tap0
should show you an adapter with an assigned IP-address. Also,systemd-resolve --status
should show you, on the very first lines of the output, that the DNS search domain and DNS server pushed by the OpenVPN server are set as global config, and a quicknslookup desktop
should now work (provided that host exists somewhere on the other side of the tunnel).This however, turns out to cause some issues when you bring the tunnel down. It goes down fine, and the tap0 device is no longer visible in ifconfig output. However,
systemd-resolve --status
will show you that your search domain and DNS server very much continue to be part of your existence. In my case, because the domain on which I run my VPN server is "mydomain.com" and the search domain is also "mydomain.com", this caused me to be unable to connect to the VPN server again once the tunnel is down, because its actual IP can no longer be resolved as long as systemd-resolved remains befuddled with the pesky search domain. Restarting the systemd-resolved service does not solve the problem, but a reboot does. Oh mortal agony!Thankfully, there's a solution for this as well. It turns out a sort-of-temporary configuration file is made at
/run/systemd/resolved.conf.d/isc-dhcp-v4-tap0.conf
which causes systemd-resolved to remain stubbornly attached to my VPN-server's DNS server. Removing the file and then restarting the service fixes the problem (sudo rm /run/systemd/resolved.conf.d/isc-dhcp-v4-tap0.conf && sudo systemctl restart systemd-resolved.service
).So, for a bare-bones setup, this will do. However, I like my luxury, and we can use a nice systemd service to provide it for us! Note that with Ubuntu's OpenVPN package, a "wildcard" systemd service is available for all OpenVPN-configs in
/etc/openvpn/client
. You can take a look at the unit file which should be located at/lib/systemd/system/openvpn-client@.service
. It can be controlled withsudo systemctl start openvpn-client@my-config-name-without-.conf
. It works totally fine for TUN-style tunnels, so leave it alone. We will duplicate it to work for TAP-devices.Create the file
/lib/systemd/system/openvpn-my-tap-service-name.service
and add:It is a simple adaption of the default service. For it to work, your client config must be located at
/etc/openvpn/client/mydomain.com.conf
. Only one thing is added - a little script to remove the "temporary" systemd-resolved config file.Create the file
/etc/openvpn/post-tap0-service-stop.sh
and set it executable (usingchmod +x /etc/openvpn/post-tap0-service-stop.sh
):Tadaa! You can now control OpenVPN using
sudo systemctl start/stop/restart/status openvpn-my-tap-service-name
(after a quicksudo systemctl daemon-reload
after you created the service file, of course).There's only one finishing touch left. It's a pain to control the service with a password all the time. We can fix this by adding the commands required to control the service to a sudoers-file.
Execute the following command
pkexec visudo -f /etc/sudoers.d/openvpn
and enter the following:Now you can execute the
sudo systemctl
commands for your service without a password.Sure hope this helps!