#!/bin/bash
# N-ETHER: Network Enumeration Tool with Host Discovery, Concurrency, and Advanced Auditing
set -euo pipefail # Strict mode for safety

# --- 1. CONFIGURATION AND UTILITIES ---

# ANSI Color Codes
RED='\033[0;31m'    # Errors
GREEN='\033[0;32m'  # Success/Found Data
BLUE='\033[0;34m'   # INFO messages
NC='\033[0m'        # No Color (Reset)

# Global Variables (set to defaults)
MASTER_LOG_FILE=""    # Holds the primary scan log/summary file name
TARGET_HOST=""        # Holds single target or list file name
PROXY_ADDR=""
TCP_PORTS_TO_SCAN="-" # Default: all ports
UDP_SCAN_ENABLED=true # Default: enabled
TEMP_TCP_PORTS=""
IPV6_ENABLED=""       # Holds the Nmap -6 flag
LIST_SCAN_MODE=false  # Flag to control list processing
ADVANCED_SCRIPTS=""   # Holds the Nmap --script arguments
HOST_DISCOVERY="-Pn"  # Default: No Ping, assumes host is up for maximum bypass

# --- Logging Functions ---

# Logs accept an optional second argument (LOG_TARGET_FILE) to handle per-target logging
log_info() {
    local MESSAGE="$1"
    local LOG_FILE="${2:-$MASTER_LOG_FILE}" # Use $2 (target file) if set, otherwise use master log
    echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $0: ${MESSAGE}${NC}"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $0: ${MESSAGE}" >> "${LOG_FILE}"
}

# NOTE: log_error is refactored. We rely on 'set -e' for fatal errors in main()
# but simply log and continue for background job failures (non-fatal to the script).
log_error() {
    local MESSAGE="$1"
    local LOG_FILE="${2:-$MASTER_LOG_FILE}"
    echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $0: ${MESSAGE}${NC}" >&2
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $0: ${MESSAGE}" >> "${LOG_FILE}"
    
    # Only exit if we are running sequentially (no target log file provided)
    if [ -z "$2" ]; then
        exit 1
    fi
}

log_success() {
    local MESSAGE="$1"
    local LOG_FILE="${2:-$MASTER_LOG_FILE}"
    echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $0: ${MESSAGE}${NC}"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $0: ${MESSAGE}" >> "${LOG_FILE}"
}

# --- Usage Function ---

usage() {
    echo "Usage: $0 [-t <target> | -L <target_file>] [-q | -f] [-x <proxy_url>] [-6] [-a] [-d] [-h]"
    echo ""
    echo "  -t <target>      Scan a single IP address or hostname (REQUIRED if -L is not used)."
    echo "  -L <target_file> Scan targets listed in a file, one per line (REQUIRED if -t is not used)."
    echo "  -q               Quick Scan (Top 100 TCP ports only, skip UDP)."
    echo "  -f               Full Scan (All TCP ports, Top 200 UDP ports) (DEFAULT)."
    echo "  -x <proxy>       Route scan traffic through a SOCKS5 proxy."
    echo "  -6               Enable IPv6 scanning mode. Target must be a valid IPv6 address/hostname."
    echo "  -a               Advanced Audit: Includes specific NSE vulnerability/discovery scripts."
    echo "  -d               Host Discovery: Use Nmap's default ping/ARP scan (Default is -Pn: No ping, assume up)."
    echo "  -h               Display this help message."
    exit 0
}

# --- 2. REPORTING AND PARSING FUNCTION ---

generate_summary() {
    local SUMMARY_FILE="summary_$(basename "${MASTER_LOG_FILE}" .txt)_$(date +%F_%H%M).txt"
    log_info "Step 3: Generating summarized report to ${SUMMARY_FILE}..."
    
    echo "--- SCAN SUMMARY ---" > "${SUMMARY_FILE}"
    echo "Target Source: ${TARGET_HOST}" >> "${SUMMARY_FILE}"
    echo "Date: $(date '+%Y-%m-%d %H:%M:%S')" >> "${SUMMARY_FILE}"
    echo "--------------------" >> "${SUMMARY_FILE}"
    echo "Target | Protocol | Port | State | Service | Version" >> "${SUMMARY_FILE}"
    echo "---------------------------------------------------------------------------------------" >> "${SUMMARY_FILE}"

    # Determine which file(s) to parse:
    local NMAP_OUTPUT_FILES
    if $LIST_SCAN_MODE; then
        # Find all individual target scan files
        NMAP_OUTPUT_FILES=$(find . -maxdepth 1 -type f -name 'scan_target_*.txt')
        if [ -z "$NMAP_OUTPUT_FILES" ]; then
            log_error "No individual target scan files found to generate summary."
            return # Don't exit the script, but stop summary generation
        fi
    else
        # Use the single master log file for single target mode
        NMAP_OUTPUT_FILES="${MASTER_LOG_FILE}"
    fi


    # Parse Nmap output: look for Host headers and open/filtered lines across all target files
    grep -E 'Host:|open|filtered' ${NMAP_OUTPUT_FILES} 2>/dev/null | \
    awk '
        /Host:/ {
            # Capture the current host IP/Name
            HOST=$2
            next
        }
        /open|filtered/ {
            # $1=port/proto, $2=state, $3=service, $4..=version
            protocol = ($1 ~ /udp/) ? "UDP" : "TCP";
            state = $2;
            
            # Use printf for neat columnar output including the HOST
            printf "%-6s | %-8s | %-4s | %-7s | %-15s | %s\n", HOST, protocol, $1, state, $3, substr($0, index($0,$4))
        }
    ' >> "${SUMMARY_FILE}"

    log_success "Summary report created:"
    echo "----------------------------------------"
    cat "${SUMMARY_FILE}"
    echo "----------------------------------------"
}

# --- CORE SCANNING FUNCTION (Run per Target) ---

scan_target() {
    local CURRENT_TARGET="$1"
    local TARGET_LOG="$2" # The specific log file for this target
    
    # --- Step 1: TCP Port Discovery and Service Scan ---
    log_info "Step 1: Discovering open TCP ports (using -p${TCP_PORTS_TO_SCAN}) on ${CURRENT_TARGET}..." "${TARGET_LOG}"

    if [ "$TCP_PORTS_TO_SCAN" == "-" ]; then
        # Full scan: Use Nmap pipeline to find ALL open ports
        log_info "Running full TCP port discovery scan (all 65535 ports)..." "${TARGET_LOG}"
        
        # Nmap call with quoted optional variables for robustness
        TEMP_TCP_PORTS=$(nmap -T4 -p- "$HOST_DISCOVERY" -oG - "$PROXY_ADDR" "$IPV6_ENABLED" "$CURRENT_TARGET" | \
            grep 'Ports:' | \
            awk '{print $NF}' | \
            tr ',' ' ' | \
            sed 's/(\(.*\))//g')
    else
        # Quick scan: Use the predefined port list
        TEMP_TCP_PORTS="${TCP_PORTS_TO_SCAN}"
        log_info "Using predefined quick scan port list: ${TEMP_TCP_PORTS}" "${TARGET_LOG}"
    fi

    if [ -n "$TEMP_TCP_PORTS" ]; then
        log_success "Found/Targeted TCP Ports on ${CURRENT_TARGET}: ${TEMP_TCP_PORTS}" "${TARGET_LOG}"
        log_info "Running detailed Nmap TCP scan on these ports..." "${TARGET_LOG}"
        
        # Detailed TCP scan using the specific target log file
        nmap -p "${TEMP_TCP_PORTS}" -sC -sV "$ADVANCED_SCRIPTS" -oN "${TARGET_LOG}" --append-output "$HOST_DISCOVERY" "$PROXY_ADDR" "$IPV6_ENABLED" "$CURRENT_TARGET" || log_error "Detailed TCP scan failed on ${CURRENT_TARGET}." "${TARGET_LOG}"
    else
        log_info "No open TCP ports found on ${CURRENT_TARGET}." "${TARGET_LOG}"
    fi

    # --- Step 2: Conditional UDP Port and Service Discovery ---
    if $UDP_SCAN_ENABLED; then
        if [ -n "$PROXY_ADDR" ]; then
            log_info "SOCKS proxy specified. Skipping UDP scan on ${CURRENT_TARGET} as it is unreliable via proxy." "${TARGET_LOG}"
        else
            log_info "Step 2: Running UDP service discovery on top 200 ports on ${CURRENT_TARGET}..." "${TARGET_LOG}"
            
            # UDP scan using the specific target log file
            nmap -sU -sV --top-ports 200 -oN "${TARGET_LOG}" --append-output "$HOST_DISCOVERY" "$IPV6_ENABLED" "$CURRENT_TARGET" || log_error "UDP scan failed on ${CURRENT_TARGET}." "${TARGET_LOG}"
            log_success "UDP scan completed successfully on ${CURRENT_TARGET}." "${TARGET_LOG}"
        fi
    else
        log_info "Skipping UDP scan based on Quick Scan (-q) setting." "${TARGET_LOG}"
    fi
}

# --- NEW: Banner Function ---

print_banner() {
    # Print the main ASCII art in GREEN
    echo -e "${GREEN}"
    cat <<- EOF
 ______            _________________________ ________________________ 
 \      \           \_   _____/\__    ___/   |   \_   _____/\______   \
 /   |   \   ______  |    __)_   |    | /    ~    \    __)_  |       _/
/    |    \ /_____/  |        \  |    | \    Y    /        \ |    |   \
\____|__  /         /_______  /  |____|  \___|_  /_______  / |____|_  /
       \/                  \/                 \/        \/         \/ 
EOF
    # Print the description line separately in BLUE, followed by the color reset (NC)
    echo -e "${BLUE}:: N-ETHER :: Network Enumeration Tool for Host Exploration and Recon${NC}"
    echo " ------------------------------------------------------------------"
    echo # Print a blank line for spacing
}
# --- 3. MAIN EXECUTION FUNCTION ---

main() {
    # ----------------------------------------
    # CALL THE N-ETHER BANNER FIRST
    # ----------------------------------------
    print_banner
    # --- Check Dependencies ---
    command -v nmap >/dev/null 2>&1 || log_error "Nmap is not installed. Please install it."

    # --- Process Command-Line Options ---
    while getopts ":t:L:qfhx:6ad" opt; do
        case ${opt} in
            t ) 
                TARGET_HOST=$OPTARG
                if $LIST_SCAN_MODE; then log_error "Cannot use both -t and -L simultaneously."; fi
                ;;
            L ) 
                TARGET_HOST=$OPTARG
                LIST_SCAN_MODE=true
                if [ ! -f "$TARGET_HOST" ]; then log_error "Target file not found: $TARGET_HOST"; fi
                ;;
            q ) 
                log_info "Quick Scan mode selected: Top 100 TCP ports only."
                TCP_PORTS_TO_SCAN="1-100"
                UDP_SCAN_ENABLED=false
                ;;
            f ) log_info "Full Scan mode selected (default)." ;;
            x ) 
                PROXY_ADDR="--proxy ${OPTARG}"
                log_info "Proxy enabled. Nmap traffic will be routed through: ${OPTARG}"
                ;;
            6 ) 
                IPV6_ENABLED="-6"
                log_info "IPv6 scanning enabled."
                ;;
            a ) 
                ADVANCED_SCRIPTS="--script ftp-anon,smb-enum-shares,ssl-enum-ciphers,dns-brute"
                log_info "Advanced Audit mode activated. Adding specific NSE scripts."
                ;;
            d ) # Host Discovery Flag
                HOST_DISCOVERY="" # Empty string reverts Nmap to default host discovery (ping/ARP)
                log_info "Host Discovery mode activated (using default Nmap ping)."
                ;;
            h ) usage ;;
            \? ) log_error "Invalid option: -$OPTARG. Use -h for help." ;;
            : ) log_error "Option -$OPTARG requires an argument." ;;
        esac
    done
    shift $((OPTIND -1))

    # --- Final Validation and Setup ---
    if [ -z "$TARGET_HOST" ]; then
        log_error "A target (-t) or a target list file (-L) is required. Use -h for help."
    fi

    # Set the dynamic master output file name now that TARGET_HOST is defined
    local BASE_NAME="${TARGET_HOST}"
    if $LIST_SCAN_MODE; then
        BASE_NAME=$(basename "${TARGET_HOST}")
    fi
    MASTER_LOG_FILE="scan_results_${BASE_NAME}_$(date +%F_%H%M).txt"
    
    log_info "Starting comprehensive enumeration scan on: ${TARGET_HOST}"
    echo "----------------------------------------" | tee "${MASTER_LOG_FILE}"

    # --- Target Processing Logic with Concurrency ---
    local MAX_PARALLEL_SCANS=5
    local PARALLEL_PIPE="/tmp/n-ether_pipe_$$"

    # Create the named pipe and set the file descriptor (FD)
    mkfifo "$PARALLEL_PIPE"
    exec 3<>"$PARALLEL_PIPE"

    # Pre-populate the pipe with tokens
    for i in $(seq "$MAX_PARALLEL_SCANS"); do echo >&3; done
    log_info "Starting scan queue with maximum ${MAX_PARALLEL_SCANS} concurrent jobs."
    
    if $LIST_SCAN_MODE; then
        # List Target Mode (Parallel)
        
        # Read file line by line
        while IFS= read -r IP_OR_HOST; do
            # Target Sanitization: Remove leading/trailing spaces and Windows carriage returns
            IP_OR_HOST=$(echo "$IP_OR_HOST" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//;s/\r//')
            
            # Skip empty lines or comments
            if [ -z "$IP_OR_HOST" ] || [[ "$IP_OR_HOST" =~ ^# ]]; then
                continue
            fi
            
            # Define a unique log file for this specific target
            # Sanitizes IP/Host for use in a filename (replaces invalid chars with '_')
            TARGET_LOG_FILE="scan_target_${IP_OR_HOST//[^a-zA-Z0-9._-]/_}_$(date +%F_%H%M).txt"
            log_info "Target ${IP_OR_HOST} assigned log file: ${TARGET_LOG_FILE}" "${MASTER_LOG_FILE}"

            # Concurrency Control: Read a token (blocks if pipe is empty)
            read -u 3
            {
                # Execute scan in the background, passing the unique log file
                log_info "--- Launching scan for target: ${IP_OR_HOST} ---" "${MASTER_LOG_FILE}"
                scan_target "$IP_OR_HOST" "${TARGET_LOG_FILE}"
                
                # Release the token back to the pipe when finished
                echo >&3
            } & # Run in the background
        done < "$TARGET_HOST"

        # Wait for all background jobs to finish
        wait
        
    else
        # Single Target Mode (Sequential)
        scan_target "$TARGET_HOST" "${MASTER_LOG_FILE}" # Use master log file
    fi

    # Cleanup the pipe
    exec 3>&-
    rm -f "$PARALLEL_PIPE"

    # --- Step 3: Reporting and Conclusion ---
    generate_summary
    log_info "Review full Nmap output in master log: ${MASTER_LOG_FILE} and individual target logs (if used: scan_target_*.txt)."
}

# --- Execute the main function ---
main "$@"
