From e19e33d0a80fe1b4520fe9dab05f6f8a96d6c574 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 31 May 2023 10:01:38 +0200 Subject: introduce fw-addr-lists --- README.md | 1 + doc/fw-addr-lists.md | 88 ++++++++++++++++++++++++++++++++++++++++++++++ fw-addr-lists.rsc | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++ global-config.rsc | 15 ++++++++ global-functions.rsc | 2 +- news-and-changes.rsc | 1 + 6 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 doc/fw-addr-lists.md create mode 100644 fw-addr-lists.rsc diff --git a/README.md b/README.md index 1d6bc9b..c03d244 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ Available scripts * [Comment DHCP leases with info from access list](doc/dhcp-lease-comment.md) * [Create DNS records for DHCP leases](doc/dhcp-to-dns.md) * [Automatically upgrade firmware and reboot](doc/firmware-upgrade-reboot.md) +* [Download, import and update firewall address-lists](doc/fw-addr-lists.md) * [Wait for global functions und modules](doc/global-wait.md) * [Send GPS position to server](doc/gps-track.md) * [Use WPA2 network with hotspot credentials](doc/hotspot-to-wpa.md) diff --git a/doc/fw-addr-lists.md b/doc/fw-addr-lists.md new file mode 100644 index 0000000..98aedcc --- /dev/null +++ b/doc/fw-addr-lists.md @@ -0,0 +1,88 @@ +Download, import and update firewall address-lists +================================================== + +[⬅️ Go back to main README](../README.md) + +> ℹ️ **Info**: This script can not be used on its own but requires the base +> installation. See [main README](../README.md) for details. + +Description +----------- + +This script downloads, imports and updates firewall address-lists. Its main +purpose is to block attacking ip addresses, spam hosts, command-and-control +servers and similar malicious entities. The default configuration contains +a list from [dshield.org](https://dshield.org/). + +The address-lists are updated in place, so after initial import you will not +see situation when the lists are not populated. + +To mitigate man-in-the-middle attacks with altered lists the server's +certificate is checked. + +Requirements and installation +----------------------------- + +Just install the script: + + $ScriptInstallUpdate fw-addr-lists; + +And add two schedulers, first one for initial import after startup, second +one for subsequent updates: + + /system/scheduler/add name="fw-addr-lists@startup" start-time=startup on-event="/system/script/run fw-addr-lists;"; + /system/scheduler/add name="fw-addr-lists" start-time=startup interval=2h on-event="/system/script/run fw-addr-lists;"; + +> ℹ️ **Info**: Modify the interval to your needs, but it is recommended to +> use less than half of the configured timeout for expiration. + +Configuration +------------- + +The configuration goes to `global-config-overlay`, these are the parameters: + +* `FwAddrLists`: a list of firewall address-lists to download and import +* `FwAddrListTimeOut`: the timeout for expiration without renew + +> ℹ️ **Info**: Copy relevant configuration from +> [`global-config`](../global-config.rsc) (the one without `-overlay`) to +> your local `global-config-overlay` and modify it to your specific needs. + +Naming a certificate for a list makes the script verify the server +certificate, so you should add that if possible. Some certificates are +available in my repository and downloaded automatically. Import it manually +(menu `/certificate/`) if missing. + +Create firewall rules to process the packets that are related to addresses +from address-lists. This rejects the packets from and to ip addresses listed +in address-list `block`. + + /ip/firewall/filter/add chain=input src-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add chain=forward src-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add chain=forward dst-address-list=block action=reject reject-with=icmp-admin-prohibited; + /ip/firewall/filter/add chain=output dst-address-list=block action=reject reject-with=icmp-admin-prohibited; + +You may want to have an address-list to allow specific addresses, as prepared +with a list `allow`. In fact you can use any list name, just change the +default ones or add your own - matching in configuration and firewall rules. + + /ip/firewall/filter/add chain=input src-address-list=allow action=accept; + /ip/firewall/filter/add chain=forward src-address-list=allow action=accept; + /ip/firewall/filter/add chain=forward dst-address-list=allow action=accept; + /ip/firewall/filter/add chain=output dst-address-list=allow action=accept; + +Modify these for your needs, but **most important**: Move the rules up in +chains and make sure they actually take effect as expected! + +Alternatively handle the packets in firewall's raw section if you prefer: + + /ip/firewall/raw/add chain=prerouting src-address-list=block action=drop; + /ip/firewall/raw/add chain=prerouting dst-address-list=block action=drop; + /ip/firewall/raw/add chain=output dst-address-list=block action=drop; + +> ⚠️ **Warning**: Just again... The order of firewall rules is important. Make +> sure they actually take effect as expected! + +--- +[⬅️ Go back to main README](../README.md) +[⬆️ Go back to top](#top) diff --git a/fw-addr-lists.rsc b/fw-addr-lists.rsc new file mode 100644 index 0000000..5117c3e --- /dev/null +++ b/fw-addr-lists.rsc @@ -0,0 +1,99 @@ +#!rsc by RouterOS +# RouterOS script: fw-addr-lists +# Copyright (c) 2023 Christian Hesse +# https://git.eworm.de/cgit/routeros-scripts/about/COPYING.md +# +# download, import and update firewall address-lists +# https://git.eworm.de/cgit/routeros-scripts/about/doc/fw-addr-lists.md + +:local 0 "fw-addr-lists"; +:global GlobalFunctionsReady; +:while ($GlobalFunctionsReady != true) do={ :delay 500ms; } + +:global FwAddrLists; +:global FwAddrListTimeOut; + +:global CertificateAvailable; +:global LogPrintExit2; +:global ScriptLock; +:global WaitFullyConnected; + +:local FindDelim do={ + :local ValidChars "0123456789./"; + :for I from=0 to=[ :len $1 ] do={ + :if ([ :typeof [ :find $ValidChars [ :pick ($1 . " ") $I ] ] ] != "num") do={ + :return $I; + } + } +} + +$ScriptLock $0; + +$WaitFullyConnected; + +:local ListComment ("managed by " . $0); + +:foreach FwListName,FwList in=$FwAddrLists do={ + :local Addresses ({}); + :local CntAdd 0; + :local CntRenew 0; + :local CntRemove 0; + :local Failure false; + + :foreach List in=$FwList do={ + :local Data; + :local CheckCertificate "no"; + + :if ([ :len ($List->"cert") ] > 0) do={ + :set CheckCertificate "yes-without-crl"; + :if ([ $CertificateAvailable ($List->"cert") ] = false) do={ + $LogPrintExit2 warning $0 ("Downloading required certificate failed, trying anyway.") false; + } + } + + :do { + :set Data ([ /tool/fetch ($List->"url") check-certificate=$CheckCertificate output=user as-value ]->"data"); + } on-error={ + :set Failure true; + $LogPrintExit2 warning $0 ("Failed downloading list from: " . $List->"url") false; + } + + :while ([ :len $Data ] != 0) do={ + :local Line [ :pick $Data 0 [ :find $Data "\n" ] ]; + :local Address ([ :pick $Line 0 [ $FindDelim $Line ] ] . ($List->"cidr")); + :if ($Address ~ "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(/[0-9]{1,2})?\$") do={ + :set ($Addresses->$Address) 1; + } + :set Data [ :pick $Data ([ :len $Line ] + 1) [ :len $Data ] ]; + } + } + + :foreach Entry in=[ /ip/firewall/address-list/find where list=$FwListName comment=$ListComment ] do={ + :local Address [ /ip/firewall/address-list/get $Entry address ]; + :if (($Addresses->$Address) = 1) do={ + $LogPrintExit2 debug $0 ("Renewing: " . $Address) false; + /ip/firewall/address-list/set $Entry timeout=$FwAddrListTimeOut; + :set ($Addresses->$Address); + :set CntRenew ($CntRenew + 1); + } else={ + :if ($Failure = false) do={ + $LogPrintExit2 debug $0 ("Removing: " . $Address) false; + /ip/firewall/address-list/remove $Entry; + :set CntRemove ($CntRemove + 1); + } + } + } + + :foreach Address,Ignore in=$Addresses do={ + $LogPrintExit2 debug $0 ("Adding: " . $Address) false; + :do { + /ip/firewall/address-list/add list=$FwListName comment=$ListComment address=$Address timeout=$FwAddrListTimeOut; + :set ($Addresses->$Address); + :set CntAdd ($CntAdd + 1); + } on-error={ + $LogPrintExit2 warning $0 ("Failed to add address " . $Address . " to list '" . $FwListName . "'.") false; + } + } + + $LogPrintExit2 info $0 ("List: " . $FwListName . " -- Added: " . $CntAdd . " - renewed: " . $CntRenew . " - removed: " . $CntRemove) false; +} diff --git a/global-config.rsc b/global-config.rsc index b17d25c..901c7b3 100644 --- a/global-config.rsc +++ b/global-config.rsc @@ -80,6 +80,21 @@ :global BackupUploadUser "mikrotik"; :global BackupUploadPass "v3ry-s3cr3t"; +# This defines the settings for firewall address-lists (fw-addr-lists). +:global FwAddrLists { +# "allow"={ +# { url="https://eworm.de/ros/fw-addr-lists/allow"; +# cert="R3" }; +# }; + "block"={ +# { url="https://eworm.de/ros/fw-addr-lists/block"; +# cert="R3" }; + { url="https://www.dshield.org/block.txt"; cidr="/24"; + cert="R3" }; + }; +}; +:global FwAddrListTimeOut 1d; + # This defines what log messages to filter or include by topic or message # text. Regular expressions are supported. Do *NOT* set an empty string, # that will filter or include everything! diff --git a/global-functions.rsc b/global-functions.rsc index 030892b..98f6978 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -12,7 +12,7 @@ :local 0 "global-functions"; # expected configuration version -:global ExpectedConfigVersion 100; +:global ExpectedConfigVersion 101; # global variables not to be changed by user :global GlobalFunctionsReady false; diff --git a/news-and-changes.rsc b/news-and-changes.rsc index 1e43722..e33a7db 100644 --- a/news-and-changes.rsc +++ b/news-and-changes.rsc @@ -14,6 +14,7 @@ 98="Extended 'check-certificates' to download new certificate by SubjectAltNames if download by CommonName fails."; 99="Modified 'dhcp-to-dns', which dropped global configuration. Settings moved to dhcp server's network definitions."; 100="The script 'ssh-keys-import' became a module 'mod/ssh-keys-import' with enhanced functionality."; + 101="Introduced new script 'fw-addr-lists' to download, import and update firewall address-lists."; }; # Migration steps to be applied on script updates -- cgit v1.2.3-54-g00ecf