Застосунок у мережевому просторі імен VPN недоступний із LAN
Мережевий простір імен дає одній програмі власний тунель і власний loopback. Публікуйте лише його порт через стрибок socat або пару veth, а не через хост.
Ваш сервіс працює на машині, тунель піднято, а браузер на вашому столі все ще не отримує відповіді. У звичайному сенсі нічого не зламано: застосунок слухає всередині мережевого простору імен, і цей стек невидимий для LAN. Його loopback належить простору імен, тому клієнт на іншій машині не має адреси, яка доходить до порту. Один навмисний стрибок або одна пара veth виправляє це, не переміщуючи решту хоста.
Чому на адресі LAN ніхто не відповідає
Простір імен — це повний мережевий стек: інтерфейси, маршрути, правила міжмережевого екрана і приватний loopback. Процес, запущений через ip netns exec, бачить лише цей стек і нічого більше, тому адреса, до якої він прив'язується, розв'язується тільки всередині простору імен. Власний 127.0.0.1 хоста — це зовсім інший loopback.
Тому curl на хості зазнає невдачі, а та сама команда всередині простору імен виконується успішно. Застосунок здоровий; адреси просто немає в стеку хоста.
Опублікуйте один порт стрибком socat
socat з'єднує два стеки в просторі користувача, чого достатньо, коли має пройти один порт TCP. Бік хоста слухає в LAN і для кожного прийнятого з'єднання запускає другий socat усередині простору імен, який підключається до loopback застосунку. Внутрішній процес досягає застосунку точно так, як це зробив би локальний клієнт. У маршрутизації простору імен нічого не змінюється, тому застосунок далі використовує тунель як єдиний вихід.
socat TCP-LISTEN:9100,reuseaddr,fork EXEC:'ip netns exec vpn socat STDIO tcp-connect:127.0.0.1:9100',nofork
Зовнішньому процесу потрібен root або можливість увійти в простір імен. Якщо VPN падає, застосунок втрачає шлях, а опублікований порт відмовляє закритим, і це саме та поведінка, якої ви чекаєте від в'язниці.
Використовуйте пару veth, коли проходить більше одного порту
Пара veth — правильна відповідь, коли мають пройти кілька портів або протоколів, або коли інші хости мають ініціювати з'єднання. Один кінець залишається в хості, другий переходить у простір імен, а мала /30 дає обом бокам стабільну адресу. Потім маршрут хоста надсилає адресу простору імен через пару.
ip link add veth0 type veth peer name veth1
ip link set veth1 netns vpn
ip addr add 10.77.0.1/30 dev veth0
ip link set veth0 up
ip netns exec vpn ip addr add 10.77.0.2/30 dev veth1
ip netns exec vpn ip link set veth1 up
Не додавайте маршрут за замовчуванням через хост, якщо не збираєтеся ламати в'язницю. Тунель має залишатися виходом, тому через пару доступна лише опублікована адреса служби. Дайте простору імен і власний файл resolver, бо ip netns exec читає /etc/netns/vpn/resolv.conf, а без нього розв'язання імен усередині в'язниці порожнє.
Тестуйте з другої машини, а не з хоста
Запускайте тест з другої машини, бо хост може дістатися до локального слухача шляхами, які нічого не кажуть про LAN. Спершу перевірте, до чого застосунок насправді прив'язався всередині простору імен, потім підключіться ззовні до опублікованої адреси. Прив'язка до всіх адрес там не розширює в'язницю, бо wildcard усе ще належить простору імен, і LAN не може його побачити.
ip netns exec vpn ss -lntp
Якщо з'єднання з хоста працює, а з LAN ні, відсутня частина — це стрибок або маршрут, а не адреса прив'язки. Запускайте OpenVPN всередині простору імен, а не переносьте туди живе пристрій tun, оскільки перенесення інтерфейсу вимикає його і може стерти маршрути, які потім не вийде полагодити ззовні. Тримайте команди відновлення на консолі, а не всередині в'язниці.