@@ -1,203 +0,0 @@
#!/bin/bash
# ru-bypass.sh — .ru трафик напрямую мимо Amnezia, всё остальное через VPN + kill switch
#
# Принцип: ipset + более специфичные маршруты имеют приоритет над amn0.
# Kill switch (UFW) остаётся активным — не-.ru трафик при отвале Amnezia блокируется.
#
# Первый запуск устанавливает ipset, два systemd сервиса и NetworkManager dispatcher:
# - ru-ipset-restore.service запускается ДО UFW, восстанавливает ipset из файла
# - ru-bypass.service запускается после network-online, обновляет RIPE-список и маршруты
# Каждый запуск обновляет список .ru IP-блоков из RIPE (кэш 24ч).
#
# Использование: sudo bash ru-bypass.sh
GATEWAY = " ${ GATEWAY :- 192 .168.1.1 } "
DEV = " ${ DEV :- wlp1s0 } "
SETNAME = "ru-direct"
CACHE = "/var/cache/ru-delegations.txt"
IPSET_SAVE = "/etc/ipset.conf"
RIPE_URL = "https://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-latest"
SCRIPT_DEST = "/usr/local/bin/ru-bypass.sh"
UFW_BEFORE = "/etc/ufw/before.rules"
if [ " $( id -u) " != "0" ] ; then
echo " Запускай от root: sudo bash $0 "
exit 1
fi
# --- Первичная настройка (однократно) ---
if ! command -v ipset >/dev/null 2>& 1; then
echo "Устанавливаем ipset..."
apt-get install -y ipset
fi
# Копируем скрипт в /usr/local/bin (нужно для systemd + NM dispatcher)
SELF = $( realpath " $0 " )
if [ " $SELF " != " $SCRIPT_DEST " ] ; then
cp " $SELF " " $SCRIPT_DEST "
chmod +x " $SCRIPT_DEST "
echo " Скрипт скопирован в $SCRIPT_DEST "
fi
# Сервис восстановления ipset ДО старта UFW (однократно)
RESTORE_SVC = "/etc/systemd/system/ru-ipset-restore.service"
if [ ! -f " $RESTORE_SVC " ] ; then
cat > " $RESTORE_SVC " <<EOF
[Unit]
Description=Restore ru-direct ipset before UFW starts
DefaultDependencies=no
Before=ufw.service network.target
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/sbin/ipset restore -exist -file $IPSET_SAVE
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable ru-ipset-restore.service
echo "Сервис ru-ipset-restore установлен (стартует до UFW)."
fi
# Основной сервис обновления маршрутов (однократно)
BYPASS_SVC = "/etc/systemd/system/ru-bypass.service"
if [ ! -f " $BYPASS_SVC " ] ; then
cat > " $BYPASS_SVC " <<'EOF'
[Unit]
Description=Route .ru IP blocks directly (bypass Amnezia VPN)
After=network-online.target ru-ipset-restore.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/ru-bypass.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable ru-bypass.service
echo "Сервис ru-bypass установлен."
fi
# NetworkManager dispatcher — авто-перезапуск когда amn0 поднимается (однократно)
NM_DISPATCHER = "/etc/NetworkManager/dispatcher.d/99-ru-bypass"
if [ ! -f " $NM_DISPATCHER " ] ; then
cat > " $NM_DISPATCHER " <<'EOF'
#!/bin/bash
[ "$1" = "amn0" ] && [ "$2" = "up" ] && exec /usr/local/bin/ru-bypass.sh
EOF
chmod +x " $NM_DISPATCHER "
echo "NetworkManager dispatcher установлен."
fi
# --- Обновляем RIPE-список (кэш 24ч) ---
if [ ! -f " $CACHE " ] || [ $(( $( date +%s) - $( stat -c %Y " $CACHE " 2>/dev/null || echo 0) )) -gt 86400 ] ; then
echo "Обновляем список .ru IP-блоков из RIPE..."
if curl -fsS -o " $CACHE .tmp " " $RIPE_URL " ; then
mv " $CACHE .tmp " " $CACHE "
else
echo "Предупреждение: не удалось скачать RIPE-список"
if [ ! -f " $CACHE " ] ; then exit 1; fi
echo " Используем старый кэш от $( date -r " $CACHE " ) "
fi
fi
# --- Создаём/обновляем ipset ---
echo " Обновляем ipset $SETNAME ... "
# create -exist: не падает если уже есть (UFW на него ссылается, destroy ломает цепочку)
ipset create " $SETNAME " hash:net -exist
# flush: очищаем записи, но сохраняем сам set (iptables-правило остаётся валидным)
ipset flush " $SETNAME "
python3 -c "
import ipaddress
entries = 0
with open(' $CACHE ') as f_in:
for line in f_in:
parts = line.strip().split('|')
if len(parts) < 5 or parts[1] != 'RU' or parts[2] != 'ipv4':
continue
ip_str, count = parts[3], int(parts[4])
first = ipaddress.IPv4Address(ip_str)
last = first + count - 1
for net in ipaddress.summarize_address_range(first, last):
print(f'add $SETNAME {net}')
entries += 1
import sys; print(f'# entries: {entries}', file=sys.stderr)
" 2>/tmp/ru-ipset-count.txt | ipset restore -exist -quiet
ENTRIES = $( ipset list " $SETNAME " 2>/dev/null | grep -c '/' )
echo " ipset обновлён: $ENTRIES записей "
# Сохраняем ipset на диск — ru-ipset-restore.service восстановит е г о до UFW при перезагрузке
ipset save " $SETNAME " > " $IPSET_SAVE "
echo " ipset сохранён в $IPSET_SAVE "
# --- Добавляем маршруты ---
echo "Добавляем маршруты..."
rm -f /tmp/ru-routes.batch
python3 -c "
import ipaddress
with open(' $CACHE ') as f, open('/tmp/ru-routes.batch', 'w') as out:
count = 0
for line in f:
parts = line.strip().split('|')
if len(parts) < 5 or parts[1] != 'RU' or parts[2] != 'ipv4':
continue
ip_str, n = parts[3], int(parts[4])
first = ipaddress.IPv4Address(ip_str)
last = first + n - 1
for net in ipaddress.summarize_address_range(first, last):
out.write(f'route replace {net} via $GATEWAY dev $DEV \n')
count += 1
print(f'Маршрутов: {count}')
"
ip -force -batch /tmp/ru-routes.batch 2>/dev/null
# --- Маршруты для локальных сетей (*.loc, RFC1918) ---
LOCAL_NETS = "10.0.0.0/8 172.16.0.0/12 192.168.0.0/16"
echo "Добавляем маршруты для локальных сетей (*.loc / RFC1918)..."
for net in $LOCAL_NETS ; do
ip route replace " $net " via " $GATEWAY " dev " $DEV " 2>/dev/null
done
# --- Правило в UFW before.rules (однократно, после создания ipset) ---
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)."
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
if grep -qE " $UFW_MARKER | $UFW_LOCAL_MARKER " " $UFW_BEFORE " 2>/dev/null; then
if ufw status | grep -qE "активен|active" ; then
ufw reload
fi
fi
echo ""
echo "Готово."
RU_EXAMPLE = $( dig +short ya.ru A 2>/dev/null | head -1)
echo " ip route get 8.8.8.8 -> dev amn0 (через VPN)"
echo " ip route get ${ RU_EXAMPLE :- <ya.ru ip> } -> dev $DEV (напрямую .ru) "
echo " ip route get 10.10.0.1 -> dev $DEV (напрямую *.loc / RFC1918) "