#!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH # ==================================================== # 系统要求: CentOS 7+、Debian 8+、Ubuntu 16+ # 描述: Socat 一键安装管理脚本 # 版本: 5.2 # ==================================================== Green="\033[32m" Font="\033[0m" Blue="\033[34m" Red="\033[31m" Yellow="\033[33m" # 创建 socats 目录并定义相关路径 SOCATS_DIR="$HOME/socats" mkdir -p "$SOCATS_DIR" # 配置文件路径 CONFIG_FILE="$SOCATS_DIR/socat_forwards.conf" # 清屏函数 clear_screen() { clear } # 按键继续函数 press_any_key() { echo read -n 1 -s -r -p "按任意键继续..." clear_screen } # 检查是否为root用户 check_root(){ if [[ $EUID -ne 0 ]]; then echo "错误:此脚本必须以root身份运行!" 1>&2 exit 1 fi } # 检查系统类型 check_sys(){ if [[ -f /etc/redhat-release ]]; then OS="CentOS" elif cat /etc/issue | grep -q -E -i "debian"; then OS="Debian" elif cat /etc/issue | grep -q -E -i "ubuntu"; then OS="Ubuntu" elif cat /etc/issue | grep -q -E -i "centos|red hat|redhat"; then OS="CentOS" else echo "不支持的操作系统!" exit 1 fi } # 获取本机IP(优化版本) get_ip(){ local ip=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1 | head -n1) echo ${ip:-"未知IPv4"} } # 获取IPv6地址 get_ipv6(){ local ipv6=$(ip -6 addr show | grep -oP '(?<=inet6\s)[\da-f:]+' | grep -v '^::1' | grep -v '^fe80' | head -n1) echo ${ipv6:-"未知IPv6"} } # 安装Socat(只在需要时执行) install_socat(){ if [ ! -s /usr/bin/socat ]; then echo -e "${Green}正在安装 Socat...${Font}" if [ "${OS}" == "CentOS" ]; then yum install -y socat else apt-get -y update apt-get install -y socat fi if [ -s /usr/bin/socat ]; then echo -e "${Green}Socat 安装完成!${Font}" else echo -e "${Red}Socat 安装失败,请检查网络连接和系统设置。${Font}" exit 1 fi fi } # 初始化配置文件 init_config() { if [ ! -f "$CONFIG_FILE" ]; then touch "$CONFIG_FILE" echo "Debug: Created new config file: $CONFIG_FILE" else echo "Debug: Config file already exists: $CONFIG_FILE" fi } # 添加到配置文件 add_to_config() { if [ "$ip_version" == "1" ]; then echo "ipv4 $port1 $socatip $port2" >> "$CONFIG_FILE" elif [ "$ip_version" == "2" ]; then echo "ipv6 $port1 $socatip $port2" >> "$CONFIG_FILE" elif [ "$ip_version" == "3" ]; then echo "domain $port1 $socatip $port2" >> "$CONFIG_FILE" elif [ "$ip_version" == "4" ]; then echo "domain6 $port1 $socatip $port2" >> "$CONFIG_FILE" fi } # 从配置文件中移除转发 remove_from_config() { local listen_port=$1 sed -i "/ $listen_port /d" "$CONFIG_FILE" } # 检测端口是否占用 check_port() { if netstat -tuln | grep -q ":$1 "; then echo -e "${Red}错误: 端口 $1 已被占用${Font}" return 1 fi return 0 } # 规范化 IPv6 地址 normalize_ipv6() { local ip=$1 ip=$(echo $ip | tr '[:upper:]' '[:lower:]') ip=$(echo $ip | sed 's/\b0*\([0-9a-f]\)/\1/g') local longest_zero="" local current_zero="" local IFS=":" for group in $ip; do if [ "$group" = "0" ]; then current_zero="$current_zero:" else if [ ${#current_zero} -gt ${#longest_zero} ]; then longest_zero=$current_zero fi current_zero="" fi done if [ ${#current_zero} -gt ${#longest_zero} ]; then longest_zero=$current_zero fi if [ -n "$longest_zero" ]; then ip=$(echo $ip | sed "s/$longest_zero/::/") ip=$(echo $ip | sed 's/:::/::/') fi ip=$(echo $ip | sed 's/^://' | sed 's/:$//') echo $ip } # 检查是否支持IPv6 check_ipv6_support() { if [ ! -f /proc/sys/net/ipv6/conf/all/disable_ipv6 ]; then echo -e "${Red}错误: 您的系统似乎不支持 IPv6${Font}" return 1 fi if [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6)" -eq 1 ]; then echo -e "${Yellow}警告: IPv6 当前被禁用${Font}" read -p "是否要启用 IPv6? (y/n): " enable_ipv6 if [[ $enable_ipv6 =~ ^[Yy]$ ]]; then sysctl -w net.ipv6.conf.all.disable_ipv6=0 echo -e "${Green}IPv6 已启用${Font}" else echo -e "${Red}IPv6 保持禁用状态,无法进行 IPv6 转发${Font}" return 1 fi fi local ipv6_addr=$(ip -6 addr show | grep -oP '(?<=inet6 )([0-9a-fA-F:]+)' | grep -v '^::1' | grep -v '^fe80' | head -n 1) if [ -z "$ipv6_addr" ]; then echo -e "${Red}错误: 未检测到可用的 IPv6 地址${Font}" echo -e "${Yellow}请确保您的网络接口已配置 IPv6 地址${Font}" return 1 else echo -e "${Green}检测到 IPv6 地址: $ipv6_addr${Font}" fi if [ "$(cat /proc/sys/net/ipv6/conf/all/forwarding)" -eq 0 ]; then echo -e "${Yellow}警告: IPv6 转发当前被禁用${Font}" read -p "是否要启用 IPv6 转发? (y/n): " enable_forwarding if [[ $enable_forwarding =~ ^[Yy]$ ]]; then sysctl -w net.ipv6.conf.all.forwarding=1 echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf echo -e "${Green}IPv6 转发已启用${Font}" else echo -e "${Red}IPv6 转发保持禁用状态,可能影响转发功能${Font}" return 1 fi fi return 0 } # 配置Socat config_socat(){ echo -e "${Green}请选择转发类型:${Font}" echo "1. IPv4 端口转发" echo "2. IPv6 端口转发" echo "3. IPv4 域名(DDNS)端口转发" echo "4. IPv6 域名(DDNS)端口转发" read -p "请输入选项 [1-4]: " ip_version if [ "$ip_version" == "2" ] || [ "$ip_version" == "4" ]; then if ! check_ipv6_support; then echo -e "${Red}无法进行 IPv6 转发,请检查系统配置${Font}" return 1 fi fi echo -e "${Green}请输入Socat配置信息!${Font}" while true; do read -p "请输入本地端口: " port1 if check_port $port1; then break fi done read -p "请输入远程端口: " port2 if [ "$ip_version" == "3" ] || [ "$ip_version" == "4" ]; then read -p "请输入远程域名: " socatip if ! is_valid_domain "$socatip"; then echo -e "${Red}错误: 无效的域名格式${Font}" return 1 fi else read -p "请输入远程IP: " socatip if [ "$ip_version" == "1" ]; then if ! [[ $socatip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo -e "${Red}错误: 无效的IPv4地址格式${Font}" return 1 fi elif [ "$ip_version" == "2" ]; then if ! [[ $socatip =~ ^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$ ]]; then echo -e "${Red}错误: 无效的IPv6地址格式${Font}" return 1 fi socatip=$(normalize_ipv6 "$socatip") fi fi } # 验证域名格式 is_valid_domain() { local domain=$1 if [[ $domain =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$ ]]; then # 尝试解析域名 if host "$domain" >/dev/null 2>&1 || nslookup "$domain" >/dev/null 2>&1 || dig "$domain" >/dev/null 2>&1; then return 0 fi fi return 1 } # 创建 systemd 服务文件 create_systemd_service() { local name=$1 local command=$2 cat > /etc/systemd/system/${name}.service < $remote_ip:$remote_port (TCP/UDP)" elif [ "$ip_type" == "ipv6" ]; then echo "$i. IPv6: [$ipv6]:$listen_port --> [$remote_ip]:$remote_port (TCP/UDP)" elif [ "$ip_type" == "domain" ]; then echo "$i. 域名: $ip:$listen_port --> $remote_ip:$remote_port (TCP/UDP) [DDNS, IPv4]" elif [ "$ip_type" == "domain6" ]; then echo "$i. 域名: [$ipv6]:$listen_port --> $remote_ip:$remote_port (TCP/UDP) [DDNS, IPv6]" fi ((i++)) done < "$CONFIG_FILE" read -p "请输入要删除的转发编号(多个编号用空格分隔,直接回车取消): " numbers if [ -n "$numbers" ]; then local nums_to_delete=($(echo "$numbers" | tr ' ' '\n' | sort -rn)) for num in "${nums_to_delete[@]}"; do if [ $num -ge 1 ] && [ $num -lt $i ]; then local index=$((num-1)) IFS=' ' read -r ip_type listen_port remote_ip remote_port <<< "${entries[$index]}" remove_forward "$listen_port" "$ip_type" sed -i "${num}d" "$CONFIG_FILE" if [ "$ip_type" == "ipv4" ]; then echo -e "${Green}已删除IPv4转发: $ip:$listen_port (TCP/UDP)${Font}" elif [ "$ip_type" == "ipv6" ]; then echo -e "${Green}已删除IPv6转发: [$ipv6]:$listen_port (TCP/UDP)${Font}" elif [ "$ip_type" == "domain" ]; then echo -e "${Green}已删除域名转发: $ip:$listen_port --> $remote_ip (TCP/UDP) [IPv4]${Font}" elif [ "$ip_type" == "domain6" ]; then echo -e "${Green}已删除域名转发: [$ipv6]:$listen_port --> $remote_ip (TCP/UDP) [IPv6]${Font}" fi remove_firewall_rules "$listen_port" "$ip_type" else echo -e "${Red}无效的编号: $num${Font}" fi done fi } # 移除单个转发 remove_forward() { local listen_port=$1 local ip_type=$2 local service_name="socat-${listen_port}-*" # 停止并移除socat服务 systemctl stop ${service_name} systemctl disable ${service_name} rm -f /etc/systemd/system/${service_name}.service systemctl daemon-reload # 如果是域名类型,移除域名监控服务 if [ "$ip_type" == "domain" ] || [ "$ip_type" == "domain6" ]; then remove_domain_monitor "$listen_port" fi echo -e "${Green}已移除端口 ${listen_port} 的转发${Font}" } # 防火墙检测和配置 configure_firewall() { local port=$1 local ip_version=$2 # 处理不同类型的IP版本 if [ "$ip_version" == "domain" ]; then ip_version="ipv4" elif [ "$ip_version" == "domain6" ]; then ip_version="ipv6" fi local firewall_tool="" if command -v firewall-cmd >/dev/null 2>&1; then firewall_tool="firewalld" elif command -v ufw >/dev/null 2>&1; then firewall_tool="ufw" elif command -v iptables >/dev/null 2>&1; then firewall_tool="iptables" fi if [ -z "$firewall_tool" ]; then echo -e "${Yellow}未检测到防火墙工具,端口 ${port} 配置完成。${Font}" return fi local has_permission=false case $firewall_tool in "firewalld") if firewall-cmd --state >/dev/null 2>&1; then has_permission=true fi ;; "ufw") if ufw status >/dev/null 2>&1; then has_permission=true fi ;; "iptables") if iptables -L >/dev/null 2>&1; then has_permission=true fi ;; esac if [ "$has_permission" = true ]; then case $firewall_tool in "firewalld") if [ "$ip_version" == "ipv4" ]; then firewall-cmd --zone=public --add-port=${port}/tcp --permanent >/dev/null 2>&1 firewall-cmd --zone=public --add-port=${port}/udp --permanent >/dev/null 2>&1 else firewall-cmd --zone=public --add-port=${port}/tcp --permanent --ipv6 >/dev/null 2>&1 firewall-cmd --zone=public --add-port=${port}/udp --permanent --ipv6 >/dev/null 2>&1 fi firewall-cmd --reload >/dev/null 2>&1 ;; "ufw") ufw allow ${port}/tcp >/dev/null 2>&1 ufw allow ${port}/udp >/dev/null 2>&1 ;; "iptables") if [ "$ip_version" == "ipv4" ]; then iptables -I INPUT -p tcp --dport ${port} -j ACCEPT >/dev/null 2>&1 iptables -I INPUT -p udp --dport ${port} -j ACCEPT >/dev/null 2>&1 else ip6tables -I INPUT -p tcp --dport ${port} -j ACCEPT >/dev/null 2>&1 ip6tables -I INPUT -p udp --dport ${port} -j ACCEPT >/dev/null 2>&1 fi ;; esac echo -e "${Green}已成功为 ${ip_version} 端口 ${port} 配置防火墙规则 (TCP/UDP)。${Font}" else echo -e "${Yellow}检测到 ${firewall_tool},但无权限修改。请手动配置 ${ip_version} 端口 ${port} 的防火墙规则 (TCP/UDP)。${Font}" fi } # 移除防火墙规则 remove_firewall_rules() { local port=$1 local ip_type=$2 # 处理不同类型的IP版本 if [ "$ip_type" == "domain" ]; then ip_type="ipv4" elif [ "$ip_type" == "domain6" ]; then ip_type="ipv6" fi local firewall_tool="" if command -v firewall-cmd >/dev/null 2>&1; then firewall_tool="firewalld" elif command -v ufw >/dev/null 2>&1; then firewall_tool="ufw" elif command -v iptables >/dev/null 2>&1; then firewall_tool="iptables" fi if [ -z "$firewall_tool" ]; then echo -e "${Yellow}未检测到防火墙工具,跳过防火墙规则移除。${Font}" return fi case $firewall_tool in "firewalld") if [ "$ip_type" == "ipv4" ]; then firewall-cmd --zone=public --remove-port=${port}/tcp --permanent >/dev/null 2>&1 firewall-cmd --zone=public --remove-port=${port}/udp --permanent >/dev/null 2>&1 else firewall-cmd --zone=public --remove-port=${port}/tcp --permanent --ipv6 >/dev/null 2>&1 firewall-cmd --zone=public --remove-port=${port}/udp --permanent --ipv6 >/dev/null 2>&1 fi firewall-cmd --reload >/dev/null 2>&1 ;; "ufw") ufw delete allow ${port}/tcp >/dev/null 2>&1 ufw delete allow ${port}/udp >/dev/null 2>&1 ;; "iptables") if [ "$ip_type" == "ipv4" ]; then iptables -D INPUT -p tcp --dport ${port} -j ACCEPT >/dev/null 2>&1 iptables -D INPUT -p udp --dport ${port} -j ACCEPT >/dev/null 2>&1 else ip6tables -D INPUT -p tcp --dport ${port} -j ACCEPT >/dev/null 2>&1 ip6tables -D INPUT -p udp --dport ${port} -j ACCEPT >/dev/null 2>&1 fi ;; esac echo -e "${Green}已移除端口 ${port} 的防火墙规则 (TCP/UDP)。${Font}" } # 恢复之前的转发 restore_forwards() { if [ -s "$CONFIG_FILE" ]; then echo "正在恢复之前的转发..." while IFS=' ' read -r ip_type listen_port remote_ip remote_port; do local service_name="socat-${listen_port}-${remote_port}" if [ "$ip_type" == "ipv4" ]; then create_systemd_service "${service_name}-tcp" "/usr/bin/socat TCP4-LISTEN:${listen_port},reuseaddr,fork TCP4:${remote_ip}:${remote_port}" create_systemd_service "${service_name}-udp" "/usr/bin/socat UDP4-LISTEN:${listen_port},reuseaddr,fork UDP4:${remote_ip}:${remote_port}" elif [ "$ip_type" == "ipv6" ]; then create_systemd_service "${service_name}-tcp" "/usr/bin/socat TCP6-LISTEN:${listen_port},reuseaddr,fork TCP6:${remote_ip}:${remote_port}" create_systemd_service "${service_name}-udp" "/usr/bin/socat UDP6-LISTEN:${listen_port},reuseaddr,fork UDP6:${remote_ip}:${remote_port}" elif [ "$ip_type" == "domain" ]; then create_systemd_service "${service_name}-tcp" "/usr/bin/socat TCP4-LISTEN:${listen_port},reuseaddr,fork TCP:${remote_ip}:${remote_port}" create_systemd_service "${service_name}-udp" "/usr/bin/socat UDP4-LISTEN:${listen_port},reuseaddr,fork UDP:${remote_ip}:${remote_port}" # 恢复域名监控 setup_domain_monitor "$remote_ip" "$listen_port" "$ip_type" "$remote_port" elif [ "$ip_type" == "domain6" ]; then create_systemd_service "${service_name}-tcp" "/usr/bin/socat TCP6-LISTEN:${listen_port},reuseaddr,fork TCP6:${remote_ip}:${remote_port}" create_systemd_service "${service_name}-udp" "/usr/bin/socat UDP6-LISTEN:${listen_port},reuseaddr,fork UDP6:${remote_ip}:${remote_port}" # 恢复域名监控 setup_domain_monitor "$remote_ip" "$listen_port" "$ip_type" "$remote_port" fi # 显示不同类型的转发恢复信息 if [ "$ip_type" == "ipv6" ] || [ "$ip_type" == "domain6" ]; then echo "已恢复IPv6转发:${listen_port} -> ${remote_ip}:${remote_port}" else echo "已恢复IPv4转发:${listen_port} -> ${remote_ip}:${remote_port}" fi # 如果是域名类型,显示监控恢复信息 if [ "$ip_type" == "domain" ] || [ "$ip_type" == "domain6" ]; then echo "已恢复域名 ${remote_ip} 的IP监控服务" fi done < "$CONFIG_FILE" fi } # 检查是否已启用BBR或其变种 check_and_enable_bbr() { echo -e "${Green}正在检查 BBR 状态...${Font}" kernel_version=$(uname -r | cut -d- -f1) if [[ $(echo $kernel_version 4.9 | awk '{print ($1 < $2)}') -eq 1 ]]; then echo -e "${Red}当前内核版本 ($kernel_version) 过低,不支持 BBR。需要 4.9 或更高版本。${Font}" return 1 fi current_cc=$(sysctl -n net.ipv4.tcp_congestion_control) if ! lsmod | grep -q "tcp_bbr"; then echo -e "${Yellow}BBR 模块未加载,正在尝试加载...${Font}" modprobe tcp_bbr if ! lsmod | grep -q "tcp_bbr"; then echo -e "${Red}无法加载 BBR 模块。请检查您的系统是否支持 BBR。${Font}" return 1 fi fi bbr_variants=("bbr" "bbr2" "bbrplus" "tsunamy") if [[ " ${bbr_variants[@]} " =~ " ${current_cc} " ]]; then echo -e "${Yellow}检测到系统已启用 ${current_cc}。${Font}" else echo -e "${Yellow}当前拥塞控制算法为 ${current_cc},正在切换到 BBR...${Font}" sysctl -w net.ipv4.tcp_congestion_control=bbr fi current_qdisc=$(sysctl -n net.core.default_qdisc) if [[ $current_qdisc != "fq" ]]; then echo -e "${Yellow}当前队列调度算法为 ${current_qdisc},正在切换到 fq...${Font}" sysctl -w net.core.default_qdisc=fq echo "net.core.default_qdisc = fq" >> /etc/sysctl.conf fi if ! grep -q "net.ipv4.tcp_congestion_control = bbr" /etc/sysctl.conf; then echo "net.ipv4.tcp_congestion_control = bbr" >> /etc/sysctl.conf fi sysctl -p current_cc=$(sysctl -n net.ipv4.tcp_congestion_control) if [[ $current_cc == "bbr" ]]; then echo -e "${Green}BBR 已成功启用。${Font}" else echo -e "${Red}BBR 启用失败,当前拥塞控制算法为 ${current_cc}。${Font}" fi } # 开启端口转发加速 enable_acceleration() { echo -e "${Green}正在开启端口转发加速...${Font}" sed -i '/net.ipv4.tcp_fastopen/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_slow_start_after_idle/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_mtu_probing/d' /etc/sysctl.conf sed -i '/net.core.rmem_max/d' /etc/sysctl.conf sed -i '/net.core.wmem_max/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_rmem/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_wmem/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_mem/d' /etc/sysctl.conf sed -i '/net.core.netdev_max_backlog/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_max_syn_backlog/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_tw_reuse/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_fin_timeout/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_keepalive_time/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_max_tw_buckets/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_fastopen/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_rfc1337/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_sack/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_fack/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_window_scaling/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_adv_win_scale/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_moderate_rcvbuf/d' /etc/sysctl.conf sed -i '/net.core.optmem_max/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_notsent_lowat/d' /etc/sysctl.conf check_and_enable_bbr echo 3 > /proc/sys/net/ipv4/tcp_fastopen sysctl -w net.ipv4.tcp_slow_start_after_idle=0 sysctl -w net.ipv4.tcp_mtu_probing=1 sysctl -w net.core.rmem_max=26214400 sysctl -w net.core.wmem_max=26214400 sysctl -w net.ipv4.tcp_rmem='4096 87380 26214400' sysctl -w net.ipv4.tcp_wmem='4096 16384 26214400' sysctl -w net.ipv4.tcp_mem='26214400 26214400 26214400' sysctl -w net.core.netdev_max_backlog=2048 sysctl -w net.ipv4.tcp_max_syn_backlog=2048 sysctl -w net.ipv4.tcp_tw_reuse=1 sysctl -w net.ipv4.tcp_fin_timeout=15 sysctl -w net.ipv4.tcp_keepalive_time=1200 sysctl -w net.ipv4.tcp_max_tw_buckets=2000000 sysctl -w net.ipv4.tcp_fastopen=3 sysctl -w net.ipv4.tcp_mtu_probing=1 sysctl -w net.ipv4.tcp_syncookies=1 sysctl -w net.ipv4.tcp_rfc1337=1 sysctl -w net.ipv4.tcp_sack=1 sysctl -w net.ipv4.tcp_fack=1 sysctl -w net.ipv4.tcp_window_scaling=1 sysctl -w net.ipv4.tcp_adv_win_scale=2 sysctl -w net.ipv4.tcp_moderate_rcvbuf=1 sysctl -w net.core.optmem_max=65535 sysctl -w net.ipv4.tcp_notsent_lowat=16384 echo "net.ipv4.tcp_fastopen = 3" >> /etc/sysctl.conf echo "net.ipv4.tcp_slow_start_after_idle = 0" >> /etc/sysctl.conf echo "net.ipv4.tcp_mtu_probing = 1" >> /etc/sysctl.conf echo "net.core.rmem_max = 26214400" >> /etc/sysctl.conf echo "net.core.wmem_max = 26214400" >> /etc/sysctl.conf echo "net.ipv4.tcp_rmem = 4096 87380 26214400" >> /etc/sysctl.conf echo "net.ipv4.tcp_wmem = 4096 16384 26214400" >> /etc/sysctl.conf echo "net.ipv4.tcp_mem = 26214400 26214400 26214400" >> /etc/sysctl.conf echo "net.core.netdev_max_backlog = 2048" >> /etc/sysctl.conf echo "net.ipv4.tcp_max_syn_backlog = 2048" >> /etc/sysctl.conf echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_fin_timeout = 15" >> /etc/sysctl.conf echo "net.ipv4.tcp_keepalive_time = 1200" >> /etc/sysctl.conf echo "net.ipv4.tcp_max_tw_buckets = 2000000" >> /etc/sysctl.conf echo "net.ipv4.tcp_fastopen = 3" >> /etc/sysctl.conf echo "net.ipv4.tcp_mtu_probing = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_syncookies = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_rfc1337 = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_sack = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_fack = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_window_scaling = 1" >> /etc/sysctl.conf echo "net.ipv4.tcp_adv_win_scale = 2" >> /etc/sysctl.conf echo "net.ipv4.tcp_moderate_rcvbuf = 1" >> /etc/sysctl.conf echo "net.core.optmem_max = 65535" >> /etc/sysctl.conf echo "net.ipv4.tcp_notsent_lowat = 16384" >> /etc/sysctl.conf sysctl -p echo -e "${Green}端口转发加速已开启${Font}" } # 关闭端口转发加速 disable_acceleration() { echo -e "${Yellow}正在关闭端口转发加速...${Font}" sysctl -w net.ipv4.tcp_fastopen=0 sysctl -w net.ipv4.tcp_congestion_control=cubic sysctl -w net.core.default_qdisc=pfifo_fast sysctl -w net.ipv4.tcp_slow_start_after_idle=1 sysctl -w net.ipv4.tcp_mtu_probing=0 sysctl -w net.core.rmem_max=212992 sysctl -w net.core.wmem_max=212992 sysctl -w net.ipv4.tcp_rmem='4096 87380 6291456' sysctl -w net.ipv4.tcp_wmem='4096 16384 4194304' sysctl -w net.ipv4.tcp_mem='378651 504868 757299' sysctl -w net.core.netdev_max_backlog=1000 sysctl -w net.ipv4.tcp_max_syn_backlog=128 sysctl -w net.ipv4.tcp_tw_reuse=0 sysctl -w net.ipv4.tcp_fin_timeout=60 sysctl -w net.ipv4.tcp_keepalive_time=7200 sysctl -w net.ipv4.tcp_max_tw_buckets=180000 sysctl -w net.ipv4.tcp_syncookies=1 sysctl -w net.ipv4.tcp_rfc1337=0 sysctl -w net.ipv4.tcp_sack=1 sysctl -w net.ipv4.tcp_fack=1 sysctl -w net.ipv4.tcp_window_scaling=1 sysctl -w net.ipv4.tcp_adv_win_scale=1 sysctl -w net.ipv4.tcp_moderate_rcvbuf=1 sysctl -w net.core.optmem_max=20480 sysctl -w net.ipv4.tcp_notsent_lowat=4294967295 sed -i '/net.ipv4.tcp_fastopen/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_congestion_control/d' /etc/sysctl.conf sed -i '/net.core.default_qdisc/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_slow_start_after_idle/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_mtu_probing/d' /etc/sysctl.conf sed -i '/net.core.rmem_max/d' /etc/sysctl.conf sed -i '/net.core.wmem_max/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_rmem/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_wmem/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_mem/d' /etc/sysctl.conf sed -i '/net.core.netdev_max_backlog/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_max_syn_backlog/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_tw_reuse/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_fin_timeout/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_keepalive_time/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_max_tw_buckets/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_fastopen/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_rfc1337/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_sack/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_fack/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_window_scaling/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_adv_win_scale/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_moderate_rcvbuf/d' /etc/sysctl.conf sed -i '/net.core.optmem_max/d' /etc/sysctl.conf sed -i '/net.ipv4.tcp_notsent_lowat/d' /etc/sysctl.conf sysctl -p echo -e "${Yellow}端口转发加速已关闭${Font}" } # 设置域名监控服务 setup_domain_monitor() { local domain=$1 local listen_port=$2 local ip_type=$3 local remote_port=$4 local monitor_script="$SOCATS_DIR/monitor_${listen_port}.sh" # 创建完整的监控脚本,直接内嵌函数定义 cat > "$monitor_script" <<'EOF' #!/bin/bash PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin export PATH # 脚本参数 DOMAIN="$1" LISTEN_PORT="$2" IP_TYPE="$3" REMOTE_PORT="$4" SOCATS_DIR="$5" # 监控域名IP变更的函数 monitor_domain_ip() { local domain=$1 local listen_port=$2 local ip_type=$3 local cache_file="${SOCATS_DIR}/dns_cache_${domain//[^a-zA-Z0-9]/_}.txt" local current_ip="" # 获取当前IP(支持IPv4和IPv6) if [[ "$ip_type" == "ipv4" || "$ip_type" == "domain" ]]; then # 尝试使用不同的命令解析IPv4 current_ip=$(host -t A "$domain" 2>/dev/null | grep "has address" | head -n1 | awk '{print $NF}') if [ -z "$current_ip" ]; then current_ip=$(dig +short A "$domain" 2>/dev/null | head -n1) fi if [ -z "$current_ip" ]; then current_ip=$(nslookup "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -n1 | awk '{print $NF}') fi else # 尝试使用不同的命令解析IPv6 current_ip=$(host -t AAAA "$domain" 2>/dev/null | grep "has IPv6 address" | head -n1 | awk '{print $NF}') if [ -z "$current_ip" ]; then current_ip=$(dig +short AAAA "$domain" 2>/dev/null | head -n1) fi if [ -z "$current_ip" ]; then current_ip=$(nslookup -type=AAAA "$domain" 2>/dev/null | grep -A1 "Name:" | grep "Address:" | head -n1 | awk '{print $NF}') fi fi if [ -z "$current_ip" ]; then echo "无法解析域名 $domain 的IP地址" >> "${SOCATS_DIR}/dns_monitor.log" return 1 fi # 如果缓存文件不存在,创建它 if [ ! -f "$cache_file" ]; then echo "$current_ip" > "$cache_file" echo "$(date): 初始化域名 $domain 的IP缓存: $current_ip" >> "${SOCATS_DIR}/dns_monitor.log" return 0 fi # 读取上次缓存的IP local cached_ip=$(cat "$cache_file") # 如果IP变更,重启服务 if [ "$current_ip" != "$cached_ip" ]; then echo "$(date): 检测到域名 $domain 的IP变更: $cached_ip -> $current_ip" >> "${SOCATS_DIR}/dns_monitor.log" echo "$current_ip" > "$cache_file" # 重启对应的socat服务 local service_name="socat-${listen_port}-*" systemctl restart $service_name echo "$(date): 已重启转发服务 $service_name" >> "${SOCATS_DIR}/dns_monitor.log" return 0 fi return 0 } # 执行监控 monitor_domain_ip "$DOMAIN" "$LISTEN_PORT" "$IP_TYPE" EOF chmod +x "$monitor_script" # 创建systemd定时器服务 local timer_name="domain-monitor-${listen_port}" cat > /etc/systemd/system/${timer_name}.service < /etc/systemd/system/${timer_name}.timer </dev/null 2>&1 systemctl disable ${timer_name}.timer >/dev/null 2>&1 rm -f /etc/systemd/system/${timer_name}.service rm -f /etc/systemd/system/${timer_name}.timer rm -f "$SOCATS_DIR/monitor_${listen_port}.sh" systemctl daemon-reload echo -e "${Green}已移除端口 ${listen_port} 的域名监控服务${Font}" } # 修改域名监控频率 change_monitor_interval() { if [ ! -s "$CONFIG_FILE" ]; then echo -e "${Red}当前没有活动的转发。${Font}" return fi local has_domain=false while IFS=' ' read -r ip_type listen_port remote_ip remote_port; do if [ "$ip_type" == "domain" ] || [ "$ip_type" == "domain6" ]; then has_domain=true break fi done < "$CONFIG_FILE" if [ "$has_domain" == "false" ]; then echo -e "${Red}当前没有活动的域名转发。${Font}" return fi echo -e "${Green}当前域名转发:${Font}" local i=1 local domain_entries=() while IFS=' ' read -r ip_type listen_port remote_ip remote_port; do if [ "$ip_type" == "domain" ] || [ "$ip_type" == "domain6" ]; then domain_entries+=("$listen_port $remote_ip $ip_type") if [ "$ip_type" == "domain" ]; then echo "$i. IPv4域名: $ip:$listen_port --> $remote_ip:$remote_port" else echo "$i. IPv6域名: [$ipv6]:$listen_port --> $remote_ip:$remote_port" fi ((i++)) fi done < "$CONFIG_FILE" if [ ${#domain_entries[@]} -eq 0 ]; then echo -e "${Red}未找到任何域名转发。${Font}" return fi read -p "请输入要修改监控频率的域名转发编号: " num if [ -z "$num" ] || ! [[ $num =~ ^[0-9]+$ ]] || [ $num -lt 1 ] || [ $num -gt ${#domain_entries[@]} ]; then echo -e "${Red}无效的编号。${Font}" return fi local index=$((num-1)) IFS=' ' read -r port domain type <<< "${domain_entries[$index]}" local timer_name="domain-monitor-${port}" local timer_file="/etc/systemd/system/${timer_name}.timer" if [ ! -f "$timer_file" ]; then echo -e "${Red}找不到域名 $domain 的监控定时器。${Font}" return fi local current_interval=$(grep "OnUnitActiveSec" "$timer_file" | awk -F= '{print $2}' | tr -d '[:space:]') echo -e "${Green}当前域名 $domain 的监控频率为 ${current_interval:-300s}${Font}" echo -e "${Yellow}请选择新的监控频率:${Font}" echo "1. 1分钟 (适合频繁变更的域名)" echo "2. 5分钟 (默认)" echo "3. 15分钟" echo "4. 30分钟" echo "5. 1小时" echo "6. 自定义" read -p "请选择 [1-6]: " choice local new_interval="" case $choice in 1) new_interval="60s" ;; 2) new_interval="300s" ;; 3) new_interval="900s" ;; 4) new_interval="1800s" ;; 5) new_interval="3600s" ;; 6) read -p "请输入自定义时间间隔 (格式: 数字+单位, 例如 10s, 5m, 1h): " custom_interval if [[ $custom_interval =~ ^[0-9]+[smhd]$ ]]; then new_interval=$custom_interval else echo -e "${Red}无效的时间格式。使用默认值300s。${Font}" new_interval="300s" fi ;; *) echo -e "${Red}无效的选择。使用默认值300s。${Font}" new_interval="300s" ;; esac # 更新定时器配置 sed -i "s/OnUnitActiveSec=.*/OnUnitActiveSec=$new_interval/" "$timer_file" systemctl daemon-reload systemctl restart ${timer_name}.timer echo -e "${Green}已将域名 $domain 的监控频率更新为 $new_interval${Font}" } # 显示Socat管理子菜单 manage_socat_menu() { while true; do clear_screen echo -e "${Green} _____ __ / ___/____ _________ _/ /_ \__ \/ __ \/ ___/ __ \`/ __/ ___/ / /_/ / /__/ /_/ / /_ /____/\____/\___/\__,_/\__/ ${Yellow}Socat管理${Font}" echo -e "${Blue}==========================================${Font}" echo -e "${Yellow}1.${Font} 开启Socat" echo -e "${Yellow}2.${Font} 关闭Socat" echo -e "${Yellow}3.${Font} 重启Socat" echo -e "${Yellow}4.${Font} 卸载Socat" echo -e "${Yellow}5.${Font} 返回主菜单" echo -e "${Blue}==========================================${Font}" read -p "请输入选项 [1-5]: " choice case $choice in 1) echo -e "${Green}开启Socat...${Font}" open_socat ;; 2) echo -e "${Green}终止所有 Socat 进程...${Font}" kill_all_socat ;; 3) echo -e "${Green}重启Socat...${Font}" re_socat ;; 4) echo -e "${Green}卸载Socat...${Font}" uninstall_socat return ;; 5) return ;; *) echo -e "${Red}无效的选项,请重新输入。${Font}" sleep 2 ;; esac done } # 开启/重新加载socat open_socat(){ restore_forwards } # 强制终止所有Socat进程 kill_all_socat() { echo -e "${Yellow}正在终止所有 Socat 进程...${Font}" # 停止并禁用所有socat服务 for service_file in /etc/systemd/system/socat-*.service; do if [ -f "$service_file" ]; then service_name=$(basename "$service_file" .service) systemctl stop "$service_name" systemctl disable "$service_name" fi done rm -f /etc/systemd/system/socat-*.service systemctl daemon-reload pkill -9 -f "$(which socat)" #pkill -9 -f "$0" sleep 2 if pgrep -f socat > /dev/null; then echo -e "${Red}警告:某些 Socat 进程可能仍在运行。请考虑手动检查。${Font}" else echo -e "${Green}所有 Socat 进程已成功终止。${Font}" fi if [[ "$1" == "uninstall" ]]; then > "$CONFIG_FILE" echo -e "${Green}已清空转发配置文件${Font}" elif [[ "$1" != "noconfirm" ]]; then read -p "是否清除Socat转发配置文件?[y/N]: " confirm if [[ $confirm =~ ^[Yy]$ ]]; then > "$CONFIG_FILE" echo -e "${Green}已清空转发配置文件${Font}" else echo -e "${Yellow}已保留转发配置文件${Font}" fi else echo -e "${Yellow}正在执行重启操作${Font}" fi echo -e "${Green}已从配置和开机自启动中移除所有 Socat 转发${Font}" } # 重启socat re_socat(){ kill_all_socat "noconfirm" sleep 2 restore_forwards } # 卸载socat uninstall_socat() { if ! command -v socat > /dev/null; then echo -e "${Red}错误:系统中未安装Socat,无需执行卸载操作${Font}" return 1 fi echo -e "${Yellow}正在执行彻底卸载操作...${Font}" # 停止并清理所有服务 kill_all_socat "uninstall" # 删除系统服务文件 rm -f /etc/systemd/system/socat-*.{service,timer} systemctl daemon-reload # 删除配置目录和文件 rm -rf "$SOCATS_DIR" [ -f "$CONFIG_FILE" ] && rm -f "$CONFIG_FILE" # 卸载socat程序 local uninstall_success=0 if command -v apt-get > /dev/null; then echo -e "${Yellow}正在通过apt-get卸载Socat...${Font}" if apt-get remove -y socat; then uninstall_success=1 echo -e "${Green}apt-get卸载成功${Font}" else echo -e "${Red}apt-get卸载失败,请手动检查${Font}" fi elif command -v yum > /dev/null; then echo -e "${Yellow}正在通过yum卸载Socat...${Font}" if yum remove -y socat; then uninstall_success=1 echo -e "${Green}yum卸载成功${Font}" else echo -e "${Red}yum卸载失败,请手动检查${Font}" fi else echo -e "${Yellow}检测到手动安装的Socat,尝试查找二进制文件...${Font}" if which socat > /dev/null; then local socat_path=$(which socat) echo -e "${Yellow}发现Socat可执行文件: $socat_path ${Font}" rm -f "$socat_path" [ ! -f "$socat_path" ] && uninstall_success=1 fi fi if [ $uninstall_success -eq 1 ] && ! command -v socat > /dev/null; then echo -e "${Green}✅ Socat卸载验证通过${Font}" else echo -e "${Red}⚠️ Socat卸载未完成,请手动检查以下内容:${Font}" echo -e "${Yellow}1. 检查残留文件: which socat\n2. 检查进程状态: pgrep -f socat${Font}" fi echo -e "${Green}已成功卸载Socat及所有相关文件${Font}" } # 显示菜单 show_menu() { echo -e "${Green} _____ __ / ___/____ _________ _/ /_ \__ \/ __ \/ ___/ __ \`/ __/ ___/ / /_/ / /__/ /_/ / /_ /____/\____/\___/\__,_/\__/ ${Yellow}Management Script${Font}" echo -e "${Blue}==========================================${Font}" echo -e "${Yellow}1.${Font} 添加新转发" echo -e "${Yellow}2.${Font} 查看或删除转发" echo -e "${Yellow}3.${Font} Socat管理" echo -e "${Yellow}4.${Font} 开启端口转发加速" echo -e "${Yellow}5.${Font} 关闭端口转发加速" echo -e "${Yellow}6.${Font} 设置域名监控频率" echo -e "${Yellow}7.${Font} 退出脚本" echo -e "${Blue}==========================================${Font}" echo -e "${Green}当前 IPv4: ${ip:-未知}${Font}" echo -e "${Green}当前 IPv6: ${ipv6:-未知}${Font}" echo } # 主程序 main() { check_root check_sys install_socat ip=$(get_ip) ipv6=$(get_ipv6) // 初始化标记检查 if [ ! -f "$SOCATS_DIR/.initialized" ]; then init_config restore_forwards clear_screen touch "$SOCATS_DIR/.initialized" echo -e "${Green}所有配置和日志文件将保存在: $SOCATS_DIR${Font}" fi clear_screen #echo -e "${Green}所有配置和日志文件将保存在: $SOCATS_DIR${Font}" while true; do show_menu read -p "请输入选项 [1-7]: " choice clear_screen case $choice in 1) if config_socat; then start_socat else echo -e "${Red}配置失败,未能启动 Socat${Font}" fi press_any_key ;; 2) view_delete_forward press_any_key ;; 3) manage_socat_menu clear_screen ;; 4) enable_acceleration press_any_key ;; 5) disable_acceleration press_any_key ;; 6) change_monitor_interval press_any_key ;; 7) echo -e "${Green}感谢使用,再见!${Font}" exit 0 ;; *) echo -e "${Red}无效选项,请重新选择${Font}" press_any_key ;; esac done } # 执行主程序 main