Запуск окремих додатків через OpenVPN без контейнерів та віртуалізації

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

Про те, що таке network namespaces в Linux написано багато, але для тих хто не знає я коротко процитующо попалося під руку опис російською мовою:

«В linux відносно давно з'явилася така чудова річ, як неймспейсы (namespaces). Основне застосування даної технології — контейнерна віртуалізація, але і на маршрутизаторі можна придумати багато різних застосувань, так як серед неймспейсов є «network namespaces». Network namespaces дозволяють у рамках однієї машини в кожному неймспейсе мати:

  • свій набір таблиць маршрутизації (а їх 2^31-1 шт)
  • свою arp-таблицю
  • свої правила iptables
  • свої пристрої (а значить і qdisc + class ' и tc)»
А тепер перейдемо до теми нашої статті.

Скрипт, для ручного підняття network namespace і запуску в ньому OpenVPN з коментуванням
#!/bin/bash
sudo ip netns add vpn # створюємо namespace по імені vpn
sudo ip netns exec vpn ip addr add 127.0.0.1/8 dev lo # створюємо в ньому інтерфейс lo
sudo ip netns exec vpn ip link set lo up # піднімаємо loopback-інтерфейс в netns
sudo ip link add vpn0 type veth peer name vpn1 # додаємо в системі віртуальний інтерфейс, через який буде netns спілкуватися із зовнішнім світом
sudo ip link set vpn0 up # піднімаємо створений інтерфейс
sudo ip link set vpn1 netns vpn up # створюємо в netns інтерфейс для спілкування в зовнішньому світі
sudo ip addr add 10.10.10.1/24 dev vpn0 # додаємо адресу користувача в системі
sudo ip netns exec vpn ip addr add 10.10.10.2/24 dev vpn1 # додаємо адресу на інтерфейсі у netns
sudo ip netns exec vpn ip route add VPN_IP via 10.10.10.1 dev vpn1 # додаємо маршрут до VPN-сервера(замініть VPN_IP на адресу вашого сервера)
sudo ip netns exec vpn ip route add default via 10.10.10.254 dev vpn1 # Додаємо адресу якого у нас немає в мережі в якості гейтвея, що б OpenVPN міг замінити при запуску гейтвей на свій(якщо не буде ніякого гейта, то OpenVPN не зможе призначити гейт і пакети поза у нас ходити через нього не будуть) 
sudo iptables -A INPUT ! -i vpn0 -s 10.10.10.0/24 -j DROP 
sudo iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o en+ -j MASQUERADE # налаштовуємо маскарадинг, замініть en+ на wl+ якщо ви використовуєте wifi-сетевуху для підключення до мережі
sudo sysctl -q net.ipv4.ip_forward=1 # дозволяємо форвардінг пакетів
sudo mkdir -p /etc/netns/vpn # створюємо директорію в якій у нас буде лежати resolv.conf для нашого netns 
echo "nameserver 8.8.8.8" |sudo tee /etc/netns/vpn/resolv.conf # прописуємо гугловый 8.8.8.8 як ДНСа
sudo ip netns exec vpn /usr/sbin/openvpn --daemon --writepid /run/openvpn/vpn.pid --cd /etc/openvpn/ --config vpn.conf # Запускаємо OpenVPN з конфіг-файл /etc/openvpn/vpn.conf всередині netns
Виконати цей скрипт ми можемо за допомогою команди:

$ sudo ip netns exec vpn curl http://ifconfig.me

Переконатися, що всередині netns у нас піднято OpenVPN і в мережу всередині netns ми виходимо через наш OpenVPN. Тепер командою:

$ sudo ip netns exec vpn su - USER_NAME -c firefox

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

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

Скрипт для зупинки нашого netns:
#!/bin/bash
sudo ip netns pid vpn | xargs -rd'\n' sudo kill
sudo rm -rf /etc/netns/vpn
sudo sysctl -q net.ipv4.ip_forward=0
sudo iptables -D INPUT ! -i vpn0 -s 10.10.10.0/24 -j DROP
sudo iptables -t nat -D POSTROUTING -s 10.10.10.0/24 -o en+ -j MASQUERADE
sudo ip link del vpn0
sudo ip netns delete vpn
Юніти для systemd піднімають все зазначене на автоматі при завантаженні. Юніт для netns:

[Unit]
Description=Network namespace for VPN
After=syslog.target network.target
StopWhenUnneeded=true
RefuseManualStart=true
RefuseManualStop=true

[Service]
EnvironmentFile=/etc/netns/vpn.env
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/ip netns add vpn
ExecStart=/bin/ip netns exec vpn ip addr add 127.0.0.1/8 dev lo
ExecStart=/bin/ip netns exec vpn ip link set lo up
ExecStart=/bin/ip link add vpn0 type veth peer name vpn1
ExecStart=/bin/ip link set vpn0 up
ExecStart=/bin/ip link set vpn1 netns vpn up
ExecStart=/bin/ip addr add ${NETWORK}.1/24 dev vpn0
ExecStart=/bin/ip netns exec vpn ip addr add ${NETWORK}.2/24 dev vpn1
ExecStart=/bin/ip netns exec vpn ip route add ${VPN_SERVER} via ${NETWORK}.1 dev vpn1
ExecStart=/bin/ip netns exec vpn ip route add default via ${NETWORK}.254 dev vpn1 
ExecStart=/sbin/iptables -A INPUT ! -i vpn0 -s ${NETWORK}.0/24 -j DROP
ExecStart=/sbin/iptables -t nat -A POSTROUTING -s ${NETWORK}.0/24 -o wl+ -j MASQUERADE
ExecStart=/sbin/sysctl -q net.ipv4.ip_forward=1
ExecStart=/bin/mkdir -p /etc/netns/vpn
ExecStart=/bin/sh -c "echo 'nameserver 8.8.8.8' > /etc/netns/vpn/resolv.conf"

ExecStop=/bin/rm -rf /etc/netns/vpn
ExecStop=/sbin/sysctl -q net.ipv4.ip_forward=0
ExecStop=/sbin/iptables -D INPUT ! -i vpn0 -s ${NETWORK}.0/24 -j DROP
ExecStop=/sbin/iptables -t nat -D POSTROUTING -s ${NETWORK}.0/24 -o wl+ -j MASQUERADE
ExecStop=/bin/ip link del vpn0
ExecStop=/bin/ip netns delete vpn

[Install]
WantedBy=multi-user.target
Юніт для OpenVPN:

[Unit]
Description=OpenVPN inside network namespace
Requires=vpnns.service
After=syslog.target network.target vpn-ns.service

[Service]
PrivateTmp=true
Type=forking
PIDFile=/var/run/openvpn/%i.pid
ExecStart=/bin/ip netns exec vpn /usr/sbin/openvpn --daemon --writepid /var/run/openvpn/%i.pid --cd /etc/openvpn/ --config %i.conf

[Install]
WantedBy=multi-user.target
Файл із змінними в якому я ставлю адреса ВПН-сервера і мережі використовуваної netns:

VPN_SERVER=1.1.1.1 # Change to your IP OpenVPN-server IP
NETWORK=10.10.10
Скопіювавши файли для systemd в їх місця на файловій системі командою

$ sudo systemctl enable openvpn-ns@NAME.service

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

$ sudo systemctl start openvpn-ns@NAME.service

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

Командою

$ sudo ip netns exec vpn curl http://ifconfig.me

ви зможете перевірити, що всередині netns тепер є VPN і ви ходите з адреси свого сервера.

» Юніти systemd на github.
» Скрипти vpnns_up.sh і vpnns_down.sh gist.gihub.com

При підготовці статті мені допомогли два посилання:
» schnouki.net/posts/2014/12/12/openvpn-for-a-single-application-on-linux
» www.linux.org.ru/forum/admin/11591881

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

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

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.