#!/bin/bash
# BDUSP DDoS Guard CLI v6

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; NC='\033[0m'; BOLD='\033[1m'

BASE="/var/lib/ddos-guard"
BLOCKLIST="$BASE/blocklist.json"
WHITELIST="$BASE/whitelist.json"
QUARANTINE="$BASE/quarantine.json"
CONFIG="$BASE/config.json"
LOGFILE="/var/log/ddos-guard.log"

header() {
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
    echo -e "${CYAN}  🛡️  BDUSP DDoS Guard v6${NC}"
    echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
}

py() { python3 -c "$1"; }

valid_ip() {
    python3 -c "
import re,sys
ip='$1'.strip()
m=re.match(r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$',ip)
sys.exit(0 if (m and all(0<=int(g)<=255 for g in m.groups())) else 1)
" 2>/dev/null
}

cfg_get() {
    py "
import json
try: d=json.load(open('$CONFIG'))
except: d={}
defs={'window_seconds':30,'block_threshold':300,'perm_threshold':1000,
      'check_interval':30,'q_enabled':True,'q_single_ip':500,'q_all_ip':5000,'q_cooldown':30}
defs.update(d)
v=defs.get('$1','')
print(str(v))
"
}

cfg_set() {
    py "
import json,os
os.makedirs('$BASE',exist_ok=True)
try: d=json.load(open('$CONFIG'))
except: d={}
v='$2'
try: v=int(v)
except:
    if v.lower()=='true': v=True
    elif v.lower()=='false': v=False
d['$1']=v
json.dump(d,open('$CONFIG','w'),indent=2)
"
}

# ── status ────────────────────────────────────────────────────────────────────
cmd_status() {
    header; echo ""
    if systemctl is-active --quiet ddos-guard; then
        echo -e "  Service    : ${GREEN}● Running${NC}"
    else
        echo -e "  Service    : ${RED}● Stopped${NC}"
    fi

    total=$(py "import json
try: d=json.load(open('$BLOCKLIST')); print(len(d))
except: print(0)")
    temp=$(py "import json
try: d=json.load(open('$BLOCKLIST')); print(sum(1 for v in d.values() if not v.get('permanent')))
except: print(0)")
    perm=$(py "import json
try: d=json.load(open('$BLOCKLIST')); print(sum(1 for v in d.values() if v.get('permanent')))
except: print(0)")
    wl=$(py "import json
try: d=json.load(open('$WHITELIST')); print(len(d))
except: print(0)")
    qc=$(py "import json
try: d=json.load(open('$QUARANTINE')); print(len(d))
except: print(0)")

    echo -e "  Blocked    : ${RED}${total} IP(s)${NC} — ${temp} temp, ${perm} permanent"
    echo -e "  Whitelist  : ${GREEN}${wl} IP(s)${NC}"
    echo -e "  Quarantine : ${YELLOW}${qc} domain(s)${NC}"
    echo ""

    q_on=$(cfg_get q_enabled)
    echo -e "  ${BOLD}IP Block (per $(cfg_get window_seconds)s window):${NC}"
    echo -e "  7-day block      : $(cfg_get block_threshold) req"
    echo -e "  Permanent block  : $(cfg_get perm_threshold) req"
    echo ""
    if [ "$q_on" = "True" ]; then
        q_s=$(cfg_get q_single_ip); q_a=$(cfg_get q_all_ip)
        q_off_s=$((q_s/2)); q_off_a=$((q_a/2))
        echo -e "  ${BOLD}Quarantine:${NC} ${GREEN}ENABLED${NC}"
        echo -e "  Single IP → ON   : ${q_s} req  |  OFF: < ${q_off_s} req"
        echo -e "  All IP    → ON   : ${q_a} req  |  OFF: < ${q_off_a} req"
        echo -e "  Cooldown         : $(cfg_get q_cooldown)s"
    else
        echo -e "  ${BOLD}Quarantine:${NC} ${RED}DISABLED${NC}"
    fi
    echo ""
}

# ── config ────────────────────────────────────────────────────────────────────
cmd_config() {
    if [ -z "$1" ]; then
        header; echo ""
        echo -e "  ${BOLD}Current Config:${NC}"; echo ""
        echo -e "  ${GREEN}window_seconds${NC}    $(cfg_get window_seconds)     Monitoring window (seconds)"
        echo -e "  ${GREEN}block_threshold${NC}   $(cfg_get block_threshold)    Req/window → 7-day block"
        echo -e "  ${GREEN}perm_threshold${NC}    $(cfg_get perm_threshold)    Req/window → permanent block"
        echo -e "  ${GREEN}check_interval${NC}    $(cfg_get check_interval)     Log check every N seconds"
        echo -e "  ${GREEN}q_enabled${NC}         $(cfg_get q_enabled)   Quarantine on/off (true/false)"
        echo -e "  ${GREEN}q_single_ip${NC}       $(cfg_get q_single_ip)     Same IP req/window → quarantine"
        echo -e "  ${GREEN}q_all_ip${NC}          $(cfg_get q_all_ip)    All IP req/window → quarantine"
        echo -e "  ${GREEN}q_cooldown${NC}        $(cfg_get q_cooldown)     Seconds before auto-off"
        echo ""
        echo -e "  ${YELLOW}Usage: vg config <key> <value>${NC}"
        echo -e "  Example: vg config block_threshold 200"
        echo -e "  Example: vg config q_enabled false"
        echo ""
        return
    fi
    [ -z "$2" ] && echo -e "${RED}Usage: vg config <key> <value>${NC}" && exit 1
    cfg_set "$1" "$2"
    systemctl restart ddos-guard 2>/dev/null
    echo -e "${GREEN}✅ $(echo $1) = $2 — saved, service restarted.${NC}"
}

# ── quarantine ────────────────────────────────────────────────────────────────
cmd_quarantine() {
    header; echo -e "\n  ${BOLD}Quarantined Domains:${NC}\n"
    py "
import json,time
try: data=json.load(open('$QUARANTINE'))
except: data={}
if not data: print('  No quarantined domains.'); exit()
print(f\"  {'Domain':<40} {'Since'}\")
print(f\"  {'─'*40} {'─'*20}\")
for d,i in data.items():
    since=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(i.get('since',0)))
    print(f'  {d:<40} {since}')
print()
"
}

cmd_quarantine_on() {
    cfg_set "q_enabled" "true"
    systemctl restart ddos-guard 2>/dev/null
    echo -e "${GREEN}✅ Quarantine ENABLED.${NC}"
}

cmd_quarantine_off() {
    cfg_set "q_enabled" "false"
    systemctl restart ddos-guard 2>/dev/null
    echo -e "${YELLOW}⚠ Quarantine DISABLED. Only IP blocking will happen.${NC}"
}

cmd_quarantine_release() {
    [ -z "$1" ] && echo -e "${RED}Usage: vg quarantine-release <domain>${NC}" && exit 1
    python3 << PYEOF
import json, os, shutil

QUARANTINE = "$QUARANTINE"
domain = "$1"
PHP_FILE = ".bdusp_ddos_challenge.php"

try:
    q = json.load(open(QUARANTINE))
except:
    print("  No quarantine data.")
    exit()

if domain not in q:
    print("  Domain not in quarantine.")
    exit()

docroot = q[domain].get("docroot", "")
if not docroot:
    print("  Docroot unknown.")
    del q[domain]
    json.dump(q, open(QUARANTINE, "w"), indent=2)
    exit()

htaccess = os.path.join(docroot, ".htaccess")
backup   = os.path.join(docroot, ".htaccess.bdusp_bak")
php_file = os.path.join(docroot, PHP_FILE)

# Restore .htaccess
if os.path.exists(backup):
    shutil.move(backup, htaccess)
    print("  .htaccess restored from backup.")
elif os.path.exists(htaccess):
    try:
        content = open(htaccess).read()
        if "BDUSP-GUARD" in content:
            os.remove(htaccess)
            print("  Quarantine .htaccess removed.")
    except:
        pass

# Remove challenge PHP
if os.path.exists(php_file):
    os.remove(php_file)
    print("  Challenge file removed.")

del q[domain]
json.dump(q, open(QUARANTINE, "w"), indent=2)
print("  Done.")
PYEOF
    echo -e "${GREEN}✅ $1 released from quarantine.${NC}"
}

cmd_quarantine_release_all() {
    python3 << PYEOF
import json, os, shutil

QUARANTINE = "$QUARANTINE"
PHP_FILE   = ".bdusp_ddos_challenge.php"

try:
    q = json.load(open(QUARANTINE))
except:
    print("  No quarantine data.")
    exit()

if not q:
    print("  No quarantined domains.")
    exit()

count = 0
for domain, info in list(q.items()):
    docroot = info.get("docroot", "")
    if docroot:
        htaccess = os.path.join(docroot, ".htaccess")
        backup   = os.path.join(docroot, ".htaccess.bdusp_bak")
        php_file = os.path.join(docroot, PHP_FILE)

        if os.path.exists(backup):
            shutil.move(backup, htaccess)
        elif os.path.exists(htaccess):
            try:
                if "BDUSP-GUARD" in open(htaccess).read():
                    os.remove(htaccess)
            except:
                pass

        if os.path.exists(php_file):
            os.remove(php_file)

    count += 1
    print("  Released: {}".format(domain))

json.dump({}, open(QUARANTINE, "w"), indent=2)
print("  Total released: {}".format(count))
PYEOF
    echo -e "${GREEN}✅ All domains released from quarantine.${NC}"
}

# ── blocklist ─────────────────────────────────────────────────────────────────
_show_bl() {
    local f="$1"
    py "
import json,time
try: data=json.load(open('$BLOCKLIST'))
except: data={}
filt='$f'
rows=[]
for ip,i in data.items():
    perm=i.get('permanent',False)
    if filt=='temp' and perm: continue
    if filt=='perm' and not perm: continue
    bt=time.strftime('%Y-%m-%d %H:%M',time.localtime(i.get('time',0)))
    if perm: ex='Never'
    else: ex=time.strftime('%Y-%m-%d %H:%M',time.localtime(i.get('time',0)+(i.get('duration') or 0)))
    src='auto' if i.get('auto') else 'manual'
    dom=i.get('domain','') or '-'
    rows.append((ip,'PERMANENT' if perm else '7 Days',bt,ex,src,dom))
if not rows: print('  No entries.'); exit()
print(f\"  {'IP':<20} {'Type':<11} {'Blocked At':<17} {'Expires':<17} {'Src':<7} {'Domain'}\")
print(f\"  {'─'*20} {'─'*11} {'─'*17} {'─'*17} {'─'*7} {'─'*20}\")
for r in rows:
    print(f'  {r[0]:<20} {r[1]:<11} {r[2]:<17} {r[3]:<17} {r[4]:<7} {r[5]}')
print()
"
}

cmd_blocklist()      { header; echo -e "\n  ${BOLD}All Blocked IPs:${NC}\n";      _show_bl all; }
cmd_blocklist_temp() { header; echo -e "\n  ${BOLD}Temp Blocked (7-day):${NC}\n"; _show_bl temp; }
cmd_blocklist_perm() { header; echo -e "\n  ${BOLD}Permanent Blocked:${NC}\n";    _show_bl perm; }

_add_bl() {
    local perm="$1"; shift
    local raw="$*"
    IFS=', ' read -ra ips <<< "$raw"
    local invalid=()
    for ip in "${ips[@]}"; do
        ip=$(echo "$ip" | tr -d ',' | xargs)
        [ -z "$ip" ] && continue
        if ! valid_ip "$ip"; then invalid+=("$ip"); continue; fi
        iptables -I INPUT -s "$ip" -j DROP 2>/dev/null
        iptables -I OUTPUT -d "$ip" -j DROP 2>/dev/null
        python3 -c "
import json,time,os
os.makedirs('$BASE',exist_ok=True)
try: d=json.load(open('$BLOCKLIST'))
except: d={}
perm=$perm
d['$ip']={'time':time.time(),'duration':None if perm else 604800,
          'permanent':perm,'label':'PERMANENT' if perm else '7d',
          'auto':False,'domain':'manual'}
json.dump(d,open('$BLOCKLIST','w'),indent=2)
"
        echo -e "${GREEN}  ✅ Blocked: $ip${NC}"
    done
    [ ${#invalid[@]} -gt 0 ] && echo -e "${RED}  Invalid IP(s): ${invalid[*]}${NC}"
}

_rm_bl() {
    local raw="$*"
    IFS=', ' read -ra ips <<< "$raw"
    local invalid=()
    for ip in "${ips[@]}"; do
        ip=$(echo "$ip" | tr -d ',' | xargs)
        [ -z "$ip" ] && continue
        if ! valid_ip "$ip"; then invalid+=("$ip"); continue; fi
        iptables -D INPUT -s "$ip" -j DROP 2>/dev/null
        iptables -D OUTPUT -d "$ip" -j DROP 2>/dev/null
        python3 -c "
import json
try: d=json.load(open('$BLOCKLIST')); d.pop('$ip',None); json.dump(d,open('$BLOCKLIST','w'),indent=2)
except: pass
"
        echo -e "${GREEN}  ✅ Removed: $ip${NC}"
    done
    [ ${#invalid[@]} -gt 0 ] && echo -e "${RED}  Invalid IP(s): ${invalid[*]}${NC}"
}

cmd_blocklist_add()             { [ -z "$1" ] && echo -e "${RED}Usage: vg blocklist-add <ip> [ip2]${NC}" && exit 1; _add_bl True "$@"; }
cmd_blocklist_remove()          { [ -z "$1" ] && echo -e "${RED}Usage: vg blocklist-remove <ip> [ip2]${NC}" && exit 1; _rm_bl "$@"; }

cmd_blocklist_remove_all() {
    echo -e "${YELLOW}Removing ALL blocked IPs...${NC}"
    py "
import json,subprocess
try: data=json.load(open('$BLOCKLIST'))
except: data={}
for ip in data:
    subprocess.run('iptables -D INPUT -s {} -j DROP 2>/dev/null'.format(ip),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    subprocess.run('iptables -D OUTPUT -d {} -j DROP 2>/dev/null'.format(ip),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
json.dump({},open('$BLOCKLIST','w'),indent=2)
print('  Removed {} IP(s).'.format(len(data)))
"
    echo -e "${GREEN}✅ Done.${NC}"
}

cmd_blocklist_remove_all_temp() {
    echo -e "${YELLOW}Removing all temp (7-day) blocked IPs...${NC}"
    py "
import json,subprocess
try: data=json.load(open('$BLOCKLIST'))
except: data={}
to_del=[ip for ip,i in data.items() if not i.get('permanent')]
for ip in to_del:
    subprocess.run('iptables -D INPUT -s {} -j DROP 2>/dev/null'.format(ip),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    subprocess.run('iptables -D OUTPUT -d {} -j DROP 2>/dev/null'.format(ip),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    del data[ip]
json.dump(data,open('$BLOCKLIST','w'),indent=2)
print('  Removed {} IP(s).'.format(len(to_del)))
"
    echo -e "${GREEN}✅ Done.${NC}"
}

cmd_blocklist_remove_all_perm() {
    echo -e "${YELLOW}Removing all permanent blocked IPs...${NC}"
    py "
import json,subprocess
try: data=json.load(open('$BLOCKLIST'))
except: data={}
to_del=[ip for ip,i in data.items() if i.get('permanent')]
for ip in to_del:
    subprocess.run('iptables -D INPUT -s {} -j DROP 2>/dev/null'.format(ip),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    subprocess.run('iptables -D OUTPUT -d {} -j DROP 2>/dev/null'.format(ip),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    del data[ip]
json.dump(data,open('$BLOCKLIST','w'),indent=2)
print('  Removed {} IP(s).'.format(len(to_del)))
"
    echo -e "${GREEN}✅ Done.${NC}"
}

# ── whitelist ─────────────────────────────────────────────────────────────────
cmd_whitelist() {
    header; echo -e "\n  ${BOLD}Whitelisted IPs:${NC}\n"
    py "
import json,time
sys_ips={'127.0.0.1':{'added':0,'note':'system'},'::1':{'added':0,'note':'system'}}
try: u=json.load(open('$WHITELIST')); sys_ips.update(u)
except: pass
print(f\"  {'IP':<22} {'Added':<20} {'Note'}\")
print(f\"  {'─'*22} {'─'*20} {'─'*20}\")
for ip,i in sys_ips.items():
    added=time.strftime('%Y-%m-%d %H:%M',time.localtime(i.get('added',0))) if i.get('added') else 'system'
    print(f\"  {ip:<22} {added:<20} {i.get('note','')}\")
print()
"
}

_add_wl() {
    local raw="$*"
    IFS=', ' read -ra ips <<< "$raw"
    local invalid=()
    for ip in "${ips[@]}"; do
        ip=$(echo "$ip" | tr -d ',' | xargs)
        [ -z "$ip" ] && continue
        if ! valid_ip "$ip"; then invalid+=("$ip"); continue; fi
        python3 -c "
import json,time,os
os.makedirs('$BASE',exist_ok=True)
try: d=json.load(open('$WHITELIST'))
except: d={}
d['$ip']={'added':time.time(),'note':'manual'}
json.dump(d,open('$WHITELIST','w'),indent=2)
"
        echo -e "${GREEN}  ✅ Whitelisted: $ip${NC}"
    done
    [ ${#invalid[@]} -gt 0 ] && echo -e "${RED}  Invalid IP(s): ${invalid[*]}${NC}"
}

_rm_wl() {
    local raw="$*"
    IFS=', ' read -ra ips <<< "$raw"
    local invalid=()
    for ip in "${ips[@]}"; do
        ip=$(echo "$ip" | tr -d ',' | xargs)
        [ -z "$ip" ] && continue
        if ! valid_ip "$ip"; then invalid+=("$ip"); continue; fi
        python3 -c "
import json
try: d=json.load(open('$WHITELIST')); d.pop('$ip',None); json.dump(d,open('$WHITELIST','w'),indent=2)
except: pass
"
        echo -e "${GREEN}  ✅ Removed: $ip${NC}"
    done
    [ ${#invalid[@]} -gt 0 ] && echo -e "${RED}  Invalid IP(s): ${invalid[*]}${NC}"
}

cmd_whitelist_add()        { [ -z "$1" ] && echo -e "${RED}Usage: vg whitelist-add <ip> [ip2]${NC}" && exit 1; _add_wl "$@"; }
cmd_whitelist_remove()     { [ -z "$1" ] && echo -e "${RED}Usage: vg whitelist-remove <ip> [ip2]${NC}" && exit 1; _rm_wl "$@"; }
cmd_whitelist_remove_all() {
    py "import json; json.dump({},open('$WHITELIST','w'),indent=2); print('  Cleared.')"
    echo -e "${GREEN}✅ Done.${NC}"
}

# ── log / service ─────────────────────────────────────────────────────────────
cmd_log()       { echo -e "${CYAN}━━━━ Live Log (Ctrl+C) ━━━━${NC}"; tail -f "$LOGFILE"; }
cmd_log_clear() { > "$LOGFILE" && echo -e "${GREEN}✅ Log cleared.${NC}"; }
cmd_start()     { systemctl start   ddos-guard && echo -e "${GREEN}▶ Started.${NC}"; }
cmd_stop()      { systemctl stop    ddos-guard && echo -e "${YELLOW}⏹ Stopped.${NC}"; }
cmd_restart()   { systemctl restart ddos-guard && echo -e "${GREEN}↺ Restarted.${NC}"; }

# ── help ──────────────────────────────────────────────────────────────────────
cmd_help() {
    header; echo ""
    echo -e "  ${BOLD}INFO${NC}"
    echo -e "  vg status                          Status + config"
    echo -e "  vg log                             Live log"
    echo -e "  vg log-clear                       Clear log"
    echo ""
    echo -e "  ${BOLD}CONFIG${NC}"
    echo -e "  vg config                          Show all config"
    echo -e "  vg config <key> <value>            Edit config"
    echo -e "    ${CYAN}window_seconds, block_threshold, perm_threshold${NC}"
    echo -e "    ${CYAN}q_enabled, q_single_ip, q_all_ip, q_cooldown${NC}"
    echo ""
    echo -e "  ${BOLD}QUARANTINE${NC}"
    echo -e "  vg quarantine                      List quarantined domains"
    echo -e "  vg quarantine-on                   Enable quarantine system"
    echo -e "  vg quarantine-off                  Disable quarantine system"
    echo -e "  vg quarantine-release <domain>     Release one domain"
    echo -e "  vg quarantine-release-all          Release ALL domains"
    echo ""
    echo -e "  ${BOLD}BLOCKLIST${NC}"
    echo -e "  vg blocklist                       All blocked IPs"
    echo -e "  vg blocklist-temp                  7-day blocked only"
    echo -e "  vg blocklist-perm                  Permanent blocked only"
    echo -e "  vg blocklist-add <ip> [ip2...]     Add IP(s) — permanent"
    echo -e "  vg blocklist-remove <ip> [ip2...]  Remove IP(s)"
    echo -e "  vg blocklist-remove-all            Remove ALL"
    echo -e "  vg blocklist-remove-all-temp       Remove all 7-day"
    echo -e "  vg blocklist-remove-all-perm       Remove all permanent"
    echo ""
    echo -e "  ${BOLD}WHITELIST${NC}"
    echo -e "  vg whitelist                       Show whitelist"
    echo -e "  vg whitelist-add <ip> [ip2...]     Add IP(s)"
    echo -e "  vg whitelist-remove <ip> [ip2...]  Remove IP(s)"
    echo -e "  vg whitelist-remove-all            Remove all"
    echo ""
    echo -e "  ${BOLD}SERVICE${NC}"
    echo -e "  vg start / vg stop / vg restart"
    echo ""
}

# ── router ────────────────────────────────────────────────────────────────────
case "$1" in
    status)                    cmd_status ;;
    config)                    cmd_config "$2" "$3" ;;
    quarantine)                cmd_quarantine ;;
    quarantine-on)             cmd_quarantine_on ;;
    quarantine-off)            cmd_quarantine_off ;;
    quarantine-release)        cmd_quarantine_release "$2" ;;
    quarantine-release-all)    cmd_quarantine_release_all ;;
    log)                       cmd_log ;;
    log-clear)                 cmd_log_clear ;;
    blocklist)                 cmd_blocklist ;;
    blocklist-temp)            cmd_blocklist_temp ;;
    blocklist-perm)            cmd_blocklist_perm ;;
    blocklist-add)             shift; cmd_blocklist_add "$@" ;;
    blocklist-remove)          shift; cmd_blocklist_remove "$@" ;;
    blocklist-remove-all)      cmd_blocklist_remove_all ;;
    blocklist-remove-all-temp) cmd_blocklist_remove_all_temp ;;
    blocklist-remove-all-perm) cmd_blocklist_remove_all_perm ;;
    whitelist)                 cmd_whitelist ;;
    whitelist-add)             shift; cmd_whitelist_add "$@" ;;
    whitelist-remove)          shift; cmd_whitelist_remove "$@" ;;
    whitelist-remove-all)      cmd_whitelist_remove_all ;;
    start)                     cmd_start ;;
    stop)                      cmd_stop ;;
    restart)                   cmd_restart ;;
    help|--help|-h)            cmd_help ;;
    *)                         cmd_help ;;
esac
