The scripts are open source and live on GitHub: Q-Feeds/Q-Feeds-Integration-for-Mikrotik-RouterOS. Always take them from there so you get the current version. You need admin rights on the router, outbound HTTPS to api.qfeeds.com and a Q-Feeds API token. See Get your threat feeds.
Prerequisites
- RouterOS: 7.15 or later, tested on 7.15, 7.17 and 7.20
- Privileges: an account with full admin rights
- Feed: malware IP list (
feed_type=malware_ip) - Network: outbound HTTPS from the router to
api.qfeeds.com - Address-list:
Malware-List, created by the scripts if it does not exist yet
Get the scripts
The repository holds two files:
Malware Import FULL.rscloads the complete list.Malware Import DIFF.rscapplies only the changes since your last pull.
Open both on GitHub and copy their contents, or download the repository as a ZIP. There is nothing to install on the router itself, you paste the script text into RouterOS.
Set your token
Both scripts start with a short variable block. Replace the placeholder token with your own:
:local apitoken "YOUR_API_TOKEN_HERE";
The next variable decides where the entries are kept:
:local useDynamic "yes";
"yes"keeps the entries in RAM. They disappear on reboot and the scheduler restores them on the next run. This is the default and the right choice for frequent updates, because it never writes to the flash memory of the router."no"writes the entries to disk. They survive a reboot, but with a list of this size and an update every twenty minutes you wear out the flash and inflate the configuration file.
Add the scripts to RouterOS
In Winbox or WebFig, go to System, Scripts and add two scripts. The names matter, because the full import looks for the differential scheduler by name:
- Malware Update - Full with the contents of
Malware Import FULL.rsc - Malware Update - Diff with the contents of
Malware Import DIFF.rsc
Give both scripts the read, write, policy and test policies, otherwise they cannot manage the address-list and the scheduler.
Create the schedulers
/system scheduler add name="Malware Update - Full" \
start-time=startup interval=1d \
on-event="Malware Update - Full"
/system scheduler add name="Malware Update - Diff" \
start-time=startup interval=20m \
on-event="Malware Update - Diff"
Run the full import daily or weekly. Set the differential interval to match your licence: 1d for Community, 4h for Plus and 20m for Premium. Pulling more often than your licence allows returns nothing new.
Run the full import once by hand before you rely on the differential update. The API returns changes since your last pull, so without a first full pull there is no baseline and the diff stays empty.
/system script run "Malware Update - Full"
Block the traffic
The scripts only fill the list. Add the filter rules yourself, for example:
/ip firewall filter
add chain=forward src-address-list="Malware-List" action=drop \
comment="Q-Feeds: drop traffic from malicious hosts"
add chain=forward dst-address-list="Malware-List" action=drop \
comment="Q-Feeds: drop traffic to malicious hosts"
Place the rules high enough in the chain that they are evaluated before a general accept rule, and add rules in the input chain as well if you want to protect the router itself.
How it works
- Full import: the script disables the differential scheduler, renames the current entries to
Malware-List - Old, downloads the feed page by page in blocks of 4,000 addresses and stops as soon as a page comes back empty. - Rollback: only when the import produced entries are the old ones removed. If the download fails, the previous list is renamed back and the router keeps its protection.
- Differential update: lines prefixed with
+are added to the address-list, lines prefixed with-are removed. Every API key has its own history, so you get exactly the changes since your own last pull, within the cadence of your licence. - Coordination: the full import switches the differential scheduler off while it runs and back on afterwards, so the two never fight over the same list.
- Address formats: IPv4, IPv6 and CIDR notation such as
192.0.2.0/24. RouterOS validates every address and silently skips anything it cannot parse. - Logging: both scripts turn the first logging action off while they run, to keep thousands of individual entries out of the log, and turn it back on when they are done.
Verify
/ip firewall address-list print count-only where list="Malware-List"
/ip firewall address-list print where list="Malware-List"
/log print where message~"Malware"
/system scheduler print
After a successful full import the count runs into the hundreds of thousands, depending on your licence, and the log shows a line per processed page plus a closing message.
Troubleshooting
- The list stays empty: check the token in both scripts, confirm the router can reach
https://api.qfeeds.comand run the full import by hand from the terminal. - The differential update never changes anything: run the full import first. Use the same API token in both scripts, because the pull history is tied to the key.
- The list is gone after a reboot: that is expected with
useDynamic "yes". The scheduler fills it again on the next run. Set the variable to"no"only if you really need persistence. - Rollback in the log: the import failed and the previous list was restored. Check connectivity and the validity of your token, and confirm the router has enough free memory.
- Nothing runs: check
/system scheduler printfor a disabled scheduler and confirm the script names match the scheduler names exactly. - Support: support@qfeeds.com or the support page. Found a bug in the scripts? Open an issue in the GitHub repository.
Q-Feeds malicious URL feeds are not supported on RouterOS. An address list matches on IP addresses, and a full URL path can only be inspected by a proxy or a web filter. Stay with the malware IP feed here.