IKEv2 IPsec tunnel

Hi, I am trying to set up an IKEv2 IPsec VPN tunnel with an external VPN provider (Windscribe) for a single IP within my LAN. For some reason, the tunnel becomes active for my entire LAN instead of for a single device. Can you help me figure out why? This is my configuration (ipsec rules disabled for now).

# nov/04/2020 14:59:57 by RouterOS 6.47.6
# software id = N3Q4-JKJ6
#
# model = RB750Gr3
# serial number = **Removed**
/interface bridge
add admin-mac=C4:AD:34:A7:80:70 auto-mac=no comment=defconf name=bridge
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
/interface wireless security-profiles
set [ find default=yes ] supplicant-identity=MikroTik
/ip hotspot profile
set [ find default=yes ] html-directory=flash/hotspot
/ip ipsec mode-config
add name=WindscribeVPN responder=no src-address-list=AndroidTV
/ip ipsec policy group
add name=WindscribeVPN
/ip ipsec profile
add dh-group=ecp384 enc-algorithm=aes-256 hash-algorithm=sha256 name=WindscribeVPN
/ip ipsec peer
add address=wf-us.windscribe.com disabled=yes exchange-mode=ike2 name=WindscribeVPN profile=WindscribeVPN
/ip ipsec proposal
add name=WindscribeVPN
/ip pool
add name=dhcp ranges=192.168.1.2-192.168.1.254
/ip dhcp-server
add address-pool=dhcp disabled=no interface=bridge lease-time=8h name=defconf
/user group
set full policy=local,telnet,ssh,ftp,reboot,read,write,policy,test,winbox,password,web,sniff,sensitive,api,romon,dude,tikapp
/dude
set data-directory=disk1/dude-data enabled=yes
/interface bridge port
add bridge=bridge comment=defconf interface=ether2
add bridge=bridge comment=defconf interface=ether3
add bridge=bridge comment=defconf interface=ether4
add bridge=bridge comment=defconf interface=ether5
/ip neighbor discovery-settings
set discover-interface-list=LAN
/interface detect-internet
set detect-interface-list=all
/interface list member
add comment=defconf interface=bridge list=LAN
add comment=defconf interface=ether1 list=WAN
/ip address
add address=192.168.1.1/24 comment=defconf interface=ether2 network=192.168.1.0
/ip dhcp-client
add comment=defconf disabled=no interface=ether1 use-peer-dns=no
/ip dhcp-server lease
add address=192.168.1.20 client-id=1:c4:98:5c:ad:6d:39 mac-address=C4:98:5C:AD:6D:39 server=defconf
/ip dhcp-server network
add address=192.168.1.0/24 comment=defconf gateway=192.168.1.1 netmask=24
/ip dns
set servers=192.168.1.150
/ip dns static
add address=192.168.1.1 name=router.lan
/ip firewall address-list
add address=**Removed** list="WAN IP"
add address=192.168.1.20 list=AndroidTV
/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=drop chain=input comment="defconf: drop all not coming from LAN" in-interface-list=!LAN
add action=accept chain=forward dst-address-list=!AndroidTV src-address-list=AndroidTV
add action=accept chain=forward dst-address-list=AndroidTV src-address-list=!AndroidTV
add action=accept chain=forward comment="defconf: accept in ipsec policy" ipsec-policy=in,ipsec
add action=accept chain=forward comment="defconf: accept out ipsec policy" ipsec-policy=out,ipsec
add action=fasttrack-connection chain=forward comment="defconf: fasttrack" connection-state=established,related
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 connection-state=new \
    in-interface-list=WAN
/ip firewall mangle
add action=change-mss chain=forward new-mss=1440 passthrough=yes protocol=tcp src-address-list=AndroidTV tcp-flags=syn tcp-mss=!0-1440
/ip firewall nat
add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=192.168.1.0/24 src-address=192.168.1.0/24
add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN
add action=dst-nat chain=dstnat dst-address-list="WAN IP" dst-port=80 protocol=tcp to-addresses=192.168.1.200 to-ports=90
add action=dst-nat chain=dstnat dst-address-list="WAN IP" dst-port=443 protocol=tcp to-addresses=192.168.1.200 to-ports=450
add action=dst-nat chain=dstnat dst-address-list="WAN IP" dst-port=1194 protocol=udp to-addresses=192.168.1.150 to-ports=1194
/ip firewall service-port
set ftp disabled=yes
set tftp disabled=yes
set irc disabled=yes
set h323 disabled=yes
set sip disabled=yes
set pptp disabled=yes
set udplite disabled=yes
set dccp disabled=yes
set sctp disabled=yes
/ip ipsec identity
add auth-method=eap certificate="" eap-methods=eap-mschapv2 generate-policy=port-strict mode-config=WindscribeVPN peer=WindscribeVPN \
    policy-template-group=WindscribeVPN remote-id=fqdn:wf-us.windscribe.com username=**Removed**
/ip ipsec policy
add dst-address=0.0.0.0/0 group=WindscribeVPN proposal=WindscribeVPN src-address=0.0.0.0/0 template=yes
/ip service
set telnet disabled=yes
set ftp disabled=yes
set api disabled=yes
set api-ssl disabled=yes
/system clock
set time-zone-name=Europe/Amsterdam
/tool graphing interface
add allow-address=192.168.1.0/24
/tool mac-server
set allowed-interface-list=LAN
/tool mac-server mac-winbox
set allowed-interface-list=LAN

If your WAN address is static, you can replace the action=masquerade rule with an action=src-nat to-addresses=the.static.wan.ip one.

I assume that the masquerade rule chooses the WAN address assigned using mode-config instead of the “real” one, as both are attached to the WAN interface.

If your WAN address is dynamic, you’ll have to use the corresponding script in /ip dhcp-client or /ppp profile to update the to-addresses in the rule on each address change. And if your WAN is LTE, you may have to run a scheduled script as there are several different ways how the IP address is assigned when LTE is used, and most of them do not allow to trigger any script.

Hi Sindy, thanks for your reply.
Can you elaborate on where you think the problem is? I do have a dynamic WAN IP, but it updates itself by DNS (I removed my public DNS name):

/ip firewall address-list
add address=**Removed** list="WAN IP"

Just so you know, the tunnel is working fine when it’s brought up, just not for a single host in the LAN (192.168.1.20) as supposed, but for the entire lan.

I’ve understood that already from your first post.

The thing is that as the IPsec tunnel goes up, you get another IP address from the VPN provider via mode-config, and an IPsec policy is dynamically generated at your side to grab any packet with that source IP and any destination IP and send it via the VPN. So to have any outbound packet actually get to the tunnel, its source address must be the one assigned this way.

So if you specify a connection-mark or src-address-list on the mode-config row, an action=src-nat rule is dynamically generated at the very top of the srcnat chain in the nat table, matching on that src-address-list or connection-mark value, with to-addresses set to the one assigned by the mode-config procedure.

(several such rules may be added in generic case, and the mode config procedure is called somehow else in IKEv2, but that’s not important for this explanation).

Now the issue is that your manually configured firewall rules contain an action=masquerade one, which also changes the source IP of packets sent out the WAN so that the responses could be routed back to your Mikrotik. If not for this rule, the packets towards some servers in the internet would be leaving with the source address from your (private) LAN range, so in better case already your ISP would drop them, in worse case they would reach the destination but the response would be sent somewhere else, as the private address from your LAN is routed somewhere else in the remote server’s network.

The dynamically created rule ignores the packets sent by other devices than the Android TV, but the action=masquerade rule matches them, and the issue you are facing is that the action=masquerade rule chooses the IP address added by the mode-config rather than the one added by DHCP, as both are assigned to the same interface. I don’t know the criteria the firewall uses to choose an address for masquerade if more than one is available. There is currently no way to avoid this “random” choice but by replacing the masquerade action by a src-nat one and specifying the correct to-addresses value manually. This has another drawback - if the DHCP-assigned address changes, not only that you have to update the rule, but you also have to remove all the tracked connections using the old address, which happens automatically with masquerade.

Thank you, that makes sense. I tested this by disabling the hairpin NAT rule altogether:

add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=192.168.1.0/24 src-address=192.168.1.0/24

But, the behaviour did not change after bringing the tunnel back up.
Should I change this default masquerade rule below as well to test this properly?

add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN

It’s not “as well”, it’s only this rule which needs to be changed.

Right, just tested this, I changed the rule to:

add action=src-nat chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN to-addresses=my.public.ip.address

And re-enabled the IPsec tunnel. This didn’t have the desired effect, everything in in LAN was still routed trough the tunnel.
Anything else I should have done?

That’s weird.

Please post the output of /ip firewall nat print and ip ipsec policy print detail while the tunnel is up. Replace public IP addresses systematically.

/ip firewall nat print
Flags: X - disabled, I - invalid, D - dynamic 
 0  D ;;; ipsec mode-config
      chain=srcnat action=src-nat to-addresses=10.121.174.209 src-address-list=AndroidTV dst-address-list=!AndroidTV 

 1    ;;; Hairpin NAT
      chain=srcnat action=masquerade src-address=192.168.1.0/24 dst-address=192.168.1.0/24 log=no log-prefix="" 

 2    ;;; defconf: masquerade
      chain=srcnat action=src-nat to-addresses=my.public.ip.addr out-interface-list=WAN log=no log-prefix="" ipsec-policy=out,none 

 3    chain=dstnat action=dst-nat to-addresses=192.168.1.200 to-ports=90 protocol=tcp dst-address-list=WAN IP dst-port=80 log=no 
      log-prefix="" 

 4    chain=dstnat action=dst-nat to-addresses=192.168.1.200 to-ports=450 protocol=tcp dst-address-list=WAN IP dst-port=443 log=no 
      log-prefix="" 

 5    chain=dstnat action=dst-nat to-addresses=192.168.1.150 to-ports=1194 protocol=udp dst-address-list=WAN IP dst-port=1194 log=no 
      log-prefix=""

and

 /ip ipsec policy print detail 
 
Flags: T - template, B - backup, X - disabled, D - dynamic, I - invalid, A - active, * - default 
 0 T  * group=default src-address=::/0 dst-address=::/0 protocol=all proposal=default template=yes 

 1 T    group=WindscribeVPN src-address=0.0.0.0/0 dst-address=0.0.0.0/0 protocol=all proposal=WindscribeVPN template=yes 

 2   DA  peer=WindscribeVPN tunnel=yes src-address=10.121.174.209/32 src-port=any dst-address=0.0.0.0/0 dst-port=any protocol=all 
        action=encrypt level=unique ipsec-protocols=esp sa-src-address=my.public.ip.addr sa-dst-address=185.232.22.131 proposal=WindscribeVPN 
        ph2-count=1

How do you determine that all the traffic from LAN is running through the tunnel?

When the VPN is up and run a continuous ping to 1.1.1.1 from some device in LAN, what does
/ip firewall connection print detail where protocol~“icmp” dst-address~“1.1.1.1”
show?

I notice the DNS server changes to the one assigned by the VPN provider on other devices than the AndroidTV, also my external IP address changes on those devices.
I will perform your test tomorrow and get back to you.

Found some time to do your test now:

/ip firewall connection print detail where protocol~"icmp" dst-address~"1.1.1.1"

Flags: E - expected, S - seen-reply, A - assured, C - confirmed, D - dying, F - fasttrack, s - srcnat, d - dstnat 
 0  S C Fs  protocol=icmp src-address=192.168.1.97 dst-address=1.1.1.1 reply-src-address=1.1.1.1 reply-dst-address=my.public.ip.addr 
            icmp-type=8 icmp-code=0 icmp-id=34970 timeout=9s orig-packets=207 orig-bytes=17 388 orig-fasttrack-packets=0 
            orig-fasttrack-bytes=0 repl-packets=207 repl-bytes=17 388 repl-fasttrack-packets=0 repl-fasttrack-bytes=0 
            orig-rate=1344bps repl-rate=1344bps

As you can see here, the new source address of the ping (the reply-dst-address) is the correct one.

If the VPN provider assigns you the same 100.121… address every time, it is possible that those connections in the firewall that have been NATed to that address survive the teardown and re-establishment of the tunnel.

So test using new connections on www.whatismyip.com or alike. You can then change the action in that NAT rule back to masquerade and test again from a new browser tab to see the difference.

As for the DNS, it’s a bit more complex. As you haven’t specified any dns-server value on the /ip dhcp-server network row, Mikrotik gives the clients a list of DNS servers it uses itself, and itself it uses all of those configured statically and received dynamically from DHCP and/or using mode-config.

If you use the VPN to bypass geographical locks, it may be important that the Android TV used the DNS servers provided by the VPN, as the content providers’ root DNS servers may respond differently to requests from different sources, directing users from different regions to different servers.

So if something doesn’t work, you’ll need a dedicated row in /ip dhcp-server network for the Android TV’s address, indicating the DNS servers provided by the VPN, whereas the common row for the rest of the LAN devices will indicate only those suggested by your ISP.

.
from your initial post I saw that:
.

/ip ipsec policy
add dst-address=0.0.0.0/0 group=WindscribeVPN proposal=WindscribeVPN src-address=0.0.0.0/0 template=yes

.
just made my first efforts with the ipsec-template feature myself … question is why is your template so …gdmn “wwiiddee” ? … have you tried to narrow down src, dst and remote-peer, so that the rest of your LAN-clients would not be selected as interessting tunnel-traffic and pass through the rest of the (feature-rich) stack ?!
.
unused-options.png

@floaty, please have a look on how dynamic assignment of address and policy to the initiator using mode-config works.

The responder doesn’t know anything about your internal address plan, plus the address plans of several users could be overlapping, so the responder has to assign public or CGNAT addresses to initiators, and the initiators have to use src-nat for the traffic they want to be sent through the tunnel.

And the initiator doesn’t know in advance what address the remote responder will assign to it, so the src-address of the template cannot be restricted, and the application scenario is to use the tunnel to access the whole internet, so the dst-address of the template cannot be restricted either.

You are absolutely right, I didn’t realise I did not set up a DNS server in my DHCP scope (I have a local DNS server), apparently this caused the VPN’s DNS server to be populated even for DHCP leases not set up in the mode config.
In the end, I decided the solution isn’t flexible enough for me, so I went with a local VPN client on the TV. However, I did learn a lot about properly setting up an IPsec tunnel :slight_smile: Thanks again for your help and valuable advice.