Last week my Docker containers suddenly lost internet on my MacBook while I was tethered to a hotel Wi-Fi + VPN. DNS looked fine, but pings to 8.8.8.8 hung.

The culprit turned out to be a rogue default route left behind by the VPN client.
netstat -nr exposed it in two seconds.

$ netstat -nr
Routing tables

Internet:
Destination        Gateway            Flags  Netif Expire
default            172.20.0.1         UGSc   utun3
default            192.168.1.1        UGSc   en0
127.0.0.1          127.0.0.1          UH     lo0
192.168.1.0/24     link#4             U      en0

How to read those columns

Column What it tells you How I used it
Destination Network or host the rule matches. default = “everything not matched elsewhere.” I immediately saw two defaults—bad sign.
Gateway Next hop for that destination. 172.20.0.1 came from the VPN adapter; should have disappeared when I disconnected.
Flags U = route up, G = via gateway, S = static, C = cloned, etc. Both defaults had UGSc, so the system could pick either—hello packet limbo.
Netif Interface sending the traffic (en0, utun3, lo0, …). The bad route pointed to utun3 (VPN tunnel) instead of en0 (Wi-Fi).
Expire Seconds until the ARP entry ages out (blank for static). Not critical here, but useful when chasing ARP/ND cache issues.

Why the -n matters
The -n switch skips DNS and reverse-lookup delays, so routes pop up instantly—crucial when you're half-connected.

Fixing my issue

# delete the stale VPN route
sudo route delete default 172.20.0.1

A quick re-run of netstat -nr showed a single healthy default pointing at 192.168.1.1 on en0, and Docker traffic flowed again.

When netstat isn't around

  • Modern Linux: ip route show gives an even terser view.
    default via 192.168.1.1 dev wlan0 proto dhcp metric 100
  • Fallback: route -n still works almost everywhere.