Mac-VPN tilkoblet, men ip-up kjørte aldri: sett opp en launchd-overvåking
Cisco IPSec- og IKEv2-tunneler starter aldri pppd, så /etc/ppp/ip-up forblir stille. Overvåk konfigurasjonsmappen og la skriptet bevise tunnelen.
Du legger en route-kommando i /etc/ppp/ip-up, kobler til kontortunnelen på nytt, og filen kjøres aldri. Det er ingenting galt med skriptet: den tilkoblingen går ikke gjennom PPP i det hele tatt. De innebygde Cisco IPSec- og IKEv2-klientene starter aldri pppd, så hook-mappen leses aldri, mens PPTP og L2TP over IPSec fortsatt går gjennom den. Finn ut hvilket tilfelle du har, og utløs deretter ikke-PPP-tilfellet fra en launchd-overvåkingsjobb.
Kontroller grensesnittet før du redigerer noen hook
To kommandoer avgjør hvilken mekanisme som kan virke. List de konfigurerte tjenestene, og list deretter grensesnittene som finnes mens tunnelen er oppe. Grensesnittnavnet er beviset; etiketten i Systeminnstillinger er det ikke.
scutil --nc list
ifconfig -l | tr ' ' '\n' | grep -E '^(utun|ppp)[0-9]+$'
En tjeneste som produserer ppp0 kjører PPP-hookene og vil kjøre filen din. En Cisco IPSec- eller IKEv2-tjeneste produserer i stedet en utun-enhet, et tunellgrensesnitt uten PPP-lag, så ingenting inne i /etc/ppp kan nå den. Når begge slagene dukker opp, sjekk hvilken tjeneste du koblet til. Folk kaster bort en ettermiddag på feil hook ved å lese klientnavnet.
På PPP-veien må filen eies av root og være kjørbar, fordi pppd sjekker begge før den kjører noe. install setter eier og modus i ett trinn.
sudo install -o root -g wheel -m 0755 /dev/null /etc/ppp/ip-up
sudo ls -l /etc/ppp/ip-up
En fil som lages via Finder eller en grafisk editor havner ofte eid av kontoen din, eller uten kjørebiten, og feiler da like stille som hooken som manglet. Legg ip-down ved siden av den nå. root og wheel i eierkolonnen pluss rwxr-xr-x i moduskolonnen er det du vil ha.
La launchd utløse skriptet når en tunnel dukker opp
For klienter som aldri berører PPP, må utløseren komme fra et annet sted, og systemkonfigurasjonslageret er den ærlige kilden: macOS skriver det på nytt ved hver tunellovergang. En launchd-jobb som overvåker den mappen, kalles når en tunnel dukker opp eller forsvinner.
<?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>
Installer den som en launch-daemon, ikke som en agent per bruker, fordi ruteutbedring hører til maskinen. bootstrap erstatter den eldre load -w-formen på gjeldende utgivelser. RunAtLoad gjør den første kjøringen observerbar, og ThrottleInterval hindrer at en byge av Wi-Fi-tilkoblinger starter skriptet om og om igjen.
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
Fellen er at den overvåkede mappen endres også for hendelser uten noe med VPN-en din å gjøre: en Wi-Fi-tilkobling, en DHCP-fornyelse, en kabel som settes i. Vakten nedenfor gjør en støyende utløser om til en brukbar hook, og en logglinje forklarer en rute på et merkelig tidspunkt.
Eierskap dekker plist så vel som skriptet. En daemon som kjører en fil i en mappe din egen konto kan skrive i, gir den kontoen root.
Vern skriptet slik at en ny kjøring ikke endrer noe
Skriptet avgjør først om tunnelen finnes, og avslutter stille når den ikke gjør det. Alt etterpå må være trygt å gjenta, fordi utløseren fyrer mye oftere enn én enkelt tilkobling. Løs opp grensesnittet ved kjøring i stedet for å hardkode en indeks som endres ved neste tilkobling.
#!/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 avslutter med ikke-null status når ruten allerede finnes, så et skript som behandler enhver ikke-null status som feil, rapporterer en ødelagt hook hver gang det gjør det riktige. netstat-testen ovenfor gjør det tilfellet om til en eksplisitt no-op.
Tilstedeværelsen av grensesnittet er svakere bevis enn det ser ut, fordi andre VPN-klienter og enkelte containermiljøer også lager utun-enheter. Spør tjenesten selv med scutil --nc status "Office VPN" og krev den tilkoblede tilstanden før du rører rutingen. Ta vare på svaret i en logglinje, for en uke senere er den registreringen den eneste forklaringen du har.
Hent gatewayen tilbake uten å ødelegge DNS
Når tunnelen overtar standardruten, går vanlig surfing ut gjennom kontoret, og den lokale internettveien slutter å virke. Fang den fysiske grensesnittets ruter først, og pek deretter standardruten tilbake på den. DHCP slår å parse en tabell som allerede inneholder tunellens egen standardrute.
PHYS=en0
GW=$(ipconfig getoption "$PHYS" router)
[ -n "$GW" ] && sudo route -n change default "$GW"
Resolverne er et eget lag med et eget verktøy, og å reparere ruten reparerer dem ikke. Se med scutil --dns hva som gjelder, og rett deretter det som lager det: tjenesterekkefølgen og DNS-oppføringene på den fysiske tjenesten. Å tømme hurtigbufferen diagnostiserer et oppslag som henger etter et nettverksbytte; det er ikke noe å planlegge.
En tunnel som overlever et Wi-Fi-bytte mens DNS står stille, er en tredje feil: sudo killall -HUP mDNSResponder får resolveren til å lese konfigurasjonen sin på nytt. Bruk den én gang, for hånd.
Bevis at jobben fyrer av seg selv
Tving fram én kjøring med kickstart -k før du stoler på overvåkingsveien, og les deretter utgangsstatusen jobben registrerte. En ren utgang beviser at skriptet virker; det beviser ikke at utløseren virker. Koble deretter fra og til igjen med jobben lastet, og se etter en kjøring du ikke ba om.
sudo launchctl kickstart -k system/net.example.tunnel-watch
sudo launchctl print system/net.example.tunnel-watch | grep -E 'last exit code|state ='
Sjekk scutil --nc status før og etter hvert forsøk. Et skript som kjørte mens tunnelen var nede, beviser ingenting om tilkoblingsveien.
Nedrivningsgrenen fortjener samme behandling som tilkoblingsgrenen: fjern ruten for hånd, la jobben kjøre, og bekreft at den kommer tilbake. En hook som legger til en rute og aldri fjerner den, etterlater en maskin som oppfører seg dårlig en uke senere, uten at noe forbinder de to hendelsene. Når begge atferdene holder, pensjonerer sudo launchctl bootout system/net.example.tunnel-watch jobben rent. En overvåkingsdaemon som blir stående lastet, er måten en engangsreparasjon blir en uforklart rute måneder senere.