Page 1 of 1

Local Array initialization bug?

Posted: Fri Aug 30, 2019 1:28 am
by lapsio
I made following script:
:if ([:len [/system script job find where script=dnsreload]] = 1) do={
    :local dyn [/ip firewall address-list find where dynamic=yes disabled=no]
    :local dynuniq 1
    :local baddns 1
    :local baddnsn 1
    :put ("a".$dynuniq)
    :put $baddns
    :put $baddnsn
    :set dynuniq ({})
    :set baddns ({})
    :set baddnsn ({})
    :put ("b".$dynuniq)
    :put $baddns
    :put $baddnsn

    :foreach counter=d in=$dyn do={
        :local lst [/ip firewall address-list get $d comment]
        :local dup false
        :foreach dd in=$dynuniq do={
            :if ($dd = $lst) do={
                :set dup true
        :if ($dup = false) do={
            :local dynlen [:len $dynuniq]
            set ($dynuniq->$dynlen) $lst
    :local dnssrv [/ip dns get servers]
    :do {
        :put ("DNS condition test... ".$dnssrv." :: ".[:resolve server=$dnssrv])
        :put "Passed"

        :put $baddns
        :put $baddnsn

        :foreach counter=d in=$dynuniq do={
            :do {
                :put $baddns
                :put $baddnsn
                :local caddr [:resolve $d server=$dnssrv]
                :local addrlst [/ip firewall address-list find where comment=$d disabled=no]
                :local found false
                :foreach counter=dd in=$addrlst do={
                    :if ([/ip firewall address-list get $dd address] = $caddr) do={
                        :set found true
#                        :put ("Match : ".$d." ".$caddr)
                :local rrlst [/ip firewall address-list find where address=$d list=rrDNS dynamic=no disabled=no]
                :if ([:len $rrlst] > 0) do={
                    :set found true
                    :put ("Ignoring mismatch on rrDNS domain: ".$d)
                    /log info message=("Ignoring mismatch on rrDNS domain: ".$d)
                :if ($found = false && [:len $addrlst] > 0) do={
                    :put ("DNS mismatch : ".$d." ".$caddr)
                    /ip firewall address-list print where comment=$d
                    /log info message=("DNS mismatch on domain ".$d)
                    :local cbaddns [/ip firewall address-list find where address=$d dynamic=no disabled=no]
                    :foreach counter=cbd in=$cbaddns do={
                        :local badlen [:len $baddns]
                        :set ($baddns->$badlen) $cbd
                    :local badnlen [:len $baddnsn]
                    :set ($baddnsn->$badnlen) $d
                } else={
                    :if ([:len $addrlst] = 0) do={
                        :put ("Cache miss on domain ".$d)
                        /log info message=("DNS cache not populated yet. Could not verify ".$d)
            } on-error={
                :if ($d != "") do={
                    :put ("Cannot resolve domain : ".$d)
                    :do {
                        :put ("Ensuring DNS condition... ".$dnssrv." :: ".[:resolve server=$dnssrv])
                        :put "DNS functional. Domain still unreachable"
                        /log warning message=("DNS domain unreachable: '".$d."'")
                    } on-error={
                        :put "DNS unavailable"
                        /log error message="DNS server became unavailable"
        :if ([:len $baddns] > 0) do={
            :put ("Mismatched: ".$baddnsn)
            /log info message=("Mismatched domains found: ".$baddnsn)
            /tool e-mail send to="" subject="DNS CACHE STALE - FORCE FLUSH" body=("Mismatch on domain: '".$baddnsn."'.  Forcing cache flush...")
            /ip firewall address-list disable $baddns
            /ip dns cache flush
            :delay delay-time=100ms
            /ip firewall address-list enable $baddns
            :set $baddns ({})
            :set $baddnsn ({})
            :set $dynuniq ({})
            :delay delay-time=10s
        } else={
            :put "Clean exit"
            /log info message="DNS reload clean exit"
    } on-error={
        :put ("DNS check failed - aborting")
        /log error message="DNS server unreachable. Integrity check aborted"
To regularly verify integrity of router DNS cache with DNS server (I have set up relatively high MikroTik DNS cache lifetime because I use lots of rules based on DNS so when DNS server is down and it would clear all dynamic address-lists then it would realistically stop entire network. That's why those dynamic address-lists are really big deal to me). So this script makes sure to flush DNS cache if it becomes obsolete but only if DNS server is actually functioning.

The problem is that I noticed really undeterministic behaviior of this script. That's why I added printing arrays. And each N-th subsequent execution of script results in output like this:
(transcript for not logged-in users:)
[lapsio@ACSWAG] /system script> run dnsreload      

DNS condition test... ::
What's going on here? It doesn't make any sense. $dynuniq array is initialized from verry beginning even though I'm clearly setting it to with empty array.

If I use some different way of empty array initialization like [:toarray ""] then iit works fine but it's super lame to initialiize empty array like this and I don't want to do that.

Re: Local Array initialization bug?  [SOLVED]

Posted: Fri Aug 30, 2019 10:31 pm
by eworm
According to wiki the "lame" solution is the correct one. ... mpty_array