Setting up IKEv2 VPN Server behind NAT

Just post the full output of /export hide-sensitive after substituting public IPs and usernames in /ppp secret section. You can also remove static dhcp leases. Certificates and user names are not part of export even without hide-sensitive.

The thing is that you never know where the issue is hidden. If you knew where to look for it, there would be no issue.

Thanks!

Can I share it with you somehow more privately, by any chance?

/interface bridge
add admin-mac=MAC_OF_BRIDGE auto-mac=no comment=defconf name=bridge
add name=site2site-tunnel-vbridge
add comment="Remote VPN Clients" name=vpn-clients-vbridge
/interface ethernet
set [ find default-name=ether1 ] name=wan
/interface eoip
add local-address=192.168.20.3 mac-address= mtu=1400 name=\
    site2site-eoip1 remote-address=192.168.25.2 tunnel-id=3
add local-address=192.168.20.4 mac-address= mtu=1400 name=\
    site2site-eoip2 remote-address=192.168.25.2 tunnel-id=4
/interface bonding
add comment="Site2Site bonding" name=site2site-eoips-bonding slaves=\
    site2site-eoip1,site2site-eoip2
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
add name=incoming
/ip ipsec policy group
add name=default-Site2Site
add name=default-RemoteVPN
/ip ipsec profile
add enc-algorithm=aes-256,aes-128 hash-algorithm=sha256 name=default-Site2Site
add enc-algorithm=aes-256,aes-128 hash-algorithm=sha256 name=default-RemoteVPN
/ip ipsec peer
add address=peer1.TIK1 exchange-mode=ike2 name=\
    Site2SitePeer1 port=34501 profile=default-Site2Site send-initial-contact=no
add address=peer2.TIK1 exchange-mode=ike2 name=\
	Site2SitePeer1 port=34502 profile=default-Site2Site send-initial-contact=no
add exchange-mode=ike2 name=IKE2-Acceptor \
    passive=yes profile=default-RemoteVPN send-initial-contact=no
/ip ipsec proposal
add auth-algorithms=null enc-algorithms=null name=default-Site2Site pfs-group=none
add auth-algorithms=sha256,sha1 enc-algorithms=aes-256-cbc,aes-128-cbc name=\
    default-RemoteVPN pfs-group=modp2048
/ip pool
add name=lan ranges=192.168.2.100-192.168.2.200
add name=ike2-vpn ranges=192.168.200.100-192.168.200.200
/ip dhcp-server
add address-pool=lan disabled=no interface=bridge name=defconf
/ip ipsec mode-config
add address-pool=ike2-vpn address-prefix-length=32 name=vpnpool-systemdns
/user group
set full policy="local,telnet,ssh,ftp,reboot,read,write,policy,test,winbox,pas\
    sword,web,sniff,sensitive,api,romon,dude,tikapp"
/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 list member
add comment=defconf interface=bridge list=LAN
add comment=defconf interface=wan list=WAN
add interface=wan list=incoming
add interface=site2site-eoips-bonding list=incoming
add interface=vpn-clients-vbridge list=LAN
/ip address
add address=192.168.2.1/24 comment=defconf interface=bridge network=\
    192.168.2.0
add address=192.168.20.3 interface=site2site-tunnel-vbridge network=192.168.20.3
add address=192.168.20.4 interface=site2site-tunnel-vbridge network=192.168.20.4
add address=192.168.30.2/30 interface=site2site-eoips-bonding network=192.168.30.0
add address=192.168.170.65/24 interface=wan network=192.168.170.0
add address=192.168.200.1/24 comment="VPN bridge" interface=\
    vpn-clients-vbridge network=192.168.200.0
/ip dns static
add address=a.b.c.d name=peer1.TIK1
add address=a.b.c.d name=peer2.TIK1
/ip firewall address-list
add address=EXTERNAL_DNSNAME list=ExternalIP
add address=myip.com list=ThroughSite2SiteTunnel
/ip firewall filter
add action=log chain=forward log=yes log-prefix=TX src-address-list=\
    ThroughSite2SiteTunnel
add action=log chain=forward dst-address-list=ThroughSite2SiteTunnel log=yes log-prefix=\
    RX
add action=accept chain=input comment=\
    "defconf: accept established,related,untracked" connection-state=\
    established,related,untracked
add action=accept chain=input comment="conf: accept IPsec" dst-port=500,4500 \
    protocol=udp
add action=accept chain=input comment="conf: accept GRE (for IPsec tunnels)" \
    ipsec-policy=in,ipsec protocol=gre
add action=drop chain=input comment="defconf: drop invalid" connection-state=\
    invalid log=yes
add action=accept chain=input comment="defconf: accept ICMP" protocol=icmp
add action=accept chain=input comment=\
    "defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1
add action=accept chain=input comment="defconf: accept all traffic from site2site tunnel" \
    in-interface=site2site-eoips-bonding
add action=drop chain=input comment="defconf: drop all not coming from LAN" \
    in-interface-list=!LAN log=yes
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-mark=no-mark 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=accept chain=prerouting comment="est. rel. connections without conm\
    ark are accepted to prevent next rules" connection-mark=no-mark \
    connection-state=established,related
add action=accept chain=prerouting comment=\
    "download packets must not be routing-marked" connection-state=\
    established,related in-interface-list=incoming
add action=mark-routing chain=prerouting comment=\
    "connection marked packets marked for route also" connection-mark=\
    ipsec-site2site-tunnel-route new-routing-mark=ipsec-site2site-tunnel-route passthrough=no
add action=mark-connection chain=prerouting comment=\
    "only initial packets of connections get here past the rules above" \
    connection-state=new dst-address-list=ThroughSite2SiteTunnel new-connection-mark=\
    ipsec-site2site-tunnel-route passthrough=yes
add action=mark-routing chain=prerouting comment="initial packets of connectio\
    ns which evaded the rules above get here with no routing mark; we just \
    repeat the mark-routing rules above" connection-mark=ipsec-site2site-tunnel-route \
    new-routing-mark=ipsec-site2site-tunnel-route passthrough=no
/ip firewall nat
add action=src-nat chain=srcnat comment="!!!! srcnat disabled !!!!" \
    connection-mark=ipsec-site2site-tunnel-route disabled=yes log=yes to-addresses=\
    192.168.30.2
add action=masquerade chain=srcnat comment="defconf: masquerade" \
    ipsec-policy=out,none out-interface-list=WAN
/ip ipsec identity
add comment="Site2Site tunnels IDs" my-id=fqdn:TIK0.1 peer=Site2SitePeer1 \
    policy-template-group=default-Site2Site
add my-id=fqdn:TIK0.2 peer=Site2SitePeer2 policy-template-group=default-Site2Site
add auth-method=digital-signature certificate=ike2-vpnserver comment=\
    "Remote tunnel(s)" generate-policy=port-strict mode-config=\
    vpnpool-systemdns peer=IKE2-Acceptor policy-template-group=default-RemoteVPN
/ip ipsec policy
add comment="Site2Site tunnel policies" dst-address=192.168.180.10/32 level=unique \
    peer=Site2SitePeer1 proposal=default-Site2Site sa-dst-address=w.x.y.z \
    sa-src-address=0.0.0.0 src-address=192.168.20.3/32 tunnel=yes
add dst-address=192.168.180.10/32 level=unique peer=Site2SitePeer2 proposal=\
    default-Site2Site sa-dst-address=w.x.y.z sa-src-address=0.0.0.0 \
    src-address=192.168.20.4/32 tunnel=yes
add comment=Remote dst-address=192.168.200.0/24 group=default-RemoteVPN \
    proposal=default-RemoteVPN src-address=0.0.0.0/0 template=yes
/ip route
add comment="Site2Site IPsec tunnel" distance=1 gateway=192.168.30.1 routing-mark=\
    ipsec-site2site-tunnel-route
add distance=2 gateway=192.168.170.254

Here we go, thank you!

From what I can see in your mangle rules:

0 action=accept chain=prerouting connection-mark=no-mark connection-state=established,related
1 action=accept chain=prerouting connection-state=established,related in-interface-list=incoming
2 action=mark-routing chain=prerouting connection-mark=ipsec-site2site-tunnel-route new-routing-mark=ipsec-site2site-tunnel-route passthrough=no
3 action=mark-connection chain=prerouting connection-state=new dst-address-list=ThroughSite2SiteTunnel new-connection-mark=ipsec-site2site-tunnel-route passthrough=yes
4 action=mark-routing chain=prerouting connection-mark=ipsec-site2site-tunnel-route new-routing-mark=ipsec-site2site-tunnel-route passthrough=no



  • the initial packet from the phone (SYN) to the destination has connection-state=new, so it evades rules 0 and 1 that match on connection-state=established,related, it evades rule 2 because it doesn’t have connection-mark ipsec-site2site-tunnel-route, and gets connection-marked by rule 3 and then routing-marked by rule 4
  • the next packets from the phone, if they eventually come, skip rule 0 because they do have a connection-mark, and match rule 1 because their in-interface is wan, so they match on in-interface-list=incoming, hence they do not reach rule 2 to get routing-marked.

So what happens to Scenario 2 if you add ipsec-policy=in,none to rule 1?

The firewall log from Scenario 2 in one of our previous posts shows the SYN to be received on wan and aimed to the tunnel, and SYN+ACK to be received on tunnel and aimed to wan, but you haven’t shown the following packet from the phone. If it is a SYN one again, it means that the SYN+ACK one didn’t make it to the phone; if so, the idea above is still relevant but it is not the explanation why the TCP session doesn’t establish.

What happens? It solves all my issues :sunglasses: :sunglasses: :sunglasses: :sunglasses:

Thank you so much Sindy! This was a huge investigation, I’m very thankful!

Hello!

I’ve came across to a small finetune:

I have here a virtual bridge “vpn-clients-vbridge” with an assigned IP Address “192.168.200.1/24”.

This virtual bridge is part of an interface list of “LAN” along with the physical bridge:

/interface list member
add comment=defconf interface=bridge list=LAN
add interface=vpn-clients-vbridge list=LAN

I also have a firewall filter rule:

add action=drop chain=input comment="defconf: drop all not coming from LAN" \
    in-interface-list=!LAN log=yes

And Tik is operating on this domain:

/ip address
add address=192.168.2.1/24 comment=defconf interface=bridge network=\
    192.168.2.0

When my phone connects to the Tik with VPN, it accesses all the local area servers, and printers (192.168.2.x).

However, my phone is not able to access the Tik itself (via the Mikrotik app), with IP 192.168.2.1.

I added this to the filter list (before the drop rule above):

add action=accept chain=input comment=\
    "defconf: accept all traffic from vpn-clients" src-address-list=\
    vpn-clients

(vpn-clients list only has one single item: 192.168.200.0/24)

After the addition of this, my phone is able to connect to Tik (192.168.2.1) via VPN.


My question: the “drop filter” above seems dropping my connection as the in_interface is not the virtual bridge, but the wan interface.

It seems that virtual bridge is not used anywhere, can I (should I) somehow make IPSec to use the virtual bridge as source of remote VPN clients?

Thank you!

One small addition:

If I modify the accept rule:

add action=accept chain=input comment=\
    "defconf: accept all traffic from vpn-clients" ipsec-policy=in,ipsec

This also works.

Which led me to another question: Which one is more preferred? (this, or the other one with the IP range?)

Accepting an in,ipsec policy on input isn’t a security hole? Or this is only accepted after the ipsec is correctly negotiated and authenticated?

Thank you!

You cannot make the bridge a source (or rather in-interface) of the IPsec payload. The in-interface of IPsec payload is always the in-interface of the IPsec transport packet that has brought that payload. The bridge is there just as a virtual IP interface, so that you could hook 192.168.200.1/24 to it; the question is whether it makes any sense to have this address at all.


There are two things to look at.

First, the ipsec-policy match condition is actually just a macro that checks the packet’s respective headers against all existing policies either directly (ipsec-policy=out,…) or inversely (ipsec-policy=in,…). But the IPsec RFC mandates that a received packet inversely matching an existing IPsec policy was dropped if it did not come in via a security association linked to that policy. This is the case even if the policy is not currently active because the related SA is not established. So in this sense, that rule is not a security hole - the rule itself would indeed match the packet even if it came in the “wrong” way, but the IPsec stack (or, more likely, an invisible dynamic firewall filter rule) drops it before it can reven each the manually configured filter rule.

Second, in more complex networks, the mere fact that a packet came in via an established IPsec SA does not automatically mean that that packet is allowed to get wherever it wants to get - e.g. you may be using IPsec to connect to customers’ networks and you only want a limited set of application connections to get through, so in such cases, you still have to combine the ipsec-policy match condition with additional ones, such as src-address(-list) or even in-interface(-list) ones (no one says all IPsec connections must be established via a single interface).

Regarding which one is better in your particular case - my feeling is that matching a single prefix (src-address) is less CPU-intensive than matching a (src-address,src-port,ip-protocol,dst-address,dst-port) quintuple to a list of traffic selectors. Security-wise, there is no difference in your particular case.

Thank you!

Hello team,
I am writing under this post because I think my issue is simillar to the one here.
I have a mikrotik connected behind an isp so I have a local ip and the isp has the public one.
I am trying to make the mikrotik an ikev2 server But my laptop connection seems to fail constantly and the reason based on the windows message is the there is not connectivity because of nat etc.
I have the exact same configuration to a customer where the public ip is on the mikrotik and it works like a charm.
Does anybody has an idea to suggest?

Your description suggests that Windows have the same default behavior when acting as an IKEv2 initiator like when acting as an L2TP/IPsec client, i.e. to terminate the connection if the responder/server is behind a NAT. There are two ways to address this - you can use regedit to change this behavior and make the Windows accept a server behind a NAT, or you can add the same public IP that runs on your ISP router also to the Mikrotik and dst-nat the incoming traffic back to that public address, so that the NAT detection mechanisms of IPsec would not notice the NAT at responder side. The latter way is better for scenarios with multiple client devices but only works if there is NAT on the client side or if the ISP router can forward ESP (most cannot). And it may trigger issues with pushing the routing table to the client.

There are multiple topics dealing with this here but right now I’ve failed to google up any of them :frowning: So if this brief description is not sufficient, come back for more detailed instructions.

Hello,
Thank you very much for your answer.
I too was trying to find some threads for this issue But this was the only one that I found. :frowning:
I tried and changed the regedit of the windows laptop with no success. :frowning:
I saw the solution with the dst nat But it really got me confused, if somebody has an example of the config it would be great.
Also my isp router cannot forward esp protocol, But is that needed also on ikev2? I am forwarding 500 and 4500 ports. Also I though of forwarding udp port 50 which somebody in the internet said it worked But not for what I need to do. :open_mouth:

UDP port 50 and IP protocol 50 are not the same thing, and too many people who don’t have a clue post authoritative statements on the internet.
IP protocol 50 indeed is ESP, and ESP indeed gets encapsulated into UDP if there is NAT between the peers, but not using port 50.

ESP itself has no notion of ports, which is why NATs have a tough time handling it, so to reliably traverse NAT, it must be encapsulated into UDP. Which is one of the things the peers do if they detect the presence of NAT on the path between them. IKEv2 uses a different message format and procedures as compared to IKE (v1), but both create the same Phase 2 security associations that use the same ESP (or, rarely, AH).

The configuration for the “forth-and-back dstnat” is actually very easy, but before diving into it - does the CN and SAN of the certificate you use on the Mikrotik refer to your public IP, to the private IP of the Mikrotik, or to the FQDN?

It refers to the ddns fqdn.

OK, so the certificate contents is correct but the fact that the public IP is dynamic makes the configuration more complicated.

As for the registry change - as said I have never tried that with IKEv2, so I’m not sure whether the embedded Windows VPN client indeed has an issue with a NATed responder and if it does, whether the same bit in the registry that helps for L2TP/IPsec can be used to change the behavior. So maybe we have to choose another tree to bark at.

So just for a quick proof of concept - add a new bridge, name it br-lo and do not add any ports to it. Then attach the current public address as a /32 one to that bridge, and set up a dstnat rule that will dst-nat whatever comes in via WAN to UDP ports 500 and 4500 to this address. Assuming that you already have the port forwarding in place on the ISP router, that’s all - now try connecting the client from the outside (e.g. via a mobile hotspot). At least 5 minutes must elapse since the last connection attempt from that client so that the non-dst-nated connection could time out from the connection tracking.

If that works, we’ll have to find a way to track the current public address and keep the dst-nat rule and the internal copy of the address in accord. How often does the ISP change the public address?

hi,
I have already a script that trucks the ISP’s public and the truth is that it does not change often.
Now that I made that change I get the message:
no policy found/generated

The config I am using is:
/interface bridge add name=bridge-loopback
/ip address add address=172.16.10.33 interface=bridge-loopback network=172.16.10.32/28
/ip pool add name=“pool vpn.ike2.xyz” ranges=172.16.10.34-172.16.10.46
/certificate add name=CA.ike2.xyz country=MY state=Selangor locality=Cyberjaya organization=IKE2.xyz common-name=ca.ike2.xyz subject-alt-name=DNS:ca.ike2.xyz key-size=2048 days-valid=3650 trusted=yes key-usage=digital-signature,key-encipherment,data-encipherment,key-cert-sign,crl-sign
/certificate sign CA.ike2.xyz
/certificate add name=xxxxxxxxx.sn.mynetname.net country=MY state=Selangor locality=Cyberjaya organization=IKE2.xyz unit=VPN common-name=xxxxxxxxx.sn.mynetname.net subject-alt-name=DNS:xxxxxxxxx.sn.mynetname.net key-size=2048 days-valid=1095 trusted=yes key-usage=tls-server
/certificate sign xxxxxxxxx.sn.mynetname.net ca=CA.ike2.xyz
/certificate add name=ekl_arx_1@xxxxxxxxx.sn.mynetname.net country=MY state=Selangor locality=Cyberjaya organization=IKE2.xyz common-name=ekl_arx_1@xxxxxxxxx.sn.mynetname.net subject-alt-name=email:ekl_arx_1@xxxxxxxxx.sn.mynetname.net key-size=2048 days-valid=365 trusted=yes key-usage=tls-client
/certificate add copy-from=ekl_arx_1@xxxxxxxxx.sn.mynetname.net name=c1@xxxxxxxxx.sn.mynetname.net common-name=c1@xxxxxxxxx.sn.mynetname.net subject-alt-name=email:c1@xxxxxxxxx.sn.mynetname.net
/certificate sign c1@xxxxxxxxx.sn.mynetname.net ca=CA.ike2.xyz
/certificate export-certificate c1@xxxxxxxxx.sn.mynetname.net type=pkcs12 export-passphrase=xxxxxx
/certificate export-certificate CA.ike2.xyz
/ip ipsec mode-config add address-pool=“pool vpn.ike2.xyz” address-prefix-length=32 name=“modeconf vpn.ike2.xyz” split-include=0.0.0.0/0 static-dns=172.16.10.33 system-dns=no ;
/ip ipsec proposal add auth-algorithms=sha512,sha256,sha1 enc-algorithms=aes-256-cbc,aes-256-ctr,aes-256-gcm,aes-192-ctr,aes-192-gcm,aes-128-cbc,aes-128-ctr,aes-128-gcm lifetime=8h name=“proposal vpn.ike2.xyz” pfs-group=none
/ip ipsec profile add dh-group=modp2048,modp1536,modp1024 enc-algorithm=aes-256,aes-192,aes-128 hash-algorithm=sha256 name=“profile vpn.ike2.xyz” nat-traversal=yes proposal-check=obey
/ip ipsec policy group add name=“group vpn.ike2.xyz”
/ip ipsec policy add dst-address=172.16.21.0/30 group=“group vpn.ike2.xyz” proposal=“proposal vpn.ike2.xyz” src-address=0.0.0.0/0 template=yes sa-src-address=0.0.0.0 sa-dst-address=0.0.0.0 ipsec-protocols=esp level=require protocol=all action=encrypt
/ip ipsec peer add exchange-mode=ike2 address=0.0.0.0/0 local-address=xxxxxxxxx name=“peer xxxxxxxxx.sn.mynetname.net” passive=yes send-initial-contact=yes profile=“profile vpn.ike2.xyz”
/ip ipsec identity add auth-method=digital-signature certificate=xxxxxxxxx.sn.mynetname.net remote-certificate=c1@xxxxxxxxx.sn.mynetname.net generate-policy=port-strict match-by=certificate mode-config=“modeconf vpn.ike2.xyz” peer=“peer xxxxxxxxx.sn.mynetname.net” policy-template-group=“group vpn.ike2.xyz” remote-id=user-fqdn:c1@xxxxxxxxx.sn.mynetname.net
/ip firewall mangle add action=change-mss chain=forward new-mss=1360 src-address=172.16.21.0/30 protocol=tcp tcp-flags=syn tcp-mss=!0-1360 ipsec-policy=in,ipsec passthrough=yes comment=“IKE2: Clamp TCP MSS from 172.16.21.0/30 to ANY”
/ip firewall mangle add action=change-mss chain=forward new-mss=1360 dst-address=172.16.21.0/30 protocol=tcp tcp-flags=syn tcp-mss=!0-1360 ipsec-policy=out,ipsec passthrough=yes comment=“IKE2: Clamp TCP MSS from ANY to 172.16.21.0/30”
/ip firewall nat add chain=srcnat src-address=172.16.21.0/30 out-interface=eth1 ipsec-policy=out,none action=masquerade comment="MSQRD IKE2:172.16.21.0/30

Hi there,
There was a configuration mistake.
I corrected it and everything is alright.
Thank you!

First, it makes the posts better readable if you post the configurations between [code] and [/code] tags (one way to get them is to press the </> button in the editing toolbar).

Next, what you posted is not a complete export of the actual configuration but rather a recording of the configuration steps you have executed, so some things may be missing there.

In any case, no policy found/generated indicates that the initial authentication has succeeded. So looking into it, there is a mismatch between the dst-address of the policy template and the pool you assign the address from - you give out addresses from 172.16.10.34-172.16.10.46 so the initiator suggests a policy with one of these addresses at its end but the policy template only allows 172.16.21.0/30 there, no wonder it fails.

Other than that - did you have to assign the public address to a bridge interface to make it work or it turned out not to be necessary after all? What you’ve posted does not answer this question.