Skip to content

MikroTik (RouterOS 7)

Requires the feed to be enabled. A script fetches the feed into the address list intrudect-block. RAW table rules drop matching traffic before connection tracking.

Script and scheduler

Replace https://WEB-UI/fw/feed/TOKEN with the feed address from Site > Firewall integration > Feed and paste into the router terminal. Runs every minute.

/system script remove [find name=intrudect-blocklist]
/system script add name=intrudect-blocklist policy=read,write,test,ftp source={
:local url "https://WEB-UI/fw/feed/TOKEN"
:local list "intrudect-block"
:local tag "intrudect"
:global intrudectFwRev
:global intrudectFwRuns
# Re-apply an unchanged list once an hour, so entries removed by hand come back.
:if ([:typeof $intrudectFwRuns] != "num") do={ :set intrudectFwRuns 0 }
:set intrudectFwRuns ($intrudectFwRuns + 1)
:if ($intrudectFwRuns >= 60) do={
  :set intrudectFwRuns 0
  :set intrudectFwRev ""
}
:local meta ""
:do {
  :set meta ([/tool fetch url=($url . "?meta=1") output=user as-value]->"data")
} on-error={ :log warning "intrudect: block list meta fetch failed" }
:local revPos [:find $meta "rev="]
:local partsPos [:find $meta " parts="]
:local entriesPos [:find $meta " entries="]
:if ([:typeof $revPos] = "num" && [:typeof $partsPos] = "num" && [:typeof $entriesPos] = "num") do={
  :local rev [:pick $meta ($revPos + 4) $partsPos]
  :local parts [:tonum [:pick $meta ($partsPos + 7) $entriesPos]]
  :if ($rev != $intrudectFwRev) do={
    :local want [:toarray ""]
    :local ok true
    :for i from=1 to=$parts do={
      :if ($ok) do={
        :local data ""
        :do {
          :set data ([/tool fetch url=($url . "?part=" . $i . "&rev=" . $rev) output=user as-value]->"data")
        } on-error={ :set ok false }
        :local prev -1
        :local len [:len $data]
        :while ($ok && $prev < ($len - 1)) do={
          :local end [:find $data "\n" $prev]
          :if ([:typeof $end] != "num") do={ :set end $len }
          :local line [:pick $data ($prev + 1) $end]
          :if ([:typeof [:toip $line]] = "ip" || [:typeof [:toip6 $line]] = "ip6") do={
            :set ($want->$line) "1"
          }
          :set prev $end
        }
      }
    }
    :if ($ok) do={
      :local have [:toarray ""]
      :foreach id in=[/ip firewall address-list find where list=$list comment=$tag] do={
        :local addr [/ip firewall address-list get $id address]
        :if ([:typeof ($want->$addr)] = "str") do={ :set ($have->$addr) "1" } else={ /ip firewall address-list remove $id }
      }
      :foreach id in=[/ipv6 firewall address-list find where list=$list comment=$tag] do={
        :local addr [/ipv6 firewall address-list get $id address]
        :local slash [:find $addr "/128"]
        :if ([:typeof $slash] = "num") do={ :set addr [:pick $addr 0 $slash] }
        :if ([:typeof ($want->$addr)] = "str") do={ :set ($have->$addr) "1" } else={ /ipv6 firewall address-list remove $id }
      }
      :foreach addr,v in=$want do={
        :if ([:typeof ($have->$addr)] != "str") do={
          :if ([:typeof [:toip $addr]] = "ip") do={
            :do { /ip firewall address-list add list=$list address=$addr comment=$tag } on-error={}
          } else={
            :do { /ipv6 firewall address-list add list=$list address=$addr comment=$tag } on-error={}
          }
        }
      }
      :set intrudectFwRev $rev
      :log info ("intrudect: block list " . $rev . " applied")
    } else={
      :log warning "intrudect: block list changed or failed during fetch, retrying next run"
    }
  }
} else={
  :log warning "intrudect: block list not available"
}
}
/system scheduler remove [find name=intrudect-blocklist]
/system scheduler add name=intrudect-blocklist interval=1m start-time=startup policy=read,write,test,ftp on-event="/system script run intrudect-blocklist"

The script:

  • fetches ?meta=1 and stops if the list revision is unchanged (re-applies once an hour);
  • fetches the list in parts of up to 60 KB into memory, no flash writes;
  • accepts only valid IPv4/IPv6 lines, never executes downloaded content;
  • updates the list only when all parts arrived; on failure the last list stays;
  • manages only entries with comment intrudect; manual entries are kept.

Warning

/tool fetch does not verify the certificate by default. Import the web UI CA and add check-certificate=yes to both /tool fetch calls.

Drop rules

/ip firewall raw
add chain=prerouting action=drop src-address-list=intrudect-block comment="Intrudect: from blocked"
add chain=prerouting action=drop dst-address-list=intrudect-block comment="Intrudect: to blocked"
add chain=output action=drop dst-address-list=intrudect-block comment="Intrudect: router to blocked"
/ipv6 firewall raw
add chain=prerouting action=drop src-address-list=intrudect-block comment="Intrudect: from blocked"
add chain=prerouting action=drop dst-address-list=intrudect-block comment="Intrudect: to blocked"
add chain=output action=drop dst-address-list=intrudect-block comment="Intrudect: router to blocked"
Rule Drops
prerouting, source traffic from a blocked address to or through the router
prerouting, destination traffic from your hosts to a blocked address (IOC, TOR, signature blocks)
output, destination traffic from the router itself to a blocked address

A blocked internal address also loses access to the router (DHCP, DNS, management).

Exceptions go above the drop rules:

/ip firewall raw
add chain=prerouting action=accept src-address=192.0.2.10 place-before=0 comment="Never block"
add chain=prerouting action=accept dst-address=192.0.2.10 place-before=0 comment="Never block"

Check

/system script run intrudect-blocklist
/log print where message~"intrudect"
/ip firewall address-list print count-only where list=intrudect-block

The router appears in Pull logs on the Feed tab.

Remove

/system scheduler remove [find name=intrudect-blocklist]
/system script remove [find name=intrudect-blocklist]
/ip firewall raw remove [find comment~"^Intrudect:"]
/ipv6 firewall raw remove [find comment~"^Intrudect:"]
/ip firewall address-list remove [find list=intrudect-block]
/ipv6 firewall address-list remove [find list=intrudect-block]