diff --git a/IPtables Blacklist/blocklists.sh b/IPtables Blacklist/blocklists.sh new file mode 100644 index 0000000..0773431 --- /dev/null +++ b/IPtables Blacklist/blocklists.sh @@ -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 \ No newline at end of file diff --git a/IPtables Blacklist/ipset_blocklist.sh b/IPtables Blacklist/ipset_blocklist.sh new file mode 100644 index 0000000..1842cb8 --- /dev/null +++ b/IPtables Blacklist/ipset_blocklist.sh @@ -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 +logmessage() { + { + MSG="$1" + logger -s -p $LOG_PRI -t "$LOG_TAG" "$MSG" + } +} + +# goodinbadnets +# - returns whitelist 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 +# - blacklists the given to bad_nets_n or gad_ips_n +# - also checks if the 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 +# - loads standard form blacklist from website, labels cache files with +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" diff --git a/IPtables Blacklist/iptables_blacklist.sh b/IPtables Blacklist/iptables_blacklist.sh new file mode 100644 index 0000000..5d2098e --- /dev/null +++ b/IPtables Blacklist/iptables_blacklist.sh @@ -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 diff --git a/UFW-Blocklist/after.init b/UFW-Blocklist/after.init index a92353a..723490c 100644 --- a/UFW-Blocklist/after.init +++ b/UFW-Blocklist/after.init @@ -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ß -# -# 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 " >&2 + exit 1 + } + + chain_name="$1" + shift + [ $# -eq 1 ] + iptables -n -L "$chain_name" >/dev/null 2>&1 + } +} -savefiles=$(find "$IPSET_DIR" -name "*-inet.save") +list_exists() { + { + [ $# -ne 1 ] && { + echo "Usage: list_exists " >&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 diff --git a/UFW-Blocklist/after6.init b/UFW-Blocklist/after6.init index d2b5f3e..a7aca1b 100644 --- a/UFW-Blocklist/after6.init +++ b/UFW-Blocklist/after6.init @@ -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ß -# -# 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 " >&2 + exit 1 + } + + chain_name="$1" + shift + [ $# -eq 1 ] + ip6tables -n -L "$chain_name" >/dev/null 2>&1 + } +} -savefiles=$(find "$IPSET_DIR" -name "*-inet\.save") -savefiles6=$(find "$IPSET_DIR" -name "*-inet6\.save") +list_exists() { + { + [ $# -ne 1 ] && { + echo "Usage: list_exists " >&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 restore -! < "$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 + + 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 - $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_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"-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 +esac \ No newline at end of file diff --git a/UFW-Blocklist/blocklist_update b/UFW-Blocklist/blocklist_update new file mode 100644 index 0000000..0b1a9e6 --- /dev/null +++ b/UFW-Blocklist/blocklist_update @@ -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 \ No newline at end of file diff --git a/UFW-Blocklist/feodobl_update b/UFW-Blocklist/feodobl_update new file mode 100644 index 0000000..e7b7866 --- /dev/null +++ b/UFW-Blocklist/feodobl_update @@ -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 \ No newline at end of file diff --git a/UFW-Blocklist/old_blocklist/after.init b/UFW-Blocklist/old_blocklist/after.init index 749581b..0e88159 100644 --- a/UFW-Blocklist/old_blocklist/after.init +++ b/UFW-Blocklist/old_blocklist/after.init @@ -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 } diff --git a/UFW-Blocklist/ufw-blocklists.sh b/UFW-Blocklist/ufw-blocklists.sh index 8b6ad05..86a01e8 100644 --- a/UFW-Blocklist/ufw-blocklists.sh +++ b/UFW-Blocklist/ufw-blocklists.sh @@ -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,20 +143,14 @@ 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" + wget -q -O "$tempfile" "$2" # Check downloaded list linecount=$(wc -l < "$tempfile") @@ -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 \ No newline at end of file diff --git a/auth-log-lookup.sh b/auth-log-lookup.sh index 9210d91..e23cbe8 100644 --- a/auth-log-lookup.sh +++ b/auth-log-lookup.sh @@ -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 @@ -24,11 +25,11 @@ while true LINE=$(cat $LOGFILE | wc -l) # Detect if IPv4 address for lookups if [ "$i" != "${i#*[0-9].[0-9]}" ]; then - LOCATION=$(geoiplookup "$i" | awk '{print $5 " " $6}') + LOCATION=$(geoiplookup "$i" | awk '{print $5 " " $6}') 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