LINUX.ORG.RU
решено ФорумAdmin

Добавить сетевое пространство имён из юнита systemd

 , ,


3

2

В общем наваял я тут такой юнит для systemd:

[Unit]
Description=OpenVPN inside %I network namespace
After=syslog.target network.target

[Service]
PrivateTmp=true
Type=forking
PIDFile=/var/run/openvpn/%i.pid

ExecStartPre=/bin/ip netns add vpn
ExecStartPre=/bin/ip -netns vpn addr add 127.0.0.1/8 dev lo
ExecStartPre=/bin/ip -netns vpn link set lo up
ExecStartPre=/bin/ip link add vpn0 type veth peer name vpn1
ExecStartPre=/bin/ip link set vpn0 up
ExecStartPre=/bin/ip link set vpn1 netns vpn up
ExecStartPre=/bin/ip addr add 10.200.200.1/24 dev vpn0
ExecStartPre=/bin/ip -netns vpn addr add 10.200.200.2/24 dev vpn1
ExecStartPre=/bin/ip -netns vpn route add default via 10.200.200.1 dev vpn1
ExecStartPre=/sbin/iptables -A INPUT ! -i vpn0 -s 10.200.200.0/24 -j DROP
ExecStartPre=/sbin/iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o wl+ -j MASQUERADE
ExecStartPre=/sbin/sysctl  -q net.ipv4.ip_forward=1
ExecStartPre=/bin/mkdir  -p /etc/netns/vpn
ExecStartPre=/bin/sh -c "echo 'nameserver 8.8.8.8' > /etc/netns/vpn/resolv.conf"

ExecStart=/bin/ip netns exec vpn /usr/sbin/openvpn --daemon --writepid /var/run/openvpn/%i.pid --cd /etc/openvpn/ --config %i.conf

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

[Install]
WantedBy=multi-user.target
Если это неочевидно, задача - создать сетевое пространство имён (network namespace) vpn, наладить взаимодействие этого пространства имён с внешним миром, и запустить в нём openvpn. Сперва протестировал эту последовательность команд вручную, всё работало. Создал юнит - запинается на второй:
/bin/ip -netns vpn addr add 127.0.0.1/8 dev lo
с таким выхлопом:
setting the network namespace "vpn" failed: Invalid argument
После фейла остаётся висеть созданное пространство имён vpn и если с ним попробовать повторить эту же команду, она так же сфейлит. Даже просто ip netns выдаёт:
RTNETLINK answers: Invalid argument
vpn
Если после этого вручную удалить и создать этот namespace, а в юните закомментить строчку с командой ip netns add vpn, то юнит запускается и работает как и должен. Отсюда делаем вывод, что при создании сетевого пространства имён из юнита systemd что то происходит не так. Вопрос - что? Есть у кого идеи?

sudo cast intelfx

Ответ на: комментарий от i_gnatenko_brain

не совсем то. как узнать имя того ns, которое systemd создаст для этого юнита? как поднять виртуальный интерфейс, чтобы дать этому ns доступ в инет? как из пространства пользователя (не из юнита systemd) запускать процессы в этом ns?

eternal_sorrow ★★★★★
() автор топика
Ответ на: комментарий от Deleted

почему у твоей авы вывернут сустав в колене

anonymous
()
Ответ на: комментарий от thesis

ip в арче умеет такой финт ушами

 -n, -net, -netns <NETNS>
              switches ip to the specified network namespace NETNS.  Actually it just simplifies executing of:

              ip netns exec NETNS ip [ OPTIONS ] OBJECT { COMMAND | help }

              to

              ip -n[etns] NETNS [ OPTIONS ] OBJECT { COMMAND | help }

Deleted
()
Ответ на: комментарий от Deleted

это то же самое, и да, я пробовал, результат такой же

eternal_sorrow ★★★★★
() автор топика
Последнее исправление: eternal_sorrow (всего исправлений: 1)
Ответ на: комментарий от vel

хочется иметь возможность запускать некоторые приложения через vpn, но при этом одновременно чтобы все остальные приложения работали через обычный инет

eternal_sorrow ★★★★★
() автор топика
Ответ на: комментарий от eternal_sorrow

запускать некоторые приложения через vpn, но при этом одновременно чтобы все остальные приложения работали через обычный инет

Поставь на vpn-сервер socks-прокси и запускай программу через proxychains или tsocks.

risenshnobel ★★★
()

Так, судя по всему никто понятия ни имеет о такой проблеме. А ведь решение где то на поверхности - каким то образом если создавать ns из юнита, оно создаётся как то неправильно и не работает. Заметил также, что файл /run/netns/vpn (он создаётся при создании ns) из юнита создаётся с правами 000, тогда как при cоздании ns вручную - 444. Предупреждая возможные вопросы, chmod делать пробовал, без толку.

Те кто предлагал изменить вторую команду ( thesis, MyLittleLoli), не туда копают. С этой командой всё в порядке, ведь если создать ns вручную, всё отрабатывает нормально. Проблема именно в команде ip netns add vpn.

intelfx судя по всему в выходные решил и от ЛОРа заодно отдохнуть.

eternal_sorrow ★★★★★
() автор топика
Последнее исправление: eternal_sorrow (всего исправлений: 3)
Ответ на: комментарий от eternal_sorrow

Насколько понимаю, дело в PrivateTmp=true.

Сетевые неймспейсы выглядят как файлик, который ядро выдаёт процессу в /proc/<pid>/ns/net при входе процесса в неймспейс. Добавить другой процесс в неймспейс значит как-либо открыть (из него) тот же файл и передать полученный fd в setns(2). Пока этот файлик имеет имя (т. е. либо в неймспейсе есть хотя бы один процесс, либо файлик куда-то прибинжен) — неймспейс живёт.

Соответственно, ip netns add создаёт неймспейс и биндит /proc/<свой-pid>/ns/net в /var/tmp/netns/<имя>. Ключевое слово — биндит. А у тебя каждый процесс выполняется в отдельном mount namespace.

Это «особенность» работы PrivateTmp=. Оно не использует один mount namespace на все запускаемые процессы, а создаёт отдельный для каждого.

intelfx судя по всему в выходные решил и от ЛОРа заодно отдохнуть.

Не то чтобы. :] Просто вчера весь день развлекался с велосипедом (что подразумевает определённую степень усталости вечером, хе-хе).

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 2)
Ответ на: комментарий от eternal_sorrow

Да я не копал, мне простоинтересно стало, где ты узнал про эту опцию. У меня, наверное, более окаменевшие версии ip, там ее нет.

Сейчас глянул - PrivateTmp=yes мешает. Но вот как и почему - не могу объяснить.

thesis ★★★★★
()
Ответ на: комментарий от intelfx

Потенциальное решение — создавать неймспейс в отдельном юните (Type=oneshot, RemainAfterExit=true, StopWhenUnneeded=true) и делать Requires=/After= из основного юнита.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 2)
Ответ на: комментарий от eternal_sorrow

Кстати, «имя неймспейса» — это искусственное понятие, изобретённое господами из iproute2. Именование неймспейсов (конкретно сетевых) достигается за счёт прибинживания файла, отвечающего за неймспейс, в /var/run/netns/<требуемое-имя>. Это тупо соглашение, принятое в iproute2, и systemd про него не знает.

Впрочем, если у тебя юнит без PrivateTmp=, никто не мешает самостоятельно забиндить /proc/self/ns/net куда тебе хочется и сэмулировать поведение ip.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

Сейчас попробую. Я так понимаю, более простым решением было бы убрать PrivateTmp=true, но так делать не стоит из соображений безопасности?

eternal_sorrow ★★★★★
() автор топика
Ответ на: комментарий от intelfx

О блин, дочитал абзац про PrivateTmp до конца, а там.
«Note that using this setting will disconnect propagation of mounts from the service to the host (propagation in the opposite direction continues to work). This means that this setting may not be used for services which shall be able to install mount points in the main mount namespace.»

А то я до сих пор считал, что PrivateTmp только породит частные /tmp и /var/tmp, и на этом всё.

thesis ★★★★★
()
Ответ на: комментарий от intelfx

Да, в общем и целом понятно, но в данном случае мне не подходит, т.к. в одном юните нужно выполнять команды и из глобального ns, и из местного. Спасибо за разъяснение.

eternal_sorrow ★★★★★
() автор топика
Ответ на: комментарий от thesis

Дело даже не в этом (точнее, не только в этом). Под каждый запущенный процесс создаётся отдельный mount namespace (с одними и теми же директориями, подключенными к /tmp и /var/tmp). Почему — понятия не имею; можно спросить у апстрима, если сильно интересно.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от eternal_sorrow

команды и из глобального ns, и из местного

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

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

а причём тут монтирование? я про то, чтобы использовать PrivateNetwork=true вместо того, чтобы создавать ns с помощью ip.

eternal_sorrow ★★★★★
() автор топика
Ответ на: комментарий от eternal_sorrow

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

intelfx ★★★★★
()

Вариант с двумя юнитами отработал как нужно, для желающих выкладываю оба юнита:

/etc/systemd/system/vpn-ns.service

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

[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/bin/ip netns add vpn
ExecStart=/bin/ip -netns vpn addr add 127.0.0.1/8 dev lo
ExecStart=/bin/ip -netns vpn 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 10.200.200.1/24 dev vpn0
ExecStart=/bin/ip -netns vpn addr add 10.200.200.2/24 dev vpn1
ExecStart=/bin/ip -netns vpn route add default via 10.200.200.1 dev vpn1
ExecStart=/sbin/iptables -A INPUT ! -i vpn0 -s 10.200.200.0/24 -j DROP
ExecStart=/sbin/iptables -t nat -A POSTROUTING -s 10.200.200.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 10.200.200.0/24 -j DROP
ExecStop=/sbin/iptables -t nat -D POSTROUTING -s 10.200.200.0/24 -o wl+ -j MASQUERADE
ExecStop=/bin/ip link del vpn0
ExecStop=/bin/ip netns delete vpn

[Install]
WantedBy=multi-user.target
/etc/systemd/system/openvpn-ns@.service
[Unit]
Description=OpenVPN on %I inside network namespace
Requires=vpn-ns.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

eternal_sorrow ★★★★★
() автор топика
Последнее исправление: eternal_sorrow (всего исправлений: 1)
16 сентября 2016 г.
Ответ на: комментарий от eternal_sorrow

Понимаю, что комментирование тем полуторогодичной давности попахивает археологией и даже некрофилией, но все же напишу.

Задался ровно тем же вопросом, для запуска браузера в отдельном netns, сначала накропал скрипт, потом подумал о юните, нашел ваши, на их базе переделал свои.

Плюс к тому убрал у netns'а default gw настоящий, что бы в нем без VPN'а нельзя было ходить в инет. Выложил на гитхаб.
https://github.com/Ernillew/netns-vpn

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

ergil ★★★
()
Ответ на: комментарий от eternal_sorrow

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

ergil ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.