свяжитесь локальный (fe80::), адреса без объема превращают свой путь в/etc/resolv.conf и вызывают проблемы

У меня есть неустойчивые проблемы возможности соединения. ipv6 связывается, локальный адрес автоматически добавляется к моему/etc/resolv.conf, и это, кажется, заставляет сопоставитель libc приводить разрешение к сбою. Я хотел бы знать, как или предотвратить тот адрес, который будет вставлен там или найдет подходящее обходное решение.

Моя установка: у Меня есть настольная установка развертывания Ubuntu 14.04 с ipv4 и ipv6. Это имеет только одно проводное соединение (никакой Wi-Fi) к порту LAN домашнего выполнения маршрутизатора OpenWrt. Сетевой рабочий стол арестован NetworkManager, который выполняет его собственную локальную копию dnsmasq. Все файлы администратора сети в / и т.д. являются "запасом", я не коснулся их.

Когда я сбросил свои сети через администратора сети, все хорошо работает (но только в течение нескольких минут). Моя рабочая конфигурация resolv.conf похожа так:

user@foo:/$ cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by     
resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 127.0.1.1
search lan

Мой маршрутизатор (192.168.1.1 или fe80:: говядина), также выполняет копию dnsmasq и настроен для рекламы 192.168.1.1 (самого) к его клиентам DHCP на v4. На v6 это периодически отправляет сообщения объявления маршрутизатора (icmpv6.type == 134) с рекурсивной опцией DNS Server для fe80:: говядина. dnsmasq сервис DNS маршрутизатора слушает на обоих адресах:.1.1 и:: говядина (мостовое соединение LAN маршрутизатора ipv6 адрес канала).

# working dns server. ran from the desktop.
user@foo:/$ dig google.com +time=1 @fe80::beef > /dev/null ; echo $?
0

Когда-либо, если я перехожу к "Информации о соединении" в NetworkManager, мой основной DNS и маршрутизатор в Ipv4 установлены на 182.168.1.1. NetworkManager GUI не показывает информации под заголовком раздела "ipv6" - но мой nic получает адреса ipv6 (slaac и dhcpv6 с сохранением информации), с которым я могу просмотреть ip addr show.

Проблема: После сброса моей сети через администратора сети (переключатель "Позволяют Объединиться в сеть") и ожидать (т.е. ожидать до следующего сообщения объявления маршрутизатора, я подозреваю), новая запись пробивается к /etc/resolv.conf:

user@foo:~$ cat /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver fe80::beef
nameserver 127.0.1.1
search lan

Проблема состоит в том, что, после того как это происходит, некоторые инструменты пространства пользователя (включая Firefox и Google Chrome) не разрешат (некэшируемые) доменные имена.

Насколько я понимаю, работающий со ссылкой, локальные адреса требуют, чтобы объем ссылки был упомянут явно. Следующая трассировка показывает как connect сбои без объема ссылки (значение по умолчанию scope_id 0).

user@foo:~$ strace ping google.com
execve("/bin/ping", ["ping", "google.com"], [/* 73 vars */]) = 0
...

stat("/etc/resolv.conf", {st_mode=S_IFREG|0644, st_size=220, ...}) = 0
socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET6, sin6_port=htons(53), inet_pton(AF_INET6, "fe80::beef", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINVAL (Invalid argument)
close(3)                                = 0
socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET6, sin6_port=htons(53), inet_pton(AF_INET6, "fe80::beef", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EINVAL (Invalid argument)
close(3)                                = 0
write(2, "ping: unknown host google.com\n", 29ping: unknown host google.com) = 29
exit_group(2)                           = ?
+++ exited with 2 +++

Сбои DNS, но у меня есть возможность соединения иначе:

user@foo:~$ ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=60 time=7.77 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=60 time=7.81 ms
....

user@foo:~$ ping6 2607:f8b0:400a:808::200e  # google.com AAAA
PING 2607:f8b0:400a:808::200e(2607:f8b0:400a:808::200e) 56 data bytes
64 bytes from 2607:f8b0:400a:808::200e: icmp_seq=1 ttl=57 time=7.94 ms
64 bytes from 2607:f8b0:400a:808::200e: icmp_seq=2 ttl=57 time=7.86 ms
...

Добавление объема (%eth0) в конец адреса в resolv.conf устраняет проблему:

nameserver fe80::beef%eth0
nameserver 127.0.1.1
search lan

Но конечно, это изменение вытерто в следующий раз вокруг.

Есть ли любой путь к:

  • Вынудите ipv4 только запросить DNS (я не думаю, что выполню ipv6-единственную установку в ближайшее время),
  • Укажите интерфейсный объем по умолчанию в сопоставителе (т.е. "%eth0")
  • Измените dnsmasq маршрутизатора (или radvd или rdnss) для не рекламы его адреса ipv6 для DNS (только его ipv4)

Править: отказавший фиксируют попытку

Если я перемещаюсь /etc/resolv.conf символьная ссылка на /etc/resolv.conf.old и запишите мои собственные помехи /etc/resolv.conf содержа только локальный dnsmasq IP сервера (сервер имен 127.0.1.1), я узнаю, что файл все еще изменяется чем-то еще, что добавляет "поисковую" строку.

user@foo:~$ cat /etc/resolv.conf  # my new file, not the symlink
# Edited by hand to avoid using the ipv6 link local scopeless address
# check resolv.conf.old to see normal file
#nameserver fe80::beef
nameserver 127.0.1.1
search lan

После небольшого количества времени:

user@foo:~$ cat /etc/resolv.conf  # my new file prefixed by something
search lan.
# Edited by hand to avoid using the ipv6 link local scopeless address
# check resolv.conf.old to see normal file
#nameserver fe80::beef
nameserver 127.0.1.1
search lan

После перезагрузки:

user@foo:~$ cat /etc/resolv.conf  # eh. same line added again.
search lan.
search lan.
# Edited by hand to avoid using the ipv6 link local scopeless address
# check resolv.conf.old to see normal file
#nameserver fe80::beef
nameserver 127.0.1.1
search lan

Так. если я не начинаю играть с болтовней +i и другие приемы для предотвращения того сценария (или независимо от того, что это) от касания/etc/resolv.conf, я чувствую, что эта полустатическая опция не является действительно чистой. Отслеживаемость, когда эти файлы изменяются или регистрирующийся об этом, была бы плюс. системный журнал ничего не имеет.

Примечание: В попытке скрыть некоторую частную информацию, я отредактировал суффиксы адреса и имена хостов выше

3
задан 12 July 2019 в 19:56

1 ответ

Я отвечаю на свой собственный вопрос и даю объяснение и патч для ссылки.

Проблема находится в dhcp6c сценариях, которым предоставляют пакет wide-dhcpv6-client. dhcp6c выполнения как демон в моей системе (запущенный /etc/init.d/wide-dhcpv6-client) и отсылает запросы DHCPv6 каждые несколько минут. Я не думаю wide-dhcpv6-client установлен по умолчанию в рабочем столе человечности. Его конфигурация (/etc/wide-dhcpv6/dhcp6c.conf) набор должен вызвать сценарий /etc/wide-dhcpv6/dhcp6c-script когда обновление должно быть сделано. Этот сценарий является багги:

  1. Это игнорирует объем в случае локальных для ссылки адресов

  2. В случаях, где /etc/resolv.conf не управляется resolvconf (т.е. не символьная ссылка), он приводит к search X строки, добавляемые, не проверяя, присутствуют ли строки уже (затем файл когда-либо растет).

Принятие Вас имеет единственный интерфейс, контролируемый dhcp6c **, исправляя файл /etc/wide-dhcpv6/dhcp6c-script с патчем ниже решит проблему:

--- /etc/wide-dhcpv6/dhcp6c-script.orig 2016-09-04 17:12:35.405042056 -0700
+++ /etc/wide-dhcpv6/dhcp6c-script.new  2016-09-04 22:57:05.213169351 -0700
@@ -6,20 +6,48 @@

 [ -f /etc/default/wide-dhcpv6-client ] && . /etc/default/wide-dhcpv6-client

+# Guess interface to use as scope_id. Ideally, dhcp6c would pass the
+# name of the interface on which the DHCPv6 reply was received.
+scope=""
+for IFACE in $INTERFACES; do
+    scope="$IFACE"
+    break;
+done
+
+# exact line match. grep would interpret domain periods as special
+# chars.  The naive loop avoids relying on other non-coreutils
+# commands (sed, awk, etc.).
+has_line () {
+    local line
+    while read line; do
+    if [ "$line" = "$1" ]; then
+       return 0
+    fi
+    done
+    return 1
+}
+    
+
 if [ -n "$new_domain_name" -o -n "$new_domain_name_servers" ]; then
     old_resolv_conf=/etc/resolv.conf
     new_resolv_conf=/etc/resolv.conf.dhcp6c-new
     rm -f $new_resolv_conf
     if [ -n "$new_domain_name" ]; then
-        echo search $new_domain_name >> $new_resolv_conf
+   has_line "search $new_domain_name" < $old_resolv_conf || {
+       echo "search $new_domain_name" >> $new_resolv_conf
+   }
     fi
     if [ -n "$new_domain_name_servers" ]; then
         for nameserver in $new_domain_name_servers; do
+       if [ -n "$scope" -a "${nameserver##fe80::}" != "$nameserver" ]; then
+          nameserver="$nameserver%$scope"
+       fi
+
             # No need to add an already existing nameserver
-            res=$(grep "nameserver $nameserver" $old_resolv_conf)
-            if [ -z "$res" ]; then
-                echo nameserver $nameserver >> $new_resolv_conf
-            fi
+       has_line "nameserver $nameserver" < $old_resolv_conf || {
+                echo "nameserver $nameserver" >> $new_resolv_conf
+       }
         done
     fi

** Код выше выберет первый интерфейс из списка интерфейсов в /etc/default/wide-dhcpv6-client, и снабдите суффиксом его к любому серверу имен, запускающемуся с fe80::. Это подобно тому, в чем выполняют /etc/dhcp/dhclient-enter-hooks.d/resolvconf. Это не идеально, особенно если у Вас есть несколько интерфейсов. dhcp6c не передает название интерфейса в среде, таким образом, мы можем только предположить. (ошибка зарегистрировала: https://bugs.launchpad.net/ubuntu / + source/wide-dhcpv6 / + ошибка/1620221)

Если Вы имеете несколько зарубок и нуждаетесь в этом, чтобы быть более устойчивыми, можно вместо этого настроить /etc/wide-dhcpv6/dhcp6c.conf запустить другую копию сценария в зависимости от имени интерфейса и hardcode название интерфейса в сценарии.

Прежде чем я выяснил проблему, я обнаружил два обходных решения, которые не решают вопрос, но избегают признаков.

Обходное решение 1: отключите dnsmasq локальный сопоставитель.

Записи в resolv.conf заполняются правильно, когда dnsmasq сервис NetworkManager отключен. Таким образом, я теряю его льготы. Не прекрасный.

Выполненные шаги в том, Как я могу отключить DNS тот Администратор сети использование?. Кроме того, см. список безопасности и последствия производительности отключения локального сопоставителя.

После перезапуска NM ссылка локальному адресу добавили объем, правильно:

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 192.168.1.1
nameserver fe80::beef%eth0
search lan

Я не абсолютно уверен, почему это работает, но я подозреваю, что это - потому что и NetworkManager и dhcp6c пишут в resolvconv, и сценарий обновления способствует fe80:: beef%eth0 (переданный NetworkManager) по сравнению с тем же адресом без объема (переданный dhcp6c).

Обходное решение 2: Настройте OpenWrt для рекламы дополнительного dhcpv6 сервера как части RDNSS. Этот сервер будет иметь приоритет по ссылке локальная в/etc/resolv.conf. Я чувствую, что это - немного лучшее решение, чем обходное решение № 1, потому что это сохраняет локальный сопоставитель (по крайней мере, для ipv4), но это более сложно.

  1. Установите OpenWrt с ULA-префиксом IPv6, скажите fd00:cafe::/48. (Menu -> Network -> Interfaces -> bottom of page). Маршрутизатор получит локальный ipv6 fd00::cafe::1 на LAN. (Я попробовал это на более спокойном хаосе OpenWRT 15.05.1).

  2. Сообщите odhcpd (который предоставляет dhcpv6 услугу на той версии openwrt) также рекламировать IP как (дополнительный) сервер DNS. odhcpd (версия 2015-11-19-01d3f...) предлагает флаг конфигурации, названный dhcp.lan.dns (описание флага). В luci UI это находится под Menu -> Network -> Interfaces -> LAN (click edit) -> DHCP Server section -> IPv6 Settings tab -> Announced DNS Servers. Добавьте, что ULA маршрутизатора адресуют к полю. Я также добавил ipv4 адрес подсети маршрутизатора к списку серверов DNS (192.168.1.1) ради симметрии.

С этим на месте, odhcpd будет рекламировать оба адреса как часть РА, но NM, в наших интересах, только пишет, что ULA адресуют к resolv.conf. Локальный для ссылки адрес никогда не добавляется к resolv.conf:

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver fd00:cafe::1
nameserver 127.0.1.1
search lan

Смотря на трассировки wireshark при конфигурировании этот путь сообщение РА от openwrt перечислит оба адреса сервера DNS, но его DHCPv6 отвечает, только имеют fd00:cafe::1 один, таким образом, ошибки в dhcp6c сценариях избегают.

Если у Вас есть хост Unix в сети не выполнение локального сопоставителя (например, если бы Вы применили обходное решение 1 и 2 на человечности), то resolv.conf имел бы всего дюйм/с:

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 192.168.1.1
nameserver fd00:cafe::1
nameserver fe80::beef%eth0
search lan

Алгоритм по умолчанию в сопоставителе libc должен попробовать каждую запись от resolv.conf в свою очередь, испытав таймаут на каждом. Также - несколько псевдонимов к тому же серверу DNS могли вызвать дополнительные задержки, когда/если проблемы возникают. В моем случае то наиболее вероятное означает мой целый маршрутизатор вниз, не только его сервер DNS, таким образом, это - надуманный вопрос. но Ваш пробег может варьироваться.

дополнительный я использовал следующий сценарий для отладки изменений, внесенных в resolvconf. Это позволило мне выяснять, какой демон отправлял неправильные изменения:

#!/bin/bash

# logs all interactions to /sbin/resolvconf into syslog
# this script is named /sbin/resolvconf, temporarily.
# moved resolvconv binary to resolvconf.real, temporarily.

BIN=/sbin/resolvconf.real
LOGGER=/usr/bin/logger

ppid () { ps -p ${1:-$$} -o ppid= 2>/dev/null | sed 's/ //g'; }

PROC=$$

"$LOGGER" "resolvconf.wrapper args: $@"

for ((i=0; i<4; i++)); do
    PROC=$(ppid $PROC)
    if [[ "$PROC" == 0 || "$PROC" == "" ]]; then
    break;
    fi
    if [[ "$i" -eq 0 ]]; then
    "$LOGGER" "resolvconf.wrapper invoked by: pid=$PROC $(/bin/ps -p $PROC -o command=)"
    else
    "$LOGGER" "resolvconf.wrapper child of: pid=$PROC $(/bin/ps -p $PROC -o command=)"
    fi
done

# peek at stdin (which contains the config)
if [[ "$1" == "-a" ]] && [[ -n "$2" ]]; then
    tmp=$(/bin/mktemp)
    while read REST; do
    logger "resolvconf.wrapper feeding: $REST"
    echo $REST >> "$tmp"
    done
    exec < "$tmp"
    rm "$tmp"
fi

exec -a /sbin/resolvconf "$BIN" "$@"

С этим на месте, системный журнал содержит блоки как так:

Sep  3 02:32:29 calm logger: resolvconf.wrapper invoked by: pid=12610 sh -c /sbin/resolvconf -a NetworkManager
Sep  3 02:32:29 calm logger: resolvconf.wrapper child of: pid=11910 NetworkManager
Sep  3 02:32:29 calm logger: resolvconf.wrapper child of: pid=1 /sbin/init
Sep  3 02:32:29 calm logger: resolvconf.wrapper feeding: # Generated by NetworkManager
Sep  3 02:32:29 calm logger: resolvconf.wrapper feeding: domain base
Sep  3 02:32:29 calm logger: resolvconf.wrapper feeding: search base base.
Sep  3 02:32:29 calm logger: resolvconf.wrapper feeding: nameserver 127.0.1.1
...
Sep  3 02:14:23 calm logger: resolvconf.wrapper gparent: pid=1553 /usr/sbin/dhcp6c -Pdefault eth0
Sep  3 02:14:23 calm logger: resolvconf.wrapper invoked by: pid=15926 /bin/sh /etc/wide-dhcpv6/dhcp6c-script
Sep  3 02:14:23 calm logger: resolvconf.wrapper args: -a eth0
Sep  3 02:14:23 calm logger: resolvconf.wrapper feeding: search base.
Sep  3 02:14:23 calm logger: resolvconf.wrapper feeding: nameserver fd00:cafe::1
0
ответ дан 1 December 2019 в 22:27

Другие вопросы по тегам:

Похожие вопросы: