Initial Commit

This commit is contained in:
Phil Connor 2024-11-14 16:49:03 -06:00
parent 77ad808cb3
commit 915a67fce7
10 changed files with 1222 additions and 220 deletions

View File

@ -0,0 +1,234 @@
#! /bin/bash
#### System Variables ####
IPSET_PREFIX="bl" # Prefix for ipset names
IPSET_TYPE="hash:net" # Type of created ipsets
IPV4=1 # Enable IPv4 by default
IPV6=1 # Enable IPv6 by default
QUIET=0 # Default quiet mode setting
VERBOSE=0 # Default verbosity level
declare -A BLOCKLISTS # Array for blocklists to use. Populated by CLI args,
IPV4_REGEX="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/[1-3]?[0-9])?" # Regex for a valid IPv4 address with optional subnet part
IPV6_REGEX="(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(/[1-6]?[0-9])?" # Regef for a valid IPv6 address with optional subnet part
if [ ! "$(command -v ipset)" ]; then
apt -y install ipset
else
IPSET_BIN=$(command -v ipset)
fi
if [ ! -d "/var/lib/ipset" ]; then
mkdir -p /var/lib/ipset
else
IPSET_DIR="/var/lib/ipset" # Folder to write ipset save files to
fi
##
# Prints the help/usage message
##
function print_usage() {
{
cat << EOF
Usage: $0 [-h]
Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org)
Options:
-l : Blocklist to use. Can be specified multiple times.
Format: "\$name \$url" (space-separated). See examples below.
-4 : Run in IPv4 only mode. Ignore IPv6 addresses.
-6 : Run in IPv6 only mode. Ignore IPv4 addresses.
-q : Quiet mode. Outputs are suppressed if flag is present.
-v : Verbose mode. Prints additional information during execution.
-h : Print this help message.
Example usage:
$0 -l "spamhaus https://www.spamhaus.org/drop/drop.txt"
$0 -l "blocklist https://lists.blocklist.de/lists/all.txt" -l "spamhaus https://www.spamhaus.org/drop/drop.txt"
$0 -l "spamhaus https://www.spamhaus.org/drop/drop.txt" -l "spamhaus6 https://www.spamhaus.org/drop/dropv6.txt"
EOF
}
}
#### Writes argument $1 to stdout if $QUIET is not set
function log() {
{
if [[ $QUIET -eq 0 ]]; then
echo "$1"
fi
}
}
#### Writes argument $1 to stdout if $VERBOSE is set and $QUIET is not set
function log_verbose() {
{
if [[ $VERBOSE -eq 1 ]]; then
if [[ $QUIET -eq 0 ]]; then
echo "$1"
fi
fi
}
}
#### Writes argument $1 to stderr. Ignores $QUIET.
function log_error() {
{
>&2 echo "[ERROR]: $1"
}
}
#### Validates the BLOCKLISTS array. Exits upon error.
function validate_blocklists() {
{
if [ ${#BLOCKLISTS[@]} -eq 0 ]; then
log_error "No blocklists given. Exiting..."
print_usage
exit 1
fi
for list in "${BLOCKLISTS[@]}"
do
list_name=$(echo "$list" | cut -d ' ' -f 1)
list_url=$(echo "$list" | cut -d ' ' -f 2)
if [ -z "$list_name" ]; then
log_error "Invalid name for list: $list"
exit 1
fi
if [ -z "$list_url" ]; then
log_error "Invalid url for list: $list"
exit 1
fi
log_verbose "Found valid blocklist: name=${list_name}, url=${list_url}"
done
}
}
#### Updates an ipset based on a list of IP addresses
function update_ipset() {
{
# Setup local vars
setname=$1 # $1 Name of the ipset to update
ipfile=$2 # $2 File containing all IP addresses to store in ipset
family=$3 # $3 Procotol family (e.g. inet OR inet6)
# Create temporary ipset to build and ensure existence of live ipset
livelist="$setname-$family"
templist="$setname-$family-T"
$IPSET_BIN create -q "$livelist" "$IPSET_TYPE" family "$family"
$IPSET_BIN create -q "$templist" "$IPSET_TYPE" family "$family"
log_verbose "Prepared ipset lists: livelist='$livelist', templist='$templist'"
while read -r ip; do
if $IPSET_BIN add "$templist" "$ip"; then
log_verbose "Added '$ip' to '$templist'"
else
log "Failed to add '$ip' to '$templist'"
fi
done < "$ipfile"
$IPSET_BIN swap "$templist" "$livelist"
log_verbose "Swapped ipset: $livelist"
$IPSET_BIN destroy "$templist"
log_verbose "Destroyed ipset: $templist"
# Write ipset savefile
$IPSET_BIN save "$livelist" > "$IPSET_DIR/$livelist.save"
log_verbose "Wrote savefile for '$livelist' to: $IPSET_DIR/$livelist.save"
log "Added $(wc -l < "$ipfile") to ipset '$livelist'"
}
}
#### Updates the given blocklist from an URL
function update_blocklist() {
{
# Download blocklist
log "Updating blacklist '$1' ..." # $1 Name of the blocklist
log_verbose "Downloading blocklist '$1' from: $2 ..." # $2 URL of the blocklist
tempfile=$(mktemp "/tmp/blocklist.$1.XXXXXXXX")
wget -q -O "$tempfile" "$2"
# Check downloaded list
linecount=$(wc -l < "$tempfile")
if [ "$linecount" -lt 10 ]; then
log_error "Blacklist '$1' containes only $linecount lines. This seems to short. Exiting..."
exit 1
fi
# Extract ips from raw list data
if [[ $IPV4 -eq 1 ]]; then
grep -v '^[#;]' "$tempfile" | grep -E -o "$IPV4_REGEX" | cut -d ' ' -f 1 > "$tempfile.filtered"
numips=$(wc -l < "$tempfile.filtered")
log_verbose "Got $numips IPv4 entries from blocklist '$1'"
if [[ $numips -gt 0 ]]; then
update_ipset "${IPSET_PREFIX}-$1" "$tempfile.filtered" "inet"
else
log_verbose "No IPv4 addresses found in blocklist '$1'. Skipping"
fi
fi
if [[ $IPV6 -eq 1 ]]; then
grep -v '^[#;]' "$tempfile" | grep -E -o "$IPV6_REGEX" | cut -d ' ' -f 1 > "$tempfile.filtered6"
numips=$(wc -l < "$tempfile.filtered6")
log_verbose "Got $numips IPv6 entries from blocklist '$1'"
if [[ $numips -gt 0 ]]; then
update_ipset "${IPSET_PREFIX}-$1" "$tempfile.filtered6" "inet6"
else
log_verbose "No IPv6 addresses found in blocklist '$1'. Skipping"
fi
fi
# Cleanup
rm "$tempfile"*
}
}
#### Main loop
function main() {
{
# Check arguments
validate_blocklists
# Update blocklists
for list in "${BLOCKLISTS[@]}"; do
list_name=$(echo "$list" | cut -d ' ' -f 1)
list_url=$(echo "$list" | cut -d ' ' -f 2)
update_blocklist "$list_name" "$list_url"
done
}
}
# Parse arguments
while getopts ":hqv46l:" opt
do
case ${opt} in
l) BLOCKLISTS[${#BLOCKLISTS[@]}]=${OPTARG}
;;
4) IPV4=1
IPV6=0
log "Using IPv4 only mode. Skipping IPv6 addresses."
;;
6) IPV4=0
IPV6=1
log "Using IPv6 only mode. Skipping IPv4 addresses."
;;
q) QUIET=1
;;
v) VERBOSE=1
;;
h) print_usage; exit
;;
:) print_usage; exit
;;
\?) print_usage; exit
;;
esac
done
#### Main function call
main

View File

@ -0,0 +1,332 @@
#!/bin/bash
# Where we keep all the blacklists.
iproute=$(ip route get 8.8.8.8 | awk -- '{print $5}')
BL_DIR="/var/lib/ipset"
if [ ! -d $BL_DIR ]; then
mkdir -p $BL_DIR
else
echo "Unable to create $BL_DIR"
fi
if [ ! "$(command -v ipset)" ]; then
dnf install ipset
else
echo 'Unable find or install ipset'
fi
# Some hosting services such as RamNode will ban you for using > 90% of the cpu!!!
# So we recommend installing cpulimit and limiting to 20% of cpu usage when
# calling this script.
#
## cpulimit -z -l 20 /usr/local/bin/blacklists.sh
# cpulimit dosn't like scripts writing to stdout/stderr so them redirect to
# an output file.
#
exec >$BL_DIR/blocklists.out 2>&1
SCRIPT_NAME=$0
HOST_NAME=$(uname -n)
# default syslog messages priority and tag.
LOG_PRI="local0.notice"
LOG_TAG="[$SCRIPT_NAME]"
# Set to empty string if you don't want error emails. Otherwise, set to an admin email.
MAIL_ADMIN="root"
# Logging is enabled for the following ports this is so we can do later audit checks
# in case we are droping legitimate traffic.
TCP_PORTS="53,80,443"
UDP_PORTS="53"
# If PSAD is installed then block Danger Level = $DL and above attackers
# each time the blacklists are reloaded.
DL=3
# Retrieve new blacklists only when they are older then BL_AGE
BL_AGE="23 hours ago"
#---------------------------------------------------------------------------
# logmessage <msg_text>
logmessage() {
{
MSG="$1"
logger -s -p $LOG_PRI -t "$LOG_TAG" "$MSG"
}
}
# <ips> goodinbadnets
# - returns whitelist <ips> that that are in blacklists.
goodinbadnets() {
{
myips=""
for good in $(ipset list good_ips | grep -E "^[1-9]");
do
myip=$(ipset test bad_nets_n "$good" 2>&1 | grep "is in" | awk '{print $1}')
if [ -n "$myip" ]; then
myips="$myips $myip"
fi
done
echo "$myips"
}
}
# blacklistit <ip/cdr> <listname>
# - blacklists the given <ip/cdr> to bad_nets_n or gad_ips_n
# - also checks if the <ip/cdr> blacklists one of your whitelisted ips, and
# if so it will remove it from the blacklist and warn you.
blacklistit() {
{
IP=$1
LISTNAME=$2
if echo "$IP" | grep -E -q "\/[0-9]+"; then
ipset add bad_nets_n "$IP" -exist
badip=$(goodinbadnets)
if [ -n "$badip" ]; then
error_msg="ERROR Your whitelist IP $badip has been blacklisted in $LISTNAME"
logmessage "$error_msg"
ERROR_MSGS="$ERROR_MSGS\n$error_msg"
ipset del bad_nets_n "$IP"
fi
else
if ipset test good_ips "$IP" 2>/dev/null; then
error_msg="ERROR Your whitelist IP $IP has been blacklisted in $LISTNAME"
logmessage "$error_msg"
ERROR_MSGS="$ERROR_MSGS\n$error_msg"
else
ipset add bad_ips_n "$IP" -exist
fi
fi
}
}
# loadblacklist <name> <url>
# - loads standard form blacklist from <url> website, labels cache files with <name>
loadblacklist() {
{
BL_NAME=$1
BL_URL=$2
BL_FILE="$BL_DIR/$BL_NAME.txt"
if [ ! -f "$BL_FILE" ] || [ "$(date +%s -r "$BL_FILE")" -lt "$(date +%s --date="$BL_AGE")" ]; then
echo "-- getting fresh $BL_NAME from $BL_URL"
wget -q -t 2 --output-document="$BL_FILE" "$BL_URL"
fi
if [ -f "$BL_FILE" ]; then
echo "-- loading $BL_NAME from $BL_FILE"
# strip comments - mac address and ipv6 not supported yet so strip :
awk '{print $1}' "$BL_FILE" | cut -d\; -f1 | cut -d\, -f1 | grep -Ev "^#|^ *$|:" | sed -e "s/[^0-9\.\/]//g" | grep -E "^[0-9]" >"${BL_FILE}".filtered
echo "-- loading $BL_NAME - $(wc -l "${BL_FILE}".filtered) entries"
filter=$(cat "${BL_FILE}".filtered)
for ip in $filter;
do
blacklistit "$ip" "$BL_NAME"
done
fi
}
}
#---------------------------------------------------------------------------
# MAIN
#---------------------------------------------------------------------------
# concatenated list of all error message
ERROR_MSGS=""
if ! which ipset >/dev/null 2>&1; then
echo "ERROR: You must install 'ipset'"
exit 1
fi
logmessage "mylinux.work blocklist script started"
# Create temporary swap ipsets
ipset create bad_ips_n hash:ip hashsize 4096 maxelem 262144 2>/dev/null
ipset flush bad_ips_n
ipset create bad_nets_n hash:net hashsize 4096 maxelem 262144 2>/dev/null
ipset flush bad_nets_n
#
# Setup the active ipsets if they don't yet exist.
# Load them from last save sets to speed up load times in cases of reboot
# and ensure protection faster.
#
if ! ipset list bad_ips >/dev/null 2>&1; then
echo "-- creating bad_ips ipset as does not exist."
ipset create bad_ips hash:ip hashsize 4096 maxelem 262144
if [ -f "$BL_DIR/bad_ips.sav" ]; then
echo "-- importing from save file $BL_DIR/bad_ips.sav"
grep -v "create" $BL_DIR/bad_ips.sav | ipset restore
fi
fi
if ! ipset list bad_nets >/dev/null 2>&1; then
echo "-- creating bad_nets ipset as does not exist."
ipset create bad_nets hash:net hashsize 4096 maxelem 262144
if [ -f "$BL_DIR/bad_nets.sav" ]; then
echo "-- importing from save file $BL_DIR/bad_nets.sav"
grep -v "create" $BL_DIR/bad_nets.sav | ipset restore
fi
fi
#
# Setup our firewall ip chains
#
if ! iptables -L ftmon-blacklists -n >/dev/null 2>&1; then
echo "-- creating iptables rules for first time"
iptables -N ftmon-blacklists
iptables -I INPUT \
-m set --match-set bad_ips src -j ftmon-blacklists
# insert the smaller set first.
iptables -I INPUT \
-m set --match-set bad_nets src -j ftmon-blacklists
# keep a record of our business traffic ports.
# so we can check if we blocked legitimate traffic if need be.
# DNS and http/https are most typical legit ports
iptables -A blocklists -i "$iproute" -p tcp -m multiport --dports $TCP_PORTS -m limit --limit 5/min -j LOG --log-prefix "[BL DROP] "
iptables -A blocklists -i "$iproute" -p udp -m multiport --dport $UDP_PORTS -m limit --limit 5/min -j LOG --log-prefix "[BL DROP] "
iptables -A blocklists -i "$iproute" -m state --state NEW -p tcp -m multiport --dports $TCP_PORTS -j REJECT
iptables -A blocklists -i "$iproute" -m state --state NEW -p udp -m multiport --dports $UDP_PORTS -j REJECT
iptables -A blocklists -i "$iproute" -m state --state NEW -j DROP
fi
# List of ips to whitelist
if ! ipset list good_ips >/dev/null 2>&1; then
ipset create good_ips hash:ip
fi
# load fresh white list each time as the list should be small.
ipset flush good_ips
# load your good ip's
WL_CUSTOM="$BL_DIR/whitelist.txt"
count=0
count1=$(grep -Ev "^#|^ *$" $WL_CUSTOM | sed -e "s/#.*$//" -e "s/[^.0-9\/]//g")
if [ -f "$WL_CUSTOM" ]; then
for ip in $count1; do
ipset add good_ips "$ip" -exist
count=$((count + 1))
done
fi
echo "-- loaded $count entries from $WL_CUSTOM"
# load your personal custom blacklists.
BL_CUSTOM="$BL_DIR/blacklist.txt"
count=0
count2=$(grep -Ev "^#|^ *$" $BL_CUSTOM | sed -e "s/#.*$//" -e "s/[^.0-9\/]//g")
if [ -f "$BL_CUSTOM" ]; then
for ip in $count2; do
blacklistit "$ip" "$BLACKLIST"
count=$((count + 1))
done
fi
echo "-- loaded $(ipset list bad_ips_n | grep -Ec "^[1-9]") entries from blacklist "
echo "-- loaded $count entries from $BL_CUSTOM"
# If PSAD is installed then use some of it's good detection work
# to stop attackers.
count=0
count3=$(awk '{print $2, $1}' /var/log/psad/top_attackers | grep "^[$DL-]" | awk '{print $2}')
if [ -f "/var/log/psad/top_attackers" ]; then
for ip in $count3; do
blacklistit "$ip" "$BLACKLIST"
count=$((count + 1))
done
fi
echo "-- loaded $count entries from /var/log/psad/top_attackers "
#
# Load Standard format blacklists
# Some of them are over zealous, you may want to comment out.
#
# loadblacklist "bl-autoshun-inet" "http://www.autoshun.org/files/shunlist.csv"
loadblacklist "bl-bdsatib-inet" "https://www.binarydefense.com/banlist.txt"
loadblacklist "bl-bfblocker-inet" "http://danger.rulez.sk/projects/bruteforceblocker/blist.php"
loadblacklist "bl-cinsarmy-inet" "http://cinsscore.com/list/ci-badguys.txt"
loadblacklist "bl-drop-inet" "https://www.spamhaus.org/drop/drop.txt"
# loadblacklist "bl-dropv6-inet6" "https://www.spamhaus.org/drop/dropv6.txt"
# loadblacklist "bl-dshield-inet" "https://iplists.firehol.org/files/dshield.netset"
# loadblacklist "bl-dshield-top10-inet" "http://feeds.dshield.org/top10-2.txt"
# loadblacklist "bl-edrop-inet" "https://www.spamhaus.org/drop/edrop.txt"
# loadblacklist "bl-f2ball-inet" "http://lists.blocklist.de/lists/all.txt"
loadblacklist "bl-firehol-inet" "https://iplists.firehol.org/files/firehol_level1.netset"
# loadblacklist "bl-greensnow-inet" "https://blocklist.greensnow.co/greensnow.txt"
# loadblacklist "bl-infiltrated-inet" "http://www.infiltrated.net/blacklisted"
# loadblacklist "bl-ipsec-inet" "http://doc.emergingthreats.net/pub/Main/RussianBusinessNetwork/RussianBusinessNetworkIPs.txt"
loadblacklist "bl-ipsum-inet" "https://raw.githubusercontent.com/stamparm/ipsum/master/levels/2.txt"
# loadblacklist "bl-maxmind-inet" "https://www.maxmind.com/en/anonymous_proxies"
# loadblacklist "bl-openbl-inet" "http://www.openbl.org/lists/base.txt"
# loadblacklist "bl-torexitnodes-inet" "https://check.torproject.org/cgi-bin/TorBulkExitList.py?ip=1.1.1.1"
# loadblacklist "bl-shlasso-inet" "http://www.spamhaus.org/drop/drop.lasso"
#
# bot nets
#
# https://palevotracker.abuse.ch/blocklists.php
# loadblacklist "bl-palevo-inet" "https://palevotracker.abuse.ch/blocklists.php?download=ipblocklist"
# https://spyeyetracker.abuse.ch/blocklist.php
# loadblacklist "bl-spyeye-inet" "https://spyeyetracker.abuse.ch/blocklist.php?download=ipblocklist"
# https://zeustracker.abuse.ch/blocklist.php
# loadblacklist "bl-zeus-inet" "https://zeustracker.abuse.ch/blocklist.php?download=badips"
#
# special cases, custom formats blacklists
#
# Obtain List of badguys from dshield.org
# https://isc.sans.edu/feeds_doc.html
BL_NAME="bl-dshield-top10-inet"
BL_URL="http://feeds.dshield.org/top10-2.txt"
BL_FILE="$BL_DIR/$BL_NAME.txt"
if [ ! -f "$BL_FILE" ] || [ "$(date +%s -r "$BL_FILE")" -lt "$(date +%s --date="$BL_AGE")" ]; then
echo "-- getting fresh $BL_NAME from $BL_URL"
wget -q -t 2 --output-document=$BL_FILE $BL_URL
fi
if [ -f "$BL_FILE" ]; then
echo "-- loading $BL_NAME from $BL_FILE"
load=$(grep -E "^[1-9]" $BL_FILE | cut -f1)
for ip in $load; do
blacklistit "$ip" $BL_NAME
done
fi
# swap in the new sets.
ipset swap bad_ips_n bad_ips
ipset swap bad_nets_n bad_nets
# show before and after counts.
complete_msg="bad_ips: current=$(ipset --list bad_ips_n | grep -Ec '^[1-9]') \
previous=$(ipset --list bad_ips | grep -Ec '^[1-9]') \
bad_nets: previous=$(ipset --list bad_nets | grep -Ec '^[1-9]') \
current=$(ipset --list bad_nets_n | grep -Ec '^[1-9]')"
logmessage "$complete_msg"
# only send email if problems.
if [ -n "$MAIL_ADMIN" ] && [ -n "$ERROR_MSGS" ]; then
echo -e "${complete_msg}\n${ERROR_MSGS}" | mail -s "$LOG_TAG $HOST_NAME" $MAIL_ADMIN
fi
# save memory space by destroying the temporary swap ipset
ipset destroy bad_ips_n
ipset destroy bad_nets_n
# save our ipsets for quick import on reboot.
ipset save bad_ips >$BL_DIR/bad_ips.sav
ipset save bad_nets >$BL_DIR/bad_nets.sav
logmessage "mylinux.work blocklist script completed"

View File

@ -0,0 +1,182 @@
#!/bin/bash
# IP blacklisting script for Linux servers
# iptables logging limit
LIMIT="10/minute"
# try to load config file
# it should contain one blacklist URL per line
config_file="/etc/ip-blacklist.conf"
if [ -f "${config_file}" ]; then
# shellcheck source=/dev/null
source ${config_file}
else
# if no config file is available, load default set of blacklists
# URLs for further blocklists are appended using the classical
# shell syntax: "$URLS new_url"
# Emerging Threats lists offensive IPs such as botnet command servers
URLS="https://danger.rulez.sk/projects/bruteforceblocker/blist.php"
# Blocklist.de collects reports from fail2ban probes, listing password brute-forces, scanners and other offenders
URLS="$URLS https://cinsscore.com/list/ci-badguys.txt"
# badips.com, from score 2 up
URLS="$URLS https://www.spamhaus.org/drop/drop.txt"
URLS="$URLS https://iplists.firehol.org/files/firehol_level1.netset"
URLS="$URLS https://raw.githubusercontent.com/stamparm/ipsum/master/levels/2.txt"
# iblocklist.com is also supported
# URLS="$URLS http://list.iblocklist.com/?list=srzondksmjuwsvmgdbhi&fileformat=p2p&archiveformat=gz&username=USERNAMEx$&pin=PIN"
fi
link_set() {
if [ "$3" = "log" ]; then
iptables -A "$1" -m set --match-set "$2" src,dst -m limit --limit "$LIMIT" -j LOG --log-prefix "BLOCK $2 "
fi
iptables -A "$1" -m set --match-set "$2" src -j DROP
iptables -A "$1" -m set --match-set "$2" dst -j DROP
}
# This is how it will look like on the server
# Chain blocklists (2 references)
# pkts bytes target prot opt in out source destination
# 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 match-set manual-blacklist src,dst limit: avg 10/min burst 5 LOG flags 0 level 4 prefix "BLOCK manual-blacklist "
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set manual-blacklist src,dst
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set rules.emergingthreats src
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set rules.emergingthreats dst
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.blocklist.de src
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.blocklist.de dst
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.badips.com src
# 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 match-set www.badips.com dst
blocklist_chain_name=blocklists
# check for dependencies - ipset and curl
if [ -z "$(which ipset 2>/dev/null)" ]; then
echo "Cannot find ipset"
echo "Run \"apt-get install ipset\" (Debian/Ubuntu) or \"yum install ipset\" (RedHat/CentOS/Fedora) or \"opkg install ipset\" (OpenWRT/LEDE)"
exit 1
fi
if [ -z "$(which curl 2>/dev/null)" ]; then
echo "Cannot find curl"
echo "Run \"apt-get install curl\" (Debian/Ubuntu) or \"yum install curl\" (RedHat/CentOS/Fedora) or \"opkg install curl\" (OpenWRT/LEDE)"
exit 1
fi
# check if we are on OpenWRT
if [ "$(which uci 2>/dev/null)" ]; then
# we're on OpenWRT
wan_iface=pppoe-wan
IN_OPT="-i $wan_iface"
INPUT=input_rule
FORWARD=forwarding_rule
COMPRESS_OPT=""
else
COMPRESS_OPT="--compressed"
INPUT=INPUT
FORWARD=FORWARD
fi
# create main blocklists chain
if ! iptables -nL | grep -q "Chain ${blocklist_chain_name}"; then
iptables -N ${blocklist_chain_name}
fi
# inject references to blocklist in the beginning of input and forward chains
if ! iptables -nL ${INPUT} | grep -q ${blocklist_chain_name}; then
iptables -I ${INPUT} 1 "${IN_OPT}" -j ${blocklist_chain_name}
fi
if ! iptables -nL ${FORWARD} | grep -q ${blocklist_chain_name}; then
iptables -I ${FORWARD} 1 "${IN_OPT}" -j ${blocklist_chain_name}
fi
# flush the chain referencing blacklists, they will be restored in a second
iptables -F ${blocklist_chain_name}
# create the "manual" blacklist set
# this can be populated manually using ipset command:
# ipset add manual-blacklist a.b.c.d
set_name="manual-blacklist"
if ! ipset list | grep -q "Name: ${set_name}"; then
ipset create "${set_name}" hash:net
fi
link_set "${blocklist_chain_name}" "${set_name}" "$1"
# download and process the dynamic blacklists
for url in $URLS; do
# initialize temp files
unsorted_blocklist=$(mktemp)
sorted_blocklist=$(mktemp)
new_set_file=$(mktemp)
headers=$(mktemp)
# download the blocklist
set_name=$(echo "$url" | awk -F/ '{print substr($3,0,21);}') # set name is derived from source URL hostname
curl -L -v -s ${COMPRESS_OPT} -k "$url" >"${unsorted_blocklist}" 2>"${headers}"
# this is required for blocklist.de that sends compressed content regardless of asked or not
if [ -z "$COMPRESS_OPT" ]; then
if grep -qi 'content-encoding: gzip' "${headers}"; then
mv "${unsorted_blocklist}" "${unsorted_blocklist}.gz"
gzip -d "${unsorted_blocklist}.gz"
fi
fi
# autodetect iblocklist.com format as it needs additional conversion
if echo "${url}" | grep -q 'iblocklist.com'; then
if [ -f /etc/range2cidr.awk ]; then
mv "${unsorted_blocklist}" "${unsorted_blocklist}.gz"
gzip -d "${unsorted_blocklist}.gz"
awk_tmp=$(mktemp)
awk -f /etc/range2cidr.awk <"${unsorted_blocklist}" >"${awk_tmp}"
mv "${awk_tmp}" "${unsorted_blocklist}"
else
echo "/etc/range2cidr.awk script not found, cannot process ${unsorted_blocklist}, skipping"
continue
fi
fi
sort -u <"${unsorted_blocklist}" | grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(/[0-9]{1,2})?$" >"${sorted_blocklist}"
# calculate performance parameters for the new set
if [ "${RANDOM}" ]; then
# bash
tmp_set_name="tmp_${RANDOM}"
else
# non-bash
tmp_set_name="tmp_$$"
fi
new_list_size=$(wc -l "${sorted_blocklist}" | awk '{print $1;}')
hash_size=$(("$new_list_size" / 2))
if ! ipset -q list "${set_name}" >/dev/null; then
ipset create "${set_name}" hash:net family inet
fi
# start writing new set file
echo "create ${tmp_set_name} hash:net family inet hashsize ${hash_size} maxelem ${new_list_size}" >>"${new_set_file}"
# convert list of IPs to ipset statements
while read -r line; do
echo "add ${tmp_set_name} ${line}" >>"${new_set_file}"
done <"$sorted_blocklist"
# replace old set with the new, temp one - this guarantees an atomic update
echo "swap ${tmp_set_name} ${set_name}" >>"${new_set_file}"
# clear old set (now under temp name)
echo "destroy ${tmp_set_name}" >>"${new_set_file}"
# actually execute the set update
ipset -! -q restore <"${new_set_file}"
link_set "${blocklist_chain_name}" "${set_name}" "$1"
# clean up temp files
rm "${unsorted_blocklist}" "${sorted_blocklist}" "${new_set_file}" "${headers}"
done

View File

@ -1,80 +1,189 @@
#!/bin/bash
# ##################################################
# ufw-ipset-blocklist-autoupdate
#
# Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org)
#
# Version: 1.1.1
#
# See: https://github.com/ngandrass/ufw-ipset-blocklist-autoupdate
#
#
# MIT License
#
# Copyright (c) 2023 Niels Gandraß <niels@gandrass.de>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ##################################################
IPSET_BIN="$(which ipset)"
IPSET_DIR="/var/lib/ipset"
#### Variables ####
iproute=$(ip route get 8.8.8.8 | awk -- '{print $5}')
seedlist_dir=/var/lib/ipset
blists=$(find "$seedlist_dir" -name "*-inet.save")
# Check prerequisites
if [ ! -x "${IPSET_BIN}" ]; then
echo "ERROR: ipset binary not found in ${IPSET_BIN}"
return
#### Check for IPset ###
if [ ! "$(command -v /usr/sbin/ipset)" ]; then
echo "ERROR: ipset binary not found in path"
exit 2
fi
if [ ! -d "${IPSET_DIR}" ]; then
echo "ERROR: ipset data directory does not exist: ${IPSET_DIR}" >&2
return
fi
chain_exists() {
{
[ $# -lt 1 ] || [ $# -gt 2 ] && {
echo "Usage: chain_exists <chain_name>" >&2
exit 1
}
savefiles=$(find "$IPSET_DIR" -name "*-inet.save")
chain_name="$1"
shift
[ $# -eq 1 ]
iptables -n -L "$chain_name" >/dev/null 2>&1
}
}
list_exists() {
{
[ $# -ne 1 ] && {
echo "Usage: list_exists <list_name>" >&2
exit 1
}
list_name="$1"
ipset list "$list_name" -name >/dev/null 2>&1
}
}
#### Command Line Options ####
case "$1" in
start)
for f in $savefiles; do
listname=$(basename -s ".save" "$f")
for sl in $blists
do
listdir=$(basename -s ".save" "$sl")
#### Check for SeedList Dir ####
if [ ! -d "$seedlist_dir" ]; then
echo "ERROR: Seedlist directory does not exist" >&2
exit 2
fi
$IPSET_BIN restore -! <"$f"
iptables -I INPUT -m set --match-set "$listname" src -j DROP
iptables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] "
ipset restore -! < "$sl"
for i in $listdir
do
if chain_exists "$i"-input; then
iptables -D INPUT -i "$iproute" -m set --match-set "$listdir" src -j "$listdir"-input || true
iptables -D "$listdir"-input -i "$iproute" -j DROP -m comment --comment "$listdir"-input || true
iptables -F "$listdir"-input
iptables -X "$listdir"-input
fi
iptables -N "$listdir"-input
iptables -A "$listdir"-input -i "$iproute" -j DROP -m comment --comment "$listdir"-input
iptables -I INPUT -i "$iproute" -m set --match-set "$listdir" src -j "$listdir"-input
done
for i in $listdir
do
if chain_exists "$i"-output; then
iptables -D OUTPUT -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-output || true
iptables -D "$listdir"-output -j DROP -m comment --comment "$listdir"-output || true
iptables -F "$listdir"-output
iptables -X "$listdir"-output
fi
iptables -N "$listdir"-output
iptables -A "$listdir"-output -j DROP -m comment --comment "$listdir"-output
iptables -I OUTPUT -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-output
done
for i in $listdir
do
if chain_exists "$i"-forward; then
iptables -D FORWARD -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-forward || true
iptables -D "$listdir"-forward -i "$iproute" -j DROP -m comment --comment "$listdir"-forward || true
iptables -F "$listdir"-forward
iptables -X "$listdir"-forward
fi
iptables -N "$listdir"-forward
iptables -A "$listdir"-forward -i "$iproute" -j DROP -m comment --comment "$listdir"-forward
iptables -I FORWARD -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-forward
done
done
;;
stop)
for f in $savefiles; do
listname=$(basename -s ".save" "$f")
for sl in $blists
do
listdir=$(basename -s ".save" "$sl")
#### Check for SeedList Dir ####
if [ ! -d "$seedlist_dir" ]; then
echo "ERROR: ipset data directory does not exist" >&2
exit 2
fi
iptables -D INPUT -m set --match-set "$listname" src -j DROP || true
iptables -D INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " || true
$IPSET_BIN destroy -q "$listname" || true
done
for i in $listdir
do
if chain_exists "$i"-input; then
iptables -D INPUT -i "$iproute" -m set --match-set "$listdir" src -j "$listdir"-input || true
iptables -D "$listdir"-input -i "$iproute" -j DROP -m comment --comment "$listdir"-input || true
iptables -F "$listdir"-input
iptables -X "$listdir"-input
fi
done
for i in $listdir
do
if chain_exists "$i"-output; then
iptables -D OUTPUT -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-output || true
iptables -D "$listdir"-output -o "$iproute"-j DROP -m comment --comment "$listdir"-output || true
iptables -F "$listdir"-output
iptables -X "$listdir"-output
fi
done
for i in $listdir
do
if chain_exists "$i"-forward; then
iptables -D FORWARD -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-forward || true
iptables -D "$listdir"-forward -o "$iproute" -j DROP -m comment --comment "$listdir"-forward || true
iptables -F "$listdir"-forward
iptables -X "$listdir"-forward
fi
done
for i in $listdir
do
if list_exists "$i"; then
ipset flush "$listdir"
ipset destroy -q "$listdir" || true
fi
done
done
;;
status)
echo "= after.init ="
$IPSET_BIN -t list
# show iptables hit/byte counts
iptables -L -nvx | grep "$listname" | grep 'match-set'
echo '= after.init Blocklist(s) Status ='
ipset -t list
# show iptables block/byte counts
echo ''
echo 'Total Block/Byte Counts by List Inbound'
echo ''
iptables -L -nvx | grep "$listdir" | grep 'match-set' | grep input | awk 'BEGIN{print "Pkts Bytes Blocklist Prot Opt In Out Source Destination"}1' | column -t
echo ""
echo 'Total Block/Byte Counts by List Outbound'
echo ''
iptables -L -nvx | grep "$listdir" | grep 'match-set' | grep output | awk 'BEGIN{print "Pkts Bytes Blocklist Prot Opt In Out Source Destination"}1' | column -t
echo ""
echo 'Total Block/Byte Counts by List Forwarded'
echo ''
iptables -L -nvx | grep "$listdir" | grep 'match-set' | grep forward | awk 'BEGIN{print "Pkts Bytes Blocklist Prot Opt In Out Source Destination"}1' | column -t
;;
reset-count)
echo '= after.init is resetting the Block/Byte Counts ='
# reset iptables blocklist pkts/bytes
ipi=$( iptables -L INPUT -nvx --line-numbers | grep bl-| awk '{print $1}')
for i in $ipi
do
iptables -Z INPUT "$i"
done
ipo=$( iptables -L OUTPUT -nvx --line-numbers | grep bl- | awk '{print $1}')
for i in $ipo
do
iptables -Z OUTPUT "$i"
done
ipf=$( iptables -L FORWARD -nvx --line-numbers | grep bl-| awk '{print $1}')
for i in $ipf
do
iptables -Z FORWARD "$i"
done
;;
*)
echo "'$1' not supported"
echo "Usage: after.init {start|stop|status}"
echo "'$1' is not supported"
echo 'Usage: /etc/ufw/after.init {start|stop|status|reset-count}'
;;
esac

View File

@ -1,93 +1,189 @@
#!/bin/sh
# ##################################################
# ufw-ipset-blocklist-autoupdate
#
# Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org)
#
# Version: 1.1.1
#
# See: https://github.com/ngandrass/ufw-ipset-blocklist-autoupdate
#
#
# MIT License
#
# Copyright (c) 2023 Niels Gandraß <niels@gandrass.de>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ##################################################
IPSET_BIN="$(which ipset)"
IPSET_DIR="/var/lib/ipset"
#### Variables ####
iproute=$(ip route get 2001:4860:4860::8888 | awk -- '{print $7}')
seedlist_dir=/var/lib/ipset
blists=$(find "$seedlist_dir" -name "*-inet6.save")
# Check prerequisites
if [ ! -x "${IPSET_BIN}" ]; then
echo "ERROR: ipset binary not found in ${IPSET_BIN}"
return
#### Check for IPset ###
if [ ! "$(command -v /usr/sbin/ipset)" ]; then
echo "ERROR: ipset binary not found in path"
exit 2
fi
if [ ! -d "${IPSET_DIR}" ]; then
echo "ERROR: ipset data directory does not exist: ${IPSET_DIR}" >&2
return
fi
chain_exists() {
{
[ $# -lt 1 ] || [ $# -gt 2 ] && {
echo "Usage: chain_exists <chain_name>" >&2
exit 1
}
savefiles=$(find "$IPSET_DIR" -name "*-inet\.save")
savefiles6=$(find "$IPSET_DIR" -name "*-inet6\.save")
chain_name="$1"
shift
[ $# -eq 1 ]
ip6tables -n -L "$chain_name" >/dev/null 2>&1
}
}
list_exists() {
{
[ $# -ne 1 ] && {
echo "Usage: list_exists <list_name>" >&2
exit 1
}
list_name="$1"
ipset list "$list_name" -name >/dev/null 2>&1
}
}
#### Command Line Options ####
case "$1" in
start)
for f in $savefiles; do
listname=$(basename -s ".save" "$f")
for f in $blists
do
listdir=$(basename -s ".save" "$f")
#### Check for SeedList Dir ####
if [ ! -d "$seedlist_dir" ]; then
echo "ERROR: Seedlist directory does not exist" >&2
exit 2
fi
$IPSET_BIN restore -! <"$f"
iptables -I INPUT -m set --match-set "$listname" src -j DROP
iptables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] "
done
for f in $savefiles6; do
listname=$(basename -s ".save" "$f")
ipset restore -! < "$f"
$IPSET_BIN restore -! <"$f"
ip6tables -I INPUT -m set --match-set "$listname" src -j DROP
ip6tables -I INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] "
for i in $listdir
do
if chain_exists "$i"-input; then
ip6tables -D INPUT -i "$iproute" -m set --match-set "$listdir" src -j "$listdir"-input || true
ip6tables -D "$listdir"-input -i "$iproute" -j DROP -m comment --comment "$listdir"-input || true
ip6tables -F "$listdir"-input
ip6tables -X "$listdir"-input
fi
ip6tables -N "$listdir"-input
ip6tables -A "$listdir"-input -i "$iproute" -j DROP -m comment --comment "$listdir"-input
ip6tables -I INPUT -i "$iproute" -m set --match-set "$listdir" src -j "$listdir"-input
done
for i in $listdir
do
if chain_exists "$i"-output; then
ip6tables -D OUTPUT -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-output || true
ip6tables -D "$listdir"-output -j DROP -m comment --comment "$listdir"-output || true
ip6tables -F "$listdir"-output
ip6tables -X "$listdir"-output
fi
ip6tables -N "$listdir"-output
ip6tables -A "$listdir"-output -j DROP -m comment --comment "$listdir"-output
ip6tables -I OUTPUT -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-output
done
for i in $listdir
do
if chain_exists "$i"-forward; then
ip6tables -D FORWARD -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-forward || true
ip6tables -D "$listdir"-forward -o "$iproute" -j DROP -m comment --comment "$listdir"-forward || true
ip6tables -F "$listdir"-forward
ip6tables -X "$listdir"-forward
fi
ip6tables -N "$listdir"-forward
ip6tables -A "$listdir"-forward -o "$iproute" -j DROP -m comment --comment "$listdir"-forward
ip6tables -I FORWARD -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-forward
done
done
;;
stop)
for f in $savefiles; do
listname=$(basename -s ".save" "$f")
for f in $blists
do
listdir=$(basename -s ".save" "$f")
#### Check for SeedList Dir ####
if [ ! -d "$seedlist_dir" ]; then
echo "ERROR: ipset data directory does not exist" >&2
exit 2
fi
iptables -D INPUT -m set --match-set "$listname" src -j DROP || true
iptables -D INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " || true
$IPSET_BIN destroy -q "$listname" || true
done
for f in $savefiles6; do
listname=$(basename -s ".save" "$f")
for i in $listdir
do
if chain_exists "$i"-input; then
ip6tables -D INPUT -i "$iproute" -m set --match-set "$listdir" src -j "$listdir"-input || true
ip6tables -D "$listdir"-input -i "$iproute" -j DROP -m comment --comment "$listdir"-input || true
ip6tables -F "$listdir"-input
ip6tables -X "$listdir"-input
fi
done
ip6tables -D INPUT -m set --match-set "$listname" src -j DROP || true
ip6tables -D INPUT -m set --match-set "$listname" src -j LOG --log-prefix "[UFW BLOCK $listname] " || true
$IPSET_BIN destroy -q "$listname" || true
done
for i in $listdir
do
if chain_exists "$i"-output; then
ip6tables -D OUTPUT -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-output || true
ip6tables -D "$listdir"-output -o "$iproute" -j DROP -m comment --comment "$listdir"-output || true
ip6tables -F "$listdir"-output
ip6tables -X "$listdir"-output
fi
done
for i in $listdir
do
if chain_exists "$i"-forward; then
ip6tables -D FORWARD -o "$iproute" -m set --match-set "$listdir" dst -j "$listdir"-forward || true
ip6tables -D "$listdir"-forward -o "$iproute" -j DROP -m comment --comment "$listdir"-forward || true
ip6tables -F "$listdir"-forward
ip6tables -X "$listdir"-forward
fi
done
for i in $listdir
do
if list_exists "$i"; then
ipset flush "$listdir"
ipset destroy -q "$listdir" || true
fi
done
done
;;
status)
echo "= after.init ="
$IPSET_BIN -t list
echo '= after.init Blocklist(s) Status ='
ipset -t list
#### show ip6tables block/byte counts ####
echo ''
echo 'Total Block/Byte Counts by List Inbound'
echo ''
ip6tables -L -nvx | grep "$listdir" | grep 'match-set' | grep input | awk 'BEGIN{print "Pkts Bytes Blocklist Prot Opt In Out Source Destination"}1' | column -t
echo ""
echo 'Total Block/Byte Counts by List Outbound'
echo ''
ip6tables -L -nvx | grep "$listdir" | grep 'match-set' | grep output | awk 'BEGIN{print "Pkts Bytes Blocklist Prot Opt In Out Source Destination"}1' | column -t
echo ""
echo 'Total Block/Byte Counts by List Forwarded'
echo ''
ip6tables -L -nvx | grep "$listdir" | grep 'match-set' | grep forward | awk 'BEGIN{print "Pkts Bytes Blocklist Prot Opt In Out Source Destination"}1' | column -t
;;
reset-count)
echo '= after.init is resetting the Block/Byte Counts ='
#### reset ip6tables blocklist counts ####
ipi=$( ip6tables -L INPUT -nvx --line-numbers | grep bl-| awk '{print $1}')
for i in $ipi
do
ip6tables -Z INPUT "$i"
done
ipo=$( ip6tables -L OUTPUT -nvx --line-numbers | grep bl- | awk '{print $1}')
for i in $ipo
do
ip6tables -Z OUTPUT "$i"
done
ipf=$( ip6tables -L FORWARD -nvx --line-numbers | grep bl-| awk '{print $1}')
for i in $ipf
do
ip6tables -Z FORWARD "$i"
done
;;
*)
echo "'$1' not supported"
echo "Usage: after.init {start|stop|status}"
echo "'$1' is not supported"
echo 'Usage: /etc/ufw/after.init {start|stop|status|reset-count}'
;;
esac

View File

@ -0,0 +1,71 @@
#! /bin/bash
#### Variables
seedlist_dir=/var/lib/ipset
update=/usr/local/bin/ufw-blocklists.sh
blists=$(find "$seedlist_dir" -name "*-inet.save")
blists6=$(find "$seedlist_dir" -name "*-inet6.save")
#### Check for SeedList Dir ####
if [ ! -d "$seedlist_dir" ]; then
echo "ERROR: ipset data directory does not exist" >&2
exit 2
fi
#### Update Ipv4 Blocklist ####
for seeds in $blists
do
seedlists=$(basename -s ".save" "$seeds")
if [ "$seedlists" = bl-bdsatib-inet ]; then
$update -l "bdsatib https://www.binarydefense.com/banlist.txt"
fi
if [ "$seedlists" = bl-bfblocker-inet ]; then
$update -l "bfblocker https://danger.rulez.sk/projects/bruteforceblocker/blist.php"
fi
if [ "$seedlists" = bl-cinsarmy-inet ]; then
$update -l "cinsarmy http://cinsscore.com/list/ci-badguys.txt"
fi
if [ "$seedlists" = bl-drop-inet ]; then
$update -l "drop https://www.spamhaus.org/drop/drop.txt"
fi
if [ "$seedlists" = bl-dshield-inet ]; then
$update -l "dshield https://iplists.firehol.org/files/dshield.netset"
fi
if [ "$seedlists" = bl-edrop-inet ]; then
$update -l "edrop https://www.spamhaus.org/drop/edrop.txt"
fi
if [ "$seedlists" = bl-f2ball-inet ]; then
$update -l "f2ball https://lists.blocklist.de/lists/all.txt"
fi
if [ "$seedlists" = bl-firehol1-inet ]; then
$update -l "firehol1 https://iplists.firehol.org/files/firehol_level1.netset"
fi
if [ "$seedlists" = bl-greensnow-inet ]; then
$update -l "greensnow https://blocklist.greensnow.co/greensnow.txt"
fi
if [ "$seedlists" = bl-ipsuml2-inet ]; then
$update -l "ipsuml2 https://raw.githubusercontent.com/stamparm/ipsum/master/levels/2.txt"
fi
if [ "$seedlists" = bl-maxmind-inet ]; then
$update -l "maxmind https://www.maxmind.com/en/anonymous_proxies"
fi
done
#### Update Ipv6 Blocklist ####
for seeds in $blists6
do
seedlists=$(basename -s ".save" "$seeds")
if [ "$seedlists" = bl-dropv6-inet ]; then
$update -l "dropv6 https://www.spamhaus.org/drop/dropv6.txt"
fi
done

View File

@ -0,0 +1,26 @@
#! /bin/bash
#### Variables ####
seedlist_dir=/var/lib/ipset
update=/usr/local/bin/ufw-blocklists.sh
blists=$(find "$seedlist_dir" -name "*-inet.save")
#### Check for SeedList Dir ####
if [ ! -d "$seedlist_dir" ]; then
echo "ERROR: ipset data directory does not exist" >&2
exit 2
fi
#### Update Loop ####
for seeds in $blists
do
seedlists=$(basename -s ".save" "$seeds")
if [ "$seedlists" = bl-feodoc2-inet ]; then
$update -l "feodoc2 https://feodotracker.abuse.ch/downloads/ipblocklist_recommended.txt"
fi
if [ "$seedlists" = bl-feodoc2ioc-inet ]; then
$update -l "feodoc2ioc https://feodotracker.abuse.ch/downloads/ipblocklist.txt"
fi
done

View File

@ -36,7 +36,7 @@ chain_exists() {
return 1
}
local chain_name="$1" ; shift
chain_name="$1" ; shift
[ $# -eq 1 ] && local table="--table $1"
iptables "$table" -n --list "$chain_name" >/dev/null 2>&1
}

View File

@ -1,17 +1,7 @@
#!/usr/bin/env bash
# ##################################################
# ufw-ipset-blocklist-autoupdate
#
# Blocking lists of IPs from public blocklists / blacklists (e.g. blocklist.de, spamhaus.org)
#
# Version: 1.1.1
#
# See: https://github.com/ngandrass/ufw-ipset-blocklist-autoupdate
# ##################################################
IPSET_BIN="/usr/bin/ipset" # Path to ipset binary. Updated by detect_ipset().
IPSET_DIR="/var/lib/ipset" # Folder to write ipset save files to
IPSET_PREFIX="bl" # Prefix for ipset names
IPSET_TYPE="hash:net" # Type of created ipsets
IPV4=1 # Enable IPv4 by default
@ -22,6 +12,18 @@ declare -A BLOCKLISTS # Array for blocklists to use. Populated by CLI args
IPV4_REGEX="(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(/[1-3]?[0-9])?" # Regex for a valid IPv4 address with optional subnet part
IPV6_REGEX="(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(/[1-6]?[0-9])?" # Regef for a valid IPv6 address with optional subnet part
if [ ! "$(command -v ipset)" ]; then
apt -y install ipset
else
IPSET_BIN=$(command -v ipset)
fi
if [ ! -d "/var/lib/ipset" ]; then
mkdir -p /var/lib/ipset
else
IPSET_DIR="/var/lib/ipset" # Folder to write ipset save files to
fi
##
# Prints the help/usage message
##
@ -48,12 +50,7 @@ EOF
}
}
##
# Writes argument $1 to stdout if $QUIET is not set
#
# Arguments:
# $1 Message to write to stdout
##
#### Writes argument $1 to stdout if $QUIET is not set
function log() {
{
if [[ $QUIET -eq 0 ]]; then
@ -62,12 +59,7 @@ function log() {
}
}
##
# Writes argument $1 to stdout if $VERBOSE is set and $QUIET is not set
#
# Arguments:
# $1 Message to write to stdout
##
#### Writes argument $1 to stdout if $VERBOSE is set and $QUIET is not set
function log_verbose() {
{
if [[ $VERBOSE -eq 1 ]]; then
@ -78,38 +70,14 @@ function log_verbose() {
}
}
##
# Writes argument $1 to stderr. Ignores $QUIET.
#
# Arguments:
# $1 Message to write to stderr
##
#### Writes argument $1 to stderr. Ignores $QUIET.
function log_error() {
{
>&2 echo "[ERROR]: $1"
}
}
##
# Detects ipset binary
#
# Return: Path to ipset
#
function detect_ipset() {
{
IPSET_BIN=$(which ipset)
if [ ! -x "${IPSET_BIN}" ]; then
log_error "ipset binary not found."
exit 1
fi
echo "${IPSET_BIN}"
}
}
##
# Validates the correctness of the BLOCKLISTS array. Exits upon error.
#
#### Validates the BLOCKLISTS array. Exits upon error.
function validate_blocklists() {
{
if [ ${#BLOCKLISTS[@]} -eq 0 ]; then
@ -138,23 +106,17 @@ function validate_blocklists() {
}
}
##
# Updates an ipset based on a list of IP addresses
#
# Arguments:
# $1 Name of the ipset to update
# $2 File containing all IP addresses to store in ipset
# $3 Procotol family (e.g. inet OR inet6)
#### Updates an ipset based on a list of IP addresses
function update_ipset() {
{
# Setup local vars
local setname=$1
local ipfile=$2
local family=$3
setname=$1 # $1 Name of the ipset to update
ipfile=$2 # $2 File containing all IP addresses to store in ipset
family=$3 # $3 Procotol family (e.g. inet OR inet6)
# Create temporary ipset to build and ensure existence of live ipset
local livelist="$setname-$family"
local templist="$setname-$family-T"
livelist="$setname-$family"
templist="$setname-$family-T"
$IPSET_BIN create -q "$livelist" "$IPSET_TYPE" family "$family"
$IPSET_BIN create -q "$templist" "$IPSET_TYPE" family "$family"
@ -181,18 +143,12 @@ function update_ipset() {
}
}
##
# Updates the given blocklist from an URL
#
# Arguments:
# $1 Name of the blocklist
# $2 URL of the blocklist
#
#### Updates the given blocklist from an URL
function update_blocklist() {
{
# Download blocklist
log "Updating blacklist '$1' ..."
log_verbose "Downloading blocklist '$1' from: $2 ..."
log "Updating blacklist '$1' ..." # $1 Name of the blocklist
log_verbose "Downloading blocklist '$1' from: $2 ..." # $2 URL of the blocklist
tempfile=$(mktemp "/tmp/blocklist.$1.XXXXXXXX")
wget -q -O "$tempfile" "$2"
@ -214,7 +170,9 @@ function update_blocklist() {
else
log_verbose "No IPv4 addresses found in blocklist '$1'. Skipping"
fi
elif [[ $IPV6 -eq 1 ]]; then
fi
if [[ $IPV6 -eq 1 ]]; then
grep -v '^[#;]' "$tempfile" | grep -E -o "$IPV6_REGEX" | cut -d ' ' -f 1 > "$tempfile.filtered6"
numips=$(wc -l < "$tempfile.filtered6")
log_verbose "Got $numips IPv6 entries from blocklist '$1'"
@ -231,23 +189,16 @@ function update_blocklist() {
}
}
##
# Main program loop
##
#### Main loop
function main() {
{
# Check arguments
validate_blocklists
# Setup ipset
IPSET_BIN=$(detect_ipset)
mkdir -p "${IPSET_DIR}"
# Update blocklists
for list in "${BLOCKLISTS[@]}"; do
list_name=$(echo "$list" | cut -d ' ' -f 1)
list_url=$(echo "$list" | cut -d ' ' -f 2)
update_blocklist "$list_name" "$list_url"
done
}
@ -280,5 +231,5 @@ while getopts ":hqv46l:" opt
esac
done
# Entry point
#### Min function call
main

View File

@ -1,5 +1,9 @@
#!/bin/bash
# Variables
LOGFILE=/var/log/auth.log # Log file
LINE=0 # Where to start count
# Install geoiplookup if needed
if [ ! "$(command -v geoiplookup)" ]; then
apt -y install geoip-bin
@ -12,9 +16,6 @@ BY="\033[1;33m" # Bold Yellow
GR="\033[0;32m" # Green
LY="\033[3;33m" # Light Yellow
RB="\033[1;31m" # Red bold (Default)
LOGFILE=/var/log/auth.log # Log file
LINE=0 # Where to start count
NC="\033[00m" # Color Reset
while true
@ -28,7 +29,7 @@ while true
else
LOCATION=$(geoiplookup6 "$i" | awk '{print $6 " " $7}')
fi
echo -e "[*] The Attacker's Country: ${RB}$LOCATION ${NC}[IP ADDRESS:${RB} $i] ${NC}"
echo -e "[*] The Blocked Attacker's Country: ${RB}$LOCATION ${NC}[IP ADDRESS:${RB} $i]${NC}"
done
sleep 2