Одна програма має використовувати звичайне з’єднання, а все інше залишається в тунелі, і у клієнта немає для цього перемикача. Прихованого меню теж немає. Маршрут вибирається з полів усередині пакета, а пакет несе адреси й порти, а не особу процесу, що його створив, тому виключення має бути виражене в одному з цих полів. Прослідкуйте пакет один раз, і доступні варіанти перестають бути загадковими.

Чому клієнт не може це запропонувати

Маршрутизація за призначенням порівнює адресу призначення з префіксами й зберігає найдовший збіг. У цей момент будь-який пакет виглядає однаково, що б його не створило. Маршрутизація за політикою джерела розширює порівняння на адресу джерела, і це той гачок, який використовує кожне практичне рішення: змініть джерело, і інша таблиця стане придатною.

Порти не допомагають. Виключення за портом довелося б оцінювати до пошуку призначення, а порт у цьому рішенні не відіграє жодної ролі. Усе, що рекламується як виключення за портом, насправді виключає за іншим полем і описує це недбало.

Справжня маршрутизація за застосунками існує там, де платформа додала для цього механізм, наприклад виклики фільтрів у Windows або прив’язка служби VPN в Android. Настільний примірник OpenVPN нічого з цього не постачає, і жоден прапорець конфігурації цього не вигадує.

Linux: позначте процес, потім маршрутизуйте позначку

Найчистіший підхід прив’язує рішення до процесу, який володіє сокетом. Збіг owner працює для локально створеного трафіку в ланцюжку OUTPUT, тому позначка, застосована там, може вибрати окрему таблицю:

iptables -t mangle -A OUTPUT -m owner --uid-owner 1001 -j MARK --set-mark 0x1
ip rule add fwmark 0x1 table 200
ip route add 192.168.1.0/24 dev eth0 src 192.168.1.0 table 200
ip route add default via 192.168.1.1 dev eth0 table 200

Пакети від користувача 1001 потім звертаються до таблиці 200 і виходять через звичайний шлюз, а основна таблиця далі надсилає все інше в тунель. Збіг owner стосується лише локально створених пакетів, а це саме той трафік, який тут важливий, і він не може класифікувати пакети, передані іншому хосту. Перевіряйте інструментами, а не наміром: ss -tnp показує локальну адресу й процес-власник встановлених з’єднань, а ip route get 1.1.1.1 mark 0x1 показує, яку таблицю вибирає позначка.

Мережевий простір імен — міцніша відповідь для самодостатньої програми, бо кожен створений у ньому сокет прив’язаний до нього за побудовою, тож допоміжні процеси й дочірні з’єднання успадковують поведінку, взагалі не класифікуючись. Ціна — сантехніка: пара veth, адреса на кожному кінці й маршрут за замовчуванням усередині простору імен, який вказує назад на хост.

ip netns add novpn
ip link add veth-host type veth peer name veth-ns
ip link set veth-ns netns novpn
ip addr add 10.200.0.1/24 dev veth-host
ip netns exec novpn ip addr add 10.200.0.2/24 dev veth-ns
ip netns exec novpn ip route add default via 10.200.0.1

Windows: призначення все ще вирішує

Windows вибирає вихідний інтерфейс за призначенням, тому програмі, якій потрібен інший шлях, доводиться змінювати те, що стек запитує до цього вибору. ForceBindIP закриває першу половину: він запускає програму із сокетами, вже прив’язаними до вказаної вами локальної адреси. Саме це не змінює інтерфейс, через який виходить пакет, бо маршрут усе ще вибирає призначення. Прив’яжіть джерело на ноутбуці, чий маршрут за замовчуванням веде в тунель, і пакет усе одно потрапить у тунель.

Симптом має читабельну форму, щойно ви з ним ознайомитесь. Він проявляється для адреси LAN, до якої вибраний інтерфейс дістається напряму, і не працює для всього в інтернеті, чий маршрут вказує на тунель. Він також виглядає працездатним, доки програма не передасть роботу помічникові, бо помічникові, який відкриває власний сокет, про прив’язку ніколи не казали.

Перенесіть рішення, коли один процес — неправильна одиниця

Якщо справжня вимога — пристрій, а не програма, помістіть його на власний SSID або VLAN і дозвольте маршрутизатору вирішувати: це джерело йде звичайним шляхом, а інші джерела використовують тунель. Виділена машина-шлюз — інший чесний варіант: вона тримає VPN і отримує лише ті призначення, які надсилає їй маршрутизатор. У VLAN політика охоплює кожен потік, який відкриває пристрій, включно з допоміжними процесами, що зламали підхід Windows. Обмін — це обсяг: дві програми на цьому пристрої більше не можна обробляти по-різному.

Обидві — політики джерела або призначення з обсягом, який можна висловити одним реченням. Жодна не є за застосунком, і проєкт, який продає себе як рішення за застосунком, ламається першого ж разу, коли програма передає свою роботу другому процесу.

Схожі статті