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=1and 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]