Route all traffic via VPN (except initial connection)

So I have two Hex S routers (7.23.1)

The routers are a simple DHCP server for a couple of local 'LAN' IPs and a OpenVPN tunnel to a remote server.

Essentially they are just used for making a VOIP connection from a site to a VOIP server but want to route all traffic over the VPN, not just the VOIP traffic.

Clearly the initial connection needs to go via the interwebs, but after that all traffic can be routed down he VPN tunnel. The WAN interface is DHCP.

I actually had both of these kind of working, but it was a bit "Heath Robinson" and cobbled together.

I have had a read of a lot of guides and they vary - often out of date.

The VPN tunnel bit is simple and runs quite happily.

The tricky bit is routing the traffic and I have been well and truly stumped - I can sometimes seem to to get some traffic down it, not others.

I have had so many rules in and out I have completely frazzed my brain :zany_face: :exploding_head:

Has anyone got a simple guide on how to do this?

I'm happy to test and document it myself but need a hand.

I was going to do a complete reset, start with a simple masqueraded LAN, and the VPN and try again.

Anyone have any pearls of wisdom to impart?

This seems to be an accepted answer except routing-mark and type are no longer right eg:

/ip route add dst-address=0.0.0.0/0 distance=1 gateway=192.168.98.1 routing-mark=vpn

/ip route add dst-address=0.0.0.0/0 type=unreachable distance=2 routing-mark=vpn

I suspect they are now



/ip route add dst-address=0.0.0.0/0 distance=1 gateway=192.168.98.1 routing-table=vpn

/ip route add dst-address=0.0.0.0/0 type=unreachable distance=2 routing-table=vpn

https://superuser.com/a/999549

An alternative method?

Any any advice appreciated - it's driving me nuts!

B. Rgds

John

You can proceed like this for RouterOS 7. First, if possible, connect to the router using WinBox and MAC address. In case you did something wrong with the routing rules, you might lock yourself out of WinBox using IP address!

  • Add a routing table with FIB:

    /routing table
    add fib name=via-vpn
    
  • Assuming 192.168.98.1 is the remote gateway on the other side of the VPN, add the default route in the via-vpn table, using 192.168.98.1 as gateway:

    /ip route 
    add dst-address=0.0.0.0/0 gateway=192.168.98.1@main \
        check-gateway=ping routing-table=via-vpn
    

    But if the remote gateway is not an IP address, but an interface, for example ovpn-client1 (or wg1 if you use WireGuard), then add the default route specifying the gateway like this instead:

    /ip route 
    add dst-address=0.0.0.0/0 gateway=ovpn-client1 routing-table=via-vpn
    
  • Add this rule at the top of the Routing -> Rules table:

    /routing rule
    add action=lookup min-prefix=0 table=main
    
  • Now for every LAN/VLAN interfaces you have, add one routing rule below the rule above. For example, if you have a bridge bridge-local and a vlan50 interfaces and you want to force route internet traffic of every clients connected to them through the VPN, with no fallback, add those routing rules:

    /routing rule
    add action=lookup-only-in-table dst-address=0.0.0.0/0 interface=bridge-local table=via-vpn
    add action=lookup-only-in-table dst-address=0.0.0.0/0 interface=vlan50 table=via-vpn
    

    change lookup-only-in-table to lookup if you want to allow falling back to the main table when the VPN tunnel is down.

  • Alternatively, if you don't want to use the source interface as criteria, but the source IP address of the clients, for example 192.168.88.0/24, 10.20.0.0/16, use routing rules like these (still placed after the min-prefix rule!):

    /routing rule
    add action=lookup-only-in-table src-address=192.168.88.0/24 table=via-vpn
    add action=lookup-only-in-table src-address=10.20.0.0/16 table=via-vpn
    
  • With those routing rules, only your LAN/VLAN clients are forced through the VPN. The router itself is not, and still uses the default internet connection when it does things like checking for upgrade or synchronize time, etc... If however, you want all traffic, even the one of the router itself, to go through the VPN, then instead of those rules above, use these following routing rules. In this example 123.45.67.89 is the IP address of the remote VPN server for which you need to use the main routing table to be able to establish the VPN connection.

    /routing rule
    add action=lookup min-prefix=0 table=main
    add action=lookup-only-in-table dst-address=123.45.67.89 table=main
    add action=lookup-only-in-table dst-address=0.0.0.0/0 table=via-vpn
    

    The 3rd rule no longer has the interface condition and forces all the rest of the IPv4 internet traffic to use the via-vpn routing table.

  • Don't forget to add the SRCNAT masquerade rule for traffic through the VPN tunnel if needed.

  • If your VPN is an OpenVPN tunnel (with the OVPN client in RouterOS) then this following step is not needed, because the default PPP profile normally automatically adjusts the TCP MSS for you. But for other kinds of VPN, a step normally is needed to adjust the TCP MSS values of the connection going through the tunnel. For example, if using WireGuard with a wg1 interface and the default 1420 MTU setting, these following mangle rules would be helpful:

    /ip firewall mangle
    add action=change-mss chain=forward comment="reduce MSS for WG" new-mss=1380 \
        out-interface=wg1 protocol=tcp tcp-flags=syn tcp-mss=1381-65535
    add action=change-mss chain=forward comment="reduce MSS for WG" new-mss=1380 \
        in-interface=wg1 protocol=tcp tcp-flags=syn tcp-mss=1381-65535
    

Thanks for the amazing guide!

I'll be testing later :slight_smile:

@CGGXANNX

I'm not really sure what the purpose of the /routing rule is.

It adds action=lookup min-prefix=0 table=main, and I have a feeling this rule is evaluated at the end.

@sindy explained something similar in a few other posts.

Let me ask you this: does min-prefix=0 effectively mean 0.0.0.0/0? And if I set it to 5, would that correspond to 0.0.0.0/5?

The rule

/routing rule
add action=lookup min-prefix=0 table=main

has this effect: All the current active routes (with A flag) in the main table will be looked at, except for the route with /0 in the destination (which means except for the routes with dst-address=0.0.0.0/0), if one of those active routes (the not 0.0.0.0/0 ones) can match the destination of the packet, then the lookup succeeds, main is used and the other routing rules below that rule are skipped.

It ensures that if the destination of the packet is towards a VLAN (or bridge) subnet for example, then the route in main will be used (because those interfaces have connected routes in main, such as dst-address=192.168.88.0/24 that are not dst-address=0.0.0.0/0), and will not match the routing rules below that direct the packet to the VPN gateway.

Let's say the routing table have those routes:

#     DST-ADDRESS       GATEWAY     ROUTING-TABLE  DISTANCE
  DAv 0.0.0.0/0         pppoe-out1  main                  1
  DAc 10.3.12.0/24      vlan312     main                  0
  DAc 192.168.88/24     bridge      main                  0
  DAc 172.18.20.0/24    containers  main                  0
  DAc 10.20.30.0/24     wireguard1  main                  0
  DAc 10.20.31.1/32     wireguard2  main                  0
  DAc 100.123.45.67/32  pppoe-out1  main                  0
  DAc 192.168.0.0/16    ether1      main                  0
0  As 0.0.0.0/0         10.20.31.1  to-vpn                1

And the packet has destination 172.18.20.5. That routing rule will match that packet, because the main table after removing all the active routes with prefix length <= 0, still has are route with matching destination (the one with dst-address=172.18.20.0/24 gateway=containers). Same with a packet with destination 192.168.3.2, it will use the route with dst-address=192.168.0.0/16 gateway=ether1.

But if the packet has destination 10.0.0.3, none of the routes in main matches (the matching one with dst-address=0.0.0.0/0 has been excluded). Which means this routing rule does not match, and the next routing rules will be checked (that will potentially use other routing tables).

In short, the routing rule with min-prefix=0 placed on top causes all reachable non-WAN destinations to use the main routing table. Traffic directed to the LAN subnets will use main, it allows inter-VLAN routing to work normally.

Now if the rule is

/routing rule
add action=lookup min-prefix=20 table=main

instead, with min-prefix=20, then when trying for a packet with destination 192.168.3.2, both routes

  DAv 0.0.0.0/0         pppoe-out1  main                  1
  DAc 192.168.0.0/16    ether1      main                  0

will be excluded as candidates (because 0 <= 20 and 16 <= 20). Of the remaining active routes in main, none will be able to match 192.168.3.2. The routing rule will not match, and the next routing rules will be considered.

But a packet with destination 192.168.88.9 will have the matching route dst-address=192.168.88/24 gateway=bridge and will use main and the routing rule processing stops here.

Also note that that rule with min-prefix=0 also works for the IPv6 routes (it excludes the dst-address=::/0 routes when trying to lookup).

So just to complicate matters.......

One of my servers runs openvpn "routed" mode.

So we have

Server:

public IP 1.2.3.4
internal 'network' 192.168.98.0/24
routed 'network' 192.168.29.0/24

The Hex S has an internal network of 192.168.88.0/24

When connected to the OpenVPN server we can browse from 192.168.88.0/24 to 192.168.98.1

I have managed to force local traffic 192.168.88.0/24 out through the router but what I cannot seem to do is permit the Voip server to talk to respond to phone.

I can see

Not LAN input: in:ovpn out:(unknown 0), connection-state:new proto UDP, 192.168.29.1:5060->192.168.29.4:37339, len 511

If I add a input rule it no longer logs as dropped, but still no joy - I am sure I need another rule but I am blowed if I know what.

Ironically this used to work but I lost the config :frowning:

/ip firewall filter
add action=accept chain=input comment="defconf: accept established,related,untracked" connection-state=established,related,untracked
add action=drop chain=input comment="defconf: drop invalid" connection-state=invalid
add action=accept chain=input comment="defconf: accept ICMP" protocol=icmp
add action=accept chain=input comment="Accept all from OpenVPN" in-interface=ovpn log=yes log-prefix="Input OpenVPN"
add action=accept chain=input comment="defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1 in-interface=lo src-address=127.0.0.1
add action=drop chain=input comment="defconf: drop all not coming from LAN" in-interface-list=!LAN log=yes log-prefix="Not LAN"
add action=accept chain=forward comment="defconf: accept in ipsec policy" disabled=yes ipsec-policy=in,ipsec
add action=accept chain=forward comment="defconf: accept out ipsec policy" disabled=yes ipsec-policy=out,ipsec
add action=fasttrack-connection chain=forward comment="defconf: fasttrack" connection-state=established,related log-prefix="Fasttrack forward"
add action=accept chain=forward comment="defconf: accept established,related, untracked" connection-state=established,related,untracked
add action=drop chain=forward comment="defconf: drop invalid" connection-state=invalid
add action=drop chain=forward comment="defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat in-interface-list=WAN

Pretty sure I am a rule away from it working but having tried all sorts I have lost the will to live :wink:

I just added two rules right at the end to try and catch any packets missed:

add action=log chain=forward log=yes log-prefix=Forwards
add action=log chain=input log=yes log-prefix=Input

Got this:

Forwards forward: in:bridge out:ovpn, connection-state:new,snat src-mac C0:74:AD:6C:BF:EA, proto UDP, 192.168.88.254:42014->192.168.98.1:514, NAT (192.168.88.254:42014->192.168.29.4:42014)->192.168.98.1:514, len 146

I presume this has something do with it or is that the masq rule?

It is currently reset to basic config with just openvpn and a Masq rule.

Any advice appreciated!