#!/bin/bash MY_IP="47.5.115.173" ATTACK_THRESHOLD="50" SERVER_IP='192.168.0.55' NGINX_ACCESS="/tmp/access.log" #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='/tmp/tmp-blocked.txt' #Log Files # SAVED_BOTS='/opt/firewall/bots.txt' CRAWLER_DB='/opt/firewall/crawlers.txt' SAFE_TRAFFIC='/opt/firewall/safe.txt' PEDO_DB='/opt/firewall/pedo.txt' PEDO_LOG='/opt/firewall/pedo-log.txt' BOT_ACCOUNT="blockbot@detroitriotcity.com" CRAWLER_TMP='/tmp/crawlers.txt' RULE_SET='/opt/firewall/nft.rules' MENU_TOP="=============================FireWall=================================" MENU_BOTTOM="=====================================================================" #Cache the Date and Current Firewall Rules at every launch DATE="$(date +%d/%b/%Y:%H:%M -d '1 minute ago')" nft list table filter >$NFT_CACHE #Countries to Block COUNTRY=( https://www.ipdeny.com/ipblocks/data/countries/il.zone https://www.ipdeny.com/ipblocks/data/countries/cn.zone ) 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 $NFT add rule ip filter input ct state new tcp dport $1 update @http_ratelimit { ip saddr limit rate 10/second } accept $NFT add rule ip6 filter input ct state new tcp dport $1 update @http_ratelimit { ip6 saddr limit rate 10/second } accept 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 else $NFT delete rule ip filter input handle $HANDLE fi } blockCountry() { for i in "${COUNTRY[@]}"; do echo echo "Blocking $i" DB=($(curl $i)) for j in "${DB[@]}"; do ipBlockParser $j done 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 module-nostr bot-search } bot-search() { CRAWLERS=($(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -Evi 'Guro|spank|report|rape|block' | grep -Ei -f $CRAWLER_DB | grep -Evi -f $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 echo $i >>$SAVED_BOTS else echo echo "Skipping Duplicate IP $i" echo fi done } drc-alert() { toot activate $BOT_ACCOUNT toot post ":emergency: :hacker_p: :hacker_e: :hacker_d: :hacker_o: :trans: :hacker_a: :hacker_l: :hacker_e: :hacker_r: :hacker_t: :emergency2: $1" -m /root/detroit/akkoma/blockbot/pedo.png } pedo-search() { echo PEDO_SEARCH=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -Ei 'tag|search' | grep -Evi -f $CRAWLER_DB | grep -Ei -f $PEDO_DB | head -1) echo $PEDO_SEARCH if [ "$PEDO_SEARCH" ]; then echo "Pedo Found!" echo "Processing Pedo Searches into NFT....." IP=$(echo $PEDO_SEARCH | cut -d ' ' -f1) ipBlockParser $IP message "[Pedo Alert] $PEDO_SEARCH" #drc-alert "$PEDO_SEARCH" echo $IP >> $PEDO_LOG else echo echo "No Pedos Found" echo fi } 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() { STATS=($(cat $SAVED_BOTS | sort -u)) for i in "${STATS[@]}"; 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 else virtualization fi } research() { STATS=($(cat $TMP_BLOCK | sort -u)) for i in "${STATS[@]}"; do echo $MENU_TOP echo " [Researching $i] " echo DATA=$(grep $i $NGINX_LOG | grep -Evi -f $SAFE_TRAFFIC) echo "$DATA" echo echo $MENU_BOTTOM echo read -p 'Press Enter to Continue ' -e done } automaticStatus() { status sleep 30 automaticStatus } status() { clear STATS=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | wc -l) GET=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep GET | wc -l) POST=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep POST | wc -l) PUT=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -i PUT | wc -l) NOT_FOUND=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep 404 | wc -l) GATEWAY=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep 502 | wc -l) SUCCESS=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep 200 | wc -l) CRAWL=$(grep $DATE $NGINX_ACCESS | grep -vi $MY_IP | grep -Ei -f $CRAWLER_DB | wc -l) echo $MENU_TOP echo "Attack Threshold: $ATTACK_THRESHOLD" echo "Firewall Rules: $($NFT list table filter | wc -l)" 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:" cat $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=($(grep -vi $MY_IP $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" echo $NFT delete rule ip filter input handle $HANDLE ipDeleteParser $HANDLE done echo "Clearing old $TMP_BLOCK" echo >$TMP_BLOCK } module-go() { GO_SPAM=$(grep $2 $NGINX_ACCESS | grep -E "Go-http-client" | wc -l) if [[ "$GO_SPAM" -gt 10 ]]; then ipBlockParser "$1" echo $1 >>$TMP_BLOCK message "Go Spam Attack!" fi } module-akkoma() { SEARCH_SPAM=$(grep $2 $NGINX_ACCESS | grep -E "api/v1/instance|api/v1/notifications|api/v1/accounts|api/v2/search|timelines/public|timelines/home|/api/v1/accounts" | grep $1 | wc -l) CHECK=$(cat $NFT_CACHE | sort -u | grep $i) if [[ "$SEARCH_SPAM" -gt 30 ]]; then echo "$IP $CHECK $COUNT" if [ "$CHECK" = "" ]; then ipBlockParser "$1" echo $1 >>$TMP_BLOCK message "module-akkoma: Spam Attack! $i" echo "module-akkoma: Spam $1" else echo "module-akkoma: Ignoring Duplicate IP: $i" fi fi } module-get-spam() { GET_SPAM=$(grep $2 $NGINX_ACCESS | grep -E "GET / HTTP" | wc -l) if [[ "$GET_SPAM" -gt 5 ]]; then ipBlockParser "$1" echo $1 >>$TMP_BLOCK message "GET Spam Attack! $1" fi } module-php() { PHP_SPAM=$(grep $2 $NGINX_ACCESS | grep -E ".php|cgi-bin|wp-content|wp-admin|wp-includes" | wc -l) if [[ "$PHP_SPAM" -gt 1 ]]; then ipBlockParser "$1" echo $1 >>$TMP_BLOCK message "PHP Attack!" fi } module-lightning() { LN_SPAM=$(grep $2 $NGINX_ACCESS | grep "lnurlp/verita84" | wc -l) if [[ "$LN_SPAM" -gt 5 ]]; then ipBlockParser "$1" message "Lightning Spam Attack!" echo $1 >>$TMP_BLOCK fi } message() { BOT_ACCOUNT="blockbot@detroitriotcity.com" echo "$1" | /root/go/bin/algia dm-post -u 33c74427f3b2b73d5e38f3e6c991c122a55d204072356f71da49a0e209fb6940 --stdin } watch() { echo "Scanning $DATE" echo IP=($(grep $DATE $NGINX_ACCESS | grep -Evi -f $SAFE_TRAFFIC | grep -Evi -f $CRAWLER_DB | grep -Evi -f $SAVED_BOTS |grep -vi $MY_IP | grep -vi '127.0.0.1' | cut -d ' ' -f1 | sort -u)) for i in "${IP[@]}"; do module-akkoma "$i" "$DATE" module-lightning "$i" "$DATE" module-php "$i" "$DATE" module-go "$i" "$DATE" module-get-spam "$i" "$DATE" COUNT=$(grep $DATE $NGINX_ACCESS | grep $i | grep -Evi -f $SAFE_TRAFFIC | grep -Evi -f $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" echo $i >>$TMP_BLOCK 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 } module-nostr(){ IP=($(grep $DATE $NGINX_ACCESS | grep "/block=" | cut -d '=' -f2| cut -d ' ' -f1 | sed 's/"//')) for i in "${IP[@]}"; do echo $i if [[ "$i" == *"npub"* ]]; then bash /opt/strfry-policies/block.sh $i else echo "No Npubs to block" fi done } test-bots() { TEST=($(cat $SAVED_BOTS)) for i in "${TEST[@]}"; do DATA=$(grep $i $NGINX_ACCESS | grep -Evi -f $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 $NGINX_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 $NGINX_ACCESS | grep -Evi -f $SAFE_TRAFFIC | grep -Evi -f $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 } if [ "$1" = "start" ]; then start elif [ "$1" = "virt" ]; then virtualization elif [ "$1" = "bot-search" ]; then bot-search elif [ "$1" = "attacker-protection" ]; then attacker-protection elif [ "$1" = "country" ]; then blockCountry 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" = "message" ]; then message $2 elif [ "$1" = "test" ]; then test-bots elif [ "$1" = "nostr" ]; then module-nostr elif [ "$1" = "import" ]; then import-saved elif [ "$1" = "saved" ]; then saved-bots else menu fi