Размяшчэнне другога кліента OpenVPN на адным хосте Linux правальваецца ў адным з двух месцаў. Або ўнутраны кліент не можа дасягнуць свайго сервера, бо знешні тунель захапіў гэты транспарт, або другі кліент перапісвае табліцу маршрутаў і першы тунель перастае працаваць. Абедзве праблемы ў маршрутызацыі, а не ў шыфраванні, і абедзве вырашаюцца да таго, як новы тунель пачне перадаваць трафік праграм. Адрасы тут ілюстратыўныя: tun0 — знешні тунель, 203.0.113.9 — унутраны сервер, а TCP 9999 — патоку, якая павінна ісці ўнутраным шляхам.

Два рэжымы збою, адна табліца маршрутаў

Унутраны кліент адкрывае UDP-сокет да свайго сервера, і гэты сокет ідзе па бягучай табліцы маршрутаў, як любы іншы. Калі знешні тунель ужо валодае маршрутам па змаўчанні, пакеты рукапоціску трапляюць у знешні тунель. Гэта працуе толькі тады, калі знешні сервер можа дасягнуць унутранага сервера і той бок згаджаецца несці патоку; інакш рукапоціск спыняецца і кліент паўтарае спробу.

Другі збой прыходзіць ад push сервера. Звычайны push — гэта redirect-gateway def1, які ўсталёўвае 0.0.0.0/1 і 128.0.0.0/1 замест замены маршруту па змаўчанні. Таму два кліенты, якія кожны ўсталёўвае сваю пару /1, сутыкаюцца, і найноўшая пара перамагае амаль для любога пункту прызначэння. Шукайце гэтыя два прэфіксы ў табліцы, калі тунель гіне пасля падключэння другога, бо сам маршрут па змаўчанні мог ніколі не змяніцца.

Пазначце патоку і дайце ёй табліцу

Кіруйце выбраным трафікам, пазначыўшы яго ў табліцы mangle і супаставіўшы пазнаку ў палітычным правіле. Правіла паказвае на асобную табліцу, маршрут па змаўчанні якой — унутраная прылада, таму ўнутраным шляхам ідуць толькі пазначаныя пакеты.

iptables -t mangle -A PREROUTING -p tcp -m multiport --dport 9999 -j MARK --set-mark 0x9999
ip rule add fwmark 0x9999 table 200 pref 1000
ip route add default dev tun1 table 200

Большасць збояў у гэтым наборы правілаў паходзіць з дзвюх памылак. Значэнне пазнакі, якое ставіць файрвол, і значэнне, якое супастаўляе правіла, павінны быць аднолькавымі, бо неадпаведнасць не дае ні памылкі, ні эфекту. А PREROUTING бачыць толькі пакеты, што прыходзяць звонку, таму злучэнню, пачатаму на гэтым хосце, патрэбна правіла OUTPUT з такім жа супастаўленнем, перш чым яго наогул пазначаць.

Забярыце ўладанне маршрутамі ў другога кліента

Дзве опцыі не даюць другому кліенту рэдагаваць табліцу, і яны дзейнічаюць у розных пунктах. route-nopull ігнаруе прапанаваныя опцыі маршрутаў, таму нічога не ўсталёўваецца. route-noexec прымае прапанаваныя опцыі ў асяроддзе кліента, але пакідае змену табліцы для hook, што якраз патрэбна, калі трэба ўбачыць, што прапанаваў сервер.

Hook працуе з прапанаванымі значэннямі ў сваім асяроддзі і павінен дадаваць толькі тыя запісы, якія вы ўхвалілі. Зрабіце яго ідэмпатэнтным: ачышчайце табліцу, якой ён валодае, перад перабудовай і не дапускайце, што папярэдні запуск пакінуў чысты стан. Перападключэнне выклікае hook зноў, і hook, які дадае без ачысткі, назапашвае дублікаты маршрутаў.

Выберыце аднаго ўладальніка і запішыце яго. Профіль, які задае абедзве опцыі, або hook, што канкуруе з ручным скрыптам, стварае табліцу, якую ніхто не зможа растлумачыць потым.

Закрэпіце абедзве адрасы сервераў

Унутранаму серверу патрэбны маршрут да хоста праз знешнюю прыладу да таго, як унутраны кліент падключыцца. Менавіта гэты запіс трымае ўнутраны транспарт унутры знешняга тунеля замест таго, каб дазволіць яму ісці па змаўчанні.

ip route add 203.0.113.9/32 dev tun0
ip route get 203.0.113.9

Дадайце такі ж маршрут да хоста для знешняга сервера ў асноўную табліцу, інакш перападключэнне можа накіраваць уласны транспарт знешняга кліента ў яго ж тунель. Парадак не па выбары: дадавайце гэтыя запісы пасля таго, як адпаведны інтэрфейс існуе, гэта значыць праз hook або скрыпт, які запускаецца пасля падключэння. Маршрут, што паказвае на выключаную прыладу, выдаляецца або ігнаруецца, таму запіс, зроблены пры загрузцы, не перажыве паслядоўнасць, якую вы меркавалі.

Правярайце вынік пошуку замест чытання ўсёй табліцы. Вывад пошуку маршруту называе прыладу і адрас крыніцы, якія выкарыстае ядро, — менавіта гэта атрымлівае кліент, калі адкрывае свой сокет.

Праверце ланцуг і зрабіце збой бачным

Захоплівайце на знешнім інтэрфейсе, пакуль унутраны кліент падключаецца. Унутраны рукапоціск павінен выглядаць як шыфраваная нагрузка ўнутры знешняга тунеля; калі ён выглядае як звычайны UDP да 203.0.113.9, маршруту да хоста няма і ланцуг ніколі не быў пабудаваны.

Ланцуг, што моўчкі вяртаецца на фізічны ўзыходны канал, — найгоршы вынік, бо стан інтэрфейса нічога не абвяшчае і ўнутраны трафік выходзіць з няправільнага адрасу крыніцы. Калі другі кліент можа падключыцца напрамую, калі знешні тунель падае, адключыце гэты шлях або прывяжыце яго да знешняга інтэрфейса, каб збой быў бачны.

Скончыце двума патокамі і адным дампам правілаў: пазначанае злучэнне і непазначанае павінны ісці рознымі шляхамі, а ip rule show павінна паказаць прыярытэт, які вы мелі на ўвазе. Калі абедзве патоку ідуць адным шляхам, пазнака не ўжываецца там, дзе вы думаеце.

Падобныя артыкулы