Vpn не для всех туннелируем трафик отдельных приложений с помощью linux network namespaces

Обновлено: 06.07.2024

Как-то одним прекрасным утром я рассказывал в телеграмме бывшему другу и коллеге о том, что такое network namespaces в Linux и с чем его едят. Коллега восхитился, так же, как я, в свое время, а мне пришла в голову, что надо не костылить скриптом, как я делал до этого, а автоматизировать запуск отдельного network namespace и OpenVPN в нем. Так как я использую Debian Sid и Ubuntu 16.04 LTS автоматизацию я себе сделал в виде юнитов systemd, но об этом в конце статьи. После того, как я рассказал еще одному человеку, на этот раз далекому от IT, о возможности запускать только одно приложение, например браузер, под VPN, а остальные, как и прежде, он сказал «Только ради этого стоит перейти на Linux на компе», а я решил написать статью-инструкцию, как это сделать.

О том, что такое network namespaces в Linux написано много, но для тех кто не знает я кратко процитирую попавшееся под руку описание на русском языке:

А теперь перейдем к теме нашей статьи.

Скрипт, для ручного поднятия network namespace и запуска в нем OpenVPN с комментированием

Выполнив этот скрипт мы можем при помощи команды:

Убедиться, что внутри netns у нас поднят OpenVPN и в сеть внутри netns мы выходим через наш OpenVPN. Теперь командой:

мы можем запустить браузер и получить браузер работающий через VPN, в то время, как вся остальная система у нас работает, как прежде и все остальное ходить напрямую(в команде замените USER_NAME на имя вашего пользователя). Пример запуска браузера приведен исходя из того, что на своем десктопе пользователь имеет sudo. Если кто-то может подсказать, как использовать ip netns exec без sudo буду признателен.

Аналогично браузеру вы можете запускать IM-клиенты, торрент-клиенты и все остальное. В случае, если firefox ругается при запуске, что не может подключиться к dbus поставьте в команде его запуска dbus-launch перед sudo.

Скрипт для остановки нашего netns:

Юниты для systemd поднимающие все указанное на автомате при загрузке. Юнит для netns:

Юнит для OpenVPN:

И файл с переменными в котором я задаю адрес ВПН-сервера и сети используемой netns:

Скопировав файлы для systemd в их места на файловой системе командой

$ sudo systemctl enable openvpn-ns@NAME.service

где NAME все то же имя вашего конфиг-файла OpenVPN. После этого можно запускать

$ sudo systemctl start openvpn-ns@NAME.service

OpenVPN запуститься в выделенном network namespace по имени vpn.

вы сможете проверить, что внутри netns теперь есть VPN и вы ходите с адреса своего сервера.

» Юниты systemd на github.

При подготовке статьи мне помогли две ссылки:

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

P.S. Запуск VPN в выделенном network namespace может использоваться не только, как обход цензуры, но и для рабочих целей, я после того, как сделал юнит для OpenVPN сделал себе еще аналогичный поднимающий VPN до сети клиента, что бы можно было запускать с доступом к его сети только отдельные приложения.

VPN не для всех. Туннелируем трафик отдельных приложений с помощью Linux network namespaces

Немного о Linux namespaces

В Linux реализована функция пространства имен (namespace), которая отвечает за изоляцию разных ресурсов системы. Она вовсю применяется в проектах контейнеризации, например таких как Docker. Существует несколько типов пространств имен: pid, net, mnt, user, uts, ipc.

Нас интересует пространство имен для сетей (netns), которое изолирует сетевые ресурсы. Для каждого netns можно назначать: свои интерфейсы, наборы IP-адресов и портов (сокеты), таблицы маршрутизации, правила файрвола и так далее. Есть возможность перемещать интерфейсы из одного netns в другой. Физический интерфейс (например, eth0) может находиться одновременно только в одном netns.

Изначально все интерфейсы и процессы содержатся в исходном (initial) netns, у него нет конкретного имени, и он не отображается в списке. После освобождения какого-либо netns все физические интерфейсы, которые были в нем, возвращаются в initial netns. Освобождение происходит после завершения последнего процесса в этом netns. Например, даже если удалить конкретный netns, но процесс, запущенный в нем, будет активным, физический интерфейс не перенесется обратно в исходный netns до тех пор, пока процесс не будет завершен. Рассмотрим этот вариант позже.

Введение в курс

Именно netns поможет нам в туннелировании трафика отдельных приложений. Для начала нужно немного разобраться в командах управления.

База netns

За контроль netns отвечает утилита ip из пакета iproute2. Для соединения netns между собой можно использовать пару виртуальных интерфейсов veth. Рассмотрим пример создания нескольких netns и их соединения. Для этого выполним

$ sudo ip netns add ns_1 $ sudo ip netns add ns_2

Управление netns и veth с помощью ip

$ sudo ip add dev virt01 type veth peer name virt02 Управление netns и veth с помощью ip

$ sudo ip set virt01 netns ns_1 $ sudo ip set virt02 netns ns_2

$ sudo ip netns exec <имя netns> <команда для выполнения>

Например, посмотреть список доступных интерфейсов внутри netns ns_1 можно при помощи

$ sudo ip netns exec ns_1 ip

Почитав man, узнаем, что выполнять команды ip внутри netns можно при помощи $ sudo ip -n <имя netns>, а значит, $ sudo ip netns exec ns_1 ip заменяем на $ sudo ip -n ns_1 .

Удостоверимся, что интерфейсы перенеслись в нужные netns

Удостоверимся, что интерфейсы перенеслись в нужные netns

По умолчанию интерфейсы, созданные или перемещенные в netns, пребывают в отключенном состоянии, даже lo.

Добавим нашим интерфейсам virt01 и virt02 по IP-адресу и переведем их в состояние UP. Для этого воспользуемся «прокачанной» командой, подсмотренной в man:

Соединяем вместе нашу виртуальную пару

$ sudo ip -n ns_1 addr add 10.0.0.1/24 dev virt01 $ sudo ip -n ns_2 addr add 10.0.0.2/24 dev virt02 $ sudo ip -n ns_1 set dev virt01 up $ sudo ip -n ns_2 set dev virt02 up $ sudo ip -n ns_1 addr show $ sudo ip -n ns_2 addr show Соединяем вместе нашу виртуальную пару

Как я уже говорил, у каждой netns своя таблица маршрутизации, проверим это.

Действительно, таблицы отличаются

Действительно, таблицы отличаются

Для проверки связи между ns_1 и ns_2 воспользуемся командой ping.

Соединение установлено успешно

$ sudo ip netns exec ns_1 ping -c 4 10.0.0.2 Соединение установлено успешно

Как ты помнишь, адрес 10.0.0.2 принадлежит интерфейсу virt02, который находится в ns_2. Похожим способом netns соединяют с физическим eth0.

Выполнение команд и запуск процессов внутри netns

Как ты помнишь, команды внутри netns выполняются при помощи

$ sudo ip netns exec <имя netns> <команда>

Чтобы не писать все это каждый раз, запустим bash!

$ sudo ip netns exec ns_1 bash

Список правил пуст

Список правил пуст

У меня всегда присутствуют правила в файрволе, так что это точно отдельный набор. .

Перейдем к примеру с возвращением физического интерфейса в initial netns. Для этого проверим текущее расположение enp0s3 и перенесем его в ns_2.

Как видно, enp0s3 больше нет в init netns

$ sudo ip set dev enp0s3 netns ns_2 Как видно, enp0s3 больше нет в init netns

Поднимем его в netns ns_2 и запустим WireShark от имени пользователя (eakj) там же.

WireShark запущен в netns ns_2

$ sudo ip -n ns_2 set dev enp0s3 up $ sudo ip -n ns_2 $ sudo ip netns exec ns_2 sudo -u eakj wireshark 2>/dev/null & WireShark запущен в netns ns_2

Теперь удалим netns ns_2 и посмотрим, вернется ли enp0s3 в initial netns:

enp0s3 не освободится, пока процесс WireShark не будет завершен, даже несмотря на удаление ns_2

$ sudo ip netns del ns_2 enp0s3 не освободится, пока процесс WireShark не будет завершен, даже несмотря на удаление ns_2

Закроем WireShark и посмотрим, даст ли это результат.

После завершения процесса enp0s3 вернулся в initial netns

После завершения процесса enp0s3 вернулся в initial netns

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

Разбираемся с OpenVPN

Не так давно я писал о том, как поднять собственный OpenVPN на арендованном сервере. Если ты следовал гайду, то у тебя уже настроен клиентский файл, который можно использовать. Конфигурационные файлы других VPN-провайдеров тоже подойдут, так как никаких изменений на сервере делать не придется.

Изменение клиентского конфига

Познакомимся с новыми директивами OpenVPN.

Полный список передаваемых переменных окружения можно посмотреть в man openvpn, секция Environmental Variables.

user nobody group nobody

и добавь новые директивы. Пример немного измененного скрипта из прошлой статьи:

Продолжение доступно только участникам

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

9 лучших бесплатных VPN-сервисов для компьютеров и смартфонов

Заходите на недоступные сайты, не тратя на это ни копейки.

1. Windscribe

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

Бесплатная версия позволяет использовать сервис только на одном устройстве.

2. Proton VPN

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

3. Browsec

Ещё один VPN без ограничений по трафику, который доступен в виде мобильного приложения и расширения для популярных браузеров. Благодаря функции Smart Settings сервис может автоматически включаться только на выбранных сайтах, пропуская остальной трафик напрямую. Бесплатно эта фишка работает только для одного сайта.

4. SurfEasy

Удобный VPN‑сервис для смартфонов и компьютеров, который поможет легко обойти региональные ограничения. SurfEasy позволяет использовать на бесплатном аккаунте до пяти устройств одновременно. Ограничений по скорости нет, но есть лимит на трафик: всего лишь 500 МБ в месяц.

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

5. Betternet

Простой и удобный сервис для стриминга, игр и безопасного сёрфинга в Сети. Работает без регистрации и сложной настройки, достаточно скачать и запустить приложение. Betternet автоматически подключается к самому быстрому серверу, но вручную выбрать его локацию в бесплатной версии нельзя.

В мобильных приложениях при включении VPN всплывает реклама и предложение купить платную подписку.

6. TurboVPN

Как и все бесплатные VPN-сервисы, при запуске TurboVPN предлагает всё-таки выбрать тариф и показывает рекламу, но не слишком навязчиво.

7. Avira Phantom VPN

Очень простой сервис от создателей одноимённого антивируса, призванный обеспечить анонимную работу в интернете. Бесплатно выделяется 500 МБ в месяц, после регистрации лимит увеличится до 1 ГБ.

При этом базовая версия лишена таких функций, как экстренное отключение от Сети и защита от DNS‑утечек.

8. Private Tunnel

Один аккаунт позволяет работать с Private Tunnel на трёх девайсах. Возможен выбор из девяти серверов. При этом предоставляется лишь 200 МБ интернет‑трафика в месяц. Если лимит исчерпается, можно купить пакет на 20 или 100 ГБ.

9. Cloudflare WARP

Этот бесплатный VPN от известного DNS‑провайдера Cloudflare работает на Windows, macOS и мобильных платформах. Ограничений по трафику и скорости нет: можно без проблем смотреть онлайн‑видео вплоть до 4К, пользоваться стримингом и торрентами.

UPD. Текст обновлён 3 сентября 2021 года: в него добавили больше актуальных данных.


В Linux реализована функция пространства имен (namespace), которая отвечает за изоляцию разных ресурсов системы. Она вовсю применяется в проектах контейнеризации, например таких как Docker. Существует несколько типов пространств имен: pid, net, mnt, user, uts, ipc.

Нас интересует пространство имен для сетей (netns), которое изолирует сетевые ресурсы. Для каждого netns можно назначать: свои интерфейсы, наборы IP-адресов и портов (сокеты), таблицы маршрутизации, правила файрвола и так далее. Есть возможность перемещать интерфейсы из одного netns в другой. Физический интерфейс (например, eth0) может находиться одновременно только в одном netns.

Изначально все интерфейсы и процессы содержатся в исходном (initial) netns, у него нет конкретного имени, и он не отображается в списке. После освобождения какого-либо netns все физические интерфейсы, которые были в нем, возвращаются в initial netns. Освобождение происходит после завершения последнего процесса в этом netns. Например, даже если удалить конкретный netns, но процесс, запущенный в нем, будет активным, физический интерфейс не перенесется обратно в исходный netns до тех пор, пока процесс не будет завершен. Рассмотрим этот вариант позже.

Введение в курс

Именно netns поможет нам в туннелировании трафика отдельных приложений. Для начала нужно немного разобраться в командах управления.

База netns

За контроль netns отвечает утилита ip из пакета iproute2 . Для соединения netns между собой можно использовать пару виртуальных интерфейсов veth. Рассмотрим пример создания нескольких netns и их соединения. Для этого выполним

Наличие этих netns смотри командой ip netns list или просто ip netns , так как list — действие по умолчанию. Добавим виртуальную пару при помощи команды

Управление netns и veth с помощью ip

Управление netns и veth с помощью ip

Интерфейсы добавились, теперь переместим virt01 в netns ns_1 , а virt02 — в ns_2 .

Например, посмотреть список доступных интерфейсов внутри netns ns_1 можно при помощи

Почитав man , узнаем, что выполнять команды ip внутри netns можно при помощи $ sudo ip -n <имя netns> , а значит, $ sudo ip netns exec ns_1 ip link заменяем на $ sudo ip -n ns_1 link .

Удостоверимся, что интерфейсы перенеслись в нужные netns

Удостоверимся, что интерфейсы перенеслись в нужные netns

По умолчанию интерфейсы, созданные или перемещенные в netns, пребывают в отключенном состоянии, даже lo .

Добавим нашим интерфейсам virt01 и virt02 по IP-адресу и переведем их в состояние UP . Для этого воспользуемся «прокачанной» командой, подсмотренной в man :

Соединяем вместе нашу виртуальную пару

Соединяем вместе нашу виртуальную пару

Как я уже говорил, у каждой netns своя таблица маршрутизации, проверим это.

Действительно, таблицы отличаются

Действительно, таблицы отличаются

Для проверки связи между ns_1 и ns_2 воспользуемся командой ping .

Соединение установлено успешно

Соединение установлено успешно

Как ты помнишь, адрес 10.0.0.2 принадлежит интерфейсу virt02 , который находится в ns_2 . Похожим способом netns соединяют с физическим eth0 .

Выполнение команд и запуск процессов внутри netns

Как ты помнишь, команды внутри netns выполняются при помощи

Чтобы не писать все это каждый раз, запустим bash !

После этого все команды будут исполняться внутри netns — заодно и проверим ситуацию с файрволом. Чтобы вернуться, пиши exit или CTRL + D .

Список правил пуст

Список правил пуст

У меня всегда присутствуют правила в файрволе, так что это точно отдельный набор. 😉

Перейдем к примеру с возвращением физического интерфейса в initial netns. Для этого проверим текущее расположение enp0s3 и перенесем его в ns_2 .

Как видно, enp0s3 больше нет в init netns

Как видно, enp0s3 больше нет в init netns

Поднимем его в netns ns_2 и запустим WireShark от имени пользователя (eakj) там же.

WireShark запущен в netns ns_2

WireShark запущен в netns ns_2

Теперь удалим netns ns_2 и посмотрим, вернется ли enp0s3 в initial netns:

enp0s3 не освободится, пока процесс WireShark не будет завершен, даже несмотря на удаление ns_2

enp0s3 не освободится, пока процесс WireShark не будет завершен, даже несмотря на удаление ns_2

Закроем WireShark и посмотрим, даст ли это результат.

После завершения процесса enp0s3 вернулся в initial netns

После завершения процесса enp0s3 вернулся в initial netns

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

Разбираемся с OpenVPN

Не так давно я писал о том, как поднять собственный OpenVPN на арендованном сервере. Если ты следовал гайду, то у тебя уже настроен клиентский файл, который можно использовать. Конфигурационные файлы других VPN-провайдеров тоже подойдут, так как никаких изменений на сервере делать не придется.

Изменение клиентского конфига

Познакомимся с новыми директивами OpenVPN.

  1. ifconfig-noexec — запрещает клиенту автоматическое выполнение ifconfig для добавления IP-адреса интерфейсу tun . Вместо этого передаст нужные параметры в качестве переменных окружения.
  2. route-noexec — та же ситуация, что и с ifconfig-noexec , только вместо IP он не будет добавлять маршруты. Необходимые параметры передадутся.
  3. route-up /полный/путь/к/скрипту отправит на скрипт переменной окружения $script_type строку route-up .
  4. up /полный/путь/к/скрипту — то же, что и route-up , только передаст строку up после поднятия интерфейса tun/tap. Выполняется до директивы user , которая должна понизить наши привилегии.
  5. down /полный/путь/к/скрипту — то же, что и route-up , только строку down , после удаления интерфейса tun/tap. Выполняется после директивы user !
  6. script-security 2 позволит исполнять кастомные скрипты.

Полный список передаваемых переменных окружения можно посмотреть в man openvpn , секция Environmental Variables.

Надеюсь, ты обратил внимание на жирный шрифт. Директива up добавит наш netns, down — удалит. Для добавления и удаления netns нужны права рута. Это не проблема в случае с up , поскольку она исполняется перед user , а та, в свою очередь, понижает права до nobody . А вот с down явно будут проблемы, так как пользователь nobody не сможет удалить netns. Поэтому первым делом в клиентском конфиге закомментируй или удали строчки

и добавь новые директивы. Пример немного измененного скрипта из прошлой статьи:

Продолжение доступно только участникам

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Abstract: Изоляция приложения на уровне сети использованием network namespaces Линукса. Организация SSH-туннелей.

Традиционно, большая часть статьи будет посвящена теории, а скучные скрипты — в конце статьи. В качестве субъекта для экспериментов будет использоваться Steam, хотя написанное применимо к любому приложению, включая веб-браузеры.


Вместо вступления. Я просто покажу эту картинку:

147%… Что-то мне это напоминает. Впрочем, хабр не для политики.

Цена на игры в Стиме зависит от региона. Регион — от IP'шника. Есть желание иметь цены в рублях, а не в евро.

Для этого мы используем VPN через SSH с использованием tun-устройств, плюс network namespaces для изоляции приложения от всех остальных сетевых устройств.

Традиционно, приложение, запускающееся даже с правами пользователя, имеет полный доступ в сеть. Оно может использовать любой сетевой адрес, существующий в системе для отправки пакетов.

Более того, большинство десктопных приложений вообще ничего не понимает в интерфейсах, так как предполагают, что у системы есть только один сетевой интерфейс и не даёт возможности указать, каким из интерфейсов надо пользоваться. Серверное ПО обычно имеет эту опцию (какой адрес использовать в качестве адреса отправителя), но для десктопов это непозволительная роскошь.

Если у нас есть несколько интерфейсов (один из которых относится к VPN), то нет штатных методов сказать стиму, что надо использовать его, а не eth0/wlan0. Точнее, мы можем «завернуть» весь трафик в VPN, но это не всегда желательно. Как минимум — рост latency и снижение скорости (даже если VPN ведёт на супербыстрый сервер, увеличение latency, оверхед от туннеля и фиксированная ширина локального канала ставят TCP в положение, когда приходится резать скорость). Как максимум — одно дело «покупать через русский VPN», другое дело — пускать туда весь трафик. Меня совсем не прельщает использование VPN для получения защиты роскомнадзором от оппозиции и вольнодумства.

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

Для решения этой задачи в Linux, уже довольно давно (аж с 2007 года) существует технология, называемая network namespaces, то есть пространства имён для сетей. Суть технологии: над сетевыми интерфейсами создаётся подобие «каталогов», в каждом каталоге может быть несколько сетевых интерфейсов и приложений. Приложение, оказавшееся в заданном сетевом пространстве имён, может использовать (и видит) только те сетевые интерфейсы, которые отнесены к этому пространству.


Картинка ниже поясняет происходящее:


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

Разные namespace'ы выделены разными цветами. Указанные интерфейсы доступны только из указанных неймспейсов и никак иначе. Например, красный namespace имеет доступ только к tap1, veth1 и lo, синий — к eth1, eth2, lo и veth0, зелёный — к tun0 и lo. За пределами namespace'ов остаются eth0, собственный интерфейс br1, tap0 и lo.

Заметим, в каждом namespace'е свой lo! Если в синем namespace'е на lo будет слушать mysql, то из зелёного (и любого другого, кроме синего) namespace'а получить к нему доступ не удастся. Пожалуй, это самая приятная особенность. Вторая особенность — мы можем использовать один и тот же IP адрес в разных пространствах имён на разных интерфейсах, и нам за это ничего не будет. Разумеется, таблица маршрутизации у каждого пространства имён — своя.

Внимательный читатель почуял дух виртуализации. Разумеется, да. Network namespaces (вместе с остальными технологиями такого уровня) являются важной частью LXC (контейнерной виртуализации в линуксе). Но, в отличие от openvz и многих других схожих технологий, компоненты LXC настолько общие, что позволяют использовать их как самостоятельные инструменты. И это правильный unix-way: каждый делает только одну вещь, но хорошо; хотя пуристы могут сказать, что «пихать всё в ядро — плохо».

Наиболее интересной картинка получается, если оставить приложение с tun/tap интерфейсом, который ведёт за пределы текущей сети (на картинке выше — зелёный namespace c одиноким tun'ом). Если tun приземляется где-то за пределами компьютера (например, на vpn-сервере), то приложение не будет иметь никакой возможности понять, какие сетевые настройки реально у компьютера. Если VPN, например, ведёт с Кипра в Россию, то любое запущенное в зелёном namespace'е приложение будет получать адрес из России и выходить в сеть так, как будто оно находится в России. Собственно, это нам и требуется для того, чтобы Steam поверил, что у нас русский IP и согласился продавать игры за пол-цены.

С определением страны у Стима всё несколько странно. Без VPN Стим иногда показывает мне цены в евро, иногда в рублях, и понять закономерности я не смог. Русский VPN снял все вопросы — цены всегда в рублях.

Краткая подсказка по работе с network namespaces (практические советы ближе к концу статьи):
ip netns — список network namespaces (во всех командах ip netns можно сокращать до ip net)
ip netns add/delete foo — создать/удалить network namespace с именем foo
ip netns exec foo /usr/bin/bin — запустить программу в заданном network namespace (заметим, перетаскивать уже запущенные приложения нельзя)
ip link set eth99 netns foo — засунуть интерфейс в заданное пространство

И несколько трюков:

ip netns exec foo ip link — список интерфейсов внутри пространства foo
ip netns exec foo tcpdump -ni eth99 — tcpdump на нём. Внимание, из-за специфичной работы exec'а, вывод на экран появится только после нажатия Ctrl-C. Если раздражает — см ниже.
sudo ip netns exec foo login -f username — запустить логин внутри namespace'а. Залогинившийся пользователь будет работать уже в заданном пространстве имён с отлично сконфигурированными настройками терминала/лидера группы и т.д.

Хотя главная причина ещё проще: SSH — штатный инструментарий, и он умеет всё, что нужно. Зачем ещё что-то?

Итак, теория SSH-туннелей

TUN-интерфейс устроен очень просто: он создаёт в системе виртуальный сетевой интерфейс (tun0, tun1 и т.д.), который другим своим «концом» смотрит в fd (файловый дескриптор) у той программы, которая его создала. Что делать с трафиком из fd программа решает сама. А приложения в системе сами решают, что делать с сетевым интерфейсом.

В случае с SSH мы говорим SSH-клиенту создать tun-интерфейс со своей стороны, SSH-серверу со своей стороны, и соединить их. Получается, что трафик с одной стороны (с клиента) вошёл, с другой стороны (с сервера) вышел. И наоборот. Чем не туннель? Чем не vpn? С учётом, что SSH ещё и шифровать трафик умеет, получаем готовый VPN. Внутри SSH это называются channel, и он их мультиплексирует, но нас это особо и не волнует.


Вот простенький рисунок того, что происходит:

Заметим, нам требуется кооперация со стороны SSH-сервера. Разрешение создавать туннели на сервере мы обсудим в секции с ниже Там же будут подробности настройки NAT'а, адресации и прочих вещей, чтобы стрелка Freedom заработала.

Примечание на полях: помимо tun-интерфейсов бывают ещё tap-интерфейсы. Они позволяют объединять L2-сегменты. Это ад, ужас, содомия и угар, но если кому-то очень хочется, то он может попробовать объединить пару сетей из разных дата-центров посредством SSH-коннекта на домашнюю заначенную машину. Это даже будет работать (за последствия не ручаюсь).

  1. Скопировать SSH ключ к root'у на сервер (если ключа нет, сгенерировать: sudo ssh-keygen ). Я обычно делаю ключ локальному root'у, чтобы не путать его со своим ключом. Ключ копируется командой sudo ssh-copy-id root@server .
  2. Проверить, что у SSH на удалённом сервере разрешено использовать туннели. В файле /etc/ssh/sshd_config переменная PermitTunnel должна быть раскомментирована и выставлена в yes .
  3. Выбрать произвольное число (echo $RANDOM). Это будет наш номер туннеля. Запомним его (или возьмём другое любимое число, например, 42).
  4. Настроим удалённый сервер. Я пишу для debian/ubuntu, процесс для других дистрибутивов/ОС — см в документации по настройке сети к ним. В файле /etc/networking/interfaces создаём следующие строчки:

  1. Выключить все предыдущие копии steam'а, включая иконку в трее
  2. Установить соединение с сервером: sudo ssh -w 42:42 root@server . Опция -w говорит создать tun42 локально и связать его (создав) с удалённым tun42.
  3. В соседней консоли:

xhost + разрешает подключаться к вашему X-серверу кому угодно (будте осторожны). Параноики могут изучить man xhost для указания более точных правил.


Собственнно, всё. На выходе имеем русские цены в Стиме и русскую цензуру. К счастью, защищать она будет только steam, а браузер в соседнем окне будет пользоваться не очень быстрым, но весьма свбодным кипрским интернетом.

Чтобы не дублировать гугл, наиболее понятное и краткое описание Network Namespaces в Linux на русском из тех, что я видел — тут.
В принципе, ничего сложного в настройке namespaces как таковых нет. Но когда мне захотелось сделать красиво, я столкнулся с парой проблем, часть из которых обходится, а часть — не очень. Особенно в KDE.
В интернетах полно мануалов, но можно поступить проще и взять готовый скрипт настройки, например, отсюда (если используется OpenVPN). После чего этот скрипт спокойно дёргать при запуске openvpn, например, такой командой:

openvpn --ifconfig-noexec --route-noexec --up [script_name] --route-up [script_name] --down [script_name] --config [config_name].ovpn --script-security 2 --up [script_name]

Опция --script-security 2 нужна, чтобы OpenVPN разрешил запуск "левого" скрипта после соединения (а его как раз нужно запустить для помещения vpn-соединения в соответствующий namespace и настройки маршрутизации).
Если для поднятия сети используется Network Manager — можно обернуть и эту команду в ещё один простенький скрипт и закинуть в /etc/NetworkManager/dispatcher.d/.
Заблаговременно можно озаботиться отдельным DNS для VPN-соединений (если это необходимо). Прописываются они в /etc/netns/[namespace]/resolv.conf абсолютно стандартным образом:

nameserver [IP-адрес]

Если всё сделано правильно, в итоге должен получиться новый namespace, запускаемые в котором приложения не будут видеть никаких
"реальных" интерфейсов, и от безысходности обращаться к tun0. На этом этапе должен иметься успешный пинг до чего угодно и даже какой-нибудь elinks.

sudo ip netns exec vpn su - [user] -c elinks

kdesudo ip netns exec vpn su - [user] -c opera

— мы получим оперу, однако это будет опера от рута и не знающая ни о каком namespace. Что будет с gksudo — не знаю.
Поэтому я выбрал pkexec. Если дебиан или убунта — не забыть проверить, чтобы в системе стоял policykit-1-gnome. Pkexec заодно надо напомнить, что за сессия и что за экран (соответственно, показать ему Xauthority и DISPLAY)

pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY ip netns exec vpn su - [user] -c opera

. И опера (по крайней мере, классическая) всё равно не запустится. Равно как и Ktorrent, и вообще большая часть приложений из состава KDE. Все они будут громко ругаться на невозможность присоединиться к действующей сессии D-Bus.
Тут есть два варианта:
— добавить запуск новой сессии D-Bus, например, так:

pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY ip netns exec vpn su - [user] -c "dbus-run-session opera"

После этого окажется, что кеды не очень хорошо принимают ситуацию нескольких открытых сессий D-Bus. После того, как Опера дёрнет D-Bus (самое очевидное — вызов кде-шного диалога открытия/сохранения), значки в трее могут перемешаться рандомным образом, а приложения из состава KDE могут начать тормозить и падать, вплоть до фриза иксов. Замена dbus-run-session на dbus-launch особо суть дела не поменяет. Как такое перенесёт гном или мэйт — не знаю. Xfce и более простым окружениям, скорее всего, как раз будет насрать, их пользователям, в принципе, уже можно успокоиться.


взять это проще и отказаться от запуска сложных, требующих интеграции со средой, приложений, в namespace. Firefox, например, хоть и изрядно поругается, но запустится. Практически без проблем запустится qBittorrent. Вообще, если приложение написано на чистом Qt или GTK — проблем с ним, скорее всего, не будет. Можно и классическую оперу научить так запускаться, сказав ей, что на самом деле у вас не KDE. За это отвечает настройка Dialog Toolkit в opera:config. Выберите 2 (GTK) или 4 (X11).

Приложениям на Qt тоже надо объяснить, что у вас на самом деле не KDE, в противном случае при попытке выбора файла они тормознут и откроют KDE-шный диалог, в котором ничего выбрать не дадут (к сессии D-Bus у них доступа нет). Обычно помогает -style=GTK+ (имейте в виду, что диалоги выбора файлов станут гномовскими, тут ничего не поделать, ну и тема GTK должна быть настроена).
В итоге в .desktop-файл можно прописать примерно следующее:


Функциональность в целом не пострадала, разве что вызвать из qBittorrent приложение, полагающееся на D-Bus, не получится. То есть, например, посмотреть загружающееся видео в SMPlayer или тем более mpv — без проблем, а вот открыть содержащую файл папку в Krusader — ни-ни.
Ну и пароль пользователя при запуске спросит. Ну, это не баг, это фича.
На выходе получится то, что нужно — одно приложение ходит в сеть через общий интерфейс, а другое — через VPN.

Читайте также: