I have a multiple connections with NordVPN and just saw that I had errors in the log about the certificate.
The certificate is running till 1 January 2036 so that could not be the problem.
Other connections to NordVPN are working fine and reconnect.
The only thing I can think of is that the server is having a different certificate than the local certificate store provides.
% ssh mikrotik / system script run nordvpn-recommendations | jq --raw-output '.[].hostname'
de861.nordvpn.com
de877.nordvpn.com
de856.nordvpn.com
Et voilà, three hosts to choose from.
Sadly there is no json parser in RouterOS… Mikrotik, please add one, I could use it for several things!
(I know there are scripts parsing json, but these are really huge.)
You can replace “nl” by “de” if and this is taken from adding a address-list but the RegEX can also be used to filter out the domain names. It has to be adapted and I will have a look at it later today.
Yes, spend gobs of money on code for useful stuff so people using questionable vpn sites can have easy lives… hint to MT - dont bother as there are much higher priorities to work on than this little distraction.
This will return the first active domain in the list:
:local data ([ / tool fetch url="https://api.nordvpn.com/v1/servers/recommendations\?limit=1" output=user as-value ]->"data"); :local position [:find $data nordvpn.com]; put [:pick $data ($position-6) ($position+11)];
And a working script writing the active domains to the log:
# Written by Shumkov
# Adapted by blacklister
# rewritten to list VPN servers
# version 20200703-01
}
:do {
:local data ([ / tool fetch url="https://api.nordvpn.com/v1/servers/recommendations\?limit=20" output=user as-value ]->"data")
:while ([:len $data]!=0) do={
:if ([:pick $data 0 [:find $data "load"]]~"[a-z][a-z][0-9]{1,3}\\.nordvpn\\.com") do={
:local position [:find $data nordvpn.com]
:do {log info [:pick $data ($position-6) ($position+11)] } on-error={}
:put [:pick $data ($position-6) ($position+11)]
}
:set $data [:pick $data ([:find $data "}}]}"]+1) [:len $data]]
}
} on-error={:log warning "Limit set to high. Data does not fit in the variable and update has failed."}
}
You can adapt it to write it to a array, put it directly in a list/dns or in a file.
Many thanks eworm for providing the download location of the file. I can extract up to 20 domains in one, this due to the length limitation in RouterOS for variables.
I can run it yet as a script and there must be something wrong which I don’t discover at this early hour. Copied and past in Terminal works fine.
If I use a put instead of a log:
snip
{... } on-error={:log warning "Limit set to high. Data does not fit in the variable and update has failed."}
nl388.nordvpn.com
nl636.nordvpn.com
nl628.nordvpn.com
nl682.nordvpn.com
nl742.nordvpn.com
nl698.nordvpn.com
nl699.nordvpn.com
nl691.nordvpn.com
nl679.nordvpn.com
nl597.nordvpn.com
nl599.nordvpn.com
nl674.nordvpn.com
nl592.nordvpn.com
nl626.nordvpn.com
nl720.nordvpn.com
nl693.nordvpn.com
nl605.nordvpn.com
nl726.nordvpn.com
nl686.nordvpn.com
nl623.nordvpn.com
Having thought more about it, it looks that there could be two approaches to this in reading a JSON file like this.
Your could go for only one value or just convert the JSON file up to 64KB in size to a array containing the values that is direct accessible by RouterOS.
The last one is think the best solution and the most flexible.
And I have shorted it and made it more flexible. You can now state the name of the field you want to be returned and it adapt the the length of that field. It is still basic but a good start to read from JSON files.
And then you can extract extra information as IP address and the current load on the server. Notice that the “load” is not a string and then a comma is the end of the field.
If I may… the $update url= beginning of the last three lines is there twice (copy-paste went wrong?), but more important, there is a risk that the response will be different each time you read it. So as you read it into a variable anyway, you can just parse the data from the same response for each parameter instead of downloading it again.
You’re welcome. It more a bit of playtime for me doing this. And at the same time improve my scripting.
There can be a difference in matching the data due to time. My next step would be to loop through different requested fields. This will limits the returned values to only strings or numbers.
Putting $data in a global variable and move the read of the file to outside function would enable that.
A thing I am looking for a way to select to only return values if the the encrypting protocol is supported by that server. So filtering on Wireguard or OpenVPN.
Personally I would only be interested in the station/IP addresses to feed my NordVPN connections.
Unfortunately only a full json parser would make you bullet-proof in this case, because the order of the sub-items in the same branch is not guaranteed, plus the availability status of the individual technologies (IKEv2, OpenVPN, Wireguard) on the servers may not be the same, and you need the complete information (server IP, IKEv2 support in general, IKEv2 current availability).
So you have to split the complete answer into the branches representing the individual servers, and within each branch, find the branch of “technologies” which contains “identifier”:“ikev2”, and within “pivot” of that branch, check that the value of “status” is “online”.