Community discussions

MikroTik App
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

MTU troubles using IKEv2 providers like NordVPN [work around]

Tue Dec 03, 2019 3:27 pm

This topic is about ICMP 3/4 packets returned to the client.
You can test that by pressing or click the preview button when writing a posting in this forum.
No preview, or it takes a long time (more than a few seconds) then you are suffering from this and then follow the instructions underneath


I am using IPSEC for a long time and first a mix of L2TP/IPSEC and later IKEv2. Had problems with the MTU on L2TP/IPSEC and hoped that was over when I replaced it with IKEv2. IKEv2 was much nicer to use and much faster. However I had still a small problem with the MTU when using a speedtest.net page and later I noticed that the Mikrotik forum offered a much faster to detect the problem.

Using Wireshark and the following line in Mangle I could detect the ICMP 3/4 packets getting lost in the RouterOS and so not arrive at the client telling it to lower the MTU.
add action=sniff-tzsp chain=postrouting icmp-options=3:4 log=yes log-prefix=post-ICMP protocol=icmp sniff-target=192.168.21.177 sniff-target-port=37008

I used this step for step optimized MSS line to reduced the MTU to a fixed value which dynamically could not be found:
add action=change-mss chain=forward disabled=yes ipsec-policy=in,ipsec log-prefix=MSS new-mss=1382 passthrough=yes protocol=tcp tcp-flags=syn
The code is disabled because Sindy found a much better way using a work around for this problem.

Sindy and I spend a good part of a weekend discussing this and ending up with a work around that ended my quest on this strange behavior. When the ICPM 3/4 packets get lost in RouterOS the data sent to Wireshark gets Network type: unknown 0x0000 what is very strange but an other support ticket.
The thread from that weekend: viewtopic.php?f=2&t=153414&p=760818&hil ... ge#p760818
About the ICMP 3/4 packets not being sent to the client is still a support ticket with Mikrotik and despite several suggestion by them it is still not resolved so I have to keep using the work around.

So what is happening. When using IKEv2 in this case all traffice is going through a tunnel between RouterOS and the VPN provider. RouterOS handles everything so most of the traffic is outside of view of the user. The MTU is determined and used except when the client is 'uploading' traffic then the MTU is not changed resulting in no upstream traffic or RouterOS switch to the emergency MTU of 576/536 resulting in a very low transfer rate but at least there is a traffic flowing upstream.

Sindy brilliant work around is, to use IPSEC policy and create a static policy handling the packets instead of the dynamically generated ones and the position in the policy list does not matter:
/ip ipsec policy
move *ffffff destination=0
add action=none dst-address=192.168.88.0/24 src-address=0.0.0.0/0 place-before=1
place-before=1 and move *ffffff destination=1 added on 17-4-2020

Replace dst-address=192.168.88.0/24 with your own local network address range.
The default template will be moved to the top of the list if it was not already there. The second line should above (action=none) should be below default and above any added IKEv2 provider lines.

The explaination by Sindy.
Anyway, there should be a remedy - a static IPsec policy action=none src-address=0.0.0.0/0 dst-address=the.client's.subnet placed before the policy template which is used to build the dynamic policy with the responder-provided IP address as src-address. This action=none policy will shadow the dynamically generated one so even though the ICMP code 3 type 4 packet will likely get src-nated by the dynamic src-nat rule, it will not reach the dynamic policy (which would divert it into the tunnel) so it will make it to the client. The client won't care about the source address as it has no relevance for it, so it should adjust the size of the re-sent TCP packet and all the subsequent ones accordingly.
This solved my long standing problem. with that work around and many many thank to Sindy for suggesting this!

O, how to test in the Mikrotik forum? That is not too difficult and if you are writing now a reply or editing an previous post you can press the Preview button and when you have the sniffer line active and Wireshark running you will see those unknown packet pop-up in Wireshark. Then is your IKEv2 and maybe IPSEC connection falling back to emergency MTU.
Last edited by msatter on Sat Dec 26, 2020 11:41 am, edited 15 times in total.
 
User avatar
eworm
Forum Guru
Forum Guru
Posts: 1071
Joined: Wed Oct 22, 2014 9:23 am
Location: Oberhausen, Germany
Contact:

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Tue Jan 14, 2020 11:09 pm

You should remove the extra disabled=yes from your code.

I can confirm this workaround works. Any news from Mikrotik about fixing this?
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Tue Jan 14, 2020 11:56 pm

Thanks and the disable=yes is removed.

I don't know. Support did not confirmed this workaround or commented on it. The ticket is still open and you never know what 2020 is going to bring. ;-)
 
ranpha
Frequent Visitor
Frequent Visitor
Posts: 62
Joined: Mon Jan 09, 2012 3:16 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Mar 22, 2020 3:24 pm

add action=none dst-address=168.192.88.0/24 src-address=0.0.0.0/0
Does this works with all IKEv2 VPN providers, or did I have to change the dst-address values?
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Mar 22, 2020 4:39 pm

Yes you have to adapt to your own address range. I have taken the default range set for Mikrotik routers.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 9:05 am

Hi, I also have similar problems but it still doesn't work when I added this policy.
add action=none dst-address=168.192.88.0/24 src-address=0.0.0.0/0
my ipsec configs
# apr/17/2020 14:00:09 by RouterOS 6.46.5
# software id = KFRD-V8Q1
#
# model = RBD52G-5HacD2HnD
# serial number = x
/ip ipsec mode-config
add name=NordVPN responder=no src-address-list=local
/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add name=NordVPN
/ip ipsec peer
add address=sg463.nordvpn.com exchange-mode=ike2 name=NordVPN profile=NordVPN
/ip ipsec proposal
add name=NordVPN pfs-group=none
/ip ipsec identity
add auth-method=eap certificate="" eap-methods=eap-mschapv2 generate-policy=port-strict mode-config=NordVPN peer=NordVPN policy-template-group=NordVPN \
    username=username
/ip ipsec policy
set 0 disabled=yes
add dst-address=0.0.0.0/0 group=NordVPN proposal=NordVPN src-address=0.0.0.0/0 template=yes
add action=none dst-address=192.168.0.0/24 src-address=0.0.0.0/0
maybe there are something wrong with my config?
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 10:23 am

I have to think about that and my first answer was not correct if you address range is 192.168.0.1-192.168.0.255

Update: I can't place the first line:
/ip ipsec policy
set 0 disabled=yes
My template is also a bit different:
/ip ipsec policy
add group=NordVPN proposal=NordVPN template=yes
On copy-paste did something went wrong?

/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add name=NordVPN


The in bold text is only possible in/ip ipsec group.
Last edited by msatter on Fri Apr 17, 2020 10:45 am, edited 1 time in total.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 10:41 am

I have to think about that and my first answer was not correct if you address range is 192.168.0.1-192.168.0.255

Update: I can't place the first line:
/ip ipsec policy
set 0 disabled=yes
the first one is disabled by itself
Image
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 10:47 am

It's simple - the policy you've added must be placed before (above) the template from which the IKEv2 connection creates the actual policy for the connection.

The order of policies matters the same way like the order of firewall rules does - the packet is matched to all of them starting from the topmost one towards the last one until the first match.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 10:54 am

I have updated my first response to you.

Enable the line with X*T and remove line with T . The one with the * is the default line.

::/0 is the same as 0.0.0.0/0 and covers also IPv6 if that is available.

If you do test hit the preview button in this forum when writing a posting and if it is shown then ICMP is working.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:03 am

It's simple - the policy you've added must be placed before (above) the template from which the IKEv2 connection creates the actual policy for the connection.

The order of policies matters the same way like the order of firewall rules does - the packet is matched to all of them starting from the topmost one towards the last one until the first match.
Thanks Cindy. On a reconnect it would automatically get to the top of the list if I am correct. If added manually then a place-before=0 would do.

Update: removed the place-before=0
Last edited by msatter on Fri Apr 17, 2020 12:47 pm, edited 1 time in total.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:11 am

Thanks for your responses,

Currently updated the suggested configs
# apr/17/2020 16:05:02 by RouterOS 6.46.5
# software id = KFRD-V8Q1
#
# model = RBD52G-5HacD2HnD
# serial number = *
/ip ipsec mode-config
add name=NordVPN responder=no src-address-list=local
/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add name=NordVPN
/ip ipsec peer
add address=sg197.nordvpn.com exchange-mode=ike2 name=NordVPN profile=NordVPN
/ip ipsec proposal
add name=NordVPN pfs-group=none
/ip ipsec identity
add auth-method=eap certificate="" eap-methods=eap-mschapv2 generate-policy=port-strict mode-config=NordVPN peer=\
    NordVPN policy-template-group=NordVPN username=*
/ip ipsec policy
add action=none dst-address=192.168.0.0/24 src-address=0.0.0.0/0
set 1 group=NordVPN
but still,
My devices does get the VPN ip and are able to ping websites but cannot browse the internet.
maybe the MTU has to be changed to make it work? My pppoe MTU is 1480.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:19 am

The MTU on the PPPoE is no problem and are you sure the VPN is up again? I see now a set 1 group=NordVPN
add group=NordVPN proposal=NordVPN template=yes
or
set 1 group=NordVPN proposal=NordVPN template=yes
Check if your proposal is the same as I wrote or replace it with your own proposal.

Update: as Cindy pointed out my earlier advise to remove this line was wrong. My excuses for that.
Last edited by msatter on Fri Apr 17, 2020 11:32 am, edited 3 times in total.
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:19 am

Thanks Cindy. On a reconnect it would automatically get to the top of the list if I am correct. If added manually then a place-before=0 would do.
No. The dynamically created policy is always created right below the template from which it was created, so disconnection and reconnection change nothing about the position of the dynamically created policy relatively to the "don't steal traffic towards LAN" one.

Also, to remove the template with policy-group=NordVPN may not have been the best recommendation, as the removed template refers to a proposal named NordVPN which may differ from the one to which the default template refers.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:31 am

I have my template on the group=default. To have it positioned then, then the *T on should be on position 0. When adding it should land on the correct spot underneath *T.

Indeed removing the template and in my the posting above I have addressed that.
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:40 am

maybe the MTU has to be changed to make it work? My pppoe MTU is 1480.
The whole purpose of the added policy with action=none is to allow MSS be automatically adjusted to MTU using the normal mechanisms in case where it is already your Mikrotik, which knows that it would have to fragment the packets, that sends ICMP notifications about this back to the sender, which is the LAN PC. The sender then adjusts the MSS to the reported path MTU and re-sends an accordingly smaller part of the buffer in the packet. The action=none policy prevents packet sent by the Mikrotik itself to LAN subnet from being stolen by IPsec and sent down the tunnel instead.

If the path MTU auto-discovery mechanism is broken somewhere furher down the path from the sender to the destination, this rule won't help and you'll have to use an action=change-mss rule in /ip firewall mangle to assign a static value of new-mss, to overcome that mid-path issue.

If you cannot open any remote site, chances are high that your config is still wrong, and in that case post a complete configuration of the router (see my automatic signature right below for a hint on how to anonymize it and remove any authentication information).

If you can open some sites and cannot open others, the configuration at Mikrotik side is fine and it's the mid-path problem.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 11:54 am

Thanks Cindy and I have tried now for each of my VPN provides a dedicated line instead of the one default one.

First I see (print detail) the template, then the DA lines and underneath those the T line for ICMP. This after restarting the VPN connections.

I don't think a dedicated template is needed to have the ICMP going the correct direction and one default one should be sufficient.

So much still to learn. :-)

You are right Sindy having the line underneath the dynamic lines broke the ICMP and I could not save this posting nor preview it. Having a ICMP on default fixed that so it seems that an ICMP line on default is sufficient as long it is almost on the top. So the place-before=0 is possible and to not push the *T (template) of its position a place-before=1 is sufficient.

My current settings (adapted to the one of nemoonpc) :
/ip ipsec policy
set 0 dst-address=0.0.0.0/0 src-address=0.0.0.0/0
add action=none comment="Fragmented (ICMP 3/4) sent to clients. 192.168.21.0/24 10.10.10.0/24" dst-address=192.168.0.0/24 src-address=0.0.0.0/0
add dst-address=0.0.0.0/0 group=PureVPN proposal=PureVPN src-address=0.0.0.0/0 template=yes
Last edited by msatter on Fri Apr 17, 2020 12:28 pm, edited 3 times in total.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 12:19 pm

maybe the MTU has to be changed to make it work? My pppoe MTU is 1480.
The whole purpose of the added policy with action=none is to allow MSS be automatically adjusted to MTU using the normal mechanisms in case where it is already your Mikrotik, which knows that it would have to fragment the packets, that sends ICMP notifications about this back to the sender, which is the LAN PC. The sender then adjusts the MSS to the reported path MTU and re-sends an accordingly smaller part of the buffer in the packet. The action=none policy prevents packet sent by the Mikrotik itself to LAN subnet from being stolen by IPsec and sent down the tunnel instead.

If the path MTU auto-discovery mechanism is broken somewhere furher down the path from the sender to the destination, this rule won't help and you'll have to use an action=change-mss rule in /ip firewall mangle to assign a static value of new-mss, to overcome that mid-path issue.

If you cannot open any remote site, chances are high that your config is still wrong, and in that case post a complete configuration of the router (see my automatic signature right below for a hint on how to anonymize it and remove any authentication information).

If you can open some sites and cannot open others, the configuration at Mikrotik side is fine and it's the mid-path problem.
Currently still connection timed out for most websites.
I only assign 1 IP / device to the VPN tunnel ( address list in the firewall listed as local )
not sure if that would interfere with the ipsec policy with action=none
my router configs below:
# apr/17/2020 17:14:49 by RouterOS 6.46.5
# software id = KFRD-V8Q1
#
# model = RBD52G-5HacD2HnD
# serial number = *
/interface bridge
add admin-mac=74:4D:28:CB:14:22 auto-mac=no comment=defconf name=bridge
add name=unifi.iptv
/interface wireless
set [ find default-name=wlan1 ] antenna-gain=0 band=2ghz-b/g/n channel-width=20/40mhz-XX country=malaysia distance=indoors \
    frequency=auto installation=indoor mode=ap-bridge ssid=MikroTik-CB1426 wireless-protocol=802.11
set [ find default-name=wlan2 ] antenna-gain=0 band=5ghz-a/n/ac channel-width=20/40/80mhz-XXXX country=malaysia distance=\
    indoors frequency=auto installation=indoor mode=ap-bridge ssid="AMPHAC\C2\B2" wireless-protocol=802.11
/interface vlan
add interface=ether1 name=vlan500 vlan-id=500
add interface=ether1 name=vlan600 vlan-id=600
/interface pppoe-client
add add-default-route=yes disabled=no interface=vlan500 name=pppoe-tmunifi service-name="TM UNIFI VDSL2" user=*
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
/interface wireless security-profiles
set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk eap-methods="" mode=dynamic-keys supplicant-identity=\
    MikroTik
/ip hotspot profile
set [ find default=yes ] html-directory=flash/hotspot
/ip ipsec mode-config
add name=NordVPN responder=no src-address-list=local
/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add name=NordVPN
/ip ipsec peer
add address=sg197.nordvpn.com exchange-mode=ike2 name=NordVPN profile=NordVPN
/ip ipsec proposal
add name=NordVPN pfs-group=none
/ip pool
add name=dhcp ranges=192.168.0.20-192.168.0.50
add name=hs-pool-1 ranges=10.5.50.2-10.5.50.20
/ip dhcp-server
add address-pool=dhcp disabled=no interface=bridge 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
/interface bridge port
add bridge=bridge comment=defconf interface=ether3
add bridge=bridge comment=defconf interface=ether4
add bridge=bridge comment=defconf interface=ether5
add bridge=bridge comment=defconf interface=wlan1
add bridge=bridge comment=defconf interface=wlan2
add bridge=unifi.iptv interface=vlan600
add bridge=unifi.iptv interface=ether2
/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 disabled=yes interface=ether1 list=WAN
add interface=pppoe-tmunifi list=WAN
/ip address
add address=192.168.0.250/24 comment=defconf interface=bridge network=192.168.0.0
add address=10.5.50.1/24 comment="hotspot network" interface=wlan1 network=10.5.50.0
/ip cloud
set ddns-enabled=yes
/ip dhcp-client
add comment=defconf interface=ether1
/ip dhcp-server lease
add address=192.168.0.1 client-id=1:9c:5c:8e:7b:c1:23 mac-address=9C:5C:8E:7B:C1:23 server=defconf
add address=192.168.0.10 client-id=1:10:62:eb:a3:e7:73 mac-address=10:62:EB:A3:E7:73 server=defconf
add address=192.168.0.5 client-id=1:c:98:38:d2:fc:63 mac-address=0C:98:38:D2:FC:63 server=defconf
/ip dhcp-server network
add address=192.168.0.0/24 comment=defconf gateway=192.168.0.250 netmask=24
/ip dns
set allow-remote-requests=yes servers=1.1.1.1,1.0.0.1,2606:4700:4700::1111,2606:4700:4700::1111
/ip dns static
add address=192.168.0.250 comment=defconf name=router.lan
/ip firewall address-list
add address=*.sn.mynetname.net list=WAN-IP
add address=192.168.0.5 list=local
/ip firewall filter
add action=accept chain=input comment="defconf: accept established,related,untracked" connection-state=\
    established,related,untracked
add action=accept chain=input comment="WINBOX REMOTE ACCESS" dst-port=8291 protocol=tcp
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=accept chain=input comment="defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1
add action=drop chain=input comment="defconf: drop all not coming from LAN" in-interface-list=!LAN
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 nat
add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=192.168.0.0/24 src-address=192.168.0.0/24
add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN
add action=dst-nat chain=dstnat comment="MC Server 25565" dst-address-list=WAN-IP dst-port=25565 protocol=tcp \
    to-addresses=192.168.0.1 to-ports=25565
add action=dst-nat chain=dstnat comment="MC Server 25566" dst-address-list=WAN-IP dst-port=25566 protocol=tcp \
    to-addresses=192.168.0.1 to-ports=25566
/ip firewall service-port
set ftp disabled=yes
/ip ipsec identity
add auth-method=eap certificate="" eap-methods=eap-mschapv2 generate-policy=port-strict mode-config=NordVPN peer=NordVPN \
    policy-template-group=NordVPN username=abc@abc.a
/ip ipsec policy
add action=none dst-address=192.168.0.0/24 src-address=0.0.0.0/0
set 1 disabled=yes
add group=NordVPN proposal=NordVPN template=yes
/ipv6 address
add disabled=yes from-pool=pppoev6 interface=bridge
/ipv6 dhcp-client
add add-default-route=yes interface=pppoe-tmunifi pool-name=pppoev6 request=prefix use-peer-dns=no
/ipv6 firewall address-list
add address=::/128 comment="defconf: unspecified address" list=bad_ipv6
add address=::1/128 comment="defconf: lo" list=bad_ipv6
add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6
add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6
add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6
add address=100::/64 comment="defconf: discard only " list=bad_ipv6
add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6
add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6
add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6
add address=::224.0.0.0/100 comment="defconf: other" list=bad_ipv6
add address=::127.0.0.0/104 comment="defconf: other" list=bad_ipv6
add address=::/104 comment="defconf: other" list=bad_ipv6
add address=::255.0.0.0/104 comment="defconf: other" list=bad_ipv6
/ipv6 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 ICMPv6" protocol=icmpv6
add action=accept chain=input comment="defconf: accept UDP traceroute" port=33434-33534 protocol=udp
add action=accept chain=input comment="defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=udp \
    src-address=fe80::/10
add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=input comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=input comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=input comment="defconf: drop everything else not coming from LAN" in-interface-list=!LAN
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 packets with bad src ipv6" src-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" hop-limit=equal:1 protocol=icmpv6
add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=icmpv6
add action=accept chain=forward comment="defconf: accept HIP" protocol=139
add action=accept chain=forward comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=forward comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=forward comment="defconf: drop everything else not coming from LAN" in-interface-list=!LAN
/system clock
set time-zone-name=Asia/Kuala_Lumpur
/tool mac-server
set allowed-interface-list=LAN
/tool mac-server mac-winbox
set allowed-interface-list=LAN

 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 12:35 pm

You are using DOH and there also dynamic DNS servers from NordVPN active try it with DOH deactivated. Should not make a difference but better one captain on the ship.

Let me know if you find somthing and else just remove the current config and leave the defaults (also active) and do a new IPSEC NordVPN setup form the manuals/wiki.
Then add the ICMP in /ip pisec policy underneath the default *T (template) line and then start your NordVPN connection.
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 12:56 pm

Then add the ICMP in /ip pisec policy underneath the default *T (template) line and then start your NordVPN connection.
Not underneath, above!!! The ICMP packets from Mikrotik itself to the LAN hosts must hit the action=drop policy before hitting the dynamically created one!!!

Currently still connection timed out for most websites.
most and all are a difference. If there are websites which work, it means that the problem with the rest is not at your Mikrotik.
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 1:02 pm

Also, you have two LAN subnets, 192.168.0.0/24 for local devices and 10.5.50.0/24 for hotspot clients. So if it's the hotspot clients who experience this problem, you need a similar action=none policy also for that subnet.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 1:37 pm

Then add the ICMP in /ip pisec policy underneath the default *T (template) line and then start your NordVPN connection.
Not underneath, above!!! The ICMP packets from Mikrotik itself to the LAN hosts must hit the action=drop policy before hitting the dynamically created one!!
I wrote underneath the default and not underneath the NordVPN line(s) assuming ofcourse the default template (*T) is at position 0.
It is a manually created template so putting it at postion 0 is on the table again?

Edit: moving the default to position 0 can be done by the command:
move *ffffff destination=0
Last edited by msatter on Fri Apr 17, 2020 2:21 pm, edited 1 time in total.
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Apr 17, 2020 2:21 pm

Sorry, I've focused on the T as template and missed the "default". You are right that as long as the default template is not actually used (which I guess is always the case for NordVPN), the default template may stay at the top and the ICMP-saving one may be below it.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Apr 19, 2020 3:34 pm

Hmmm strange, then I am able to browse ipleak but gets this.
Does the proposal for the action=none fragmented ICMP policy has to set to the vpn proposal or just leave it as default?
Image
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Apr 19, 2020 6:15 pm

Does the proposal for the action=none fragmented ICMP policy has to set to the vpn proposal or just leave it as default?
action=none doesn't need any proposal. The two issues the ipleak page indicates to you are unrelated to each other:
  • the WebRTC warning would be relevant if it showed the public IP of your WAN; as it shows a private IP on your LAN, it means that this IP leaks in the payload of the messages which the browser sends to the server. As these messages are most likely sent using https, there is no easy way how a VPN could modify their contents. Doing so would require a device performing a MITM attack based on generating a forged server certificate signed by a CA which your PC trusts, deciphering the messages, modifying them, and re-cipering them. So it is much easier and generally safer to run the PC on which you use the browser connectíng to WebRTC services on a private IP.
  • the DNS leakage happens if you access the actual server via VPN, but the DNS query used to resolve its domain name to an IP address is sent to a DNS server via your basic internet uplink, not via the VPN. If you are sure that you have configured the addresses of NordVPN's DNS servers in your PC's network configuration, you may want to use an action=dstnat rule in Mikrotik's firewall to redirect any DNS query coming from the PC to Mikrotik's own DNS server (if that one uses the NordVPN's servers) or directly to one of the NordVPN's DNS servers (the only scenario where this would make sense is if some application on the PC was ignoring the network configuration and using its own DNS servers, which is a behaviour the leakip page is unable to detect as it cannot request your browser to bypass normal DNS handling).
    If you have more than one network interface on the PC, it is possible that Windows on that PC are configured to send DNS queries via gateways asscociated to all network interfaces, bypassing regular routing rules. This used to be the default setting at certain time, maybe it still is. The purpose seems to be to get the response as fast as possible, assuming that the DNS may be better reachable via some other gateway than the one chosen by routing.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Apr 19, 2020 7:03 pm

When I temember it well you use the DoH client in RouterOS to connect to Cloudflare. This DNS DoH traffic is not passing through the VPN because only your client IP 192.168.0.5 is using only the VPN.

The shortest way for now is to use the dynamic DNS server of NordVPN and disable DoH. This if you don't want to 'leak' DNS requests.
Your ISP can't look into your encrypted DNS requests and also not in your encrypted VPN connection. So the risks are minimal to none.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Apr 19, 2020 9:37 pm

When I temember it well you use the DoH client in RouterOS to connect to Cloudflare. This DNS DoH traffic is not passing through the VPN because only your client IP 192.168.0.5 is using only the VPN.

The shortest way for now is to use the dynamic DNS server of NordVPN and disable DoH. This if you don't want to 'leak' DNS requests.
Your ISP can't look into your encrypted DNS requests and also not in your encrypted VPN connection. So the risks are minimal to none.
How do I disable DoH ? Currently I'm using 1.1.1.1 and disabled use peer dns on the ppooe connection. I don't see and DoH options in ROS, should I enable use peer dns (ppooe) and clear the custom dns ?
 
tinus
just joined
Posts: 16
Joined: Thu Oct 27, 2005 9:01 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Mon Apr 20, 2020 10:17 pm

Hi msatter,
I still have issue for NordVPN with IKEv2.
VPN connected, Ping and Traceroute no issue, but web browsing is still problem.
Disable fasttrack up-to use IPSEC policy and create a static policy handling the packets also not working.
Could you share your full config for NordVPN?
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Tue Apr 21, 2020 2:11 pm

I use the provided config by Mikrotik in the Wiki and I use connection-marking to selrct the traffic I want have handled by the VPN. Fasttracking and IPSEC is a no-no.

The policy has to be at the top in /ip ipsec policy table and the NordVPN lines underneath. To be sure the order is correct you could run: /ip ipsec policy print

The universal check is is when posting/editing in THIS forum to click or press the preview button and you will have your answer. No preview then your policy line to your local network does not work. If you get shown a preview then the policy line is working.

This ofcourse depends if you are visiting the forum.mikrotik.com through the VPN.

It is simple to check. sadly it seems not to be picked up or refered, to by anybody.
Mikrosoft...hahaha I wrote that instead of Mikrotik but that was my subconscious thinking the way Mikrotik is handling this problem. Frustrating it is. Support request went nowhere and I gave up.
 
nemoonpc
just joined
Posts: 8
Joined: Thu Jan 23, 2020 6:27 am
Location: Kuala Lumpur, Malaysia

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Thu Apr 23, 2020 7:31 pm

update: I've added google dns to DNS tab, vpn dynamic servers does appear.
I also changed to Surfshark ikev2. The VPN still didn't work properly.
When I IPLeak test the connection for my device, ipv4 vpn ip is detected, but ISP ipv6 are also detected. The DNS detected are google dns, not the VPN dns. (ip leaked)
Then, I disabled ipv6 in the router, my device (vpn) could not get any internet anymore.

I also excluded ipsec from fasttrack and added mark connections in mangle
I doubt there are something to do with the DNS settings, or firewall, not sure.
and is there any ways that I can automatically disable ipv6 to the clients when using the VPN without actually disable IPv6 in the router?
# apr/24/2020 00:01:14 by RouterOS 6.46.5
# software id = KFRD-V8Q1
#
# model = RBD52G-5HacD2HnD
# serial number = **********
/interface bridge
add name=TMNETUNIFI.IPTV
add admin-mac=74:4D:28:CB:14:22 auto-mac=no comment=defconf name=bridge
/interface wireless
set [ find default-name=wlan1 ] antenna-gain=0 band=2ghz-b/g/n channel-width=20/40mhz-XX country=malaysia distance=\
    indoors frequency=auto installation=indoor mode=ap-bridge ssid=MikroTik-CB1426 wireless-protocol=802.11
set [ find default-name=wlan2 ] band=5ghz-a/n/ac channel-width=20/40/80mhz-XXXX country=malaysia distance=indoors \
    frequency=auto installation=indoor mode=ap-bridge ssid="AMPHAC\C2\B2" wireless-protocol=802.11
/interface vlan
add interface=ether1 name=vlan500 vlan-id=500
add interface=ether1 name=vlan600 vlan-id=600
/interface pppoe-client
add add-default-route=yes disabled=no interface=vlan500 name=pppoe-tmunifi service-name=TMNET_UNIFI_VDSL2 user=\
    ***********
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
/interface wireless security-profiles
set [ find default=yes ] authentication-types=wpa-psk,wpa2-psk eap-methods="" mode=dynamic-keys \
    supplicant-identity=MikroTik
/ip hotspot profile
set [ find default=yes ] html-directory=flash/hotspot
/ip ipsec mode-config
add name=SSVPN responder=no src-address-list=vpnc
/ip ipsec policy group
add name=SSVPN
/ip ipsec profile
add name=SSVPN
/ip ipsec peer
add address=lv-rig.prod.surfshark.com disabled=yes exchange-mode=ike2 name=SSVPN profile=SSVPN
/ip ipsec proposal
add name=SSVPN pfs-group=none
/ip pool
add name=dhcp ranges=192.168.0.20-192.168.0.60
/ip dhcp-server
add address-pool=dhcp disabled=no interface=bridge name=DHCP
/interface bridge port
add bridge=TMNETUNIFI.IPTV comment="iptv bridge to Eth 2" interface=ether2
add bridge=bridge comment=defconf interface=ether3
add bridge=bridge comment=defconf interface=ether4
add bridge=bridge comment=defconf interface=ether5
add bridge=bridge comment=defconf interface=wlan1
add bridge=bridge comment=defconf interface=wlan2
add bridge=TMNETUNIFI.IPTV comment="vlan 600 bridge to iptv bridge" interface=vlan600
/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 disabled=yes interface=ether1 list=WAN
add interface=pppoe-tmunifi list=WAN
/ip address
add address=192.168.0.250/24 comment=defconf interface=ether4 network=192.168.0.0
/ip cloud
set ddns-enabled=yes ddns-update-interval=5m
/ip dhcp-client
add comment=defconf interface=ether1
/ip dhcp-server lease
add address=192.168.0.251 client-id=1:10:62:eb:a3:e7:73 mac-address=10:62:EB:A3:E7:73 server=DHCP
add address=192.168.0.5 client-id=1:c:98:38:d2:fc:63 mac-address=0C:98:38:D2:FC:63 server=DHCP
add address=192.168.0.1 client-id=1:9c:5c:8e:7b:c1:23 mac-address=9C:5C:8E:7B:C1:23 server=DHCP
/ip dhcp-server network
add address=192.168.0.0/24 comment=defconf gateway=192.168.0.250 netmask=24
/ip dns
set servers=8.8.8.8,8.8.4.4,2001:4860:4860::8888,2001:4860:4860::8844
/ip dns static
add address=192.168.0.250 comment=defconf name=router.lan
/ip firewall address-list
add address=bef00a0a78c5.sn.mynetname.net list=WAN-IP
add address=192.168.0.5 list=vpnc
add address=192.168.0.1 disabled=yes list=vpnc
/ip firewall filter
add action=accept chain=input comment="defconf: accept established,related,untracked" connection-state=\
    established,related,untracked
add action=accept chain=input comment="WINBOX REMOTE ACCESS" dst-port=8291 protocol=tcp
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 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 \
    disabled=yes
add action=fasttrack-connection chain=forward comment="FastTrack w !ipsec" connection-mark=!ipsec 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=mark-connection chain=forward comment="Mark IPsec" ipsec-policy=in,ipsec new-connection-mark=ipsec
add action=mark-connection chain=forward comment="Mark IPsec" ipsec-policy=out,ipsec new-connection-mark=ipsec
/ip firewall nat
add action=masquerade chain=srcnat comment="Hairpin NAT" dst-address=192.168.0.0/24 src-address=192.168.0.0/24
add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN
add action=dst-nat chain=dstnat comment="MC Server 25565" dst-address-list=WAN-IP dst-port=25565 protocol=tcp \
    to-addresses=192.168.0.1 to-ports=25565
add action=dst-nat chain=dstnat comment="MC Server 25566" dst-address-list=WAN-IP dst-port=25566 protocol=tcp \
    to-addresses=192.168.0.1 to-ports=25566
/ip ipsec identity
add auth-method=eap certificate=surfshark_ikev2.crt_0 eap-methods=eap-mschapv2 generate-policy=port-strict \
    mode-config=SSVPN peer=SSVPN policy-template-group=SSVPN username=***********
/ip ipsec policy
add action=none dst-address=192.168.0.0/24 src-address=0.0.0.0/0
set 1 disabled=yes
add group=SSVPN proposal=SSVPN template=yes
/ipv6 address
add from-pool=pppoev6 interface=bridge
/ipv6 dhcp-client
add add-default-route=yes interface=pppoe-tmunifi pool-name=pppoev6 request=prefix use-peer-dns=no
/ipv6 firewall address-list
add address=::/128 comment="defconf: unspecified address" list=bad_ipv6
add address=::1/128 comment="defconf: lo" list=bad_ipv6
add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6
add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6
add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6
add address=100::/64 comment="defconf: discard only " list=bad_ipv6
add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6
add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6
add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6
add address=::224.0.0.0/100 comment="defconf: other" list=bad_ipv6
add address=::127.0.0.0/104 comment="defconf: other" list=bad_ipv6
add address=::/104 comment="defconf: other" list=bad_ipv6
add address=::255.0.0.0/104 comment="defconf: other" list=bad_ipv6
/ipv6 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 ICMPv6" protocol=icmpv6
add action=accept chain=input comment="defconf: accept UDP traceroute" port=33434-33534 protocol=udp
add action=accept chain=input comment="defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=udp \
    src-address=fe80::/10
add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=input comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=input comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=input comment="defconf: drop everything else not coming from LAN" in-interface-list=!LAN
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 packets with bad src ipv6" src-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" hop-limit=equal:1 protocol=icmpv6
add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=icmpv6
add action=accept chain=forward comment="defconf: accept HIP" protocol=139
add action=accept chain=forward comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=forward comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=forward comment="defconf: drop everything else not coming from LAN" in-interface-list=!LAN
/system clock
set time-zone-name=Asia/Kuala_Lumpur
/system identity
set name=AMPHAC2
/system ntp client
set enabled=yes primary-ntp=203.95.213.129 secondary-ntp=162.159.200.123 server-dns-names=""
/system scheduler
add interval=5m name=DynDNS on-event=DynDNS policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
/system script
add dont-require-permissions=no name=DynDNS owner=amph policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":global ddnsuser \"*************\"\r\
    \n:global ddnspass \"**************\"\r\
    \n:global theinterface \"pppoe-tmunifi\"\r\
    \n:global ddnshost \"***********\" \r\
    \n:global ipddns [:resolve \$ddnshost];\r\
    \n:global ipfresh [ /ip address get [/ip address find interface=\$theinterface ] address ]\r\
    \n:if ([ :typeof \$ipfresh ] = nil ) do={\r\
    \n   :log info (\"DynDNS: No ip address on \$theinterface .\")\r\
    \n} else={\r\
    \n   :for i from=( [:len \$ipfresh] - 1) to=0 do={ \r\
    \n      :if ( [:pick \$ipfresh \$i] = \"/\") do={ \r\
    \n    :set ipfresh [:pick \$ipfresh 0 \$i];\r\
    \n      } \r\
    \n}\r\
    \n \r\
    \n:if (\$ipddns != \$ipfresh) do={\r\
    \n    :log info (\"DynDNS: IP-DynDNS = \$ipddns\")\r\
    \n    :log info (\"DynDNS: IP-Fresh = \$ipfresh\")\r\
    \n   :log info \"DynDNS: Update IP needed, Sending UPDATE...!\"\r\
    \n   :global str \"/nic/update\\\?hostname=\$ddnshost&myip=\$ipfresh&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG\"\r\
    \n   /tool fetch address=members.dyndns.org src-path=\$str mode=http user=\$ddnsuser \\\r\
    \n         password=\$ddnspass dst-path=(\"/DynDNS.\".\$ddnshost)\r\
    \n    :delay 1\r\
    \n    :global str [/file find name=\"DynDNS.\$ddnshost\"];\r\
    \n    /file remove \$str\r\
    \n    :global ipddns \$ipfresh\r\
    \n  :log info \"DynDNS: IP updated to \$ipfresh!\"\r\
    \n    } else={\r\
    \n     :log info \"DynDNS: dont need changes\";\r\
    \n    }\r\
    \n} "
/tool mac-server
set allowed-interface-list=LAN
/tool mac-server mac-winbox
set allowed-interface-list=LAN
 
blackoutfolo
just joined
Posts: 19
Joined: Mon Apr 30, 2018 6:52 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Wed Apr 29, 2020 2:13 am

Hello,
I'am in the same situation: Devices does get the VPN ip and are able to ping websites but cannot browse the internet:


# apr/28/2020 10:35:35 by RouterOS 6.46.5
# software id = FQAZ-Y0T5
#
# model = RB760iGS
# serial number = **************
/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=NordVPN responder=no src-address-list=local
/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add name=NordVPN
/ip ipsec peer
add address=nl125.nordvpn.com exchange-mode=ike2 name=NordVPN profile=NordVPN
/ip ipsec proposal
add name=NordVPN pfs-group=none
/ip pool
add name=dhcp_pool0 ranges=10.5.8.10-10.5.8.250
/ip dhcp-server
add address-pool=dhcp_pool0 disabled=no interface=ether3 name=dhcp1
/ip address
add address=10.5.8.254/24 interface=ether3 network=10.5.8.0
/ip dhcp-client
add disabled=no interface=ether1
/ip dhcp-server network
add address=10.5.8.0/24 dns-server=103.86.96.100,103.86.99.100 gateway=\
10.5.8.254
/ip dns
set allow-remote-requests=yes
/ip firewall address-list
add address=10.5.8.0/24 list=local
/ip firewall nat
add action=masquerade chain=srcnat out-interface=ether1
/ip ipsec identity
add auth-method=eap certificate="" eap-methods=eap-mschapv2 generate-policy=\
port-strict mode-config=NordVPN password=******* peer=NordVPN \
policy-template-group=NordVPN username=******@******
/ip ipsec policy
add dst-address=0.0.0.0/0 group=NordVPN proposal=NordVPN src-address=\
0.0.0.0/0 template=yes
/system clock
set time-zone-name=******/********
/system logging
add prefix=vpn topics=ipsec
add action=none dst-address=10.5.8.0/24 src-address=0.0.0.0/0 place-before=0

What can i do?
You do not have the required permissions to view the files attached to this post.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Wed Apr 29, 2020 2:43 am

You are not in the same situation because this topic goes about not being to see the preview in this forum due to problems of ICMP 3/4 packets not being return to the client by the router.

Please open a own topic on this.

Update:

I had quick look and is your DNS resolving?

You can test that quickly by opening a terminal and type:

:put [resolve nu.nl];

It should show then a IP address:
......> :put [resolve nu.nl];
13.224.67.24
Second update:
/ip pool
add name=dhcp_pool0 ranges=10.5.8.10-10.5.8.250
/ip dhcp-server
add address-pool=dhcp_pool0 disabled=no interface=ether3 name=dhcp1
/ip address
add address=10.5.8.254/24 interface=ether3 network=10.5.8.0
Seeing Ether3 but you screen shot says nordvpn-eth5.
 
blackoutfolo
just joined
Posts: 19
Joined: Mon Apr 30, 2018 6:52 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri May 01, 2020 9:33 am

Code: Select all
/ip pool
add name=dhcp_pool0 ranges=10.5.8.10-10.5.8.250
/ip dhcp-server
add address-pool=dhcp_pool0 disabled=no interface=ether3 name=dhcp1
/ip address
add address=10.5.8.254/24 interface=ether3 network=10.5.8.0
Seeing Ether3 but you screen shot says nordvpn-eth5
Yeah i change router for another test. The screenshot is for first router but config is same.
i have 13.224.67.118 after the command :put [resolve nu.nl];
 
mike7
just joined
Posts: 12
Joined: Sun Oct 28, 2018 12:20 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Tue May 26, 2020 5:44 pm

The default template will be moved to the top of the list if it was not already there. The second line should above (action=none) should be below default and above any added IKEv2 provider lines.

The explaination by Sindy.
Anyway, there should be a remedy - a static IPsec policy action=none src-address=0.0.0.0/0 dst-address=the.client's.subnet placed before the policy template which is used to build the dynamic policy with the responder-provided IP address as src-address. This action=none policy will shadow the dynamically generated one so even though the ICMP code 3 type 4 packet will likely get src-nated by the dynamic src-nat rule, it will not reach the dynamic policy (which would divert it into the tunnel) so it will make it to the client. The client won't care about the source address as it has no relevance for it, so it should adjust the size of the re-sent TCP packet and all the subsequent ones accordingly.
This solved my long standing problem. with that work around and many many thank to Sindy for suggesting this!

Looks like in the next release Mikrotik will place dynamic policies in the top of the list or I misunderstand something?
From 6.47rc2 changelog:
*) ipsec - place dynamically created IPsec policies at the begining of the table;
 
User avatar
eworm
Forum Guru
Forum Guru
Posts: 1071
Joined: Wed Oct 22, 2014 9:23 am
Location: Oberhausen, Germany
Contact:

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Tue May 26, 2020 10:50 pm

I did fear the same, but looks like everything still works as expected.
Not sure what this change is supposed to do.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Tue May 26, 2020 10:55 pm

No worries. I am running 6.47RC and nothing has changed there. The Dynamic are still grouped under their own specific template.
 
pedra
just joined
Posts: 5
Joined: Tue Feb 27, 2018 10:41 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Feb 19, 2021 1:21 pm

For months I have been using NordVPN with no problems.
few days ago this problem has also occurred to me, ping ok, traceroute ok but I don't browse.
I have added the "policy none" but nothing has changed.
Can you help me?
/ip ipsec mode-config
add name=NordVPN responder=no src-address-list=Ike
/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add dh-group=ecp256,modp3072 enc-algorithm=aes-256 hash-algorithm=sha384 \
    name=NordVPN
/ip ipsec peer
add address=it199.nordvpn.com exchange-mode=ike2 name=NordVPN profile=NordVPN
/ip ipsec proposal
add name=NordVPN pfs-group=none
/ip ipsec identity
add auth-method=eap certificate="" eap-methods=eap-mschapv2 generate-policy=\
    port-strict mode-config=NordVPN peer=NordVPN policy-template-group=\
    NordVPN username=nu4LVuhnuqfjJDZ3CS8thjWL
/ip ipsec policy
set 0 group=NordVPN proposal=NordVPN
add action=none dst-address=10.0.0.0/24 src-address=0.0.0.0/0
add disabled=yes dst-address=0.0.0.0/0 group=NordVPN proposal=NordVPN \
    src-address=0.0.0.0/0 template=yes

/ip firewall filter
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=drop chain=forward comment="defconf: drop invalid" \
    connection-state=invalid log-prefix=drop
add action=drop chain=forward comment=\
    "defconf:  drop all from WAN not DSTNATed" connection-nat-state=!dstnat \
    connection-state=new in-interface-list=WAN log-prefix=drop
add action=drop chain=forward in-interface=wan2 log-prefix=drop
add action=accept chain=input comment=\
    "defconf: accept established,related, untracked" connection-state=\
    established,related,untracked
add action=accept chain=forward 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=drop chain=input in-interface=Eolo log-prefix="drop "
add action=accept chain=forward comment="VLAN100 to NTP" dst-address-list=\
    PiHole dst-port=53 protocol=udp src-address-list=VLAN100
add action=accept chain=forward comment="VLAN100 to DNS" dst-address-list=\
    PiHole dst-port=123 protocol=udp src-address-list=VLAN100
add action=accept chain=forward comment="LAN to CAM VLAN100" \
    dst-address-list=CAM src-address-list=LAN
add action=accept chain=forward comment="CAM VLAN100 to NAS" dst-address=\
    10.0.0.21 log-prefix=drop src-address-list=CAM
add action=drop chain=forward comment="DROP VLAN100 to LAN" dst-address-list=\
    LAN log-prefix=drop src-address-list=VLAN100

/ip firewall nat
add action=masquerade chain=srcnat comment="Masquerade Eolo" out-interface=\
    Eolo
add action=masquerade chain=srcnat comment="Masquerede Wan2" out-interface=\
    wan2
add action=masquerade chain=srcnat comment="Masquerade OVPN-Sede" \
    out-interface=ovpn-Sede
add action=masquerade chain=srcnat comment="Masquerade VLAN100" \
    out-interface=bridge100
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Feb 19, 2021 8:30 pm

/ip ipsec policy
set 0 group=NordVPN proposal=NordVPN
add action=none dst-address=10.0.0.0/24 src-address=0.0.0.0/0
add disabled=yes dst-address=0.0.0.0/0 group=NordVPN proposal=NordVPN \
    src-address=0.0.0.0/0 template=yes
First dst-address=0.0.0.0/0 should contain the entry point if the tunnel. This should dynamicly entered on connect. And disabled=yes is wrong and should be no.
 
pedra
just joined
Posts: 5
Joined: Tue Feb 27, 2018 10:41 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Feb 19, 2021 9:41 pm

sorry disabled = yes is a typo.
what do you mean by entry point?

this is a print of ip ipsec policy:
[admin@MikroTik] /ip ipsec policy> print detail
Flags: T - template, B - backup, 
X - disabled, D - dynamic, I - invalid, A - active, * - default 
 0 T    group=NordVPN src-address=0.0.0.0/0 dst-address=0.0.0.0/0 
        protocol=all proposal=NordVPN template=yes 

 1      peer="" src-address=0.0.0.0/0 src-port=any 
        dst-address=10.0.0.0/24 dst-port=any protocol=all 
        action=none 

 2   DA  peer=NordVPN tunnel=yes src-address=10.6.2.22/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=xx.xx.xx.56 
        sa-dst-address=217.138.197.67 proposal=NordVPN 
        ph2-count=1 

and this is an update ipsec policy export

/ip ipsec policy
set 0 group=NordVPN proposal=NordVPN
add action=none dst-address=10.0.0.0/24 src-address=0.0.0.0/0
add dst-address=0.0.0.0/0 group=NordVPN proposal=NordVPN src-address=\
    0.0.0.0/0 template=yes
Last edited by pedra on Fri Feb 19, 2021 10:06 pm, edited 1 time in total.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Feb 19, 2021 9:56 pm

I wrote dst-address and that should be src-addres and it this one: src-address=10.6.2.22/32

How do generate the second screen, because it does not match the first screen? And is 10.0.0.0/24 your internal network?

Please change you personal IP address from your posting above! sa-src-address=XX.XX.XXX.56

Remember, I address a very specific problem of ICMP 3/4 getting lost in the router which is not a generic connection problem.
 
pedra
just joined
Posts: 5
Joined: Tue Feb 27, 2018 10:41 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Feb 19, 2021 10:17 pm

The second screen is a simple export from terminal
yes my network is 10.0.0.0/24.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri Feb 19, 2021 10:28 pm

The second screen is a simple export from terminal
yes my network is 10.0.0.0/24.
I missed the word template in the second screen so the 0.0.0.0/0 is correct.

You have to check what is wrong on a other place in the NordVPN setup. You can leave my line in there to avoid any MTU problems.

There is an other thread that give samples of different setups for NordVPN and other IKEv2 providers and I will add the link in a few minutes when I have found it....

Link: viewtopic.php?f=23&t=169273&p=841093&hi ... pn#p841093
 
pedra
just joined
Posts: 5
Joined: Tue Feb 27, 2018 10:41 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sat Feb 20, 2021 9:02 pm

thank you,
I will try to bring to factory default ​​and reconfigure the router. I have already read the topic you pointed out to me, together with many others, if you notice a part of the configuration is copied from your post.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sat Feb 20, 2021 11:00 pm

That is encouraged by me because my only interest is to avoid that other to discover the wheel all over again. My search took many months and few support request, Sindy helped me out with this.
 
apnmyid
just joined
Posts: 5
Joined: Sun Feb 21, 2021 9:19 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Wed May 19, 2021 8:15 pm

I am using default configuration, bridge ether2 to ether5 as LAN, except WAN is pppoe client, add LAN subnet to ipsec policy as suggested by Sindy, but unable to browse anything on internet.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Wed May 19, 2021 8:25 pm

I am using default configuration, bridge ether2 to ether5 as LAN, except WAN is pppoe client, add LAN subnet to ipsec policy as suggested by Sindy, but unable to browse anything on internet.
Not by accident still have fasttraking active?
 
apnmyid
just joined
Posts: 5
Joined: Sun Feb 21, 2021 9:19 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Wed May 19, 2021 8:29 pm

I am using default configuration, bridge ether2 to ether5 as LAN, except WAN is pppoe client, add LAN subnet to ipsec policy as suggested by Sindy, but unable to browse anything on internet.
Not by accident still have fasttraking active?
forgot to mention, fastrack already disable.
 
apnmyid
just joined
Posts: 5
Joined: Sun Feb 21, 2021 9:19 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Thu May 20, 2021 3:33 pm

Just wondering why Sindy's workaround is not working on this setup? Does change the MSS is the only solution?


On a different LAN setup, not using bridge but VLAN, I don't have to change the MSS. The workaround working great.
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Thu May 20, 2021 7:36 pm

Show the complete setup which is not working and we may get somewhere. PPPoE may surely be related as it can cause MTU problems on its own.
 
apnmyid
just joined
Posts: 5
Joined: Sun Feb 21, 2021 9:19 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Thu May 20, 2021 10:05 pm

Show the complete setup which is not working and we may get somewhere. PPPoE may surely be related as it can cause MTU problems on its own.


Thanks for your concern. Here they are:


/interface bridge
add admin-mac=ZZ:BB:CC:DD:EE:GG auto-mac=no comment=defconf name=bridge \
    protocol-mode=none
/interface ethernet
set [ find default-name=ether1 ] mac-address=AA:BB:CC:DD:EE:FF
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
add name=Outbond
/interface wireless security-profiles
set [ find default=yes ] supplicant-identity=MikroTik
/ip ipsec mode-config
add name="NordVPN mode config" responder=no src-address-list=under_vpn \
    use-responder-dns=no
/ip ipsec policy group
add name=NordVPN
/ip ipsec profile
add dh-group=modp2048 enc-algorithm=aes-256 hash-algorithm=sha512 name=\
    "NordVPN profile"
/ip ipsec peer
add address=sg466.nordvpn.com exchange-mode=ike2 name=NordVPN profile=\
    "NordVPN profile"
/ip ipsec proposal
add auth-algorithms=sha256 enc-algorithms=aes-256-cbc lifetime=0s name=\
    "NordVPN proposal" pfs-group=none
/ip pool
add name=default-dhcp ranges=10.0.1.101-10.0.1.254
/ip dhcp-server
add address-pool=default-dhcp disabled=no interface=bridge lease-time=1d10m \
    name=defconf
/ppp profile
add change-tcp-mss=yes name=MyPPPoE on-down="# !rsc\
    \n# RouterOS script: myPPPoE-on-down\
    \n# Copyright (c) 2020 xxxxx <xxxxx@gmail.com>\
    \n#\
    \n# run scripts on myPPPoE down\
    \n\
    \n:global LogPrintExit;\
    \n\
    \n:local Interface \$interface;\
    \n\
    \n:if ([ :typeof \$Interface ] = \"nothing\") do={\
    \n  \$LogPrintExit error \"This script is sdownposed to run from PPPo\
    E on-down script hook.\" true;\
    \n}\
    \n\
    \n:local IntName [ / interface get \$Interface name ];\
    \n:log info (\"PPP interface \" . \$IntName . \" is down.\");\
    \n\
    \n:local Scripts {\
    \n  \"myPPPoE-on-down\"\
    \n}\
    \n\
    \n:foreach Script in=\$Scripts do={\
    \n  :if ([ / system script print count-only where name=\$Script ] > 0) do=\
    {\
    \n    :log debug (\"Running script from myPPPoE-on-down: \" . \$Script)\
    ;\
    \n    / system script run \$Script;\
    \n  }\
    \n}\
    \n" on-up="#!rsc\
    \n# RouterOS script: ppp-on-up\
    \n# Copyright (c) 2013-2020 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# run scripts on ppp up\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md\
    \n\
    \n:global LogPrintExit;\
    \n\
    \n:local Interface \$interface;\
    \n\
    \n:if ([ :typeof \$Interface ] = \"nothing\") do={\
    \n  \$LogPrintExit error \"This script is supposed to run from ppp on-up s\
    cript hook.\" true;\
    \n}\
    \n\
    \n:local IntName [ / interface get \$Interface name ];\
    \n:log info (\"PPP interface \" . \$IntName . \" is up.\");\
    \n\
    \n:local Scripts {\
    \n  \"check-PPPoE-ip\"\
    \n}\
    \n\
    \n:foreach Script in=\$Scripts do={\
    \n  :if ([ / system script print count-only where name=\$Script ] > 0) do=\
    {\
    \n    :log debug (\"Running script from ppp-on-up: \" . \$Script);\
    \n    / system script run \$Script;\
    \n  }\
    \n}\
    \n"
add change-tcp-mss=yes name=MyPptpPsh on-down="#!rsc by RouterOS\
    \n# RouterOS script: ppp-on-down\
    \n# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# run scripts on ppp down\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-down.md\
    \n\
    \n:local 0 \"ppp-on-down\";\
    \n:global GlobalFunctionsReady;\
    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
    \n\
    \n:global LogPrintExit2;\
    \n\
    \n:local Interface \$interface;\
    \n\
    \n:if ([ :typeof \$Interface ] = \"nothing\") do={\
    \n  \$LogPrintExit2 error \$0 (\"This script is sdownposed to run from ppp\
    \_on-down script hook.\") true;\
    \n}\
    \n\
    \n:local IntName [ / interface get \$Interface name ];\
    \n:log info (\"PPP interface \" . \$IntName . \" is down.\");\
    \n\
    \n:local Scripts {\
    \n  \"pptppsh-on-down\"\
    \n}\
    \n\
    \n:foreach Script in=\$Scripts do={\
    \n  :if ([ :len [ / system script find where name=\$Script ] ] > 0) do={\
    \n    :log debug (\"Running script from ppp-on-down: \" . \$Script);\
    \n    / system script run \$Script;\
    \n  }\
    \n}\
    \n" on-up="#!rsc by RouterOS\
    \n# RouterOS script: ppp-on-up\
    \n# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# run scripts on ppp up\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/ppp-on-up.md\
    \n\
    \n:local 0 \"ppp-on-up\";\
    \n:global GlobalFunctionsReady;\
    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
    \n\
    \n:global LogPrintExit2;\
    \n\
    \n:local Interface \$interface;\
    \n\
    \n:if ([ :typeof \$Interface ] = \"nothing\") do={\
    \n  \$LogPrintExit2 error \$0 (\"This script is supposed to run from ppp o\
    n-up script hook.\") true;\
    \n}\
    \n\
    \n:local IntName [ / interface get \$Interface name ];\
    \n:log info (\"PPP interface \" . \$IntName . \" is up.\");\
    \n\
    \n\
    \n:local Scripts {\
    \n  \"pptppsh-on-up\"\
    \n}\
    \n\
    \n:foreach Script in=\$Scripts do={\
    \n  :if ([ :len [ / system script find where name=\$Script ] ] > 0) do={\
    \n    :log debug (\"Running script from ppp-on-up: \" . \$Script);\
    \n    / system script run \$Script;\
    \n  }\
    \n}" use-encryption=yes
/interface pppoe-client
add add-default-route=yes disabled=no interface=ether1 name=PPPoE profile=\
    MyPPPoE user=xxxxx@xxxxx.xxx
/interface pptp-client
add connect-to=111.111.111.111 disabled=no name=PptpPsh profile=MyPptpPsh \
    user=x-user
/queue type
add kind=pcq name=pcq-download-streaming pcq-burst-rate=1536k \
    pcq-burst-threshold=1152k pcq-classifier=dst-address pcq-rate=960k
add kind=pcq name=pcq-download-gaming pcq-classifier=dst-address pcq-rate=\
    768k
add kind=pcq name=pcq-upload-gaming pcq-classifier=src-address pcq-rate=768k
add kind=pcq name=pcq-upload-streaming pcq-classifier=src-address pcq-rate=\
    768k
add kind=pcq name=pcq-download-1M pcq-classifier=dst-address pcq-limit=64KiB \
    pcq-rate=1M pcq-total-limit=3840KiB
add kind=pcq name=pcq-download-burst pcq-burst-rate=2M pcq-burst-threshold=\
    1536 pcq-classifier=dst-address pcq-limit=64KiB pcq-rate=1M \
    pcq-total-limit=3840KiB
/queue tree
add max-limit=29M name=Download parent=global priority=2 queue=default
add max-limit=5M name=Upload parent=global priority=1 queue=default
add limit-at=3M max-limit=5M name=HeavyDownload packet-mark=HeavyDownload \
    parent=Download priority=6 queue=pcq-download-streaming
add limit-at=2M max-limit=8M name=VideoDownload packet-mark=VideoDownload \
    parent=Download priority=7 queue=pcq-download-streaming
add limit-at=2M max-limit=29M name=SpeedtestDownload packet-mark=\
    SpeedtestDownload parent=Download queue=pcq-download-default
add limit-at=3M max-limit=8M name=GameDownload packet-mark=GameDownload \
    parent=Download priority=3 queue=pcq-download-gaming
add limit-at=3M max-limit=10M name=LightDownload packet-mark=LightDownload \
    parent=Download priority=5 queue=pcq-download-gaming
add limit-at=4M max-limit=8M name=VoipDownload packet-mark=VoipDownload \
    parent=Download priority=4 queue=pcq-download-default
add limit-at=512k max-limit=2M name=VideoUpload packet-mark=VideoUpload \
    parent=Upload priority=6 queue=pcq-upload-streaming
add limit-at=512k max-limit=2M name=HeavyUpload packet-mark=HeavyUpload \
    parent=Upload priority=5 queue=pcq-upload-streaming
add limit-at=128k max-limit=5M name=SpeedtestUpload packet-mark=\
    SpeedtestUpload parent=Upload queue=pcq-upload-default
add limit-at=768k max-limit=4M name=GameUpload packet-mark=GameUpload parent=\
    Upload priority=2 queue=pcq-upload-gaming
add limit-at=512k max-limit=2M name=LightUpload packet-mark=LightUpload \
    parent=Upload priority=4 queue=pcq-upload-gaming
add limit-at=768k max-limit=2M name=VoipUpload packet-mark=VoipUpload parent=\
    Upload priority=3 queue=pcq-upload-default
add limit-at=1M max-limit=18M name=PriviledgeDownload packet-mark=\
    PriviledgeDownload parent=Download priority=7 queue=pcq-download-default
add limit-at=128k max-limit=3M name=PriviledgeUpload packet-mark=\
    PriviledgeUpload parent=Upload priority=6 queue=pcq-upload-default
/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=WAN internet-interface-list=WAN lan-interface-list=\
    LAN wan-interface-list=WAN
/interface list member
add comment=defconf interface=bridge list=LAN
add comment=defconf disabled=yes interface=ether1 list=WAN
add interface=PPPoE list=WAN
add interface=bridge list=Outbond
add comment="dynamic, service=pptp, server=PptpPsh" interface=PptpPsh list=\
    LAN
/ip address
add address=10.0.1.1/24 comment=defconf interface=bridge network=10.0.1.0
add address=192.168.1.6/30 interface=ether1 network=192.168.1.4
/ip cloud
set ddns-enabled=yes
/ip dhcp-client
add comment=defconf interface=ether1
/ip dhcp-server network
add address=10.0.1.0/24 comment=defconf dns-server=10.0.1.1 gateway=10.0.1.1
/ip dns
set allow-remote-requests=yes servers=8.8.8.8,8.8.4.4
/ip dns static
add address=10.0.1.1 comment=defconf name=router.lan
/ip firewall address-list
add address=0.0.0.0/8 comment="default, RFC6890" list=NotPublic
add address=10.0.0.0/8 comment="default, RFC6890" list=NotPublic
add address=100.64.0.0/10 comment="default, RFC6890" list=NotPublic
add address=127.0.0.0/8 comment="default, RFC6890" list=NotPublic
add address=169.254.0.0/16 comment="default, RFC6890" list=NotPublic
add address=172.16.0.0/12 comment="default, RFC6890" list=NotPublic
add address=192.0.0.0/24 comment="default, RFC6890" list=NotPublic
add address=192.0.2.0/24 comment="default, RFC6890" list=NotPublic
add address=192.168.0.0/16 comment="default, RFC6890" list=NotPublic
add address=192.88.99.0/24 comment="default, RFC3068" list=NotPublic
add address=198.18.0.0/15 comment="default, RFC6890" list=NotPublic
add address=198.51.100.0/24 comment="default, RFC6890" list=NotPublic
add address=203.0.113.0/24 comment="default, RFC6890" list=NotPublic
add address=224.0.0.0/4 comment="default, RFC4601" list=NotPublic
add address=240.0.0.0/4 comment="default, RFC6890" list=NotPublic
add address=10.0.1.112 list=PriviledgeClient
add address=10.0.1.124 list=PriviledgeClient
add address=192.168.1.5 comment="default, F609" list=RestrictedNetwork
add address=10.0.1.0/24 comment=default list=HomeNetwork
add address=10.0.1.0/24 list=LocalNetwork
add address=172.16.220.36 comment="dynamic, service=pptp, server=PptpPsh" \
    list=PiHole
add address=172.16.220.36 comment="dynamic, service=pptp, server=PptpPsh" \
    list=AcceptSrcAdd
add address=172.16.220.36 comment="dynamic, service=pptp, server=PptpPsh" \
    list=AcceptDstAdd
/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="adminconf, OpenVPN" dst-port=1194 \
    in-interface=PPPoE protocol=tcp
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=drop chain=input comment="defconf: drop all not coming from LAN" \
    in-interface-list=!LAN
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 disabled=yes
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 dst-port=53 protocol=udp
add action=accept chain=prerouting dst-port=53,8291,64874,64875 protocol=tcp
add action=accept chain=prerouting src-address-list=AcceptSrcAdd
add action=accept chain=prerouting dst-address-list=AcceptDstAdd
add action=passthrough chain=lb-accept-prerouting disabled=yes
add action=passthrough chain=lb-mark-con-prerouting disabled=yes
add action=passthrough chain=lb-mark-routing-prerouting disabled=yes
add action=mark-connection chain=prerouting comment=\
    "Mark All Outbond Connection" connection-mark=no-mark dst-address-list=\
    !NotPublic in-interface-list=Outbond new-connection-mark=LightConnection \
    passthrough=yes
add action=mark-connection chain=prerouting comment=GameConnection \
    connection-mark=LightConnection disabled=yes in-interface-list=Outbond \
    new-connection-mark=GameConnection passthrough=yes protocol=icmp
add action=mark-connection chain=prerouting comment=PriviledgeConnection \
    connection-mark=LightConnection in-interface-list=Outbond \
    new-connection-mark=PriviledgeConnection passthrough=yes \
    src-address-list=PriviledgeClient
add action=mark-connection chain=prerouting comment=GameConnection \
    connection-mark=LightConnection dst-address-list=GameNetwork \
    in-interface-list=Outbond new-connection-mark=GameConnection passthrough=\
    yes
add action=mark-connection chain=prerouting comment=VoipConnection \
    connection-mark=LightConnection dst-address-list=VoipNetwork \
    in-interface-list=Outbond new-connection-mark=VoipConnection passthrough=\
    yes
add action=mark-connection chain=prerouting comment=VoipConnection \
    connection-mark=LightConnection dst-port=599,3478,3479,5090,8801-8810 \
    in-interface-list=Outbond new-connection-mark=VoipConnection passthrough=\
    yes protocol=udp
add action=mark-connection chain=prerouting comment=VoipConnection \
    connection-mark=LightConnection dst-port=5938 in-interface-list=Outbond \
    new-connection-mark=VoipConnection passthrough=yes protocol=tcp
add action=mark-connection chain=prerouting comment=VideoConnection \
    connection-mark=LightConnection dst-address-list=VideoNetwork \
    in-interface-list=Outbond new-connection-mark=VideoConnection \
    passthrough=yes
add action=mark-connection chain=prerouting comment=SpeedtestConnection \
    connection-mark=LightConnection dst-port=8080 in-interface-list=Outbond \
    new-connection-mark=SpeedtestConnection passthrough=yes protocol=tcp
add action=mark-connection chain=prerouting comment=SpeedtestConnection \
    connection-mark=LightConnection dst-port=8080 in-interface-list=Outbond \
    new-connection-mark=SpeedtestConnection passthrough=yes protocol=udp
add action=mark-connection chain=prerouting comment=HeavyConnection \
    connection-bytes=500000-0 connection-mark=LightConnection \
    connection-rate=200k-100M in-interface-list=Outbond new-connection-mark=\
    HeavyConnection passthrough=yes protocol=tcp
add action=mark-connection chain=prerouting comment=HeavyConnection \
    connection-bytes=500000-0 connection-mark=LightConnection \
    connection-rate=200k-100M dst-port="" in-interface-list=Outbond \
    new-connection-mark=HeavyConnection passthrough=yes protocol=udp
add action=accept chain=input comment="default, hotspot" dst-port=64872 \
    hotspot="" protocol=udp
add action=accept chain=input comment="default, hotspot" dst-port=64872-64875 \
    hotspot="" protocol=tcp
add action=passthrough chain=lb-mark-con-input disabled=yes
add action=accept chain=forward dst-port=53 protocol=udp
add action=accept chain=forward dst-port=53 protocol=tcp
add action=accept chain=forward src-address-list=AcceptSrcAdd
add action=accept chain=forward dst-address-list=AcceptDstAdd
add action=accept chain=forward dst-address-list=NotPublic in-interface-list=\
    Outbond
add action=mark-packet chain=forward comment=PriviledgeConnection \
    connection-mark=PriviledgeConnection in-interface-list=WAN \
    new-packet-mark=PriviledgeDownload passthrough=no
add action=mark-packet chain=forward comment=PriviledgeConnection \
    connection-mark=PriviledgeConnection in-interface-list=Outbond \
    new-packet-mark=PriviledgeUpload passthrough=no
add action=mark-packet chain=forward comment=GameConnection connection-mark=\
    GameConnection in-interface-list=WAN new-packet-mark=GameDownload \
    passthrough=no
add action=mark-packet chain=forward comment=GameConnection connection-mark=\
    GameConnection in-interface-list=Outbond new-packet-mark=GameUpload \
    passthrough=no
add action=mark-packet chain=forward comment=VoipConnection connection-mark=\
    VoipConnection in-interface-list=WAN new-packet-mark=VoipDownload \
    passthrough=no
add action=mark-packet chain=forward comment=VoipConnection connection-mark=\
    VoipConnection in-interface-list=Outbond new-packet-mark=VoipUpload \
    passthrough=no
add action=mark-packet chain=forward comment=VideoConnection connection-mark=\
    VideoConnection in-interface-list=WAN new-packet-mark=VideoDownload \
    passthrough=no
add action=mark-packet chain=forward comment=VideoConnection connection-mark=\
    VideoConnection in-interface-list=Outbond new-packet-mark=VideoUpload \
    passthrough=no
add action=mark-packet chain=forward comment=SpeedtestConnection \
    connection-mark=SpeedtestConnection in-interface-list=WAN \
    new-packet-mark=SpeedtestDownload passthrough=no
add action=mark-packet chain=forward comment=SpeedtestConnection \
    connection-mark=SpeedtestConnection in-interface-list=Outbond \
    new-packet-mark=SpeedtestUpload passthrough=no
add action=mark-packet chain=forward comment=HeavyConnection connection-mark=\
    HeavyConnection in-interface-list=WAN new-packet-mark=HeavyDownload \
    passthrough=no
add action=mark-packet chain=forward comment=HeavyConnection connection-mark=\
    HeavyConnection in-interface-list=Outbond new-packet-mark=HeavyUpload \
    passthrough=no
add action=mark-packet chain=forward comment=LightConnection connection-mark=\
    LightConnection in-interface-list=WAN new-packet-mark=LightDownload \
    passthrough=no
add action=mark-packet chain=forward comment=LightConnection connection-mark=\
    LightConnection in-interface-list=Outbond new-packet-mark=LightUpload \
    passthrough=no
add action=accept chain=output comment="default, hotspot" hotspot="" \
    protocol=udp src-port=64872
add action=accept chain=output comment="default, hotspot" hotspot="" \
    protocol=tcp src-port=64872-64875
add action=passthrough chain=lb-mark-routing-output disabled=yes
/ip firewall nat
add action=src-nat chain=srcnat comment=\
    "dynamic, service=pptp, server=PptpPsh" out-interface=PptpPsh \
    to-addresses=172.16.220.12
add action=masquerade chain=srcnat dst-address-list=RestrictedNetwork \
    src-address-list=HomeNetwork
add action=src-nat chain=srcnat comment=NordVPN dst-address=104.18.19.110 \
    protocol=icmp to-addresses=10.6.0.36
add action=passthrough chain=ipsec-placeholder disabled=yes
add action=src-nat chain=srcnat comment="PPPoE, src-nat" out-interface=\
    PPPoE to-addresses=111.111.111.222
add action=masquerade chain=srcnat comment="defconf: masquerade" \
    ipsec-policy=out,none out-interface-list=WAN
add action=dst-nat chain=dstnat comment=\
    "dynamic, service=pptp, server=PptpPsh" dst-address-list=!PiHole \
    dst-port=53 in-interface-list=!WAN protocol=udp src-address-list=!PiHole \
    to-addresses=172.16.220.36 to-ports=53
add action=dst-nat chain=dstnat comment=\
    "dynamic, service=pptp, server=PptpPsh" dst-address-list=!PiHole \
    dst-port=53 in-interface-list=!WAN protocol=tcp src-address-list=!PiHole \
    to-addresses=172.16.220.36 to-ports=53
add action=dst-nat chain=pre-hotspot comment=\
    "dynamic, service=pptp, server=PptpPsh" dst-port=53 hotspot=auth \
    protocol=udp to-addresses=172.16.220.36 to-ports=53
add action=dst-nat chain=pre-hotspot comment=\
    "dynamic, service=pptp, server=PptpPsh" dst-port=53 hotspot=auth \
    protocol=tcp to-addresses=172.16.220.36 to-ports=53
/ip ipsec identity
add auth-method=eap certificate=NordVPNRootCA eap-methods=eap-mschapv2 \
    generate-policy=port-strict mode-config="NordVPN mode config" peer=\
    NordVPN policy-template-group=NordVPN username=KKKKKKKKKKKKKKKK
/ip ipsec policy
add action=none dst-address=10.0.1.0/24 src-address=0.0.0.0/0
add action=none comment="PPPoE IP" dst-address=111.111.111.222/32 \
    src-address=0.0.0.0/0
add dst-address=0.0.0.0/0 group=NordVPN proposal="NordVPN proposal" \
    src-address=0.0.0.0/0 template=yes
/ip route
add comment="dynamic, load-balance, PPPoE" distance=10 dst-address=\
    89.187.162.97/32 gateway=213.245.6.1 scope=10
add comment="dynamic, service=pptp, server=PptpPsh" distance=6 dst-address=\
    172.16.220.0/24 gateway=172.16.220.1
add distance=6 dst-address=172.30.15.0/24 gateway=172.16.220.1
add comment="dynamic, load-balance, PPPoE" distance=10 dst-address=\
    213.244.68.174/32 gateway=213.245.6.1 scope=10
/system clock
set time-zone-name=Asia/Jakarta
/system identity
set name=RBFL_E67E
/system ntp client
set enabled=yes primary-ntp=216.239.35.0
/system scheduler
add interval=1m name=pihole-check on-event=\
    "/ system script run pihole-check;" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-date=apr/15/2021 start-time=19:42:10
add interval=1m name=log-forward on-event="/ system script run log-forward;" \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
add interval=1m name=nordvpn-ipsec on-event=\
    "/ system script run nordvpn-ipsec;" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
add name=global-scripts on-event="/ system script { run global-config; run glo\
    bal-config-overlay; run global-functions; run my-function; }" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
add interval=1d name=ScriptInstallUpdate on-event=\
    ":global ScriptInstallUpdate; \$ScriptInstallUpdate;" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
add interval=1w name=email-backup on-event=\
    "/ system script run email-backup;" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-date=mar/27/2021 start-time=09:15:00
add interval=1m name=netwatch-notify on-event=\
    "/ system script run netwatch-notify;" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
add interval=1m name=FlushEmailQueue on-event=\
    ":global FlushEmailQueue; \$FlushEmailQueue;" policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    start-time=startup
/system script
add dont-require-permissions=no name=global-config owner=global-config \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source="#!rsc by RouterOS\
    \n# RouterOS script: global-config\
    \n# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# global configuration\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/\
    \n\
    \n# Make sure all configuration properties are up to date and this\
    \n# value is in sync with value in script 'global-functions'!\
    \n:global GlobalConfigVersion 52;\
    \n\
    \n# This is used for DNS and backup file.\
    \n:global Domain \"example.com\";\
    \n:global HostNameInZone true;\
    \n:global PrefixInZone true;\
    \n:global ServerNameInZone false;\
    \n\
    \n# These addresses are used to send e-mails to. The to-address needs\
    \n# to be filled; cc-address can be empty, one address or a comma\
    \n# separated list of addresses.\
    \n:global EmailGeneralTo \"\";\
    \n:global EmailGeneralCc \"\";\
    \n#:global EmailGeneralTo \"mail@example.com\";\
    \n#:global EmailGeneralCc \"another@example.com,third@example.com\";\
    \n\
    \n# You can send Telegram notifications. Register a bot\
    \n# and add the token and chat ids here.\
    \n:global TelegramTokenId \"\";\
    \n:global TelegramChatId \"\";\
    \n#:global TelegramTokenId \"123456:ABCDEF-GHI\";\
    \n#:global TelegramChatId \"12345678\";\
    \n# This is whether or not to send Telegram messages with fixed-width font\
    .\
    \n:global TelegramFixedWidthFont true;\
    \n\
    \n# It is possible to override e-mail and Telegram setting for every scrip\
    t.\
    \n# This is done in arrays EmailGeneralToOverride, EmailGeneralCcOverride,\
    \n# TelegramTokenIdOverride and TelegramChatIdOverride like this:\
    \n#:global EmailGeneralToOverride {\
    \n#  \"check-certificates\"=\"override@example.com\";\
    \n#  \"email-backup\"=\"backup@example.com\";\
    \n#}\
    \n\
    \n# Toggle this to disable symbols in notifications.\
    \n:global NotificationsWithSymbols true;\
    \n# Toggle this to disable color output in terminal/cli.\
    \n:global TerminalColorOutput true;\
    \n\
    \n# This defines what backups to generate and what password to use.\
    \n:global BackupSendBinary false;\
    \n:global BackupSendExport true;\
    \n:global BackupPassword \"v3ry-s3cr3t\";\
    \n:global BackupRandomDelay 0;\
    \n# These credentials are used to upload backup and config export files.\
    \n# SFTP authentication is tricky, you may have to limit authentication\
    \n# methods for your SSH server.\
    \n:global BackupUploadUrl \"sftp://example.com/backup/\";\
    \n:global BackupUploadUser \"mikrotik\";\
    \n:global BackupUploadPass \"v3ry-s3cr3t\";\
    \n\
    \n# This defines a filter on log topics not to be forwarded.\
    \n:global LogForwardFilter \"(debug|info)\";\
    \n# ... and the same for log message text. Regular expressions are support\
    ed.\
    \n# Do *NOT* set an empty string - that will filter everything!\
    \n:global LogForwardFilterMessage [];\
    \n#:global LogForwardFilterMessage \"message text\";\
    \n#:global LogForwardFilterMessage \"(message text|another text|...)\";\
    \n\
    \n# Specify an address to enable auto update to version assumed safe.\
    \n# The configured channel (bugfix, current, release-candidate) is appende\
    d.\
    \n:global SafeUpdateUrl \"\";\
    \n#:global SafeUpdateUrl \"https://example.com/ros/safe-update/\";\
    \n# Allow to install patch updates automatically.\
    \n:global SafeUpdatePatch false;\
    \n# Allow to install updates automatically if seen in neighbor list.\
    \n:global SafeUpdateNeighbor false;\
    \n\
    \n# These thresholds control when to send health notification\
    \n# on temperature and voltage.\
    \n:global CheckHealthTemperature {\
    \n  temperature=50;\
    \n  cpu-temperature=70;\
    \n  board-temperature1=50;\
    \n  board-temperature2=50;\
    \n}\
    \n# This is deviation on recovery threshold against notification flooding.\
    \n:global CheckHealthTemperatureDeviation 2;\
    \n:global CheckHealthVoltagePercent 10;\
    \n\
    \n# This controls what configuration is activated by bridge-port-to-defaul\
    t.\
    \n:global BridgePortTo \"default\";\
    \n\
    \n# Access-list entries matching this comment are updated\
    \n# with daily pseudo-random PSK.\
    \n:global DailyPskMatchComment \"Daily PSK\";\
    \n:global DailyPskSecrets {\
    \n  { \"Abusive\"; \"Aggressive\"; \"Bored\"; \"Chemical\"; \"Cold\";\
    \n    \"Cruel\"; \"Curved\"; \"Delightful\"; \"Discreet\"; \"Elite\";\
    \n    \"Evasive\"; \"Faded\"; \"Flat\"; \"Future\"; \"Grandiose\";\
    \n    \"Hanging\"; \"Humorous\"; \"Interesting\"; \"Magenta\";\
    \n    \"Magnificent\"; \"Numerous\"; \"Optimal\"; \"Pathetic\";\
    \n    \"Possessive\"; \"Remarkable\"; \"Rightful\"; \"Ruthless\";\
    \n    \"Stale\"; \"Unusual\"; \"Useless\"; \"Various\" };\
    \n  { \"Adhesive\"; \"Amusing\"; \"Astonishing\"; \"Frantic\";\
    \n    \"Kindhearted\"; \"Limping\"; \"Roasted\"; \"Robust\";\
    \n    \"Staking\"; \"Thundering\"; \"Ultra\"; \"Unreal\" };\
    \n  { \"Belief\"; \"Button\"; \"Curtain\"; \"Edge\"; \"Jewel\";\
    \n    \"String\"; \"Whistle\" }\
    \n}\
    \n\
    \n# Run different commands with multiple mode-button presses.\
    \n:global ModeButton {\
    \n  1=\"/ system script run leds-toggle-mode;\";\
    \n  2=\":global SendNotification; :global Identity; \\\$SendNotification (\
    \\\"Hello...\\\") (\\\"Hello world, \\\" . \\\$Identity . \\\" calling!\\\
    \");\";\
    \n  3=\"/ system shutdown;\";\
    \n  4=\"/ system reboot;\";\
    \n  5=\"/ system script run bridge-port-toggle;\";\
    \n# add more here...\
    \n};\
    \n# This led gives visual feedback if type is 'on' or 'off'.\
    \n:global ModeButtonLED \"user-led\";\
    \n\
    \n# Run commands on SMS action.\
    \n:global SmsAction {\
    \n  bridge-port-toggle=\"/ system script run bridge-port-toggle;\";\
    \n  reboot=\"/ system reboot;\";\
    \n  shutdown=\"/ system shutdown;\";\
    \n# add more here...\
    \n};\
    \n\
    \n# This address should resolve ntp servers and is used to update\
    \n# ntp settings. A pool can rotate servers.\
    \n:global NtpPool \"pool.ntp.org\";\
    \n\
    \n# This is the address used to send gps data to.\
    \n:global GpsTrackUrl \"https://example.com/index.php\";\
    \n\
    \n# Enable this to fetch scripts from given url.\
    \n:global ScriptUpdatesFetch true;\
    \n:global ScriptUpdatesBaseUrl \"https://git.eworm.de/cgit/routeros-script\
    s/plain/\";\
    \n# alternative urls - main: stable code - next: currently in development\
    \n#:global ScriptUpdatesBaseUrl \"https://raw.githubusercontent.com/eworm-\
    de/routeros-scripts/main/\";\
    \n#:global ScriptUpdatesBaseUrl \"https://raw.githubusercontent.com/eworm-\
    de/routeros-scripts/next/\";\
    \n#:global ScriptUpdatesBaseUrl \"https://gitlab.com/eworm-de/routeros-scr\
    ipts/raw/main/\";\
    \n#:global ScriptUpdatesBaseUrl \"https://gitlab.com/eworm-de/routeros-scr\
    ipts/raw/next/\";\
    \n:global ScriptUpdatesUrlSuffix \"\";\
    \n# use next branch with default url (git.eworm.de)\
    \n#:global ScriptUpdatesUrlSuffix \"\\\?h=next\";\
    \n\
    \n# This project is developed in private spare time and usage is free of c\
    harge\
    \n# for you. If you like the scripts and think this is of value for you or\
    \_your\
    \n# business please consider a donation:\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/#donate\
    \n# Enable this to silence donation hint.\
    \n:global IDonate false;\
    \n\
    \n# Use this for certificate auto-renew\
    \n:global CertRenewUrl \"\";\
    \n#:global CertRenewUrl \"https://example.com/certificates/\";\
    \n:global CertRenewTime 3w;\
    \n:global CertRenewPass {\
    \n  \"v3ry-s3cr3t\";\
    \n  \"4n0th3r-s3cr3t\";\
    \n}\
    \n:global CertIssuedExportPass {\
    \n  \"cert1-cn\"=\"v3ry-s3cr3t\";\
    \n  \"cert2-cn\"=\"4n0th3r-s3cr3t\";\
    \n}\
    \n"
add dont-require-permissions=no name=global-config-overlay owner=\
    global-config-overlay policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
    \_Overlay for global configuration by RouterOS Scripts\
    \n# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# global configuration, custom overlay\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/\
    \n\
    \n# Make sure all configuration properties are up to date and this\
    \n# value is in sync with value in script 'global-functions'!\
    \n# Comment or remove to disable news and change notifications.\
    \n:global GlobalConfigVersion 47;\
    \n\
    \n# Copy configuration from global-config here and modify it.\
    \n\
    \n:global PptpServerIfaceName \"PptpPsh\";\
    \n:global PptpServerName \"asdkfeifhdkfks.sn.mynetname.net\";\
    \n:global PptpServerIp \"0.0.0.0\";\
    \n:global PshStatus 0;\
    \n\
    \n# This is for PPPoE PPPOE\
    \n:global PPPoEIface \"PPPoE\";\
    \n:global PPPoEIpPref {111;222;223;224};\
    \n\
    \n# This is used for DNS and backup file.\
    \n:global Domain \"zzzzzzzzzzzz.xx.zz.yy\";\
    \n:global HostNameInZone true;\
    \n:global PrefixInZone true;\
    \n:global ServerNameInZone false;\
    \n\
    \n# These addresses are used to send e-mails to. The to-address needs\
    \n# to be filled; cc-address can be empty, one address or a comma\
    \n# separated list of addresses.\
    \n:global EmailGeneralTo \"xxxxx@gmail.com\";\
    \n:global EmailGeneralCc \"xxxxx@gmail.com\";\
    \n#:global EmailGeneralTo \"mail@example.com\";\
    \n#:global EmailGeneralCc \"another@example.com,third@example.com\";\
    \n\
    \n# You can send Telegram notifications. Register a bot\
    \n# and add the token and chat ids here.\
    \n:global TelegramTokenId \"123456:ABCDEF-GHI\
    \";\
    \n:global TelegramChatId \"-12345678\";\
    \n#:global TelegramTokenId \"123456:ABCDEF-GHI\";\
    \n#:global TelegramChatId \"12345678\";\
    \n# This is whether or not to send Telegram messages with fixed-width font\
    .\
    \n:global TelegramFixedWidthFont true;\
    \n\
    \n# Toggle this to disable symbols in notifications.\
    \n:global NotificationsWithSymbols true;\
    \n# Toggle this to disable color output in terminal/cli.\
    \n:global TerminalColorOutput true;\
    \n\
    \n# This defines what backups to generate and what password to use.\
    \n:global BackupSendBinary true;\
    \n:global BackupSendExport true;\
    \n:global BackupPassword \"xzxzxzxz\";\
    \n:global BackupRandomDelay 0;\
    \n# These addresses are used to send backup and config export files to.\
    \n:global EmailBackupTo \"xxxxx@gmail.com\";\
    \n:global EmailBackupCc \"xxxxx@gmail.com\";\
    \n# These credentials are used to upload backup and config export files.\
    \n# SFTP authentication is tricky, you may have to limit authentication\
    \n# methods for your SSH server.\
    \n:global BackupUploadUrl \"sftp://example.com/backup/\";\
    \n:global BackupUploadUser \"root\";\
    \n:global BackupUploadPass \"xzxzxzxz\";\
    \n\
    \n# This defines a filter on log topics not to be forwarded.\
    \n:global LogForwardFilter \"(debug|info)\";\
    \n# ... and the same for log message text. Regular expressions are support\
    ed.\
    \n# Do *NOT* set an empty string - that will filter everything!\
    \n:global LogForwardFilterMessage [];\
    \n#:global LogForwardFilterMessage \"message text\";\
    \n#:global LogForwardFilterMessage \"(message text|another text|...)\";\
    \n\
    \n# Specify an address to enable auto update to version assumed safe.\
    \n# The configured channel (bugfix, current, release-candidate) is appende\
    d.\
    \n:global SafeUpdateUrl \"\";\
    \n#:global SafeUpdateUrl \"https://example.com/ros/safe-update/\";\
    \n# Allow to install patch updates automatically.\
    \n:global SafeUpdatePatch false;\
    \n# Allow to install updates automatically if seen in neighbor list.\
    \n:global SafeUpdateNeighbor false;\
    \n\
    \n# These thresholds control when to send health notification\
    \n# on temperature and voltage.\
    \n:global CheckHealthTemperature {\
    \n  temperature=50;\
    \n  cpu-temperature=70;\
    \n  board-temperature1=50;\
    \n  board-temperature2=50;\
    \n}\
    \n# This is deviation on recovery threshold against notification flooding.\
    \n:global CheckHealthTemperatureDeviation 2;\
    \n:global CheckHealthVoltagePercent 10;\
    \n\
    \n# This controls what configuration is activated by bridge-port-to-defaul\
    t.\
    \n:global BridgePortTo \"default\";\
    \n\
    \n# Access-list entries matching this comment are updated\
    \n# with daily pseudo-random PSK.\
    \n:global DailyPskMatchComment \"Daily PSK\";\
    \n:global DailyPskSecrets {\
    \n  { \"Abusive\"; \"Aggressive\"; \"Bored\"; \"Chemical\"; \"Cold\";\
    \n    \"Cruel\"; \"Curved\"; \"Delightful\"; \"Discreet\"; \"Elite\";\
    \n    \"Evasive\"; \"Faded\"; \"Flat\"; \"Future\"; \"Grandiose\";\
    \n    \"Hanging\"; \"Humorous\"; \"Interesting\"; \"Magenta\";\
    \n    \"Magnificent\"; \"Numerous\"; \"Optimal\"; \"Pathetic\";\
    \n    \"Possessive\"; \"Remarkable\"; \"Rightful\"; \"Ruthless\";\
    \n    \"Stale\"; \"Unusual\"; \"Useless\"; \"Various\" };\
    \n  { \"Adhesive\"; \"Amusing\"; \"Astonishing\"; \"Frantic\";\
    \n    \"Kindhearted\"; \"Limping\"; \"Roasted\"; \"Robust\";\
    \n    \"Staking\"; \"Thundering\"; \"Ultra\"; \"Unreal\" };\
    \n  { \"Belief\"; \"Button\"; \"Curtain\"; \"Edge\"; \"Jewel\";\
    \n    \"String\"; \"Whistle\" }\
    \n}\
    \n\
    \n# Run different commands with multiple mode-button presses.\
    \n:global ModeButton {\
    \n  1=\"/ system script run leds-toggle-mode;\";\
    \n  2=\":global SendNotification; :global Identity; \\\$SendNotification (\
    \\\"Hello...\\\") (\\\"Hello world, \\\" . \\\$Identity . \\\" calling!\\\
    \");\";\
    \n  3=\"/ system shutdown;\";\
    \n  4=\"/ system reboot;\";\
    \n  5=\"/ system script run bridge-port-toggle;\";\
    \n# add more here...\
    \n};\
    \n# This led gives visual feedback if type is 'on' or 'off'.\
    \n:global ModeButtonLED \"user-led\";\
    \n\
    \n# Run commands on SMS action.\
    \n:global SmsAction {\
    \n  bridge-port-toggle=\"/ system script run bridge-port-toggle;\";\
    \n  reboot=\"/ system reboot;\";\
    \n  shutdown=\"/ system shutdown;\";\
    \n# add more here...\
    \n};\
    \n\
    \n# This address should resolve ntp servers and is used to update\
    \n# ntp settings. A pool can rotate servers.\
    \n:global NtpPool \"pool.ntp.org\";\
    \n\
    \n# This is the address used to send gps data to.\
    \n:global GpsTrackUrl \"https://example.com/index.php\";\
    \n\
    \n# Enable this to fetch scripts from given url.\
    \n:global ScriptUpdatesFetch true;\
    \n:global ScriptUpdatesBaseUrl \"https://git.eworm.de/cgit/routeros-script\
    s/plain/\";\
    \n# alternative urls - main: stable code - next: currently in development\
    \n#:global ScriptUpdatesBaseUrl \"https://raw.githubusercontent.com/eworm-\
    de/routeros-scripts/main/\";\
    \n#:global ScriptUpdatesBaseUrl \"https://raw.githubusercontent.com/eworm-\
    de/routeros-scripts/next/\";\
    \n#:global ScriptUpdatesBaseUrl \"https://gitlab.com/eworm-de/routeros-scr\
    ipts/raw/main/\";\
    \n#:global ScriptUpdatesBaseUrl \"https://gitlab.com/eworm-de/routeros-scr\
    ipts/raw/next/\";\
    \n:global ScriptUpdatesUrlSuffix \"\";\
    \n# use next branch with default url (git.eworm.de)\
    \n#:global ScriptUpdatesUrlSuffix \"\\\?h=next\";\
    \n\
    \n# This project is developed in private spare time and usage is free of c\
    harge\
    \n# for you. If you like the scripts and think this is of value for you or\
    \_your\
    \n# business please consider a donation:\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/#donate\
    \n# Enable this to silence donation hint.\
    \n:global IDonate false;\
    \n\
    \n# Use this for certificate auto-renew\
    \n:global CertRenewUrl \"\";\
    \n#:global CertRenewUrl \"https://example.com/certificates/\";\
    \n:global CertRenewTime 3w;\
    \n:global CertRenewPass {\
    \n  \"xzxzxzxz\";\
    \n  \"xzxzxzxz\";\
    \n}\
    \n:global CertIssuedExportPass {\
    \n  \"cert1-cn\"=\"xzxzxzxz\";\
    \n  \"cert2-cn\"=\"xzxzxzxz\";\
    \n}\
    \n\
    \n# End of global-config-overlay\
    \n"
add dont-require-permissions=no name=global-functions owner=global-functions \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source="#!rsc by RouterOS\
    \n# RouterOS script: global-functions\
    \n# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>\
    \n#                         Michael Gisbers <michael@gisbers.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# global functions\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/\
    \n\
    \n# expected configuration version\
    \n:global ExpectedConfigVersion 52;\
    \n\
    \n# global variables not to be changed by user\
    \n:global GlobalFunctionsReady false;\
    \n:global Identity [ / system identity get name ];\
    \n\
    \n# global functions\
    \n:global CertificateAvailable;\
    \n:global CertificateDownload;\
    \n:global CertificateNameByCN;\
    \n:global CharacterReplace;\
    \n:global CleanFilePath;\
    \n:global DefaultRouteIsReachable;\
    \n:global DeviceInfo;\
    \n:global DNSIsResolving;\
    \n:global DownloadPackage;\
    \n:global EitherOr;\
    \n:global EscapeForRegEx;\
    \n:global FlushEmailQueue;\
    \n:global FlushTelegramQueue;\
    \n:global GetMacVendor;\
    \n:global GetRandom20CharHex;\
    \n:global GetRandomNumber;\
    \n:global IfThenElse;\
    \n:global IPCalc;\
    \n:global LogPrintExit;\
    \n:global LogPrintExit2;\
    \n:global MkDir;\
    \n:global ParseKeyValueStore;\
    \n:global QuotedPrintable;\
    \n:global RandomDelay;\
    \n:global RequiredRouterOS;\
    \n:global ScriptFromTerminal;\
    \n:global ScriptInstallUpdate;\
    \n:global ScriptLock;\
    \n:global SendEMail;\
    \n:global SendEMail2;\
    \n:global SendNotification;\
    \n:global SendNotification2;\
    \n:global SendTelegram;\
    \n:global SendTelegram2;\
    \n:global SymbolByUnicodeName;\
    \n:global SymbolForNotification;\
    \n:global TimeIsSync;\
    \n:global UrlEncode;\
    \n:global ValidateSyntax;\
    \n:global VersionToNum;\
    \n:global WaitDefaultRouteReachable;\
    \n:global WaitDNSResolving;\
    \n:global WaitForFile;\
    \n:global WaitFullyConnected;\
    \n:global WaitTimeSync;\
    \n\
    \n# check and download required certificate\
    \n:set CertificateAvailable do={\
    \n  :local CommonName [ :tostr \$1 ];\
    \n\
    \n  :global CertificateDownload;\
    \n  :global LogPrintExit2;\
    \n  :global ParseKeyValueStore;\
    \n  :global RequiredRouterOS;\
    \n\
    \n  :if ([ / system resource get free-hdd-space ] < 8388608 && \\\
    \n       [ / certificate settings get crl-download ] = true && \\\
    \n       [ / certificate settings get crl-store ] = \"system\") do={\
    \n    \$LogPrintExit2 warning \$0 (\"This system has low free flash space \
    but \" . \\\
    \n      \"is configured to download certificate CRLs to system!\") false;\
    \n  }\
    \n\
    \n  :if ([ :len [ / certificate find where common-name=\$CommonName ] ] = \
    0) do={\
    \n    \$LogPrintExit2 info \$0 (\"Certificate with CommonName \\\"\" . \$C\
    ommonName . \"\\\" not available.\") false;\
    \n    :if ([ \$CertificateDownload \$CommonName ] = false) do={\
    \n      :return false;\
    \n    }\
    \n  }\
    \n\
    \n  :if ([ \$RequiredRouterOS \$0 \"6.47\" ] = false) do={\
    \n    :return true;\
    \n  }\
    \n\
    \n  :local CertVal [ / certificate get [ find where common-name=\$CommonNa\
    me ] ];\
    \n  :while ((\$CertVal->\"akid\") != \"\" && (\$CertVal->\"akid\") != (\$C\
    ertVal->\"skid\")) do={\
    \n    :if ([ :len [ / certificate find where skid=(\$CertVal->\"akid\") ] \
    ] = 0) do={\
    \n      \$LogPrintExit2 info \$0 (\"Certificate chain for \\\"\" . \$Commo\
    nName . \\\
    \n        \"\\\" is incomplete, missing \\\"\" . ([ \$ParseKeyValueStore (\
    \$CertVal->\"issuer\") ]->\"CN\") . \"\\\".\") false;\
    \n      :if ([ \$CertificateDownload \$CommonName ] = false) do={\
    \n        :return false;\
    \n      }\
    \n    }\
    \n    :set CertVal [ / certificate get [ find where skid=(\$CertVal->\"aki\
    d\") ] ];\
    \n  }\
    \n  :return true;\
    \n}\
    \n\
    \n# download and import certificate\
    \n:set CertificateDownload do={\
    \n  :local CommonName [ :tostr \$1 ];\
    \n\
    \n  :global ScriptUpdatesBaseUrl;\
    \n  :global ScriptUpdatesUrlSuffix;\
    \n\
    \n  :global CertificateNameByCN;\
    \n  :global LogPrintExit2;\
    \n  :global UrlEncode;\
    \n  :global WaitForFile;\
    \n\
    \n  \$LogPrintExit2 info \$0 (\"Downloading and importing certificate with\
    \_\" . \\\
    \n      \"CommonName \\\"\" . \$CommonName . \"\\\".\") false;\
    \n  :do {\
    \n    :local LocalFileName (\$CommonName . \".pem\");\
    \n    :local UrlFileName ([ \$UrlEncode \$CommonName ] . \".pem\");\
    \n    / tool fetch check-certificate=yes-without-crl \\\
    \n      (\$ScriptUpdatesBaseUrl . \"certs/\" . \\\
    \n      \$UrlFileName . \$ScriptUpdatesUrlSuffix) \\\
    \n      dst-path=\$LocalFileName as-value;\
    \n    \$WaitForFile \$LocalFileName;\
    \n    / certificate import file-name=\$LocalFileName passphrase=\"\" as-va\
    lue;\
    \n    / file remove \$LocalFileName;\
    \n\
    \n    :foreach Cert in=[ / certificate find where name~(\"^\" . \$LocalFil\
    eName . \"_[0-9]+\\\$\") ] do={\
    \n      \$CertificateNameByCN [ / certificate get \$Cert common-name ];\
    \n    }\
    \n  } on-error={\
    \n    \$LogPrintExit2 warning \$0 (\"Failed importing certificate with \" \
    . \\\
    \n        \"CommonName \\\"\" . \$CommonName . \"\\\"!\") false;\
    \n    :return false;\
    \n  }\
    \n  :return true;\
    \n}\
    \n\
    \n# name a certificate by its common-name\
    \n:set CertificateNameByCN do={\
    \n  :local CommonName [ :tostr \$1 ];\
    \n\
    \n  :global CharacterReplace;\
    \n\
    \n  :local Cert [ / certificate find where common-name=\$CommonName ];\
    \n  / certificate set \$Cert \\\
    \n    name=[ \$CharacterReplace [ \$CharacterReplace [ \$CharacterReplace \
    \$CommonName \"'\" \"-\" ] \" \" \"-\" ] \"---\" \"-\" ];\
    \n}\
    \n\
    \n# character replace\
    \n:set CharacterReplace do={\
    \n  :local String [ :tostr \$1 ];\
    \n  :local ReplaceFrom [ :tostr \$2 ];\
    \n  :local ReplaceWith [ :tostr \$3 ];\
    \n  :local Return \"\";\
    \n\
    \n  :if (\$ReplaceFrom = \"\") do={\
    \n    :return \$String;\
    \n  }\
    \n\
    \n  :while ([ :typeof [ :find \$String \$ReplaceFrom ] ] != \"nil\") do={\
    \n    :local Pos [ :find \$String \$ReplaceFrom ];\
    \n    :set Return (\$Return . [ :pick \$String 0 \$Pos ] . \$ReplaceWith);\
    \n    :set String [ :pick \$String (\$Pos + [ :len \$ReplaceFrom ]) [ :len\
    \_\$String ] ];\
    \n  }\
    \n\
    \n  :return (\$Return . \$String);\
    \n}\
    \n\
    \n# clean file path\
    \n:set CleanFilePath do={\
    \n  :local Path [ :tostr \$1 ];\
    \n\
    \n  :global CharacterReplace;\
    \n\
    \n  :while (\$Path ~ \"//\") do={\
    \n    :set \$Path [ \$CharacterReplace \$Path \"//\" \"/\" ];\
    \n  }\
    \n  :if ([ :pick \$Path 0 ] = \"/\") do={\
    \n    :set Path [ :pick \$Path 1 [ :len \$Path ] ];\
    \n  }\
    \n  :if ([ :pick \$Path ([ :len \$Path ] - 1) ] = \"/\") do={\
    \n    :set Path [ :pick \$Path 0 ([ :len \$Path ] - 1) ];\
    \n  }\
    \n\
    \n  :return \$Path;\
    \n}\
    \n\
    \n# default route is reachable\
    \n:set DefaultRouteIsReachable do={\
    \n  :if ([ :len [ / ip route find where dst-address=0.0.0.0/0 active !blac\
    khole !routing-mark !unreachable ] ] > 0) do={\
    \n    :return true;\
    \n  }\
    \n  :return false;\
    \n}\
    \n\
    \n# get readable device info\
    \n:set DeviceInfo do={\
    \n  :global ExpectedConfigVersion;\
    \n  :global GlobalConfigVersion;\
    \n  :global Identity;\
    \n\
    \n  :global IfThenElse;\
    \n\
    \n  :local Resource [ / system resource get ];\
    \n  :local RouterBoard [ / system routerboard get ];\
    \n  :local Update [ / system package update get ];\
    \n\
    \n  :return ( \\\
    \n         \"Hostname:       \" . \$Identity . \\\
    \n       \"\\nBoard name:     \" . \$Resource->\"board-name\" . \\\
    \n       \"\\nArchitecture:   \" . \$Resource->\"architecture-name\" . \\\
    \n    [ \$IfThenElse (\$RouterBoard->\"routerboard\" = true) \\\
    \n      (\"\\nModel:          \" . \$RouterBoard->\"model\" . \\\
    \n         [ \$IfThenElse ([ :len (\$RouterBoard->\"revision\") ] > 0) \\\
    \n           (\" \" . \$RouterBoard->\"revision\") ] . \\\
    \n       \"\\nSerial number:  \" . \$RouterBoard->\"serial-number\") ] . \
    \\\
    \n       \"\\nRouterOS:\" . \\\
    \n       \"\\n    Channel:    \" . \$Update->\"channel\" . \\\
    \n       \"\\n    Installed:  \" . \$Update->\"installed-version\" . \\\
    \n    [ \$IfThenElse ([ :typeof (\$Update->\"latest-version\") ] != \"noth\
    ing\" && \\\
    \n        \$Update->\"installed-version\" != \$Update->\"latest-version\")\
    \_\\\
    \n      (\"\\n    Available:  \" . \$Update->\"latest-version\") ] . \\\
    \n       \"\\nRouterOS-Scripts:\" . \\\
    \n       \"\\n    Current:    \" . \$GlobalConfigVersion . \\\
    \n    [ \$IfThenElse (\$GlobalConfigVersion != \$ExpectedConfigVersion) \\\
    \n      (\"\\n    Expected:   \" . \$ExpectedConfigVersion) ]);\
    \n}\
    \n\
    \n# check if DNS is resolving\
    \n:set DNSIsResolving do={\
    \n  :global CharacterReplace;\
    \n\
    \n  :do {\
    \n    :resolve \"low-ttl.eworm.de\";\
    \n  } on-error={\
    \n    :return false;\
    \n  }\
    \n  :return true;\
    \n}\
    \n\
    \n# download package from upgrade server\
    \n:set DownloadPackage do={\
    \n  :local PkgName [ :tostr \$1 ];\
    \n  :local PkgVer  [ :tostr \$2 ];\
    \n  :local PkgArch [ :tostr \$3 ];\
    \n  :local PkgDir  [ :tostr \$4 ];\
    \n\
    \n  :global CertificateAvailable;\
    \n  :global CleanFilePath;\
    \n  :global LogPrintExit2;\
    \n  :global WaitForFile;\
    \n\
    \n  :if ([ :len \$PkgName ] = 0) do={ :return false; }\
    \n  :if ([ :len \$PkgVer  ] = 0) do={ :set PkgVer  [ / system package upda\
    te get installed-version ]; }\
    \n  :if ([ :len \$PkgArch ] = 0) do={ :set PkgArch [ / system resource get\
    \_architecture-name ]; }\
    \n\
    \n  :local PkgFile (\$PkgName . \"-\" . \$PkgVer . \"-\" . \$PkgArch . \".\
    npk\");\
    \n  :if (\$PkgArch = \"x86_64\" || \$PkgName ~ \"^routeros-\") do={\
    \n    :set PkgFile (\$PkgName . \"-\" . \$PkgVer . \".npk\");\
    \n  }\
    \n  :local PkgDest [ \$CleanFilePath (\$PkgDir . \"/\" . \$PkgFile) ];\
    \n\
    \n  :if ([ :len [ / file find where name=\$PkgDest type=\"package\" ] ] > \
    0) do={\
    \n    \$LogPrintExit2 info \$0 (\"Package file \" . \$PkgName . \" already\
    \_exists.\") false;\
    \n    :return true;\
    \n  }\
    \n\
    \n  :if ([ \$CertificateAvailable \"R3\" ] = false) do={\
    \n    \$LogPrintExit2 error \$0 (\"Downloading required certificate failed\
    .\") true;\
    \n  }\
    \n\
    \n  \$LogPrintExit2 info \$0 (\"Downloading package file '\" . \$PkgName .\
    \_\"'...\") false;\
    \n  :local Retry 3;\
    \n  :while (\$Retry > 0) do={\
    \n    :do {\
    \n      / tool fetch check-certificate=yes-without-crl \\\
    \n        (\"https://upgrade.mikrotik.com/routeros/\" . \$PkgVer . \"/\" .\
    \_\$PkgFile) \\\
    \n        dst-path=\$PkgDest;\
    \n      \$WaitForFile \$PkgDest;\
    \n\
    \n      :if ([ / file get [ find where name=\$PkgDest ] type ] = \"package\
    \") do={\
    \n        :return true;\
    \n      }\
    \n    } on-error={\
    \n      \$LogPrintExit2 debug \$0 (\"Downloading package file failed.\") f\
    alse;\
    \n    }\
    \n\
    \n    / file remove [ find where name=\$PkgDest ];\
    \n    :set Retry (\$Retry - 1);\
    \n  }\
    \n\
    \n  \$LogPrintExit2 warning \$0 (\"Downloading package file '\" . \$PkgNam\
    e . \"' failed.\") false;\
    \n  :return false;\
    \n}\
    \n\
    \n# return either first (if \"true\") or second\
    \n:set EitherOr do={\
    \n  :global IfThenElse;\
    \n\
    \n  :if ([ :typeof \$1 ] = \"num\") do={\
    \n    :return [ \$IfThenElse (\$1 != 0) \$1 \$2 ];\
    \n  }\
    \n  :return [ \$IfThenElse ([ :len [ :tostr \$1 ] ] > 0) \$1 \$2 ];\
    \n}\
    \n\
    \n# escape for regular expression\
    \n:set EscapeForRegEx do={\
    \n  :local Input [ :tostr \$1 ];\
    \n\
    \n  :if ([ :len \$Input ] = 0) do={\
    \n    :return \"\";\
    \n  }\
    \n\
    \n  :local Return \"\";\
    \n  :local Chars \"^.[]\\\$()|*+\\\?{}\\\\\";\
    \n\
    \n  :for I from=0 to=([ :len \$Input ] - 1) do={\
    \n    :local Char [ :pick \$Input \$I ];\
    \n    :if ([ :find \$Chars \$Char ]) do={\
    \n      :set Char (\"\\\\\" . \$Char);\
    \n    }\
    \n    :set Return (\$Return . \$Char);\
    \n  }\
    \n\
    \n  :return \$Return;\
    \n}\
    \n\
    \n# flush e-mail queue\
    \n:set FlushEmailQueue do={\
    \n  :global EmailQueue;\
    \n\
    \n  :global EitherOr;\
    \n  :global LogPrintExit2;\
    \n\
    \n  :local AllDone true;\
    \n  :local QueueLen [ :len \$EmailQueue ];\
    \n\
    \n  :if ([ :len [ / system scheduler find where name=\"FlushEmailQueue\" ]\
    \_] > 0 && \$QueueLen = 0) do={\
    \n    \$LogPrintExit2 warning \$0 (\"Flushing E-Mail messages from schedul\
    er, but queue is empty.\") false;\
    \n  }\
    \n\
    \n  / system scheduler set interval=(\$QueueLen . \"m\") [ find where name\
    =\"FlushEmailQueue\" ];\
    \n\
    \n  :foreach Id,Message in=\$EmailQueue do={\
    \n    :if ([ :typeof \$Message ] = \"array\" ) do={\
    \n      / tool e-mail send to=(\$Message->\"to\") cc=(\$Message->\"cc\") s\
    ubject=(\$Message->\"subject\") \\\
    \n        body=(\$Message->\"body\") file=[ \$EitherOr (\$Message->\"attac\
    h\") \"\" ];\
    \n      :local Wait true;\
    \n      :do {\
    \n        :delay 1s;\
    \n        :local Status [ / tool e-mail get last-status ];\
    \n        :if (\$Status = \"succeeded\") do={\
    \n          :set (\$EmailQueue->\$Id);\
    \n          :set Wait false;\
    \n        }\
    \n        :if (\$Status = \"failed\") do={\
    \n          :set AllDone false;\
    \n          :set Wait false;\
    \n        }\
    \n      } while=(\$Wait = true);\
    \n    }\
    \n  }\
    \n\
    \n  :if (\$AllDone = true && \$QueueLen = [ :len \$EmailQueue ]) do={\
    \n    / system scheduler remove [ find where name=\"FlushEmailQueue\" ];\
    \n    :set EmailQueue;\
    \n  } else={\
    \n    / system scheduler set interval=1m [ find where name=\"FlushEmailQue\
    ue\" ];\
    \n  }\
    \n}\
    \n\
    \n# flush telegram queue\
    \n:set FlushTelegramQueue do={\
    \n  :global TelegramQueue;\
    \n\
    \n  :global LogPrintExit2;\
    \n\
    \n  :local AllDone true;\
    \n  :local QueueLen [ :len \$TelegramQueue ];\
    \n\
    \n  :if ([ :len [ / system scheduler find where name=\"FlushTelegramQueue\
    \" ] ] > 0 && \$QueueLen = 0) do={\
    \n    \$LogPrintExit2 warning \$0 (\"Flushing Telegram messages from sched\
    uler, but queue is empty.\") false;\
    \n  }\
    \n\
    \n  :foreach Id,Message in=\$TelegramQueue do={\
    \n    :if ([ :typeof \$Message ] = \"array\" ) do={\
    \n      :do {\
    \n        / tool fetch check-certificate=yes-without-crl output=none http-\
    method=post \\\
    \n          (\"https://api.telegram.org/bot\" . (\$Message->\"tokenid\") .\
    \_\"/sendMessage\") \\\
    \n          http-data=(\"chat_id=\" . (\$Message->\"chatid\") . \\\
    \n          \"&disable_notification=\" . (\$Message->\"silent\") . \\\
    \n          \"&disable_web_page_preview=true&parse_mode=\" . (\$Message->\
    \"parsemode\") . \\\
    \n          \"&text=\" . (\$Message->\"text\")) as-value;\
    \n        :set (\$TelegramQueue->\$Id);\
    \n      } on-error={\
    \n        \$LogPrintExit2 debug \$0 (\"Sending queued Telegram message fai\
    led.\") false;\
    \n        :set AllDone false;\
    \n      }\
    \n    }\
    \n  }\
    \n\
    \n  :if (\$AllDone = true && \$QueueLen = [ :len \$TelegramQueue ]) do={\
    \n    / system scheduler remove [ find where name=\"FlushTelegramQueue\" ]\
    ;\
    \n    :set TelegramQueue;\
    \n  }\
    \n}\
    \n\
    \n# get MAC vendor\
    \n:set GetMacVendor do={\
    \n  :local Mac [ :tostr \$1 ];\
    \n\
    \n  :global CertificateAvailable;\
    \n  :global LogPrintExit2;\
    \n\
    \n  :do {\
    \n    :if ([ \$CertificateAvailable \"Cloudflare Inc ECC CA-3\" ] = false)\
    \_do={\
    \n      \$LogPrintExit2 warning \$0 (\"Downloading required certificate fa\
    iled.\") true;\
    \n    }\
    \n    :local Vendor ([ / tool fetch check-certificate=yes-without-crl \\\
    \n        (\"https://api.macvendors.com/\" . [ :pick \$Mac 0 8 ]) output=u\
    ser as-value ]->\"data\");\
    \n    :return \$Vendor;\
    \n  } on-error={\
    \n    :do {\
    \n      / tool fetch check-certificate=yes-without-crl (\"https://api.macv\
    endors.com/\") \\\
    \n        output=none as-value;\
    \n      \$LogPrintExit2 debug \$0 (\"The mac vendor is not known in databa\
    se.\") false;\
    \n    } on-error={\
    \n      \$LogPrintExit2 warning \$0 (\"Failed getting mac vendor.\") false\
    ;\
    \n    }\
    \n    :return \"unknown vendor\";\
    \n  }\
    \n}\
    \n\
    \n# generate random 20 chars hex (0-9 and a-f)\
    \n:set GetRandom20CharHex do={\
    \n  :local Random ([ / certificate scep-server otp generate minutes-valid=\
    0 as-value ]->\"password\");\
    \n  / certificate scep-server otp remove [ find where password=\$Random ];\
    \n  :return \$Random;\
    \n}\
    \n\
    \n# generate random number\
    \n:set GetRandomNumber do={\
    \n  :local Max 4294967295;\
    \n  :if ([ :typeof \$1 ] != \"nothing\" ) do={\
    \n    :set Max ([ :tonum \$1 ] + 1);\
    \n  }\
    \n\
    \n  :global GetRandom20CharHex;\
    \n\
    \n  :local Num;\
    \n  :local 40CharHex ([ \$GetRandom20CharHex ] . [ \$GetRandom20CharHex ])\
    ;\
    \n\
    \n  :for I from=0 to=39 do={\
    \n    :local Char [ :pick \$40CharHex \$I ];\
    \n    :if (\$Char~\"[0-9]\") do={\
    \n      :set Num (\$Num . \$Char);\
    \n    }\
    \n  }\
    \n\
    \n  :return ([ :tonum [ :pick \$Num 0 18 ] ] % \$Max);\
    \n}\
    \n\
    \n# mimic conditional/ternary operator (condition \? consequent : alternat\
    ive)\
    \n:set IfThenElse do={\
    \n  :if ([ :tostr \$1 ] = \"true\" || [ :tobool \$1 ] = true) do={\
    \n    :return \$2;\
    \n  }\
    \n  :return \$3;\
    \n}\
    \n\
    \n# calculate and print netmask, network, min host, max host and broadcast\
    \n:set IPCalc do={\
    \n  :local Input [ :tostr \$1 ];\
    \n  :local Address [ :toip [ :pick \$Input 0 [ :find \$Input \"/\" ] ] ];\
    \n  :local Bits [ :tonum [ :pick \$Input ([ :find \$Input \"/\" ] + 1) [ :\
    len \$Input ] ] ];\
    \n  :local Mask ((255.255.255.255 << (32 - \$Bits)) & 255.255.255.255);\
    \n\
    \n  :local Return {\
    \n    \"address\"=\$Address;\
    \n    \"netmask\"=\$Mask;\
    \n    \"networkaddress\"=(\$Address & \$Mask);\
    \n    \"networkbits\"=\$Bits;\
    \n    \"network\"=((\$Address & \$Mask) . \"/\" . \$Bits);\
    \n    \"hostmin\"=((\$Address & \$Mask) | 0.0.0.1);\
    \n    \"hostmax\"=((\$Address | ~\$Mask) ^ 0.0.0.1);\
    \n    \"broadcast\"=(\$Address | ~\$Mask);\
    \n  }\
    \n\
    \n  :put ( \\\
    \n    \"Address:   \" . \$Return->\"address\" . \"\\n\\r\" . \\\
    \n    \"Netmask:   \" . \$Return->\"netmask\" . \"\\n\\r\" . \\\
    \n    \"Network:   \" . \$Return->\"network\" . \"\\n\\r\" . \\\
    \n    \"HostMin:   \" . \$Return->\"hostmin\" . \"\\n\\r\" . \\\
    \n    \"HostMax:   \" . \$Return->\"hostmax\" . \"\\n\\r\" . \\\
    \n    \"Broadcast: \" . \$Return->\"broadcast\");\
    \n\
    \n  :return \$Return;\
    \n}\
    \n\
    \n# deprecated compatibility wrapper\
    \n:set LogPrintExit do={\
    \n  :global LogPrintExit2;\
    \n\
    \n  \$LogPrintExit2 warning \$0 (\"This function is deprecated. Please use\
    \_\\\$LogPrintExit2 instead.\") false;\
    \n  \$LogPrintExit2 \$1 \"unknown\" \$2 \$3;\
    \n}\
    \n\
    \n# log and print with same text, optionally exit\
    \n:set LogPrintExit2 do={\
    \n  :local Severity [ :tostr \$1 ];\
    \n  :local Name     [ :tostr \$2 ];\
    \n  :local Message  [ :tostr \$3 ];\
    \n  :local Exit     [ :tostr \$4 ];\
    \n\
    \n  :global PrintDebug;\
    \n\
    \n  :local PrintSeverity do={\
    \n    :global TerminalColorOutput;\
    \n\
    \n    :if (\$TerminalColorOutput != true) do={\
    \n      :return \$1;\
    \n    }\
    \n\
    \n    :local Color { debug=96; info=97; warning=93; error=91 };\
    \n    :return (\"\\1B[\" . \$Color->\$1 . \"m\" . \$1 . \"\\1B[0m\");\
    \n  }\
    \n\
    \n  :local Log (\$Name . \": \" . \$Message);\
    \n  :if (\$Severity ~ \"^(debug|error|info)\\\$\") do={\
    \n    :if (\$Severity = \"debug\") do={ :log debug \$Log; }\
    \n    :if (\$Severity = \"error\") do={ :log error \$Log; }\
    \n    :if (\$Severity = \"info\" ) do={ :log info  \$Log; }\
    \n  } else={\
    \n    :log warning \$Log;\
    \n    :set Severity \"warning\";\
    \n  }\
    \n\
    \n  :if (\$Severity != \"debug\" || \$PrintDebug = true) do={\
    \n    :if (\$Exit = \"true\") do={\
    \n      :error ([ \$PrintSeverity \$Severity ] . \": \" . \$Message);\
    \n    } else={\
    \n      :put ([ \$PrintSeverity \$Severity ] . \": \" . \$Message);\
    \n    }\
    \n  }\
    \n}\
    \n\
    \n# create directory\
    \n:set MkDir do={\
    \n  :local Dir [ :tostr \$1 ];\
    \n\
    \n  :global CleanFilePath;\
    \n  :global WaitForFile;\
    \n\
    \n  :set Dir [ \$CleanFilePath \$Dir ];\
    \n\
    \n  :if ([ :len [ / file find where name=\$Dir type=\"directory\" ] ] = 1)\
    \_do={\
    \n    :return true;\
    \n  }\
    \n\
    \n  :local Return true;\
    \n  :local WwwVal [ / ip service get www ];\
    \n  / ip service set www address=127.0.0.1/32 disabled=no port=80;\
    \n  :do {\
    \n    / tool fetch http://127.0.0.1/ dst-path=(\$Dir . \"/tmp\") as-value;\
    \n    \$WaitForFile (\$Dir . \"/tmp\");\
    \n    / file remove (\$Dir . \"/tmp\");\
    \n  } on-error={\
    \n    :set Return false;\
    \n  }\
    \n  / ip service set www address=(\$WwwVal->\"address\") \\\
    \n      disabled=(\$WwwVal->\"disabled\") port=(\$WwwVal->\"port\");\
    \n  :return \$Return;\
    \n}\
    \n\
    \n# parse key value store\
    \n:set ParseKeyValueStore do={\
    \n  :local Source \$1;\
    \n  :if ([ :typeof \$Source ] != \"array\") do={\
    \n    :set Source [ :tostr \$1 ];\
    \n  }\
    \n  :local Result [ :toarray \"\" ];\
    \n  :foreach KeyValue in=[ :toarray \$Source ] do={\
    \n    :if ([ :find \$KeyValue \"=\" ]) do={\
    \n      :set (\$Result->[ :pick \$KeyValue 0 [ :find \$KeyValue \"=\" ] ])\
    \_\\\
    \n        [ :pick \$KeyValue ([ :find \$KeyValue \"=\" ] + 1) [ :len \$Key\
    Value ] ];\
    \n    } else={\
    \n      :set (\$Result->\$KeyValue) true;\
    \n    }\
    \n  }\
    \n  :return \$Result;\
    \n}\
    \n\
    \n# convert string to quoted-printable\
    \n:global QuotedPrintable do={\
    \n  :local Input [ :tostr \$1 ];\
    \n\
    \n  :if ([ :len \$Input ] = 0) do={\
    \n    :return \$Input;\
    \n  }\
    \n\
    \n  :local Return \"\";\
    \n  :local Chars (\"\\80\\81\\82\\83\\84\\85\\86\\87\\88\\89\\8A\\8B\\8C\\\
    8D\\8E\\8F\\90\\91\\92\\93\\94\\95\\96\\97\" . \\\
    \n    \"\\98\\99\\9A\\9B\\9C\\9D\\9E\\9F\\A0\\A1\\A2\\A3\\A4\\A5\\A6\\A7\\\
    A8\\A9\\AA\\AB\\AC\\AD\\AE\\AF\\B0\\B1\\B2\\B3\" . \\\
    \n    \"\\B4\\B5\\B6\\B7\\B8\\B9\\BA\\BB\\BC\\BD\\BE\\BF\\C0\\C1\\C2\\C3\\\
    C4\\C5\\C6\\C7\\C8\\C9\\CA\\CB\\CC\\CD\\CE\\CF\" . \\\
    \n    \"\\D0\\D1\\D2\\D3\\D4\\D5\\D6\\D7\\D8\\D9\\DA\\DB\\DC\\DD\\DE\\DF\\\
    E0\\E1\\E2\\E3\\E4\\E5\\E6\\E7\\E8\\E9\\EA\\EB\" . \\\
    \n    \"\\EC\\ED\\EE\\EF\\F0\\F1\\F2\\F3\\F4\\F5\\F6\\F7\\F8\\F9\\FA\\FB\\\
    FC\\FD\\FE\\FF\");\
    \n  :local Hex { \"0\"; \"1\"; \"2\"; \"3\"; \"4\"; \"5\"; \"6\"; \"7\"; \
    \"8\"; \"9\"; \"A\"; \"B\"; \"C\"; \"D\"; \"E\"; \"F\" };\
    \n\
    \n  :for I from=0 to=([ :len \$Input ] - 1) do={\
    \n    :local Char [ :pick \$Input \$I ];\
    \n    :local Replace [ :find \$Chars \$Char ];\
    \n\
    \n    :if (\$Char = \"=\") do={\
    \n      :set Char \"=3D\";\
    \n    }\
    \n    :if ([ :typeof \$Replace ] = \"num\") do={\
    \n      :set Char (\"=\" . (\$Hex->(\$Replace / 16 + 8)) . (\$Hex->(\$Repl\
    ace % 16)));\
    \n    }\
    \n    :set Return (\$Return . \$Char);\
    \n  }\
    \n\
    \n  :if (\$Input = \$Return) do={\
    \n    :return \$Input;\
    \n  }\
    \n\
    \n  :return (\"=\\\?utf-8\\\?Q\\\?\" . \$Return . \"\\\?=\");\
    \n}\
    \n\
    \n# delay a random amount of seconds\
    \n:set RandomDelay do={\
    \n  :global GetRandomNumber;\
    \n\
    \n  :delay ([ \$GetRandomNumber \$1 ] . \"s\");\
    \n}\
    \n\
    \n# check for required RouterOS version\
    \n:set RequiredRouterOS do={\
    \n  :local Caller   [ :tostr \$1 ];\
    \n  :local Required [ :tostr \$2 ];\
    \n\
    \n  :global IfThenElse;\
    \n  :global LogPrintExit2;\
    \n  :global VersionToNum;\
    \n\
    \n  :if ([ \$VersionToNum \$Required ] > [ \$VersionToNum [ / system packa\
    ge update get installed-version ] ]) do={\
    \n    \$LogPrintExit2 warning \$0 (\"This \" . [ \$IfThenElse ([ :pick \$C\
    aller 0 ] = \"\\\$\") \"function\" \"script\" ] . \\\
    \n      \" '\" . \$Caller . \"' (at least specific functionality) requires\
    \_RouterOS \" . \$Required . \". Please update!\") false;\
    \n    :return false;\
    \n  }\
    \n  :return true;\
    \n}\
    \n\
    \n# check if script is run from terminal\
    \n:set ScriptFromTerminal do={\
    \n  :local Script [ :tostr \$1 ];\
    \n\
    \n  :global LogPrintExit2;\
    \n\
    \n  :foreach Job in=[ / system script job find where script=\$Script ] do=\
    {\
    \n    :set Job [ / system script job get \$Job ];\
    \n    :while ([ :typeof (\$Job->\"parent\") ] = \"id\") do={\
    \n      :set Job [ / system script job get [ find where .id=(\$Job->\"pare\
    nt\") ] ];\
    \n    }\
    \n    :if ((\$Job->\"type\") = \"login\") do={\
    \n      \$LogPrintExit2 debug \$0 (\"Script \" . \$Script . \" started fro\
    m terminal.\") false;\
    \n      :return true;\
    \n    }\
    \n  }\
    \n  \$LogPrintExit2 debug \$0 (\"Script \" . \$Script . \" NOT started fro\
    m terminal.\") false;\
    \n\
    \n  :return false;\
    \n}\
    \n\
    \n# install new scripts, update existing scripts\
    \n:set ScriptInstallUpdate do={\
    \n  :local Scripts [ :toarray \$1 ];\
    \n\
    \n  :global ExpectedConfigVersion;\
    \n  :global GlobalConfigVersion;\
    \n  :global Identity;\
    \n  :global IDonate;\
    \n  :global NotificationsWithSymbols;\
    \n  :global ScriptUpdatesBaseUrl;\
    \n  :global ScriptUpdatesFetch;\
    \n  :global ScriptUpdatesUrlSuffix;\
    \n  :global SentConfigChangesNotification;\
    \n\
    \n  :global CertificateAvailable;\
    \n  :global IfThenElse;\
    \n  :global LogPrintExit2;\
    \n  :global ParseKeyValueStore;\
    \n  :global ScriptInstallUpdate;\
    \n  :global SendNotification2;\
    \n  :global SymbolForNotification;\
    \n  :global ValidateSyntax;\
    \n\
    \n  :if ([ \$CertificateAvailable \"R3\" ] = false) do={\
    \n    \$LogPrintExit2 warning \$0 (\"Downloading certificate failed, tryin\
    g without.\") false;\
    \n  }\
    \n\
    \n  :foreach Script in=\$Scripts do={\
    \n    :if ([ :len [ / system script find where name=\$Script ] ] = 0) do={\
    \n      \$LogPrintExit2 info \$0 (\"Adding new script: \" . \$Script) fals\
    e;\
    \n      / system script add name=\$Script source=\"#!rsc by RouterOS\\n\";\
    \n    }\
    \n  }\
    \n\
    \n  :local ExpectedConfigVersionBefore \$ExpectedConfigVersion;\
    \n  :local ScriptInstallUpdateBefore [ :tostr \$ScriptInstallUpdate ];\
    \n\
    \n  :foreach Script in=[ / system script find where source~\"^#!rsc( by Ro\
    uterOS)\\\?\\n\" ] do={\
    \n    :local ScriptVal [ / system script get \$Script ];\
    \n    :local ScriptFile [ / file find where name=(\"script-updates/\" . \$\
    ScriptVal->\"name\") ];\
    \n    :local SourceNew;\
    \n    :if ([ :len \$ScriptFile ] > 0) do={\
    \n      :set SourceNew [ / file get \$ScriptFile content ];\
    \n      / file remove \$ScriptFile;\
    \n    }\
    \n\
    \n    :foreach Scheduler in=[ / system scheduler find where on-event~(\"\\\
    \\b\" . \$ScriptVal->\"name\" . \"\\\\b\") ] do={\
    \n      :local SchedulerVal [ / system scheduler get \$Scheduler ];\
    \n      :if (\$ScriptVal->\"policy\" != \$SchedulerVal->\"policy\") do={\
    \n        \$LogPrintExit2 warning \$0 (\"Policies differ for script \" . \
    \$ScriptVal->\"name\" . \\\
    \n          \" and its scheduler \" . \$SchedulerVal->\"name\" . \"!\") fa\
    lse;\
    \n      }\
    \n    }\
    \n\
    \n    :if ([ :len \$SourceNew ] = 0 && \$ScriptUpdatesFetch = true) do={\
    \n      :local Comment [ \$ParseKeyValueStore (\$ScriptVal->\"comment\") ]\
    ;\
    \n      :if (!(\$Comment->\"ignore\" = true)) do={\
    \n        \$LogPrintExit2 debug \$0 (\"Fetching script from url: \" . \$Sc\
    riptVal->\"name\") false;\
    \n        :do {\
    \n          :local BaseUrl \$ScriptUpdatesBaseUrl;\
    \n          :local UrlSuffix \$ScriptUpdatesUrlSuffix;\
    \n          :if ([ :typeof (\$Comment->\"base-url\") ] = \"str\") do={ :se\
    t BaseUrl (\$Comment->\"base-url\"); }\
    \n          :if ([ :typeof (\$Comment->\"url-suffix\") ] = \"str\") do={ :\
    set UrlSuffix (\$Comment->\"url-suffix\"); }\
    \n\
    \n          :local Result [ / tool fetch check-certificate=yes-without-crl\
    \_\\\
    \n              (\$BaseUrl . \$ScriptVal->\"name\" . \$UrlSuffix) output=u\
    ser as-value ];\
    \n          :if (\$Result->\"status\" = \"finished\") do={\
    \n            :set SourceNew (\$Result->\"data\");\
    \n          }\
    \n        } on-error={\
    \n          \$LogPrintExit2 warning \$0 (\"Failed fetching \" . \$ScriptVa\
    l->\"name\") false;\
    \n        }\
    \n      }\
    \n    }\
    \n\
    \n    :if ([ :len \$SourceNew ] > 0) do={\
    \n      :if (\$SourceNew != \$ScriptVal->\"source\") do={\
    \n        :if ([ :pick \$SourceNew 0 18 ] = \"#!rsc by RouterOS\\n\") do={\
    \n          :if ([ \$ValidateSyntax \$SourceNew ] = true) do={\
    \n            :local DontRequirePermissions \\\
    \n                (\$SourceNew~\"\\n# requires: dont-require-permissions=y\
    es\\n\");\
    \n            \$LogPrintExit2 info \$0 (\"Updating script: \" . \$ScriptVa\
    l->\"name\") false;\
    \n            / system script set owner=(\$ScriptVal->\"name\") source=\$S\
    ourceNew \\\
    \n                dont-require-permissions=\$DontRequirePermissions \$Scri\
    pt;\
    \n            :if (\$ScriptVal->\"name\" = \"global-config\") do={\
    \n              \$LogPrintExit2 info \$0 (\"Reloading global configuration\
    \_and overlay.\") false;\
    \n              :do {\
    \n                / system script { run global-config; run global-config-o\
    verlay; }\
    \n              } on-error={\
    \n                \$LogPrintExit2 error \$0 (\"Reloading global configurat\
    ion and overlay failed!\" . \\\
    \n                  \" Syntax error or missing overlay\\\?\") false;\
    \n              }\
    \n            }\
    \n            :if (\$ScriptVal->\"name\" = \"global-functions\") do={\
    \n              \$LogPrintExit2 info \$0 (\"Reloading global functions.\")\
    \_false;\
    \n              :do {\
    \n                / system script run global-functions;\
    \n              } on-error={\
    \n                \$LogPrintExit2 error \$0 (\"Reloading global functions \
    failed!\") false;\
    \n              }\
    \n            }\
    \n          } else={\
    \n            \$LogPrintExit2 warning \$0 (\"Syntax validation for script \
    \" . \$ScriptVal->\"name\" . \\\
    \n              \" failed! Ignoring!\") false;\
    \n          }\
    \n        } else={\
    \n          \$LogPrintExit2 warning \$0 (\"Looks like new script \" . \$Sc\
    riptVal->\"name\" . \\\
    \n            \" is not valid (missing shebang). Ignoring!\") false;\
    \n        }\
    \n      } else={\
    \n        \$LogPrintExit2 debug \$0 (\"Script \" .  \$ScriptVal->\"name\" \
    . \" did not change.\") false;\
    \n      }\
    \n    } else={\
    \n      \$LogPrintExit2 debug \$0 (\"No update for script \" . \$ScriptVal\
    ->\"name\" . \".\") false;\
    \n    }\
    \n  }\
    \n\
    \n  :if (\$ExpectedConfigVersionBefore != \$ExpectedConfigVersion) do={\
    \n    :global GlobalConfigChanges;\
    \n    :global GlobalConfigMigration;\
    \n    :local ChangeLogCode;\
    \n\
    \n    \$LogPrintExit2 debug \$0 (\"Fetching news, changes and migration.\"\
    ) false;\
    \n    :do {\
    \n      :local Result [ / tool fetch check-certificate=yes-without-crl \\\
    \n          (\$ScriptUpdatesBaseUrl . \"global-config.changes\" . \$Script\
    UpdatesUrlSuffix) \\\
    \n          output=user as-value ];\
    \n      :if (\$Result->\"status\" = \"finished\") do={\
    \n        :set ChangeLogCode (\$Result->\"data\");\
    \n      }\
    \n    } on-error={\
    \n      \$LogPrintExit2 warning \$0 (\"Failed fetching news, changes and m\
    igration!\") false;\
    \n    }\
    \n\
    \n    :if ([ :len \$ChangeLogCode ] > 0) do={\
    \n      :if ([ \$ValidateSyntax \$ChangeLogCode ] = true) do={\
    \n        [ :parse \$ChangeLogCode ];\
    \n      } else={\
    \n        \$LogPrintExit2 warning \$0 (\"The changelog failed syntax valid\
    ation!\") false;\
    \n      }\
    \n    }\
    \n\
    \n    :if ([ :len \$GlobalConfigMigration ] > 0) do={\
    \n      :for I from=(\$ExpectedConfigVersionBefore + 1) to=\$ExpectedConfi\
    gVersion do={\
    \n        :local Migration (\$GlobalConfigMigration->[ :tostr \$I ]);\
    \n        :if ([ :typeof \$Migration ] = \"str\") do={\
    \n          :if ([ \$ValidateSyntax \$Migration ] = true) do={\
    \n            \$LogPrintExit2 info \$0 (\"Applying migration for change \"\
    \_. \$I . \": \" . \$Migration) false;\
    \n            [ :parse \$Migration ];\
    \n          } else={\
    \n            \$LogPrintExit2 warning \$0 (\"Migration code for change \" \
    . \$I . \" failed syntax validation!\") false;\
    \n          }\
    \n        }\
    \n      }\
    \n    }\
    \n\
    \n    :if (\$SentConfigChangesNotification != \$ExpectedConfigVersion && \
    \\\
    \n         \$GlobalConfigVersion < \$ExpectedConfigVersion) do={\
    \n      :local NotificationMessage (\"Current configuration on \" . \$Iden\
    tity . \\\
    \n          \" is out of date. Please update global-config-overlay, then i\
    ncrease \" . \\\
    \n          \"\\\$GlobalConfigVersion (currently \" . \$GlobalConfigVersio\
    n . \\\
    \n          \") to \" . \$ExpectedConfigVersion . \" and re-run global-con\
    fig-overlay.\");\
    \n      \$LogPrintExit2 info \$0 (\$NotificationMessage) false;\
    \n\
    \n      :if ([ :len \$GlobalConfigChanges ] > 0) do={\
    \n        :set NotificationMessage (\$NotificationMessage . \"\\n\\nChange\
    s:\");\
    \n        :for I from=(\$GlobalConfigVersion + 1) to=\$ExpectedConfigVersi\
    on do={\
    \n          :local Change (\$GlobalConfigChanges->[ :tostr \$I ]);\
    \n          :set NotificationMessage (\$NotificationMessage . \"\\n \" . \
    \\\
    \n              [ \$IfThenElse (\$NotificationsWithSymbols = true) (\"\\E2\
    \\97\\8F\") \"*\" ] . \" \" . \$Change);\
    \n          \$LogPrintExit2 info \$0 (\"Change \" . \$I . \": \" . \$Chang\
    e) false;\
    \n        }\
    \n      } else={\
    \n        :set NotificationMessage (\$NotificationMessage . \"\\n\\nNews a\
    nd changes are not available.\");\
    \n      }\
    \n\
    \n      :local Link;\
    \n      :if (\$IDonate != true) do={\
    \n        :set NotificationMessage (\$NotificationMessage . \\\
    \n          \"\\n\\n==== donation hint ====\\n\" . \\\
    \n          \"This project is developed in private spare time and usage is\
    \_\" . \\\
    \n          \"free of charge for you. If you like the scripts and think th\
    is is \" . \\\
    \n          \"of value for you or your business please consider a donation\
    .\");\
    \n        :set Link \"https://git.eworm.de/cgit/routeros-scripts/about/#do\
    nate\";\
    \n      }\
    \n\
    \n      \$SendNotification2 ({ origin=\$0; \\\
    \n        subject=([ \$SymbolForNotification \"pushpin\" ] . \"News and co\
    nfiguration changes\"); \\\
    \n        message=\$NotificationMessage; link=\$Link });\
    \n      :set SentConfigChangesNotification \$ExpectedConfigVersion;\
    \n    }\
    \n\
    \n    :set GlobalConfigChanges;\
    \n    :set GlobalConfigMigration;\
    \n  }\
    \n\
    \n  :if (\$ScriptInstallUpdateBefore != [ :tostr \$ScriptInstallUpdate ]) \
    do={\
    \n    \$LogPrintExit2 info \$0 (\"This function changed, you may want to r\
    e-run.\") false;\
    \n  }\
    \n}\
    \n\
    \n# lock script against multiple invocation\
    \n:set ScriptLock do={\
    \n  :global LogPrintExit2;\
    \n\
    \n  :local Script [ :tostr \$1 ];\
    \n\
    \n  :if ([ :len [ / system script job find where script=\$Script ] ] > 1) \
    do={\
    \n    \$LogPrintExit2 info \$0 (\"Script \" . \$Script . \" started more t\
    han once... Aborting.\") true;\
    \n  }\
    \n}\
    \n\
    \n# send notification via e-mail - expects at lease two string arguments\
    \n:set SendEMail do={\
    \n  :global SendEMail2;\
    \n\
    \n  \$SendEMail2 ({ subject=\$1; message=\$2; link=\$3 });\
    \n}\
    \n\
    \n# send notification via e-mail - expects one array argument\
    \n:set SendEMail2 do={\
    \n  :local Notification \$1;\
    \n\
    \n  :global Identity;\
    \n  :global EmailGeneralTo;\
    \n  :global EmailGeneralToOverride;\
    \n  :global EmailGeneralCc;\
    \n  :global EmailGeneralCcOverride;\
    \n  :global EmailQueue;\
    \n\
    \n  :global EitherOr;\
    \n  :global IfThenElse;\
    \n  :global LogPrintExit2;\
    \n  :global QuotedPrintable;\
    \n\
    \n  :local To [ \$EitherOr (\$EmailGeneralToOverride->(\$Notification->\"o\
    rigin\")) \$EmailGeneralTo ];\
    \n  :local Cc [ \$EitherOr (\$EmailGeneralCcOverride->(\$Notification->\"o\
    rigin\")) \$EmailGeneralCc ];\
    \n\
    \n  :if ([ :len \$To ] = 0) do={\
    \n    :return false;\
    \n  }\
    \n\
    \n  :if ([ :typeof \$EmailQueue ] = \"nothing\") do={\
    \n      :set EmailQueue [ :toarray \"\" ];\
    \n  }\
    \n  :local Signature [ / system note get note ];\
    \n  :set (\$EmailQueue->[ :len \$EmailQueue ]) {\
    \n    to=\$To; cc=\$Cc;\
    \n    subject=[ \$QuotedPrintable (\"[\" . \$Identity . \"] \" . (\$Notifi\
    cation->\"subject\")) ];\
    \n    body=((\$Notification->\"message\") . \\\
    \n      [ \$IfThenElse ([ :len (\$Notification->\"link\") ] > 0) (\"\\n\\n\
    \" . (\$Notification->\"link\")) \"\" ] . \\\
    \n      [ \$IfThenElse ([ :len \$Signature ] > 0) (\"\\n-- \\n\" . \$Signa\
    ture) \"\" ]); \\\
    \n    attach=(\$Notification->\"attach\") };\
    \n  :if ([ :len [ / system scheduler find where name=\"FlushEmailQueue\" ]\
    \_] = 0) do={\
    \n    / system scheduler add name=FlushEmailQueue interval=1s start-time=s\
    tartup \\\
    \n      on-event=\":global FlushEmailQueue; \\\$FlushEmailQueue;\";\
    \n  }\
    \n}\
    \n\
    \n# send notification via e-mail and telegram - expects at lease two strin\
    g arguments\
    \n:set SendNotification do={\
    \n  :global SendNotification2;\
    \n\
    \n  \$SendNotification2 ({ subject=\$1; message=\$2; link=\$3; silent=\$4 \
    });\
    \n}\
    \n\
    \n# send notification via e-mail and telegram - expects one array argument\
    \n:set SendNotification2 do={\
    \n  :local Notification \$1;\
    \n\
    \n  :global SendEMail2;\
    \n  :global SendTelegram2;\
    \n\
    \n  \$SendEMail2 \$Notification;\
    \n  \$SendTelegram2 \$Notification;\
    \n}\
    \n\
    \n# send notification via telegram - expects at lease two string arguments\
    \n:set SendTelegram do={\
    \n  :global SendTelegram2;\
    \n\
    \n  \$SendTelegram2 ({ subject=\$1; message=\$2; link=\$3; silent=\$4 });\
    \n}\
    \n\
    \n# send notification via telegram - expects one array argument\
    \n:set SendTelegram2 do={\
    \n  :local Notification \$1;\
    \n\
    \n  :global Identity;\
    \n  :global TelegramChatId;\
    \n  :global TelegramChatIdOverride;\
    \n  :global TelegramFixedWidthFont;\
    \n  :global TelegramQueue;\
    \n  :global TelegramTokenId;\
    \n  :global TelegramTokenIdOverride;\
    \n\
    \n  :global CertificateAvailable;\
    \n  :global CharacterReplace;\
    \n  :global EitherOr;\
    \n  :global IfThenElse;\
    \n  :global LogPrintExit2;\
    \n  :global SymbolForNotification;\
    \n  :global UrlEncode;\
    \n\
    \n  :local EscapeMD do={\
    \n    :global TelegramFixedWidthFont;\
    \n\
    \n    :global CharacterReplace;\
    \n    :global IfThenElse;\
    \n\
    \n    :if (\$TelegramFixedWidthFont != true) do={\
    \n      :return (\$1 . [ \$IfThenElse (\$2 = \"body\") \"\\n\" \"\" ]);\
    \n    }\
    \n\
    \n    :local Return \$1;\
    \n    :local Chars {\
    \n      \"body\"={ \"\\\\\"; \"`\" };\
    \n      \"hint\"={ \"_\"; \"*\"; \"[\"; \"]\"; \"(\"; \")\"; \"~\"; \"`\";\
    \_\">\";\
    \n               \"#\"; \"+\"; \"-\"; \"=\"; \"|\"; \"{\"; \"}\"; \".\"; \
    \"!\" };\
    \n    }\
    \n    :foreach Char in=(\$Chars->\$2) do={\
    \n      :set Return [ \$CharacterReplace \$Return \$Char (\"\\\\\" . \$Cha\
    r) ];\
    \n    }\
    \n\
    \n    :if (\$2 = \"body\") do={\
    \n      :return (\"```\\n\" . \$Return . \"\\n```\");\
    \n    }\
    \n\
    \n    :return \$Return;\
    \n  }\
    \n\
    \n  :local ChatId [ \$EitherOr (\$TelegramChatIdOverride->(\$Notification-\
    >\"origin\")) \$TelegramChatId ];\
    \n  :local TokenId [ \$EitherOr (\$TelegramTokenIdOverride->(\$Notificatio\
    n->\"origin\")) \$TelegramTokenId ];\
    \n\
    \n  :if ([ :len \$TokenId ] = 0 || [ :len \$ChatId ] = 0) do={\
    \n    :return false;\
    \n  }\
    \n\
    \n  :local Truncated false;\
    \n  :local LenLink [ :len (\$Notification->\"link\") ];\
    \n  :local Text (\"[\" . \$Identity . \"] \" . (\$Notification->\"subject\
    \") . \"\\n\\n\" . (\$Notification->\"message\"));\
    \n  :local LenText [ :len \$Text ];\
    \n  :if (\$LenText > (3968 - \$LenLink)) do={\
    \n    :set Text [ \$EscapeMD ([ :pick \$Text 0 (3840 - \$LenLink) ] . \"..\
    .\") \"body\" ];\
    \n    :set Truncated true;\
    \n  } else={\
    \n    :set Text [ \$EscapeMD \$Text \"body\" ];\
    \n  }\
    \n  :if (\$LenLink > 0) do={\
    \n    :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"link\" ] .\
    \_[ \$EscapeMD (\$Notification->\"link\") \"hint\" ]);\
    \n  }\
    \n  :if (\$Truncated = true) do={\
    \n    :set Text (\$Text . \"\\n\" . [ \$SymbolForNotification \"scissors\"\
    \_] . \\\
    \n      [ \$EscapeMD (\"The Telegram message was too long and has been tru\
    ncated, cut off \" . \\\
    \n      ((\$LenText - [ :len \$Text ]) * 100 / \$LenText) . \"%!\") \"hint\
    \" ]);\
    \n  }\
    \n  :set Text [ \$UrlEncode \$Text ];\
    \n  :local ParseMode [ \$IfThenElse (\$TelegramFixedWidthFont = true) \"Ma\
    rkdownV2\" \"\" ];\
    \n\
    \n  :do {\
    \n    :if ([ \$CertificateAvailable \"Go Daddy Secure Certificate Authorit\
    y - G2\" ] = false) do={\
    \n      \$LogPrintExit2 warning \$0 (\"Downloading required certificate fa\
    iled.\") true;\
    \n    }\
    \n    / tool fetch check-certificate=yes-without-crl output=none http-meth\
    od=post \\\
    \n      (\"https://api.telegram.org/bot\" . \$TokenId . \"/sendMessage\") \
    \\\
    \n      http-data=(\"chat_id=\" . \$ChatId . \"&disable_notification=\" . \
    (\$Notification->\"silent\") . \\\
    \n      \"&disable_web_page_preview=true&parse_mode=\" . \$ParseMode . \"&\
    text=\" . \$Text) as-value;\
    \n  } on-error={\
    \n    \$LogPrintExit2 info \$0 (\"Failed sending telegram notification! Qu\
    euing...\") false;\
    \n\
    \n    :if ([ :typeof \$TelegramQueue ] = \"nothing\") do={\
    \n      :set TelegramQueue [ :toarray \"\" ];\
    \n    }\
    \n    :set Text (\$Text . [ \$UrlEncode (\"\\n\" . [ \$SymbolForNotificati\
    on \"alarm-clock\" ] . \\\
    \n      [ \$EscapeMD (\"This message was queued since \" . [ / system cloc\
    k get date ] . \\\
    \n      \" \" . [ / system clock get time ] . \" and may be obsolete.\") \
    \"hint\" ]) ]);\
    \n    :set (\$TelegramQueue->[ :len \$TelegramQueue ]) { chatid=\$ChatId; \
    tokenid=\$TokenId;\
    \n      parsemode=\$ParseMode; text=\$Text; silent=(\$Notification->\"sile\
    nt\") };\
    \n    :if ([ :len [ / system scheduler find where name=\"FlushTelegramQueu\
    e\" ] ] = 0) do={\
    \n      / system scheduler add name=FlushTelegramQueue interval=1m start-t\
    ime=startup \\\
    \n        on-event=\":global FlushTelegramQueue; \\\$FlushTelegramQueue;\"\
    ;\
    \n    }\
    \n  }\
    \n}\
    \n\
    \n# return UTF-8 symbol for unicode name\
    \n:set SymbolByUnicodeName do={\
    \n  :local Symbols {\
    \n    \"alarm-clock\"=\"\\E2\\8F\\B0\";\
    \n    \"calendar\"=\"\\F0\\9F\\93\\85\";\
    \n    \"cloud\"=\"\\E2\\98\\81\";\
    \n    \"cross-mark\"=\"\\E2\\9D\\8C\";\
    \n    \"fire\"=\"\\F0\\9F\\94\\A5\";\
    \n    \"floppy-disk\"=\"\\F0\\9F\\92\\BE\";\
    \n    \"high-voltage-sign\"=\"\\E2\\9A\\A1\";\
    \n    \"incoming-envelope\"=\"\\F0\\9F\\93\\A8\";\
    \n    \"link\"=\"\\F0\\9F\\94\\97\";\
    \n    \"lock-with-ink-pen\"=\"\\F0\\9F\\94\\8F\";\
    \n    \"mobile-phone\"=\"\\F0\\9F\\93\\B1\";\
    \n    \"pushpin\"=\"\\F0\\9F\\93\\8C\";\
    \n    \"scissors\"=\"\\E2\\9C\\82\";\
    \n    \"sparkles\"=\"\\E2\\9C\\A8\";\
    \n    \"up-arrow\"=\"\\E2\\AC\\86\";\
    \n    \"warning-sign\"=\"\\E2\\9A\\A0\";\
    \n    \"white-heavy-check-mark\"=\"\\E2\\9C\\85\"\
    \n  }\
    \n\
    \n  :return (\$Symbols->\$1);\
    \n}\
    \n\
    \n# return symbol for notification\
    \n:set SymbolForNotification do={\
    \n  :global NotificationsWithSymbols;\
    \n  :global SymbolByUnicodeName;\
    \n\
    \n  :if (\$NotificationsWithSymbols != true) do={\
    \n    :return \"\";\
    \n  }\
    \n  :local Return \"\";\
    \n  :foreach Symbol in=[ :toarray \$1 ] do={\
    \n    :set Return (\$Return . [ \$SymbolByUnicodeName \$Symbol ]);\
    \n  }\
    \n  :return (\$Return . \" \");\
    \n}\
    \n\
    \n# check if system time is sync\
    \n:set TimeIsSync do={\
    \n  :global LogPrintExit2;\
    \n\
    \n  :if ([ / system ntp client get enabled ] = true) do={\
    \n    :do {\
    \n      :if ([ / system ntp client get status ] = \"synchronized\") do={\
    \n        :return true;\
    \n      }\
    \n    } on-error={\
    \n      :if ([ :typeof [ / system ntp client get last-adjustment ] ] = \"t\
    ime\") do={\
    \n        :return true;\
    \n      }\
    \n    }\
    \n    :return false;\
    \n  }\
    \n\
    \n  :if ([ / ip cloud get ddns-enabled ] = true && [ / ip cloud get update\
    -time ] = true) do={\
    \n    :if ([ :typeof [ / ip cloud get public-address ] ] = \"ip\") do={\
    \n      :return true;\
    \n    }\
    \n    :return false;\
    \n  }\
    \n\
    \n  \$LogPrintExit2 debug \$0 (\"No time source configured! Returning grac\
    efully...\") false;\
    \n  :return true;\
    \n}\
    \n\
    \n# url encoding\
    \n:set UrlEncode do={\
    \n  :local Input [ :tostr \$1 ];\
    \n\
    \n  :if ([ :len \$Input ] = 0) do={\
    \n    :return \"\";\
    \n  }\
    \n\
    \n  :local Return \"\";\
    \n  :local Chars \"\\n\\r !\\\"#\\\$%&'()*+,:;<=>\\\?@[\\\\]^`{|}~\";\
    \n  :local Subs { \"%0A\"; \"%0D\"; \"%20\"; \"%21\"; \"%22\"; \"%23\"; \"\
    %24\"; \"%25\"; \"%26\"; \"%27\";\
    \n         \"%28\"; \"%29\"; \"%2A\"; \"%2B\"; \"%2C\"; \"%3A\"; \"%3B\"; \
    \"%3C\"; \"%3D\"; \"%3E\"; \"%3F\";\
    \n         \"%40\"; \"%5B\"; \"%5C\"; \"%5D\"; \"%5E\"; \"%60\"; \"%7B\"; \
    \"%7C\"; \"%7D\"; \"%7E\" };\
    \n\
    \n  :for I from=0 to=([ :len \$Input ] - 1) do={\
    \n    :local Char [ :pick \$Input \$I ];\
    \n    :local Replace [ :find \$Chars \$Char ];\
    \n\
    \n    :if ([ :typeof \$Replace ] = \"num\") do={\
    \n      :set Char (\$Subs->\$Replace);\
    \n    }\
    \n    :set Return (\$Return . \$Char);\
    \n  }\
    \n\
    \n  :return \$Return;\
    \n}\
    \n\
    \n# basic syntax validation\
    \n:set ValidateSyntax do={\
    \n  :local Code [ :tostr \$1 ];\
    \n\
    \n  :do {\
    \n    [ :parse (\":local Validate do={\\n\" . \$Code . \"\\n}\") ];\
    \n  } on-error={\
    \n    :return false;\
    \n  }\
    \n  :return true;\
    \n}\
    \n\
    \n# convert version string to numeric value\
    \n:set VersionToNum do={\
    \n  :local Input [ :tostr \$1 ];\
    \n  :local Multi 0x1000000;\
    \n  :local Return 0;\
    \n\
    \n  :global CharacterReplace;\
    \n\
    \n  :set Input [ \$CharacterReplace [ \$CharacterReplace [ \$CharacterRepl\
    ace \$Input \\\
    \n    \".\" \",\" ] \"beta\" \",beta,\" ] \"rc\" \",rc,\" ];\
    \n\
    \n  :foreach Value in=([ :toarray \$Input ], 0) do={\
    \n    :local Num [ :tonum \$Value ];\
    \n    :if (\$Multi = 0x100) do={\
    \n      :if ([ :typeof \$Num ] = \"num\") do={\
    \n        :set Return (\$Return + 0xff00);\
    \n        :set Multi (\$Multi / 0x100);\
    \n      } else={\
    \n        :if (\$Value = \"beta\") do={ :set Return (\$Return + 0x3f00); }\
    \n        :if (\$Value = \"rc\") do={ :set Return (\$Return + 0x7f00); }\
    \n      }\
    \n    }\
    \n    :if ([ :typeof \$Num ] = \"num\") do={ :set Return (\$Return + (\$Va\
    lue * \$Multi)); }\
    \n    :set Multi (\$Multi / 0x100);\
    \n  }\
    \n\
    \n  :return \$Return;\
    \n}\
    \n\
    \n# wait for default route to be reachable\
    \n:set WaitDefaultRouteReachable do={\
    \n  :global DefaultRouteIsReachable;\
    \n\
    \n  :while ([ \$DefaultRouteIsReachable ] = false) do={\
    \n    :delay 1s;\
    \n  }\
    \n}\
    \n\
    \n# wait for DNS to resolve\
    \n:set WaitDNSResolving do={\
    \n  :global DNSIsResolving;\
    \n\
    \n  :while ([ \$DNSIsResolving ] = false) do={\
    \n    :delay 1s;\
    \n  }\
    \n}\
    \n\
    \n# wait for file to be available\
    \n:set WaitForFile do={\
    \n  :local FileName [ :tostr \$1 ];\
    \n\
    \n  :global CleanFilePath;\
    \n\
    \n  :set FileName [ \$CleanFilePath \$FileName ];\
    \n  :local I 0;\
    \n\
    \n  :while ([ :len [ / file find where name=\$FileName ] ] = 0) do={\
    \n    :if (\$I > 20) do={\
    \n      :return false;\
    \n    }\
    \n    :delay 100ms;\
    \n    :set I (\$I + 1);\
    \n  }\
    \n  :return true;\
    \n}\
    \n\
    \n# wait to be fully connected (default route is reachable, time is sync, \
    DNS resolves)\
    \n:set WaitFullyConnected do={\
    \n  :global WaitDefaultRouteReachable;\
    \n  :global WaitDNSResolving;\
    \n  :global WaitTimeSync;\
    \n\
    \n  \$WaitDefaultRouteReachable;\
    \n  \$WaitTimeSync;\
    \n  \$WaitDNSResolving;\
    \n}\
    \n\
    \n# wait for time to become synced\
    \n:set WaitTimeSync do={\
    \n  :global LogPrintExit2;\
    \n  :global TimeIsSync;\
    \n\
    \n  :while ([ \$TimeIsSync ] = false) do={\
    \n    :if ([ :len [ / system script find where name=\"rotate-ntp\" ] ] > 0\
    \_&& \\\
    \n         ([ / system resource get uptime ] % (180 * 1000000000)) = 0s) d\
    o={\
    \n      :do {\
    \n        / system script run rotate-ntp;\
    \n      } on-error={\
    \n        \$LogPrintExit2 debug \$0 (\"Running rotate-ntp failed.\") false\
    ;\
    \n      }\
    \n    }\
    \n    :delay 1s;\
    \n  }\
    \n}\
    \n\
    \n# check for required RouterOS version\
    \n\$RequiredRouterOS \"global-functions\" \"6.47\";\
    \n\
    \n# signal we are ready\
    \n:set GlobalFunctionsReady true;\
    \n"
add dont-require-permissions=no name=email-backup owner=email-backup policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
    !rsc by RouterOS\
    \n# RouterOS script: email-backup\
    \n# Copyright (c) 2013-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# create and email backup and config file\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/email-backup.md\
    \n\
    \n:local 0 \"email-backup\";\
    \n:global GlobalFunctionsReady;\
    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
    \n\
    \n:global BackupPassword;\
    \n:global BackupRandomDelay;\
    \n:global BackupSendBinary;\
    \n:global BackupSendExport;\
    \n:global Domain;\
    \n:global Identity;\
    \n\
    \n:global CharacterReplace;\
    \n:global DeviceInfo;\
    \n:global LogPrintExit2;\
    \n:global MkDir;\
    \n:global RandomDelay;\
    \n:global ScriptFromTerminal;\
    \n:global SendEMail2;\
    \n:global SymbolForNotification;\
    \n:global WaitForFile;\
    \n:global WaitFullyConnected;\
    \n\
    \n:if (\$BackupSendBinary != true && \\\
    \n     \$BackupSendExport != true) do={\
    \n  \$LogPrintExit2 error \$0 (\"Configured to send neither backup nor con\
    fig export.\") true;\
    \n}\
    \n\
    \n\$WaitFullyConnected;\
    \n\
    \n:if ([ \$ScriptFromTerminal \$0 ] = false && \$BackupRandomDelay > 0) do\
    ={\
    \n  \$RandomDelay \$BackupRandomDelay;\
    \n}\
    \n\
    \n:if ([ \$MkDir \$0 ] = false) do={\
    \n  \$LogPrintExit2 error \$0 (\"Failed creating directory!\") true;\
    \n}\
    \n\
    \n# filename based on identity\
    \n:local FileName [ \$CharacterReplace (\$Identity . \".\" . \$Domain) \".\
    \" \"_\" ];\
    \n:local FilePath (\$0 . \"/\" . \$FileName);\
    \n:local BackupFile \"none\";\
    \n:local ConfigFile \"none\";\
    \n:local Attach [ :toarray \"\" ];\
    \n\
    \n# binary backup\
    \n:if (\$BackupSendBinary = true) do={\
    \n  / system backup save encryption=aes-sha256 name=\$FilePath password=\$\
    BackupPassword;\
    \n  \$WaitForFile (\$FilePath . \".backup\");\
    \n  :set BackupFile (\$FileName . \".backup\");\
    \n  :set Attach (\$Attach, (\$FilePath . \".backup\"));\
    \n}\
    \n\
    \n# create configuration export\
    \n:if (\$BackupSendExport = true) do={\
    \n  / export terse file=\$FilePath;\
    \n  \$WaitForFile (\$FilePath . \".rsc\");\
    \n  :set ConfigFile (\$FileName . \".rsc\");\
    \n  :set Attach (\$Attach, (\$FilePath . \".rsc\"));\
    \n}\
    \n\
    \n# send email with status and files\
    \n\$SendEMail2 ({ origin=\$0; \\\
    \n  subject=([ \$SymbolForNotification \"floppy-disk,incoming-envelope\" ]\
    \_. \\\
    \n    \"Backup & Config\"); \\\
    \n  message=(\"See attached files for backup and config export for \" . \\\
    \n    \$Identity . \".\\n\\n\" . \\\
    \n    [ \$DeviceInfo ] . \"\\n\\n\" . \\\
    \n    \"Backup file:    \" . \$BackupFile . \"\\n\" . \\\
    \n    \"Config file:    \" . \$ConfigFile); \\\
    \n  attach=\$Attach });\
    \n"
add dont-require-permissions=no name=log-forward owner=log-forward policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
    !rsc by RouterOS\
    \n# RouterOS script: log-forward\
    \n# Copyright (c) 2020-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# forward log messages via notification\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/log-forward.md\
    \n\
    \n:local 0 \"log-forward\";\
    \n:global GlobalFunctionsReady;\
    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
    \n\
    \n:global Identity;\
    \n:global LogForwardFilter;\
    \n:global LogForwardFilterMessage;\
    \n:global LogForwardLast;\
    \n:global LogForwardRateLimit;\
    \n:global NotificationsWithSymbols;\
    \n\
    \n:global EscapeForRegEx;\
    \n:global IfThenElse;\
    \n:global LogPrintExit2;\
    \n:global QuotedPrintable;\
    \n:global ScriptLock;\
    \n:global SendNotification2;\
    \n:global SymbolForNotification;\
    \n:global WaitFullyConnected;\
    \n\
    \n\$ScriptLock \$0;\
    \n\
    \n:if ([ :typeof \$LogForwardRateLimit ] = \"nothing\") do={\
    \n  :set LogForwardRateLimit 0;\
    \n}\
    \n\
    \n:if (\$LogForwardRateLimit > 30) do={\
    \n  :set LogForwardRateLimit (\$LogForwardRateLimit - 1);\
    \n  \$LogPrintExit2 info \$0 (\"Rate limit in action, not forwarding logs,\
    \_if any!\") true;\
    \n}\
    \n\
    \n\$WaitFullyConnected;\
    \n\
    \n:local Count 0;\
    \n:local Duplicates false;\
    \n:local Messages \"\";\
    \n:local MessageVal;\
    \n:local MessageDups [ :toarray \"\" ];\
    \n\
    \n:local LogForwardFilterLogForwarding (\"^\" . [ \$EscapeForRegEx (\"Erro\
    r sending e-mail <\" . \\\
    \n    [ \$QuotedPrintable (\"[\" . \$Identity . \"] \" . [ \$SymbolForNoti\
    fication \"warning-sign\" ] . \\\
    \n    \"Log Forwarding\") ] . \">:\") ]);\
    \n:foreach Message in=[ / log find where !(topics~\$LogForwardFilter) !(me\
    ssage=\"\") \\\
    \n    !(message~\$LogForwardFilterLogForwarding) !(message~\$LogForwardFil\
    terMessage) ] do={\
    \n  :set MessageVal [ / log get \$Message ];\
    \n\
    \n  :if (\$LogForwardLast = (\$MessageVal->\".id\")) do={\
    \n    :set Count 0;\
    \n    :set Duplicates false;\
    \n    :set Messages \"\";\
    \n    :set MessageDups [ :toarray \"\" ];\
    \n  } else={\
    \n    :local DupCount (\$MessageDups->(\$MessageVal->\"message\"));\
    \n    :if (\$DupCount < 3) do={\
    \n      :set Messages (\$Messages . \"\\n\" . [ \$IfThenElse (\$Notificati\
    onsWithSymbols = true) (\" \\E2\\97\\8F \") ] . \\\
    \n        \$MessageVal->\"time\" . \" \" . [ :tostr (\$MessageVal->\"topic\
    s\") ] . \" \" . \$MessageVal->\"message\");\
    \n    } else={\
    \n      :set Duplicates true;\
    \n    }\
    \n    :set (\$MessageDups->(\$MessageVal->\"message\")) (\$DupCount + 1);\
    \n    :set Count (\$Count + 1);\
    \n  }\
    \n}\
    \n\
    \n:if (\$Count > 0) do={\
    \n  \$SendNotification2 ({ origin=\$0; \\\
    \n    subject=([ \$SymbolForNotification \"warning-sign\" ] . \"Log Forwar\
    ding\"); \\\
    \n    message=(\"The log on \" . \$Identity . \" contains \" . [ \$IfThenE\
    lse (\$Count = 1) \\\
    \n      \"this message\" (\"these \" . \$Count . \" messages\") ] . \" aft\
    er \" . \\\
    \n      [ / system resource get uptime ] . \" uptime.\" . [ \$IfThenElse (\
    \$Duplicates = true) \\\
    \n      (\" Multi-repeated messages have been skipped.\") ] . \"\\n\" . \$\
    Messages) });\
    \n\
    \n  :set LogForwardRateLimit (\$LogForwardRateLimit + 10);\
    \n  :set LogForwardLast (\$MessageVal->\".id\");\
    \n} else={\
    \n  :if (\$LogForwardRateLimit > 0) do={\
    \n    :set LogForwardRateLimit (\$LogForwardRateLimit - 1);\
    \n  }\
    \n}\
    \n"
add dont-require-permissions=no name=netwatch-notify owner=netwatch-notify \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source="#!rsc by RouterOS\
    \n# RouterOS script: netwatch-notify\
    \n# Copyright (c) 2020-2021 Christian Hesse <mail@eworm.de>\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md\
    \n#\
    \n# monitor netwatch and send notifications\
    \n# https://git.eworm.de/cgit/routeros-scripts/about/doc/netwatch-notify.m\
    d\
    \n\
    \n:local 0 \"netwatch-notify\";\
    \n:global GlobalFunctionsReady;\
    \n:while (\$GlobalFunctionsReady != true) do={ :delay 500ms; }\
    \n\
    \n:global NetwatchNotify;\
    \n\
    \n:global DNSIsResolving;\
    \n:global IfThenElse;\
    \n:global LogPrintExit2;\
    \n:global ParseKeyValueStore;\
    \n:global SendNotification2;\
    \n:global SymbolForNotification;\
    \n:global ValidateSyntax;\
    \n\
    \n:if ([ :typeof \$NetwatchNotify ] = \"nothing\") do={\
    \n  :set NetwatchNotify [ :toarray \"\" ];\
    \n}\
    \n\
    \n:foreach Host in=[ / tool netwatch find where comment~\"^notify,\" disab\
    led=no ] do={\
    \n  :local HostVal [ / tool netwatch get \$Host ];\
    \n  :local HostInfo [ \$ParseKeyValueStore (\$HostVal->\"comment\") ];\
    \n  :local HostName (\$HostInfo->\"hostname\");\
    \n\
    \n  :local Metric { \"count\"=0; \"notified\"=false };\
    \n  :if ([ :typeof (\$NetwatchNotify->\$HostName) ] = \"array\") do={\
    \n    :set \$Metric (\$NetwatchNotify->\$HostName);\
    \n  }\
    \n\
    \n  :if ([ :typeof (\$HostInfo->\"resolve\") ] = \"str\" && [ \$DNSIsResol\
    ving ] = true) do={\
    \n    :do {\
    \n      :local Resolve [ :resolve (\$HostInfo->\"resolve\") ];\
    \n      :if (\$Resolve != \$HostVal->\"host\") do={\
    \n         \$LogPrintExit2 info \$0 (\"Name '\" . \$HostInfo->\"resolve\" \
    . [ \$IfThenElse (\$HostInfo->\"resolve\" != \\\
    \n           \$HostInfo->\"hostname\") (\"' for host '\" . \$HostInfo->\"h\
    ostname\") \"\" ] . \\\
    \n           \"' resolves to different address \" . \$Resolve . \", updati\
    ng.\") false;\
    \n        / tool netwatch set host=\$Resolve \$Host;\
    \n        :set (\$Metric->\"resolve-failed\") false;\
    \n      }\
    \n    } on-error={\
    \n      :if (\$Metric->\"resolve-failed\" != true) do={\
    \n        \$LogPrintExit2 warning \$0 (\"Resolving name '\" . \$HostInfo->\
    \"resolve\" . [ \$IfThenElse (\$HostInfo->\"resolve\" != \\\
    \n          \$HostInfo->\"hostname\") (\"' for host '\" . \$HostInfo->\"ho\
    stname\") \"\" ] . \"' failed.\") false;\
    \n        :set (\$Metric->\"resolve-failed\") true;\
    \n      }\
    \n    }\
    \n  }\
    \n\
    \n  :if (\$HostVal->\"status\" = \"up\") do={\
    \n    :local Count (\$Metric->\"count\");\
    \n    :if (\$Count > 0) do={\
    \n      \$LogPrintExit2 info \$0 (\"Host \" . \$HostName . \" (\" . \$Host\
    Val->\"host\" . \") is up.\") false;\
    \n      :set (\$Metric->\"count\") 0;\
    \n    }\
    \n    :if (\$Metric->\"notified\" = true) do={\
    \n      :local Message (\"Host \" . \$HostName . \" (\" . \$HostVal->\"hos\
    t\" . \") is up since \" . \$HostVal->\"since\" . \".\\n\" . \\\
    \n        \"It was down for \" . \$Count . \" checks since \" . (\$Metric-\
    >\"since\") . \".\");\
    \n      :if ([ :typeof (\$HostInfo->\"up-hook\") ] = \"str\") do={\
    \n        :if ([ \$ValidateSyntax (\$HostInfo->\"up-hook\") ] = true) do={\
    \n          \$LogPrintExit2 info \$0 (\"Running hook on host \" . \$HostNa\
    me . \" up: \" . (\$HostInfo->\"up-hook\")) false;\
    \n          :set Message (\$Message . \"\\n\\nRunning hook:\\n\" . \$HostI\
    nfo->\"up-hook\");\
    \n          [ :parse (\$HostInfo->\"up-hook\") ];\
    \n        } else={\
    \n          \$LogPrintExit2 warning \$0 (\"The up-hook for host \" . \$Hos\
    tName . \" failed syntax validation.\") false;\
    \n        }\
    \n      }\
    \n      \$SendNotification2 ({ origin=\$0; \\\
    \n        subject=([ \$SymbolForNotification \"white-heavy-check-mark\" ] \
    . \"Netwatch Notify: \" . \$HostName . \" up\"); \\\
    \n        message=\$Message });\
    \n    }\
    \n    :set (\$Metric->\"notified\") false;\
    \n    :set (\$Metric->\"parent\") (\$HostInfo->\"parent\");\
    \n    :set (\$Metric->\"since\");\
    \n  } else={\
    \n    :set (\$Metric->\"count\") (\$Metric->\"count\" + 1);\
    \n    :set (\$Metric->\"parent\") (\$HostInfo->\"parent\");\
    \n    :set (\$Metric->\"since\") (\$HostVal->\"since\");\
    \n    :local Count [ \$IfThenElse ([ :tonum (\$HostInfo->\"count\") ] > 0)\
    \_(\$HostInfo->\"count\") 5 ];\
    \n    :local Parent (\$HostInfo->\"parent\");\
    \n    :while ([ :len \$Parent ] > 0) do={\
    \n      :set Count (\$Count + 1);\
    \n      :set Parent (\$NetwatchNotify->\$Parent->\"parent\");\
    \n    }\
    \n    :set Parent (\$HostInfo->\"parent\");\
    \n    :local ParentNotified false;\
    \n    :while (\$ParentNotified = false && [ :len \$Parent ] > 0) do={\
    \n      :set ParentNotified [ \$IfThenElse ((\$NetwatchNotify->\$Parent->\
    \"notified\") = true) true false ];\
    \n      :if (\$ParentNotified = false) do={\
    \n        :set Parent (\$NetwatchNotify->\$Parent->\"parent\");\
    \n      }\
    \n    }\
    \n    \$LogPrintExit2 info \$0 (\"Host \" . \$HostName . \" (\" . \$HostVa\
    l->\"host\" . \") is down for \" . \\\
    \n      \$Metric->\"count\" . \" checks, \" . [ \$IfThenElse (\$ParentNoti\
    fied = false) [ \$IfThenElse \\\
    \n      (\$Metric->\"notified\" = true) (\"already notified.\") (\$Count -\
    \_\$Metric->\"count\" . \" to go.\") ] \\\
    \n      (\"parent host \" . \$Parent . \" is down.\") ]) false;\
    \n    :if (\$ParentNotified = false && \$Metric->\"count\" >= \$Count && \
    \$Metric->\"notified\" != true) do={\
    \n      :local Message (\"Host \" . \$HostName . \" (\" . \$HostVal->\"hos\
    t\" . \") is down since \" . \$HostVal->\"since\" . \".\");\
    \n      :if ([ :typeof (\$HostInfo->\"down-hook\") ] = \"str\") do={\
    \n        :if ([ \$ValidateSyntax (\$HostInfo->\"down-hook\") ] = true) do\
    ={\
    \n          \$LogPrintExit2 info \$0 (\"Running hook on host \" . \$HostNa\
    me . \" down: \" . (\$HostInfo->\"down-hook\")) false;\
    \n          :set Message (\$Message . \"\\n\\nRunning hook:\\n\" . \$HostI\
    nfo->\"down-hook\");\
    \n          [ :parse (\$HostInfo->\"down-hook\") ];\
    \n        } else={\
    \n          \$LogPrintExit2 warning \$0 (\"The down-hook for host \" . \$H\
    ostName . \" failed syntax validation.\") false;\
    \n        }\
    \n      }\
    \n      \$SendNotification2 ({ origin=\$0; \\\
    \n        subject=([ \$SymbolForNotification \"cross-mark\" ] . \"Netwatch\
    \_Notify: \" . \$HostName . \" down\"); \\\
    \n        message=\$Message });\
    \n      :set (\$Metric->\"notified\") true;\
    \n    }\
    \n  }\
    \n  :set (\$NetwatchNotify->\$HostName) {\
    \n    \"count\"=(\$Metric->\"count\");\
    \n    \"notified\"=(\$Metric->\"notified\");\
    \n    \"parent\"=(\$Metric->\"parent\");\
    \n    \"resolve-failed\"=(\$Metric->\"resolve-failed\");\
    \n    \"since\"=(\$Metric->\"since\") };\
    \n}\
    \n"
add dont-require-permissions=no name=pptppsh-on-up owner=pptppsh-on-up \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source="# !rsc by RouterOS\
    \n# RouterOS script: pptppsh-on-up\
    \n# Copyright (c) 2020 xxxxx <xxxxx@gmail.com>\
    \n#\
    \n#\
    \n\
    \n:local 0 \"pptppsh-on-up\";\
    \n:global LogPrintExit2;\
    \n:global PptpServerIfaceName;\
    \n:global PptpServerIp;\
    \n:local MyChain \"pihole-placeholder-chain\";\
    \n:local MyComment (\"dynamic, service=pptp, server=\" . \$PptpServerIface\
    Name);\
    \n:local PiHoleIp \"172.16.220.36\";\
    \n:local PiHoleNetwork \"172.16.220.0/24\";\
    \n:local IpAddress [ / ip address get [ find interface=\$PptpServerIfaceNa\
    me ] address ];\
    \n\
    \n:if ([ :len [ / system script job find where script=\"pptppsh-on-up\" ] \
    ] > 1) do={\
    \n  \$LogPrintExit2 error \$0 (\"on process, skip this one\") true;\
    \n}\
    \n\
    \n:while ([ :len [ / system script job find where script=\"pptppsh-on-down\
    \" ] ] > 0) do={\
    \n  :local d 100;;\
    \n  :delay (\$d . \"ms\");\
    \n}\
    \n\
    \n:set PptpServerIp \"0.0.0.0\";\
    \n\
    \n/ interface list member add list=\"LAN\" interface=\$PptpServerIfaceName\
    \_comment=\$MyComment;\
    \n/ ip route add dst-address=\$PiHoleNetwork distance=6 gateway=\"172.16.2\
    20.1\" comment=\$MyComment;\
    \n/ ip firewall address-list add address=\$PiHoleIp list=PiHole comment=\$\
    MyComment;\
    \n/ ip firewall address-list add address=\$PiHoleIp list=AcceptSrcAdd comm\
    ent=\$MyComment;\
    \n/ ip firewall address-list add address=\$PiHoleIp list=AcceptDstAdd comm\
    ent=\$MyComment;\
    \n/ ip firewall nat add chain=srcnat action=src-nat to-addresses=\$IpAddre\
    ss place-before=([ find ]->0) comment=\$MyComment out-interface=\$PptpServ\
    erIfaceName;\
    \n\
    \n/ ip firewall nat add action=dst-nat chain=dstnat comment=\$MyComment ds\
    t-address-list=!PiHole dst-port=53 in-interface-list=!WAN protocol=udp src\
    -address-list=!PiHole to-addresses=\$PiHoleIp to-ports=53;\
    \n/ ip firewall nat add action=dst-nat chain=dstnat comment=\$MyComment ds\
    t-address-list=!PiHole dst-port=53 in-interface-list=!WAN protocol=tcp src\
    -address-list=!PiHole to-addresses=\$PiHoleIp to-ports=53;\
    \n/ ip firewall nat add action=dst-nat chain=pre-hotspot comment=\$MyComme\
    nt dst-port=53 hotspot=auth protocol=udp to-addresses=\$PiHoleIp to-ports=\
    53;\
    \n/ ip firewall nat add action=dst-nat chain=pre-hotspot comment=\$MyComme\
    nt dst-port=53 hotspot=auth protocol=tcp to-addresses=\$PiHoleIp to-ports=\
    53;\
    \n\
    \n# / ip firewall mangle add action=accept chain=forward dst-address-list=\
    PiHole place-before=[ find where chain=\$MyChain ] comment=\$MyComment;\
    \n\$LogPrintExit2 info \$0 (\"completed\") true;\
    \n"
add dont-require-permissions=no name=pptppsh-on-down owner=pptppsh-on-down \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source="# !rsc by RouterOS\
    \n# RouterOS script: pptppsh-on-down\
    \n# Copyright (c) 2020 xxxxx <xxxxx@gmail.com>\
    \n#\
    \n#\
    \n\
    \n:local 0 \"pptppsh-on-down\";\
    \n:global LogPrintExit2;\
    \n:global PptpServerIfaceName;\
    \n:global PptpServerName;\
    \n:global PptpServerIp;\
    \n:global PshStatus;\
    \n:local MyComment (\"dynamic, service=pptp, server=\" . \$PptpServerIface\
    Name);\
    \n\
    \n:if ([ :len [ / system script job find where script=\"pptppsh-on-down\" \
    ] ] > 1) do={\
    \n  \$LogPrintExit2 error \$0 (\"on process, skip this one\") true;\
    \n}\
    \n\
    \n:local NewIp [ :tostr [ :resolve \$PptpServerName ] ];\
    \n:if (\$NewIp ~ \"^failure\") do={\
    \n  \$LogPrintExit2 error \$0 (\"Error while checking PPTP server. \" . \$\
    NewIp) false;\
    \n}\
    \n\
    \n:if (\$PptpServerIp = \$NewIp) do={\
    \n  \$LogPrintExit2 debug \$0 (\"Skip PPTP Server IP check\") false;\
    \n} else={\
    \n  / interface pptp-client set connect-to=\$NewIp [ find where name=\$Ppt\
    pServerIfaceName ];\
    \n  :set PptpServerIp \$NewIp;\
    \n  \$LogPrintExit2 debug \$0 (\"Renew \" . \$PptpServerIfaceName . \" IP \
    Address to: \" . \$NewIp) false;\
    \n}\
    \n\
    \n/ interface list member remove [ find where comment=\$MyComment ];\
    \n/ ip route remove [ find where comment=\$MyComment ];\
    \n/ ip firewall address-list remove [ find where comment=\$MyComment ];\
    \n/ ip firewall nat remove [ find where comment=\$MyComment ];\
    \n/ ip firewall mangle remove [ find where comment=\$MyComment ];\
    \n:delay 500ms;\
    \n\$LogPrintExit2 info \$0 (\"completed\") true;\
    \n"
add dont-require-permissions=no name=reset-owner owner=reset-owner policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
    foreach i in=[ / system script find where owner=\"admin\" ] do={\
    \n  / system script set \$i owner=[ / system script get \$i name ];\
    \n};\
    \n"
add dont-require-permissions=no name=restart-pptppsh owner=restart-pptppsh \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source=":global PptpServerIfaceName;\
    \n\
    \n/ interface set disabled=yes [ find where !disabled && name=\$PptpServer\
    IfaceName ];\
    \n#:delay 3s;\
    \n/ interface set disabled=no [ find where disabled && name=\$PptpServerIf\
    aceName ];\
    \n"
add dont-require-permissions=no name=nordvpn-ipsec owner=nordvpn-ipsec \
    policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon \
    source=":local MyComment \"ipsec mode-config\";\
    \n:if ([ / ip firewall nat print count-only where comment=\$MyComment && d\
    ynamic ] > 0) do={\
    \n  :local count 0;\
    \n  :local MyChain;\
    \n  :while (\$MyChain != \"ipsec-placeholder\") do={\
    \n    :set MyChain [ / ip firewall nat get ([ find ]->\$count) chain ];\
    \n    :set count (\$count +1);\
    \n  }\
    \n  :if ([ / ip firewall nat get ([ find ]->(\$count-2)) comment ] != \$My\
    Comment) do={\
    \n    # Route to NordVPN except GameConnection\
    \n    / ip firewall nat set [ find comment=\$MyComment && dynamic ] src-ad\
    dress-list=NordVPNClient dst-address-list=!NordVPNClient connection-mark=!Game\
    Connection;\
    \n    / ip firewall nat move [ find comment=\$MyComment && dynamic ] desti\
    nation=[ find where chain=\$MyChain ];\
    \n    / ip firewall nat set [ find where comment~\"NordVPN\" && chain=srcn\
    at ] disable=no to-addresses=([ / ip firewall nat get [ find comment=\$MyC\
    omment && dynamic ] to-addresses ]);\
    \n    / ip firewall mangle set disable=no [ find where comment~\"NordVPN\"\
    \_&& disabled ];\
    \n    / ip firewall address-list set disable=no [ find where list~\"NordVP\
    N\" && disabled ];\
    \n  }\
    \n} else={\
    \n  / ip firewall address-list set disable=yes [ find where list~\"NordVPN\
    \" && !disabled ];\
    \n  / ip firewall mangle set disable=yes [ find where comment~\"NordVPN\" \
    && !disabled ];\
    \n  / ip firewall nat set disable=yes [ find where comment~\"NordVPN\" && \
    !disabled ];\
    \n}\
    \n"
add dont-require-permissions=no name=myPPPoE-on-down owner=\
    myPPPoE-on-down policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
    global PptpServerIfaceName;\
    \n# / interface set disabled=yes [ find where !disabled && name=\$PptpServ\
    erIfaceName ];\
    \n\
    \n:global PPPoEIface;\
    \n/ ip route remove [ find where comment~\$PPPoEIface ];\
    \n\
    \n/ ip ipsec peer disable [ find where !disabled ];\
    \n/ system script run nordvpn-ipsec;\
    \n\
    \n:global PshStatus;\
    \n:set \$PshStatus 0;\
    \n"
add dont-require-permissions=no name=check-PPPoE-ip owner=\
    check-PPPoE-ip policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
    \_!rsc\
    \n# RouterOS script: check-PPPoE-ip\
    \n# Copyright (c) 2020 xxxxx <xxxxx@gmail.com>\
    \n#\
    \n# Force PPPoE to get IP Public\
    \n\
    \n:local 0 \"check-PPPoE-ip\";\
    \n:global LogPrintExit2;\
    \n:global PPPoEIface;\
    \n:global PptpServerName;\
    \n:global PptpServerIfaceName;\
    \n:local MyComment (\"dynamic, load-balance, \" . \$PPPoEIface);\
    \n\
    \n/ ip ipsec peer disable [ find where !disabled ];\
    \n/ interface set disabled=yes [ find where !disabled && name=\$PptpServer\
    IfaceName ];\
    \n\
    \n:local count 0;\
    \n:while ([ / interface pppoe-client print count-only where name=\$PPPo\
    EIface ] = 0) do={\
    \n  :if (\$count = 30) do={\
    \n    \$LogPrintExit2 error \$0 (\"Unable to find PPP Interface \" . \$Ind\
    iHomeIface .\" as PPPoE Client\") true;\
    \n  }\
    \n  :delay 1s;\
    \n  :set count (\$count +1);\
    \n};\
    \n\
    \n:set count 0;\
    \n:while ([ / ip address print count-only where interface=\$PPPoEIface \
    ] = 0) do={\
    \n  :if (\$count = 30) do={\
    \n    \$LogPrintExit2 error \$0 (\$PPPoEIface .\" is not connected\") t\
    rue;\
    \n  }\
    \n  :delay 1s;\
    \n  :set count (\$count +1);\
    \n};\
    \n\
    \n:global PPPoEIpPref;\
    \n\
    \n\
    \n:local IpAddress;\
    \n:local NetworkAddress;\
    \n:local GatewayIp;\
    \n:local CurrentIp;\
    \n:local PPPoEIp;\
    \n:local CurrentPref;\
    \n:local VarType;\
    \n\
    \n:foreach i in=[ / ip address find where interface=\$PPPoEIface ] do={\
    \n   :set IpAddress [ / ip address get \$i address ];\
    \n   :set NetworkAddress [ / ip address get \$i network ];\
    \n   :set CurrentIp [ :pick \$IpAddress 0 [ :find \$IpAddress \"/\" ] ];\
    \n   :if (\$CurrentIp != \$NetworkAddress) do={\
    \n      :set GatewayIp \$NetworkAddress;\
    \n      :set PPPoEIp \$CurrentIp;\
    \n      :set CurrentPref [ :pick \$CurrentIp 0 [ :find \$CurrentIp \".\" ]\
    \_];\
    \n      :set VarType [ :typeof [ :find \$PPPoEIpPref \$CurrentPref ] ];\
    \n   }\
    \n}\
    \n\
    \nif (\$VarType = \"num\" and \$CurrentPref != \"10\") do={\
    \n  / ip firewall nat set to-addresses=\$PPPoEIp [ find where comment~\
    \$PPPoEIface ];\
    \n  / interface set disabled=no [ find where disabled && name=\$PptpServer\
    IfaceName ];\
    \n  / ip cloud force-update;\
    \n  / ip ipsec policy set dst-address=\$PPPoEIp [ find comment=\"PPP\
    oE IP\" ];\
    \n  / ip ipsec peer enable [ find where disabled ];\
    \n  / ip route add distance=10 dst-address=[ :resolve \$PptpServerName ] g\
    ateway=\$GatewayIp scope=10 comment=\$MyComment;\
    \n  / ip route add distance=10 dst-address=[ :resolve [ / ip ipsec peer ge\
    t NordVPN address ] ] gateway=\$GatewayIp scope=10 comment=\$MyComment;\
    \n  / ip firewall connection remove [ find where src-address~\"192.168.219\
    .243\" ];\
    \n  \$LogPrintExit2 info \$0 (\"Completed. \" . \$PPPoEIface . \" is no\
    w connected on prefered IP: \" . \$PPPoEIp) true;\
    \n}\
    \n\
    \n\$LogPrintExit2 info \$0 (\$PPPoEIface . \" is not connected on prefe\
    red IP: \" . \$PPPoEIp) false;\
    \n\
    \n/ interface disable [ find where name=\$PPPoEIface ];\
    \n:delay 1s;\
    \n/ interface enable [ find where name=\$PPPoEIface ];\
    \n"
add dont-require-permissions=no name=pihole-check owner=pihole-check policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="#\
    \_!rsc\
    \n# RouterOS script: pihole-check\
    \n# Copyright (c) 2020 xxxxx <xxxxx@gmail.com>\
    \n#\
    \n# Check PiHole for dynamically change DNS\
    \n\
    \n:local 0 \"pihole-check\";\
    \n:local Server \"172.16.220.36\";\
    \n:local Domain \"google.com\";\
    \n:global LogPrintExit2;\
    \n\
    \n:do {\
    \n  :put [ :resolve \$Domain server \$Server ];\
    \n  / ip firewall nat set [ find where action=dst-nat && to-addresses=\$Se\
    rver && disabled ] disabled=no;\
    \n} on-error={\
    \n  \$LogPrintExit2 error \$0 (\"Unable to resolve \" . \$Domain .\" via \
    \" . \$Server ) false;\
    \n  / ip firewall nat set [ find where action=dst-nat && to-addresses=\$Se\
    rver && !disabled ] disabled=yes;\
    \n};\
    \n"
add dont-require-permissions=no name=my-function owner=my-function policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
    global NordVpnStart;\
    \n\
    \n:set NordVpnStart do={\
    \n  :local Peer [ :tostr \$1 ];\
    \n\
    \n  :local NewPeer;\
    \n  :global LogPrintExit2;\
    \n  :global SymbolForNotification;\
    \n  :global SendTelegram;\
    \n\
    \n\
    \n  :local CurrentPeer [ /ip ipsec peer get [ find name=NordVPN ] address \
    ];\
    \n  \$LogPrintExit2 info \$0 (\"NordVPN current peer: \" . \$CurrentPeer) \
    false;\
    \n  :local CurrentSrcAddress \"10.6.\";\
    \n  :do {\
    \n    :set CurrentSrcAddress [ / ip ipsec policy get [ find peer=NordVPN ]\
    \_src-address ];\
    \n    :set CurrentSrcAddress [ :pick \$CurrentSrcAddress 0 [ :find \$Curre\
    ntSrcAddress \"/\" ] ];\
    \n  } on-error={\
    \n    \$LogPrintExit2 info \$0 (\"NordVPN was disconnected\") false;\
    \n  }\
    \n\
    \n\
    \n  :if ([ :len \$Peer ] = 0) do={\
    \n    # ApiCountry is used to select a country, if it is empty then the co\
    untry will be selected automatically\
    \n    # https://api.nordvpn.com/v1/servers/countries\
    \n    :local ApiCountry 195\
    \n\
    \n    # ApiGroup is used to select server type, if it is empty then will b\
    e selected automatically\
    \n    # https://api.nordvpn.com/v1/servers/groups\
    \n    :local ApiGroup 11\
    \n\
    \n    # ApiMaxLoad is used to define the maximum acceptable load of the cu\
    rrent server, after exceeding this value the server will be changed\
    \n    :local ApiMaxLoad 20\
    \n\
    \n    :if (([:typeof \$ApiCountry] = \"num\" || [:len \$ApiCountry] = 0) &\
    & ([:typeof \$ApiGroup] = \"num\" || [:len \$ApiGroup] = 0) && ([:typeof \
    \$ApiMaxLoad] = \"num\" || [:len \$ApiMaxLoad] = 0)) do={\
    \n      :local CurrentLoad ([/tool fetch url=(\"https://api.nordvpn.com/se\
    rver/stats/\$CurrentPeer\") output=user as-value ]->\"data\");\
    \n      :set CurrentLoad [:pick [:pick \$CurrentLoad [:find \$CurrentLoad \
    \"percent\"] [:find \$CurrentLoad \"}\"]] 9 99];\
    \n      :if (\$CurrentLoad > \$ApiMaxLoad) do={\
    \n        :local RecPeer ([/tool fetch url=(\"https://api.nordvpn.com/v1/s\
    ervers/recommendations\\\?filters[servers_groups]=\$ApiGroup&filters[count\
    ry_id]=\$ApiCountry&filters[servers_technologies][identifier]=ikev2&limit=\
    1\") output=user as-value ]->\"data\");\
    \n        :if (\$RecPeer = \"[]\") do={\
    \n          \$LogPrintExit2 info \$0 (\"server not found for the current c\
    onfiguration\") true;\
    \n        } else={\
    \n          :local NewLoad [:pick [:pick \$RecPeer [:find \$RecPeer \"nord\
    vpn.com\"] [:find \$RecPeer \",\\\"status\"]] 20 99];\
    \n          :set RecPeer [:pick [:pick \$RecPeer [:find \$RecPeer \"hostna\
    me\"] [:find \$RecPeer \"\\\",\\\"load\"]] 11 99];\
    \n          :if ((\$CurrentPeer != \$RecPeer) && (\$CurrentLoad > \$NewLoa\
    d)) do={\
    \n\t\t\t:set NewPeer \$RecPeer;\
    \n          }\
    \n        }\
    \n      }\
    \n    } else={\
    \n      \$LogPrintExit2 error \$0 (\"variables must be numbers\") true;\
    \n    }\
    \n  } else={\
    \n    :if ([:typeof [:find \$Peer \".nordvpn.com\"]] = \"nil\") do={\
    \n      \$LogPrintExit2 error \$0 (\"Invalid NordVPN peer: \" . \$Peer) tr\
    ue;\
    \n    }\
    \n    :do {\
    \n      :resolve \$Peer;\
    \n    } on-error={\
    \n      \$LogPrintExit2 error \$0 (\"Invalid NordVPN peer: \" . \$Peer) tr\
    ue;\
    \n    }\
    \n    :set NewPeer \$Peer;\
    \n  }\
    \n  / ip ipsec active-peers remove [ find id=\$CurrentPeer ];\
    \n  # / ip ipsec peer set [ find name=NordVPN ] disabled=yes;\
    \n  / ip firewall connection remove [ find reply-dst-address~\"^\$CurrentS\
    rcAddress\" ];\
    \n  :if ((\$CurrentPeer != \$NewPeer) && ([ :len \$NewPeer ] > 0)) do={\
    \n    \$LogPrintExit2 info \$0 (\"NordVPN new peer: \" . \$NewPeer) false;\
    \n    / ip ipsec peer set [ find name=NordVPN ] address=\$NewPeer;\
    \n    \$SendTelegram ([ \$SymbolForNotification \"white-heavy-check-mark\"\
    \_] . \"NordVPN peer changed\") (\"from: \" . \$CurrentPeer . \" to: \" . \
    \$NewPeer);\
    \n  }\
    \n  # / ip ipsec peer set [ find name=NordVPN ] disabled=no;\
    \n}\
    \n"
/tool e-mail
set address=smtp.gmail.com from="Mikrotik Router" port=587 start-tls=yes \
    user=xxxxx@gmail.com
/tool mac-server
set allowed-interface-list=LAN
/tool mac-server mac-winbox
set allowed-interface-list=LAN
/tool netwatch
add disabled=yes down-script="/ sys sch add name=logf" host=192.168.234.5
add comment="notify, hostname=api.nordvpn.com, down-hook=:global NordVpnStart;\
    \_\$NordVpnStart;" disabled=yes host=104.17.50.74
add comment="notify, count=1, hostname=api.nordvpn.com, down-hook=:global Nord\
    VpnStart; \$NordVpnStart;" host=104.18.19.110
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Fri May 21, 2021 8:12 pm

I can't see anything unusual regarding IPsec there.

The action=none policy preventing the packets from the router to the LAN clients from being diverted into the tunnel (which is no workaround, it's merely how IPsec works) permits PMTUD to work for packets sent by the client via the IPsec tunnel. But if the MTU reported at the PPPoE interface is wrong, too large packets get dropped silently rather than aloud (i.e. with an ICMP "this doesn't fit, send at max xyz bytes" message). So this is one possible reason. Another possible reason is that the PMTUD fails in the opposite direction, when the remote server sends a packet too large to fit, and the ICMP warning doesn't reach it.

So it needs debugging to find out which of the cases you encounter. For that, sniffing at the LAN interface is a good start, you can see how large packets the client is sending and how large packets arrive from the remote end. If you receive only packets smaller than, say, 500 bytes from any remote HTTPS server, it is clearly an issue with PMTUD in the server->client direction, as the certificates alone normally don't fit to a single 1500-byte packet so multiple packets maxing out the MTU are sent. If you can see the client hammering the server with 1500-byte packets, it is clear that these don't get through (but for usual web browsing, the client rarely sends such large packets, unless it authenticates itself using a certificate too).

For the above you even don't need Wireshark, /tool sniffer quick port=443 interface=bridge is enough if you make the command line window wide enough to show you the packet size column.

You can also make the action=change-mss rule selective per direction, i.e. only change the MSS of the packets sent by the client (tcp-flags=syn,!ack) or only change the one of the packets sent by the server (tcp-flags=syn,ack). This is another method to find out which direction is problematic.

Purely theoretically, if the MTU was smaller at your bridge than at the PPPoE interface, the ICMP notification about that might not reach the remote server because the Mikrotik would send it from an address not NATed to the one matched by the policy. But I say purely theoretically because your configuration doesn't suggest anything like that.
 
shogunx
just joined
Posts: 18
Joined: Sat Aug 22, 2020 9:23 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Feb 06, 2022 3:47 am

Apologies for resurrecting an old thread, but I wanted to ask if anyone has had any issues with this fix/workaround suddenly no longer working? I have had my hEX router working with surfshark fairly smoothly for months, then suddenly I started having issues with pages loading which indicated MTU issues were back. Nothing had changed in my setup - I still have firewall rules in place to make sure ICMP can get through for PMTU discover, but the only way I was able to fix it was putting in the mangle rule to set the MTU under 1398 (and actually I have reduced it even further since the connection is still somewhat flaky - speedtest.net hits the max link capacity every time but youtube vids and teams calls get all stuttery for some reason). I first tried setting the clamp-to-pmtu setting but that didn't work, which makes me think PMTU discovery is not working again for some reason.

I was running 6.47 firmware when the issues popped up. I have upgraded to 7.1 and that hasn't helped. I tried calling my ISP but their tech support is useless. So I just wanted to put the call out to see if anyone else has had similar problems, or if this is just some issue with my own setup...
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Feb 06, 2022 10:59 am

The PMTUD must work both ways, i.e. not only the client (your PC) must be able to receive the ICMP "fragmentation needed" messages from your router (which is the purpose of the action=none policy), but also the server must be able to receive it from the VPN gateway router, as the MTU bottleneck is the encryption between the two routers (the encrypted payload packet augmented with the IPsec overhead exceeds the MTU).

And if the issue is between the VPN gateway and the remote server, you have no choice but to use the action=change-mss rule to lower the MSS the client originally advertises in the SYN packet it sends to the server.
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Feb 06, 2022 1:42 pm

Using IKEv2 and WireGuard side by side and I use this line for returning traffic besides the above written:
add action=change-mss chain=forward comment="WireGuard & IKEv2 Sync" ipsec-policy=in,none log-prefix=MSS new-mss=clamp-to-pmtu passthrough=yes protocol=tcp tcp-flags=syn
 
shogunx
just joined
Posts: 18
Joined: Sat Aug 22, 2020 9:23 am

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Feb 06, 2022 11:36 pm

The PMTUD must work both ways, i.e. not only the client (your PC) must be able to receive the ICMP "fragmentation needed" messages from your router (which is the purpose of the action=none policy), but also the server must be able to receive it from the VPN gateway router, as the MTU bottleneck is the encryption between the two routers (the encrypted payload packet augmented with the IPsec overhead exceeds the MTU).

And if the issue is between the VPN gateway and the remote server, you have no choice but to use the action=change-mss rule to lower the MSS the client originally advertises in the SYN packet it sends to the server.

Sure, I get that PMTUD needs to work bidirectionally. I'm just wondering why it suddenly stopped working. Do I need to explicitly allow outbound ICMP or something from the router? I noticed there's no rules in the output chain, but there never has been so I assume the default policy for output is allow. Any suggestions on what I can do to figure out what exactly is being blocked and where?
 
sindy
Forum Guru
Forum Guru
Posts: 10206
Joined: Mon Dec 04, 2017 9:19 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Feb 06, 2022 11:44 pm

You would have to disable the change-mss rule for the server->client direction, and sniff on the PC/TV facing interface to see whether you can see the following:
...
large TCP packet (1514 bytes inc. Ethernet headers) from client IP to remote server IP
ICMP packet from Mikrotik IP to client IP
a bit smaller TCP packet from client IP to remote server IP
...
If you can see this exchange, or if you can't see it but nevertheless it works although only the client->server change-mss rule remains active, it means that the problem popped up at the VPN provider end, so it's neither your fault nor can you do anything else than using the change-mss rule.
 
roxanaschram
just joined
Posts: 18
Joined: Sat Oct 10, 2020 7:59 am
Location: PR

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Sun Mar 13, 2022 1:57 am

Apologies for resurrecting an old thread, but I wanted to ask if anyone has had any issues with this fix/workaround suddenly no longer working? I have had my hEX router working with surfshark fairly smoothly for months, then suddenly I started having issues with pages loading which indicated MTU issues were back. Nothing had changed in my setup - I still have firewall rules in place to make sure ICMP can get through for PMTU discover, but the only way I was able to fix it was putting in the mangle rule to set the MTU under 1398 (and actually I have reduced it even further since the connection is still somewhat flaky - speedtest.net hits the max link capacity every time but youtube vids and teams calls get all stuttery for some reason). I first tried setting the clamp-to-pmtu setting but that didn't work, which makes me think PMTU discovery is not working again for some reason.

I was running 6.47 firmware when the issues popped up. I have upgraded to 7.1 and that hasn't helped. I tried calling my ISP but their tech support is useless. So I just wanted to put the call out to see if anyone else has had similar problems, or if this is just some issue with my own setup...
I'm in the same boat. I factory reset the router and started over and still no luck. They only servers of theirs I can find that still work are the Frankfurt servers. I just got out of chat and they are blaming the router basically. Mine worked flawlessly until one day it stopped. No changes made prior to. You may want to reach out to them to let them know you also are having the same issues.
 
nin
newbie
Posts: 32
Joined: Sat Feb 20, 2010 9:02 pm

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Mon Mar 14, 2022 7:09 pm

Using IKEv2 and WireGuard side by side and I use this line for returning traffic besides the above written:
May i ask if that means you use ike and wg with different vpn providers side by side?
 
msatter
Forum Guru
Forum Guru
Topic Author
Posts: 2912
Joined: Tue Feb 18, 2014 12:56 am
Location: Netherlands / Nīderlande

Re: MTU troubles using IKEv2 providers like NordVPN [work around]

Mon Mar 14, 2022 7:21 pm

Yes, different and same VPN providers. To use WG you need to have v7.x installed.

Who is online

Users browsing this forum: armandfumal, n0rbl, yonutm and 113 guests