Пълен тунел на OpenVPN прекъсва SSH сесията ви: оправете пътя на отговора
Маршрутът по подразбиране изпраща SSH отговорите в тунела. Заковайте партньора, филтрирайте redirect-gateway или маршрутизирайте по източник, преди да загубите машината.
Включването на клиент на OpenVPN с пълен тунел на машина, до която стигате по SSH, може да прекъсне сесията за секунда, а машината не прави нищо нередно. Тунелът не променя как пакетите стигат до сървъра; той променя как отговорите излизат. Щом маршрутът по подразбиране сочи към tun0, отговорът към вашия SSH клиент влиза в мрежата на доставчика, която няма маршрут обратно към вашия адрес. Връзката увисва, следващият опит изтича, а демонът през цялото време слуша на порт 22.
Прочетете таблицата за маршрутизация, преди да четете лога на VPN. Логът ще каже, че тунелът е вдигнат, и е прав. Въпросът е на кой интерфейс се предава всеки отговор, а това е търсене за всеки пакет в таблица, която тунелът току-що е пренаписал.
Защо отговорът излиза през грешната врата
Входящите пакети все още пристигат на физическия интерфейс, защото VPN клиент не може да промени как интернет стига до публичния адрес на вашия сървър. Отговорите са отделно решение: за всеки пакет ядрото търси дестинацията и след --redirect-gateway записът по подразбиране казва тунел. Изходът на доставчика вижда дестинация, която не обслужва, и изхвърля пакета.
Собствената защита на OpenVPN покрива точно една дестинация. Ръководството за 2.6 описва --redirect-gateway като последователност: добавя хост маршрут за VPN партньора през шлюза, използван преди тунела, за да не може криптираният трафик да се върне в себе си, и след това заменя маршрута по подразбиране. Този хост маршрут е само за партньора. Вашият SSH клиент е просто още един интернет адрес и не получава изключение.
Една грешка с префикс си струва да се изключи рано. Командата ip route add -net 0.0.0.0 gw 10.8.0.1 dev tun0 без дължина съвпада с единичния адрес 0.0.0.0, а не с интернет; трябва да бъде 0.0.0.0/0. И ако приемането на маршрута по подразбиране счупи собствения транспорт на тунела, добавете крайната точка като хост маршрут през физическия интерфейс, използвайки реалния адрес на доставчика.
Заковайте адреса на SSH клиента си за незабавно поправяне
Най-бързото поправяне е хост маршрут за адреса на вашия клиент през шлюза, който сървърът е използвал преди тунела. От ваша страна намерете адреса, който сървърът ще види, после прочетете таблицата на сървъра, за да знаете стария шлюз:
curl -s https://ifconfig.co
ip route
На сървъра добавете изключението преди клиентът да стартира. Адресите тук са заместители; формата е важна:
sudo ip route add 80.128.240.55 via 192.168.178.1
Това е поправката, използвана в докладвания случай, и работи веднага. Тя е и крехка по два предвидими начина: маршрутът изчезва при рестарт и става грешен в момента, в който доставчикът ви даде друг адрес. Отнасяйте се към нея като към аварийна мярка и я направете трайна умишлено, чрез мрежова единица или hook на диспечера, или приемете, че е временна, и запишете пътя за възстановяване.
Спрете клиента да вземе маршрута по подразбиране
По-чистият вариант е тунелът изобщо да не заменя маршрута по подразбиране. route-nopull, използван с --client или --pull, приема изпратените опции с изключение на маршрути, block-outside-dns и опции от тип DHCP като DNS сървъри, така че добавяте само префиксите, които ви трябват. По-тесен инструмент е филтър за изтегляне, който отхвърля една проблемна директива и запазва останалите:
route-nopull
pull-filter ignore "redirect-gateway"
Използвайте едното или другото, не и двете, и бъдете наясно какво се променя. Без маршрут по подразбиране през тунела сървърът вече не сърфира интернет през доставчика; той стига само до това, което сте маршрутизирали изрично. Ако пълният тунел беше целият смисъл на настройката, това е грешният ключ и хост маршрутът по-горе е правилният.
Разделете обратния път по източник или по връзка
Когато входящият адрес е стабилен, правило по източник пази отговорите локални, без да пипа маршрутите на самия тунел. Дайте на адреса на физическия интерфейс собствена таблица с LAN префикса и физическия маршрут по подразбиране, после избирайте тази таблица за трафик, който идва от него:
ip rule add from 192.168.1.11 table 128
ip route add table 128 to 192.168.1.0/24 dev eth0
ip route add table 128 default via 192.168.1.1
Това работи, защото отговорите на входяща SSH връзка изхождат от адреса, към който клиентът се е свързал. Докладван случай, в който всяка входяща услуга трябваше да продължи да работи, използва точно тази форма. Когато входящият адрес плава или пътят е динамичен, маркирайте връзката вместо това: сложете conntrack марка на първия пакет, пристигащ от физическия интерфейс, копирайте я върху пакетите отговор в OUTPUT и маршрутизирайте маркираните пакети през таблица, сочеща към физическия шлюз.
iptables -t mangle -A PREROUTING -i eth0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1234
iptables -t mangle -A OUTPUT -m connmark --mark 1234 -j MARK --set-mark 4321
ip route add default via 192.168.1.1 dev eth0 table 3412
ip rule add fwmark 4321 table 3412
Пазете марката на връзката, марката на защитната стена и номера на таблицата различни по време на теста. Повторното използване на един номер за две роли дава правило, което изглежда правилно и съвпада с грешните пакети. Записът по подразбиране на таблицата също изисква via с LAN шлюза при обикновена Ethernet връзка; гол запис dev eth0 работи само когато интерфейсът е точка-точка или следващият хоп се решава по друг начин. Докладваният хост Jessie случайно се оказа на връзка, където голата форма работеше, което не е правило за дистрибуция, което да се копира.
Проверете, без да се заключите отвън
Не тествайте чрез прекъсване. Дръжте първата сесия отворена, вдигнете тунела и попитайте ядрото кой път ще поеме вашият адрес:
ip route get 80.128.240.55
Отговорът трябва да назове физическия интерфейс и стария шлюз, не тунела. После отворете втора SSH връзка; това е истинският тест, защото старата сесия може да оцелее на състояние, което нова връзка не може да възпроизведе. Ако втората увисне, докато първата още отговаря, правилото така и не е съвпаднало с важния трафик и трябва да търсите в марките или в адреса на източника.
Дръжте извънлентова конзола на разположение през цялото упражнение. Сървър, чийто единствен път за достъп е тунелът, който току-що счупихте, не може да се поправи през този тунел, а връщането назад е по-лесно, когато сте записали номерата на таблиците и префиксите, които сте добавили.