Azure Site-to-Site VPN with a Linux based router to bridge the VPN ports to a RRAS server while keeping NAT for other traffic

I am trying to get an Azure Site-to-Site VPN up and running using RRAS but require help configuring my router's iptables to bridge the VPN ports and protocols to the RRAS server without using NAT while still allowing NAT to be used for all other traffic.

I've been able to configure Azure and the VM correctly, and I can get the connection up and running with data flowing across the link (and shown in the Azure portal as connected with data going both ways). However the connection that is set up isn't usable, I can't ping or seem to make any form of connection between the Azure VM's and my local machines.

I believe it is due to Azure's Site-to-Site VPN requiring the local VPN gateway to be connected directly to the internet without going through a NAT firewall (which I have to use as it's my home broadband so only have one IP) so while a connection can be established the NAT on my router alters the packets in a way that means they are unable be routed correctly once reaching the RRAS server.

I have tried alternate Site-to-Site VPN solutions (OpenVPN, SoftEther, RRAS itself) but none work correctly all exhibiting the same problem whereby the two VM's hosting VPN connection are able to connect to everything, and my home network servers can be correctly routed to connect to the Azure side but I believe either due to restrictions on Azure VM's (only a single network adapter and no ability to enable promiscuous mode) or the Azure virtual network itself it means no other Azure VM is able to connect to my home network despite adding in static routes to go via the VPN server or adding it as an additional gateway.

I am using a Asus RT-AC68U router running the latest Merlin build so I am hoping I can use the Azure Site-to-Site VPN by changing it's iptables rules & the network configuration in the following way:

  • Leaving the existing iptables configuration largely untouched so NAT can continue to be used to allow my other local servers and workstations to continue to connect to the internet, or have ports forwarded to them.
  • The RRAS VM on my home network has two network adapters, one with the private IP, currently the other has a private IP but this would be changed to be my public IP as per Microsoft's recommendations.
  • Lastly, and the part I do not know how to accomplish is for the specific VPN ports and protocols (UDP 500, UDP 4500, UDP 1701 and ESP (protocol #50)) to be excluded from NAT and be bridged directly to the network adapter on the VM configured now setup with my home network's public IP.

The network looks like this currently:

Azure VM's - 192.168.1.0/25, VPN gateway using dynamic routing with a public IP.

Home network 192.168.0.0/24:

VDSL Modem <- PPPOE bridge so the Router has the public IP -> Asus Router <- NAT -> 192.168.0.0.24

So this is what I am trying to get to so RRAS has public ip for VPN purposes only:

  • VDSL Modem <- PPPOE bridge so the Router has the public IP -> Asus Router
    • <- Bridge for the VPN ports and protocol -> RRAS VM's public adapter's MAC address
    • <- NAT for everything else -> 192.168.0.0/24

I'm open to other suggestions to get the Site-to-Site VPN working if there is a simpler solution.

[update 1]

I'm currently thinking of the following, I have given the RRAS Hyper-V VM the additional network adapter and assigned it to VLAN 635, promiscuous mode is enabled if for some reason it wants to change it's MAC address. I've then disabled all connection items other than the two Link-Layer Topology Discovery items and IPv4.

I've assigned the IPv4 settings the public IP Address, a subnet mask of 255.255.255.255 and the gateway that is the same gateway of the ppp0 adapter in the router.

I've run the following on the router to attempt to direct any traffic trying to communicate with the Azure VPN gateway through the to the VLAN, and thus hopefully allowing it to be routed without using NAT:

/usr/sbin/ip link add link br0 name br0.635 type vlan id 635
/usr/sbin/ip link set dev br0.635 up

/usr/sbin/iptables -I INPUT -i br0.635 -j ACCEPT
/usr/sbin/iptables -I FORWARD -i ppp0 -o br0.635 -s <azure gateway IP> -j ACCEPT
/usr/sbin/iptables -I FORWARD -i br0.635 -o ppp0 -d <azure gateway IP> -j ACCEPT
/usr/sbin/iptables -I FORWARD -i ppp0 -o br0.635 -s <ppp0's gateway> -j ACCEPT
/usr/sbin/iptables -I FORWARD -i br0.635 -o ppp0 -d <ppp0's gateway> -j ACCEPT

Unfortunately this doesn't work and when attempting to connect in RRAS it tells me the remote server isn't responding.


Solution 1:

So I've managed to figure this out after a lot of digging around, I am able to use the native Azure Site-to-Site VPN functionality with OpenSwan which runs on a linux box (Raspberry Pi/Arch Linux) behind my home network's NAT router.

Network topology:

  • 192.168.0.0/24 - Home network
  • 192.168.1.0/24 - Azure network
  • 192.168.0.1 - Home router's private IP
  • 192.168.0.2 - Linux box acting as the home network's VPN server and gatewat

Firstly I set up Azure with:

  • It's remote network as normal
  • My local network with the VPN address as my public IP
  • Enabled the Site-to-Site checkbox on the Azure network linking it to my local network
  • Created a static gateway so IKEv1 is used

On my home network's router I forwarded the following to my Linux gateway running Openswan (192.168.0.2):

  • UDP 500
  • UDP 4500
  • Protocol 50 (GRE)

My ipsec.conf looks like this:

version 2.0

config setup
    nat_traversal=yes
    virtual_private=%4:192.168.0.0/24
    protostack=auto
    interfaces="ipsec0=eth0"

conn azure
    authby=secret
    auto=start
    type=tunnel
    left=192.168.0.2
    leftsubnet=192.168.0.0/24
    leftnexthop=192.168.0.1
    right=<azure's VPN gateway IP>
    rightsubnet=192.168.1.0/24
    ike=3des-sha1-modp1024,aes128-sha1-modp1024
    esp=3des-sha1,aes128-sha1
    pfs=no

ipsec.secrets:

192.168.0.2 <azure vpn gateway> : PSK "Azure's PSK"

That got the link up and running, to allow routing between sites (both ways after a lot of frustration):

/etc/sysctl.conf:

net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.icmp_ignore_bogus_error_responses = 1

A bash script that runs on boot to keep 'ipsec verify' happy:

#!/bin/bash

for vpn in /proc/sys/net/ipv4/conf/*; do
    echo 0 > $vpn/accept_redirects;
    echo 0 > $vpn/send_redirects;
done

sysctl -p

Finally my iptables rules which took the most amount of fiddling:

filter table, this allows the home network to connect to Azure and allows the connection to be established, but Azure VM's still aren't yet able to connect to home network servers:

-A FORWARD -s 192.168.1.0/24 -m policy --dir in --pol ipsec -j ACCEPT
-A FORWARD -s 192.168.0.0/24 -m policy --dir out --pol ipsec -j ACCEPT
-A INPUT -p udp -m udp --dport 500 -j ACCEPT
-A INPUT -p udp -m udp --dport 4500 -j ACCEPT
-A INPUT -m policy --dir in --pol ipsec -j ACCEPT
-A INPUT -p esp -j ACCEPT

nat table, this allows the Azure VM's to connect to any machine on my home network:

-A PREROUTING -i eth0 -p udp -m udp --dport 4500 -j DNAT --to-destination <azure public vpn ip>:4500
-A PREROUTING -i eth0 -p udp -m udp --dport 500 -j DNAT --to-destination <azure public vpn ip>:500
-A POSTROUTING -o eth0 -j MASQUERADE

With all this I can ping and communicate in both directions, all Azure VM's can see my home network, all home network machines can see my Azure VM's.

The Azure side routes correctly on it's own, for my home network I set up a static route in my router to send 192.168.1.0/24 to 192.168.0.2 but for testing on my machine I just created a static route:

route -p ADD 192.168.1.0 MASK 255.255.255.0 192.168.0.2 METRIC 100

I hope at least someone finds this useful, getting this set up has taken a long time and there isn't a good complete guide out there just a mixture of solutions which partially work.