fix: kill switch — UFW before.rules с актуальным DEV, прямые iptables, /etc/hosts для *.eltex.loc и elph
Три корневые проблемы и их исправления: 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 <noreply@anthropic.com>
This commit is contained in:
@@ -35,6 +35,17 @@ LOCAL_DNS="${LOCAL_DNS:-}"
|
|||||||
AMNEZIA_SERVER="${AMNEZIA_SERVER:-}"
|
AMNEZIA_SERVER="${AMNEZIA_SERVER:-}"
|
||||||
KILL_SWITCH_EXCEPTIONS="${KILL_SWITCH_EXCEPTIONS:-}"
|
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)
|
# Сохраняем конфиг для будущих запусков (systemd, NM dispatcher)
|
||||||
cat > /etc/ru-bypass.conf <<_CONF
|
cat > /etc/ru-bypass.conf <<_CONF
|
||||||
GATEWAY="$GATEWAY"
|
GATEWAY="$GATEWAY"
|
||||||
@@ -146,6 +157,33 @@ EOF
|
|||||||
echo "NetworkManager dispatcher установлен."
|
echo "NetworkManager dispatcher установлен."
|
||||||
fi
|
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ч) ---
|
# --- Обновляем RIPE-список (кэш 24ч) ---
|
||||||
|
|
||||||
if [ ! -f "$CACHE" ] || [ $(( $(date +%s) - $(stat -c %Y "$CACHE" 2>/dev/null || echo 0) )) -gt 86400 ]; then
|
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
|
if echo "$item" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$"; then
|
||||||
ips="$item"
|
ips="$item"
|
||||||
else
|
else
|
||||||
ips=$(dig +short "$item" A 2>/dev/null)
|
ips=$(getent hosts "$item" 2>/dev/null | awk '{print $1}' | sort -u)
|
||||||
fi
|
fi
|
||||||
for ip in $ips; do
|
for ip in $ips; do
|
||||||
ipset add ru-direct "$ip" -exist 2>/dev/null || true
|
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
|
if echo "$item" | grep -qE "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$"; then
|
||||||
ips="$item"
|
ips="$item"
|
||||||
else
|
else
|
||||||
ips=$(dig +short "$item" A 2>/dev/null)
|
ips=$(getent hosts "$item" 2>/dev/null | awk '{print $1}' | sort -u)
|
||||||
fi
|
fi
|
||||||
for ip in $ips; do
|
for ip in $ips; do
|
||||||
ip route replace "$ip/32" via "$GATEWAY" dev "$DEV" 2>/dev/null
|
ip route replace "$ip/32" via "$GATEWAY" dev "$DEV" 2>/dev/null
|
||||||
@@ -279,34 +317,60 @@ if [ -n "$LOCAL_DNS" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Правило в UFW before.rules (однократно, после создания ipset) ---
|
# --- Правила в UFW before.rules (обновляются при каждом запуске) ---
|
||||||
|
# Маркеры используются для идентификации правил; DEV всегда актуальный.
|
||||||
|
|
||||||
UFW_MARKER="match-set $SETNAME"
|
UFW_IPSET_MARKER="ru-bypass: ipset $SETNAME"
|
||||||
if ! grep -q "$UFW_MARKER" "$UFW_BEFORE" 2>/dev/null; then
|
UFW_LOCAL_MARKER="ru-bypass: local-nets-bypass"
|
||||||
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 before.rules..."
|
||||||
echo "UFW обновлён (.ru ipset)."
|
|
||||||
|
# Удаляем старые правила (если есть) — и в новом, и в старом формате маркеров
|
||||||
|
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
|
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 + allow amn0 (однократно) ---
|
||||||
ufw default deny outgoing >/dev/null 2>&1 || true
|
ufw default deny outgoing >/dev/null 2>&1 || true
|
||||||
ufw allow out on amn0 >/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
|
if ufw status | grep -qE "активен|active"; then
|
||||||
ufw reload
|
ufw reload
|
||||||
fi
|
fi
|
||||||
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 ""
|
||||||
echo "Готово."
|
echo "Готово."
|
||||||
RU_EXAMPLE=$(dig +short ya.ru A 2>/dev/null | head -1)
|
RU_EXAMPLE=$(dig +short ya.ru A 2>/dev/null | head -1)
|
||||||
|
|||||||
Reference in New Issue
Block a user