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:
DigiJ
2026-03-13 12:39:02 -07:00
commit 9e839ee826
62 changed files with 14605 additions and 0 deletions

464
setec-web/ddos.py Normal file
View 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}'"
)