Как OpenVPN клиент зад NAT се превръща в интернет изход
Изходът сам осъществява връзката, така че рутерът му не се нуждае от входящ порт. Проследете какво маршрутизира хъбът, какво препраща изходът и откъде идва обратният път.
Три Linux хоста, един дизайн: публично достъпен OpenVPN хъб, потребителски лаптоп и машина изход зад обикновен домашен рутер, който не препраща нищо входящо. Изходът сам се свързва с хъба. След това интернет трафикът на потребителя влиза в тунела при лаптопа и излиза през собствения upstream на изхода. Всичко изненадващо в тази подредба следва от една подробност: изходът е започнал връзката, затова пътят навътре вече съществува и не е нужен port forward, за да се създаде.
Следващото проследява пътя на пакета, а не реда на конфигурацията, защото конфигурацията има смисъл само след като знаете кой компонент взема кое решение. Всеки слой взема точно едно решение, а грешките се струпват там, където два слоя се приемат за един.
Две транспортни сесии, един вътрешен път
Всеки хост поддържа собствена външна връзка към хъба и нито една от тези връзки не знае за другата. Трафикът на потребителя към интернет е отделен вътрешен поток, който случайно се пренася в тунела на потребителя и после се излъчва отново от тунела на изхода. Точно този вътрешен поток хъбът трябва да маршрутизира и точно него изходът трябва да препраща.
outer: consumer --TLS--> hub
outer: exit --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink
Тъй като и двете външни връзки са изходящи от страната на клиента, рутерът на изхода никога не вижда входящ SYN и никога не се нуждае от правило за destination NAT. Той трябва само да поддържа установения транспорт жив, което вече прави за всяка дълготрайна връзка. Нищо в публичния интернет не трябва първо да достига до изхода, затова динамичният адрес на този upstream не е проблем. Рутерът все пак трябва да разреши изходящата сесия, но това е същото разрешение, което браузърът вече използва.
Какво всъщност инсталира iroute вътре в сървъра
Хъбът е единственото устройство, което решава кой партньор притежава коя дестинация, и взема това решение в собствената си потребителска маршрутна таблица, а не в тази на ядрото. Запис client-config-dir за изхода с име exit-node може да заяви там подразбиращия се префикс:
# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0
Този ред казва на сървърния процес "вътрешни пакети с всяка дестинация принадлежат на този клиент". Той не добавя маршрут по подразбиране към операционната система на хъба и не превръща хъба в интернет шлюз. Справочникът за OpenVPN 2.6 поддържа вътрешното маршрутизиране за конкретен клиент и маршрутизирането на ядрото като отделни механизми и точно това разделение е причината дизайнът да работи, без да се пипа маршрутът по подразбиране на хъба.
Потребителят се нуждае от огледалната инструкция, доставена като push, така че собственият му трафик да влиза в тунела, вместо да излиза през локалния му шлюз. При подмрежова топология пулът е свързан маршрут на tun устройството на изхода, затова обратната посока не се нуждае от допълнителен push; това, което изходът не бива да получава, е пренасочването по-долу, което би върнало собствения му upstream трафик в тунела, който се опитва да използва. Изпращайте го само към потребителя и четете приложените маршрути на клиента, вместо да вярвате, че CCD файлът е избран.
# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"
Ядрото на изхода извършва препращането
Вътре в изхода пакет от потребителя пристига на tun интерфейса, адресиран до някакъв интернет хост. Ядрото се допитва до маршрутната си таблица, намира реалния upstream като най-добро съвпадение и след това прилага две независими политики: може ли този пакет да се препраща изобщо и може ли да напусне през този интерфейс с този адрес на източника. Препращането е sysctl и по подразбиране е изключено в много дистрибуции.
Затова изходът се нуждае от постоянно включено IPv4 препращане, правило за препращане, което допуска източниците от тунела на потребителя към upstream, и път за отговора обратно през tun. Включването на препращане за целия хост променя и поведението на всичко друго, което маршрутизира през него, затова правилото трябва да посочва източниците и интерфейсите, вместо да приема всичко.
Обратният път се купува с транслация на източника
Интернет хостът няма маршрут до адрес 10.90.0.x, затова отговорите биха били отхвърлени, преди изобщо да достигнат до изхода. Пренаписването на източника, докато пакетът напуска upstream, решава това, а проследяването на връзките обръща пренаписването на връщане.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9 # run on the exit: must point at the tun
Правилото по-горе е отправна точка за един upstream интерфейс, а не firewall политика. Стеснете източника до назначенията, които наистина сте разрешили, и дръжте собствената входна политика на изхода отделна, за да не изложи маскирането за тунелен трафик тихо локални услуги. На хост с динамичен upstream адрес маскирането ви спестява и ръчното проследяване на адреса.
Къде хъбът може и къде не може да наложи правила
С client-to-client и традиционния потребителски път на данните хъбът предава вътрешни пакети между партньорите вътре в сървърния процес. Те никога не преминават през FORWARD веригата на ядрото на хъба, затова правило в ядрото там не може да ограничи транзита между партньори, колкото и внимателно да е написано. Наложението трябва да живее в собствената политика на сървъра: кой има право да се свързва, кой CCD файл получава и дали изобщо се дава подразбиращото се притежание на изхода.
Затова iroute по подразбиране е широко решение за доверие. Изходът трябва законно да приема обратен трафик от произволни интернет адреси и трябва да е машина, която контролирате, обновявате и наблюдавате. Даването на същото притежание на партньор, на когото не бихте дали рутер е грешката, към която този дизайн приканва.
Членството е истинският контрол. Всеки клиент, който може да конфигурира собствените си маршрути, може да опита да използва изхода, затова ограничаването кой може да се свързва или кои партньори изходът ще обслужва е част от дизайна, а не добавка.
Безопасен отказ, когато изходът изчезне
Изключете изхода и вътрешното подразбиращо се притежание изчезва заедно със сесията му. Това, което не бива да се случи, е хъбът тихо да стане заместващ изход: никакъв маршрут по подразбиране от VPN пула към upstream на хъба и никакво широко правило за маскиране на хъба, което с готовност би препратило същия трафик. Тествайте този отказ умишлено, после тествайте възстановяването с нов поток, а не със страница, която вече е била отворена.
# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
Ако трафикът на потребителя все още достига до интернет след изчезването на изхода, нещо друго го носи и границата, която сте имали предвид, не съществува. Отнасяйте се към DNS и IPv6 също като към отделни решения: IPv4 маршрут плюс маскиране не казва нищо за AAAA трафик, а resolver, изпратен от хъба, ще отговаря откъдето заявката действително излиза.