Routing a particular subnet into a VPN tunnel

11,201

This can be achieved using a custom routing table and policy (I recently did something very similar myself)

  1. Firstly create a custom routing table for your VPN

    echo "10 vpn" >> /etc/iproute2/rt_tables
    
  2. Tell iproute2 to use this routing table for traffic to and from your 192.168.2.0 network

    ip rule add from 192.168.2.0/24 table vpn
    ip rule add to 192.168.2.0/24 table vpn
    
  3. Set up NAT masquerading for the 192.168.2.0 network

    iptables -A FORWARD -i eth0:2 -s 192.168.2.0/24 -j ACCEPT
    iptables -A FORWARD -i tun0 -d 192.168.2.0/24 -j ACCEPT
    iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o tun0 -j MASQUERADE
    
  4. Enable IP forwarding if it's not enabled (required for NAT)

    echo 1 > /proc/sys/net/ipv4/ip_forward
    
  5. In your OpenVPN config add the following lines

    #Prevents default gateway from being set on the default routing table
    route-noexec
    #Allows route-up script to be executed
    script-security 2
    #Calls custom shell script after connection to add necessary routes
    route-up /etc/openvpn/route-up.sh
    
  6. Create a custom shell script in /etc/openvpn/route-up.sh and chmod +x it

    #!/bin/sh
    
    #Clear all routes on vpn routing table (this is to make sure there isn't any crap left over from a previous vpn connection
    /sbin/ip route flush table vpn
    
    #Copy routing table from main routing table into vpn table
    /sbin/ip route show table main | grep -Ev ^default | while read ROUTE ; do ip route add table vpn $ROUTE; done
    
    #Add default gateway to vpn routing table
    /sbin/ip route add default via ${route_vpn_gateway} dev ${dev} table vpn
    

Steps 2 and 3 will not persist across reboots so you will need to add those parts to your init scripts as required.

Share:
11,201

Related videos on Youtube

moonmoon
Author by

moonmoon

Updated on September 18, 2022

Comments

  • moonmoon
    moonmoon over 1 year

    My network looks like this:

    enter image description here

    I'm trying configure my router so that the subnet (192.168.2.0/24) is routed over the VPN tunnel (tun0) on the gateway/router.

    While at the same time clients on the subnet (192.168.1.0/24) are routed directly out over ppp0, ie not through the VPN.

    I don't want to run VPN software clients, and certain clients on the network need direct access. eg a windows gaming computer, voip phone etc.

    My router also runs an unbound DNS server that forwards DNS lookups to dnscrypt-proxy.

    The network interfaces on the router are configured like:

    auto lo
        iface lo inet loopback
    
    auto lo:1
    iface lo:1 inet static
        address 127.0.0.2
        netmask 255.0.0.0
    
    auto eth0
    iface eth0 inet static
        address 192.168.1.1
        netmask 255.255.255.0
    
    # Virtual interface
    auto eth0:2
    iface eth0:2 inet static
        address 192.168.2.1
        netmask 255.255.255.0
    
    auto eth1
    iface eth1 inet static
        address 192.168.0.2
        netmask 255.255.255.252
    
    auto ppp0
    iface ppp0 inet ppp
        pre-up ip link set dev eth1 up
        provider <isp>
        post-down ip link set dev eth1 down
    

    For the moment I'm using a virtual interface ie eth0:2. I am also wondering if this is appropriate or should that be a VLAN ie eth0.2?

    As far as I was aware the only difference would be that clients would then require a VLAN interface eg:

    /etc/systemd/network/MyEth.network

    [Match]
    Name=enp10s0
    
    [Network]
    DHCP=v4
    DNS=192.168.2.1
    Address=192.168.2.30/24
    Gateway=192.168.2.1
    VLAN=vlan2
    

    /etc/systemd/network/MyEth.netdev

    [NetDev]
    Name=vlan2
    Kind=vlan
    
    [VLAN]
    Id=2
    

    and be unable to cross over subnets eg 192.168.1.10 would be unable to talk to 192.168.2.10.

    The iptables rules I've attempted to get this working with are as follows:

    iptables -F
    iptables -t nat -F
    
    export WAN=ppp0           # Link to ISP
    export INT_IF=eth0        # Interface that serves internal network
    export EXT_IF=eth1        # Interface between router and modem
    export WAN_TUNNEL=tun0    # VPN tunnel created by OpenVPN
    export VPN_VLAN_IF=eth0:2 # Interface internal clients have as their gateway
    
    # Allows internet access on gateway
    iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
    
    #############
    # NAT Rules #
    ###############################################################################
    # VPN
    iptables -I FORWARD -i ${VPN_VLAN_IF} -d 192.168.2.0/24 -j DROP
    iptables -A FORWARD -i ${VPN_VLAN_IF} -s 192.168.2.0/24 -j ACCEPT
    iptables -A FORWARD -i ${WAN_TUNNEL} -d 192.168.2.0/24 -j ACCEPT
    iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o ${WAN_TUNNEL} -j MASQUERADE
    ###############################################################################
    
    ###############################################################################
    # NO VPN
    iptables -I FORWARD -i ${INT_IF} -d 192.168.1.0/24 -j DROP
    iptables -A FORWARD -i ${INT_IF} -s 192.168.1.0/24 -j ACCEPT
    iptables -A FORWARD -i ${WAN} -d 192.168.1.0/24 -j ACCEPT
    iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o ${WAN} -j MASQUERADE
    ###############################################################################
    
    iptables -P INPUT DROP
    iptables -P OUTPUT ACCEPT
    iptables -P FORWARD DROP
    
    echo 1 > /proc/sys/net/ipv4/ip_forward
    for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 1 > $f ; done
    
    /etc/init.d/iptables save
    

    I also expect that I would need to use route-nopull in my openvpn configuration, otherwise everything on the gateway would be routed over the VPN?

    By default when I connect to the OpenVPN server I see:

    openvpn[3469]: /sbin/ip route add <ip_of_vpn> dev ppp0
    openvpn[3469]: /sbin/ip route add 0.0.0.0/1 via 172.16.32.1
    openvpn[3469]: /sbin/ip route add 128.0.0.0/1 via 172.16.32.1
    

    which results in a route like:

    ip route
    0.0.0.0/1 via 172.16.32.1 dev tun0 
    default dev ppp0  scope link  metric 300 
    <ip_of_vpn> dev ppp0  scope link 
    128.0.0.0/1 via 172.16.32.1 dev tun0 
    172.16.32.0/20 dev tun0  proto kernel  scope link  src 172.16.39.64 
    192.168.0.0/30 dev eth1  proto kernel  scope link  src 192.168.0.2 
    192.168.1.0/24 dev eth0  proto kernel  scope link  src 192.168.1.1 
    192.168.2.0/24 dev eth0  proto kernel  scope link  src 192.168.2.1 
    <ip_from_isp> dev ppp0  proto kernel  scope link  src X.X.X.X
    

    Would I need a static route to route 192.168.2.0/24 to the VPN ie to tun0

  • y_nk
    y_nk over 7 years
    tried with openwrt and a mwan setup, didn't work. i suspect mwan rules to mess up with this