qzeleza / kvas

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

Коррекция правил iptables #116

Closed AltGrF13 closed 2 months ago

AltGrF13 commented 3 months ago

Есть куча скриптов в opt/etc/ndm/netfilter.d, которые срабатывают при перезапуске роутера целиком или какого-то из его интерфейсов (например, в веб-морде что-то изменили). В 100-dns-local идёт вызов ip4_firewall_dns_rules_set из opt/etc/ndm/ndm:129, где:

  1. Правила iptables без протокола, т.е. ALL. Т.е. туда полетят и ICMP (как минимум), а SS умеет работать только с TCP и UDP. В общем, для SS нельзя создавать правила iptables без -p, посыл коммита 6e5db2e2dda07537aa1d4a285b2b4cf09a31d52e не верен. Как минимум не откачено ещё в:

    • ip4_firewall_vpn_mark
    • ip4_firewall_mark_rules_tcp_udp_on
    • ip4tbl_flush_rm_match_set
  2. В if остался grep закомментированного protocol, после вышеназванного коммита условие не срабатывает никогда (более того, в логе роутера постоянный спам ошибки), для подключения SS этих правил DNS в iptables больше нет (хотя несколько лет подряд КВАСом для SS они создавались всегда)

    iptables -A PREROUTING -w -t nat -i br0 -p tcp --dport 53 -j DNAT --to 192.168.1.1
    iptables -A PREROUTING -w -t nat -i br0 -p udp --dport 53 -j DNAT --to 192.168.1.1

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

В общем, предлагаю этот метод откатить (к использованию protocol) и временно задокументировать целиком. Если жалоб не будет, то при очередном рефакторинге почистить и его тело, и вызов в 100-dns-local.

ip4_firewall_dns_rules_set() {
#   interface=$(get_local_inface)
    local_ip=$(get_router_ip)

#   for protocol in tcp udp ; do
        #   Если не заданы аргументы, то ничего не выполняем
#       if [ -n "${interface}" ] && [ -n "${local_ip}" ]; then
            # если правила для tcp есть, то пропускаем их добавление
#           if ! ip4save | grep -q "${protocol} \-\-dport ${DNS_PORT} \-j DNAT" ; then
#               log_warning "Подключаем правила для корректной работы DNS трафика через 53 порт:"
#               log_warning "Интерфейс: ${interface}, IP: ${local_ip}, протокол: ${protocol}."
#               ip4tables PREROUTING -w -t nat -i "${interface}" -p "${protocol}" --dport ${DNS_PORT} -j DNAT --to "${local_ip}" &>/dev/null \
#                   || error "[${FUNCNAME}] Возникла ошибка в функции при установке правил iptables."
#           fi
#       else
#           log_error "При вызове ip4_firewall_dns_rules_set не были заданы обязательные аргументы."
#       fi
#   done
}
qzeleza commented 3 months ago

Я правильно Вас понял, что Вы предлагаете полностью удалить ip4_firewall_dns_rules_set?

AltGrF13 commented 3 months ago

Фактически, да.

  1. В комментариях к вызову этой функции указано, что она для работы SS. Что как раз мой (хорошо изученный) случай.
  2. После указанного январского коммита этот код всё равно не отрабатывал; что и удивило меня — привычных 2 правил в iptables нет.
  3. Но обход прекрасно работал, это заставило внимательнее присмотреться к привычному. В итоге мы видим, что создавались 2 правила для основного домашнего WiFi; которые, встречая трафик на не зашифрованный DNS, перенаправляют его на роутер (если они шли не к нему, фактически). Ну и у этого кода, получается, довольно слабая позиция: лишь один случай DNS, лишь одна подсеть.
  4. Но, опять же, не проверялось с adguard (вдруг там какой-то хитрый механизм, который я пока не понимаю). Или вдруг влияет использование роутером во вне шифрованного DNS? Все случаи объять невозможно.
  5. Но, заметьте, когда мы расшаривали основной SS другим подсетям, то мы всегда тащили 2 правила для роутинга трафика. А от этих DNS-правил для других подсетей отказались (фактически, однажды мы их уже выкинули для других подсетей — даже Ваш коммент на эту тему могу найти).
qzeleza commented 3 months ago

Добро, спасибо, после проверки - включу изменения в следующий релиз.

AltGrF13 commented 3 months ago

В первом пункте ещё описано, что SS нельзя создавать правила iptables без -p. И что в ip4tbl_flush_rm_match_set код откачен так и не был. Там сейчас вот такой блок

#       for prot in tcp udp; do
#       ip4save | grep "${route}" | grep "${chain}" | grep -q "${prot}" && {
        ip4save | grep "${route}" | grep -q "${chain}" && {
            if [ -n "${interface}" ] && [ -n "${proxy_port}" ] ; then
#                   Для shadowsocks
                iptab -t "${table}" -i "${interface}" -D "${route}" -p "${prot}" -m set --match-set ${table_name} dst -j "${chain}" --to-port "${proxy_port}" &>/dev/null
                iptab -t "${table}" -i "${interface}" -D "${route}" -p "${prot}" -m set --match-set ${table_name} dst -j "${chain}" --to-port "${proxy_port}" &>/dev/null
            else
#                   Для VPN
#               iptab -t "${table}" -D "${route}" -p "${prot}" -m set --match-set ${table_name} dst -j "${chain}" &>/dev/null
                iptab -t "${table}" -D "${route}" -m set --match-set ${table_name} dst -j "${chain}" &>/dev/null
            fi
        }
#       done

Как видите, переменная prot закомменчена, а правила в ветке shadowsocks с ней (какими они и должны быть). Сейчас эти правила не очищаются, выходит. И сыпят ошибкой в лог.

AltGrF13 commented 3 months ago

опять же, не проверялось с adguard (вдруг там какой-то хитрый механизм, который я пока не понимаю)

А к этому подозрению бы добавил; что, может эти 2 правила нужны, когда основное соединение VPN (и комментарий в коде, что это лишь для SS, ошибочен)? Ибо SS+dnsmasq точно ничего такого не требует, всё прекрасно работает.

AltGrF13 commented 3 months ago

Ну и раз залезли в эту область кода, то немного странная логика в триггерных файлах opt/etc/ndm/netfilter.d

100-dns-local

100-proxy-redirect

100-vpn-mark

            if fastnet_enabled ; then
                ip4_firewall_vpn_mark &> /dev/null
            else
                ip4_firewall_mark_rules_tcp_udp_on &> /dev/null
            fi

Но у нас уже есть готовая функция ip4_mark_vpn_network, в которой делается тоже самое + накидывание гостевых правил.

Итого, предлагается:

  1. Из 100-dns-local выкинуть накидывание гостевых правил (и файл не тот, и очерёдность).
  2. В 100-proxy-redirect добавить накидывание гостевых правил SS последним действием (это файл SS, логично здесь это и держать).
  3. В 100-vpn-mark тоже добавить воссоздание гостевых правил VPN последним действием, путём вызова общей функции, в которой есть все действия.
qzeleza commented 3 months ago

Хорошо, спасибо, посмотрю

qzeleza commented 3 months ago

изменения внесены в 1.1.8 r1 прошу дать обратную связь.

AltGrF13 commented 3 months ago

После обновления были проверены (что на сайтах из списка обхода подключение через прокси, а на обычные — напрямую) домашний WiFi, гостевой, IKEv2 при основном подключении SS. Везде всё хорошо.

В логе ошибка тоже пропала.

Вопрос можно закрывать.

qzeleza commented 2 months ago

закрываю, раз проблема ушла