Каманда ping на 192.0.2.10 паведамляе, што адзін адрас адказаў на ICMP-рэха, і больш нічога. У сетцы без тунеля яна можа ўсё роўна прайсці, бо адрас можа знаходзіцца ў лакальнай падсетцы; з здаровым тунелем яна можа праваліцца, бо сервер скідае ICMP, абслугоўваючы HTTPS. Праверка, якая патрэбна вашаму скрыпту, — гэта запыт стану платформы плюс тэст маршруту да прызначэння, якое выкарыстоўвае праграма. Разглядайце іх як два асобныя палі, ніколі як адзін boolean.

Што насамрэч даказвае адказ на рэха

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

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

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

Спытайце Android пра транспарт, а не пра ping

Android адказвае на пытанне стану напрамую праз ConnectivityManager. Магчымасці актыўнай сеткі нясуць сцяг VPN-транспарту, які ўсталёўваецца, калі трафік ідзе праз VPN-інтэрфейс. Выклік лакальны, танны і не залежыць ад таго, ці адказвае які-небудзь аддалены хост.

Гэтая версія на Java вяртае false, а не кідае выключэнне, калі актыўнай сеткі няма. Паколькі яна чытае актыўную сетку, яна адлюстроўвае профіль, які карыстальнік выбраў у Наладах.

ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
NetworkCapabilities caps = cm.getNetworkCapabilities(cm.getActiveNetwork());
boolean tunnel = caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);

Для апавяшчэнняў пра змены зарэгіструйце NetworkCallback замест апытання па таймеры. Не блытайце гэта з VpnService.prepare, які паведамляе толькі, ці дазволіў карыстальнік VPN, а не ці ідуць пакеты. Адкліканне прыходзіць праз VpnService.onRevoke, але забыццё профілю ў Наладах не дае ніякай шырокавяшчальнай рассылкі.

iOS: назвы інтэрфейсаў — эўрыстыка, а не кантракт

Многія фрагменты кода для iOS аглядаюць налады проксі, знаходзяць слоўнік __SCOPED__ і шукаюць ключы інтэрфейсаў накшталт tap, tun, utun2, ppp ці ipsec. Гэты падыход — канвенцыя наймення, а не дакументаваная гарантыя, таму абнаўленне сістэмы, якое пераймянуе інтэрфейс, можа яго зламаць. Ён таксама схільны паведамляць праўду для састарэлых запісаў, якія перажываюць тунель.

Калі канфігурацыяй валодае ваша праграма, NEVPNManager дае сапраўдны стан. Ён апісвае тунель, які запусціла ваша праграма; пры VPN для асобных праграм іншыя праграмы могуць цалкам знаходзіцца па-за гэтым тунелем.

Перазагрузіце налады перад чытаннем стану, бо значэнне змяняецца, пакуль тунель то ўзнікае, то знікае:

let manager = NEVPNManager.shared()
manager.loadFromPreferences { error in
    let up = manager.connection.status == .connected
    print(up)
}

Сцяг стану платформы ўсё яшчэ не даказвае, што трафік дасягае партнёра. Менавіта гэтую прагаліну закрывае тэст маршруту, і таму аднаго boolean недастаткова для падтрымкі.

Профілі Windows паказваюць сапраўднае поле стану

Windows вядзе VPN-профілі асобна ад адаптараў, а Get-VpnConnection паказвае ConnectionStatus для кожнага вядомага профілю. Тут з'яўляюцца профілі, створаныя праз кліент Windows або пакет прадвызначэння. Гэты cmdlet не з'яўляецца ўніверсальным дэтэктарам тунеляў.

Чытайце поле для названага профілю, дадаючы -AllUserConnection, калі профіль належыць усім карыстальнікам:

Get-VpnConnection -Name "Fabrikam" | Select-Object Name, ConnectionStatus, ServerAddress

Кліенты трэціх бакоў часта застаюцца нябачнымі для гэтага cmdlet нават тады, калі іх тунель працуе, таму пусты вынік азначае невядома, а не адключана. Спісы адаптараў гэтак жа падманлівыя: адаптар вытворцы можа заставацца, калі ён бяздзейны, а некаторыя адаптары існуюць толькі падчас сеансу. Для профілю, якім валодае Windows, rasdial паведамляе код выхаду, па якім можна разгалінавацца. Усё гэта апісвае лакальныя ўяўленні, а не дасяжнасць партнёра.

Стан плюс маршрут: праверка з дзвюх частак

Падключаны профіль нічога не кажа пра тое, куды ідуць пакеты. Раздзелены тунель можа трымаць тунель уключаным, выключаючы патрэбнае вам прызначэнне. Профілі Always-on застаюцца падключанымі да мёртвага сервера, а kill switch наўмысна блакуе трафік, калі тунель падае.

Праверце абодва ўзроўні: пераканайцеся, што VPN-транспарт або профіль актыўны, а затым што прызначэнне развязана і адказвае па гэтым шляху. На Linux спытайце ядро, які інтэрфейс яно выкарыстае:

ip route get 192.0.2.10
resolvectl query intranet.example.test

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

Тэст, які можна выканаць па парадку

Спачатку запішыце стан платформы, перш чым змяняць які-небудзь стан сеткі. Развяжыце імя хоста і адзначце сямейства адрасоў, бо запіс AAAA можа ісці іншым шляхам, чым запіс A. Адкрыйце порт паслугі і патрабуйце адказ праграмы, а не проста рукапоціск. Трымайце кожнае назіранне ў асобным полі журнала.

На машыне Linux з dig і curl тры каманды пакрываюць развязанне, маршрут і саму паслугу. Выканайце іх з уключаным тунелем і зноў з выключаным:

dig +short intranet.example.test
ip route get 198.51.100.20
curl -sS -o /dev/null -w "%{http_code}" --max-time 8 https://intranet.example.test/health

Чатыры асобныя палі лепш за адзін boolean, бо стан, DNS, маршрут і палітыка адмаўляюць незалежна і трапляюць да розных каманд. ping у тэрмінале застаецца добрым ручным правяральным тэстам. Для аўтаматызацыі гэта дрэннае азначэнне злучэння, бо там на сапраўднае пытанне адказваюць API платформы і тэст маршруту.

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