Transmission в Linux: ограничить исходящий трафик по владельцу процесса
Пир-порт — не вся история. Привяжите правило брандмауэра к учётной записи клиента, охватите оба семейства адресов и проверьте при упавшем туннеле.
Блокировка входящего порта Transmission — это не политика VPN. Торрент-клиент открывает исходящие соединения к пирам и трекерам, разрешает имена и может держать слушатель удалённого управления, и каждый из этих потоков способен выйти через интерфейс, который вы не планировали. Пройдите пять проверок по порядку и считайте границей правило брандмауэра, а не настройки клиента. Последние две проверки обычно пропускают, и именно они определяют, сохраняется ли гарантия, когда туннель падает.
Назовите процесс, которому принадлежит передача
Настольное приложение и системный демон работают под разными учётными записями, а правило по владельцу следует за учётной записью, а не за именем программы. Выясните, какой из них запущен, прежде чем писать правило. Отдельная служебная учётная запись даёт политике точный субъект, тогда как настольный пользователь делит свою личность с браузерами, редакторами и всем остальным в сеансе. Подтвердите UID, а не предполагайте, что имя учётной записи из пакета и есть используемое.
systemctl status transmission-daemon
ps -o user=,pid=,cmd= -C transmission-daemon
Если учётной записи ещё нет, создайте её для этой цели и не давайте ей ничего другого запускать. Запишите учётную запись и UID в комментарий к правилу, потому что правило без субъекта — это правило, которое никто не сможет безопасно изменить.
Отделите поля прослушивания от маршрута
Transmission 4.x документирует адреса прослушивания пиров отдельно от rpc-bind-address, и эта разница важна. Настройка RPC управляет только слушателем удалённого управления, поэтому её изменение не выбирает маршрут для пирового трафика. Чтение двух настроек как одной — самая частая причина, по которой аккуратная на вид конфигурация всё равно течёт. Та же документация описывает запасной вариант, когда адрес прослушивания пиров недействителен, то есть недоступный адрес — это задокументированный запасной случай, а не гарантированный отказ.
grep -E '"(peer-port|rpc-bind-address|bind-address-ipv4)"' /var/lib/transmission-daemon/.config/transmission-daemon/settings.json
Используйте средства клиента по их назначению, а гарантию помещайте в брандмауэр. Настройка прослушивания всё ещё может быть полезной, но она не доказывает, что связь с трекерами, локальное обнаружение или делегированный запрос выходят через туннель. Когда эти две вещи расходятся, решает брандмауэр.
Запишите совпадение по владельцу в нужную цепочку
Руководство Netfilter по совпадению владельца объясняет, как локально созданные пакеты приписываются пользователю или группе, владеющим файлом сокета. Это приписывание не распространяется на пересылаемый трафик, а сопоставление дополнительных групп требует явной опции. Читайте руководство для того расширения, которое действительно используете, а не первый найденный пример.
iptables -A OUTPUT -m owner --uid-owner transmission -o tun0 -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner transmission -j REJECT
ip6tables -A OUTPUT -m owner --uid-owner transmission -o tun0 -j ACCEPT
ip6tables -A OUTPUT -m owner --uid-owner transmission -j REJECT
Порядок важен не меньше совпадения. Широкое разрешение выше в цепочке сводит на нет точный запрет ниже, поэтому просмотрите всю цепочку, а не добавляйте правило в надежде. Включите оба семейства адресов, если хост работает с IPv6, потому что политика только для v4 оставляет открытым путь, за которым никто не следит. Сохраняйте правила при перезапусках и клиента, и туннеля.
Решите, что произойдёт, когда tun0 исчезнет
Политика отказа — суть упражнения. Если туннель исчезнет и тот же хук удалит правила, клиент сможет использовать физический интерфейс, пока что-нибудь его не остановит. Безопасный дизайн сохраняет правила и позволяет им отклонять, и именно это делает границу независимой от состояния туннеля. Хук демонтажа, который заодно удаляет правила, — полная противоположность политике отказа.
ip link show tun0
iptables -S OUTPUT
Проверьте это намеренно: остановите туннель, запустите передачу, которую не страшно прервать, и посмотрите, не уходит ли что-нибудь наружу. Затем верните туннель и убедитесь, что нужный путь снова работает.
Охватите пути, которых правило не видит
Разрешением имён может заниматься отдельный процесс-резолвер, а пространство имён или выделенный шлюз способны дать ещё одну границу, если их пути совместного использования и загрузки это предусматривают. Решите, какой компонент отвечает за DNS и следует ли он тому же правилу выхода. Затем посмотрите на RPC: если используется rpc-whitelist, то одобренная сеть управления входит в договор, а широкий диапазон RFC1918 — нет.
ss -tunp | grep -i transmission
Счётчики интерфейса могут подтвердить наблюдение, но не могут доказать, какой процесс породил байты. Проведите передачу, которую разрешено прервать: сначала по рабочему пути, затем без туннеля при запуске, затем через прерывание, переподключение и только что созданный интерфейс. Проверьте и новую попытку, и уже открытое соединение, потому что правило могло не примениться к старому сокету. Запишите дату, учётную запись и результат вместе с проверкой.
Вставлять пример, который очищает всю цепочку, — значит менять одну дыру на несколько, поэтому добавляйте правила, а не удаляйте их. Когда все пять проверок пройдены, гарантия явная: трафик клиента уходит через туннель или никуда, и правило, которое это обеспечивает, переживает собственный сбой туннеля.