How to Force Split Routing in Juniper Network Connect VPN on macOS: Bypass VPN for Local Traffic


5 views

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:

  1. Open System Preferences → Network
  2. Click the gear icon → Set Service Order
  3. Drag your primary connection above the VPN
  4. 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