482 lines
13 KiB
Bash
Executable File
482 lines
13 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="100"
|
|
RATE_LIMITED_HTTP="30"
|
|
MODULES="/opt/firewall/modules"
|
|
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["Uptime"]="4001"
|
|
portConfig["DNS-1"]="53"
|
|
portConfig["DNS-2"]="67"
|
|
portConfig["DNS-3"]="68"
|
|
portConfig["CUPS-1"]="631"
|
|
portConfig["CUPS-2"]="5353"
|
|
#portConfig["Bitcoin-1"]="8333"
|
|
#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"
|
|
MACHINES=(127.0.0.1)
|
|
VIRT_BRIDGE="virbr0"
|
|
#### NFT CONFIG ####
|
|
#
|
|
NFT='/usr/bin/nft'
|
|
NFT_CACHE='/tmp/nft.cache'
|
|
TMP_BLOCK=($(redis-cli --raw SMEMBERS tmp_block))
|
|
#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
|
|
}
|
|
|
|
wireguard-networking() {
|
|
$NFT add table nat
|
|
$NFT add chain nat postrouting
|
|
$NFT add rule nat postrouting oif wg0 iif enp11s0
|
|
$NFT add rule nat postrouting oif enp11s0 iif wg0
|
|
$NFT add rule nat postrouting masquerade
|
|
$NFT add rule filter forward iifname wg0 oif enp11s0 accept
|
|
$NFT add rule filter forward iifname enp11s0 oif wg0 accept
|
|
$NFT add rule ip filter input ip saddr 192.168.5.0/24 accept
|
|
}
|
|
|
|
attacker-protection() {
|
|
watch
|
|
bash $MODULES/module-nostr.sh "$i" "$DATE"
|
|
bot-search
|
|
}
|
|
|
|
bot-search() {
|
|
echo "Searching for Web Crawalers...."
|
|
CRAWLERS=($(grep $DATE $ACCESS | grep -vi $MY_IP | 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
|
|
|
|
#$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
|
|
}
|
|
|
|
trust() {
|
|
for i in "${MACHINES[@]}"; do
|
|
$NFT add rule filter input ip saddr $i accept
|
|
done
|
|
}
|
|
|
|
import-saved() {
|
|
|
|
for i in "${SAVED_BOTS[@]}"; do
|
|
ipBlockParser $i
|
|
done
|
|
}
|
|
|
|
start() {
|
|
basic-security
|
|
|
|
if [[ $HOSTNAME == *"nas"* ]]; then
|
|
sysctl -w net.ipv4.conf.all.forwarding=1
|
|
import-saved
|
|
blockCountry
|
|
wireguard-networking
|
|
docker restart uptime-kuma
|
|
|
|
#Docker
|
|
$NFT insert rule filter input iif docker0 accept
|
|
|
|
#HTTP Rate Limit
|
|
bash $MODULES/module-rate-limit.sh $HTTP_LIMIT
|
|
|
|
else
|
|
virtualization
|
|
fi
|
|
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)
|
|
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 "Rate-limited 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
|
|
# $NFT add rule ip6 filter input icmpv6 type nd-neighbor-solicit accept
|
|
# $NFT add rule ip6 filter input icmpv6 type nd-router-advert accept
|
|
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.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' | cut -d ' ' -f1 | sort -u))
|
|
|
|
for i in "${IP[@]}"; do
|
|
bash $MODULES/module-akkoma-instance.sh "$i" "$DATE"
|
|
bash $MODULES/module-akkoma-timeline-public.sh "$i" "$DATE"
|
|
bash $MODULES/module-akkoma-timeline-home.sh "$i" "$DATE"
|
|
bash $MODULES/module-akkoma-accounts.sh "$i" "$DATE"
|
|
bash $MODULES/module-akkoma-search.sh "$i" "$DATE"
|
|
bash $MODULES/module-lightning.sh "$i" "$DATE"
|
|
bash $MODULES/module-php.sh "$i" "$DATE"
|
|
bash $MODULES/module-go.sh "$i" "$DATE"
|
|
|
|
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
|
|
echo "Danger! Blocking IP: $i Count: $COUNT"
|
|
logger "Blocking IP: $i with a count of: $COUNT"
|
|
redis-cli SADD tmp_block $i
|
|
ipBlockParser $i
|
|
message "Blocking IP: $i with a count of: $COUNT"
|
|
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.sh $HTTP_LIMIT
|
|
else
|
|
bash $MODULES/module-rate-limit.sh $RATE_LIMITED_HTTP
|
|
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 $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
|
|
}
|
|
|
|
menu() {
|
|
clear
|
|
echo
|
|
echo $MENU_TOP
|
|
echo "1. Start"
|
|
echo "2. Stop"
|
|
echo "3. Reseearch"
|
|
echo "4. Forgive"
|
|
echo "5. Status"
|
|
echo "6. Live Traffic"
|
|
echo "7. Test Bot Search Rules"
|
|
echo "8. Research IP"
|
|
echo "9. View Current Rule Set"
|
|
echo "0. Quit"
|
|
echo $MENU_BOTTOM
|
|
echo
|
|
read -p 'Choice: ' CHOICE
|
|
echo
|
|
if [ "$CHOICE" = "1" ]; then
|
|
echo
|
|
echo "Starting Firewall"
|
|
start
|
|
read -p 'Press Enter to Continue ' -e-
|
|
elif [ "$CHOICE" = "2" ]; then
|
|
echo
|
|
echo "Stopping Firewall"
|
|
stop
|
|
read -p 'Press Enter to Continue ' -e
|
|
elif [ "$CHOICE" = "3" ]; then
|
|
research
|
|
read -p 'Press Enter to Continue ' -e
|
|
elif [ "$CHOICE" = "4" ]; then
|
|
forgive
|
|
elif [ "$CHOICE" = "55" ]; then
|
|
automaticStatus
|
|
elif [ "$CHOICE" = "5" ]; then
|
|
status
|
|
read -p 'Press Enter to Continue ' -e
|
|
elif [ "$CHOICE" = "6" ]; then
|
|
tail -f $ACCESS | grep -Fivf <(printf '%s\n' "${SAFE_TRAFFIC[@]}") | grep -Fivf <(printf '%s\n' "${CRAWLER_DB[@]}")
|
|
read -p 'Press Enter to Continue ' -e
|
|
elif [ "$CHOICE" = "7" ]; then
|
|
test-bots
|
|
read -p 'Press Enter to Continue ' -e
|
|
elif [ "$CHOICE" = "8" ]; then
|
|
research-ip
|
|
read -p 'Press Enter to Continue ' -e
|
|
elif [ "$CHOICE" = "9" ]; then
|
|
nft -s list ruleset | less
|
|
elif [ "$CHOICE" = "0" ]; then
|
|
exit
|
|
fi
|
|
echo
|
|
menu
|
|
}
|
|
|
|
importDB() {
|
|
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
|
|
}
|
|
|
|
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" = "status" ]; then
|
|
automaticStatus
|
|
elif [ "$1" = "forgive" ]; then
|
|
forgive
|
|
elif [ "$1" = "watch" ]; then
|
|
watch
|
|
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
|
|
menu
|
|
fi
|