Tunnelblick IPv6 DNS – get it working

Basically – If you are using OpenVPN with IPv6 support, MacOS will not recognize it and only allow IPv4 DNS resolution.

References:
https://openvpn.net/vpn-server-resources/limited-ipv6-support-built-into-the-access-server/
https://apple.stackexchange.com/questions/304215/how-to-add-aaaa-flag-ipv6-to-dns-resolver-configuration-on-sierra
https://www.tunnelblick.net/cUsingScripts.html
https://tunnelblick.net/cConfigT.html#creating-and-installing-a-tunnelblick-vpn-configuration

First, you have to configure IPv6 in your OpenVPN Server. For OpenVPN AS, there is a guide linked above.

Once IPv6 is working in the tunnel, you will probably recognize that some services are working, but in some applications (like Safari), IPv6 only sites won’t work. This is because they use the systems DNS resolver, which doesn’t allow AAAA requests, if it thinks that it has no IPv6 internet access.

You can check this using:

scutil --dns                                                     
DNS configuration

resolver #1
  search domain[0] : openvpn
  nameserver[0] : 8.8.8.8
  nameserver[1] : 8.8.4.4
  flags    : Request A records
  reach    : 0x00000002 (Reachable)

As you can see above, the resolver is only used for A records.

On Stackexchange, user smammy created a nice writeup for Wireguard, that utilizes a script to convince the MacOS resolver to resolve AAAA records using the given DNS servers. This can easily be adapted for Tunnelblick.

You need to create a Tunnelblick configuration package by creating a folder, adding the necessary files to it and adding the .tblk ending to it. MacOS will recognize it as a Tunnelblick package then and allow you to install the configuration including the necessary scripts.

The folder should contain 4 files:

  • profile.ovpn
  • up-suffix.sh
  • down-suffix.sh
  • wg-updown.sh

profile.ovpn
This is your OpenVPN profile, in my case the auto login profile exported from OpenvpnAS.

up-suffix.sh
This is executed when establishing the connection.

./wg-updown.sh up utun3

down-suffix.sh
This is executed when terminating the connection.

./wg-updown.sh down utun3

wg-updown.sh
This is the script from stack exchange

#!/usr/bin/env python3

import re
import subprocess
import sys

def service_name_for_interface(interface):
    return 'wg-updown-' + interface

v4pat = re.compile(r'^\s*inet\s+(\S+)\s+-->\s+(\S+)\s+netmask\s+\S+')
v6pat = re.compile(r'^\s*inet6\s+(\S+?)(?:%\S+)?\s+prefixlen\s+(\S+)')
def get_tunnel_info(interface):
    ipv4s = dict(Addresses=[], DestAddresses=[])
    ipv6s = dict(Addresses=[], DestAddresses=[], Flags=[], PrefixLength=[])
    ifconfig = subprocess.run(["ifconfig", interface], capture_output=True,
                              check=True, text=True)
    for line in ifconfig.stdout.splitlines():
        v6match = v6pat.match(line)
        if v6match:
            ipv6s['Addresses'].append(v6match[1])
            # This is cribbed from Viscosity and probably wrong.
            if v6match[1].startswith('fe80'):
                ipv6s['DestAddresses'].append('::ffff:ffff:ffff:ffff:0:0')
            else:
                ipv6s['DestAddresses'].append('::')
            ipv6s['Flags'].append('0')
            ipv6s['PrefixLength'].append(v6match[2])
            continue
        v4match = v4pat.match(line)
        if v4match:
            ipv4s['Addresses'].append(v4match[1])
            ipv4s['DestAddresses'].append(v4match[2])
            continue
    return (ipv4s, ipv6s)

def run_scutil(commands):
    print(commands)
    subprocess.run(['scutil'], input=commands, check=True, text=True)

def up(interface):
    service_name = service_name_for_interface(interface)
    (ipv4s, ipv6s) = get_tunnel_info(interface)
    run_scutil('\n'.join([
        f"d.init",
        f"d.add Addresses * {' '.join(ipv4s['Addresses'])}",
        f"d.add DestAddresses * {' '.join(ipv4s['DestAddresses'])}",
        f"d.add InterfaceName {interface}",
        f"set State:/Network/Service/{service_name}/IPv4",
        f"set Setup:/Network/Service/{service_name}/IPv4",
        f"d.init",
        f"d.add Addresses * {' '.join(ipv6s['Addresses'])}",
        f"d.add DestAddresses * {' '.join(ipv6s['DestAddresses'])}",
        f"d.add Flags * {' '.join(ipv6s['Flags'])}",
        f"d.add InterfaceName {interface}",
        f"d.add PrefixLength * {' '.join(ipv6s['PrefixLength'])}",
        f"set State:/Network/Service/{service_name}/IPv6",
        f"set Setup:/Network/Service/{service_name}/IPv6",
    ]))

def down(interface):
    service_name = service_name_for_interface(interface)
    run_scutil('\n'.join([
        f"remove State:/Network/Service/{service_name}/IPv4",
        f"remove Setup:/Network/Service/{service_name}/IPv4",
        f"remove State:/Network/Service/{service_name}/IPv6",
        f"remove Setup:/Network/Service/{service_name}/IPv6",
    ]))

def main():
    operation = sys.argv[1]
    interface = sys.argv[2]
    if operation == 'up':
        up(interface)
    elif operation == 'down':
        down(interface)
    else:
        raise NotImplementedError()

if __name__ == "__main__":
    main() 

When the folder/package is complete, it can be imported to Tunnelblick. You will get a lot of warnings.

After importing, the connection can be started. After it is established, the output of scutils should look something like this:

scutil --dns
DNS configuration

resolver #1
  search domain[0] : openvpn
  nameserver[0] : 8.8.8.8
  nameserver[1] : 8.8.4.4
  flags    : Request A records, Request AAAA records
  reach    : 0x00000002 (Reachable)

Success! AAAA DNS resolution should now work in all applications.

What I haven’t gotten to work yet, is that MacOS recognizes IPv6 DNS servers pushed trough the VPN config. I could only get it to resolve IPv6 addresses trough IPv4 DNS servers. If you have any success with this, please let me know.

Building a AUX and USB Adapter for Nissan Connect

I’ve decided to add a DSP to the AUX input of my cars radio.

I have a 2012 Nissan NV200 with a Bosch-made Nissan Connect radio. That radio has a combined 8-pin plug for USB and Aux.

On the internet you can find various adapters from 8pin to RCA+USB, however those all have the wrong gender. They’re made to connect a radio with generic Inputs to a Nissan wiring-harness. However, I needed a adapter to connect an Nissan/Bosch radio to a generic wiring-harness.

Continue reading Building a AUX and USB Adapter for Nissan Connect

Es gibt Dinge, die die Welt nicht braucht

Leider ist eine Freundin aus dem Karlsruher Chaos und drei ihrer Kommilitonen bei einem Busunglück in Peru ums Leben gekommen.

Dies ist eine Chronologische Sammlung von Medienberichten, Übersetzungen und weiteren Informationen, in der Hoffnung andere betroffene die Geschehnisse besser nachvollziehen können, sowie in einem Versuch, das selber zu verarbeiten.

Continue reading Es gibt Dinge, die die Welt nicht braucht

A word on empty ink cartridges

So, the other day I got a ‘working’ HP DesignJet 130nr and started trying to fix it. I guess the LM print head started to clot up during storage and transport.

On a side note – I found out there’s a reason HP call this series of printers ‘Ultra Low End‘. I can’t recommend getting one of these to anyone, even for free.

Anyway, since I was working with a syringe on the printer anyway (air in the ink-tubes.. again.. see above) I decided to find out how much ink was left in the LC cartridge that I had replaced last week. Continue reading A word on empty ink cartridges