diff --git a/README.md b/README.md index 115eeb4..89c7e19 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # ipset-blacklist -A Bash shell script which uses ipset and iptables to ban a large number of IP addresses published in IP blacklists. ipset uses a hashtable to store/fetch IP addresses and thus the IP lookup is a lot (!) faster than thousands of sequentially parsed iptables ban rules. ~~However, the limit of an ipset list is 2^16 entries.~~ +A Bash shell script which uses ipset, iptables and ip6tables to ban a large number of IP addresses published in IP blacklists. ipset uses a hashtable to store/fetch IP addresses and thus the IP lookup is a lot (!) faster than thousands of sequentially parsed iptables ban rules. +Thanks to @trick77 for original code and to https://github.com/leshniak/nft-blacklist for inspiration and code to add ipv6 support. The ipset command doesn't work under OpenVZ. It works fine on dedicated and fully virtualized servers like KVM though. ## What's new +- 04/30/2023: Added ipv6 support - 10/17/2018: Added support for CIDR aggregation if iprange command is available - 10/17/2018: Merged Shellcheck PR from [@extremeshok](https://github.com/extremeshok) - 05/10/2018: Added regex filter improvements from [@sbujam](https://github.com/sbujam) @@ -18,20 +20,21 @@ The ipset command doesn't work under OpenVZ. It works fine on dedicated and full ## Quick start for Debian/Ubuntu based installations -1. `wget -O /usr/local/sbin/update-blacklist.sh https://raw.githubusercontent.com/trick77/ipset-blacklist/master/update-blacklist.sh` -2. `chmod +x /usr/local/sbin/update-blacklist.sh` -3. `mkdir -p /etc/ipset-blacklist ; wget -O /etc/ipset-blacklist/ipset-blacklist.conf https://raw.githubusercontent.com/trick77/ipset-blacklist/master/ipset-blacklist.conf` +1. `wget -O /usr/local/bin/update-blacklist.sh https://raw.githubusercontent.com/kiekerjan/ipset-blacklist/master/update-blacklist.sh` +2. `chmod +x /usr/local/bin/update-blacklist.sh` +3. `mkdir -p /etc/ipset-blacklist ; wget -O /etc/ipset-blacklist/ipset-blacklist.conf https://raw.githubusercontent.com/kiekerjan/ipset-blacklist/master/ipset-blacklist.conf` 4. Modify `ipset-blacklist.conf` according to your needs. Per default, the blacklisted IP addresses will be saved to `/etc/ipset-blacklist/ip-blacklist.restore` 5. `apt-get install ipset` -6. Create the ipset blacklist and insert it into your iptables input filter (see below). After proper testing, make sure to persist it in your firewall script or similar or the rules will be lost after the next reboot. -7. Auto-update the blacklist using a cron job +6. Get cidr-merger from https://github.com/zhanhb/cidr-merger/releases (optional) +7. Create the ipset blacklist and insert it into your iptables input filter (see below). After proper testing, make sure to persist it in your firewall script or similar or the rules will be lost after the next reboot. +8. Auto-update the blacklist using a cron job ## First run, create the list to generate the `/etc/ipset-blacklist/ip-blacklist.restore`: ```sh -/usr/local/sbin/update-blacklist.sh /etc/ipset-blacklist/ipset-blacklist.conf +/usr/local/bin/update-blacklist.sh /etc/ipset-blacklist/ipset-blacklist.conf ``` ## iptables filter rule @@ -39,19 +42,20 @@ to generate the `/etc/ipset-blacklist/ip-blacklist.restore`: ```sh # Enable blacklists ipset restore < /etc/ipset-blacklist/ip-blacklist.restore -iptables -I INPUT 1 -m set --match-set blacklist src -j DROP +iptables -I INPUT 1 -m set --match-set blacklist_v4 src -j DROP +ip6tables -I INPUT 1 -m set --match-set blacklist_v6 src -j DROP ``` -Make sure to run this snippet in a firewall script or just insert it to `/etc/rc.local`. +Make sure to run this snippet in a firewall script or just insert it to `/etc/rc.local` or a cron job that runs at boot. ## Cron job In order to auto-update the blacklist, copy the following code into `/etc/cron.d/update-blacklist`. Don't update the list too often or some blacklist providers will ban your IP address. Once a day should be OK though. ```sh -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +PATH=/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root -33 23 * * * root /usr/local/sbin/update-blacklist.sh /etc/ipset-blacklist/ipset-blacklist.conf +33 23 * * * root /usr/local/bin/update-blacklist.sh /etc/ipset-blacklist/ipset-blacklist.conf ``` ## Check for dropped packets diff --git a/ansible/deploy.yaml b/ansible/deploy.yaml index 23dc744..0864e2c 100644 --- a/ansible/deploy.yaml +++ b/ansible/deploy.yaml @@ -3,7 +3,7 @@ hosts: publicserver become: true vars: - download_script_url: https://raw.githubusercontent.com/trick77/ipset-blacklist/master/update-blacklist.sh + download_script_url: https://raw.githubusercontent.com/kiekerjan/ipset-blacklist/master/update-blacklist.sh ipsets_confdir: /etc/ipset-blacklist ipsets_blacklist_name: blacklist ip_blacklist_restore: ip-blacklist.restore @@ -14,6 +14,7 @@ - https://www.dshield.org/block.txt - https://lists.blocklist.de/lists/ssh.txt maxelements: 131072 + maxelements_v6: 131072 tasks: @@ -36,7 +37,7 @@ - name: Download update-blacklist.conf (for documentation) get_url: - url: https://raw.githubusercontent.com/trick77/ipset-blacklist/master/ipset-blacklist.conf + url: https://raw.githubusercontent.com/kiekerjan/ipset-blacklist/master/ipset-blacklist.conf dest: "{{ ipsets_confdir }}/ipset-blacklist.conf.orig" - name: Generate update-blacklist.conf diff --git a/ansible/templates/update-blacklist.conf.j2 b/ansible/templates/update-blacklist.conf.j2 index 4e7cf4e..d8df0f7 100644 --- a/ansible/templates/update-blacklist.conf.j2 +++ b/ansible/templates/update-blacklist.conf.j2 @@ -1,15 +1,19 @@ -IPSET_BLACKLIST_NAME={{ ipsets_blacklist_name }} +IPSET_BLACKLIST_NAME={{ ipsets_blacklist_name }} # change it if it collides with a pre-existing ipset list IPSET_TMP_BLACKLIST_NAME={{ ipsets_blacklist_name }}-tmp IP_BLACKLIST_RESTORE="{{ ipsets_confdir }}/ip-blacklist.restore" -IP_BLACKLIST="{{ ipsets_confdir }}/ip-blacklist.list" +IP_BLACKLIST_FILE="{{ ipsets_confdir }}/ip-blacklist.list" +IP6_BLACKLIST_FILE="{{ ipsets_confdir }}/ip6-blacklist.list" VERBOSE={{ verbose }} # probably set to "no" for cron jobs, default to yes FORCE={{ force }} # will create the ipset-iptable binding if it does not already exist let IPTABLES_IPSET_RULE_NUMBER=1 # if FORCE is yes, the number at which place insert the ipset-match rule (default to 1) -# Sample (!) list of URLs for IP blacklists. Currently, only IPv4 is supported in this script, everything else will be filtered. +# Sample (!) list of URLs for IP blacklists. BLACKLISTS=( "{{ blacklists|join("\"\n \"") }}" ) MAXELEM={{ maxelements }} +MAXELEM={{ maxelements_v6 }} + + diff --git a/ipset-blacklist.conf b/ipset-blacklist.conf index a1fb898..ed4791e 100644 --- a/ipset-blacklist.conf +++ b/ipset-blacklist.conf @@ -3,25 +3,29 @@ IPSET_TMP_BLACKLIST_NAME=${IPSET_BLACKLIST_NAME}-tmp # ensure the directory for IP_BLACKLIST/IP_BLACKLIST_RESTORE exists (it won't be created automatically) IP_BLACKLIST_RESTORE=/etc/ipset-blacklist/ip-blacklist.restore -IP_BLACKLIST=/etc/ipset-blacklist/ip-blacklist.list +IP_BLACKLIST_FILE=/etc/ipset-blacklist/ip-blacklist.list +IP6_BLACKLIST_FILE=/etc/ipset-blacklist/ip6-blacklist.list VERBOSE=yes # probably set to "no" for cron jobs, default to yes FORCE=yes # will create the ipset-iptable binding if it does not already exist let IPTABLES_IPSET_RULE_NUMBER=1 # if FORCE is yes, the number at which place insert the ipset-match rule (default to 1) -# Sample (!) list of URLs for IP blacklists. Currently, only IPv4 is supported in this script, everything else will be filtered. +# Sample (!) list of URLs for IP blacklists. BLACKLISTS=( # "file:///etc/ipset-blacklist/ip-blacklist-custom.list" # optional, for your personal nemeses (no typo, plural) - "https://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1" # Project Honey Pot Directory of Dictionary Attacker IPs - "https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1" # TOR Exit Nodes - "http://danger.rulez.sk/projects/bruteforceblocker/blist.php" # BruteForceBlocker IP List - "https://www.spamhaus.org/drop/drop.lasso" # Spamhaus Don't Route Or Peer List (DROP) - "https://cinsscore.com/list/ci-badguys.txt" # C.I. Army Malicious IP List - "https://lists.blocklist.de/lists/all.txt" # blocklist.de attackers - "https://blocklist.greensnow.co/greensnow.txt" # GreenSnow + #"https://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1" # Project Honey Pot Directory of Dictionary Attacker IPs + #"https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1" # TOR Exit Nodes + #"http://danger.rulez.sk/projects/bruteforceblocker/blist.php" # BruteForceBlocker IP List + "https://www.spamhaus.org/drop/drop.txt" # Spamhaus Don't Route Or Peer List (DROP) + #"https://cinsscore.com/list/ci-badguys.txt" # C.I. Army Malicious IP List + #"https://lists.blocklist.de/lists/all.txt" # blocklist.de attackers + #"https://blocklist.greensnow.co/greensnow.txt" # GreenSnow "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset" # Firehol Level 1 - "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/stopforumspam_7d.ipset" # Stopforumspam via Firehol + # "https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/stopforumspam_7d.ipset" # Stopforumspam via Firehol # "https://raw.githubusercontent.com/ipverse/rir-ip/master/country/zz/ipv4-aggregated.txt" # Ban an entire country(-code), see https://github.com/ipverse/rir-ip # "https://raw.githubusercontent.com/ipverse/asn-ip/master/as/1234/ipv4-aggregated.txt" # Ban a specific autonomous system (ISP), see https://github.com/ipverse/asn-ip + "https://www.spamhaus.org/drop/dropv6.txt" # Spamhaus Don't Route Or Peer List ipv6 (DROPv6) + # "https://team-cymru.org/Services/Bogons/fullbogons-ipv6.txt" # Team Cymru Bogons ) MAXELEM=131072 +MAXELEM_V6=131072 diff --git a/update-blacklist.sh b/update-blacklist.sh index 5494fdd..922b0c3 100755 --- a/update-blacklist.sh +++ b/update-blacklist.sh @@ -3,7 +3,27 @@ # usage update-blacklist.sh # eg: update-blacklist.sh /etc/ipset-blacklist/ipset-blacklist.conf # + +IPV4_REGEX="(?:[0-9]{1,3}\.){3}[0-9]{1,3}(?:/[0-9]{1,2})?" +IPV6_REGEX="(?:(?:[0-9a-f]{1,4}:){7,7}[0-9a-f]{1,4}|\ +(?:[0-9a-f]{1,4}:){1,7}:|\ +(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|\ +(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|\ +(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|\ +(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|\ +(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|\ +[0-9a-f]{1,4}:(?:(?::[0-9a-f]{1,4}){1,6})|\ +:(?:(?::[0-9a-f]{1,4}){1,7}|:)|\ +::(?:[f]{4}(?::0{1,4})?:)?\ +(?:(25[0-5]|(?:2[0-4]|1?[0-9])?[0-9])\.){3,3}\ +(?:25[0-5]|(?:2[0-4]|1?[0-9])?[0-9])|\ +(?:[0-9a-f]{1,4}:){1,4}:\ +(?:(?:25[0-5]|(?:2[0-4]|1?[0-9])?[0-9])\.){3,3}\ +(?:25[0-5]|(?:2[0-4]|1?[0-9])?[0-9]))\ +(?:/[0-9]{1,3})?" + function exists() { command -v "$1" >/dev/null 2>&1 ; } +function count_entries() { wc -l "$1" | cut -d' ' -f1 ; } if [[ -z "$1" ]]; then echo "Error: please specify a configuration file, e.g. $0 /etc/ipset-blacklist/ipset-blacklist.conf" @@ -16,98 +36,148 @@ if ! source "$1"; then exit 1 fi -if ! exists curl && exists egrep && exists grep && exists ipset && exists iptables && exists sed && exists sort && exists wc ; then - echo >&2 "Error: searching PATH fails to find executables among: curl egrep grep ipset iptables sed sort wc" +IPSET_BLACKLIST_NAME_V4="${IPSET_BLACKLIST_NAME}_v4" +IPSET_BLACKLIST_NAME_V6="${IPSET_BLACKLIST_NAME}_v6" +IPSET_TMP_BLACKLIST_NAME_V4="${IPSET_TMP_BLACKLIST_NAME}_v4" +IPSET_TMP_BLACKLIST_NAME_V6="${IPSET_TMP_BLACKLIST_NAME}_v6" + +if ! (exists curl && exists egrep && exists grep && exists ipset && exists iptables && exists ip6tables && exists sed && exists sort && exists wc) ; then + echo >&2 "Error: searching PATH fails to find executables among: curl egrep grep ipset iptables ip6tables sed sort wc" exit 1 fi +# download cidr-merger from https://github.com/zhanhb/cidr-merger/releases DO_OPTIMIZE_CIDR=no -if exists iprange && [[ ${OPTIMIZE_CIDR:-yes} != no ]]; then +if exists cidr-merger && [[ ${OPTIMIZE_CIDR:-yes} != no ]]; then DO_OPTIMIZE_CIDR=yes fi -if [[ ! -d $(dirname "$IP_BLACKLIST") || ! -d $(dirname "$IP_BLACKLIST_RESTORE") ]]; then - echo >&2 "Error: missing directory(s): $(dirname "$IP_BLACKLIST" "$IP_BLACKLIST_RESTORE"|sort -u)" +if [[ ! -d $(dirname "$IP_BLACKLIST_FILE") || ! -d $(dirname "$IP_BLACKLIST_RESTORE") || ! -d $(dirname "$IP6_BLACKLIST_FILE") ]]; then + echo >&2 "Error: missing directory(s): $(dirname "$IP_BLACKLIST_FILE" "$IP_BLACKLIST_RESTORE" "$IP6_BLACKLIST_FILE" "$IP6_BLACKLIST_RESTORE"|sort -u)" exit 1 fi -# create the ipset if needed (or abort if does not exists and FORCE=no) -if ! ipset list -n|command grep -q "$IPSET_BLACKLIST_NAME"; then +# ipv4 create the ipset if needed (or abort if does not exists and FORCE=no) +if ! ipset list -n|command grep -q "$IPSET_BLACKLIST_NAME_V4"; then + if [[ ${FORCE:-no} != yes ]]; then + echo >&2 "Error: ipset v4 does not exist yet, add it using:" + echo >&2 "# ipset create $IPSET_BLACKLIST_NAME_V4 -exist hash:net family inet hashsize ${HASHSIZE:-16384} maxelem ${MAXELEM:-65536}" + exit 1 + fi + if ! ipset create "$IPSET_BLACKLIST_NAME_V4" -exist hash:net family inet hashsize "${HASHSIZE:-16384}" maxelem "${MAXELEM:-65536}"; then + echo >&2 "Error: while creating the initial ipset v4" + exit 1 + fi +fi + +# ipv6 create the ipset if needed (or abort if does not exists and FORCE=no) +if ! ipset list -n|command grep -q "$IPSET_BLACKLIST_NAME_V6"; then if [[ ${FORCE:-no} != yes ]]; then - echo >&2 "Error: ipset does not exist yet, add it using:" - echo >&2 "# ipset create $IPSET_BLACKLIST_NAME -exist hash:net family inet hashsize ${HASHSIZE:-16384} maxelem ${MAXELEM:-65536}" + echo >&2 "Error: ipset v6 does not exist yet, add it using:" + echo >&2 "# ipset create $IPSET_BLACKLIST_NAME_V6 -exist hash:net family inet6 hashsize ${HASHSIZE_V6:-16384} maxelem ${MAXELEM_V6:-131072}" exit 1 fi - if ! ipset create "$IPSET_BLACKLIST_NAME" -exist hash:net family inet hashsize "${HASHSIZE:-16384}" maxelem "${MAXELEM:-65536}"; then - echo >&2 "Error: while creating the initial ipset" + if ! ipset create "$IPSET_BLACKLIST_NAME_V6" -exist hash:net family inet6 hashsize "${HASHSIZE_V6:-16384}" maxelem "${MAXELEM_V6:-131072}"; then + echo >&2 "Error: while creating the initial v6 ipset" exit 1 fi fi -# create the iptables binding if needed (or abort if does not exists and FORCE=no) -if ! iptables -nvL INPUT|command grep -q "match-set $IPSET_BLACKLIST_NAME"; then +# ipv4 create the iptables binding if needed (or abort if does not exists and FORCE=no) +if ! iptables -nvL INPUT|command grep -q "match-set $IPSET_BLACKLIST_NAME_V4"; then # we may also have assumed that INPUT rule n°1 is about packets statistics (traffic monitoring) if [[ ${FORCE:-no} != yes ]]; then echo >&2 "Error: iptables does not have the needed ipset INPUT rule, add it using:" - echo >&2 "# iptables -I INPUT ${IPTABLES_IPSET_RULE_NUMBER:-1} -m set --match-set $IPSET_BLACKLIST_NAME src -j DROP" + echo >&2 "# iptables -I INPUT ${IPTABLES_IPSET_RULE_NUMBER:-1} -m set --match-set $IPSET_BLACKLIST_NAME_V4 src -j DROP" exit 1 fi - if ! iptables -I INPUT "${IPTABLES_IPSET_RULE_NUMBER:-1}" -m set --match-set "$IPSET_BLACKLIST_NAME" src -j DROP; then + if ! iptables -I INPUT "${IPTABLES_IPSET_RULE_NUMBER:-1}" -m set --match-set "$IPSET_BLACKLIST_NAME_V4" src -j DROP; then echo >&2 "Error: while adding the --match-set ipset rule to iptables" exit 1 fi fi -IP_BLACKLIST_TMP=$(mktemp) -for i in "${BLACKLISTS[@]}" +# ipv6 create the ip6tables binding if needed (or abort if does not exists and FORCE=no) +if ! ip6tables -nvL INPUT|command grep -q "match-set $IPSET_BLACKLIST_NAME_V6"; then + # we may also have assumed that INPUT rule n°1 is about packets statistics (traffic monitoring) + if [[ ${FORCE:-no} != yes ]]; then + echo >&2 "Error: ip6tables does not have the needed ipset INPUT rule, add it using:" + echo >&2 "# ip6tables -I INPUT ${IPTABLES_IPSET_RULE_NUMBER:-1} -m set --match-set $IPSET_BLACKLIST_NAME_V6 src -j DROP" + exit 1 + fi + if ! ip6tables -I INPUT "${IPTABLES_IPSET_RULE_NUMBER:-1}" -m set --match-set "$IPSET_BLACKLIST_NAME_V6" src -j DROP; then + echo >&2 "Error: while adding the --match-set ipset rule to ip6tables" + exit 1 + fi +fi + +IP_BLACKLIST_TMP_FILE=$(mktemp) +IP6_BLACKLIST_TMP_FILE=$(mktemp) +for url in "${BLACKLISTS[@]}" do - IP_TMP=$(mktemp) - (( HTTP_RC=$(curl -L -A "blacklist-update/script/github" --connect-timeout 10 --max-time 10 -o "$IP_TMP" -s -w "%{http_code}" "$i") )) + IP_TMP_FILE=$(mktemp) + (( HTTP_RC=$(curl -L -A "blacklist-update/script/github" --connect-timeout 10 --max-time 10 -o "$IP_TMP_FILE" -s -w "%{http_code}" "$url") )) if (( HTTP_RC == 200 || HTTP_RC == 302 || HTTP_RC == 0 )); then # "0" because file:/// returns 000 - command grep -Po '^(?:\d{1,3}\.){3}\d{1,3}(?:/\d{1,2})?' "$IP_TMP" | sed -r 's/^0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)$/\1.\2.\3.\4/' >> "$IP_BLACKLIST_TMP" + command grep -Po "^$IPV4_REGEX" "$IP_TMP_FILE" | sed -r 's/^0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)\.0*([0-9]+)$/\1.\2.\3.\4/' >> "$IP_BLACKLIST_TMP_FILE" + command grep -Pio "^$IPV6_REGEX" "$IP_TMP_FILE" >> "$IP6_BLACKLIST_TMP_FILE" [[ ${VERBOSE:-yes} == yes ]] && echo -n "." elif (( HTTP_RC == 503 )); then - echo -e "\\nUnavailable (${HTTP_RC}): $i" + echo -e "\\nUnavailable (${HTTP_RC}): $url" else - echo >&2 -e "\\nWarning: curl returned HTTP response code $HTTP_RC for URL $i" + echo >&2 -e "\\nWarning: curl returned HTTP response code $HTTP_RC for URL $url" fi - rm -f "$IP_TMP" + rm -f "$IP_TMP_FILE" done +[[ ${VERBOSE:-no} == yes ]] && echo -e "\\n" + # sort -nu does not work as expected -sed -r -e '/^(0\.0\.0\.0|10\.|127\.|172\.1[6-9]\.|172\.2[0-9]\.|172\.3[0-1]\.|192\.168\.|22[4-9]\.|23[0-9]\.)/d' "$IP_BLACKLIST_TMP"|sort -n|sort -mu >| "$IP_BLACKLIST" +sed -r -e '/^(0\.0\.0\.0|10\.|127\.|172\.1[6-9]\.|172\.2[0-9]\.|172\.3[0-1]\.|192\.168\.|22[4-9]\.|23[0-9]\.)/d' "$IP_BLACKLIST_TMP_FILE" | sort -n | sort -mu >| "$IP_BLACKLIST_FILE" +sed -r -e '/^([0:]+\/0|fe80:)/Id' "$IP6_BLACKLIST_TMP_FILE" | sort -d | sort -mu >| "$IP6_BLACKLIST_FILE" + if [[ ${DO_OPTIMIZE_CIDR} == yes ]]; then - if [[ ${VERBOSE:-no} == yes ]]; then - echo -e "\\nAddresses before CIDR optimization: $(wc -l "$IP_BLACKLIST" | cut -d' ' -f1)" - fi - < "$IP_BLACKLIST" iprange --optimize - > "$IP_BLACKLIST_TMP" 2>/dev/null - if [[ ${VERBOSE:-no} == yes ]]; then - echo "Addresses after CIDR optimization: $(wc -l "$IP_BLACKLIST_TMP" | cut -d' ' -f1)" - fi - cp "$IP_BLACKLIST_TMP" "$IP_BLACKLIST" + [[ ${VERBOSE:-no} == yes ]] && echo -e "Optimizing entries...\\nFound: $(count_entries "$IP_BLACKLIST_FILE") IPv4, $(count_entries "$IP6_BLACKLIST_FILE") IPv6" + cidr-merger -o "$IP_BLACKLIST_TMP_FILE" -o "$IP6_BLACKLIST_TMP_FILE" "$IP_BLACKLIST_FILE" "$IP6_BLACKLIST_FILE" + [[ ${VERBOSE:-no} == yes ]] && echo -e "Saved: $(count_entries "$IP_BLACKLIST_TMP_FILE") IPv4, $(count_entries "$IP6_BLACKLIST_TMP_FILE") IPv6\\n" + + cp "$IP_BLACKLIST_TMP_FILE" "$IP_BLACKLIST_FILE" + cp "$IP6_BLACKLIST_TMP_FILE" "$IP6_BLACKLIST_FILE" fi -rm -f "$IP_BLACKLIST_TMP" +rm -f "$IP_BLACKLIST_TMP_FILE" "$IP6_BLACKLIST_TMP_FILE" -# family = inet for IPv4 only cat >| "$IP_BLACKLIST_RESTORE" <> "$IP_BLACKLIST_RESTORE" +if [[ -s "$IP_BLACKLIST_FILE" ]]; then + # can be IPv4 including netmask notation + sed -rn -e '/^#|^$/d' -e "s/^([0-9./]+).*/add $IPSET_TMP_BLACKLIST_NAME_V4 \\1/p" "$IP_BLACKLIST_FILE" >> "$IP_BLACKLIST_RESTORE" + +fi +if [[ -s "$IP6_BLACKLIST_FILE" ]]; then + sed -rn -e '/^#|^$/d' -e "s/^(([0-9a-f:.]+:+[0-9a-f]*)+(\/[0-9]{1,3})?).*/add $IPSET_TMP_BLACKLIST_NAME_V6 \\1/Ip" "$IP6_BLACKLIST_FILE" >> "$IP_BLACKLIST_RESTORE" +fi + cat >> "$IP_BLACKLIST_RESTORE" <