# DDoS/DoS detection, prevention, mitigation, rate limiting, and Cloudflare integration # Each function returns a bash command string that app.py executes via ssh_run() def connection_stats_cmd(): """Return bash cmd to show current connection statistics.""" return ( "echo '=== Connection Statistics ===' && " "echo '' && " "echo '--- Connection States ---' && " "ss -ant 2>/dev/null | awk 'NR>1 {state[$1]++} END {for (s in state) printf \" %-15s %d\\n\", s, state[s]}' && " "echo '' && " "TOTAL=$(ss -ant 2>/dev/null | tail -n +2 | wc -l) && " "echo \"Total connections: $TOTAL\" && " "echo '' && " "echo '--- Top 20 IPs by Connection Count ---' && " "ss -ant 2>/dev/null | awk 'NR>1 {split($5,a,\":\"); print a[1]}' | " "grep -v '^$' | grep -v '\\*' | sort | uniq -c | sort -rn | head -20 && " "echo '' && " "echo '--- Connections per Port ---' && " "ss -ant 2>/dev/null | awk 'NR>1 {split($4,a,\":\"); print a[length(a)]}' | " "sort -n | uniq -c | sort -rn | head -20" ) def syn_flood_check_cmd(): """Return bash cmd to detect potential SYN flood.""" return ( "echo '=== SYN Flood Detection ===' && " "echo '' && " "SYN_COUNT=$(ss -ant state syn-recv 2>/dev/null | tail -n +2 | wc -l) && " "echo \"Current SYN_RECV connections: $SYN_COUNT\" && " "echo '' && " "if [ \"$SYN_COUNT\" -gt 50 ]; then " " echo 'WARNING: Possible SYN flood detected! SYN_RECV count exceeds threshold (50)'; " "elif [ \"$SYN_COUNT\" -gt 20 ]; then " " echo 'NOTICE: Elevated SYN_RECV count. Monitor closely.'; " "else " " echo 'OK: SYN_RECV count is within normal range.'; " "fi && " "echo '' && " "echo '--- Top Source IPs for SYN_RECV ---' && " "ss -ant state syn-recv 2>/dev/null | awk 'NR>1 {split($4,a,\":\"); print a[1]}' | " "sort | uniq -c | sort -rn | head -20 && " "echo '' && " "echo '--- SYN Cookies Status ---' && " "SYNCOOKIE=$(sysctl -n net.ipv4.tcp_syncookies 2>/dev/null) && " "if [ \"$SYNCOOKIE\" = \"1\" ]; then " " echo 'SYN cookies: ENABLED (good)'; " "else " " echo 'SYN cookies: DISABLED (consider enabling)'; " "fi" ) def bandwidth_stats_cmd(): """Return bash cmd to show bandwidth usage.""" return ( "echo '=== Bandwidth Statistics ===' && " "echo '' && " "if command -v vnstat >/dev/null 2>&1; then " " echo '--- vnstat Summary ---' && " " vnstat 2>&1 && " " echo '' && " " echo '--- vnstat Live (5 second sample) ---' && " " vnstat -tr 5 2>&1; " "else " " echo '--- /proc/net/dev (vnstat not installed) ---' && " " echo 'Interface RX bytes TX bytes' && " " awk 'NR>2 {split($0,a,\":\"); iface=a[1]; gsub(/^ +/,\"\",iface); " " split(a[2],b,\" \"); printf \"%-16s %-16s %s\\n\", iface, b[1], b[9]}' " " /proc/net/dev 2>/dev/null && " " echo '' && " " echo '--- Current Rate (2 second sample) ---' && " " IFACE=$(ip route get 8.8.8.8 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i==\"dev\") print $(i+1); exit}') && " " if [ -n \"$IFACE\" ]; then " " RX1=$(cat /sys/class/net/$IFACE/statistics/rx_bytes 2>/dev/null) && " " TX1=$(cat /sys/class/net/$IFACE/statistics/tx_bytes 2>/dev/null) && " " sleep 2 && " " RX2=$(cat /sys/class/net/$IFACE/statistics/rx_bytes 2>/dev/null) && " " TX2=$(cat /sys/class/net/$IFACE/statistics/tx_bytes 2>/dev/null) && " " RX_RATE=$(( (RX2 - RX1) / 2 )) && " " TX_RATE=$(( (TX2 - TX1) / 2 )) && " " echo \"Interface: $IFACE\" && " " echo \"RX rate: $RX_RATE bytes/sec\" && " " echo \"TX rate: $TX_RATE bytes/sec\"; " " else " " echo 'Could not determine primary interface'; " " fi; " "fi" ) def nginx_rate_limit_status_cmd(): """Return bash cmd to check current nginx rate limiting config.""" return ( "echo '=== Nginx Rate Limiting Status ===' && " "echo '' && " "if ! command -v nginx >/dev/null 2>&1; then " " echo 'nginx is not installed'; " "else " " echo '--- limit_req_zone directives ---' && " " grep -rn 'limit_req_zone' /etc/nginx/ 2>/dev/null || echo 'None found' && " " echo '' && " " echo '--- limit_req directives ---' && " " grep -rn 'limit_req ' /etc/nginx/ 2>/dev/null || echo 'None found' && " " echo '' && " " echo '--- limit_conn directives ---' && " " grep -rn 'limit_conn' /etc/nginx/ 2>/dev/null || echo 'None found'; " "fi" ) def nginx_rate_limit_cmd(requests_per_second=10, burst=20): """Return bash cmd to configure nginx rate limiting.""" zone_line = f"limit_req_zone $binary_remote_addr zone=setec_ratelimit:10m rate={requests_per_second}r/s;" req_line = f"limit_req zone=setec_ratelimit burst={burst} nodelay;" return ( "echo '=== Configuring Nginx Rate Limiting ===' && " "if ! command -v nginx >/dev/null 2>&1; then " " echo 'ERROR: nginx is not installed'; exit 1; " "fi && " "cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%Y%m%d_%H%M%S) && " "echo 'Backup created' && " # Remove old setec rate limit config if present "sed -i '/# setec-ratelimit-begin/,/# setec-ratelimit-end/d' /etc/nginx/nginx.conf && " # Add zone in http block (after the http { line) "sed -i '/^http {/a\\\\ # setec-ratelimit-begin\\n" f" {zone_line}\\n" " # setec-ratelimit-end' /etc/nginx/nginx.conf && " # Add limit_req to each server block in sites-enabled "for CONF in /etc/nginx/sites-enabled/*; do " " [ -f \"$CONF\" ] || continue; " " sed -i '/# setec-ratelimit-req-begin/,/# setec-ratelimit-req-end/d' \"$CONF\"; " " sed -i '/^[[:space:]]*server {/a\\\\ # setec-ratelimit-req-begin\\n" f" {req_line}\\n" " limit_req_status 429;\\n" " # setec-ratelimit-req-end' \"$CONF\"; " "done && " "nginx -t 2>&1 && " "systemctl reload nginx 2>&1 && " f"echo 'Rate limiting configured: {requests_per_second}r/s with burst={burst}'" ) def nginx_rate_limit_remove_cmd(): """Return bash cmd to remove nginx rate limiting.""" return ( "echo '=== Removing Nginx Rate Limiting ===' && " "if ! command -v nginx >/dev/null 2>&1; then " " echo 'ERROR: nginx is not installed'; exit 1; " "fi && " "cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%Y%m%d_%H%M%S) && " "sed -i '/# setec-ratelimit-begin/,/# setec-ratelimit-end/d' /etc/nginx/nginx.conf && " "for CONF in /etc/nginx/sites-enabled/*; do " " [ -f \"$CONF\" ] || continue; " " sed -i '/# setec-ratelimit-req-begin/,/# setec-ratelimit-req-end/d' \"$CONF\"; " "done && " "nginx -t 2>&1 && " "systemctl reload nginx 2>&1 && " "echo 'Rate limiting removed and nginx reloaded'" ) def auto_blacklist_cmd(threshold=100, period=60): """Return bash cmd to set up automatic IP blacklisting.""" script = ( "#!/bin/bash\\n" "# Setec Labs Auto-Blacklist Script\\n" "LOGFILE=/var/log/setec-blacklist.log\\n" f"THRESHOLD={threshold}\\n" "WHITELIST=\\\"127.0.0.1\\\"\\n" "\\n" "touch \\\"$LOGFILE\\\"\\n" "\\n" "# Get IPs with connections exceeding threshold\\n" "ss -ant 2>/dev/null | awk 'NR>1 {split(\\$5,a,\\\":\\\"); print a[1]}' | \\\\\\n" " grep -v '^$' | grep -v '\\\\*' | sort | uniq -c | sort -rn | \\\\\\n" " while read COUNT IP; do\\n" " # Skip whitelist\\n" " echo \\\"$WHITELIST\\\" | grep -q \\\"$IP\\\" && continue\\n" " # Skip private ranges\\n" " echo \\\"$IP\\\" | grep -qE '^(10\\\\.|172\\\\.(1[6-9]|2[0-9]|3[01])\\\\.|192\\\\.168\\\\.)' && continue\\n" " if [ \\\"$COUNT\\\" -gt \\\"$THRESHOLD\\\" ]; then\\n" " # Check if already banned\\n" " if ! iptables -C INPUT -s \\\"$IP\\\" -j DROP 2>/dev/null; then\\n" " iptables -A INPUT -s \\\"$IP\\\" -j DROP\\n" " echo \\\"$(date): Banned $IP ($COUNT connections)\\\" >> \\\"$LOGFILE\\\"\\n" " fi\\n" " fi\\n" " done\\n" ) return ( "echo '=== Setting Up Auto-Blacklisting ===' && " f"echo -e '{script}' > /usr/local/bin/setec-blacklist.sh && " "chmod +x /usr/local/bin/setec-blacklist.sh && " "touch /var/log/setec-blacklist.log && " "(crontab -l 2>/dev/null | grep -v 'setec-blacklist.sh'; " "echo '* * * * * /usr/local/bin/setec-blacklist.sh') | crontab - && " f"echo 'Auto-blacklist installed: threshold={threshold} connections' && " "echo 'Cron job added: runs every minute'" ) def auto_blacklist_status_cmd(): """Return bash cmd to check auto-blacklist status and recent bans.""" return ( "echo '=== Auto-Blacklist Status ===' && " "echo '' && " "echo '--- Script ---' && " "if [ -f /usr/local/bin/setec-blacklist.sh ]; then " " echo 'Script: INSTALLED'; " " ls -la /usr/local/bin/setec-blacklist.sh; " "else " " echo 'Script: NOT INSTALLED'; " "fi && " "echo '' && " "echo '--- Cron Job ---' && " "if crontab -l 2>/dev/null | grep -q 'setec-blacklist.sh'; then " " echo 'Cron: ACTIVE'; " " crontab -l 2>/dev/null | grep 'setec-blacklist.sh'; " "else " " echo 'Cron: NOT FOUND'; " "fi && " "echo '' && " "echo '--- Currently Banned IPs ---' && " "iptables -L INPUT -n 2>/dev/null | grep DROP | awk '{print $4}' | sort | head -50 && " "echo '' && " "echo '--- Recent Ban Log (last 20) ---' && " "if [ -f /var/log/setec-blacklist.log ]; then " " tail -20 /var/log/setec-blacklist.log; " "else " " echo 'No ban log found'; " "fi" ) def auto_blacklist_remove_cmd(): """Return bash cmd to remove auto-blacklisting.""" return ( "echo '=== Removing Auto-Blacklisting ===' && " "(crontab -l 2>/dev/null | grep -v 'setec-blacklist.sh') | crontab - && " "rm -f /usr/local/bin/setec-blacklist.sh && " "echo 'Auto-blacklist script removed' && " "echo 'Cron job removed' && " "echo 'Note: Existing iptables bans are still active. Use show_blacklist to review.'" ) def blacklist_ip_cmd(ip): """Return bash cmd to manually blacklist an IP via iptables.""" return ( f"echo '=== Blacklisting IP: {ip} ===' && " f"if iptables -C INPUT -s {ip} -j DROP 2>/dev/null; then " f" echo 'IP {ip} is already blacklisted'; " "else " f" iptables -A INPUT -s {ip} -j DROP 2>&1 && " f" echo 'IP {ip} has been blacklisted (DROP rule added)' && " f" echo \"$(date): Manual ban {ip}\" >> /var/log/setec-blacklist.log; " "fi" ) def unblacklist_ip_cmd(ip): """Return bash cmd to remove an IP from blacklist.""" return ( f"echo '=== Removing IP from Blacklist: {ip} ===' && " f"if iptables -C INPUT -s {ip} -j DROP 2>/dev/null; then " f" iptables -D INPUT -s {ip} -j DROP 2>&1 && " f" echo 'IP {ip} has been removed from blacklist' && " f" echo \"$(date): Manual unban {ip}\" >> /var/log/setec-blacklist.log; " "else " f" echo 'IP {ip} was not found in blacklist'; " "fi" ) def show_blacklist_cmd(): """Return bash cmd to show all blacklisted IPs.""" return ( "echo '=== Current IP Blacklist ===' && " "echo '' && " "iptables -L INPUT -n --line-numbers 2>/dev/null | grep DROP && " "echo '' && " "COUNT=$(iptables -L INPUT -n 2>/dev/null | grep -c DROP) && " "echo \"Total blacklisted IPs: $COUNT\"" ) def syn_protection_cmd(): """Return bash cmd to enable SYN flood protection via sysctl and iptables.""" return ( "echo '=== Enabling SYN Flood Protection ===' && " "echo '' && " "echo '--- Sysctl Tuning ---' && " "sysctl -w net.ipv4.tcp_syncookies=1 2>&1 && " "sysctl -w net.ipv4.tcp_max_syn_backlog=2048 2>&1 && " "sysctl -w net.ipv4.tcp_synack_retries=2 2>&1 && " "sysctl -w net.ipv4.tcp_syn_retries=2 2>&1 && " "sysctl -w net.ipv4.conf.all.rp_filter=1 2>&1 && " "sysctl -w net.ipv4.tcp_timestamps=1 2>&1 && " # Persist settings "cat >> /etc/sysctl.d/99-syn-protection.conf << 'SYSCTL_EOF'\n" "# Setec SYN flood protection\n" "net.ipv4.tcp_syncookies = 1\n" "net.ipv4.tcp_max_syn_backlog = 2048\n" "net.ipv4.tcp_synack_retries = 2\n" "net.ipv4.tcp_syn_retries = 2\n" "net.ipv4.conf.all.rp_filter = 1\n" "net.ipv4.tcp_timestamps = 1\n" "SYSCTL_EOF\n" " && " "echo '' && " "echo '--- iptables SYN Rate Limiting ---' && " # Remove old rules if they exist "iptables -D INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT 2>/dev/null; " "iptables -D INPUT -p tcp --syn -j DROP 2>/dev/null; " # Add new rules "iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT 2>&1 && " "echo 'SYN rate limit: 1/s with burst of 3' && " "echo '' && " "echo 'SYN flood protection enabled' && " "echo 'Sysctl settings persisted to /etc/sysctl.d/99-syn-protection.conf'" ) def cloudflare_under_attack_cmd(zone_id, api_token, enable=True): """Return bash cmd to toggle Cloudflare Under Attack mode.""" level = "under_attack" if enable else "medium" action = "Enabling Under Attack mode" if enable else "Disabling Under Attack mode (setting to medium)" return ( f"echo '=== Cloudflare: {action} ===' && " "if ! command -v curl >/dev/null 2>&1; then " " echo 'ERROR: curl is required'; exit 1; " "fi && " f"RESPONSE=$(curl -s -X PATCH " f"'https://api.cloudflare.com/client/v4/zones/{zone_id}/settings/security_level' " f"-H 'Authorization: Bearer {api_token}' " f"-H 'Content-Type: application/json' " f"--data '{{\"value\":\"{level}\"}}' 2>&1) && " "echo \"$RESPONSE\" | " "if command -v jq >/dev/null 2>&1; then " " jq -r '\"Success: \" + (.success|tostring) + \" | Level: \" + .result.value' 2>/dev/null || echo \"$RESPONSE\"; " "else " " grep -o '\"success\":[a-z]*' 2>/dev/null || echo \"$RESPONSE\"; " "fi" ) def cloudflare_status_cmd(zone_id, api_token): """Return bash cmd to check current Cloudflare security level.""" return ( "echo '=== Cloudflare Security Status ===' && " "if ! command -v curl >/dev/null 2>&1; then " " echo 'ERROR: curl is required'; exit 1; " "fi && " f"RESPONSE=$(curl -s -X GET " f"'https://api.cloudflare.com/client/v4/zones/{zone_id}/settings/security_level' " f"-H 'Authorization: Bearer {api_token}' " f"-H 'Content-Type: application/json' 2>&1) && " "echo \"$RESPONSE\" | " "if command -v jq >/dev/null 2>&1; then " " jq -r '\"Security Level: \" + .result.value + \" | Modified: \" + .result.modified_on' 2>/dev/null || echo \"$RESPONSE\"; " "else " " grep -oP '\"value\":\"[^\"]+\"' 2>/dev/null || echo \"$RESPONSE\"; " "fi" ) def tor_exit_block_cmd(enable=True): """Return bash cmd to download and block Tor exit nodes.""" if enable: return ( "echo '=== Blocking Tor Exit Nodes ===' && " "if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then " " echo 'ERROR: curl or wget required'; exit 1; " "fi && " # Check for ipset "if ! command -v ipset >/dev/null 2>&1; then " " echo 'Installing ipset...' && " " apt-get install -y ipset 2>&1 || yum install -y ipset 2>&1; " "fi && " # Create or flush ipset "ipset create tor_exit hash:ip -exist 2>&1 && " "ipset flush tor_exit 2>&1 && " # Download Tor exit node list "echo 'Downloading Tor exit node list...' && " "TOR_LIST=$(mktemp) && " "if command -v curl >/dev/null 2>&1; then " " curl -s 'https://check.torproject.org/torbulkexitlist' > \"$TOR_LIST\" 2>&1; " "else " " wget -q 'https://check.torproject.org/torbulkexitlist' -O \"$TOR_LIST\" 2>&1; " "fi && " "COUNT=0 && " "while IFS= read -r IP; do " " echo \"$IP\" | grep -qE '^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$' || continue; " " ipset add tor_exit \"$IP\" -exist 2>/dev/null; " " COUNT=$((COUNT + 1)); " "done < \"$TOR_LIST\" && " "rm -f \"$TOR_LIST\" && " # Add iptables rule if not present "if ! iptables -C INPUT -m set --match-set tor_exit src -j DROP 2>/dev/null; then " " iptables -A INPUT -m set --match-set tor_exit src -j DROP 2>&1; " "fi && " "echo \"Blocked $COUNT Tor exit nodes\" && " # Save for persistence "ipset save > /etc/ipset.conf 2>/dev/null; " "echo 'Tor exit node blocking enabled'" ) else: return ( "echo '=== Removing Tor Exit Node Blocking ===' && " "iptables -D INPUT -m set --match-set tor_exit src -j DROP 2>/dev/null; " "ipset destroy tor_exit 2>/dev/null; " "echo 'Tor exit node blocking removed'" ) def geoblock_cmd(country_codes): """Return bash cmd to block traffic from specific countries using xtables-addons/geoip.""" if isinstance(country_codes, str): codes = country_codes else: codes = ",".join(country_codes) return ( f"echo '=== GeoIP Blocking: {codes} ===' && " "echo '' && " # Check/install xtables-addons "if ! modprobe xt_geoip 2>/dev/null; then " " echo 'Installing xtables-addons...' && " " apt-get install -y xtables-addons-common libtext-csv-xs-perl 2>&1 || " " yum install -y xtables-addons 2>&1; " "fi && " # Download GeoIP database "echo 'Updating GeoIP database...' && " "mkdir -p /usr/share/xt_geoip && " "if [ -d /usr/lib/xtables-addons ] || [ -d /usr/libexec/xtables-addons ]; then " " DBDIR=$(find /usr/lib /usr/libexec -name 'xt_geoip_dl' -type f 2>/dev/null | head -1 | xargs dirname 2>/dev/null) && " " if [ -n \"$DBDIR\" ]; then " " cd /tmp && " " \"$DBDIR/xt_geoip_dl\" 2>&1 && " " \"$DBDIR/xt_geoip_build\" -D /usr/share/xt_geoip *.csv 2>&1; " " else " " echo 'WARNING: Could not find xt_geoip_dl. GeoIP DB may be outdated.'; " " fi; " "else " " echo 'WARNING: xtables-addons path not found'; " "fi && " "echo '' && " # Remove old setec geoblock rules "iptables-save 2>/dev/null | grep 'setec-geoblock' | while read RULE; do " " CLEAN=$(echo \"$RULE\" | sed 's/^-A //' ); " " iptables -D $CLEAN 2>/dev/null; " "done; " # Add rules for each country f"for CC in $(echo '{codes}' | tr ',' ' '); do " " iptables -A INPUT -m geoip --src-cc \"$CC\" -j DROP " " -m comment --comment 'setec-geoblock' 2>&1 && " " echo \"Blocked country: $CC\"; " "done && " "echo '' && " f"echo 'GeoIP blocking active for: {codes}'" )