My ISP provides me only with an IPv4 address.
After setting up a connection to my university OpenVPN server, I get an IPv6 address. With an example IPv6 address www6.fit.vutbr.cz
I can:
- host www6.fit.vutbr.cz
- ping6 www6.fit.vutbr.cz
- traceroute6 www6.fit.vutbr.cz
- open http://[2001:67c:1220:809::93e5:916] in a web browser (safari/firefox)
BUT, I cannot:
- open www6.fit.vutbr.cz in a web browser
i.e. web browser does not resolve an ipv6 dns address.
If I add the following mapping to /etc/hosts
2001:67c:1220:809::93e5:916 www6.fit.vutbr.cz
the web browser finally works.
I think it has something to do with scutil –dns showing:
DNS configuration
resolver #1
search domain[0] : lan
nameserver[0] : 192.168.1.1
nameserver[1] : 8.8.8.8
nameserver[2] : 8.8.4.4
flags : Request A records
reach : 0x00020002 (Reachable,Directly Reachable Address)
I believe, I should see Request AAAA records.
Why does host and traceroute6 and ping6 resolve the DNS, but the web browsers don't? Any suggestions?
Thanks
Best Answer
This was a huge hassle to figure out, so I wrote up a little guide in hopes that others would find it helpful:
How to convince macOS to do IPv6 DNS lookups when your only IPv6 address is via a VPN or tunnel of some sort
The Problem
macOS's domain name resolver will only return IPv6 addresses (from AAAA records) when it thinks that you have a valid routable IPv6 address. For physical interfaces like Ethernet or Wi-Fi it's enough to set or be assigned an IPv6 address, but for tunnels (such as those using
utun
interfaces) there are some extra annoying steps that need to be taken to convince the system that yes, you indeed have an IPv6 address, and yes, you'd like to get IPv6 addresses back for DNS lookups.I use
wg-quick
to establish a WireGuard tunnel between my laptop and a Linode virtual server. WireGuard uses autun
user-space tunnel device to make the connection. Here's how that device gets configured:And here's a few relevant lines from my routing table:
10.20.4/24
is my local ethernet network.10.20.4.5
is my laptop's LAN IP address.10.20.4.4
is my gateway's LAN IP address.10.75.131.2
is the IPv4 address of my end of the WireGuard point-to-point tunnel.2600:3c03::de:d002
is the IPv6 address of my end of the WireGuard point-to-point tunnel.50.116.51.30
is the public address of my Linode server.This should be enough to have IPv6 connectivity, right? Well, name resolution works when
host
talks directly to my name server:Pinging by IPv6 address works:
And HTTP connections by IPv6 address work:
However, HTTP connections by IPv6-only hostname don't work:
The result is the same in
wget
as well as in GUI apps like Firefox: connecting by a literal IPv6 address works fine, but connecting by a hostname that only has an AAAA record (and no A record) associated with it does not.Interestingly,
ping6
is able to do a DNS lookup and get an IPv6 address back:Why can
ping6
do this when nothing else can? It turns out that whenping6
callsgetaddrinfo
it overwrites the default flags. One of the default flags isAI_ADDRCONFIG
, which tells the resolver to only return addresses in address families that the system has an IP address for. (That is, don't return IPv6 addresses unless the system has a (not link-local) IPv6 address.) Most other programs add to the default flags rather than clobbering them, which I suppose is sensible.If you run
scutil --dns
it will tell you how the resolver is set up. Here's the output on my system (minus a bunch of mdns stuff that doesn't matter):Note that under
flags
, it saysRequest A records
but notRequest AAAA records
. So it's left to us to try to convince macOS's resolver that we do in fact have a valid IPv6 address, even though it's on a tunnel interface.SystemConfiguration
The "right" way for this to happen is for whatever program sets up the tunnel to use the bizarre and largely undocumented
SystemConfiguration
API to register the network "service" and its IPv6 properties. The Viscosity app does this. Tunnelblick does not, the official OpenVPN Client does not, andwg-quick
sure as hell doesn't.The
scutil
KludgeWe can create the same SystemConfiguration "service" strucures manually using the
scutil
command:First we create the IPv4 part of the service:
And then we create the IPv6 part:
Once this is done, the output of
scutil --dns
(again modulo mdns stuff) changes:Now we see
Request AAAA records
in the flags! I'm not really sure what "scoped queries" are or why the DNS configuration for them didn't change, but things seem to work now so whatever:When disconnecting from the tunnel, all you have to do is remove the SystemConfiguration keys you added:
A couple things to note:
my_ipv6_tunnel_service
is totally arbitrary..ovpn
profile, you have to create both theSetup:
andState:
keys. I didn't verify this because I am lazy.DestAddresses
come from. I copied these from Viscosity because they seemed to work there.::ffff:ffff:ffff:ffff:0:0
for the link-local address and::
for the publicDestAddresses
means or what it's used for.A nice script
I wrote a python script that gleans addresses and prefix lengths from
ifconfig
output. It requires Python 3.6 or later so make sure you've got that in your path. It's calledwg-updown
and calls its SystemConfiguration servicewg-updown-utun#
, but it's not really WireGuard-specific. You could call it as a post-up/pre-down script for any old VPN tunnel or run it manually. Call it like this:replace
IFACE
with the name of the interface that your tunnel/VPN client is using, e.g.utun1
. It will print the commands that it's sending toscutil
so you can see what it's doing in detail.