Daily MaverickINSURANCE POLICY OUTRAGE: Murder for Money trial — testimony recounts loss, lies and a witness killingESPNKram: What the Wolves scandal tells us about the Clippers' future -- good and very badESPN DeportesMourinho sobre Messi: Tendremos que ver la MLSוואלהאחרי שלושה נרצחים אתמול: גבר נורה למוות בנצרתRTP DesportoJogos do Mediterrâneo. Portugal encerra participação histórica com 32 medalhasThe Jerusalem PostFake rabbi plants billboards across New York City advertising Christian proselytizing websiteIl Fatto QuotidianoDal 1 novembre scatta la tassa sui pacchi extra-Ue: ecco cosa cambia con la nuova agenzia delle doganeTechCrunchMeta is paying to peek at how you use their latest AI modelANSA SportF1: Briatore, 'in Formula 1 il pilota conta solo per il 20%'BBC NewsFifa accuses Uefa of 'smear campaign' against Infantinokicker"Viele werden das nicht verstehen": Weltmeister Marcos Llorente tritt aus der Nationalelf zurückConsequenceThe Hives Announce New Live EP Recorded in Mexico, Share Performance with Molotov’s Miky Huidobro
The Daily Newsstand · Free, Always
Thursday, September 3, 2026

Анонимная среда для работы в интернете на Tor под Shadowsocks

Translate

Есть два стандартных варианта, и оба ломаются об одно и то же.

Tor Browser: списки выходных узлов публичные и лежат в открытом доступе. Cloudflare встречает капчей, часть сервисов отвечает Access denied, что-то просто рвёт сессию. Анонимность есть, интернета нет.

VPN или Shadowsocks: работает всё, но доверие вы просто переносите. Провайдер видит, что вы соединились с конкретным VPS. Оператор этого VPS видит ваш реальный адрес и весь ваш трафик. Один участник знает про вас всё сразу.

Мне нужна была среда, в которой картину целиком не видит никто: провайдер не знает, куда я хожу, сайт не знает, кто я, и при этом меня не блокируют как пользователя Tor. Поэтому создал irondome (может есть аналоги и лучше, но не нашел, если знаете, напишите в комментарии) CLI на bash, который собирает такую среду на Linux-машине и, что важнее, не даёт трафику из неё вылезти мимо цепочки.

Порядок звеньев решает

Обычная схема, которую советуют в каждом втором треде, VPN, а поверх него Tor. Здесь наоборот, и на этом держится всё остальное.

Shadowsocks → Tor. Провайдер видит соединение с VPS. Оператор VPS видит ваш реальный IP. Сайт видит Tor exit и блокирует.

Tor → Shadowsocks. Провайдер видит obfs4-мост, то есть шум без опознавательных знаков. Выходная нода Tor видит соединение с VPS, но не знает, кто вы. Оператор VPS видит Tor exit, а не вас. Сайт видит обычный адрес обычного хостера.

Ни одно звено не держит полную картину:

Кто смотрит

Что видит

Чего не видит

Провайдер, DPI

obfs4-соединение с неизвестным адресом

что это Tor, куда вы ходите, какие домены резолвите

Мост Tor

ваш IP

пункт назначения

Выходная нода Tor

соединение с VPS

кто вы

Оператор VPS

Tor exit, шифрованный поток

ваш IP

Сайт

адрес обычного хостера

что вы через Tor, и что вы это вы

Чтобы вас деанонимизировать по сети, нужно свести данные минимум двух независимых участников: провайдера и оператора VPS, либо входной и выходной точек Tor. Это не невозможно, но это принципиально другой порядок усилий, чем «посмотреть логи одного VPN-провайдера».

Цена двойная задержка, и она заметна. Интерактивная работа терпимая.

Цепочка целиком:

приложение
  → прозрачный маршрут iron0 (strict mode)
  → SOCKS5 127.0.0.1:1080   (shadowsocks-libev через torsocks)
  → Tor 127.0.0.1:9050      (obfs4-мосты)
  → Outline/Shadowsocks VPS
  → интернет

Прозрачный маршрут: sing-box вместо «настройте прокси в приложении»

Трафик заворачивается на уровне ядра. sing-box поднимает TUN-интерфейс iron0, а конфиг генерируется на старте в /run/iron-dome/sing-box.json:

{
  "inbounds": [{
    "type": "tun",
    "interface_name": "iron0",
    "address": ["172.19.0.1/30"],
    "mtu": 1200,
    "auto_route": true,
    "auto_redirect": true,
    "strict_route": true,
    "include_uid": [1000]
  }],
  "outbounds": [
    {"type": "socks", "tag": "outline-socks", "server": "127.0.0.1", "server_port": 1080}
  ],
  "route": {
    "final": "outline-socks",
    "rules": [
      {"action": "sniff"},
      {"type": "logical", "mode": "or",
       "rules": [{"protocol": "dns"}, {"port": 53}], "action": "hijack-dns"},
      {"network": "udp", "action": "reject"}
    ]
  }
}

Самая частая дыра в самодельных схемах DNS. Трафик идёт через туннель, а резолвинг доменов уходит напрямую к провайдеру. IP при этом не светится, зато у провайдера оседает полный список посещённых сайтов в хронологическом порядке; опознают по нему не хуже, чем по адресу. hijack-dns перехватывает всё, что летит на 53 порт, и отправляет DoH-запросом внутрь той же цепочки у DNS-сервера в конфиге стоит "detour": "outline-socks".

Строка {"network": "udp", "action": "reject"} выглядит грубо, и она грубая. UDP через SOCKS5 либо не ходит вовсе, либо ходит мимо туннеля, а второе недопустимо поэтому UDP отбрасывается целиком. Браузер после этого не умеет в QUIC и откатывается на TCP, часть сайтов открывается чуть медленнее.

include_uid задаёт границу анонимной среды: маршрутизируется не вся машина, а конкретный UID. Остальная система ходит в сеть как обычно обновления, ssh на рабочие хосты, что угодно. Смысл практический: рабочий ноутбук не превращается в машину, где всё тормозит, а анонимная среда живёт под отдельным пользователем. Опционально туда же добавляется UID 0.

strict_route: true закрывает приложения, которые сами выбирают интерфейс. Обойти TUN изнутри системы нельзя, даже намеренно.

MTU 1200 - параметр. Внутри двойного туннеля с обфускацией накладные расходы плавают, и на некоторых мостах приходится опускать ещё ниже. Симптом завышенного MTU коварный: соединение устанавливается, а крупные ответы молча не доходят.

Замок: три независимых механизма

Прозрачный маршрут это про то, как трафик ходит правильно. Замок про то, что будет, если он попробует иначе.

Сценарии, которые нужно закрыть: упал Tor, упал ss-local, приложение принудительно привязалось к физическому интерфейсу, sing-box не поднялся, кто-то выключил сервис.

Базовое правило для защищённого UID выглядит так:

# всё, что не loopback - отбросить
iptables -I OUTPUT 1 -m owner --uid-owner "$KUID" ! -o lo -j REJECT
# ...кроме того, что помечено маркой прозрачного маршрута
iptables -I OUTPUT 1 -m owner --uid-owner "$KUID" -m mark --mark 0x2023 -j ACCEPT
# ...но если помеченное лезет в физический интерфейс  тоже отбросить
iptables -I OUTPUT 1 -m owner --uid-owner "$KUID" -o "$DIRECT_IFACE" -m mark --mark 0x2023 -j REJECT

По умолчанию запрещено всё. Разрешается только то, что реально прошло через TUN. Третье правило закрывает обход через --interface: даже если пакет промаркирован, но уходит наружу через eth0, он отбрасывается.

Сверху policy routing, потому что iptables закрывает не все дыры:

ip -4 rule add priority 1000 uidrange "$KUID-$KUID" lookup 2022

Отдельная таблица маршрутизации для конкретного UID. Это закрывает случаи, когда пакет вообще не доходит до нужной цепочки OUTPUT.

Всё то же самое дублируется в ip6tables. IPv6 здесь не маршрутизируется, а отбрасывается по-моему, для такой задачи так и правильно: тянуть вторую полноценную цепочку ради IPv6 дороже, чем его закрыть.

У процесса ss-local собственный системный пользователь, и ему разрешён один-единственный адрес.

iptables -I OUTPUT 1 -m owner --uid-owner "$CUID" ! -o lo -j REJECT
iptables -I OUTPUT 1 -m owner --uid-owner "$CUID" \
  -d "$OUTLINE_IP" -p tcp --dport "$OUTLINE_PORT" -j ACCEPT

То есть shadowsocks-клиент физически не может соединиться ни с чем, кроме своего VPS. Если он вдруг решит сходить куда-то ещё не сходит.

Что происходит, когда что-то падает

Это главный вопрос к любой такой схеме, и ответ на него важнее, чем то, как она работает в исправном состоянии. Мосты перестают отвечать. Бесплатные ключи Outline умирают регулярно. После обновления пакетов сервис может не подняться.

Замок вешается до старта цепочки, а не после.

[IRON DOME] applying lock before starting the chain
[IRON DOME] starting Tor with bridges
[IRON DOME] waiting for Tor .......... OK
[IRON DOME] starting Outline over Tor
[IRON DOME] waiting for 1080 ..... OK
[IRON DOME] starting transparent route

Это работает, потому что таблица 2022 пуста, пока её не наполнит sing-box. Ранний замок означает не «маршрут не тот», а «маршрута нет вообще». Пока цепочка поднимается, защищённый пользователь никуда не ходит; если она не поднялась он так и остаётся без сети:

[IRON DOME] Tor did not bootstrap; check your bridges with: sudo tor-bridges
[IRON DOME] the lock stays applied: protected traffic is blocked, not leaking.
[IRON DOME] run 'sudo iron-dome-stop' to restore normal networking.

Обратная сторона: неудачный старт при загрузке оставляет вас без интернета до ручного iron-dome-stop. Если вам это не подходит есть iron-dome-open, тот же стек без замка.

Ожидание Tor до 90 попыток по 2 секунды. Мосты бывают медленные, и три минуты на bootstrap это норма, а не повод считать, что всё сломалось.

В конце старт пытается пробить собственную защиту:

ip route get 1.1.1.1 uid "$CHECK_UID" | grep -q "dev iron0" &&
curl -s https://1.1.1.1 >/dev/null &&
! curl -s --interface "$direct_if" --max-time 3 https://ifconfig.me >/dev/null

Маршрут защищённого пользователя идёт через iron0, обычный запрос проходит, а запрос, принудительно привязанный к физическому интерфейсу, не проходит. Последнее условие и есть настоящий тест на утечку.

Проверка на живой машине

Одно дело написать «fail-closed», другое показать. В виртуалке strict mode активен:

Проверка

Результат

curl https://api.ipify.org

193.29.139.xxx адрес Outline

через SOCKS 127.0.0.1:1080

193.29.139.xxx совпадает

через privoxy 127.0.0.1:8119

193.29.139.xxx совпадает

через Tor 127.0.0.1:9050

{"IsTor":true,"IP":"45.84.107.xxx"}

curl --interface eth0

exit 7 прямой выход закрыт

curl -6 https://api64.ipify.org

exit 6 IPv6 закрыт

ping 1.1.1.1

нет ответа

UDP на 1.1.1.1:53

timeout

ip route get 1.1.1.1 uid 1000

via 172.19.0.2 dev iron0 table 2022

Обычный curl на check.torproject.org отвечает IsTor:false и это правильно. Последний хоп цепочки не Tor exit, а VPS, поэтому сайты и не блокируют вас как пользователя Tor.

iron-dome-stop снимает правила, и машина возвращается в обычное состояние: ip rule и iptables чистые, прямой выход открыт.

Как этим пользоваться

Нужен Linux с systemd.

sudo apt install -y tor obfs4proxy torsocks shadowsocks-libev privoxy socat sing-box curl python3
git clone https://github.com/madnessbrainsbl/irondome.git
cd irondome && chmod +x bin/irondome lib/*.sh

Всё генерируется из состояния в state/, поэтому ручных правок конфигов в системе нет вообще.

./bin/irondome setup     # мастер: пользователь, префикс, мосты, ss:// ключ
./bin/irondome render    # конфиги и юниты из шаблонов в generated/
sudo ./bin/irondome install
sudo iron-dome-start
./bin/irondome doctor

install раскладывает по системе набор хелперов, и дальше вы живёте уже ими, а не CLI из папки проекта. Это то, что реально набирается каждый день:

sudo iron-dome-start          # строгий режим: цепочка + замок
sudo iron-dome-stop           # разобрать всё, вернуть обычную сеть
sudo iron-dome-open           # то же, что start, но без замка
sudo ss-key 'ss://...'        # заменить ключ Outline на живой системе
sudo tor-bridges 'obfs4 ...'  # заменить мосты на живой системе
iron-windows-proxy status     # слушатель для браузера на хосте

install заодно включает iron-dome-boot.service, так что после перезагрузки щит поднимается сам. Ровно та же последовательность, что и вручную: замок, потом цепочка. Если мосты за ночь умерли, машина встанет без сети, а не с открытым выходом.

Два режима работы. iron-dome-open поднимает цепочку, но не вешает замок им удобно диагностировать и проходить логины, которые в строгом режиме упираются в капчу. iron-dome-start строгий режим с fail-closed. iron-dome-stop разбирает и то и другое: гасит юниты, снимает правила iptables и ip6tables, убирает policy-routing, возвращая машину в обычное состояние.

Отдельно про ss-key это самая частая операция после первой настройки, потому что бесплатные ключи Outline протухают. Хелпер разбирает ss://, переписывает конфиг, перезапускает сервис, проверяет, что 1080 ожил, и печатает GeoIP с ASN нового выхода. Если 1080 не поднялся откатывается на прежний ключ:

sudo ss-key 'ss://YWVzLTI1Ni1nY206cGFzcw==@server:8388'

Ключ можно не передавать аргументом тогда он спросит его с ввода, что удобнее, если не хочется светить ключ в истории шелла. Права на себя хелпер поднимает сам, так что sudo можно и опустить.

Второй по частоте случай мосты. Публичные obfs4-мосты живут недолго, и когда текущий перестаёт отвечать, менять его надо на работающей машине, а не через полный цикл renderinstall:

sudo tor-bridges 'obfs4 198.51.100.7:9443 <FINGERPRINT> cert=<CERT> iat-mode=0'

Без аргумента он спросит список с ввода: по строке на мост, пустая строка заканчивает ввод. Дальше он переписывает блок UseBridges / ClientTransportPlugin / Bridge в установленном torrc.strict, перезапускает Tor и ждёт bootstrap, проверяя check.torproject.org через 9050.

Тонкость, которая стоила мне отдельной итерации: после рестарта Tor надо перезапускать и ss-local. Он ходит к своему VPS через torsocks, то есть поверх Tor, и при обрыве нижнего слоя просто зависает с мёртвым сокетом. Поэтому хелпер после успешного bootstrap перезапускает iron-ss-outline.service и проверяет, что 1080 действительно ожил. Если не ожил или мосты не поднялись откат на прежний список.

ClientTransportPlugin генерируется по транспорту: obfs4 и snowflake подставляются сами, всё остальное принимается с предупреждением и требует ручной строчки.

Новый список пишется ещё и обратно в state/bridges.txt иначе следующий render молча накатил бы поверх старые мосты. Такие рассинхроны между «живой системой» и «состоянием проекта» самый неприятный класс багов в подобных инструментах, потому что ломается не сразу, а через месяц.

Состояние и диагностика:

./bin/irondome status         # что настроено и что отрендерено
./bin/irondome doctor         # живая проверка цепочки
=== SERVICES ===
iron-tor.service         active
iron-ss-outline.service  active
iron-transparent.service active
iron-dome-lock.service   active

=== ENDPOINTS ===
TOR 9050: OK
OUTLINE 1080: OK
PRIVOXY 8119: OK

Если doctor показывает TOR 9050: OK, но OUTLINE 1080: FAILED почти всегда умер ключ, лечится sudo ss-key. Если оба OK, а трафик не идёт смотреть замок:

systemctl status iron-dome-lock.service --no-pager
journalctl -u iron-dome-lock.service --no-pager -n 80

И проверка руками, которая говорит больше, чем весь doctor:

curl --socks5-hostname 127.0.0.1:1080 https://api.ipify.org   # адрес VPS
curl -6 https://api64.ipify.org                                # должно упасть

Первая команда показывает адрес, который видят сайты. Вторая обязана не отработать: если IPv6 отвечает, значит замок закрыт не полностью.

Перед тем как трогать живую систему, можно раскатать всё в песочницу install умеет ставить в произвольный корень:

./bin/irondome install --root /tmp/irondome-test

Ничего в /usr/local, /etc/systemd/system и /opt при этом не попадает, а посмотреть на итоговый набор файлов и юнитов можно заранее. Этой же ручкой пользуется смоук-тест, который гоняет полный цикл без root и без сети.

Браузер на хостовой машине

Если Linux с цепочкой живёт в виртуалке, а браузер на хостовой Windows, локальный HTTP-прокси пробрасывается наружу:

Windows browser → VM:18119 → privoxy 127.0.0.1:8119 → 1080 → Tor → VPS

Слушатель ограничен доверенной сетью через socat ... range=192.168.98.0/24, но аутентификации там нет это фильтр по адресу источника, не более. Host-only сеть виртуалки годится, публичный вайфай категорически нет.

Отдельно есть опциональная обвязка для конкретных приложений: например, Electron-клиенты, которым нужен свой выходной адрес, а не общий. Это вынесено в интеграции и по умолчанию выключено ядро про них ничего не знает.

Чего это не даёт

Не защищает от отпечатка браузера. Маршрут закрыт: браузер защищённого пользователя физически не может выйти мимо цепочки, это и есть смысл замка. Но сайт узнаёт вас не только по IP. navigator.userAgent, разрешение экрана, список шрифтов, canvas- и WebGL-хеши, Date.getTimezoneOffset() едут внутри HTTPS-сессии, и маршрутизация на них не влияет вообще.

Особенно выдаёт часовой пояс: выход в Нидерландах, а система рапортует московское время комбинация редкая, профиль по ней сужается резко. Tor Browser поэтому подгоняет всех пользователей под один общий отпечаток, врёт про пояс, шрифты и размер окна. Обычный Firefox через прокси остаётся собой.

Одну классическую утечку схема всё же закрывает: WebRTC выясняет публичный адрес через STUN по UDP, а UDP здесь отбрасывается целиком. Не потому, что так задумывалось против WebRTC, просто побочный эффект правила, закрывающего QUIC.

Логин перечёркивает всё. Зашли в аккаунт деанонимизировались полностью, и никакая цепочка этого не отменяет.

Против глобальной корреляции бессильно. Тот, кто видит и ваш аплинк, и аплинк VPS, сопоставит их по таймингам и объёму. Два хопа тут не помогают, и никакая схема на этом уровне не поможет.

Сам VPS остаётся доверенным звеном. Он не видит вашего IP, но видит весь трафик и его паттерн. Выходной адрес стабилен, поэтому все сессии с одного ключа связываются между собой даже если ни одна не связывается с вами.

Всё, что ушло до старта, ушло напрямую. DHCP, NTP, автообновления, успевшие отработать до iron-dome-start, прошли мимо цепочки.

Ваш собственный пользователь тоже угроза. install кладёт /etc/sudoers.d/iron-dome с беспарольным root на четыре команды, чтобы не вводить пароль по десять раз в день. Плата за это: любой процесс, работающий от вашего пользователя, может выполнить sudo ss-key 'ss://...' и молча увести весь трафик на чужой сервер без запроса пароля и без заметного следа. Не устраивает удалите строки NOPASSWD:, всё продолжит работать, sudo просто будет спрашивать пароль.

Мнение, с которым можно спорить: если нужна серьёзная анонимность ставьте Whonix или Tails, а не собирайте это из скриптов. Whonix изолирует утечки архитектурно, на уровне отдельной сетевой ВМ, а здесь всё держится на правилах iptables, привязанных к UID, сложнее и хрупче. Смысл в моей схеме появляется в узком случае: когда нужен выходной адрес, не связанный ни с вами, ни с Tor, и нужен он для повседневной работы, а не для противостояния государственному уровню угрозы. Если задача другая почти наверняка есть решение лучше.

Статус

Репозиторий

Если будете поднимать у себя начните с sudo iron-dome-open и doctor, и только потом включайте строгий режим. И проверьте замок сами, теми же четырьмя командами из таблицы выше. Замок, который вы не проверили, хуже отсутствующего: он создаёт ощущение защиты, которого нет.

View the original on Хабр

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.