MacOS – Force DNS resolution to happen outside VPN

dnsmacosNetworkvpn

I'm running Mojave (10.14) and I have a Cisco AnyConnect VPN over which traffic for selected routes (determined by the VPN profile, out of my control) is sent.

Traffic routing works fine, the issue is that DNS resolution is taking place over the VPN for hostnames that are not on the internal network.

The output of scutil --dns contains:

craig@TBMBP:~$ scutil --dns
DNS configuration

resolver #1
  search domain[0] : a.mycompany.com
  search domain[1] : b.mycompany.com
  search domain[2] : c.mycompany.com
  search domain[3] : d.mycompany.com
  search domain[4] : hsd1.ma.comcast.net <-- (my ISP)
  nameserver[0] : 10.70.yy.yy

Further, it contains:

DNS configuration (for scoped queries)

resolver #1
  search domain[0] : hsd1.ma.comcast.net
  nameserver[0] : 2601:184:497f:...     <-- (some ipv6 address)
  nameserver[1] : 192.168.1.1
  if_index : 10 (en0)
  flags    : Scoped, Request A records, Request AAAA records
  reach    : 0x00000002 (Reachable)

That means when I open www.apple.com, I see over the VPN:

39  2.316879    10.70.xx.xx 10.70.yy.yy DNS 63  Standard query 0xefee A www.apple.com

And I don't want this to happen. Rather, I want DNS resolution to happen between me and my ISP (or between me and 1.1.1.1 or 8.8.8.8) and then if resolution fails, to consult with the VPN.

How do I update the resolver to use Cloudflare/Google first for DNS, using the command line on Mac?

Best Answer

I have a similar situation where I have to use a very heavy-handed captive portal Wi-Fi connection with a very heavy-handed, very creepy virtual firewall. Not only does snoop on secure connections, it impersonates DNS server IPs, using DPI (when it detects the request).

The only thing that works for me is to go over the top of the VPN/firewall rather than try to sneak under it, using dnscrypt-proxy using only DNS-over-HTTPS, as it can detect the dnscrypt protocol. Right now, its not aware of DNS-over-HTTPS at all.

I implement it using a LaunchAgent that watches /etc/resolve.conf for changes, and when it detects a change, it restarts dnscrypt-proxy, then runs networksetup -setdnsservers Wi-Fi 127.0.0.1.

Aside: I've been using Quad9 for a while now, and much prefer it to Google and CloudFlare.

Edit: After playing a bit more with this, I'm noticing that (somehow, I haven't even figured out where the traffic is to/from), IPv6 addresses are somehow resolved with ::1 as a DNS server, even if there are no other DNS servers set. So probably better to just disable IPv6 if you can.


Edit 2:

Yeah, I think being able to split out that route might be just too much to do with the newer system-level VPN implementation; I think DNS proxying is probably your best bet. It might be possible to remove ipsec0 as the default route and then add it back for a restricted IP range... but every time I try this (with IKEv2, not AnyConnect, but I'm assuming they're using the same API) it just... stops.

As for the residual traffic, maybe its Rendezvous? sudo killall -HUP mDNSResponder; sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist?

Also, perhaps you might be able to use an app like Shimo? It's available with Setapp! I don't know exactly how AnyConnect works, but it says it supports it, and it has configuration options available that are exactly what you are looking for for other protocols, including IKE, so... maybe?

Shimo