Mikrotik: configure IPsec to automatically update the VPN server address

When configuring IPSec, sooner or later, everyone is faced with the fact that you can only set the IP addresses of the remote VPN server. Specifying DNS records in the IPsec Policies and IPsec Peers settings is not supported.

This can cause some inconvenience in cases where the VPN server:
  • changed one provider to another;
  • Decided to change the used static IP address;
  • dynamic (gray) IP address is used.


Taking even the simplest scheme, it becomes clear that we will have to change the settings of the three router clients of the VPN server:



And in each of the three routers, change the values:
  • Ipsec / policy / dst-address
  • Ipsec / policy / sa-dst-address
  • Ipsec / peer / address


In reality, when there are tens and hundreds of customers, automation of this process becomes a necessity. Let's see how to implement this using standard Microtik features: DDNS, Scripts, and Scheduler.

For fun, we’ll complicate the scheme a bit. Let the central VPN servers we have two routers to which our clients connect.



We enable the DDNS provided by the company on both VPN servers. Mikrotik provides DDNS as a free service to RouterOS customers.

ip cloud set ddns-enabled=yes

Other DDNS Providers
I use the paid DynECT service from DynDNS, but the working scheme does not change from this.

We can see the result: the received A-records in the domain sn.mynetname.net , pointing to our VPN servers.

 > ip cloud print 
    ddns-enabled: yes
  public-address: 1.1.1.1
        dns-name: 111111111111.sn.mynetname.net
          status: updated

We pass to routers which act as clients.

In the IpSec / Policy and IpSec / Peer settings, in the comments for each line, we will write the DNS names of the VPN servers:





Next, add the SetIpSecDstAddrFromDns script , which will receive the DNS names of our VPN servers from the comment and compare them with the values ​​in the settings:

:if ([:len [/system script job find script=SetIpSecDstAddrFromDns]]>1) do={
  :error
}
:local DnsNameFromComment
:local ResolvedIpFromComment
:local ResolvedIpWithMaskFromComment
:local IpDstAddr
:local IpSaDstAddr
:foreach IpSecPolicyCount in=[/ip ipsec policy find] do={
  :set DnsNameFromComment [/ip ipsec policy get $IpSecPolicyCount comment]
  :if ($DnsNameFromComment!="") do={
    :do {
      :set ResolvedIpFromComment ([:resolve $DnsNameFromComment])
      :set ResolvedIpWithMaskFromComment ($ResolvedIpFromComment . "/32")
      :set IpDstAddr [/ip ipsec policy get $IpSecPolicyCount dst-address]
      :set IpSaDstAddr [/ip ipsec policy get $IpSecPolicyCount sa-dst-address]
      :if ($ResolvedIpWithMaskFromComment!=$IpDstAddr or $ResolvedIpFromComment!=$IpSaDstAddr) do={
        :log warning ("[SetIpSecDstAddrFromDns] Change IpSec policy dst-addr from " . $IpSaDstAddr . " to " . $ResolvedIpFromComment)
        /ip ipsec policy set $IpSecPolicyCount dst-address=$ResolvedIpWithMaskFromComment sa-dst-address=$ResolvedIpFromComment
      }
    } on-error={
      :set ResolvedIpFromComment "unknown"
      :log error ("[SetIpSecDstAddrFromDns] Cant resolve name " . $DnsNameFromComment)
    }
  }
}
:local IpPeerAddr
:foreach IpSecPeerCount in=[/ip ipsec peer find] do={
  :set DnsNameFromComment [/ip ipsec peer get $IpSecPeerCount comment]
  :if ($DnsNameFromComment!="") do={
    :do {
      :set ResolvedIpFromComment [:resolve $DnsNameFromComment]
      :set ResolvedIpWithMaskFromComment ($ResolvedIpFromComment . "/32")
      :set IpPeerAddr [/ip ipsec peer get $IpSecPeerCount address]
      :if ($ResolvedIpWithMaskFromComment!=$IpPeerAddr) do={
        :log warning ("[SetIpSecDstAddrFromDns] Change IpSec peer addr from " . $IpPeerAddr . " to " . $ResolvedIpFromComment)
        /ip ipsec peer set $IpSecPeerCount address=$ResolvedIpWithMaskFromComment
      }
    } on-error={
      :set ResolvedIpFromComment "unknown"
      :log error ("[SetIpSecDstAddrFromDns] Cant resolve name " . $DnsNameFromComment)
    }
  }
}

We add a task to the scheduler, which will run a script every 30 seconds and check if the addresses of our VPN servers are relevant and update them if necessary.

Thanks for attention.

PS This article is not intended for beginners, so I omitted the simplest things, such as setting up a VPN tunnel or describing the Mikrotik scripting language.

Also popular now: