Содержание статьи
Немного о 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 смотри командой ip netns list
или просто ip netns
, так как list
— действие по умолчанию. Добавим виртуальную пару при помощи команды
$ sudo ip link add dev virt01 type veth peer name virt02

Интерфейсы добавились, теперь переместим virt01
в netns ns_1
, а virt02
— в ns_2
.
$ sudo ip link set virt01 netns ns_1
$ sudo ip link set virt02 netns ns_2
Если не появилось сообщений об ошибках, значит, все прошло успешно. Для выполнения команды внутри netns используется команда
$ sudo ip netns exec <имя netns> <команда для выполнения>
Например, посмотреть список доступных интерфейсов внутри netns ns_1
можно при помощи
$ sudo ip netns exec ns_1 ip link
Почитав man
, узнаем, что выполнять команды ip
внутри netns можно при помощи $ sudo ip -n <имя netns>
, а значит, $ sudo ip netns exec ns_1 ip link
заменяем на $ sudo ip -n ns_1 link
.

По умолчанию интерфейсы, созданные или перемещенные в 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 link set dev virt01 up
$ sudo ip -n ns_2 link 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
После этого все команды будут исполняться внутри netns — заодно и проверим ситуацию с файрволом. Чтобы вернуться, пиши exit
или CTRL + D
.

У меня всегда присутствуют правила в файрволе, так что это точно отдельный набор. 😉
Перейдем к примеру с возвращением физического интерфейса в initial netns. Для этого проверим текущее расположение enp0s3
и перенесем его в ns_2
.
$ sudo ip link set dev enp0s3 netns ns_2

Поднимем его в netns ns_2
и запустим WireShark от имени пользователя (eakj) там же.
$ sudo ip -n ns_2 link set dev enp0s3 up
$ sudo ip -n ns_2 link
$ sudo ip netns exec ns_2 sudo -u eakj wireshark 2>/dev/null &

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

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

Этого должно быть достаточно, чтобы понять, как работают netns и как ими управлять. Перейдем к OpenVPN.
Разбираемся с OpenVPN
Не так давно я писал о том, как поднять собственный OpenVPN на арендованном сервере. Если ты следовал гайду, то у тебя уже настроен клиентский файл, который можно использовать. Конфигурационные файлы других VPN-провайдеров тоже подойдут, так как никаких изменений на сервере делать не придется.
Изменение клиентского конфига
Познакомимся с новыми директивами OpenVPN.
ifconfig-noexec
— запрещает клиенту автоматическое выполнениеifconfig
для добавления IP-адреса интерфейсуtun
. Вместо этого передаст нужные параметры в качестве переменных окружения.route-noexec
— та же ситуация, что и сifconfig-noexec
, только вместо IP он не будет добавлять маршруты. Необходимые параметры передадутся.route-up /полный/путь/к/скрипту
отправит на скрипт переменной окружения$script_type
строкуroute-up
.up /полный/путь/к/скрипту
— то же, что иroute-up
, только передаст строкуup
после поднятия интерфейса tun/tap. Выполняется до директивыuser
, которая должна понизить наши привилегии.down /полный/путь/к/скрипту
— то же, что иroute-up
, только строкуdown
, после удаления интерфейса tun/tap. Выполняется после директивыuser
!script-security 2
позволит исполнять кастомные скрипты.
Полный список передаваемых переменных окружения можно посмотреть в man openvpn
, секция Environmental Variables.
Надеюсь, ты обратил внимание на жирный шрифт. Директива up
добавит наш netns, down
— удалит. Для добавления и удаления netns нужны права рута. Это не проблема в случае с up
, поскольку она исполняется перед user
, а та, в свою очередь, понижает права до nobody
. А вот с down
явно будут проблемы, так как пользователь nobody
не сможет удалить netns. Поэтому первым делом в клиентском конфиге закомментируй или удали строчки
user nobody
group nobody
и добавь новые директивы. Пример немного измененного скрипта из прошлой статьи:
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»
inkognito.o
16.01.2018 в 05:49
большое спасибо за статью. Было очень интересно!
loneattic
08.06.2019 в 18:51
спасибо