How to check if the mac is connected to VPN

Asifahmed
New Contributor III

How can I find if any connected to VPN? Is it dependent on app to find it, like as for Cisco AnyConnect and Pulse it will be different. Or any generic way is there in macOS?

 

17 REPLIES 17

sdagley
Esteemed Contributor II

@Asifahmed One common way that's used to determine if a Mac is on an institutional network, not necessarily VPN, is to look up the IP address of a known host and see if the result is for the internal versus external network (or it may be an address that doesn't resolve externally). Looking specifically for a VPN connection being active is trickier because there is no single mechanism that will identify if a VPN client has an active tunnel.

junjishimazaki
Valued Contributor

I use an EA to know whether the computer is connected to the VPN. This EA displays the DNS server when it is connected to the VPN.

#!/bin/bash

echo "<result>$(/opt/cisco/anyconnect/bin/vpn stats | grep "Client Address (IPv4):" | awk '{print $4}')</result>"

exit 0

AJPinto
Esteemed Contributor

A VPN should have a predictable IP range, looking for computers within that range should be sufficient for 99.9% of cases. Beyond that, you need to look in to what options your specific VPN client has to gather this information. 

cdev
Contributor III

Depending on how far down the rabbit hole you want to go (and whether you want to detect VPN on the client-side or from Jamf), you can play with some different things:

  • ifconfig - simple terminal command to report all network interfaces. Most VPN tools show up under the utun interfaces. Might take some trial and error to figure-out which one is the VPN.
  • Network Segments - whomever if managing your VPN should know what IP range ties to your VPN and you can add this range to Jamf to be able to limit-to or exclude VPN devices
  • VPN client - Cisco AnyConnect (and others) have a command-line interface you can query on the client. For Cisco, these commands can give you some info: 
    • /opt/cisco/anyconnect/bin/vpn stats
    • /opt/cisco/anyconnect/bin/vpn state

easyedc
Valued Contributor II

In the days we used Pulse as a VPN, it was easy to query scutil and check for any virtual NICs created (like from a vpn...). So that's what I did. If you're Pulse it may just work for you out of the box or you may have to tweak it. 

 

#!/bin/bash

#  VPN IP.sh
#  
#
#  Created by Corfman, Ed on 6/3/21.
#
## Get the current Network information with a system configuration command
VPNlink=$( /usr/sbin/scutil --nwi )

## Parse the system configuration information for the utun2 entry
pulseIP=$( /usr/sbin/scutil --nwi | /usr/bin/sed -n 5p | /usr/bin/awk '{ print $NF }' )

## Parse the Network information and search for the Pulse VPN connection via utun2 entry
if [[ "$VPNlink" == *"utun"* ]]; then
echo "<result>$pulseIP</result>"
exit 0

else
echo "<result>Pulse Secure VPN is not connected</result>"
fi
exit 0

 

Asifahmed
New Contributor III

Thanks

@easyedc Thanks for the helpful post. I was wondering if I could modify this for Cisco AnyConnect in the same manner, not sure if you've had anyone run that question out to you since Cisco is in most IT infrastructures?

I'll play around with your script and see if I can get it to work regarding Cisco VPN (AnyConnect).

easyedc
Valued Contributor II

I don't really know much about AnyConnect, other than it exists. I've never been in an organization that uses it.  Using the same scutil command now 

/usr/sbin/scutil --nwi

Doesn't provide a tunneled IP address, so it's all a matter of how Cisco operates. I'm currently using Zscaler (which is an always on VPN) it just spits out my current IP address on my home network. It doesn't get a unique VPN Address, as a result this is less helpful than it was in the past.

 

howie_isaacks
Valued Contributor III

Thanks! Your post helped me. I created this after seeing your script.

#!/bin/bash

:<<EXTENSION_ATTRIBUTE
-----------------------------------
Checks if a Mac is on the corporate LAN (onsite) or offsite based on which network interface is the 
default interface. Network interfaces starting with "en" or anything other than "utun" are
onsite. "utun" indicates that the Mac is connected to VPN.

3/26/2025 | Howie Canterbury
-----------------------------------
EXTENSION_ATTRIBUTE

checkGPStatus() {
	gpStatus=$(scutil --nwi | grep "Network interfaces:" | awk '{print $3}')
	case $gpStatus in
		utun* )
			status="Offsite"
		;;
		en* )
			status="Onsite"
		;;
	esac
}

# Run network interface check
checkGPStatus

# Report result
if [ "$status" = "Offsite" ]; then
echo "<result>Offsite</result>"
elif [ "$status" = "Onsite" ]; then
echo "<result>Onsite</result>"
fi

AVmcclint
Honored Contributor

Just wanted to leave my solution specifically for Cisco Secure Client. I don't have a Cisco AnyConnect client to test this, but it just might if you change the path to the command.

#!/bin/bash

# Check if the Cisco Secure Client VPN is active
vpn_status=$(/opt/cisco/secureclient/bin/vpn status | egrep -o "state: (Connected|Reconnecting)")

# If you have Cisco AnyConnect, you can try this path instead. I have not tested this.
# vpn_status=$(/opt/cisco/anyconnect/bin/vpn status | egrep -o "state: (Connected|Reconnecting)")

if [ -n "$vpn_status" ]; then
    echo "Cisco VPN is active."
else
    echo "No active Cisco VPN connection."
fi

I had to also search for "Reconnecting" since that also was an indication that a connection was going on. 

michael_madsen
Contributor

How about this?

#!/bin/bash
vpn=$(scutil --nc list | grep VPN | grep Connected)
vpnConnected=false
if [ "$vpn" != "" ]; then
    vpnConnected=true
fi
echo "vpn: $vpn"
echo "vpnConnected: $vpnConnected"

michael_madsen
Contributor

Just remember that an Extension Attribute is only updated on every inventory update. It may not make a lot of sense to reflect whether someone is connected to VPN in an Extension Attribute, since it will (probably) show something wrong most of the time (unless you run jamf recon often) 😉

Of course! I wrote my EA mainly to test on a larger number of Macs than just my production Mac and test Macs. The EA does no harm running during inventory. It just reports if the Mac is in the office (onsite) or on VPN (offsite). There's a broader purpose. I included a lot of that code in another script that I created for running packet traces while a Jamf policy is running. We have had a lot of issues with packages failing to download when policies that contain an installer package payload are running. I needed to be able to know if the Mac was connected to our office network at the time or if it was connected over VPN remotely. Now I can easily distinguish between the two scenarios. I can have the script run the packet trace through the interface used by Global Protect for offsite Macs and have it run the trace through which ever interface it's using (ethernet or WiFi) if it's in the office. It appears that Global Protect is not permitting all Jamf Pro activity, and it is causing packages to fail to download. The packet traces will help prove that.

sdagley
Esteemed Contributor II

@howie_isaacks You might also check to see if a user is logged in when you see downloads failing in your policies.

howie_isaacks
Valued Contributor III

They are. I got confirmation that Global Protect is causing the issue. We are working on making sure that the Jamf agent is allowed to do what it needs to do fully. I pointed out that this never happens until Global Protect gets installed. This is why our provisioning process never has failed installs. Global Protect is installed last.

sdagley
Esteemed Contributor II

Is the problem something Palo Alto Networks has acknowledged is an issue in GP, or something in how your org has GP configured? And if the former, what version(s) exhibit the problem?

howie_isaacks
Valued Contributor III

It’s how we have it configured. I’m all for security. You should see how paranoid I have my home network setup! What I’m not for is GP interfering with important functionality. Since we know what is causing the issue it can be fixed. This has been a learning experience and it also proved me right that the issue was not on Jamf’s side. I knew this from the start.