# Work Around An Always-On VPN on macOS (Global Protect Edition)
> ⚠️ **This trick will undo itself after 5 minutes** as Global Protect resets routes automatically.
> ❌ This is meant to unblock **very temporarily** you for things like finding out your real latency or debugging network issues. Remember that your company's IT team uses Global Protect's MITM for good reasons. You should have Global Protect enabled at all times.
IT might require an always-on VPN on your Mac. It is sometimes useful to disable it for a time, e.g., to check your real latency or to diagnose network issues.
What the always-on VPN does is that it creates a catch-all route, and all traffic goes to the `utun0` interface which gets routed to the VPN's gateway:
```console
$ netstat -rn | head
Destination Gateway Flags Netif
default 10.220.43.57 UGScg utun0 <- cuplrit
default 192.168.1.1 UGScIg en8
```
## TL;DR
```bash
#!/bin/bash
#
# Remember that GlobalProtect will reset these changes after a few minutes.
#
set -euo pipefail
vpn_if=$(ifconfig utun0 | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}')
if route get default "$vpn_if" 2>&1 | grep -vq "not in table"; then
sudo route delete default "$vpn_if"
fi
if route get "0/2" "$vpn_if" 2>&1 | grep -vq "not in table"; then
sudo route delete "0/2" "$vpn_if"
fi
# phys_if=$(netstat -rn -f inet | grep '^default' | awk '{print $4}' | grep -v utun | head -1 || en13)
phys_ifs=$(for iface in $(networksetup -listallhardwareports | awk '/Device/ { print $2 }'); do
if ifconfig "$iface" 2>&1 | grep -q "status: active"; then
echo "$iface"
fi
done)
# dig +short clouddocsdev.s3-website-us-west-2.amazonaws.com @10.220.30.1 | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' |
# xargs -I@ sudo route add @ "$vpn_if"
for phys_if in $phys_ifs; do
sudo route add default "$(ifconfig "$phys_if" | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}')"
done
if ! scutil < <(echo $'open\nget State:/Network/Global/DNS\nd.show') | grep cyber-ark.com; then
echo "cyber-ark.com is already in DNS search domains"
else
vpn_id=$(scutil < <(echo $'open\nget State:/Network/Global/DNS\nd.show') | grep __CONFIGURATION_ID__ | awk '{print $4}')
sudo scutil <<EOF
open
d.init
d.add ServerAddresses * 8.8.8.8
set State:/Network/Global/DNS
set State:/Network/Service/$vpn_id/DNS
set State:/Network/Service/gpd.pan/DNS
quit
EOF
fi
```
## Workaround: What does this script do?
To work around the VPN, all you have to do is replace this route with a catch-all route routing everything to your physical networking card. In my example, that's `en8` with the gateway IP 192.168.1.1.
So, all I have to do is to remove the utun0 route:
```bash
sudo route delete default 10.220.43.57
```
And replace it with my NIC's interface and gateway:
```bash
sudo route add default 192.168.1.1
```
The top-level default route is now your network interface card (in my case, `en8` is an ethernet adapter):
```
$ netstat -rn | head
Destination Gateway Flags Netif
default 192.168.1.1 UGScg en8 <- no longer MITM'ed!
default 192.168.1.1 UGScIg en8
```
Let's check that the traffic no longer goes through `utun0`:
```
$ route get google.fr
route to: mad01s26-in-f163.1e100.net
destination: default
mask: default
gateway: 192.168.1.1
interface: en8
flags: <UP,GATEWAY,DONE,STATIC,PRCLONING,IFSCOPE,GLOBAL>
```
Yes!
And if you wonder how to undo these changes, click "Refresh Connection":

## Split Tunnelling: Selectively Forward to the VPN
Some internal sites can only be accessed from the VPN's gateway IPs. For these, I wrote a tool to help me calculate the biggest CIDR from a list of IPs:
```bash
go install github.com/maelvls/cidrcalc@latest
```
For example:
```console
$ cidrcalc -hostname foo.s3-website-us-west-2.amazonaws.com -debug
debug: Resolved IPs for foo.s3-website-us-west-2.amazonaws.com: [52.92.251.99 52.92.179.115 52.92.225.163 52.92.208.171 52.92.153.179 52.92.193.203 52.92.239.51 52.92.149.107]
52.92.128.0/17
```
Thus, the biggest CIDR is 52.92.128.0/17. I can now configure a route to make sure these IPs are routed through the VPN:
```bash
vpn_ip=$(ifconfig utun0 | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}')
sudo route delete default $vpn_ip
sudo route add default 192.168.1.1
sudo route add $(cidrcalc -hostname foo.s3-website-us-west-2.amazonaws.com) $vpn_ip
```
With that, I can access the internal site https://foo.s3-website-us-west-2.amazonaws.com.
## Does it stay that way forever?
No. Global Protect regularly refreshes the connection every few minutes after which your changes will be undone.
## DNS
First, find the `State:` string that corresponds to your VPN:
```bash
scutil <<< list | grep DNS | awk '{print $4}' \
| xargs -L1 -I@ sh -c "echo @; sudo scutil <<< $'open\nget @\nd.show'"
```
In my case, it was this one:
```text
State:/Network/Service/FABE6D8F-7603-40A7-A232-9A041DF24C17/DNS
<dictionary> {
SearchDomains : <array> {
}
ServerAddresses : <array> {
0 : 10.220.43.1
}
ServiceIdentifier : 2
SupplementalMatchDomains : <array> {
0 :
}
}
```
Thus, you can do:
```bash
sudo scutil <<EOF
open
d.init
d.add ServerAddresses * 8.8.8.8
set State:/Network/Service/FABE6D8F-7603-40A7-A232-9A041DF24C17/DNS
set State:/Network/Service/gpd.pan/DNS
set State:/Network/Global/DNS
quit
EOF
```