4

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
7
  • CentOS I'm assuming ?
    – Lawrence
    Jul 16, 2014 at 5:37
  • could you also post your openvpn config from the server?
    – Thomas
    Jul 16, 2014 at 6:09
  • @Lawrence Close; Fedora 19.
    – Chris
    Jul 16, 2014 at 15:55
  • @Thomas I posted the server config above
    – Chris
    Jul 16, 2014 at 15:56
  • 1
    I have similar issue, did you find any solution? May 20, 2018 at 17:14

2 Answers 2

5

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):

# Automatically generated configuration
daemon ovpn-server1
server-bridge   # proxy the DHCP server
push "route 0.0.0.0 255.255.255.255 net_gateway"
proto udp
port 1194
dev tap21
ncp-ciphers AES-256-GCM
auth SHA384
comp-lzo adaptive
keepalive 15 60
verb 2
push "dhcp-option DNS 10.75.233.1"   # Pushes the DNS server
tls-crypt static.key
ca ca.crt
dh dh.pem
cert server.crt
key server.key
crl-verify crl.pem
status-version 2
status status 5

# Custom Configuration
mssfix 1420  # You might not need this, it depends on your local network conditions
tun-mtu 1500  # You might not need this, it depends on your local network conditions
tls-version-min 1.2
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384

All of which is not that interesting. This is the client config:

client
dev tap0
persist-tun
persist-key
proto udp
remote mydomain.com 1194
float
ncp-ciphers AES-256-GCM
auth sha384
comp-lzo adaptive
remote-cert-tls server
auth-nocache
tls-version-min 1.2
verb 2

ca /etc/openvpn/secrets/mydomain/ca.crt
cert /etc/openvpn/secrets/mydomain/client.crt
key /etc/openvpn/secrets/mydomain/client.key
tls-crypt /etc/openvpn/secrets/mydomain/ta.key

resolv-retry infinite
nobind

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):

# interfaces(5) file used by ifup(8) and ifdown(8)
auto lo
iface lo inet loopback

allow-hotplug tap0
iface tap0 inet dhcp

Restart your networking stack using:

sudo systemctl daemon-reload
sudo systemctl restart networking

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 quick nslookup 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 with sudo 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:

[Unit]
Description=OpenVPN tunnel for mydomain.com
After=syslog.target network-online.target
Wants=network-online.target
Documentation=man:openvpn(8)
Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO

[Service]
Type=notify
PrivateTmp=true
WorkingDirectory=/etc/openvpn/client
ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config mydomain.com.conf
ExecStopPost=/etc/openvpn/post-tap0-service-stop.sh  # Removes search domain and DNS server from systemd-resolved config
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE
LimitNPROC=10
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw
ProtectSystem=true
ProtectHome=true
KillMode=process

[Install]
WantedBy=multi-user.target

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 (using chmod +x /etc/openvpn/post-tap0-service-stop.sh):

#!/bin/bash

FILE_MESSING_WITH_SYSTEMD_RESOLVED=/run/systemd/resolved.conf.d/isc-dhcp-v4-tap0.conf

echo "Removing $FILE_MESSING_WITH_SYSTEMD_RESOLVED..."
rm -f $FILE_MESSING_WITH_SYSTEMD_RESOLVED 

echo "Restarting systemd-resolved service..."
systemctl restart systemd-resolved.service

Tadaa! You can now control OpenVPN using sudo systemctl start/stop/restart/status openvpn-my-tap-service-name (after a quick sudo 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:

Cmnd_Alias OPENVPN = /bin/systemctl start openvpn-my-tap-service-name, \
                     /bin/systemctl stop openvpn-my-tap-service-name, \
                     /bin/systemctl restart openvpn-my-tap-service-name

%my-username ALL= NOPASSWD: OPENVPN

Now you can execute the sudo systemctl commands for your service without a password.

Sure hope this helps!

0

I ran into this odd situation as well. Openvpn was working fine until I made the following three changes in a failed effort to disable openvpn dhcp server and use my own (bridge/tap mode). Perhaps in your case you may need to apply the opposite changes to your configuration (add server directive, remove tls-server and server x y).

  1. In the server configuration, I commented out the server X Y directive
  2. In the server configuration, I added tls-server and mode server and commented out an ip pool option, all in response to fatal error messages received while starting openvpn without server x y

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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