Кліент VPN падключаецца, браўзер працуе, а тая адзіная каманда, якая вам сапраўды патрэбна, па-ранейшаму выходзіць праз ваша хатняе злучэнне. Або адбываецца адваротнае: тунель захоплівае маршрут па змаўчанні, і лакальны файлавы сервер знікае з працоўнага стала. Я сутыкнуўся з гэтым на агент зборкі, якому трэба было дасягнуць унутранага люстэрка артэфактаў, пакуль астатні хост заставаўся ў офіснай LAN, і кліент прапанаваў роўна два выбары: увесь трафік або нічога. Запыт у абодва бакі адзін і той жа: гэтая праграма, а не ўся машына, і ў большасці кліентаў няма для яго сцяжка, бо табліца маршрутызацыі ніколі не ведала, што такое праграма.

Чаму табліца маршрутызацыі не бачыць вашу праграму

Калі працэс адпраўляе пакет, стек шукае адрас прызначэння ў табліцы маршрутызацыі. Ні імя выконваемага файла, ні порт не ўдзельнічаюць у гэтым пошуку. Дамейныя імёны не спрацоўваюць па той жа прычыне: тунель нясе трафік да адраса, і да таго часу, як імя ператвараецца ў адрас, маршрутызацыя — адзіны рычаг, які ядро яшчэ мае. Вось чаму «VPN толькі для гэтага сайта» ў рэшце рэшт азначае проксі, а «VPN толькі для гэтай праграмы» — адзін з невялікага набору механізмаў.

MechanismWhat selectsCoversOn tunnel drop
Socket bindsource addressa client you controlconnections fail
UID rule (Linux)owning userevery process of one accountconnections fail
Firewall profile (Windows)adapter profileone programfails closed
Network namespacenamespace membershipeverything started insideconnections fail
SOCKS hopapp proxy settingone app or one browser profileconnections fail

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

Адзіная мэта — гэта ўсё яшчэ маршрут, а не правіла праграмы. На macOS звычайны рэцэпт — зняць «Адпраўляць увесь трафік праз VPN» і дадаць маршрут да хоста: sudo route add -host internal-tuner.example -interface ppp0, выдаляецца зноў праз sudo route delete -host internal-tuner.example -interface ppp0. Спачатку прачытайце імя інтэрфейса з ifconfig, бо ppp0 — толькі прыклад. Шаблоны не працуюць у маршруце да хоста, таму сэрвіс, які звяртаецца да некалькіх імёнаў, патрабуе па аднаму запісу на імя, а правіла ахоплівае кожны працэс на машыне, а не той, які вы мелі на ўвазе.

Прывязаць сокет да адраса тунеля

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

import socket
s = socket.socket()
s.bind(("10.8.0.2", 0))
s.connect(("build.internal.example", 443))

Інструменты вышэйшага ўзроўню прапануюць тую ж ідэю: curl --interface 10.8.0.2, CURLOPT_INTERFACE у PHP і аргумент source_address у HTTP-кліентах Python. Адрас павінен належаць тунелю, і друкарская памылка тут выглядае як звычайная памылка злучэння, а не як скарга на маршрутызацыю. Прывязка да імя прылады замест адраса — гэта прывілей Linux і не пераносіцца на Windows або macOS, таму пераносныя скрыпты перадаюць адрас.

Linux: супастаўляйце ўладальніка, а не імя праграмы

Ядро можа супаставіць карыстальніка-ўладальніка сокета, таму выдзелены ўліковы запіс становіцца сродкам выбару. Змясціце тунель у асобную табліцу маршрутызацыі і накіруйце туды трафік толькі гэтага ўліковага запісу:

ip rule add uidrange 1001-1001 lookup 100
ip route add default dev tun0 table 100

Гэта працуе, толькі калі тунель ужо не з’яўляецца маршрутам па змаўчанні. Запусціце кліент з --route-nopull або адфільтруйце праштурханае перанакіраванне з дапамогай --pull-filter ignore "redirect-gateway" на OpenVPN 2.4 і пазней, потым дадайце запіс табліцы самі. Інакш існуюць абодва маршруты па змаўчанні, і перамагае той, у якога прыярытэт ніжэй. Свядомая версія гэтага — накіраваць маршрут па змаўчанні на шлюз тунеля або зрабіць гэта са скрыпта адключэння: гэта трымае трафік па-за інтэрнэтам, калі тунель падае, але гэта выключальнік, а не сродак выбару, і ён застаецца, пакуль хтосьці яго не выдаліць.

Мацнейшая версія — сеткавая прастора імёнаў. Стварыце яе, запусціце кліент унутры і запусціце праграму з ip netns exec. Нішто па-за прасторай імёнаў не бачыць інтэрфейс тунеля, таму праграма не можа выпадкова вярнуцца да маршруту хоста. Кошт рэальны: прасторы імёнаў патрэбна пара veth для доступу да фізічнай сеткі і ўласны файл рэзалвера, бо прастора імёнаў мантавання не падзяляе налады развязання хоста.

Два рэжымы адмовы тлумачаць большасць уцечак. Развязанне імёнаў па-ранейшаму адбываецца ў рэзалверы хоста, таму запыт выходзіць па-за тунель, нават калі злучэнне TCP ідзе ўнутр. І IPv6 патрабуе ўласнага ip -6 rule, бо правіла v4 яго не ахоплівае.

Windows і macOS: абмяжуйце міжсеткавы экран або аддайце проксі

У Windows таксама няма сродку выбару маршруту для асобнай праграмы, але яго правілы міжсеткавага экрана можна абмежаваць профілем, а адаптар VPN можна аднесці да «Публічнага», пакуль хатняя LAN застаецца «Прыватнай». Стварыце правілы блакіроўкі зыходнага трафіку для праграмы ў профілях «Прыватны» і «Дамэнны», пакіньце «Публічны» адкрытым, і праграма зможа дасягаць сеткі толькі праз тунель. Спачатку задайце сеткавую катэгорыю злучэння, потым пацвердзіце, што правіла супала на панэлі маніторынгу міжсеткавага экрана. Гэта блакіроўка, а не маршрут: яна адмаўляе пры падзенні тунеля і не можа спыніць праграму, якая ігнаруе міжсеткавы экран.

macOS ідзе па той жа логіцы з іншымі інструментамі. Слухач SOCKS, дасяжны праз SSH, — найменш інвазіўны варыянт, бо ssh -D 1080 user@host стварае адзін лакальны порт, і толькі праграмы, наладжаныя на яго, ідуць гэтым шляхам. Правіла pf можа заблакаваць праграму па карыстальніку або групе, але ўсё яшчэ не можа выбраць тунель для гэтай праграмы асобна. Tunnelblick зусім не ўмее фільтраваць па дамене, бо маршруты працуюць з адрасамі; карыстальнікі OpenConnect бяруць vpn-slice, калі сервер праштурхвае занадта шырокі спіс прэфіксаў.

Два абыходныя шляхі пакрываюць тое, што прапускаюць інструменты платформы. Пашырэнні браўзера, якія перамыкаюць проксі па дамене, — практычны адказ для «толькі гэты сайт», бо яны дзейнічаюць на ўзроўні праграмы, дзе імёны яшчэ існуюць; яны ахопліваюць адзін браўзер і больш нічога. Грубы варыянт — запусціць кліент пастаўшчыка ў віртуальнай машыне, каб госць валодаў змяненнем маршруту, а хост захоўваў свой шлях, коштам двух сеткавых стэкаў у абслугоўванні.

Пераскок SOCKS для інструментаў без магчымасці прывязкі

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

ssh -N -D 127.0.0.1:9999 [email protected]

Усё, што наладжана на гэты порт, выходзіць на бастыёне, пакуль астатні працоўны стол захоўвае звычайнае злучэнне. Лакальны асобнік 3proxy, прывязаны да адраса тунеля, робіць тое ж для аднаго порта без SSH, а stunnel ахоплівае адзін порт, абгорнуты TLS. Абмежаванні практычныя: проксі нясе толькі пратаколы, якія ўмеюць ім карыстацца, UDP патрабуе асацыяцыі SOCKS5 UDP, якую налада «SOCKS5» у многіх кліентах не ўключае, а DNS павінен развязвацца праз проксі (socks5h у curl), інакш імя ўцячэ да лакальнага рэзалвера.

Трымайце слухач на вяртальнай пятлі, пакуль ён не патрэбны іншай машыне.

Правярайце шлях перахопам, а не паведамленнем аб стане

Вокны стану праграмы апісваюць наладу, а не пакет. Перахапіце на абодвух інтэрфейсах і параўнайце:

tcpdump -i any -n port 443
ss -tnp | grep 443

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

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

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