Add clashctl and auto port selection

This commit is contained in:
wnlen
2026-01-14 13:31:05 +08:00
parent 0607ff6adc
commit 90f63e54e8
8 changed files with 297 additions and 18 deletions

102
scripts/port_utils.sh Normal file
View File

@ -0,0 +1,102 @@
#!/bin/bash
PORT_CHECK_WARNED=${PORT_CHECK_WARNED:-0}
is_port_in_use() {
local port="$1"
if command -v ss >/dev/null 2>&1; then
ss -lnt | awk '{print $4}' | grep -E "(:|\.)${port}$" >/dev/null 2>&1
return $?
fi
if command -v netstat >/dev/null 2>&1; then
netstat -lnt | awk '{print $4}' | grep -E "(:|\.)${port}$" >/dev/null 2>&1
return $?
fi
if command -v lsof >/dev/null 2>&1; then
lsof -iTCP -sTCP:LISTEN -P -n | awk '{print $9}' | grep -E "(:|\.)${port}$" >/dev/null 2>&1
return $?
fi
if [ "$PORT_CHECK_WARNED" -eq 0 ]; then
echo -e "\033[33m[WARN] 未找到端口检测工具,端口冲突检测可能不准确\033[0m" >&2
PORT_CHECK_WARNED=1
fi
return 1
}
find_available_port() {
local start_port=${1:-20000}
local end_port=${2:-65000}
local port
if command -v shuf >/dev/null 2>&1; then
for _ in {1..50}; do
port=$(shuf -i "${start_port}-${end_port}" -n 1)
if ! is_port_in_use "$port"; then
echo "$port"
return 0
fi
done
fi
for port in $(seq "$start_port" "$end_port"); do
if ! is_port_in_use "$port"; then
echo "$port"
return 0
fi
done
return 1
}
resolve_port_value() {
local name="$1"
local value="$2"
local resolved
if [ -z "$value" ] || [ "$value" = "auto" ]; then
resolved=$(find_available_port)
if [ -z "$resolved" ]; then
return 1
fi
echo -e "\033[33m[WARN] ${name} 端口已自动分配为 ${resolved}\033[0m" >&2
echo "$resolved"
return 0
fi
if [[ "$value" =~ ^[0-9]+$ ]]; then
if is_port_in_use "$value"; then
resolved=$(find_available_port)
if [ -n "$resolved" ]; then
echo -e "\033[33m[WARN] ${name} 端口 ${value} 已被占用,已自动切换为 ${resolved}\033[0m" >&2
echo "$resolved"
return 0
fi
fi
fi
echo "$value"
}
resolve_host_port() {
local name="$1"
local raw="$2"
local default_host="$3"
local host
local port
if [ "$raw" = "auto" ] || [ -z "$raw" ]; then
host="$default_host"
port="auto"
else
if [[ "$raw" == *:* ]]; then
host="${raw%:*}"
port="${raw##*:}"
else
host="$default_host"
port="$raw"
fi
fi
port=$(resolve_port_value "$name" "$port") || return 1
echo "${host}:${port}"
}