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

291 lines
11 KiB
Bash

#!/usr/bin/env bash
#########################################################################################
#### port-checker.sh — Check host:port pairs and report open/closed/timeout status ####
#### Accepts targets from CLI args, a file, or stdin ####
#### ####
#### Author: Phil Connor ####
#### Contact: contact@mylinux.work ####
#### License: MIT ####
#### Version 1.00 ####
#### ####
#### Usage: ####
#### ./port-checker.sh host1:port1 host2:port2 ####
#### ./port-checker.sh --file targets.txt ####
#### echo "host:port" | ./port-checker.sh ####
#### ####
#### See --help for all options. ####
#########################################################################################
set -euo pipefail
# ── Defaults ──────────────────────────────────────────────────────────
TIMEOUT="${PORT_CHECK_TIMEOUT:-3}"
VERBOSE="${VERBOSE:-false}"
COLOR="${COLOR:-auto}"
JSON_OUTPUT="${JSON_OUTPUT:-false}"
INPUT_FILE=""
# ── State ─────────────────────────────────────────────────────────────
SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_NAME
TARGETS=()
COUNT_OPEN=0
COUNT_CLOSED=0
COUNT_TIMEOUT=0
COUNT_TOTAL=0
# ── Colors ────────────────────────────────────────────────────────────
setup_colors() {
if [[ "$COLOR" == "never" ]]; then
RED="" GREEN="" YELLOW="" BOLD="" DIM="" RESET=""
return
fi
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BOLD='\033[1m'
DIM='\033[2m'
RESET='\033[0m'
else
RED="" GREEN="" YELLOW="" BOLD="" DIM="" RESET=""
fi
}
# ── Logging ───────────────────────────────────────────────────────────
log() { echo -e "${DIM}[INFO]${RESET} $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
# ── Helpers ───────────────────────────────────────────────────────────
check_port() {
local host="$1"
local port="$2"
local status="closed"
local latency="-"
verbose "Checking ${host}:${port} (timeout ${TIMEOUT}s)"
local start_ns end_ns elapsed_ms
start_ns=$(date +%s%N)
if command -v nc &>/dev/null; then
if nc -z -w "$TIMEOUT" "$host" "$port" &>/dev/null; then
status="open"
fi
elif command -v ncat &>/dev/null; then
if ncat -z -w "$TIMEOUT" "$host" "$port" &>/dev/null; then
status="open"
fi
else
if (echo >/dev/tcp/"$host"/"$port") 2>/dev/null; then
status="open"
fi
fi
end_ns=$(date +%s%N)
elapsed_ms=$(( (end_ns - start_ns) / 1000000 ))
if [[ "$status" == "closed" && "$elapsed_ms" -ge $(( TIMEOUT * 1000 )) ]]; then
status="timeout"
fi
if [[ "$status" != "closed" || "$elapsed_ms" -lt $(( TIMEOUT * 1000 )) ]]; then
latency="${elapsed_ms}ms"
fi
COUNT_TOTAL=$((COUNT_TOTAL + 1))
case "$status" in
open) COUNT_OPEN=$((COUNT_OPEN + 1)) ;;
closed) COUNT_CLOSED=$((COUNT_CLOSED + 1)) ;;
timeout) COUNT_TIMEOUT=$((COUNT_TIMEOUT + 1)) ;;
esac
if [[ "$JSON_OUTPUT" == "true" ]]; then
local json_comma=""
if [[ "$COUNT_TOTAL" -gt 1 ]]; then
json_comma=","
fi
printf '%s{"host":"%s","port":%s,"status":"%s","latency":"%s"}' \
"$json_comma" "$host" "$port" "$status" "$latency"
else
local color
case "$status" in
open) color="$GREEN" ;;
closed) color="$RED" ;;
timeout) color="$YELLOW" ;;
*) color="" ;;
esac
printf " %-30s %-8s %b%-10s%b %s\n" "$host" "$port" "$color" "$status" "$RESET" "$latency"
fi
}
load_targets_from_file() {
local file="$1"
if [[ ! -f "$file" ]]; then
err "File not found: $file"
exit 1
fi
while IFS= read -r line; do
line="${line%%#*}"
line="${line// /}"
[[ -z "$line" ]] && continue
TARGETS+=("$line")
done < "$file"
}
load_targets_from_stdin() {
while IFS= read -r line; do
line="${line%%#*}"
line="${line// /}"
[[ -z "$line" ]] && continue
TARGETS+=("$line")
done
}
# ══════════════════════════════════════════════════════════════════════
# USAGE
# ══════════════════════════════════════════════════════════════════════
usage() {
cat <<EOF
${SCRIPT_NAME} — Check host:port pairs and report open/closed/timeout status
USAGE:
${SCRIPT_NAME} [OPTIONS] host1:port1 [host2:port2 ...]
${SCRIPT_NAME} --file targets.txt
echo "host:port" | ${SCRIPT_NAME}
OPTIONS:
--file FILE Read targets from file (one host:port per line)
--timeout SECONDS Connection timeout (default: ${TIMEOUT})
--json Output results in JSON format
--verbose Enable debug output
--no-color Disable colored output
--help Show this help
ENVIRONMENT VARIABLES:
PORT_CHECK_TIMEOUT Connection timeout in seconds (default: 3)
COLOR Color mode: auto, always, never (default: auto)
EXAMPLES:
# Check specific hosts
./port-checker.sh google.com:443 github.com:22
# Read from file
./port-checker.sh --file targets.txt
# From stdin
echo -e "google.com:443\ngithub.com:22" | ./port-checker.sh
# JSON output with custom timeout
./port-checker.sh --json --timeout 5 myhost:8080
# Pipe-friendly
./port-checker.sh --no-color myhost:80 myhost:443
EOF
}
# ══════════════════════════════════════════════════════════════════════
# ARGUMENT PARSING
# ══════════════════════════════════════════════════════════════════════
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--file)
INPUT_FILE="$2"; shift 2 ;;
--timeout)
TIMEOUT="$2"; shift 2 ;;
--json)
JSON_OUTPUT="true"; shift ;;
--verbose)
VERBOSE="true"; shift ;;
--no-color)
COLOR="never"; shift ;;
--help|-h)
setup_colors
usage
exit 0 ;;
-*)
err "Unknown option: $1"
echo "Run ${SCRIPT_NAME} --help for usage" >&2
exit 1 ;;
*)
TARGETS+=("$1"); shift ;;
esac
done
}
# ══════════════════════════════════════════════════════════════════════
# MAIN
# ══════════════════════════════════════════════════════════════════════
main() {
parse_args "$@"
setup_colors
# Load targets from file if specified
if [[ -n "$INPUT_FILE" ]]; then
load_targets_from_file "$INPUT_FILE"
fi
# Load from stdin if no targets yet and stdin is not a terminal
if [[ ${#TARGETS[@]} -eq 0 ]] && ! [[ -t 0 ]]; then
load_targets_from_stdin
fi
# Validate we have targets
if [[ ${#TARGETS[@]} -eq 0 ]]; then
err "No targets specified"
echo "Run ${SCRIPT_NAME} --help for usage" >&2
exit 1
fi
if [[ "$JSON_OUTPUT" == "true" ]]; then
printf '{"results":['
else
echo ""
echo -e "${BOLD}Port Checker${RESET}"
echo -e "${DIM}Timeout: ${TIMEOUT}s${RESET}"
echo ""
printf " ${BOLD}%-30s %-8s %-10s %s${RESET}\n" "HOST" "PORT" "STATUS" "LATENCY"
printf " %s\n" "$(printf '%.0s─' {1..62})"
fi
for target in "${TARGETS[@]}"; do
local host port
if [[ "$target" == *:* ]]; then
host="${target%%:*}"
port="${target##*:}"
else
warn "Invalid format (expected host:port): $target"
continue
fi
if [[ -z "$host" || -z "$port" ]]; then
warn "Invalid target: $target"
continue
fi
check_port "$host" "$port"
done
if [[ "$JSON_OUTPUT" == "true" ]]; then
printf '],"summary":{"total":%d,"open":%d,"closed":%d,"timeout":%d}}\n' \
"$COUNT_TOTAL" "$COUNT_OPEN" "$COUNT_CLOSED" "$COUNT_TIMEOUT"
else
echo ""
echo -e " ${BOLD}Summary${RESET}"
printf " %-14s %d\n" "Total checked:" "$COUNT_TOTAL"
printf " %-14s %b%d%b\n" "Open:" "$GREEN" "$COUNT_OPEN" "$RESET"
printf " %-14s %b%d%b\n" "Closed:" "$RED" "$COUNT_CLOSED" "$RESET"
printf " %-14s %b%d%b\n" "Timeout:" "$YELLOW" "$COUNT_TIMEOUT" "$RESET"
echo ""
fi
}
main "$@"