VPN на Mac е свързан, но ip-up не се задейства: пуснете наблюдение с launchd
Тунелите на Cisco IPSec и IKEv2 никога не стартират pppd, затова /etc/ppp/ip-up остава тих. Наблюдавайте папката с конфигурацията и накарайте скрипта да докаже тунела.
Слагате команда route в /etc/ppp/ip-up, свързвате отново офисния тунел и файлът така и не се изпълнява. Със скрипта нищо не е наред: тази връзка изобщо не минава през PPP. Вградените клиенти Cisco IPSec и IKEv2 никога не стартират pppd, затова папката с куките не се чете, докато PPTP и L2TP през IPSec все още минават през нея. Определете кой случай е вашият и след това задействайте не-PPP случая от задача за наблюдение на launchd.
Проверете интерфейса, преди да редактирате каквато и да е кука
Две команди решават кой механизъм може да работи. Изброете конфигурираните услуги, след това изброете интерфейсите, които съществуват, докато тунелът е активен. Името на интерфейса е доказателството; етикетът в Системни настройки не е.
scutil --nc list
ifconfig -l | tr ' ' '\n' | grep -E '^(utun|ppp)[0-9]+$'
Услуга, която създава ppp0, изпълнява PPP куките и ще изпълни вашия файл. Услуга Cisco IPSec или IKEv2 създава вместо това устройство utun, тунелен интерфейс без PPP слой, така че нищо в /etc/ppp не може да го достигне. Когато се появят и двата вида, проверете към коя услуга сте се свързали. Хората губят следобед на грешната кука, защото четат името на клиента.
По 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 или графичен редактор, често се оказва собственост на вашия акаунт или без бит за изпълнение и после се проваля толкова тихо, колкото липсващата кука. Сложете 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 демон, а не като агент за отделен потребител, защото поправката на маршрути принадлежи на машината. 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, включен кабел. Пазачът по-долу превръща шумния сигнал в използваема кука, а ред в журнала обяснява маршрут в странен час.
Собствеността покрива 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 излиза с ненулев статус, когато маршрутът вече съществува, така че скрипт, който приема всеки ненулев статус за грешка, съобщава счупена кука всеки път, когато прави правилното. Тестът с 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 преди и след всеки опит. Скрипт, който е работил, докато тунелът е бил спрян, не доказва нищо за пътя на свързване.
Клонът за разглобяване заслужава същото отношение като клона за свързване: премахнете маршрута на ръка, оставете задачата да работи и потвърдете, че се връща. Кука, която добавя маршрут и никога не го премахва, оставя машина, която след седмица се държи зле, без нищо да свързва двете събития. Когато и двете поведения се държат, sudo launchctl bootout system/net.example.tunnel-watch оттегля задачата чисто. Оставен зареден демон за наблюдение е начинът, по който еднократна поправка става необяснен маршрут месеци по-късно.