#!/bin/bash
# Continuous network leak monitor for privacy containers
# Monitors from the host side using tcpdump
#
# Usage: monitor-leaks.sh <container> [--type tor|vpn|wireguard] [--log <file>]
#
# Requirements: tcpdump, sudo

set -e

CONTAINER=""
PRIVACY_TYPE="tor"
LOG_FILE=""
ALERT_CMD=""
VERBOSE=0

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

usage() {
    cat << EOF
Network Leak Monitor for Privacy Containers

Usage: $0 <container> [options]

Options:
  --type, -t <type>    Privacy type: tor, vpn, wireguard (default: tor)
  --log, -l <file>     Log leak events to file
  --alert, -a <cmd>    Command to run on leak detection (receives JSON via stdin)
  --verbose, -v        Verbose output
  --help, -h           Show this help

Examples:
  $0 tor-browser                           # Monitor Tor container
  $0 vpn-gateway --type vpn --log leaks.log
  $0 tor-browser --alert 'notify-send "Leak detected!"'
EOF
    exit 1
}

log() { echo -e "${CYAN}[monitor]${NC} $1"; }
warn() { echo -e "${YELLOW}[monitor]${NC} $1"; }
error() { echo -e "${RED}[monitor]${NC} $1"; }
alert() { echo -e "${RED}[LEAK]${NC} $1"; }

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

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

# Check if container is running
check_container() {
    if ! sudo machinectl status "$CONTAINER" &>/dev/null; then
        error "Container '$CONTAINER' is not running"
        exit 1
    fi
}

# Get container's network namespace PID
get_container_pid() {
    sudo machinectl show "$CONTAINER" -p Leader --value 2>/dev/null
}

# Get veth interface for container (if using bridge networking)
get_veth_interface() {
    local veth="ve-${CONTAINER}"
    if ip link show "$veth" &>/dev/null; then
        echo "$veth"
        return
    fi

    # Try alternate naming
    veth="vb-${CONTAINER}"
    if ip link show "$veth" &>/dev/null; then
        echo "$veth"
        return
    fi

    echo ""
}

# Build tcpdump filter based on privacy type
build_filter() {
    local filter=""

    case $PRIVACY_TYPE in
        tor)
            # For Tor: capture anything not going to localhost (leak)
            filter="not host 127.0.0.1 and not host ::1"
            # Exclude common private networks
            filter="$filter and not net 10.0.0.0/8"
            filter="$filter and not net 172.16.0.0/12"
            filter="$filter and not net 192.168.0.0/16"
            ;;
        vpn)
            # For VPN: we monitor the physical interface
            # Filter out VPN tunnel traffic (usually UDP to VPN server)
            # This needs customization based on VPN config
            filter="not port 1194 and not port 443"
            filter="$filter and not net 10.0.0.0/8"
            filter="$filter and not net 172.16.0.0/12"
            filter="$filter and not net 192.168.0.0/16"
            ;;
        wireguard)
            # For WireGuard: filter out WG traffic
            filter="not port 51820"
            filter="$filter and not net 10.0.0.0/8"
            filter="$filter and not net 172.16.0.0/12"
            filter="$filter and not net 192.168.0.0/16"
            ;;
    esac

    echo "$filter"
}

# Process a captured packet line
process_packet() {
    local line="$1"
    local timestamp=$(date -Iseconds)
    local leak_type=""
    local details=""

    # Detect IPv6 traffic (common leak)
    if echo "$line" | grep -q " IP6 "; then
        leak_type="ipv6"
        details="IPv6 traffic detected"
    # Detect DNS to external servers
    elif echo "$line" | grep -qE '\.53:|> [0-9.]+\.53:'; then
        if ! echo "$line" | grep -q "127.0.0"; then
            leak_type="dns"
            details="DNS query to external server"
        fi
    # Detect direct IP connections
    elif echo "$line" | grep -qE '> [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:'; then
        leak_type="direct_ip"
        details="Direct IP connection"
    fi

    if [[ -n "$leak_type" ]]; then
        local json="{\"timestamp\":\"$timestamp\",\"container\":\"$CONTAINER\",\"type\":\"$leak_type\",\"details\":\"$details\",\"packet\":\"${line:0:200}\"}"

        alert "$leak_type: $details"
        if [[ $VERBOSE -eq 1 ]]; then
            echo "  Packet: ${line:0:100}..."
        fi

        # Log to file
        if [[ -n "$LOG_FILE" ]]; then
            echo "$json" >> "$LOG_FILE"
        fi

        # Run alert command
        if [[ -n "$ALERT_CMD" ]]; then
            echo "$json" | bash -c "$ALERT_CMD" 2>/dev/null &
        fi
    fi
}

# Main monitoring function
monitor() {
    check_container

    local pid=$(get_container_pid)
    if [[ -z "$pid" ]]; then
        error "Could not get container PID"
        exit 1
    fi

    local veth=$(get_veth_interface)
    local filter=$(build_filter)

    log "Monitoring container: $CONTAINER"
    log "Privacy type: $PRIVACY_TYPE"
    log "Container PID: $pid"

    if [[ -n "$veth" ]]; then
        log "Using veth interface: $veth"
        log "Filter: $filter"
        log "Starting tcpdump on interface..."

        # Monitor the veth interface from host
        sudo tcpdump -i "$veth" -l -n -q $filter 2>/dev/null | while read line; do
            process_packet "$line"
        done
    else
        log "No veth interface found, monitoring from container netns"
        log "Filter: $filter"
        log "Starting tcpdump in container network namespace..."

        # Monitor from inside container's network namespace
        sudo nsenter -t "$pid" -n tcpdump -l -n -q $filter 2>/dev/null | while read line; do
            process_packet "$line"
        done
    fi
}

# Trap for cleanup
cleanup() {
    log "Stopping monitor..."
    # tcpdump gets killed when script exits
    exit 0
}
trap cleanup SIGINT SIGTERM

# Run
log "Starting network leak monitor..."
if [[ -n "$LOG_FILE" ]]; then
    log "Logging to: $LOG_FILE"
fi

monitor
