Poses una ordre route a /etc/ppp/ip-up, tornes a connectar el túnel de l’oficina i el fitxer no s’executa mai. Amb l’script no hi ha res malament: aquesta connexió no passa per PPP de cap manera. Els clients integrats Cisco IPSec i IKEv2 no inicien mai pppd, així que el directori de ganxos no es llegeix mai, mentre que PPTP i L2TP sobre IPSec encara hi passen. Esbrina quin cas tens i després dispara el cas no-PPP des d’una feina de vigilància launchd.

Comprova la interfície abans d’editar cap ganxo

Dues ordres decideixen quin mecanisme pot funcionar. Llista els serveis configurats i després llista les interfícies que existeixen mentre el túnel és actiu. El nom de la interfície és la prova; l’etiqueta a Configuració del Sistema no ho és.

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

Un servei que produeix ppp0 executa els ganxos PPP i executarà el teu fitxer. Un servei Cisco IPSec o IKEv2 produeix en canvi un dispositiu utun, una interfície de túnel sense capa PPP, així que res dins de /etc/ppp no hi pot arribar. Quan apareixen tots dos tipus, comprova a quin servei t’has connectat. La gent perd una tarda al ganxo equivocat perquè llegeix el nom del client.

Al camí PPP el fitxer ha de ser propietat de root i executable, perquè pppd comprova les dues coses abans d’executar res. install fixa propietari i mode en un sol pas.

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

Un fitxer creat amb el Finder o un editor gràfic sovint acaba sent propietat del teu compte, o sense el bit d’execució, i llavors falla tan silenciosament com el ganxo que faltava. Posa ip-down al seu costat ara. root i wheel a la columna de propietari més rwxr-xr-x a la columna de mode és el que vols.

Deixa que launchd dispari l’script quan aparegui un túnel

Per als clients que no toquen mai PPP, el disparador ha de venir d’un altre lloc, i el magatzem de configuració del sistema és la font honesta: macOS el reescriu a cada transició de túnel. Una feina launchd que vigila aquell directori es crida quan un túnel apareix o desapareix.

<?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>

Instal·la’l com a dimoni launch, no com a agent per usuari, perquè la reparació de rutes pertany a la màquina. bootstrap substitueix la forma antiga load -w a les versions actuals. RunAtLoad fa observable la primera execució i ThrottleInterval evita que una allau de canvis de connexió Wi-Fi llancí l’script repetidament.

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

La trampa és que el directori vigilat canvia per esdeveniments que no tenen res a veure amb la teva VPN: una connexió Wi-Fi, una renovació DHCP, un cable endollat. El guardià de sota converteix un disparador sorollós en un ganxo utilitzable, i una línia de registre explica una ruta a una hora estranya.

La propietat cobreix el plist igual que l’script. Un dimoni que executa un fitxer en un directori on el teu compte pot escriure lliura root a aquell compte.

Protegeix l’script perquè una segona execució no canviï res

L’script primer decideix si el túnel existeix i surt en silenci quan no. Tot el que ve després ha de ser segur de repetir, perquè el disparador s’activa molt més sovint que una sola connexió. Resol la interfície en temps d’execució en lloc de codificar un índex que canvia a la connexió següent.

#!/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 surt amb estat no zero quan la ruta ja hi és, així que un script que tracta cada estat no zero com a error informa d’un ganxo trencat cada vegada que fa el correcte. La prova amb netstat de dalt converteix aquest cas en un no-op explícit.

La presència de la interfície és una prova més feble del que sembla, perquè altres clients VPN i alguns entorns de contenidors també creen dispositius utun. Pregunta al mateix servei amb scutil --nc status "Office VPN" i exigeix l’estat connectat abans de tocar l’encaminament. Guarda la resposta en una línia de registre, perquè una setmana després aquest registre serà l’única explicació que tindràs.

Recupera la passarel·la sense trencar el DNS

Quan el túnel assumeix la ruta per defecte, la navegació normal surt per l’oficina i el camí local a internet deixa de funcionar. Captura primer l’encaminador de la interfície física i després apunta-hi la ruta per defecte. DHCP supera l’anàlisi d’una taula que ja conté la ruta per defecte pròpia del túnel.

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

Els resolutors són una capa separada amb una eina separada, i reparar la ruta no els repara. Mira què està en vigor amb scutil --dns i després arregla què ho produeix: l’ordre de serveis i les entrades DNS del servei físic. Buidar la memòria cau diagnostica una consulta encallada després d’un canvi de xarxa; no és una cosa per programar.

Un túnel que sobreviu a un canvi de Wi-Fi mentre el DNS s’atura és una tercera fallada: sudo killall -HUP mDNSResponder fa que el resolutor rellegeixi la seva configuració. Fes-lo servir un cop, a mà.

Demostra que la feina es dispara sola

Força una execució amb kickstart -k abans de confiar en el camí de vigilància i després llegeix l’estat de sortida que la feina ha registrat. Una sortida neta demostra que l’script funciona; no demostra que el disparador funcioni. Després desconnecta i torna a connectar amb la feina carregada i vigila una execució que no has demanat.

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

Comprova scutil --nc status abans i després de cada intent. Un script que va córrer mentre el túnel estava caigut no demostra res sobre el camí de connexió.

La branca de desmuntatge mereix el mateix tracte que la branca de connexió: treu la ruta a mà, deixa córrer la feina i confirma que torna. Un ganxo que afegeix una ruta i no la treu mai deixa una màquina que es comporta malament una setmana després, sense res que connecti els dos esdeveniments. Quan tots dos comportaments es mantenen, sudo launchctl bootout system/net.example.tunnel-watch retira la feina netament. Un dimoni de vigilància deixat carregat és com una reparació d’un sol cop es converteix en una ruta inexplicada mesos després.

Articles relacionats