Somewhere in a deploy script there is a check for whether the tunnel is up before a copy starts. Three answers are available, and they do not mean the same thing: the service state that scutil reports, the route the kernel selected, and whether the far end actually replies. Comparing them is the difference between a check that predicts the copy and one that only decorates a log.

Three answers to "is the VPN up?"

The service state is a control-plane fact. macOS knows that a configuration is connected because its client process said so. The route is a data-plane fact: the kernel will send this destination through that interface. Reachability is an end-to-end fact, and it can fail for reasons neither of the other two sees.

SignalAnswersBlind spot
scutil --nc statusIs the service connected?Third-party clients, wrong routes
route -n getWhere would this go?The peer may be down
A request to the far sideDoes it work now?Slow, and it changes state

A useful check combines the first two and uses the third as the confirmation that the other two were not lying. Any one alone is a guess with a timestamp.

Read the identifier, not the display name

scutil --nc list
scutil --nc status "Office"

The listing prints one line per service, and each line carries a parenthesised status followed by the service identifier, the type, and the display name. Script against the identifier, because the display name is what someone typed into System Settings and can change without notice. The status command prints a single word followed by statistics for some service types; match that first word rather than searching the whole output for the name, which also appears elsewhere.

Starting a service can raise an authorization prompt or be refused outright when the profile is managed. That refusal is not a fault in the tunnel; it is a policy statement about who may bring it up.

A third-party client hides from the list

An empty list does not mean there is no VPN. Configurations created inside the system's own network settings appear here; a vendor client, a management profile, or a third-party app can hold an active tunnel that this command never sees. Its own tool is the authority for its own service. Asking scutil about a client that never registered with it returns nothing, and nothing is not the same answer as disconnected.

When the list is empty but traffic is clearly encrypted, look for the interface instead: a utun or ppp device with an address in the expected range is evidence that something established a tunnel. That is a weaker signal than a service state, so pair it with a route check rather than treating the interface as proof of identity. Several clients can create several such interfaces, and only one of them belongs to the tunnel you meant.

Status is not routing

A connected service says the tunnel exists. It does not say that your destination uses it. Read the addresses, then ask the kernel directly:

ifconfig | grep -A4 utun
netstat -rn -f inet
route -n get 10.40.0.20

A full-tunnel client installs a default route through the tunnel; a split-tunnel client installs specific private prefixes. Both report Connected, and a script that checks only the status will happily run over the wrong path. Stopping a tunnel does not necessarily remove routes that another client installed, which is one way a machine ends up with a connected service and a stale route at the same time. Look at the destination you care about, not at the route table as a whole.

Naming is a separate problem

Other machines cannot reach the Mac by name while its address works, and that gets reported as a VPN fault. The local host name, the host name, and the DNS record are three different things. scutil --get LocalHostName shows the Bonjour name; sudo scutil --set HostName mac-office sets the name the system reports.

Neither setting creates a record in the office zone. If other hosts have to resolve the name through DNS, the zone owner must add it, or the script should use the address instead. Setting a stable name makes announcements consistent; it does not make the resolver answer.

Record the service identifier and the expected route shape together in the script, and check both before the copy. A tunnel that is up and routed the wrong way fails exactly like no tunnel at all, and the log line that says Connected will send the next person looking in the wrong place.

פֿאַרבונדענע אַרטיקלען