/etc/ppp/ip-up ичине route буйругун саласыз, кеңсе туннелин кайра туташтырасыз, бирок файл эч качан аткарылбайт. Скриптте эч кандай кемчилик жок: ал туташуу PPP аркылуу такыр өтпөйт. Курулган Cisco IPSec жана IKEv2 кардарлары pppd-ди эч качан иштетпейт, ошондуктан hook папкасы эч качан окулбайт, ал эми PPTP жана IPSec үстүндөгү L2TP дагы эле андан өтөт. Кайсы учур экенин аныктаңыз, анан PPP эмес учурду launchd көзөмөл тапшырмасынан иштетиңиз.

Каалаган hook-ту оңдоодон мурун интерфейсти текшериңиз

Эки буйрук кайсы механизм иштей аларын чечет. Конфигурацияланган кызматтарды тизмектеңиз, анан туннель күйүп турганда бар интерфейстерди тизмектеңиз. Интерфейстин аты — далил; Система жөндөөлөрүндөгү белги эмес.

scutil --nc list
ifconfig -l | tr ' ' '\n' | grep -E '^(utun|ppp)[0-9]+$'

ppp0 өндүргөн кызмат PPP hook-торун иштетет жана файлыңызды аткарат. Cisco IPSec же IKEv2 кызматы анын ордуна utun түзмөгүн өндүрөт, PPP катмары жок туннель интерфейси, ошондуктан /etc/ppp ичиндеги эч нерсе ага жете албайт. Эки түрү тең көрүнгөндө, кайсы кызматка туташканыңызды текшериңиз. Адамдар кардардын атын окуп, туура эмес hook-ко түштөн кийинки убакытты корот.

PPP жолунда файл root-ко таандык жана аткарылуучу болушу керек, анткени pppd бир нерсени иштетүүдөн мурун экөөнү тең текшерет. install ээсин жана режимин бир кадамда коёт.

sudo install -o root -g wheel -m 0755 /dev/null /etc/ppp/ip-up
sudo ls -l /etc/ppp/ip-up

Finder же графикалык редактор аркылуу түзүлгөн файл көбүнчө сиздин эсебиңизге таандык болот же аткаруу бити жок болот, анан жок hook сыяктуу эле унчукпай ишке ашпайт. Азыр анын жанына ip-down коюңуз. Ээсинин тилкесинде root жана wheel, режим тилкесинде rwxr-xr-x — кереги ушул.

Туннель пайда болгондо launchd скриптти иштетсин

PPP-ге эч качан тийбеген кардарлар үчүн триггер башка жерден келиши керек, ал эми тутумдук конфигурация кампасы — чыныгы булак: macOS аны ар бир туннель өтүүсүндө кайра жазат. Ошол папканы көзөмөлдөгөн launchd тапшырмасы туннель пайда болгондо же жоголгондо чакырылат.

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
  <key>WatchPaths</key>
  <array><string>/Library/Preferences/SystemConfiguration</string></array>
  <key>Label</key><string>net.example.tunnel-watch</string>
  <key>ProgramArguments</key>
  <array><string>/bin/sh</string><string>/usr/local/sbin/tunnel-hook</string></array>
  <key>RunAtLoad</key><true/>
  <key>ThrottleInterval</key><integer>20</integer>
</dict>
</plist>

Аны launch daemon катары орнотуңуз, ар бир колдонуучуга агент катары эмес, анткени маршрутты оңдоо машинага таандык. bootstrap учурдагы чыгарылыштарда эски load -w формасын алмаштырат. RunAtLoad биринчи аткарууну байкоого боло тургандай кылат, ал эми ThrottleInterval Wi-Fi туташуу өзгөрүүлөрүнүн агымы скриптти кайра-кайра иштетишине жол бербейт.

sudo install -o root -g wheel -m 0644 tunnel-watch.plist \
  /Library/LaunchDaemons/net.example.tunnel-watch.plist
sudo launchctl bootstrap system \
  /Library/LaunchDaemons/net.example.tunnel-watch.plist

Тузок — көзөмөлдөнгөн папка VPN-ге тиешеси жок окуялардан да өзгөрөт: Wi-Fi туташуу, DHCP жаңыртуу, кабель сайылуу. Төмөнкү кароолчу чуулдуу триггерди пайдалуу hook-ко айландырат, ал эми журнал сабы бейтааныш сааттагы маршрутту түшүндүрөт.

Ээлик скрипт менен катар plist-ке да тиешелүү. Өз эсебиңиз жаза алган папкадагы файлды аткарган демон ошол эсепке root берет.

Скриптти коргоңуз, экинчи иштетүү эч нерсени өзгөртпөсүн

Скрипт адегенде туннель бар-жогун чечет, жок болсо унчукпай чыгат. Андан кийинкинин баары кайталоого коопсуз болушу керек, анткени триггер бир туташууга караганда алда канча көп иштейт. Кийинки туташууда өзгөрө турган индексти катуу коддоонун ордуна интерфейсти аткаруу учурунда аныктаңыз.

#!/bin/sh
set -u
TUN=$(ifconfig -l | tr ' ' '\n' | grep -m1 '^utun[0-9]' || true)
[ -n "$TUN" ] || exit 0
netstat -rn -f inet | grep -q '^10\.42' && exit 0
route -n add -net 10.42.0.0/16 -interface "$TUN"

route add маршрут мурун эле бар болсо, нөлдөн башка статус менен чыгат, ошондуктан ар бир нөлдөн башка статусту ката деп эсептеген скрипт туура иш кылган сайын сынган hook тууралуу билдирет. Жогорку netstat сынагы бул учурду ачык no-op-ко айландырат.

Интерфейстин бар болушу көрүнгөндөн алсыз далил, анткени башка VPN кардарлары жана кээ бир контейнер чөйрөлөрү да utun түзмөктөрүн түзөт. scutil --nc status "Office VPN" аркылуу кызматтын өзүнөн сураңыз жана маршруттоого тийүүдөн мурун туташкан абалды талап кылыңыз. Жоопту журнал сабында сактаңыз, анткени бир жумадан кийин ошол жазуу сиздин жалгыз түшүндүрмөңүз болот.

DNS-ти бузбай дарбазаны кайтарыңыз

Туннель демейки маршрутту өзүнө алганда, жөнөкөй серептөө кеңсе аркылуу чыгат жана жергиликтүү интернет жолу иштебей калат. Адегенде физикалык интерфейстин роутерин кармап алыңыз, анан демейкини кайра ошого багыттаңыз. DHCP туннелдин өз демейкиси бар таблицаны талдоодон артык.

PHYS=en0
GW=$(ipconfig getoption "$PHYS" router)
[ -n "$GW" ] && sudo route -n change default "$GW"

Чечүүчүлөр өзүнчө куралы бар өзүнчө катмар, ал эми маршрутту оңдоо аларды оңдобойт. scutil --dns аркылуу эмне күчүндө экенин көрүңүз, анан аны жараткан нерсени оңдоңуз: кызматтардын тартиби жана физикалык кызматтагы DNS жазуулары. Кэшти тазалоо тармак алмашкандан кийин тыгылып калган издөөнү диагностикалайт; аны пландаштыруунун кереги жок.

Wi-Fi өзгөрүүсүнөн аман өтүп, бирок DNS тыгылып калган туннель — үчүнчү бузук: sudo killall -HUP mDNSResponder чечүүчүнү конфигурациясын кайра окууга мажбурлайт. Аны бир жолу, кол менен колдонуңуз.

Тапшырма өзү иштээрин далилдеңиз

Көзөмөл жолуна ишенүүдөн мурун kickstart -k аркылуу бир иштетүүнү мажбурлаңыз, анан тапшырма жазган чыгуу статусун окуңуз. Таза чыгуу скрипттин иштээрин далилдейт; триггердин иштээрин далилдебейт. Анан тапшырма жүктөлгөн абалда ажыратып кайра туташтырыңыз жана сиз сурабаган иштетүүнү байкаңыз.

sudo launchctl kickstart -k system/net.example.tunnel-watch
sudo launchctl print system/net.example.tunnel-watch | grep -E 'last exit code|state ='

Ар бир аракеттен мурун жана кийин scutil --nc status текшериңиз. Туннель өчүп турганда иштеген скрипт туташуу жолу жөнүндө эч нерсени далилдебейт.

Ажыратуу бутагы туташуу бутагы сыяктуу эле камкордукка татыктуу: маршрутту кол менен алып салыңыз, тапшырма иштешине жол бериңиз жана анын кайра келерин ырастаңыз. Маршрут кошуп, аны эч качан албаган hook бир жумадан кийин туура эмес иштеген машинаны калтырат, ал эми эки окуяны эч нерсе байланыштырбайт. Эки жүрүм-турум тең сакталса, sudo launchctl bootout system/net.example.tunnel-watch тапшырманы таза түрдө пенсияга чыгарат. Жүктөлгөн бойдон калтырылган көзөмөл демону — бир жолку оңдоонун айлардан кийин түшүндүрүлбөгөн маршрутка айлануу жолу.

Тектеш макалалар