mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-10 19:36:36 +08:00
添加强制断开链接
This commit is contained in:
@@ -1,41 +1,62 @@
|
|||||||
package port
|
package port
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ForceClosePortConnections 强制断开指定端口的所有连接
|
func ForceClosePortConnections(addr string) (err error) {
|
||||||
func ForceClosePortConnections(addr string) error {
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Printf("⚠️ ForceClosePortConnections panic recovered: %v\n", r)
|
||||||
|
err = nil // 永远返回 nil
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
|
fmt.Println("⚠️ 地址为空")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_, portStr, err := splitHostPort(addr)
|
_, portStr, err := splitHostPort(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parse address failed: %v", err)
|
fmt.Printf("⚠️ 地址解析失败: %v\n", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
port, err := strconv.Atoi(portStr)
|
port, err := strconv.Atoi(portStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid port: %v", err)
|
fmt.Printf("⚠️ 端口非法: %v\n", err)
|
||||||
}
|
|
||||||
|
|
||||||
if runtime.GOOS != "linux" {
|
|
||||||
fmt.Println("Warning: current OS is not Linux, skipping connection close.")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return closePortConnectionsBySS(port)
|
cmd := exec.Command("tcpkill", "-i", "any", "port", fmt.Sprintf("%d", port))
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
fmt.Printf("⚠️ 启动 tcpkill 失败: %v\n", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
fmt.Printf("⚠️ tcpkill goroutine panic recovered: %v\n", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
if cmd.Process != nil {
|
||||||
|
if err := cmd.Process.Kill(); err != nil {
|
||||||
|
fmt.Printf("⚠️ 终止 tcpkill 失败: %v\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
fmt.Printf("✅ 正在断开端口 %d 上的所有连接...\n", port)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitHostPort 是 net.SplitHostPort 的包装,容错增强
|
|
||||||
func splitHostPort(addr string) (string, string, error) {
|
func splitHostPort(addr string) (string, string, error) {
|
||||||
if !strings.Contains(addr, ":") {
|
if !strings.Contains(addr, ":") {
|
||||||
return "", "", fmt.Errorf("missing port in address")
|
return "", "", fmt.Errorf("missing port in address")
|
||||||
@@ -43,7 +64,6 @@ func splitHostPort(addr string) (string, string, error) {
|
|||||||
return netSplitHostPortCompat(addr)
|
return netSplitHostPortCompat(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// netSplitHostPortCompat 是增强版本的 SplitHostPort,兼容无 host 情况
|
|
||||||
func netSplitHostPortCompat(addr string) (string, string, error) {
|
func netSplitHostPortCompat(addr string) (string, string, error) {
|
||||||
lastColon := strings.LastIndex(addr, ":")
|
lastColon := strings.LastIndex(addr, ":")
|
||||||
if lastColon < 0 {
|
if lastColon < 0 {
|
||||||
@@ -51,67 +71,3 @@ func netSplitHostPortCompat(addr string) (string, string, error) {
|
|||||||
}
|
}
|
||||||
return addr[:lastColon], addr[lastColon+1:], nil
|
return addr[:lastColon], addr[lastColon+1:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// closePortConnectionsBySS 通过 ss 找到 pid/fd 然后关闭连接
|
|
||||||
func closePortConnectionsBySS(targetPort int) error {
|
|
||||||
cmd := exec.Command("ss", "-tnp")
|
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to execute ss: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
scanner := bufio.NewScanner(strings.NewReader(string(out)))
|
|
||||||
for scanner.Scan() {
|
|
||||||
line := scanner.Text()
|
|
||||||
|
|
||||||
if !strings.Contains(line, fmt.Sprintf(":%d", targetPort)) || !strings.Contains(line, "ESTAB") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 例如:users:(("gost",pid=1234,fd=17))
|
|
||||||
start := strings.Index(line, "pid=")
|
|
||||||
if start == -1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
rest := line[start:]
|
|
||||||
parts := strings.Split(rest, ",")
|
|
||||||
if len(parts) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pidStr := strings.TrimPrefix(parts[0], "pid=")
|
|
||||||
fdStr := strings.TrimPrefix(parts[1], "fd=")
|
|
||||||
pid := strings.Trim(pidStr, ")")
|
|
||||||
fd := strings.Trim(fdStr, ")")
|
|
||||||
|
|
||||||
fdPath := fmt.Sprintf("/proc/%s/fd/%s", pid, fd)
|
|
||||||
realPath, err := filepath.EvalSymlinks(fdPath)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Warning: unable to resolve %s: %v\n", fdPath, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 再次确认是 socket
|
|
||||||
if !strings.Contains(realPath, "socket:") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试关闭 fd
|
|
||||||
func() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
fmt.Printf("Warning: panic closing %s: %v\n", fdPath, r)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
f, err := os.OpenFile(fdPath, os.O_RDWR, 0)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Warning: open fd failed: %v\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
return scanner.Err()
|
|
||||||
}
|
|
||||||
|
|||||||
+73
-2
@@ -54,6 +54,74 @@ check_ipv6_support() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 检查并安装 tcpkill
|
||||||
|
check_and_install_tcpkill() {
|
||||||
|
# 检查 tcpkill 是否已安装
|
||||||
|
if command -v tcpkill &> /dev/null; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检测操作系统类型
|
||||||
|
OS_TYPE=$(uname -s)
|
||||||
|
|
||||||
|
# 检查是否需要 sudo
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
SUDO_CMD="sudo"
|
||||||
|
else
|
||||||
|
SUDO_CMD=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$OS_TYPE" == "Darwin" ]]; then
|
||||||
|
if command -v brew &> /dev/null; then
|
||||||
|
brew install dsniff &> /dev/null
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 检测 Linux 发行版并安装对应的包
|
||||||
|
if [ -f /etc/os-release ]; then
|
||||||
|
. /etc/os-release
|
||||||
|
DISTRO=$ID
|
||||||
|
elif [ -f /etc/redhat-release ]; then
|
||||||
|
DISTRO="rhel"
|
||||||
|
elif [ -f /etc/debian_version ]; then
|
||||||
|
DISTRO="debian"
|
||||||
|
else
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $DISTRO in
|
||||||
|
ubuntu|debian)
|
||||||
|
$SUDO_CMD apt update &> /dev/null
|
||||||
|
$SUDO_CMD apt install -y dsniff &> /dev/null
|
||||||
|
;;
|
||||||
|
centos|rhel|fedora)
|
||||||
|
if command -v dnf &> /dev/null; then
|
||||||
|
$SUDO_CMD dnf install -y dsniff &> /dev/null
|
||||||
|
elif command -v yum &> /dev/null; then
|
||||||
|
$SUDO_CMD yum install -y dsniff &> /dev/null
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
alpine)
|
||||||
|
$SUDO_CMD apk add --no-cache dsniff &> /dev/null
|
||||||
|
;;
|
||||||
|
arch|manjaro)
|
||||||
|
$SUDO_CMD pacman -S --noconfirm dsniff &> /dev/null
|
||||||
|
;;
|
||||||
|
opensuse*|sles)
|
||||||
|
$SUDO_CMD zypper install -y dsniff &> /dev/null
|
||||||
|
;;
|
||||||
|
gentoo)
|
||||||
|
$SUDO_CMD emerge --ask=n net-analyzer/dsniff &> /dev/null
|
||||||
|
;;
|
||||||
|
void)
|
||||||
|
$SUDO_CMD xbps-install -Sy dsniff &> /dev/null
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# 配置 Docker 启用 IPv6
|
# 配置 Docker 启用 IPv6
|
||||||
configure_docker_ipv6() {
|
configure_docker_ipv6() {
|
||||||
echo "🔧 配置 Docker IPv6 支持..."
|
echo "🔧 配置 Docker IPv6 支持..."
|
||||||
@@ -126,8 +194,6 @@ configure_docker_ipv6() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 显示菜单
|
# 显示菜单
|
||||||
show_menu() {
|
show_menu() {
|
||||||
echo "==============================================="
|
echo "==============================================="
|
||||||
@@ -191,6 +257,8 @@ install_panel() {
|
|||||||
configure_docker_ipv6
|
configure_docker_ipv6
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 检查并安装 tcpkill
|
||||||
|
check_and_install_tcpkill
|
||||||
|
|
||||||
cat > .env <<EOF
|
cat > .env <<EOF
|
||||||
DB_NAME=$DB_NAME
|
DB_NAME=$DB_NAME
|
||||||
@@ -235,6 +303,9 @@ update_panel() {
|
|||||||
configure_docker_ipv6
|
configure_docker_ipv6
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 检查并安装 tcpkill
|
||||||
|
check_and_install_tcpkill
|
||||||
|
|
||||||
echo "🛑 停止当前服务..."
|
echo "🛑 停止当前服务..."
|
||||||
$DOCKER_CMD down
|
$DOCKER_CMD down
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user