firewall/firewall.sh
Your Name c46d519bd0 fix
2024-09-30 13:31:39 -06:00

408 lines
11 KiB
Bash
Executable File

#!/bin/bash
DATE="$(date +%d/%b/%Y:%H:%M -d '1 minute ago')"
MY_IP=($(redis-cli --raw SMEMBERS my_ip))
ATTACK_THRESHOLD="50"
NGINX_ACCESS="/tmp/access.log"
ACCESS="/tmp/minute.log"
HTTP_LIMIT="150"
RATE_LIMITED_HTTP="30"
MODULES="/opt/firewall/modules"
TMP_BLOCK_TIMEOUT="45"
grep $DATE $NGINX_ACCESS >$ACCESS
#Firewall Port Configuration
#
declare -A portConfig
portConfig["https"]="443"
portConfig["http"]="80"
portConfig["cups"]="631"
#portConfig["WireGuard"]="57692"
#portConfig["AdGuard-1"]="3000"
#portConfig["AdGuard-2"]="8082"
#portConfig["AdGuard-3"]="853"
#portConfig["akkoma"]="4000"
#portConfig["strfry"]="7777"
#portConfig["DNS-2"]="67"
#portConfig["DNS-3"]="68"
portConfig["CUPS-1"]="631"
portConfig["CUPS-2"]="5353"
#portConfig["Bitcoin-2"]="8332"
#portConfig["Bitcoin-3"]="8333"
#portConfig["Bitcoin-4"]="4050"
#portConfig["KDE-Connect"]="1714-1764"
#portConfig["Lightning-1"]="10009"
#portConfig["Lightning-1"]="9735"
#portConfig["Lightning-2"]="8080"
#portConfig["Lightning-3"]="28334"
#portConfig["Lightning-4"]="28333"
#portConfig["Lightning-5"]="19998"
#portConfig["Lightning-6"]="29000"
portConfig["SyncThing-1"]="22000"
portConfig["SyncThing-2"]="8384"
portConfig["SyncThing-3"]="21027"
#portConfig["NFS-1"]="2049"
#portConfig["NFS-2"]="111"
portConfig["Jellyfin-1"]="8096"
portConfig["Jellyfin-1"]="7359"
portConfig["SSH"]="22"
VIRT_BRIDGE="virbr0"
#### NFT CONFIG ####
#
NFT='/usr/bin/nft'
NFT_CACHE='/tmp/nft.cache'
TMP_BLOCK=($(redis-cli --raw SMEMBERS tmp_block))
TRUST=($(redis-cli --raw SMEMBERS trust))
#Redis DB
#
SAVED_BOTS=($(redis-cli --raw SMEMBERS bots))
CRAWLER_DB=($(redis-cli --raw SMEMBERS crawlers))
SAFE_TRAFFIC=($(redis-cli --raw SMEMBERS safe_traffic))
RULE_SET='/opt/firewall/nft.rules'
MENU_TOP="=============================FireWall================================="
MENU_BOTTOM="====================================================================="
nft list table filter >$NFT_CACHE
ipBlockParser() {
if [[ "$1" == *":"* ]]; then
$NFT insert rule ip6 filter input position 0 ip6 saddr $1 drop
else
$NFT insert rule ip filter input position 0 ip saddr "$1" drop
fi
}
portOpenParser() {
if [[ "$1" == "443" || "$1" == "80" ]]; then
echo "Skipping $1"
else
$NFT add rule ip filter input position 0 tcp dport $1 accept
$NFT add rule ip filter input position 0 udp dport $1 accept
$NFT add rule ip6 filter input position 0 tcp dport $1 accept
$NFT add rule ip6 filter input position 0 udp dport $1 accept
fi
}
ipDeleteParser() {
if [[ "$1" == *":"* ]]; then
$NFT delete rule ip6 filter input handle $HANDLE &>/dev/null
else
$NFT delete rule ip filter input handle $HANDLE &>/dev/null
fi
redis-cli SREM tmp_block $i
redis-cli SREM bots $i
}
blockCountry() {
DATA=($(redis-cli SMEMBERS country_ip))
for i in "${DATA[@]}"; do
echo "Blocking $i"
ipBlockParser $i
done
}
attacker-protection() {
watch
bash $MODULES/module-nostr.sh "$i" "$DATE" "$ACCESS"
bot-search
}
bot-search() {
echo "Searching for Web Crawalers...."
CRAWLERS=($(grep $DATE $ACCESS | grep -vi $MY_IP | grep -vi 127.0.0.1 | grep -Evi 'Guro|spank|report|rape|block' | grep -Ff <(printf '%s\n' "${CRAWLER_DB[@]}") | grep -Fivf <(printf '%s\n' "${SAFE_TRAFFIC[@]}") | cut -d "-" -f1 | sort -u))
echo
echo "Processing Web Crawler list into NFT....."
echo
for i in "${CRAWLERS[@]}"; do
CHECK=$(cat $NFT_CACHE | grep $i)
if [ "$CHECK" = "" ]; then
ipBlockParser $i
redis-cli SADD bots $i
else
echo
echo "Skipping Duplicate IP $i"
echo
fi
done
}
basic-security() {
$NFT flush ruleset
$NFT -f /opt/firewall/ipv4-filter.nft
$NFT -f /opt/firewall/ipv6-filter.nft
$NFT add rule filter input icmp type echo-request drop
$NFT rule filter output accept
$NFT rule filter forward accept
$NFT insert rule filter input ct state established accept
$NFT insert rule filter input iif lo accept
for i in "${!portConfig[@]}"; do
echo "Enabling Port for: $i"
portOpenParser "${portConfig[$i]}"
done
bash $MODULES/module-trust.sh
#$NFT add rule filter input drop
#$NFT add rule ip6 filter input drop
}
virtualization() {
ip link del virbr0
killall dnsmasq
/usr/bin/systemctl restart libvirtd
/usr/bin/virsh net-start default
/usr/bin/systemctl restart pleroma
$NFT insert rule filter input iif $VIRT_BRIDGE accept
}
import-saved() {
for i in "${SAVED_BOTS[@]}"; do
ipBlockParser $i
done
}
start() {
basic-security
sysctl -w net.ipv4.conf.all.forwarding=1
import-saved
blockCountry
docker restart uptime-kuma
#Docker
$NFT insert rule filter input iif docker0 accept
#HTTP Rate Limit
bash $MODULES/module-rate-limit-web.sh $HTTP_LIMIT
message "Starting Firewall"
}
research() {
STATS=($(redis-cli --raw SMEMBERS tmp_block | sort -u))
for i in "${STATS[@]}"; do
echo $MENU_TOP
echo " [Researching $i] "
echo
DATA=$(grep $i $NGINX_LOG | grep -Fivf <(printf '%s\n' "${SAFE_TRAFFIC[@]}"))
echo "$DATA"
echo
echo $MENU_BOTTOM
echo
read -p 'Press Enter to Continue ' -e
done
}
automaticStatus() {
status
sleep 30
automaticStatus
}
status() {
clear
sleep 2
RATE=$(cat $NFT_CACHE | grep 443 | cut -d ' ' -f14 | head -1)
DATE="$(date +%d/%b/%Y:%H:%M -d '1 minute ago')"
STATS=$(grep $DATE $ACCESS | grep -vi $MY_IP | wc -l)
GET=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep GET | wc -l)
POST=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep POST | wc -l)
PUT=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep -i PUT | wc -l)
NOT_FOUND=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep 404 | wc -l)
GATEWAY=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep 502 | wc -l)
SUCCESS=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep 200 | wc -l)
CRAWL=$(grep $DATE $ACCESS | grep -vi $MY_IP | grep -Ff <(printf '%s\n' "${CRAWLER_DB[@]}") | wc -l)
echo $MENU_TOP
echo "Attack Threshold: $ATTACK_THRESHOLD"
echo "Firewall Rules: $($NFT list table filter | wc -l)"
echo "Rate Limit: $RATE"
echo
echo "Traffic Last Minute: $STATS"
echo " GET: $GET"
echo " PUT: $PUT"
echo " POST: $POST"
echo " Crawlers: $CRAWL"
echo
echo "Query Stats: "
echo " 200: $SUCCESS"
echo " 404: $NOT_FOUND"
echo " 502: $GATEWAY"
echo
#echo "Dropped Traffic: $($NFT list table filter | grep -Ei 'log counter packets' | cut -d ' ' -f6)"
echo
echo "Temporary Blocked IP's:"
echo
redis-cli --raw SMEMBERS tmp_block | sort -u
echo $MENU_BOTTOM
}
stop() {
#forgive
#$NFT -s list ruleset | tee $RULE_SET
$NFT flush ruleset
$NFT -f /usr/share/nftables/ipv4-filter.nft
$NFT add rule filter input icmp type echo-request accept
$NFT rule filter input accept
$NFT rule filter output accept
$NFT rule filter forward accept
$NFT insert rule filter input ct state established accept
$NFT insert rule filter input iif lo accept
$NFT -f /opt/firewall/ipv6-filter.nft
message "Stopping Firewall"
}
forgive() {
IP=($(redis-cli --raw SMEMBERS tmp_block | sort -u))
echo $IP
for i in "${IP[@]}"; do
HANDLE=$(nft -n -a list ruleset | grep $i | grep handle | cut -d '#' -f2 | cut -d ' ' -f3)
echo "Removing: $i Handle: $HANDLE"
ipDeleteParser $HANDLE
done
echo "Clearing old $TMP_BLOCK"
redis-cli DEL tmp_blocked
bash $MODULES/module-rate-limit-web.sh $HTTP_LIMIT
}
watch() {
echo "Scanning $DATE"
echo
IP=($(grep $DATE $ACCESS | grep -Fivf <(printf '%s\n' "${SAFE_TRAFFIC[@]}") | grep -Fivf <(printf '%s\n' "${CRAWLER_DB[@]}") | grep -Fivf <(printf '%s\n' "${SAVED_BOTS[@]}") | grep -vi $MY_IP | grep -vi 127.0.0.1 | grep -vi '127.0.0.1' | cut -d ' ' -f1 | sort -u))
for i in "${IP[@]}"; do
bash $MODULES/module-akkoma-instance.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-akkoma-timeline-public.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-akkoma-timeline-home.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-akkoma-accounts.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-akkoma-search.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-lightning.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-php.sh "$i" "$DATE" "$ACCESS"
bash $MODULES/module-go.sh "$i" "$DATE" "$ACCESS"
COUNT=$(grep $DATE $ACCESS | grep $i | grep -Fivf <(printf '%s\n' "${SAFE_TRAFFIC[@]}") | grep -Fivf <(printf '%s\n' "${SAVED_BOTS[@]}") | wc -l)
CHECK=$(cat $NFT_CACHE | sort -u | grep $i)
if [[ "$COUNT" -gt $ATTACK_THRESHOLD ]]; then
if [ "$CHECK" = "" ]; then
redis-cli SADD tmp_block $i
ipBlockParser $i
message "Blocking IP: $i with a count of: $COUNT"
cp -f $ACCESS /tmp/debug-high-traffic-$i.txt
else
echo
echo "Skipping Duplicate IP"
echo
fi
else
echo
echo "$i count: $COUNT below Threshhold: $ATTACK_THRESHOLD"
echo
fi
done
BLOCK_CHECK=$(redis-cli --raw SMEMBERS tmp_block)
if [[ "$BLOCK_CHECK" == *"empty"* || "$BLOCK_CHECK" == "" ]]; then
bash $MODULES/module-rate-limit-web.sh $HTTP_LIMIT
else
bash $MODULES/module-rate-limit-web.sh $RATE_LIMITED_HTTP
sleep $TMP_BLOCK_TIMEOUT
forgive
fi
}
message() {
#Message Alert Module. Configure modules/module-message.sh with actions.
bash $MODULES/module-message.sh "$1"
}
test-bots() {
for i in "${SAVED_BOTS[@]}"; do
DATA=$(grep $i $NGINX_ACCESS | grep -Fivf <(printf '%s\n' "${CRAWLER_DB[@]}"))
if [ "$DATA" = "" ]; then
echo "No Data. Probably OK"
else
echo $DATA
echo
read -p 'Press Enter to Continue ' -e
fi
done
}
research-ip() {
echo "Enter an IP Address to search"
read -p 'IP Address: ' -e IP
cat $ACCESS | grep $IP
echo
read -p 'Press Enter to Continue ' -e
}
importDB() {
DATA=($(cat trust.txt))
for i in "${DATA[@]}"; do redis-cli SADD trust $i; done
DATA=($(cat safe.txt))
for i in "${DATA[@]}"; do redis-cli SADD safe_traffic $i; done
DATA=($(cat bots.txt))
for i in "${DATA[@]}"; do redis-cli SADD bots $i; done
DATA=($(cat crawlers.txt))
for i in "${DATA[@]}"; do redis-cli SADD crawlers $i; done
redis-cli SADD my_ip $(curl ifconfig.me)
redis-cli SADD country https://www.ipdeny.com/ipblocks/data/countries/il.zone \
https://www.ipdeny.com/ipblocks/data/countries/cn.zone
COUNTRY=($(redis-cli SMEMBERS country))
for i in "${COUNTRY[@]}"; do
echo
echo "Blocking $i"
DB=($(curl $i))
for j in "${DB[@]}"; do
redis-cli SADD country_ip $j
done
done
}
exportDB() {
rm -f crawlers.txt
rm -f bots.txt
rm -f safe.txt
for i in "${CRAWLER_DB[@]}"; do echo $i >>crawlers.txt; done
for i in "${SAVED_BOTS[@]}"; do echo $i >>bots.txt; done
for i in "${SAFE_TRAFFIC[@]}"; do echo $i >>safe.txt; done
for i in "${TRUST[@]}"; do echo $i >>trust.txt; done
}
if [ "$1" = "start" ]; then
start
elif [ "$1" = "import-db" ]; then
importDB
elif [ "$1" = "export-db" ]; then
exportDB
elif [ "$1" = "virt" ]; then
virtualization
elif [ "$1" = "bot-search" ]; then
bot-search
elif [ "$1" = "attacker-protection" ]; then
attacker-protection
elif [ "$1" = "automatic-status" ]; then
automaticStatus
elif [ "$1" = "status" ]; then
status
elif [ "$1" = "forgive" ]; then
forgive
elif [ "$1" = "watch" ]; then
watch
elif [ "$1" = "research-ip" ]; then
research-ip
elif [ "$1" = "research" ]; then
research
elif [ "$1" = "stop" ]; then
stop
elif [ "$1" = "test" ]; then
test-bots
elif [ "$1" = "message" ]; then
message "$2"
elif [ "$1" = "ipBlockParser" ]; then
ipBlockParser "$2"
elif [ "$1" = "import" ]; then
import-saved
else
bash $MODULES/module-menu.sh
fi