#!/bin/bash
# Active leak testing for privacy containers
# Runs tests from inside the container to check for leaks
#
# Usage: test-leaks.sh <container> [--type tor|vpn|wireguard]
#
# Requirements: sudo, machinectl

set -e

CONTAINER=""
PRIVACY_TYPE="tor"
VERBOSE=0
PASSED=0
FAILED=0

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

usage() {
    cat << EOF
Active Leak Testing for Privacy Containers

Usage: $0 <container> [options]

Options:
  --type, -t <type>    Privacy type: tor, vpn, wireguard (default: tor)
  --verbose, -v        Verbose output
  --help, -h           Show this help

Tests performed:
  - DNS leak test (direct DNS queries)
  - Direct IP connection test
  - IPv6 leak test
  - Tunnel verification (check IP through tunnel)
  - iptables rule verification

Examples:
  $0 tor-browser
  $0 vpn-gateway --type vpn
EOF
    exit 1
}

log() { echo -e "${CYAN}[test]${NC} $1"; }
pass() { echo -e "${GREEN}[PASS]${NC} $1"; PASSED=$((PASSED+1)); }
fail() { echo -e "${RED}[FAIL]${NC} $1"; FAILED=$((FAILED+1)); }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --type|-t)
            PRIVACY_TYPE="$2"
            shift 2
            ;;
        --verbose|-v)
            VERBOSE=1
            shift
            ;;
        --help|-h)
            usage
            ;;
        -*)
            echo "Unknown option: $1"
            usage
            ;;
        *)
            if [[ -z "$CONTAINER" ]]; then
                CONTAINER="$1"
            fi
            shift
            ;;
    esac
done

if [[ -z "$CONTAINER" ]]; then
    echo "Container name required"
    usage
fi

# Check container is running
if ! sudo machinectl status "$CONTAINER" &>/dev/null; then
    echo "Error: Container '$CONTAINER' is not running"
    exit 1
fi

# Run command in container
run_in_container() {
    local timeout="${2:-10}"
    sudo machinectl shell "$CONTAINER" /bin/bash -c "$1" 2>/dev/null
}

# Get container PID
get_pid() {
    sudo machinectl show "$CONTAINER" -p Leader --value
}

echo ""
echo "========================================"
echo "  Network Leak Test: $CONTAINER"
echo "  Privacy Type: $PRIVACY_TYPE"
echo "========================================"
echo ""

# Test 1: DNS Leak Test
log "Test 1: DNS Leak Test"
log "  Attempting direct DNS query to 8.8.8.8..."

# Try DNS query using available tools
DNS_RESULT=$(run_in_container "
if command -v dig &>/dev/null; then
    dig +short +timeout=5 @8.8.8.8 whoami.akamai.net 2>&1
elif command -v nslookup &>/dev/null; then
    timeout 5 nslookup whoami.akamai.net 8.8.8.8 2>&1
elif command -v host &>/dev/null; then
    timeout 5 host whoami.akamai.net 8.8.8.8 2>&1
else
    # Test raw UDP to DNS port
    timeout 5 bash -c 'echo > /dev/udp/8.8.8.8/53' 2>&1 && echo 'UDP_OPEN' || echo 'BLOCKED'
fi
" || echo "BLOCKED")

if echo "$DNS_RESULT" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'; then
    fail "DNS leak detected! Query to 8.8.8.8 succeeded: $DNS_RESULT"
elif echo "$DNS_RESULT" | grep -qiE 'timed out|connection refused|BLOCKED|no servers|can.t find|network is unreachable'; then
    pass "DNS leak test passed - external DNS is blocked"
elif echo "$DNS_RESULT" | grep -q "UDP_OPEN"; then
    # UDP port 53 is open but may be redirected to Tor DNS
    # Check iptables for DNS redirect
    PID=$(get_pid)
    if sudo nsenter -t "$PID" -n iptables-save 2>/dev/null | grep -q "udp.*53.*REDIRECT"; then
        pass "DNS test passed - DNS is redirected to Tor"
    else
        warn "UDP port 53 is open - verify DNS is going through Tor"
    fi
else
    warn "DNS test inconclusive: ${DNS_RESULT:0:100}"
fi
echo ""

# Test 2: Direct IP Connection Test (bypass proxy check)
log "Test 2: Direct IP Connection Test"
log "  Checking if traffic bypasses tunnel..."

# For Tor transparent proxy containers, all traffic goes through Tor
# We check if iptables rules redirect traffic to Tor ports
PID=$(get_pid)
IPTABLES_RULES=$(sudo nsenter -t "$PID" -n iptables-save 2>/dev/null || echo "")

if echo "$IPTABLES_RULES" | grep -q "REDIRECT.*9040"; then
    pass "Traffic redirect rule found - TCP goes through Tor transparent proxy"
else
    # Try a direct connection test
    IP_RESULT=$(run_in_container "curl -s --connect-timeout 5 http://1.1.1.1/cdn-cgi/trace 2>&1" || echo "BLOCKED")
    if echo "$IP_RESULT" | grep -qiE 'timed out|connection refused|BLOCKED|Could not'; then
        pass "Direct IP test passed - direct connections are blocked"
    elif echo "$IP_RESULT" | grep -q "ip="; then
        # Check if the IP is a Tor exit node
        DETECTED_IP=$(echo "$IP_RESULT" | grep "ip=" | cut -d= -f2)
        warn "Connection succeeded via IP: $DETECTED_IP (check if this is a Tor exit)"
    else
        warn "Direct IP test inconclusive: ${IP_RESULT:0:50}"
    fi
fi
echo ""

# Test 3: IPv6 Leak Test
log "Test 3: IPv6 Leak Test"
log "  Checking for IPv6 connectivity..."

IPV6_RESULT=$(run_in_container "curl -6 -s --connect-timeout 5 http://ipv6.icanhazip.com/ 2>&1" || echo "BLOCKED")

if echo "$IPV6_RESULT" | grep -qE '^[0-9a-fA-F:]+$'; then
    fail "IPv6 leak detected! IPv6 address: $IPV6_RESULT"
elif echo "$IPV6_RESULT" | grep -qiE 'timed out|Could not|BLOCKED|Network is unreachable'; then
    pass "IPv6 leak test passed - IPv6 is disabled or blocked"
else
    pass "IPv6 test passed (no connectivity)"
fi
echo ""

# Test 4: Tunnel Verification
log "Test 4: Tunnel Verification"
case $PRIVACY_TYPE in
    tor)
        log "  Checking Tor connectivity..."
        TOR_CHECK=$(run_in_container "curl -s --socks5 127.0.0.1:9050 https://check.torproject.org/api/ip 2>&1" || echo "FAILED")

        if echo "$TOR_CHECK" | grep -q '"IsTor":true'; then
            pass "Tor verification passed - traffic is going through Tor"
            TOR_IP=$(echo "$TOR_CHECK" | grep -oP '"IP":"[^"]+' | cut -d'"' -f4)
            log "  Tor exit IP: $TOR_IP"
        elif echo "$TOR_CHECK" | grep -q '"IsTor":false'; then
            fail "Tor verification failed - NOT using Tor!"
        else
            warn "Tor verification inconclusive: ${TOR_CHECK:0:50}"
        fi
        ;;
    vpn)
        log "  Checking VPN tunnel interface..."
        # Check for tun0 (OpenVPN) or WireGuard interfaces (wg0, mullvad, etc.)
        VPN_IF=$(run_in_container "ip addr show tun0 2>&1" || echo "NOT_FOUND")
        WG_IF=""
        WG_NAME=""

        if echo "$VPN_IF" | grep -q "inet "; then
            pass "VPN interface (tun0) is up"
            VPN_IP=$(echo "$VPN_IF" | grep -oP 'inet \K[0-9.]+')
            log "  VPN IP: $VPN_IP"
        else
            # Try WireGuard interfaces
            for iface in mullvad wg0 wg1; do
                WG_IF=$(run_in_container "ip addr show $iface 2>&1" || echo "NOT_FOUND")
                if echo "$WG_IF" | grep -q "inet "; then
                    WG_NAME="$iface"
                    break
                fi
            done

            if [ -n "$WG_NAME" ]; then
                pass "WireGuard interface ($WG_NAME) is up"
                # Strip ANSI codes and extract IP
                WG_IP=$(echo "$WG_IF" | sed 's/\x1b\[[0-9;]*m//g' | grep -oP 'inet \K[0-9.]+' | head -1)
                log "  WireGuard IP: $WG_IP"
            else
                fail "VPN interface (tun0/wg0/mullvad) not found or not up"
            fi
        fi
        ;;
    wireguard)
        log "  Checking WireGuard tunnel interface..."
        # Check for common WireGuard interface names
        WG_IF=""
        WG_NAME=""
        for iface in wg0 mullvad wg1; do
            WG_IF=$(run_in_container "ip addr show $iface 2>&1" || echo "NOT_FOUND")
            if echo "$WG_IF" | grep -q "inet "; then
                WG_NAME="$iface"
                break
            fi
        done

        if [ -n "$WG_NAME" ]; then
            pass "WireGuard interface ($WG_NAME) is up"
            # Strip ANSI codes and extract IP
            WG_IP=$(echo "$WG_IF" | sed 's/\x1b\[[0-9;]*m//g' | grep -oP 'inet \K[0-9.]+' | head -1)
            log "  WireGuard IP: $WG_IP"
        else
            fail "WireGuard interface (wg0/mullvad) not found or not up"
        fi
        ;;
esac
echo ""

# Test 5: iptables Rules Check
log "Test 5: Firewall Rules Check"
PID=$(get_pid)

IPTABLES=$(sudo nsenter -t "$PID" -n iptables-save 2>/dev/null || echo "")

if [[ -z "$IPTABLES" ]]; then
    warn "Could not read iptables rules"
else
    case $PRIVACY_TYPE in
        tor)
            if echo "$IPTABLES" | grep -q "REDIRECT.*9040"; then
                pass "Tor transparent proxy redirect rule found"
            else
                warn "No Tor transparent proxy redirect found"
            fi

            if echo "$IPTABLES" | grep -qE "(DROP|REJECT)"; then
                pass "Kill switch rules found (DROP/REJECT)"
            else
                warn "No kill switch rules found"
            fi
            ;;
        vpn|wireguard)
            if echo "$IPTABLES" | grep -qE "(DROP|REJECT)"; then
                pass "Kill switch rules found"
            else
                warn "No kill switch rules found"
            fi
            ;;
    esac

    if echo "$IPTABLES" | grep -q "LOG"; then
        pass "Logging rules found for leak detection"
    else
        warn "No logging rules found (recommended for leak detection)"
    fi
fi
echo ""

# Test 6: Check for iptables LOG entries (recent leaks)
log "Test 6: Checking for logged leak attempts..."
LEAK_LOGS=$(sudo journalctl -k --since "1 hour ago" 2>/dev/null | grep -i "leak" | tail -5 || echo "")

if [[ -n "$LEAK_LOGS" ]]; then
    warn "Recent leak attempts found in kernel log:"
    echo "$LEAK_LOGS"
else
    pass "No recent leak attempts in kernel log"
fi
echo ""

# Summary
echo "========================================"
echo "  Test Summary"
echo "========================================"
echo -e "  ${GREEN}Passed: $PASSED${NC}"
echo -e "  ${RED}Failed: $FAILED${NC}"
echo ""

if [[ $FAILED -eq 0 ]]; then
    echo -e "${GREEN}All tests passed! Container appears secure.${NC}"
    exit 0
else
    echo -e "${RED}Some tests failed! Review the issues above.${NC}"
    exit 1
fi
