MacOS – How to simultaneously access IPv4 devices on 2 different 10/24 networks when using 2 active VPN connections

macosNetworkvpn

After a company is sold to different parties, you might end up with a situation where the old 10.0.0.0/8 network is split in two or more different networks, like 10.0.0.0/24 and 10.0.1.0/24.

Now I wish to access both networks at the same time using Mavericks built-in VPN client. One VPN network is on L2TP, the other PPTP.

However only the devices in the first established VPN connection can be reached, and not the computers on the second network. The only exception is the remote IP (gateway) of VPN connection #2.

How can I fix this set and forget?

Note: With set and forget I mean I don't want to have extra steps when "dialing" an already existing VPN connection profile.

Best Answer

Routing issue

The issue here is that both VPN connection profiles are in a 10 network, which officially comes with a /8 a.k.a. 255.0.0.0 a.k.a. 0xff000000 netmask. So when establishing both VPN connections at once, you end up with only one destination in the routing table for the 10-network. And that routing entry will route all 10.x.x.x traffic to the first established ppp connection, except for the local and remote IP addresses in the second ppp connection.

$ netstat -nr -f inet
Routing tables

Internet:
Destination        Gateway            Flags        Refs      Use   Netif Expire
default            192.168.0.1        UGSc           10        0     en0
default            10.0.1.1           UGScI           0        0    ppp0
default            10.0.0.1           UGScI           0        0    ppp1
10                 ppp0               USc             1        0    ppp0
10.0.0.1           10.0.0.12          UHr             2        0    ppp1
10.0.1.1           10.0.1.200         UHr             1        0    ppp0

Routing solution

The fix is to manually extend the routing table with the desired entries. There is no need to remove the 10 entry, only add new route entries. As long as the newly added route entries address a smaller subnet the entry will have preference. Read this as: when the subnet has a higher /X number. For example /24 is higher then /8 so a 10/24 entry will have preference over a 10/8 routing entry. Basically add a new routing entry after having established the second VPN connection, like: $ sudo /sbin/route -n add -net 10.0.2.0/24 -interface ppp1

Automation solution

It is cumbersome and can introduce mistakes when having to enter the route manually after having established the secondary VPN connection. Luckily there is a solution built-into the ppp daemon using if-up, as you can read in $ man pppd. Every time a ppp (VPN) connection is establish that uses IPv4 addressing, a script (/etc/ppp/if-up) is called where you can execute your custom rules/commands a.k.a. hooks.

The script below is extensively commented and should be self explanatory.

Your Mac might not have this script ($ ls /etc/ppp). In that case create it ($ sudo touch /etc/ppp/ip-up) with executable permissions ($ sudo chmod +x /etc/ppp/ip-up).

#!/bin/sh
#
# This script is run by the pppd after the link is established.
# It should be used to add routes, set IP address, etc.
#
# Tested with Mavericks (Mac OS X 10.9)
#
# This script is called with the following arguments:
# Arg   Name            Example
# $0    Script full location    /etc/ppp/ip-up
# $1    Interface name      ppp0
# $2    TTY device      <blank>
# $3    Speed           0
# $4    Local IP address    10.0.0.200
# $5    Remote IP address   10.0.0.1
# $6    LAN gateway     192.168.0.1
# source for $1-$6 is $ man -P 'less -p "    /etc/ppp/ip-up"' pppd

# ppp.log for non english systems do still have an english timestamp
export LC_TIME="C";

# Note: there is no static assignment for ppp0 to PPTP and ppp1 to L2TP
#       therefore $1 isn't useful to differentiate VPN networks

# To debug, uncomment the line below
#echo "$(date +%c) : \$5=$5" >> /var/log/ppp.log

# Add your routing table corrections here
# note: 2>&1 will redirect errors to the standard output
case "$5" in
10.0.0.1) OUT=$(exec /sbin/route -n add -net 10.0.0.0/24 -interface "$1" 2>&1) ;;
10.0.1.1) OUT=$(exec /sbin/route -n add -net 10.0.1.0/24 -interface "$1" 2>&1) ;;
esac

# If standard output is not empty, log it prepended by a timestamp
[ ! -z "$OUT" ] && echo "$(date +%c) : $OUT" >>/var/log/ppp.log

# There is automatic route removal on ppp disconnect.
# So no need to manually remove the above route(s) in /etc/ppp/ip-down

With thanks for the idea from jalbrecht2000 at http://hints.macworld.com/article.php?story=20030906232648318