Du lægger en route-kommando i /etc/ppp/ip-up, genopretter forbindelsen til kontortunnelen, og filen kører aldrig. Der er intet galt med scriptet: den forbindelse går slet ikke gennem PPP. De indbyggede Cisco IPSec- og IKEv2-klienter starter aldrig pppd, så hook-mappen læses aldrig, mens PPTP og L2TP over IPSec stadig går gennem den. Find ud af, hvilket tilfælde du har, og udløs derefter ikke-PPP-tilfældet fra et launchd-overvågningsjob.

Kontrollér grænsefladen, før du redigerer en hook

To kommandoer afgør, hvilken mekanisme der kan virke. List de konfigurerede tjenester, og list derefter de grænseflader, der findes, mens tunnelen er oppe. Grænsefladens navn er beviset; etiketten i Systemindstillinger er det ikke.

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

En tjeneste, der frembringer ppp0, kører PPP-hooks og vil udføre din fil. En Cisco IPSec- eller IKEv2-tjeneste frembringer i stedet en utun-enhed, en tunnelgrænseflade uden PPP-lag, så intet inde i /etc/ppp kan nå den. Når begge slags dukker op, så tjek, hvilken tjeneste du har forbundet til. Folk spilder en eftermiddag på den forkerte hook ved at læse klientnavnet.

På PPP-vejen skal filen ejes af root og være eksekverbar, fordi pppd tjekker begge dele, før noget køres. install sætter ejer og tilstand i ét trin.

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

En fil, der oprettes via Finder eller en grafisk editor, ender ofte som ejet af din konto eller uden eksekveringsbit, og fejler så lige så tavst som den manglende hook. Læg ip-down ved siden af den nu. root og wheel i ejerkolonnen plus rwxr-xr-x i tilstandskolonnen er, hvad du vil have.

Lad launchd starte scriptet, når en tunnel dukker op

For klienter, der aldrig rører PPP, skal udløseren komme fra et andet sted, og systemkonfigurationslageret er den ærlige kilde: macOS omskriver det ved hver tunnelovergang. Et launchd-job, der overvåger den mappe, kaldes, når en tunnel dukker op eller forsvinder.

<?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 det som en launch-daemon, ikke som en agent pr. bruger, fordi ruteudbedring hører til maskinen. bootstrap erstatter den ældre load -w-form på nuværende udgivelser. RunAtLoad gør den første kørsel observerbar, og ThrottleInterval forhindrer, at et stormløb af Wi-Fi-tilslutninger starter scriptet igen og igen.

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

Fælden er, at den overvågede mappe ændrer sig ved hændelser uden relation til din VPN: en Wi-Fi-tilslutning, en DHCP-fornyelse, et kabel, der sættes i. Værgen nedenfor gør en støjende udløser til en brugbar hook, og en loglinje forklarer en rute på et mærkeligt tidspunkt.

Ejerskab dækker plist såvel som script. En daemon, der udfører en fil i en mappe, din egen konto kan skrive i, giver den konto root.

Beskyt scriptet, så en anden kørsel ikke ændrer noget

Scriptet afgør først, om tunnelen findes, og afslutter stille, når den ikke gør. Alt derefter skal være sikkert at gentage, fordi udløseren fyrer langt oftere end en enkelt forbindelse. Slå grænsefladen op ved kørsel i stedet for at hardkode et indeks, der ændrer sig ved næste forbindelse.

#!/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 afslutter med ikke-nul status, når ruten allerede findes, så et script, der behandler enhver ikke-nul status som fejl, rapporterer en brækket hook hver gang, det gør det rigtige. netstat-testen ovenfor gør det tilfælde til en eksplicit no-op.

Tilstedeværelsen af grænsefladen er et svagere bevis, end det ser ud, fordi andre VPN-klienter og nogle container-miljøer også opretter utun-enheder. Spørg tjenesten selv med scutil --nc status "Office VPN" og kræv den forbundne tilstand, før du rører routingen. Gem svaret i en loglinje, for en uge senere er den registrering den eneste forklaring, du har.

Hent gatewayen tilbage uden at ødelægge DNS

Når tunnelen overtager standardruten, forlader almindelig browsing kontoret, og den lokale internetvej holder op med at virke. Fang den fysiske grænseflades router først, og peg derefter standardruten tilbage på den. DHCP slår at parse en tabel, der allerede indeholder tunnelens egen standardrute.

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

Resolverne er et separat lag med et separat værktøj, og at reparere ruten reparerer dem ikke. Se med scutil --dns, hvad der er gældende, og ret derefter det, der frembringer det: tjenesterækkefølgen og DNS-posterne på den fysiske tjeneste. At tømme cachen diagnosticerer et opslag, der hænger efter et netværksskift; det er ikke noget, man planlægger.

En tunnel, der overlever et Wi-Fi-skift, mens DNS står stille, er en tredje fejl: sudo killall -HUP mDNSResponder får resolveren til at læse sin konfiguration igen. Brug den én gang, i hånden.

Bevis, at jobbet fyrer af sig selv

Tving én kørsel med kickstart -k, før du stoler på overvågningsvejen, og læs derefter den exitstatus, jobbet har registreret. En ren exit beviser, at scriptet virker; det beviser ikke, at udløseren virker. Afbryd derefter og tilslut igen med jobbet indlæst, og hold øje med en kørsel, du ikke har bedt om.

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

Tjek scutil --nc status før og efter hvert forsøg. Et script, der kørte, mens tunnelen var nede, beviser intet om forbindelsesvejen.

Nedrivningsgrenen fortjener samme behandling som forbindelsesgrenen: fjern ruten i hånden, lad jobbet køre, og bekræft, at det kommer tilbage. En hook, der tilføjer en rute og aldrig fjerner den, efterlader en maskine, der opfører sig dårligt en uge senere, uden at noget forbinder de to begivenheder. Når begge adfærdsmønstre holder, pensionerer sudo launchctl bootout system/net.example.tunnel-watch jobbet rent. En overvågningsdaemon, der lades indlæst, er måden, hvorpå en engangsreparation bliver en uforklaret rute måneder senere.

Relaterede artikler