Initial commit — SETEC LABS Manager (Setec_CDM)
Flask-based VPS management panel with SSH remote command execution. Includes E2E encrypted SSH tunnel (AES-256-GCM + Go agent), setup wizard, security hardening tools, DNS management, firewall configs, monitoring, backup, and .sec patch update system. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
464
setec-web/ddos.py
Normal file
464
setec-web/ddos.py
Normal file
@@ -0,0 +1,464 @@
|
||||
# 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}'"
|
||||
)
|
||||
Reference in New Issue
Block a user