Skip to content

Instantly share code, notes, and snippets.

@tavinus
Last active December 7, 2022 12:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tavinus/da970afd77d2a9884a2deadc8d131811 to your computer and use it in GitHub Desktop.
Save tavinus/da970afd77d2a9884a2deadc8d131811 to your computer and use it in GitHub Desktop.
Make Linux NetworkManager apply DNS from VPN

The Problem

Injecting a DNS server from a VPN can be troublesome in Linux.

If you are not using Network Manager, you can fix this issue by adding the resolvconf script to your VPN config.

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

This will make it work if calling the config file directly

openvpn myconfig.ovpn

You can use this to test your config and also to check the DNS server IP if you don't know it

It will be shown in the VPN connection log as something like

2022-12-06 20:00:02 /etc/openvpn/update-resolv-conf tun0 1500 1624 10.8.0.240 255.255.255.0 init dhcp-option DNS 10.0.10.245

In this case it is 10.0.10.245
(and this is correct, since the server pushes a static route to the 10.0.10.x network)


Another option if you are not using Network Manager is to put the config file into the /etc/openvpn/client folder and use the systemd openvpn service.


Troubleshooting

You may need to symlink the /etc/resolv.conf for this to work. Can be done with

sudo dpkg-reconfigure resolvconf

or

sudo mv /etc/resolv.conf /etc/resolvconf-backup
sudo ln -s /etc/resolv.conf  /run/resolvconf/resolv.conf

This will change how systemd-resolve operates though (more info here).


NetworkManager Issue

There is a long standing problem where the Linux (Ubuntu?) Network Manager app will not import and impose DNS configurations from an OpenVPN config file.

The fixes above will not make an imported OpenVPN config work in Network Manager. It will connect but not run the up/down scripts.

I use several VPNs and each of them inject their own DNS for internal domain names. They work only for the LAN part, not for the Internet, but uses the VPN DNS for everything (local and internet). I can't let they all run at the same time because of conflicts (systemd service mode).

In other words, being able to toggle ON / OFF on them as needed is the best option for me. My only other option would be to have bash scripts to connect and disconnect them.

As of December / 2022 POP!_OS 22.04 (and Ubuntu) will not import the DNS settings or apply the needed config.

Ubuntu Launchpad has a very long discussion on this problem and comment #92 provides the answer we need.

This will not import the DNS config from the OpenVPN Server, but will allow you to add your DNS server to the client config.

Tweak NetworkManager config

After importing your openvpn config file into network manager (and with it working, but only just not pulling the DNS config), disconnect from it if connected.

Edit the NetworkManager config file

sudo nano /etc/NetworkManager/system-connections/<vpn name>.nmconnection

where <vpn-name> is the name of the connection (tip: use tab to auto-complete)

Then edit the [ipv4] block to be something like this

[ipv4]
dns=<vpn dns server ip address>;
ignore-auto-dns=true
method=auto
dns-priority=-1

The negative dns-priority means only this dns server will be used (avoid dns leak)

Then reload the config file with

sudo nmcli c reload <vpn name>

Toggle it ON and it should be working with the VPN DNS

Forcing local internet

Most of my VPNs are not for internet and should not route the internet of clients through them.

The easiest way of doing this is by adding the following line to your server config

push "route 0.0.0.0 0.0.0.0 vpn_gateway 999"

This works great and lets you push that config to all clients. Except for clients using NetworkManager, because the vpn_gateway keywork is not supported by NM. This is an old issue and it seems like no one is working on it.

The workaround I found was to enable custom routes and then add the route above by using the actual VPN Gateway IP instead of the keyword vpn_gateway. Most times your vpn_gateway is your VPN Server IP.

The main down side of this method is that you will also have to manually configure any other routes your VPN server was pushing into your connection. Normal routes (without keywords) are pushed fine, but when you turn off automatic routes you lose them. With automatic routes ON the custom config did not work.

You can check your routes by manually connecting to your original .ovpn file and looking at the log for something like

2022-12-06 22:03:02 PUSH: Received control message: 'PUSH_REPLY,dhcp-option DNS 192.168.190.250,route 0.0.0.0 0.0.0.0 vpn_gateway 999,route 192.168.190.0 255.255.255.0,route-gateway 10.8.190.1,topology subnet,ping 10,ping-restart 120,ifconfig 10.8.190.240 255.255.255.0,peer-id 0,cipher AES-128-GCM'

In this case I only had the route route 192.168.190.0 255.255.255.0
And the vpn_gateway IP is 192.168.190.1 (for all routes)
The metric I used was 0 (see below)

Also, if you have a working connection with the proper routes established, you can list them with

route -n

This is also useful to check the Metrics of the routes

So this is How it looked like in the end

image

Now I am wondering if editing my server config and changing vpn_gateway to the actual IP would also be enough to fix this. I will test later and edit here. It should be something like

push "route 0.0.0.0 0.0.0.0 10.8.190.1 999"

Can't think of any reason for it not working, but there are many cases where we just cannot change the server config anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment