When using Juniper Network Connect on macOS, the default configuration often routes all network traffic through the VPN tunnel. This becomes problematic when you need to:
- Access local network resources
- Stream media from services that block VPN traffic
- Maintain faster connections to non-work resources
The Juniper client aggressively modifies /etc/resolv.conf
to enforce the corporate DNS policy. You've correctly identified this behavior when observing:
search XXX.com [redacted]
nameserver 10.30.16.140
nameserver 10.30.8.140
The error -bash: /etc/resolv.conf: Permission denied
occurs because modern macOS implements System Integrity Protection (SIP). Even root can't directly modify some system files. Here's why your command failed:
sudo echo "nameserver 192.168.0.1" >> /etc/resolv.conf
The shell handles the redirection before sudo elevation occurs.
Instead of fighting the file modification, try these approaches:
Method 1: Using networksetup
sudo networksetup -setdnsservers Wi-Fi 192.168.0.1
Method 2: Create a persistent resolver config
sudo mkdir -p /etc/resolver
sudo sh -c 'echo "nameserver 192.168.0.1" > /etc/resolver/local'
Here's how to modify your routing tables to bypass the VPN for specific traffic:
# Get your current default gateway (before VPN connection)
ORIGINAL_GW=$(netstat -rn | grep default | grep -v utun | awk '{print $2}')
# Connect to VPN, then add specific routes
sudo route -n add -net 192.168.0.0/16 $ORIGINAL_GW
sudo route -n add -net 10.0.0.0/8 $ORIGINAL_GW
# For media streaming services
sudo route -n add -host 54.239.25.200 $ORIGINAL_GW # Example: Amazon Music
Create a script to handle this automatically:
#!/bin/bash
# Store original DNS
ORIGINAL_DNS=$(networksetup -getdnsservers Wi-Fi | tr '\n' ' ')
function cleanup {
networksetup -setdnsservers Wi-Fi $ORIGINAL_DNS
echo "Restored original DNS settings"
}
trap cleanup EXIT
# Connect to VPN
# ... your VPN connection command here ...
# Set split DNS
networksetup -setdnsservers Wi-Fi 192.168.0.1 10.30.16.140
# Set split routing
ORIGINAL_GW=$(netstat -rn | grep default | grep -v utun | awk '{print $2}')
for subnet in 192.168.0.0/16 10.0.0.0/8; do
route -n add -net $subnet $ORIGINAL_GW
done
For persistent configuration, create a network preference profile:
<?xml version="1.0"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>DNS</key>
<dict>
<key>ServerAddresses</key>
<array>
<string>192.168.0.1</string>
<string>10.30.16.140</string>
</array>
</dict>
</dict>
</plist>
Save as ~/Library/Preferences/Network/com.mycompany.splitdns.plist
The Juniper Network Connect client typically implements a full-tunnel VPN configuration by default, routing all network traffic through the VPN gateway. This becomes evident when examining these system changes:
# Original resolv.conf
nameserver 192.168.0.1
# After VPN connection
search XXX.com
nameserver 10.30.16.140
nameserver 10.30.8.140
The permission denied error occurs because Juniper modifies file permissions during connection. Try these alternative approaches:
# Method 1: Use tee with sudo
echo "nameserver 192.168.0.1" | sudo tee -a /etc/resolv.conf
# Method 2: Disable resolv.conf modification
sudo chattr +i /etc/resolv.conf # Make file immutable
# Note: Reverse with chattr -i when needed
For true split tunneling, we need to modify the routing table. Create a script to preserve local routes:
#!/bin/bash
# Save current routes
netstat -rn > ~/original_routes.txt
# Connect to VPN
# (Juniper connection command here)
# Delete default route through VPN
sudo route -n delete default
# Add specific route for VPN resources only
sudo route -n add 10.0.0.0/8 [VPN_GATEWAY_IP]
Configure network service order in macOS:
- Open System Preferences → Network
- Click the gear icon → Set Service Order
- Drag your primary connection above the VPN
- This ensures non-VPN traffic uses your regular interface
For a more permanent solution, configure a custom DNS resolver:
# Install dnsmasq
brew install dnsmasq
# Configure /usr/local/etc/dnsmasq.conf
server=/clientdomain.com/10.30.16.140
server=/8.8.8.8
Use pf to create firewall rules for selective routing:
# /etc/pf.conf
table <vpn_networks> { 10.0.0.0/8 }
pass out on en0 route-to (lo0 127.0.0.1) from any to !<vpn_networks>
Use these commands to verify your configuration:
# Check active routes
netstat -rn
# Verify DNS resolution
scutil --dns
# Test traffic routing
traceroute 8.8.8.8