Files
chiefgeek a1a17e81a1 Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist,
same-site referer bypass, Blackbox-Exporter allowed bot, and all
new exporters, cheat sheets, and automation scripts.
2026-05-25 03:31:08 +02:00

477 lines
20 KiB
Bash

#!/usr/bin/env bash
#########################################################################################
#### network-diag.sh — One-shot network diagnostics dump for Linux servers ####
#### Shows interfaces, routes, DNS, firewall rules, listening ports, connections ####
#### ####
#### Author: Phil Connor ####
#### Contact: contact@mylinux.work ####
#### License: MIT ####
#### Version 1.00 ####
#### ####
#### Usage: ####
#### ./network-diag.sh ####
#### ./network-diag.sh --section interfaces,dns ####
#### ####
#### See --help for all options. ####
#########################################################################################
set -euo pipefail
# ── Defaults ──────────────────────────────────────────────────────────
SECTIONS="${SECTIONS:-all}"
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"
# ── State ─────────────────────────────────────────────────────────────
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
# ── Colors ────────────────────────────────────────────────────────────
setup_colors() {
if [[ "$COLOR" == "never" ]]; then
RED="" GREEN="" YELLOW="" CYAN="" BOLD="" DIM="" RESET=""
return
fi
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'
else
RED="" GREEN="" YELLOW="" CYAN="" BOLD="" DIM="" RESET=""
fi
}
# ── Logging ───────────────────────────────────────────────────────────
log() { echo -e "${DIM}[INFO]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
# ── Helpers ───────────────────────────────────────────────────────────
section_header() {
echo ""
echo -e " ${BOLD}${CYAN}── $1 ──${RESET}"
echo ""
}
field() {
printf " ${BOLD}%-22s${RESET} %s\n" "$1" "$2"
}
field_color() {
printf " ${BOLD}%-22s${RESET} %b\n" "$1" "$2"
}
should_show() {
[[ "$SECTIONS" == "all" ]] || [[ ",$SECTIONS," == *",$1,"* ]]
}
# ══════════════════════════════════════════════════════════════════════
# INTERFACES
# ══════════════════════════════════════════════════════════════════════
show_interfaces() {
section_header "Network Interfaces"
printf " ${BOLD}%-16s %-18s %-20s %-8s %s${RESET}\n" "INTERFACE" "IP ADDRESS" "MAC" "STATE" "MTU"
printf " %s\n" "$(printf '%.0s─' {1..72})"
if command -v ip &>/dev/null; then
local ifaces
ifaces=$(ip -o link show 2>/dev/null | awk -F': ' '{print $2}' | sed 's/@.*//')
while IFS= read -r iface; do
[[ -z "$iface" ]] && continue
local ip_addr mac state mtu
ip_addr=$(ip -4 -o addr show "$iface" 2>/dev/null | awk '{print $4}' | head -1)
ip_addr="${ip_addr:-}"
mac=$(ip link show "$iface" 2>/dev/null | awk '/link\/ether/ {print $2}')
mac="${mac:-}"
state=$(ip link show "$iface" 2>/dev/null | grep -oP 'state \K\S+' || echo "UNKNOWN")
mtu=$(ip link show "$iface" 2>/dev/null | grep -oP 'mtu \K\d+' || echo "—")
local state_color="$DIM"
if [[ "$state" == "UP" ]]; then
state_color="$GREEN"
elif [[ "$state" == "DOWN" ]]; then
state_color="$RED"
fi
printf " %-16s %-18s %-20s %b%-8s%b %s\n" \
"$iface" "$ip_addr" "$mac" "$state_color" "$state" "$RESET" "$mtu"
done <<< "$ifaces"
else
warn "ip command not available"
ifconfig 2>/dev/null || echo " No interface information available"
fi
# IPv6 addresses
if command -v ip &>/dev/null; then
local ipv6_count
ipv6_count=$(ip -6 -o addr show scope global 2>/dev/null | wc -l)
if [[ "$ipv6_count" -gt 0 ]]; then
echo ""
echo -e " ${BOLD}IPv6 Global Addresses:${RESET}"
ip -6 -o addr show scope global 2>/dev/null | while IFS= read -r line; do
local v6_iface v6_addr
v6_iface=$(echo "$line" | awk '{print $2}')
v6_addr=$(echo "$line" | awk '{print $4}')
printf " %-16s %s\n" "$v6_iface" "$v6_addr"
done
fi
fi
}
# ══════════════════════════════════════════════════════════════════════
# ROUTES
# ══════════════════════════════════════════════════════════════════════
show_routes() {
section_header "Routing"
if command -v ip &>/dev/null; then
# Default route
local default_route
default_route=$(ip route show default 2>/dev/null | head -1)
if [[ -n "$default_route" ]]; then
field "Default route:" "$default_route"
else
field_color "Default route:" "${YELLOW}None${RESET}"
fi
echo ""
echo -e " ${BOLD}Routing Table:${RESET}"
printf " %-24s %-18s %-12s %s\n" "DESTINATION" "GATEWAY" "DEVICE" "PROTO"
printf " %s\n" "$(printf '%.0s─' {1..65})"
ip route show 2>/dev/null | while IFS= read -r line; do
local dest gw dev proto
dest=$(echo "$line" | awk '{print $1}')
gw=$(echo "$line" | grep -oP 'via \K\S+' || echo "—")
dev=$(echo "$line" | grep -oP 'dev \K\S+' || echo "—")
proto=$(echo "$line" | grep -oP 'proto \K\S+' || echo "—")
printf " %-24s %-18s %-12s %s\n" "$dest" "$gw" "$dev" "$proto"
done
else
route -n 2>/dev/null || echo " No routing information available"
fi
}
# ══════════════════════════════════════════════════════════════════════
# DNS
# ══════════════════════════════════════════════════════════════════════
show_dns() {
section_header "DNS Configuration"
# /etc/resolv.conf
if [[ -f /etc/resolv.conf ]]; then
echo -e " ${BOLD}/etc/resolv.conf:${RESET}"
local nameservers search_domains
nameservers=$(grep "^nameserver" /etc/resolv.conf 2>/dev/null | awk '{print $2}')
search_domains=$(grep "^search" /etc/resolv.conf 2>/dev/null | sed 's/^search //')
if [[ -n "$nameservers" ]]; then
while IFS= read -r ns; do
printf " Nameserver: %s\n" "$ns"
done <<< "$nameservers"
fi
if [[ -n "${search_domains:-}" ]]; then
printf " Search: %s\n" "$search_domains"
fi
# Check if resolv.conf is a symlink (systemd-resolved)
if [[ -L /etc/resolv.conf ]]; then
local link_target
link_target=$(readlink -f /etc/resolv.conf)
printf " ${DIM}(symlink → %s)${RESET}\n" "$link_target"
fi
fi
# systemd-resolved
if command -v resolvectl &>/dev/null; then
echo ""
echo -e " ${BOLD}systemd-resolved:${RESET}"
resolvectl status 2>/dev/null | grep -E "DNS Server|DNS Domain|DNSSEC" | while IFS= read -r line; do
printf " %s\n" "$line"
done
elif command -v systemd-resolve &>/dev/null; then
echo ""
echo -e " ${BOLD}systemd-resolved:${RESET}"
systemd-resolve --status 2>/dev/null | grep -E "DNS Server|DNS Domain|DNSSEC" | while IFS= read -r line; do
printf " %s\n" "$line"
done
fi
}
# ══════════════════════════════════════════════════════════════════════
# FIREWALL
# ══════════════════════════════════════════════════════════════════════
show_firewall() {
section_header "Firewall"
local fw_found=false
# iptables
if command -v iptables &>/dev/null; then
fw_found=true
echo -e " ${BOLD}iptables:${RESET}"
local ipt_rules
ipt_rules=$(iptables -S 2>/dev/null | wc -l || echo "0")
printf " Rules: %d\n" "$ipt_rules"
if [[ "$VERBOSE" == "true" ]]; then
iptables -L -n --line-numbers 2>/dev/null | while IFS= read -r line; do
printf " %s\n" "$line"
done
else
# Summary by chain
iptables -S 2>/dev/null | awk '/^-A/ {print $2}' | sort | uniq -c | sort -rn | while IFS= read -r line; do
printf " %s\n" "$line"
done
fi
fi
# nftables
if command -v nft &>/dev/null; then
fw_found=true
echo ""
echo -e " ${BOLD}nftables:${RESET}"
local nft_tables
nft_tables=$(nft list tables 2>/dev/null | wc -l || echo "0")
printf " Tables: %d\n" "$nft_tables"
if [[ "$VERBOSE" == "true" ]]; then
nft list ruleset 2>/dev/null | while IFS= read -r line; do
printf " %s\n" "$line"
done
else
nft list tables 2>/dev/null | while IFS= read -r line; do
printf " %s\n" "$line"
done
fi
fi
# ufw
if command -v ufw &>/dev/null; then
fw_found=true
echo ""
echo -e " ${BOLD}UFW:${RESET}"
local ufw_status
ufw_status=$(ufw status 2>/dev/null | head -1 || echo "Unknown")
printf " %s\n" "$ufw_status"
fi
# firewalld
if command -v firewall-cmd &>/dev/null; then
fw_found=true
echo ""
echo -e " ${BOLD}firewalld:${RESET}"
local fwd_state
fwd_state=$(firewall-cmd --state 2>/dev/null || echo "not running")
printf " State: %s\n" "$fwd_state"
if [[ "$fwd_state" == "running" ]]; then
local active_zones
active_zones=$(firewall-cmd --get-active-zones 2>/dev/null | head -5)
if [[ -n "$active_zones" ]]; then
printf " Active zones:\n"
echo "$active_zones" | while IFS= read -r line; do
printf " %s\n" "$line"
done
fi
fi
fi
if [[ "$fw_found" == "false" ]]; then
log "No firewall tools detected (iptables, nftables, ufw, firewalld)"
fi
}
# ══════════════════════════════════════════════════════════════════════
# LISTENING PORTS
# ══════════════════════════════════════════════════════════════════════
show_ports() {
section_header "Listening Ports"
if command -v ss &>/dev/null; then
printf " ${BOLD}%-8s %-30s %-8s %s${RESET}\n" "PROTO" "LISTEN ADDRESS" "PORT" "PROCESS"
printf " %s\n" "$(printf '%.0s─' {1..70})"
ss -tlnp 2>/dev/null | tail -n +2 | while IFS= read -r line; do
local addr port_str proto proc_info
proto="tcp"
addr=$(echo "$line" | awk '{print $4}')
port_str="${addr##*:}"
proc_info=$(echo "$line" | grep -oP 'users:\(\("\K[^"]+' || echo "—")
printf " %-8s %-30s %-8s %s\n" "$proto" "$addr" "$port_str" "$proc_info"
done
# UDP listeners
local udp_count
udp_count=$(ss -ulnp 2>/dev/null | tail -n +2 | wc -l)
if [[ "$udp_count" -gt 0 ]]; then
echo ""
ss -ulnp 2>/dev/null | tail -n +2 | while IFS= read -r line; do
local addr port_str proc_info
addr=$(echo "$line" | awk '{print $4}')
port_str="${addr##*:}"
proc_info=$(echo "$line" | grep -oP 'users:\(\("\K[^"]+' || echo "—")
printf " %-8s %-30s %-8s %s\n" "udp" "$addr" "$port_str" "$proc_info"
done
fi
local total_tcp total_udp
total_tcp=$(ss -tlnp 2>/dev/null | tail -n +2 | wc -l)
total_udp=$(ss -ulnp 2>/dev/null | tail -n +2 | wc -l)
echo ""
field "TCP listeners:" "$total_tcp"
field "UDP listeners:" "$total_udp"
elif command -v netstat &>/dev/null; then
netstat -tlnp 2>/dev/null | while IFS= read -r line; do
printf " %s\n" "$line"
done
else
warn "Neither ss nor netstat available"
fi
}
# ══════════════════════════════════════════════════════════════════════
# CONNECTIONS
# ══════════════════════════════════════════════════════════════════════
show_connections() {
section_header "Active Connections"
if command -v ss &>/dev/null; then
echo -e " ${BOLD}Connections by state:${RESET}"
printf " %-20s %s\n" "STATE" "COUNT"
printf " %s\n" "$(printf '%.0s─' {1..30})"
ss -tan 2>/dev/null | tail -n +2 | awk '{print $1}' | sort | uniq -c | sort -rn | while IFS= read -r line; do
local count state
count=$(echo "$line" | awk '{print $1}')
state=$(echo "$line" | awk '{print $2}')
local color=""
case "$state" in
ESTAB) color="$GREEN" ;;
TIME-WAIT) color="$YELLOW" ;;
CLOSE-WAIT) color="$RED" ;;
*) color="" ;;
esac
printf " %b%-20s%b %s\n" "$color" "$state" "$RESET" "$count"
done
local total_conn
total_conn=$(ss -tan 2>/dev/null | tail -n +2 | wc -l)
echo ""
field "Total connections:" "$total_conn"
elif command -v netstat &>/dev/null; then
netstat -tan 2>/dev/null | awk '/^tcp/ {print $6}' | sort | uniq -c | sort -rn | while IFS= read -r line; do
printf " %s\n" "$line"
done
else
warn "Neither ss nor netstat available"
fi
}
# ══════════════════════════════════════════════════════════════════════
# USAGE
# ══════════════════════════════════════════════════════════════════════
usage() {
cat <<EOF
${SCRIPT_NAME} — One-shot network diagnostics dump for Linux servers
USAGE:
${SCRIPT_NAME} [OPTIONS]
OPTIONS:
--section SECTIONS Comma-separated sections to show (default: all)
Available: interfaces, routes, dns, firewall, ports,
connections
--verbose Enable debug output (show full firewall rules)
--no-color Disable colored output
--help Show this help
ENVIRONMENT VARIABLES:
SECTIONS Sections to display (default: all)
COLOR Color mode: auto, always, never (default: auto)
EXAMPLES:
# Full network dump
./network-diag.sh
# Interfaces and DNS only
./network-diag.sh --section interfaces,dns
# Verbose firewall rules
./network-diag.sh --section firewall --verbose
# Pipe-friendly
./network-diag.sh --no-color | tee /tmp/netdiag-\$(hostname).txt
EOF
}
# ══════════════════════════════════════════════════════════════════════
# ARGUMENT PARSING
# ══════════════════════════════════════════════════════════════════════
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--section)
SECTIONS="$2"; shift 2 ;;
--verbose)
VERBOSE="true"; shift ;;
--no-color)
COLOR="never"; shift ;;
--help|-h)
setup_colors
usage
exit 0 ;;
*)
echo "Unknown option: $1" >&2
echo "Run ${SCRIPT_NAME} --help for usage" >&2
exit 1 ;;
esac
done
}
# ══════════════════════════════════════════════════════════════════════
# MAIN
# ══════════════════════════════════════════════════════════════════════
main() {
parse_args "$@"
setup_colors
echo ""
echo -e "${BOLD}Network Diagnostics — $(hostname -f 2>/dev/null || hostname)${RESET}"
echo -e "${DIM}$(date '+%Y-%m-%d %H:%M:%S %Z')${RESET}"
should_show "interfaces" && show_interfaces
should_show "routes" && show_routes
should_show "dns" && show_dns
should_show "firewall" && show_firewall
should_show "ports" && show_ports
should_show "connections" && show_connections
echo ""
}
main "$@"