14 votes

Résolution dns IPv6 sur MacOS High Sierra

Mon FAI ne me fournit qu'une adresse IPv4.

Après avoir établi une connexion avec le serveur OpenVPN de mon université, j'obtiens une adresse IPv6. Avec un exemple d'adresse IPv6 www6.fit.vutbr.cz

Je peux :

MAIS, je ne peux pas :

  • ouvrir www6.fit.vutbr.cz dans un navigateur web

i.e. le navigateur web ne résout pas une adresse dns ipv6.

Si j'ajoute le mappage suivant à /etc/hosts

2001:67c:1220:809::93e5:916 www6.fit.vutbr.cz

le navigateur web fonctionne enfin.

Je pense que ça a quelque chose à voir avec l'affichage de scutil --dns :

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)

Je crois que je devrais voir les enregistrements de Request AAAA. Pourquoi host, traceroute6 et ping6 résolvent-ils le DNS, mais pas les navigateurs web ? Avez-vous des suggestions ? Merci

16voto

AdnanG Points 111

C'était un énorme J'ai donc rédigé un petit guide dans l'espoir que d'autres personnes le trouvent utile :

Comment convaincre MacOS d'effectuer des recherches DNS IPv6 lorsque votre seule adresse IPv6 est obtenue via un VPN ou un tunnel quelconque ?

Le problème

Le résolveur de nom de domaine de MacOS ne renvoie les adresses IPv6 (à partir des enregistrements AAAA) que lorsqu'il pense que vous avez une adresse IPv6 routable valide. Pour les interfaces physiques telles que l'Ethernet ou le Wi-Fi, il suffit de définir ou de se voir attribuer une adresse IPv6, mais pour les tunnels (tels que ceux utilisant le protocole utun interfaces) il y a des étapes supplémentaires ennuyeuses qui doivent être prises pour convaincre le système que oui, vous avez effectivement une adresse IPv6, et oui, vous aimeriez récupérer les adresses IPv6 pour les recherches DNS.

J'utilise wg-quick pour établir un tunnel WireGuard entre mon ordinateur portable et un serveur virtuel Linode. WireGuard utilise un utun périphérique de tunnel en espace utilisateur pour établir la connexion. Voici comment ce périphérique est configuré :

utun1: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1420
    inet 10.75.131.2 --> 10.75.131.2 netmask 0xffffff00
    inet6 fe80::a65e:60ff:fee1:b1bf%utun1 prefixlen 64 scopeid 0xc
    inet6 2600:3c03::de:d002 prefixlen 116
    nd6 options=201<PERFORMNUD,DAD>

Et voici quelques lignes pertinentes de ma table de routage :

Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
0/1                utun1              USc             0        0   utun1
default            10.20.4.4          UGSc            0        0     en3
10.20.4/24         link#14            UCS             3        0     en3      !
10.75.131.2        10.75.131.2        UH              0        0   utun1
50.116.51.30       10.20.4.4          UGHS            7  2629464     en3
128.0/1            utun1              USc             5        0   utun1

Internet6:
Destination                             Gateway                         Flags         Netif Expire
::/1                                    utun1                           USc           utun1
2600:3c03::de:d000/116                  fe80::a65e:60ff:fee1:b1bf%utun1 Uc            utun1
8000::/1                                utun1                           USc           utun1
  • 10.20.4/24 est mon réseau local ethernet.
  • 10.20.4.5 est l'adresse IP du réseau local de mon ordinateur portable.
  • 10.20.4.4 est l'adresse IP du réseau local de ma passerelle.
  • 10.75.131.2 est l'adresse IPv4 de mon extrémité du tunnel point à point WireGuard.
  • 2600:3c03::de:d002 est l'adresse IPv6 de mon extrémité du tunnel point à point WireGuard.
  • 50.116.51.30 est l'adresse publique de mon serveur Linode.

Cela devrait être suffisant pour avoir une connectivité IPv6, non ? Eh bien, la résolution de nom fonctionne lorsque host communique directement avec mon serveur de noms :

sam@shiny ~> host ipv6.whatismyv6.com
ipv6.whatismyv6.com has IPv6 address 2607:f0d0:3802:84::128

Le ping par adresse IPv6 fonctionne :

sam@shiny ~> ping6 -c1 2607:f0d0:3802:84::128
PING6(56=40+8+8 bytes) 2600:3c03::de:d002 --> 2607:f0d0:3802:84::128
16 bytes from 2607:f0d0:3802:84::128, icmp_seq=0 hlim=55 time=80.991 ms

--- 2607:f0d0:3802:84::128 ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 80.991/80.991/80.991/0.000 ms

Et les connexions HTTP par adresse IPv6 fonctionnent :

sam@shiny ~> curl -s 'http://[2607:f0d0:3802:84::128]' -H 'Host: ipv6.whatismyv6.com' | html2text | head -3
                 This page shows your IPv6 and/or IPv4 address
                          You are connecting with an IPv6 Address of:
                                             2600:3c03::de:d002

Cependant, les connexions HTTP par nom d'hôte IPv6 uniquement ne fonctionnent pas :

sam@shiny ~> curl 'http://ipv6.whatismyv6.com'
curl: (6) Could not resolve host: ipv6.whatismyv6.com

Le résultat est le même en wget ainsi que dans les applications graphiques comme Firefox : la connexion par une adresse IPv6 littérale fonctionne bien, mais la connexion par un nom d'hôte auquel n'est associé qu'un enregistrement AAAA (et aucun enregistrement A) ne fonctionne pas.

C'est intéressant, ping6 est capable de faire une recherche DNS et d'obtenir une adresse IPv6 en retour :

sam@shiny ~ [6]> ping6 -c1 ipv6.whatismyv6.com
PING6(56=40+8+8 bytes) 2600:3c03::de:d002 --> 2607:f0d0:3802:84::128
16 bytes from 2607:f0d0:3802:84::128, icmp_seq=0 hlim=55 time=49.513 ms

--- ipv6.whatismyv6.com ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 49.513/49.513/49.513/0.000 ms

Pourquoi ping6 faire ça quand rien d'autre ne le peut ? Il s'avère que lorsque ping6 appelle getaddrinfo il écrase les drapeaux par défaut. L'un des drapeaux par défaut est AI_ADDRCONFIG qui indique au résolveur de ne renvoyer que les adresses des familles d'adresses pour lesquelles le système possède une adresse IP. (C'est-à-dire ne pas renvoyer les adresses IPv6 à moins que le système ne possède une adresse IPv6 (non locale au lien)). La plupart des autres programmes ajouter aux drapeaux par défaut plutôt que de les écraser, ce qui, je suppose, est raisonnable.

Si vous exécutez scutil --dns il vous indiquera comment le résolveur est configuré. Voici la sortie sur mon système (sans un tas de trucs mdns qui n'ont pas d'importance) :

DNS configuration

resolver #1
  search domain[0] : home.munkynet.org
  nameserver[0] : 10.20.4.4
  if_index : 14 (en3)
  flags    : Request A records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

DNS configuration (for scoped queries)

resolver #1
  search domain[0] : home.munkynet.org
  nameserver[0] : 10.20.4.4
  if_index : 14 (en3)
  flags    : Scoped, Request A records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

Notez que sous flags il est dit Request A records mais pas Request AAAA records . Il nous reste donc à essayer de convaincre le résolveur de MacOS que nous avons bien une adresse IPv6 valide, même si elle se trouve sur une interface tunnel.

Configuration du système

La "bonne" façon pour que cela se produise est que le programme qui met en place le tunnel utilise la méthode bizarre et largement non documentée suivante SystemConfiguration API pour enregistrer le "service" réseau et ses propriétés IPv6. L'application Viscosity le fait. Tunnelblick ne le fait pas, le Client OpenVPN officiel ne le fait pas, et le Client OpenVPN officiel ne le fait pas. wg-quick c'est sûr que non.

Le site scutil Kludge

Nous pouvons créer manuellement les mêmes structures de "service" SystemConfiguration à l'aide de la commande scutil commandement :

Tout d'abord, nous créons la partie IPv4 du service :

sam@shiny ~> sudo scutil
> d.init
> d.add Addresses * 10.75.131.2
> d.add DestAddresses * 10.75.131.2
> d.add InterfaceName utun1
> set State:/Network/Service/my_ipv6_tunnel_service/IPv4
> set Setup:/Network/Service/my_ipv6_tunnel_service/IPv4

Et ensuite on crée la partie IPv6 :

> d.init
> d.add Addresses * fe80::a65e:60ff:fee1:b1bf 2600:3c03::de:d002
> d.add DestAddresses * ::ffff:ffff:ffff:ffff:0:0 ::
> d.add Flags * 0 0
> d.add InterfaceName utun1
> d.add PrefixLength * 64 116
> set State:/Network/Service/my_ipv6_tunnel_service/IPv6
> set Setup:/Network/Service/my_ipv6_tunnel_service/IPv6
> quit

Une fois que cela est fait, la sortie de scutil --dns (encore une fois modulo mdns stuff) changements :

DNS configuration

resolver #1
  search domain[0] : home.munkynet.org
  nameserver[0] : 10.20.4.4
  if_index : 14 (en3)
  flags    : Request A records, Request AAAA records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

DNS configuration (for scoped queries)

resolver #1
  search domain[0] : home.munkynet.org
  nameserver[0] : 10.20.4.4
  if_index : 14 (en3)
  flags    : Scoped, Request A records
  reach    : 0x00020002 (Reachable,Directly Reachable Address)

Maintenant, nous voyons Request AAAA records dans les drapeaux ! Je ne suis pas vraiment sûr de ce que sont les "scoped queries" ou pourquoi la configuration DNS pour celles-ci n'a pas changé, mais les choses semblent fonctionner maintenant, alors peu importe :

sam@shiny ~> curl -s 'http://ipv6.whatismyv6.com' | html2text | head -3
                 This page shows your IPv6 and/or IPv4 address
                          You are connecting with an IPv6 Address of:
                                             2600:3c03::de:d002

Lors de la déconnexion du tunnel, il suffit de supprimer les clés SystemConfiguration que vous avez ajoutées :

sam@shiny ~> sudo scutil
> remove State:/Network/Service/my_ipv6_tunnel_service/IPv4
> remove Setup:/Network/Service/my_ipv6_tunnel_service/IPv4
> remove State:/Network/Service/my_ipv6_tunnel_service/IPv6
> remove Setup:/Network/Service/my_ipv6_tunnel_service/IPv6
> quit

Quelques points à noter :

  • Le nom my_ipv6_tunnel_service est totalement arbitraire.
  • D'après les informations que j'ai glanées dans les scripts de haut en bas du Mullvad. .ovpn vous devez créer à la fois le profil Setup: y State: les clés. Je ne l'ai pas vérifié parce que je suis paresseux.
  • Je n'ai aucune idée de l'endroit où l'IPv6 DestAddresses viennent de. Je les ai copiés de Viscosity parce qu'ils semblaient y fonctionner. ::ffff:ffff:ffff:ffff:0:0 pour l'adresse locale de liaison et :: pour le public
  • Je ne sais même pas vraiment ce que DestAddresses signifie ou à quoi il sert.

Un joli script

J'ai écrit un script en Python qui récupère les adresses et les longueurs de préfixe à partir des données suivantes ifconfig sortie. Il nécessite Python 3.6 ou plus, donc assurez-vous que vous l'avez dans votre chemin. Il s'appelle wg-updown et appelle son service SystemConfiguration wg-updown-utun# mais ce n'est pas vraiment spécifique à WireGuard. Vous pourriez l'appeler comme un script post-up/pre-down pour n'importe quel vieux tunnel VPN ou l'exécuter manuellement. Appelez-le comme ceci :

# After tunnel comes up
wg-updown up IFACE

# Before tunnel goes down
wg-updown down IFACE

remplacer IFACE avec le nom de l'interface que votre client tunnel/VPN utilise, par ex. utun1 . Il imprimera les commandes qu'il envoie à scutil pour que vous puissiez voir ce qu'il fait en détail.

#!/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()

2voto

zionpi Points 113

Au moins une interface réseau doit inclure un serveur DNS adressé en IPv6.

Cela active le drapeau AAAA, et le Mac OS résoudra alors les adresses IPv6.

0voto

Marc Runkel Points 1

Le problème semble provenir du fait que l'IPv6 est désactivé sur l'interface Ethernet (du moins, il l'était chez moi).

J'accède à l'Internet IPv6 via tunnelbroker.net. Je viens d'ajouter mes adresses locale et de passerelle Tunnelbroker dans la page Préférences système - Réseau dans la page réseau.

Une solution plus propre serait d'ajuster les drapeaux pour demander des enregistrements AAAA, mais je n'ai aucune idée de la façon de le faire.

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X