From 0fdc1facfa6e5d58520e4540e56470e35288649b Mon Sep 17 00:00:00 2001 From: DAProgs Date: Thu, 5 Nov 2026 18:08:22 -0500 Subject: [PATCH] 2611.1 --- network-config.sh | 142 ++++++++++++++++++++++++++++++++++++++++++---- test_webhook.sh | 17 ++++++ 2 files changed, 148 insertions(+), 11 deletions(-) create mode 100755 test_webhook.sh diff --git a/network-config.sh b/network-config.sh index e60a12c..e2fbf2b 100755 --- a/network-config.sh +++ b/network-config.sh @@ -5,6 +5,9 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOG_FILE="/var/log/portspoof.log" EVENTS_WINDOW_FILE="$SCRIPT_DIR/.events_window" EVENTS_HOURS=1 +WEBHOOK_FILE="$SCRIPT_DIR/.discord_webhook" +WEBHOOK_OFFSET_FILE="$SCRIPT_DIR/.webhook_offset" +WEBHOOK_PID_FILE="$SCRIPT_DIR/.webhook.pid" if [ -f "$EVENTS_WINDOW_FILE" ]; then read -r _loaded < "$EVENTS_WINDOW_FILE" 2>/dev/null case "$_loaded" in @@ -102,7 +105,7 @@ status_box() { echo " ╠══════════════════════════════════════════════════════════════════════════╣" echo " ║ Network Interface Status ║" echo " ╠══════════════════════════════════════════════════════════════════════════╣" - echo " ║ v0.18 ║" + echo " ║ v0.19 ║" local ifaces mapfile -t ifaces < <(get_interfaces) @@ -415,6 +418,118 @@ shell_access() { read -rp "Press Enter to continue..." } +# ── discord webhook ─────────────────────────────────────────────────────────── + +send_discord() { + local webhook + webhook=$(cat "$WEBHOOK_FILE" 2>/dev/null) + [ -n "$webhook" ] || return 1 + curl -s -o /dev/null --max-time 10 \ + -H "Content-Type: application/json" \ + -d "$(printf '{"content":"%s"}' "$1")" "$webhook" +} + +# Builds the Discord message from one raw log line; exits non-zero if unparseable. +webhook_msg() { + python3 -c ' +import sys, json +from datetime import datetime +try: + e = json.loads(sys.argv[1]) +except ValueError: + sys.exit(1) +raw = str(e.get("timestamp", "")) +if raw.endswith("Z"): + raw = raw[:-1] + "+00:00" +try: + ts = datetime.fromisoformat(raw).astimezone().strftime("%Y-%m-%d %H:%M:%S") +except ValueError: + ts = "?" +src = str(e.get("src_ip", "?")).replace("\"", "").replace("\\", "") +dst = str(e.get("dst_port", "?")) +print(f"⚠️ **PortSpoof alert** — {src} → port {dst} at {ts}") +' "$1" +} + +# Forwards new log lines to the webhook. Runs in the background; survives the menu. +start_webhook_watcher() { + [ -f "$WEBHOOK_FILE" ] || return 0 + if [ -f "$WEBHOOK_PID_FILE" ] && kill -0 "$(cat "$WEBHOOK_PID_FILE")" 2>/dev/null; then + return 0 + fi + # Seed offset so old events are not replayed. + echo "$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0)" > "$WEBHOOK_OFFSET_FILE" + ( + trap 'rm -f "$WEBHOOK_PID_FILE"' EXIT + while true; do + sleep 2 + [ -f "$LOG_FILE" ] || continue + total=$(wc -l < "$LOG_FILE") + offset=$(cat "$WEBHOOK_OFFSET_FILE" 2>/dev/null) + [ -n "$offset" ] || offset=0 + if [ "$total" -le "$offset" ]; then + [ "$total" -lt "$offset" ] && echo "$total" > "$WEBHOOK_OFFSET_FILE" + continue + fi + tail -n +"$((offset + 1))" "$LOG_FILE" | while IFS= read -r line; do + msg=$(webhook_msg "$line") || continue + send_discord "$msg" + done + echo "$total" > "$WEBHOOK_OFFSET_FILE" + done + ) & + echo $! > "$WEBHOOK_PID_FILE" +} + +stop_webhook_watcher() { + if [ -f "$WEBHOOK_PID_FILE" ]; then + kill "$(cat "$WEBHOOK_PID_FILE")" 2>/dev/null + rm -f "$WEBHOOK_PID_FILE" + fi +} + +set_webhook() { + clear + echo "" + echo "╔══════════════════════════════════════════════════════════════════════════╗" + echo "║ Discord Webhook ║" + echo "╚══════════════════════════════════════════════════════════════════════════╝" + echo "" + local current + current=$(cat "$WEBHOOK_FILE" 2>/dev/null) + echo " Current: ${current:-none}" + echo "" + + while true; do + read -rp " Webhook URL (leave empty to disable): " url + if [ -z "$url" ]; then + stop_webhook_watcher + rm -f "$WEBHOOK_FILE" "$WEBHOOK_OFFSET_FILE" + echo "" + echo " Webhook disabled." + read -rp "Press Enter to continue..." + return + fi + case "$url" in + https://discord.com/api/webhooks/*) ;; + *) echo " Invalid: must start with https://discord.com/api/webhooks/"; continue ;; + esac + if curl -s -o /dev/null --max-time 10 -X POST \ + -H "Content-Type: application/json" \ + -d '{"content":"PortSpoof webhook test — configured from menu"}' "$url"; then + echo "$url" > "$WEBHOOK_FILE" + start_webhook_watcher + echo "" + echo " Webhook saved — test message sent, watcher started." + break + else + echo " Test failed — check the URL and try again." + fi + done + echo "" + read -rp "Press Enter to continue..." +} + # ── log helpers ─────────────────────────────────────────────────────────────── # Prints the last 5 events within the last $EVENTS_HOURS hours # (always exactly 5 lines): timestamp (local time), src_ip, dst_port. @@ -584,7 +699,7 @@ main_screen() { # ── main menu ───────────────────────────────────────────────────────────────── -MENU_ITEMS=("Refresh" "Timeframe: ${EVENTS_HOURS}h" "Set Static IP" "Set DHCP" "Shell" "Reboot" "Update") +MENU_ITEMS=("Refresh" "Timeframe: ${EVENTS_HOURS}h" "Discord Webhook" "Set Static IP" "Set DHCP" "Shell" "Reboot" "Update") toggle_timeframe() { if [ "$EVENTS_HOURS" = "1" ]; then @@ -609,26 +724,29 @@ main_menu() { toggle_timeframe ;; 2) + set_webhook + ;; + 3) if select_interface; then set_static "$SELECTED_IFACE" fi echo "" read -rp "Press Enter to continue..." ;; - 3) + 4) if select_interface; then set_dhcp "$SELECTED_IFACE" fi echo "" read -rp "Press Enter to continue..." ;; - 4) + 5) shell_access ;; - 5) + 6) reboot_confirm ;; - 6) + 7) run_update ;; esac @@ -637,9 +755,11 @@ main_menu() { # ── entry point ─────────────────────────────────────────────────────────────── -if [ "$EUID" -ne 0 ]; then - echo "This script must be run as root (use sudo)." - exit 1 +if [ "${BASH_SOURCE[0]}" = "$0" ]; then + if [ "$EUID" -ne 0 ]; then + echo "This script must be run as root (use sudo)." + exit 1 + fi + start_webhook_watcher + main_menu fi - -main_menu diff --git a/test_webhook.sh b/test_webhook.sh new file mode 100755 index 0000000..3f7738a --- /dev/null +++ b/test_webhook.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# Self-check for the Discord webhook helpers: bash test_webhook.sh +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=network-config.sh +source "$SCRIPT_DIR/network-config.sh" + +line='{"timestamp":"2026-11-05T12:00:00Z","src_ip":"1.2.3.4","dst_port":8080}' +msg=$(webhook_msg "$line") || { echo "FAIL: valid line rejected"; exit 1; } +echo "$msg" | grep -q "1.2.3.4" || { echo "FAIL: src_ip missing from: $msg"; exit 1; } +echo "$msg" | grep -q "8080" || { echo "FAIL: dst_port missing from: $msg"; exit 1; } + +if webhook_msg 'not json' >/dev/null; then + echo "FAIL: invalid line accepted" + exit 1 +fi + +echo "OK: $msg"