qzeleza / kvas

vpn и shadowsocks клиент для роутеров keenetic
Other
901 stars 54 forks source link

1.1.9-beta_6: вопросы DNS #195

Closed AltGrF13 closed 3 weeks ago

AltGrF13 commented 1 month ago

Несколько дней отлаживал и экспериментировал (с полной зачисткой Entware), поэтому вопрос будет из нескольких частей отдельными комментариями

AltGrF13 commented 1 month ago

Удалена установка и перезапись устаревших версий dnsmasq из кода, теперь dnsmasq устанавливается исключительно из репозитория

Проверим версию

~ # dnsmasq -v
Dnsmasq version 2.90  Copyright (c) 2000-2024 Simon Kelley
Compile time options: IPv6 GNU-getopt no-RTC no-DBus no-UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset no-nftset auth no-cryptohash no-DNSSEC no-ID loop-detect inotify dumpfile

Если заглянуть во флаги установившегося из репозитория dnsmasq, то по сравнению с предыдущим комплектным (из sbin) добавился no-nftset и отсутствует regex(+ipset). Regexp — это та самая поддержка регулярок в правилах, позволявшая добавлять либо чисто домен, либо правила вида

ipset=/:.*googlevideo\.com:/kvas_ipset
server=/:.*googlevideo\.com:/127.0.0.1#9153

С новой версией правила экспортировать надо без звёздочек, они все работают как звёздочковые в прошлой версии (проверено многократно). Это работает сейчас идентично вышеприведённому на старой версии:

ipset=/googlevideo.com/kvas_ipset
server=/googlevideo.com/127.0.0.1#9153

Соответственно вопрос: это был сознательный выбор (отказ от регулярок)? Лично мне идея нравится:

  1. Dnsmasq будет обновляться из репа, меньше вероятность уязвимостей.
  2. КВАС позиционирует себя как простой продукт из коробки, задумывание над вопросом wildcard затормаживает.
  3. Вообще случай, когда домен нужен без поддоменов, крайне редок.
  4. На сборку Dnsmasq с поддержкой регулярок и поддержку его в актуальном состоянии будет уходить не малое время (потребуется мержить патч каждый раз).

Если всё остаётся, то этот момент надо подробнее отразить в заметках к релизу (изменение поведения). И начать убирать в консольных командах тот самый дополнительный вопрос про wildcard, вычищать звёздочки в передаваемых доменах (люди по инерции будут их ставить), в списке по-умолчанию заменить *2ip на 2ip.

Но если откат и возврат к Dnsmasq с регулярками планируется, то необходимо будет рассмотреть вопрос, чтобы заполнение файла kvas.dnsmasq сделать более… ожидаемым. Например, если я добавляю в любой из старых версий *abc.co, то подойдёт и домен abc.com. Хотя последний ожидаешь лишь для правила *abc.co*. В общем, если с какой-то из сторон звёздочка не передана, то там в регулярке должны быть символы начала и конца строки

The regex line [a-z]*gle.com will match both google.com and google.com.hk. Use anchor ^ and $ to produce a more precise match.

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

More specific domains take precedence over less specific domains, so: --server=/google.com/1.2.3.4 --server=/www.google.com/2.3.4.5 will send queries for google.com and gmail.google.com to 1.2.3.4, but www.google.com will go to 2.3.4.5

AltGrF13 commented 1 month ago

Автоматическое добавление и преревод DNS сервера на 5793 порт, где теперь постоянно размещен dnsmasq. Теперь нет необходимости отключать DNS провайдера командой opkg dns-override и теперь все клиенты роутера, которые не подключены к Квасу работают через системный DNS самого роутера, а те, что подключены к Квасу работают через dnsmasq.

Очень понравилась идея, когда не приходится освобождать 53 порт и оставаться на это время без интернета. Понижается общая сложность решения. К тому же, если работающий комплектный dns-прокси завести в dnsmasq, то можно будет со временем победить политики доступа (клиенты нестандартных политик висят своим DNS на 41100 порту на ndhcps мимо Dnsmasq).

Перенаправление встроенного DNS-прокси в Dnsmasq

При установке КВАС устанавливает [IP роутера]:9753 в качестве DNS для внешнего подключения. С точки зрения документации это означает, что ndhcps (DNS-прокси от Keenetic) на 53ем порту получает DNS-запросы и переправляет их в [IP роутера]:9753 (а dnsmasq может дальше передать их dnscrypt-proxy2). И этот подход работает не стабильно, долгое время не получалось уловить закономерность.

  1. Когда я пытаюсь обратиться к локальным адресам (типа f13.test), то ndhcps не передаёт запросы на указанный ему DNS [IP роутера]:9753. Он обслуживает их сам и отвечает, что ничего не знает. В Dnsmasq он его не проксирует.

  2. Скажем так, проблема балансировки или подключения. 2.1. Если в списке DNS для интернет подключения (в админке раздел /internet-filter/dns-configuration) оставить только [IP роутера]:9753, то я не могу подключиться к интернету (проверять после перезагрузки роутера, когда все DNS чисты). Для окончания подключения/авторизации обычно используется финальный переход на некий success url (зависит от провайдера), но роутер его совершить не может. Потому что он знает об единственном DNS — [IP роутера]:9753, а Dnsmasq на роутере (до подключения к интернету) почему-то ничем ему не помогает. 2.2. Если в этот же список добавить ещё DNS'ы (скриншот ниже) шифрованные, то согласно документации указанный DNS [IP роутера]:9753 использоваться не будет.

    При включении протокола DoT/DoH все DNS-запросы будут направляться на указанный при настройке адрес сервера. Полученные ранее DNS-серверы от вашего интернет-провайдера и прописанные вручную DNS-серверы использоваться не будут.

    image 2.3. Если в список DNS-серверов добавить только не шифрованные (например, провайдера), то подключение к интернету тоже происходит (как и в предыдущем пункте). Но ndhcps опять же старается весь DNS-трафик отправлять на добавленный, а не в Dnsmasq. Балансировка внутри него обычно выбирает их, а не [IP роутера]:9753.

  3. Хоть у меня у роутера и отключен пакет «Протокол IPv6», но DHCP локальным клиентам старается выдавать и IPv6 адреса. И многое не отключаемо, постепенно на уровне систем внедряется всё больше IPv6 мелочей насильно (пример обсуждения на форуме Кинетика). В свойствах подключения поддержка IPv6 у меня тоже отключена (скриншот ниже), но на уровне системы (если она современная) при обмене с DNS-сервером ему сообщается о поддержке IPv6 адресов. И ndhcps периодически отвечает IPv6 адресами (видны при nslookup), хотя и в свойствах подключения, и в роутере у меня всё отключено. image

В общем, этим путём проксирования добиться не удалось. Но если этого добиться, то и задачу #41 решить будет можно.

Прямое подключение клиентов к Dnsmasq

В админке роутера (/segments/Bridge0) в настройках DHCP мы можем указать адрес DNS-сервера. Указанный в этом разделе передаётся клиентам напрямую, ни с каким проксированием DNS играться тогда не придётся. Но компания почему-то решила запретить тут указание не стандартного порта (что странно, в других DHCP я такое совершал). image

Перенаправление DNS трафика

Раз предыдущие способы завести DNS-трафик в Dnsmasq не помогли, то будем перехватывать.

Про эту область разговор уже был, в тот момент я просил исключить этот "перехват". Он собирал весь нешифрованный DNS-трафик локальной сети, шедший на 53 порт, и переправлял его в 53 же порт роутера. Хотя весь DNS-трафик в локальной сети итак шёл на роутер:53. Тот код мог помочь лишь в случае, если кто-то из клиентов насильно изменил адрес DNS-сервера, при этом выбрал по какой-то причине нешифрованный DNS (шифрованный обитает на других портах). Была выпущена одна из бета-версий, где это убрано (с которой я полгода и прожил). Но чуть позже этот перехват Вы вернули (т.е. что-то не работало и мне интересно что). При этом вернута была более плохая вариация кода:

    ip4tables PREROUTING -t nat -p udp --dport ${DNS_PORT} -j DNAT --to "${local_ip}:${DNS_PORT}" &>/dev/null

Без указания интерфейса этот перехват навесился на все 30–50 сетевых интерфейсов Кинетика, в том числе и на внешние. Встречая любой DNS-трафик во внешней сети, он забирал его себе. Т.е. частично это правило повинно в сильной нагрузке на роутер, которую позже решали закрытием на фаерволле 53 порта.

Что ж, исправим этот перехват под наши нужды. Сейчас там навешено правило, которое на всех сетевых интерфейсах трафик порта 9753 перенаправляет в Кинетик. Нам же нужно, чтобы трафик в локальных сетевых интерфейсах на 53 порт уходил в 9753.

opt/etc/ndm/netfilter.d/100-dns-local:

if [ "${type}" = "iptables" ] && [ "${table}" = "nat" ] ; then
    . /opt/apps/kvas/bin/libs/ndm
    # перенаправляем dns-запросы в dnsmasq
    ip4_firewall_dns_rules_set &> /dev/null
fi

ndm:135

ip4_firewall_dns_rules_set() {
    local router_ip=$(get_router_ip)
    local submessage=" DNS трафика домашней сети в ${router_ip}:${DNS_PORT}."

    log_warning "Подключаем перенаправление${submessage}"
    for protocol in tcp udp ; do
        local iptables_rule=" -i br0 -p ${protocol} -m ${protocol} --dport 53 -j DNAT --to-destination ${router_ip}:${DNS_PORT}"

        if ip4save | grep -Fq -- "${iptables_rule}" ; then
            continue
        fi

        # без echo дублирование пробелов (что даёт warning и проблему наличия)
        iptables -A PREROUTING -t nat$(echo "${iptables_rule}") &>/dev/null \
         || echo "[${FUNCNAME}] Возникла ошибка при подключении перенаправления ${protocol}${submessage}"
    done
}

И наконец-то beta6 стабильно залетала (сейчас уже более суток на нескольких устройствах)! Весь обход (в том числе wildcard без звёздочек) отлично работает, ничуть не хуже beta3 или 1.1.8r2.

Единственный момент — надо ещё решить вопрос обхода в гостевых. Ни при каких условиях это не надо решать убиранием указания интерфейса в вышеприведённом коде; это проблема и производительности, и безопасности! Исправление гостевых чуть позже предоставлю в отдельной задачи, т.к. кроме DNS будет ещё немного правок.

UPD Функция обновлена

UPD2 Ещё понимаю, что обычно правила в КВАСе идут парами: устанавливающие и удаляющие (при перенавесе, удалении пакета). Не совсем понял, какой именно метод уравновешивал перехват DNS, убирал его. Во всяких flush* не нашёл.

AltGrF13 commented 1 month ago

Начиная с какой-то из версий для уменьшения жора dnscrypt строчка server_names = была отключена/закомментирована (и это верный шаг). Сейчас перед стартом он ищет наиболее быстрый сервер сам. Это помогло, скорее всего, лишь только потому; что перечисленные там google, cloudflare и yandex в списках DNSCrypt имеют лишь DoH сервера. Он всегда тяжелее для роутера, чем DoT или DNSCrypt. Чтобы он не пытался даже проверять или подключаться к DoH, нужно раскомментировать и сменить флаг doh_servers = false

qzeleza commented 4 weeks ago

Доброго дня

Благодарю Вас за столь подробный разбор темы. Редко такое случается сейчас - ценно. Теперь по вопросам.

Соответственно вопрос: это был сознательный выбор (отказ от регулярок)?

Да, это так. В следующей версии звездочки в tags уберу.

Перенаправление встроенного DNS-прокси в Dnsmasq

Не совсем понял о чем речь, у меня как раз все ожидаемо работает в описанным Вам случаях, видимо конфигурация разная. Если не трудно, постучитесь ко мне в "личку", в телеграмме - обсудим.

Что ж, исправим этот перехват под наши нужды. Сейчас там навешено правило, которое на всех сетевых интерфейсах трафик порта 9753 перенаправляет в Кинетик. Нам же нужно, чтобы трафик в локальных сетевых интерфейсах на 53 порт уходил в 9753.

Подключил Ваш вариант, благодарю, в следующей версии появится.

какой именно метод уравновешивал перехват DNS, убирал его. Во всяких flush* не нашёл.

ndm: 510 _-> ip4_firewall_fastnet_vpn_prune

Чтобы он не пытался даже проверять или подключаться к DoH, нужно раскомментировать и сменить флаг doh_servers = false

Добавил, в следующей версии появится.