VPN do Mac conectada pero ip-up nunca se disparou: executa unha vixilancia launchd
Os túneles Cisco IPSec e IKEv2 nunca inician pppd, así que /etc/ppp/ip-up queda en silencio. Vixía o directorio de configuración e fai que o script demostre o túnel.
Pos un comando route en /etc/ppp/ip-up, volves conectar o túnel da oficina e o ficheiro nunca se executa. Co script non hai nada mal: esa conexión non pasa por PPP en absoluto. Os clientes integrados Cisco IPSec e IKEv2 nunca inician pppd, así que o directorio de ganchos nunca se le, mentres que PPTP e L2TP sobre IPSec seguen pasando por el. Descubre que caso tes e despois dispara o caso non-PPP desde un traballo de vixilancia launchd.
Comproba a interface antes de editar calquera gancho
Dous comandos deciden que mecanismo pode funcionar. Lista os servizos configurados e despois lista as interfaces que existen mentres o túnel está activo. O nome da interface é a proba; a etiqueta en Configuración do Sistema non o é.
scutil --nc list
ifconfig -l | tr ' ' '\n' | grep -E '^(utun|ppp)[0-9]+$'
Un servizo que produce ppp0 executa os ganchos PPP e executará o teu ficheiro. Un servizo Cisco IPSec ou IKEv2 produce no seu lugar un dispositivo utun, unha interface de túnel sen capa PPP, así que nada dentro de /etc/ppp pode alcanzalo. Cando aparecen ambos os tipos, comproba a que servizo te conectaches. A xente perde unha tarde no gancho equivocado por ler o nome do cliente.
Na ruta PPP o ficheiro debe pertencer a root e ser executable, porque pppd comproba ambas as cousas antes de executar nada. install fixa propietario e modo nun só paso.
sudo install -o root -g wheel -m 0755 /dev/null /etc/ppp/ip-up
sudo ls -l /etc/ppp/ip-up
Un ficheiro creado co Finder ou un editor gráfico a miúdo acaba sendo propiedade da túa conta, ou sen o bit de execución, e entón falla tan silenciosamente como o gancho ausente. Pon ip-down ao seu carón agora. root e wheel na columna de propietario máis rwxr-xr-x na columna de modo é o que queres.
Deixa que launchd dispare o script cando apareza un túnel
Para os clientes que nunca tocan PPP, o disparador debe vir doutro sitio, e o almacén de configuración do sistema é a fonte honesta: macOS reescríbeo en cada transición de túnel. Un traballo launchd que vixía ese directorio é chamado cando un túnel aparece ou desaparece.
<?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>
Instálao como daemon launch, non como axente por usuario, porque a reparación de rutas pertence á máquina. bootstrap substitúe a forma antiga load -w nas versións actuais. RunAtLoad fai observable a primeira execución, e ThrottleInterval evita que unha morea de cambios de conexión Wi-Fi lance o script repetidamente.
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
A trampa é que o directorio vixiado cambia por eventos que non teñen nada que ver coa túa VPN: unha conexión Wi-Fi, unha renovación DHCP, un cable enchufado. O gardián de abaixo converte un disparador ruidoso nun gancho utilizábel, e unha liña de rexistro explica unha ruta a unha hora estraña.
A propiedade cobre o plist tanto como o script. Un daemon que executa un ficheiro nun directorio onde a túa propia conta pode escribir entrégalle root a esa conta.
Protexe o script para que unha segunda execución non cambie nada
O script primeiro decide se o túnel existe e sae en silencio cando non. Todo o posterior debe ser seguro de repetir, porque o disparador actívase moito máis a miúdo que unha soa conexión. Resolve a interface en tempo de execución en lugar de codificar un índice que cambia na seguinte conexión.
#!/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 sae con estado distinto de cero cando a ruta xa existe, así que un script que trata cada estado distinto de cero como fallo informa dun gancho roto cada vez que fai o correcto. A proba con netstat de arriba converte ese caso nun no-op explícito.
A presenza da interface é unha proba máis feble do que parece, porque outros clientes VPN e algúns ambientes de contedores tamén crean dispositivos utun. Pregunta ao propio servizo con scutil --nc status "Office VPN" e esixe o estado conectado antes de tocar o encamiñamento. Garda a resposta nunha liña de rexistro, porque unha semana despois ese rexistro será a única explicación que teñas.
Recupera a pasarela sen romper o DNS
Cando o túnel asume a ruta predeterminada, a navegación normal sae pola oficina e a ruta local a internet deixa de funcionar. Captura primeiro o router da interface física e despois apunta a predeterminada de volta a el. DHCP supera a analizar unha táboa que xa contén a predeterminada propia do túnel.
PHYS=en0
GW=$(ipconfig getoption "$PHYS" router)
[ -n "$GW" ] && sudo route -n change default "$GW"
Os resolvedores son unha capa aparte cunha ferramenta aparte, e reparar a ruta non os repara. Mira que está en vigor con scutil --dns e despois corrixe o que o produce: a orde de servizos e as entradas DNS do servizo físico. Baleirar a caché diagnostica unha consulta atascada tras un cambio de rede; non é algo que se programme.
Un túnel que sobrevive a un cambio de Wi-Fi mentres o DNS se atasca é un terceiro fallo: sudo killall -HUP mDNSResponder fai que o resolvedor relea a súa configuración. Úsao unha vez, a man.
Demostra que o traballo se dispara só
Forza unha execución con kickstart -k antes de confiar na ruta de vixilancia e despois le o estado de saída que rexistrou o traballo. Unha saída limpa demostra que o script funciona; non demostra que funcione o disparador. Despois desconecta e volve conectar co traballo cargado e observa unha execución que non pediches.
sudo launchctl kickstart -k system/net.example.tunnel-watch
sudo launchctl print system/net.example.tunnel-watch | grep -E 'last exit code|state ='
Comproba scutil --nc status antes e despois de cada intento. Un script que se executou mentres o túnel estaba caído non demostra nada sobre a ruta de conexión.
A rama de desmontaxe merece o mesmo trato que a rama de conexión: quita a ruta a man, deixa que o traballo se execute e confirma que volve. Un gancho que engade unha ruta e nunca a quita deixa unha máquina que se comporta mal unha semana despois, sen nada que conecte os dous sucesos. Cando ambos os comportamentos se manteñen, sudo launchctl bootout system/net.example.tunnel-watch retira o traballo limpiamente. Un daemon de vixilancia deixado cargado é como unha reparación puntual se converte nunha ruta inexplicada meses despois.