I have a router that connects to multiple ipsec/ike servers with dynamic IP addresses. I would like to write a script that is executed periodically, updating the remote peer address based on the hostname.
My first idea was to use a specfic comment on the peers to store the associated host names. E.g.:
/ip ipsec peer
set 1 comment="address:example1.dyndns.com"
set 2 comment="address:example2.dyndns.com"
set 3 comment="address:example3.dyndns.com"
Next step, I would like to go over these items:
:put [/ip ipsec peer find where comment ~ "address:"]
then resolve the address, check if it is different from the peer address, and change it if it is so.
My problem is that I don’t know how to write a loop like that. I tried :foreach but I don’t know how to get the comment and address attribute of the (found) ipsec peers.
It is even so that the connection stays up until it fails, and the fqdn gets re-resolved before a new connection attempt; there was a period of time (RouterOS releases) when the fqdn was being re-resolved every time the TTL of the previous response expired and the running IKE connection was torn down and re-established if the address changed, so you couldn’t stay connected if the responder was a server in a farm using short-lived DNS records to distribute the load.
However, if you nevertheless want to learn something about RouterOS scripting, here’s how you could do that if you stored the fqdn in peer’s name parameter (and used the comment parameter to flag peers which require such handling):
:foreach peer in=[/ip ipsec peer find where comment~"address:"] do={
:local fqdn [/ip ipsec peer get $peer name]
/ip ipsec peer set $peer address=[:resolve $fqdn]
}
You can even :pick a substring from a comment like “fqdn: my.remote.domain”:
All right then thank you! Meanwhile, I came up with this script:
:foreach peer in=[/ip ipsec peer find where comment~"address:.*"] do={
:local name [/ip ipsec peer get $peer name];
:local comment [/ip ipsec peer get $peer comment];
:local fqdn [:pick $comment 8 50];
:local good [/resolve $fqdn];
:local old [/ip ipsec peer get $peer address];
:if ($good != $old) do={
:local message ("ipsec peer " . $name . " changed from " . [:tostr $old ] . " to " . [ :tostr $good ] . "\r" );
:put $message;
:log info $message;
/ip ipsec peer set $peer address=$good;
}
}
There are two problems with this. The first one is that /resolve returns an ip address, but the peer address parameter expects an ip prefix. I’m not sure how to convert 1.2.3.4 IP address value to 1.2.3.4/32 ip address prefix value. The second thing I’m not sure about is that what happens if I do not check for change, and set the address to the same value it already has.
I just found out that I get “failure: DNS can not be used with passive peer” when I try to set a DNS name for a passive=yes peer.
The /32 is not a problem, it is added automatically if you set the address to just 1.2.3.4 .
I didn’t know that address=fqdn cannot be used for passive=yes peers, I haven’t come across such an application case, can you detail why you need to identify the initiator by the source IP address tracked by fqdn? Is the ID_I value of IKE not sufficient? You can use it to assign all Phase 2 and many Phase 1 properties individually for each initiator.
Any update of peer parameters causes existing connections to be dropped. So yes, a check whether the address has actually changed is necessary.
It is a problem because the $old != $good condition always evaluates to false. It means that all connections will be dropped periodically, unless I can test for IP change. Possibly I can use tostr to convert both sides and compare them as strings, but that is very clumsy.
I was trying to force ipsec profiles based on IP address ranges. But I think you are right, I can stop doing that. The IKE id should be sufficient.
Ah, sorry, I didn’t realize the problem is the comparison, not the update.
The fastest solution is $good in $old; here, the first parameter ($good) may be an IP address or a prefix, and the second one ($old) is always a prefix (192.168.0.0 in 192.168.0.0/32 returns true, whereas 192.168.0.0 in 192.168.0.0 returns false without any error message).
Regarding choice of different /ip ipsec profile rows depending on address of the remote peer, you can do the following:
assign multiple private addresses not conflicting with any existing subnet in your network to the Mikrotik itself (a bridge without any ports is the best choice of an interface to use)
for each passive=yes peer with same exchange-mode but different profile, use a different local-address from those created above; set the address of these peers to 0.0.0.0/0
create an address list item for each remote peer, where address will be that peer’s fqdn and the list value will be the same for all remote peers that should land at the same /ip ipsec peer row
create an action=dst-nat firewall rule for each local peer, matching on src-address-list and with to-addresses pointing to the local-address of the respective peer.
An fqdn as address in an /ip firewall address-list item gets resolved, creates one or more dynamic items in the same list with the IP numbers it has resolved to, and whenever the response’s TTL expires, the process repeats.
I went through my config again, and it seems that I could use a single profile for all VPN clients. What I cannot do is to use different policies for different clients (identities). Each client has a specific (remote) subnet, and I need to create different policies for each client (identity). For example, the identity branch01 has remote subnet 172.16.1.0/24 and the identity branch02 has remote subnet 172.16.2.0/24 etc. I want to (manually) create specific policies that are used for specific identities. I could not find a way to assign policies with identities directly. Every identity has a peer, and every policy has a peer. But there is no way to assign policies to identities (at least I could not do it). This is the real reason why I need to create a separate peer for each identity, because this way the peer determines the identity, and then I can create the policies for the peers (which in this case, also determines the identity).
However, the (passive) peer configs must be differentiated somehow. And the only way to do this (as far as I know) is to specify their address directly. (Everything else is the same: same profile, same exchange method etc.) The VPN clients do not have fixed addresses. So in the end, I’m forced to create as many passive peers as many identities I have, and update their address property periodically with a script.
If you could tell me a simpler way to achieve this, then I would be very happy.
I’m not sure it is a simpler way, but it seems to be the intended way:
at the responder (server),
for each remote initiator (client), create an individual row in /ip ipsec policy group: /ip ipsec policy group
add name=branch01-group
add name=branch02-group
for each remote initiator, create an individual policy template referring to that group, with src-address and dst-address you would otherwise set up in the static policy: /ip ipsec policy
add src-address=10.0.0.0/24 dst-address=172.16.1.0/24 template=yes group=branch01-group proposal=xyz
add src-address=10.0.0.0/24 dst-address=172.16.2.0/24 template=yes group=branch01-group proposal=xyz
on each /ip ipsec identity row, set generate-policy=port-strict policy-template-group=branchXX-group
at the initiators, configure the static policies as needed (src-address=172.16.X.0/24 dst-address=10.0.0.0/24)
With IKEv2 mode, it is possible that if you use a policy template 0.0.0.0/0 <->0.0.0.0/0 and generate-policy=port-strict at the initiators, it will work as well (as IKEv2 allows the peers to negotiate an intersection of their policies), but I have never actually tried this.
Oh, I always wondered about the usefulness of policy template groups. Thank you, I’ll try this.
For me, sometimes it is hard to see the connections between policies, groups, identities and peers. (I work with databases, already tried to draw an ER diagram with these entities but failed to do so.)
I’m trying to add policy groups for each initiator. I’m having problems with specifying the different profiles.
You wrote this: “You can use it to assign all Phase 2 and many Phase 1 properties individually for each initiator.”
I don’t see how? Phase 1 (/ip ipsec profile) can only be assigned to peers. It cannot be assigned to policies or identities.
If I try to add two peers with different profiles without specifying the remote addresses, then all of them but the first one becomes unavailable:
/ip ipsec peer
add exchange-mode=ike2 name=peer-branch01 passive=yes profile=profile-for-branch01
# This entry is unreachable
add exchange-mode=ike2 name=peer-branch02 passive=yes profile=profile-for-branch02
# This entry is unreachable
add exchange-mode=ike2 name=peer-branch03 passive=yes profile=profile-for-branch03
Let’s say that I have 20 initiators that require stronger encryption, and 20 initiators that can only use weaker encryption. Each initiator has a different identity, that is known in advance. But I cannot create peers with different profiles, all but one becomes unavailable.
The only way I see to make this work, is to create 40 different passive=yes peers, with different address values. For passive=yes peers, fqdn cannot be used for the address parameter. So it means that I have to use a script to update the address parameters.
Just to be clear, I want a solution where I can use different phase1 profiles AND different policies for each identity at the same time. I think you already gave me a solution for policy-identity assignment by assigning them to different policy groups. You also gave me a solution for using different profiles for different identities, by assigning them to technical local addresses. If I want to combine them for 20 initiators, then I need to add 20 policy groups, 20 new technical bridges and 20 new NAT rules. It seems to be a very awkward cumbersome solution.
Adding 20 different peers and updating their addresses from a script is also cumbersome, but it seems less cumersome to me.
The best solution would be the ability to assing and address list to an ipsec peer, instead of a single address. But that is not possible.
Well, I think I have two working solution now. We can say that the problem was solved.
Bad wording on my side. When mentioning “many Phase 1 properties”, I had in mind the various parameters of identity, but these are probably strictly speaking not Phase 1 properties. So yes, you are right, only a single profile (Phase 1 proposal) row can be linked to a single peer row.
That’s an expected behaviour - when acting as a responder, the IPsec stack chooses the peer already based on the properties of the initial packet received from the initiator. The properties taken into account are the source address, the destination address, and the exchange mode (plus IKE version, which is integrated into the same property of the RouterOS configuration).
So to allow the stack to distinguish between multiple peers with the same address parameter, they must differ in exchange-mode (not possible in your case) and/or local-address. Since most of us are thankful to have a single public IP, let alone multiple ones, we cannot distinguish the peers by public local addresses. But the IPstack is not the first layer of the network stack to receive the packet - multiple layers of firewall, including the dstnat chain, handle the packet first.
So as I wrote in one of previous posts, you can create two passive (responder-only) peers, each with a different local-address parameter, and dst-nat the incoming connections to one of these private local addresses depending on the fqdn of the initiator. Details are explained in one of my previous posts in this topic.
So you don’t need 20 peers, just two, so only two technical private IPs are enough. And both (or all) can be assigned to the same interface. It even need not be a dedicated bridge, it can be one of existing interfaces, but it is just less dependencies to think about if it is the dedicated bridge.
Also (number_of_peers - 1) dst-nat rules are sufficient (one peer’s local-address may be the public one) - you can place multiple fqdns to the same address-list.
I should use as many peers (and technical local addresses) as many ipsec phase1 profiles I have. If I have two different profiles, then I need to add two peers with different technical addresses. Then connect the local addresses by initiator addresses with NAT rules. With NAT rules, I’ll be able to use address lists.
Then I should also use policy groups - as many groups as many initiators - and connect the identities with the manually created ipsec policies through these.
Make sense, but it took me some time to interpret.
If the ISP are not totally stupid, there should be no way for you to access the management of their radius server to modify anything there (but there also should be no way for you to access the management of their access point, right?). The RADIUS protocol the access points use to obtain the subscriber settings is only designed for reading the configuration instructions and for traffic accounting, not for provisioning of the subscriber data.
If you want to study how things work, I’d suggest you to use a virtualization environment and learn there rather than hacking your ISP network. With your own lab environment, you don’t risk cutting yourself off the internet.