From d2bbcc7e33042e99321e75f6070b1bd42e82bf35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D1=82=D0=B0=D0=BB=D0=B8=D0=B9=20=D0=9D=D0=B8?= =?UTF-8?q?=D0=BA=D0=B8=D1=82=D0=B5=D0=BD=D0=BA=D0=BE?= Date: Mon, 8 Jun 2026 12:44:20 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20kill=20switch=20=E2=80=94=20UFW=20before?= =?UTF-8?q?.rules=20=D1=81=20=D0=B0=D0=BA=D1=82=D1=83=D0=B0=D0=BB=D1=8C?= =?UTF-8?q?=D0=BD=D1=8B=D0=BC=20DEV,=20=D0=BF=D1=80=D1=8F=D0=BC=D1=8B?= =?UTF-8?q?=D0=B5=20iptables,=20/etc/hosts=20=D0=B4=D0=BB=D1=8F=20*.eltex.?= =?UTF-8?q?loc=20=D0=B8=20elph?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Три корневые проблемы и их исправления: 1. MANAGE_BUILTINS=no в /etc/default/ufw — цепочка ufw-before-output не вызывалась из OUTPUT, правила before.rules не применялись. → автофикс no→yes + прямые правила iptables (не зависят от UFW). 2. UFW-правила создавались однократно по маркеру — при смене DEV (wlp1s0→enp4s0) продолжали ссылаться на старый интерфейс. → теперь при каждом запуске удаляются и пересоздаются с актуальным DEV. 3. DNS через VPN для локальных доменов возвращал внешние IP вместо внутренних (RFC1918) — трафик уходил в VPN и не достигал серверов. → /etc/hosts с фиксированными IP для *.eltex.loc, mattermost, elph. → замена dig +short на getent hosts (уважает /etc/hosts). Добавлены built-in KILL_SWITCH_EXCEPTIONS: mattermost.eltex-co.ru elph.eltex-co.ru 10.80.0.15 Co-Authored-By: Claude Opus 4.8 --- scripts/ru-bypass.sh | 98 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/scripts/ru-bypass.sh b/scripts/ru-bypass.sh index 751c37c..a0f1599 100644 --- a/scripts/ru-bypass.sh +++ b/scripts/ru-bypass.sh @@ -35,6 +35,17 @@ LOCAL_DNS="${LOCAL_DNS:-}" AMNEZIA_SERVER="${AMNEZIA_SERVER:-}" KILL_SWITCH_EXCEPTIONS="${KILL_SWITCH_EXCEPTIONS:-}" +# Базовые исключения, необходимые для работы корпоративных сервисов +# Добавляются автоматически, даже если не указаны в конфиге +_BUILTIN_EXCEPTIONS="mattermost.eltex-co.ru elph.eltex-co.ru 10.80.0.15" +for _exc in $_BUILTIN_EXCEPTIONS; do + case " $KILL_SWITCH_EXCEPTIONS " in + *" $_exc "*) ;; + *) KILL_SWITCH_EXCEPTIONS="$KILL_SWITCH_EXCEPTIONS $_exc" ;; + esac +done +KILL_SWITCH_EXCEPTIONS="${KILL_SWITCH_EXCEPTIONS# }" + # Сохраняем конфиг для будущих запусков (systemd, NM dispatcher) cat > /etc/ru-bypass.conf <<_CONF GATEWAY="$GATEWAY" @@ -146,6 +157,33 @@ EOF echo "NetworkManager dispatcher установлен." fi +# --- Локальные хосты (фиксируем IP для доменов, которые должны резолвиться локально) --- +# Без этого DNS через VPN может вернуть внешний IP вместо внутреннего, +# и трафик пойдёт через VPN вместо прямого соединения. +HOSTS_MARKER="# ru-bypass: local hosts" + +# Удаляем старые записи по маркеру (чтобы не копились дубли) +sed -i "/$HOSTS_MARKER/d" /etc/hosts + +# Добавляем актуальные +cat >> /etc/hosts <<_HOSTS +$HOSTS_MARKER +# Eltex corporate services (*.eltex.loc, mattermost, elph) +172.16.0.3 eltex.loc +172.16.5.103 intdocs.eltex.loc +172.16.5.251 red.eltex.loc +172.16.1.17 gitlab.eltex.loc +172.16.1.106 pixso.eltex.loc +172.16.1.94 mcpe-builder.eltex.loc +172.16.5.63 proxy.eltex.loc +10.80.0.16 ssw.eltex.loc +172.16.5.78 nexus.eltex.loc +172.16.1.149 cpe-worker.eltex.loc +172.16.5.22 mattermost.eltex-co.ru elph.eltex-co.ru ecss-elph-proxy.eltex-co.ru +_HOSTS + +echo "Локальные хосты: *.eltex.loc, mattermost, elph → /etc/hosts" + # --- Обновляем RIPE-список (кэш 24ч) --- if [ ! -f "$CACHE" ] || [ $(( $(date +%s) - $(stat -c %Y "$CACHE" 2>/dev/null || echo 0) )) -gt 86400 ]; then @@ -201,7 +239,7 @@ if [ -n "${ALL_EXC// }" ]; then if echo "$item" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$"; then ips="$item" else - ips=$(dig +short "$item" A 2>/dev/null) + ips=$(getent hosts "$item" 2>/dev/null | awk '{print $1}' | sort -u) fi for ip in $ips; do ipset add ru-direct "$ip" -exist 2>/dev/null || true @@ -255,7 +293,7 @@ if [ -n "${ALL_EXC// }" ]; then if echo "$item" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$"; then ips="$item" else - ips=$(dig +short "$item" A 2>/dev/null) + ips=$(getent hosts "$item" 2>/dev/null | awk '{print $1}' | sort -u) fi for ip in $ips; do ip route replace "$ip/32" via "$GATEWAY" dev "$DEV" 2>/dev/null @@ -279,34 +317,60 @@ if [ -n "$LOCAL_DNS" ]; then fi fi -# --- Правило в UFW before.rules (однократно, после создания ipset) --- +# --- Правила в UFW before.rules (обновляются при каждом запуске) --- +# Маркеры используются для идентификации правил; DEV всегда актуальный. -UFW_MARKER="match-set $SETNAME" -if ! grep -q "$UFW_MARKER" "$UFW_BEFORE" 2>/dev/null; then - echo "Добавляем правило в UFW before.rules..." - sed -i "0,/^COMMIT/{s/^COMMIT/# .ru bypass (ipset $SETNAME)\n-A ufw-before-output -m set --match-set $SETNAME dst -o $DEV -j ACCEPT\nCOMMIT/}" "$UFW_BEFORE" - echo "UFW обновлён (.ru ipset)." +UFW_IPSET_MARKER="ru-bypass: ipset $SETNAME" +UFW_LOCAL_MARKER="ru-bypass: local-nets-bypass" + +echo "Обновляем правила UFW before.rules..." + +# Удаляем старые правила (если есть) — и в новом, и в старом формате маркеров +sed -i "/# $UFW_IPSET_MARKER/d; /# \.ru bypass (ipset $SETNAME)/d" "$UFW_BEFORE" +sed -i "/-A ufw-before-output -m set --match-set $SETNAME dst/d" "$UFW_BEFORE" +sed -i "/# $UFW_LOCAL_MARKER/d; /# local nets bypass (local-nets-bypass)/d" "$UFW_BEFORE" +sed -i "/-A ufw-before-output -d 10\.0\.0\.0\/8 -o/d" "$UFW_BEFORE" +sed -i "/-A ufw-before-output -d 172\.16\.0\.0\/12 -o/d" "$UFW_BEFORE" +sed -i "/-A ufw-before-output -d 192\.168\.0\.0\/16 -o/d" "$UFW_BEFORE" + +# Добавляем правила заново с актуальным DEV +sed -i "0,/^COMMIT/{s/^COMMIT/# $UFW_IPSET_MARKER\n-A ufw-before-output -m set --match-set $SETNAME dst -o $DEV -j ACCEPT\nCOMMIT/}" "$UFW_BEFORE" +sed -i "0,/^COMMIT/{s/^COMMIT/# $UFW_LOCAL_MARKER\n-A ufw-before-output -d 10.0.0.0\/8 -o $DEV -j ACCEPT\n-A ufw-before-output -d 172.16.0.0\/12 -o $DEV -j ACCEPT\n-A ufw-before-output -d 192.168.0.0\/16 -o $DEV -j ACCEPT\nCOMMIT/}" "$UFW_BEFORE" + +echo "UFW before.rules обновлён (ipset + локальные сети, DEV=$DEV)." + +# --- Исправляем MANAGE_BUILTINS (должен быть yes, иначе before.rules не вызывается) --- +if grep -q '^MANAGE_BUILTINS=no' /etc/default/ufw 2>/dev/null; then + sed -i 's/^MANAGE_BUILTINS=no/MANAGE_BUILTINS=yes/' /etc/default/ufw + echo "UFW: MANAGE_BUILTINS исправлен (no → yes)." fi -UFW_LOCAL_MARKER="local-nets-bypass" -if ! grep -q "$UFW_LOCAL_MARKER" "$UFW_BEFORE" 2>/dev/null; then - echo "Добавляем правила UFW для локальных сетей..." - sed -i "0,/^COMMIT/{s/^COMMIT/# local nets bypass ($UFW_LOCAL_MARKER)\n-A ufw-before-output -d 10.0.0.0\/8 -o $DEV -j ACCEPT\n-A ufw-before-output -d 172.16.0.0\/12 -o $DEV -j ACCEPT\n-A ufw-before-output -d 192.168.0.0\/16 -o $DEV -j ACCEPT\nCOMMIT/}" "$UFW_BEFORE" - echo "UFW обновлён (локальные сети)." -fi - - # --- Настройка UFW default deny + allow amn0 (однократно) --- ufw default deny outgoing >/dev/null 2>&1 || true ufw allow out on amn0 >/dev/null 2>&1 || true -if grep -qE "$UFW_MARKER|$UFW_LOCAL_MARKER" "$UFW_BEFORE" 2>/dev/null; then +if grep -qE "$UFW_IPSET_MARKER|$UFW_LOCAL_MARKER" "$UFW_BEFORE" 2>/dev/null; then if ufw status | grep -qE "активен|active"; then ufw reload fi fi +# --- Прямые правила iptables (гарантия работы даже при MANAGE_BUILTINS=no) --- +echo "Добавляем прямые правила iptables..." + +# Правило для ipset ru-direct (RU-IP + исключения kill switch) +iptables -C OUTPUT -m set --match-set "$SETNAME" dst -o "$DEV" -j ACCEPT 2>/dev/null || \ + iptables -I OUTPUT 1 -m set --match-set "$SETNAME" dst -o "$DEV" -j ACCEPT + +# Правила для локальных сетей (RFC1918) +for _net in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16; do + iptables -C OUTPUT -d "$_net" -o "$DEV" -j ACCEPT 2>/dev/null || \ + iptables -I OUTPUT 1 -d "$_net" -o "$DEV" -j ACCEPT +done + +echo "iptables: прямые правила добавлены." + echo "" echo "Готово." RU_EXAMPLE=$(dig +short ya.ru A 2>/dev/null | head -1)