PPTP у Docker проходить автентифікацію, але не передає трафік
PPTP потрібен TCP 1723 для керування і GRE для корисного навантаження. У контейнері часто немає помічника conntrack, тому вхід працює, а більше нічого.
Клієнт автентифікується, PPP узгоджує адресу, і далі нічого не рухається. Ping не проходить, браузер не працює, а контейнер увесь час виглядає підключеним. Це не проблема таблиці маршрутизації, бо проблеми маршрутизації зазвичай ламають і керуюче з'єднання. Це шлях корисного навантаження, а в PPTP навантаження — це інший протокол, не той, що щойно спрацював.
П'ять перевірок у порядку, який економить найбільше часу.
Перевірка 1: відокремте канал керування від навантаження
PPTP автентифікується через TCP 1723, а потім несе навантаження PPP усередині GRE, протоколу IP 47. GRE — не TCP і не UDP, тому кожне правило, що пропускає порт керування, нічого про нього не каже. NAT або міжмережевий екран, що пропускає 1723, може мовчки відкинути протокол 47, і сеанс залишається наполовину побудованим так, що це виглядає як успіх.
Якщо вхід працює і жоден пакет не повертається, спочатку припустіть GRE, а потім це доведіть.
Перевірка 2: підтвердьте помічник у ядрі хоста
Відстеження з'єднань не може зв'язати керуюче з'єднання TCP із потоком GRE без помічника. Модуль — nf_conntrack_pptp, він живе в ядрі хоста, і завантаження його всередині образу контейнера нічого не дає, бо модулі діють на весь хост. lsmod | grep nf_conntrack_pptp на хості Docker — це і є перевірка. Якщо його немає, modprobe nf_conntrack_pptp завантажує його для працюючого ядра і нічого не каже про наступне завантаження, тому додайте його і в конфігурацію хоста.
Модуль, що зникає під час перезавантаження, наступного місяця стане тією ж заявкою.
Перевірка 3: прочитайте політику ядра, яка його вимикає
Навіть за наявності модуля ядра від 4.7 за замовчуванням ставлять net.netfilter.nf_conntrack_helper у 0, що вимикає автоматичне призначення помічника для кожного протоколу. Саме через це значення за замовчуванням правильно встановлений модуль усе одно нічого не робить: код є, а політика каже його не використовувати. sysctl net.netfilter.nf_conntrack_helper показує поточне значення, і встановлення його в 1 під час роботи знову робить помічник доступним. Збережіть значення через конфігурацію sysctl хоста, якщо проєкт це дозволяє.
Автоматичне призначення дозволяє трафіку неявно створювати очікування, і саме тому значення за замовчуванням змінили. Обмежте його довіреним хостом або використайте явне правило, націлене на помічника.
Перевірка 4: погляньте на шлях контейнера окремо
Завантажений помічник не створює маршрут. Контейнеру потрібен шлях до сервера PPTP, і переспрямування на хості має дозволяти GRE в обох напрямках: iptables -L FORWARD -v -n показує, чи приймається протокол 47 і чи рухаються лічильники. Правила masquerade у Docker перетворюють TCP і UDP, а не протокол 47, тому контейнеру з мостом може знадобитися явний дозвіл forward і, на деяких хостах, власне правило перетворення. Переконайтеся також, що контейнер підтримує пристрої PPP, яких очікує його образ.
Читайте лічильники, а не текст правила. Правило, яке існує і ні з чим не збігається, — це прикраса.
Перевірка 5: доведіть, що GRE відстежується, потім вирішіть щодо PPTP
Поки клієнт працює, прочитайте таблицю відстеження. Установлений запис керування PPTP плюс пов'язаний запис GRE означають, що помічник зв'язує потоки, а решта несправності в іншому місці. Запис керування без запису GRE означає, що навантаження відкидається або не відстежується, що повертає вас до перевірок 2 і 3.
Сам PPTP застарів, а MS-CHAPv2 слабкий. Якщо сервер також пропонує L2TP/IPsec, IKEv2 або WireGuard, перехід на один із них усуває весь цей клас проблем.
Там, де PPTP має залишитися, запуск клієнта на хості, а не всередині контейнера прибирає один шар NAT і фільтрації, що часто є дешевшим рішенням.