This is for once not a security related post, but as I couldn’t find one important detail on the Internet, I thought I’ll share my story.
When connecting with the MacOS built-in VPN service to a server, MacOS (12, Monterey) will happily accept all the parameters coming from the VPN server: Force their DNS setting, force their IP address routes (in this case route all traffic through VPN), etc. and there is no GUI to change it.
As I didn’t want to route all traffic through the VPN and as I didn’t want DNS resolutions to go through the VPN (except for certain domains), I wanted to reconfigure MacOS to do as I like. The routing issue was straight forward by adding a couple of specific routes (10.0.0.0/8) and then telling MacOS to use my usual default gateway in my network (192.168.1.1):
/sbin/route -nv add -net 10.0.0.0/8 -interface ipsec0 /sbin/route change default 192.168.1.1
However, when it came to changing the DNS settings, there are many not very helpful links that suggest that you change the “Service Order” (you can’t, IKEv2 VPNs do not get a Service entry) via GUI (network settings) or command line (networksetup
). So that was not an option.
What sounded absolutely plausible is to change the SearchOrder (sometimes shown as just “order” in MacOS tools) of the VPN-DNS server to a higher value. This was attempted by Rakhesh but also didn’t work as he explains. He then explains that he overwrites the VPN’s DNS IP address with the one we want (d.add ServerAddresses * 192.168.1.1
), but that didn’t work for me either and that just lead to not being able to do DNS resolving at all (my guess would be MacOS then tries to reach 192.168.1.1 via the VPN interface, which doesn’t work). So for me all available approaches didn’t work.
However, I found out that I can change something called “PrimaryRank” from “first” to “second”, which then made the DNS server of the VPN disappear as a resolver in the “DNS configuration” section of scutil --dns
and everything worked as expected:
$ sudo scutil > get State:/Network/Service/E6[REDACTED]57C > d.show <dictionary> { PrimaryRank : First } > d.add PrimaryRank Second > set State:/Network/Service/E6[REDACTED]57C > exit
The only problem is that I need to change that value back to “first” before I connect again. So the entire script I run and then prompts me to connect the VPN:
#!/bin/bash # OPTIONS: default gateway and DNS server to use for normal Internet connection GW_TO_USE="192.168.1.1" DNS_TO_USE="$GW_TO_USE" # Run this script after connection in the Network settings of MacOS to the VPN # Check if running as root if [ $EUID -ne 0 ]; then echo "This script should be run as root." > /dev/stderr exit 1 fi echo "+ Fixing PrimaryRank to the original value" scutil << EOF get State:/Network/Service/E6[REDACTED]57C d.add PrimaryRank First set State:/Network/Service/E6[REDACTED]57C exit EOF read -p "Connect VPN now, then press Enter to continue" </dev/tty echo "+ Sleeping 3 seconds to make sure VPN is correctly connected..." sleep 3 ## # Routing part ## echo "+ Adding a manual route for VPN IP address range" /sbin/route -nv add -net 10.0.0.0/8 -interface ipsec0 echo "+ Removing VPN as the default gateway" /sbin/route change default "$GW_TO_USE" ## # DNS part ## echo "+ Last line of /etc/resolv.conf:" tail -1 /etc/resolv.conf echo "+ add DNS for *.example.org in /etc/resolver/example.org, it will be the last line from /etc/resolv.conf!" tail -1 /etc/resolv.conf > /etc/resolver/example.org echo "+ Last time we checked this was:" echo 'nameserver 10.15.7.8' echo "+ Fixing VPN DNS always being used" scutil << EOF get State:/Network/Service/E6[REDACTED]57C d.add PrimaryRank Second set State:/Network/Service/E6[REDACTED]57C exit EOF echo "+ sleeping for 2 seconds" sleep 2 echo "+ Your new /etc/resolv.conf:" tail -1 /etc/resolv.conf
Useful information, thank you. Is this still your solution?
It works for me but the service UUID seems to be generated randomly (on boot?) so the script would need modifying to make sure the correct UUID is being set. Is this also the case for you?
Unfortunately I think you are right. Yes, this is still my solution, although currently I don’t use it. Probably modifying the script to read out the service UUID would work, happy hacking!