Risoluzione DNS IPv6 su macOS High Sierra


5

Il mio ISP mi fornisce solo un indirizzo IPv4.

Dopo aver impostato una connessione al mio server OpenVPN universitario, ottengo un indirizzo IPv6. Con un indirizzo IPv6 di esempio www6.fit.vutbr.cz

Io posso:

Ma non posso:

  • apri www6.fit.vutbr.cz in un browser web

cioè il browser web non risolve un indirizzo dns ipv6.

Se aggiungo il seguente mapping a / etc / hosts

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

il browser funziona finalmente.

Penso che abbia qualcosa a che fare con scutil --dns che mostra:

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)

Credo che dovrei vedere i record Richiedi AAAA. Perché host e traceroute6 e ping6 risolvono il DNS, ma i browser Web no? Eventuali suggerimenti? Grazie


Commento rapido: finora non sono stato in grado di risolvere il problema utilizzando OpenVPN né Tunnelblick, ma l'utilizzo di Viscosity risolve il problema. Vale a dire, la viscosità gestisce il DNS IPv6 tramite VPN.
OndrejG,

Risposte:


2

Almeno un'interfaccia di rete deve includere un server DNS indirizzato IPv6.

Ciò imposta il flag AAAA, quindi Mac OS risolverà gli indirizzi IPv6.


0

Il problema sembra derivare dal fatto che IPv6 è disabilitato sull'interfaccia Ethernet (almeno era con me).

Sto accedendo a Internet IPv6 tramite tunnelbroker.net. Ho appena aggiunto i miei indirizzi locali e gateway di Tunnelbroker nella pagina Preferenze di sistema - Rete nella pagina di rete.

Una soluzione più pulita sarebbe quella di adattare le bandiere ai record Request AAAA, ma non ho idea di come farlo.


0

Questa è stata una seccatura enorme da capire, quindi ho scritto una piccola guida nella speranza che altri lo trovino utile:

Come convincere macOS a fare ricerche DNS IPv6 quando il tuo unico indirizzo IPv6 è tramite una VPN o un tunnel di qualche tipo

Il problema

il risolutore di nomi di dominio macOS restituirà gli indirizzi IPv6 (dai record AAAA) quando ritiene di avere un indirizzo IPv6 instradabile valido. Per interfacce fisiche come Ethernet o Wi-Fi è sufficiente impostare o assegnare un indirizzo IPv6, ma per i tunnel (come quelli che usano le utuninterfacce) ci sono alcuni passaggi extra che devono essere presi per convincere il sistema che sì, tu davvero avere un indirizzo IPv6 e sì, si desidera recuperare gli indirizzi IPv6 per le ricerche DNS.

Uso wg-quickper stabilire un tunnel WireGuard tra il mio laptop e un server virtuale Linode. WireGuard utilizza un utundispositivo tunnel spazio utente per effettuare la connessione. Ecco come viene configurato quel dispositivo:

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>

Ed ecco alcune righe pertinenti dalla mia tabella di routing:

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 è la mia rete ethernet locale.
  • 10.20.4.5 è l'indirizzo IP LAN del mio laptop.
  • 10.20.4.4 è l'indirizzo IP LAN del mio gateway.
  • 10.75.131.2 è l'indirizzo IPv4 della mia estremità del tunnel punto-punto di WireGuard.
  • 2600:3c03::de:d002 è l'indirizzo IPv6 della mia estremità del tunnel punto-punto WireGuard.
  • 50.116.51.30 è l'indirizzo pubblico del mio server Linode.

Questo dovrebbe essere sufficiente per avere la connettività IPv6, giusto? Bene, la risoluzione dei nomi funziona quando hostparla direttamente al mio server dei nomi:

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

Il ping per indirizzo IPv6 funziona:

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

E le connessioni HTTP per indirizzo IPv6 funzionano:

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

Tuttavia, le connessioni HTTP con solo il nome host IPv6 non funzionano:

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

Il risultato è lo stesso wgetsia nelle app della GUI come Firefox: la connessione tramite un indirizzo IPv6 letterale funziona bene, ma la connessione con un nome host che ha solo un record AAAA (e nessun record A) associato non lo fa.

È interessante notare che ping6 è in grado di effettuare una ricerca DNS e ottenere un indirizzo IPv6:

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

Perché può ping6farlo quando nient'altro può? Si scopre che quando ping6chiama getaddrinfosovrascrive i flag predefiniti. Uno dei flag predefiniti è AI_ADDRCONFIG, che indica al risolutore di restituire gli indirizzi solo nelle famiglie di indirizzi per cui il sistema dispone di un indirizzo IP. (Cioè, non restituire gli indirizzi IPv6 a meno che il sistema non disponga di un indirizzo IPv6 (non link-local). La maggior parte degli altri programmi aggiunge ai flag predefiniti anziché bloccarli, cosa che suppongo sia ragionevole.

Se lo esegui scutil --dnsti dirà come è impostato il resolver. Ecco l'output sul mio sistema (meno un sacco di roba mdns che non importa):

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)

Si noti che sotto flags, dice Request A recordsma non Request AAAA records. Quindi ci resta da provare a convincere il risolutore di macOS che in realtà abbiamo un indirizzo IPv6 valido, anche se si trova su un'interfaccia tunnel.

Configurazione di sistema

Il modo "giusto" perché ciò avvenga è che qualunque programma installi il tunnel per utilizzare l' SystemConfigurationAPI bizzarra e ampiamente non documentata per registrare il "servizio" di rete e le sue proprietà IPv6. L'app Viscosità fa questo. Tunnelblick no, il client OpenVPN ufficiale no, e wg-quicksicuramente no.

Il scutilKludge

Possiamo creare manualmente le stesse strutture di "servizio" SystemConfiguration usando il scutilcomando:

Innanzitutto creiamo la parte IPv4 del servizio:

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

E quindi creiamo la parte 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

Fatto ciò, l'output di scutil --dns(ancora roba modulo mdns) cambia:

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)

Ora vediamo Request AAAA recordstra le bandiere! Non sono davvero sicuro di cosa siano le "query con ambito" o perché la configurazione DNS per loro non sia cambiata, ma le cose sembrano funzionare ora quindi qualunque cosa:

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

Quando ti disconnetti dal tunnel, tutto ciò che devi fare è rimuovere le chiavi SystemConfiguration che hai aggiunto:

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

Un paio di cose da notare:

  • Il nome my_ipv6_tunnel_serviceè totalmente arbitrario.
  • Secondo le informazioni che ho raccolto dagli script su / giù nel .ovpnprofilo Mullvad , devi creare sia i tasti Setup:che i State:tasti. Non l'ho verificato perché sono pigro.
  • Non ho idea da dove DestAddressesprovenga l'IPv6 . Li ho copiati da Viscosity perché sembravano funzionare lì. ::ffff:ffff:ffff:ffff:0:0per l'indirizzo di collegamento locale e ::per il pubblico
  • Non so nemmeno cosa DestAddressessignifichi o a cosa serva.

Una bella sceneggiatura

Ho scritto uno script Python che raccoglie indirizzi e lunghezze del prefisso ifconfigdall'output. Richiede Python 3.6 o successivo, quindi assicurati di averlo nel tuo percorso. Si chiama wg-updowne chiama il suo servizio SystemConfiguration wg-updown-utun#, ma non è specifico per WireGuard. Potresti chiamarlo come script post-up / pre-down per qualsiasi vecchio tunnel VPN o eseguirlo manualmente. Chiamalo così:

# After tunnel comes up
wg-updown up IFACE

# Before tunnel goes down
wg-updown down IFACE

sostituire IFACEcon il nome dell'interfaccia utilizzata dal client tunnel / VPN, ad es utun1. Stampa i comandi che sta inviando in scutilmodo da poter vedere cosa sta facendo in dettaglio.

#!/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()
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.