Démarrer un VPN Mac enregistré depuis le terminal avec scutil --nc
Utilisez scutil --nc pour démarrer, inspecter et arrêter un service VPN macOS enregistré, gardez les identifiants hors d’argv et prouvez que le trafic utilise réellement le tunnel.
Vous avez un service VPN enregistré dans Réglages Système, et vous voulez que le terminal le démarre. Sur macOS, le chemin pris en charge est scutil --nc, mais uniquement pour les services que possède le gestionnaire de connexions réseau du système lui-même. La barre de menus n’est pas l’API : les clients tiers ont généralement leur propre automatisation, et un profil poussé par un service de gestion peut refuser un démarrage local. Voici la liste de contrôle que j’applique : trouvez le service exact, lisez son état, démarrez-le, attendez que l’état change, puis prouvez que le trafic utilise réellement le tunnel. Arrêtez-vous à la première étape qui ne concorde pas, car chaque commande suivante suppose que la précédente a réussi.
Trouvez le service avant d’essayer de le démarrer
Commencez par l’inventaire plutôt que par le nom de profil dont vous vous souvenez :
scutil --nc help
scutil --nc list
Chaque ligne associe un état à un identifiant de service, un type et un nom d’affichage. L’identifiant est la valeur sur laquelle on écrit des scripts, car les noms d’affichage se répètent et peuvent être modifiés. Le manuel scutil d’Apple documente le mode de connexion réseau, tandis que le --nc help installé est la liste faisant autorité des sous-commandes sur ce Mac ; ne supposez pas qu’un indicateur d’un ancien guide existe encore dans votre version de macOS.
Une liste vide est un résultat, pas une erreur. Un service créé par un client fournisseur ou un profil de gestion peut être actif alors qu’il est invisible ici, ou visible avec un type que le contrôleur natif ne peut pas piloter. Dans ce cas, utilisez l’outil du fournisseur ou la documentation du profil. Créer un profil natif parallèle juste pour avoir quelque chose à démarrer est un mauvais marché.
Lisez l’état actuel et confirmez le sélecteur
Interrogez le service avant de le démarrer, afin de savoir ce qu’un démarrage réussi devrait changer :
scutil --nc status "Office VPN"
Si deux services partagent un nom d’affichage, le nom est ambigu. Passez plutôt l’identifiant ; la commande accepte l’un ou l’autre, mais seul l’identifiant garantit de sélectionner un seul service. Vérifiez que le mot d’état est l’un de ceux que vous connaissez — généralement Connected, Disconnected, Connecting ou Disconnecting — avant de l’analyser dans un script. Vérifiez aussi si le profil est géré, car une configuration verrouillée peut accepter la commande et malgré tout l’ignorer ou demander une confirmation.
Cet appel d’état est peu coûteux, utilisez-le donc comme garde dans l’automatisation : ne démarrez que lorsque l’état est Disconnected, et ne traitez pas Connecting comme un échec. Si le service est déjà Connected, sautez le démarrage plutôt que d’interrompre un tunnel qui fonctionne.
Démarrez la connexion et attendez que l’état se stabilise
La demande de démarrage est asynchrone. La commande revient lorsque la demande a été acceptée, pas lorsque l’authentification est terminée ou que les routes sont installées. Exécutez-la, puis interrogez l’état avec une attente bornée et sortez si le service retombe sur Disconnected :
scutil --nc start "Office VPN"
n=0
while [ "$n" -lt 30 ]; do
state=$(scutil --nc status "Office VPN" | head -n 1)
[ "$state" = "Connected" ] && break
[ "$state" = "Disconnected" ] && { echo "start failed"; exit 1; }
sleep 2
n=$((n + 1))
done
Un état Connecting qui ne se résout jamais indique généralement des identifiants, MFA ou le serveur, pas scutil. La commande ne peut pas fournir de connexion interactive, donc un profil qui attend un jeton ou une clé matérielle restera en Connecting et finira par retomber. Lisez le mot d’état avant d’ajouter des tentatives ; une boucle face à une invite d’authentification ne peut pas réussir.
Ne traitez pas le code de sortie du shell comme une disponibilité. Le signal utile est la chaîne d’état, suivie de la preuve que le tunnel transporte du trafic. Une commande de démarrage qui revient silencieusement peut encore vous laisser avec une connexion qui ne s’authentifie jamais.
Prouvez que le tunnel transporte du trafic, pas seulement qu’il dit Connected
Connected décrit la connexion, pas la décision de routage. Les services natifs PPP et IKEv2 créent une interface ppp ou utun et installent des routes, tandis qu’un tunnel divisé laisse délibérément la route par défaut intacte. Inspectez les interfaces et les deux familles d’adresses :
ifconfig -l
netstat -rn -f inet
netstat -rn -f inet6
scutil --dns
Trouvez l’interface que le service a créée au lieu de deviner un numéro, puis demandez à la table de routage quelle interface une destination précise utilise : route -n get 10.0.0.10, en le remplaçant par un hôte interne. S’il indique l’interface physique, le tunnel est actif mais ne transporte pas ce flux. Vérifiez les routes du tunnel divisé, l’ordre des résolveurs et toute règle de pare-feu locale qui autorise l’interface du tunnel mais pas le processus.
La résolution de noms est le faux négatif habituel. Les noms internes peuvent se résoudre via le mauvais résolveur alors que le tunnel est parfaitement sain, ce qui ressemble à une panne VPN et n’en est pas une. scutil --dns montre l’ordre que macOS utilisera ; après un changement de résolveur, videz le cache avec dscacheutil -flushcache et sudo killall -HUP mDNSResponder.
Gardez les identifiants et les privilèges hors de la ligne de commande
Ne mettez jamais un mot de passe, une clé pré-partagée ou un jeton dans les arguments. Les arguments sont visibles dans les listes de processus et finissent dans l’historique du shell, et une transcription de support copiée peut les divulguer. La gestion des identifiants propre au profil — qu’il s’agisse d’un élément Keychain, d’une invite système ou du flux d’authentification du client — est l’endroit pour les secrets.
Exécuter la commande avec sudo ne rend pas une connexion interactive non supervisée. Cela change l’utilisateur effectif, pas la disponibilité d’une invite GUI, d’un jeton matériel ou du trousseau de connexion. Un LaunchAgent peut démarrer un service après que l’utilisateur s’est connecté et que le trousseau est déverrouillé ; un LaunchDaemon n’atteint généralement pas ces éléments de la session utilisateur. Si une organisation gère le service, ses règles de cycle de vie l’emportent sur tout script local.
Arrêtez le service et vérifiez qu’il est resté arrêté
Arrêtez avec le même sélecteur que celui utilisé pour démarrer, puis relisez l’état au lieu de supposer que le tunnel a disparu :
scutil --nc stop "Office VPN"
scutil --nc status "Office VPN"
Un arrêt qui revient à Disconnected laisse encore une chose à vérifier : si le profil est réglé pour se connecter à la demande, ce qui peut le ramener sans votre script. Si un autre client possède des routes sur le même Mac, ces routes peuvent survivre à un arrêt natif. Revérifiez la route avant de conclure que la machine est hors du VPN.
Pour un wrapper que vous exécutez à la main, gardez l’ordre fixe : liste, état, démarrage, interrogation, test de route, arrêt, vérification. N’analysez pas le nom convivial à partir d’une sortie libre lorsque l’identifiant est disponible, et ne traitez pas la sortie de la commande de démarrage comme une disponibilité. Le gestionnaire de connexions rapporte l’état ; votre preuve est l’état plus une route qui pointe vers le tunnel.