softroute/scripts/gateway.sh.j2
2025-11-30 12:24:03 +08:00

355 lines
15 KiB
Django/Jinja
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
set -eo pipefail
# ==============================================================================
# 网关主机配置变量 - 请根据你的实际环境修改!
# ==============================================================================
# 网关主机内网IP (用于其他内网主机连接)
GATEWAY_LAN_IP="{{ gateway_lan_ip }}"
GATEWAY_LAN_CIDR="{{ gateway_lan_cidr }}" # 内网网段
# DHCP 租约范围
DHCP_START_IP="{{ dhcp_start_ip }}"
DHCP_END_IP="{{ dhcp_end_ip }}"
DHCP_LEASE_TIME="{{ dhcp_lease_time }}" # 租约时间,秒 (例如 2 小时)
# 网关主机网卡名称
WAN_INTERFACE="{{ wan_interface }}" # 连接外网的网卡通常是DHCP获取IP
LAN_INTERFACE="{{ lan_interface }}" # 连接内网的网卡我们将配置静态IP
# SSH SOCKS5 代理配置
REMOTE_SSH_USER="{{ remote_ssh_user }}" # 远程服务器的SSH用户名
REMOTE_SSH_IP="{{ remote_ssh_ip }}" # 远程服务器的IP地址
REMOTE_SSH_PORT="{{ remote_ssh_port }}" # 远程服务器的SSH端口
LOCAL_SOCKS5_PORT="{{ local_socks5_port }}" # SSH SOCKS5 代理在本机监听的端口 (127.0.0.1:1080)
# 透明代理工具 redsocks 监听端口
REDSOCKS_PORT="{{ redsocks_port }}" # redsocks 在本机监听的端口
# DNSMASQ 配置
DNSMASQ_LISTEN_IP="${GATEWAY_LAN_IP}" # dnsmasq 监听的IP
DOMESTIC_DNS1="{{ domestic_dns1 }}" # 国内DNS服务器
DOMESTIC_DNS2="{{ domestic_dns2 }}" # 国内DNS服务器
FOREIGN_DNS1="{{ foreign_dns1 }}" # 国外DNS服务器 (通过SSH SOCKS5代理访问)
FOREIGN_DNS2="{{ foreign_dns2 }}" # 国外DNS服务器 (通过SSH SOCKS5代理访问)
# GFWLIST2NEW 工具仓库和安装路径
GFWLIST2NEW_REPO="{{ gfwlist2new_repo }}"
GFWLIST2NEW_DIR="{{ gfwlist2new_dir }}"
# ==============================================================================
# 通用函数
# ==============================================================================
log_info() {
echo -e "\e[32m[INFO] $(date +'%Y-%m-%d %H:%M:%S') $1\e[0m"
}
log_warn() {
echo -e "\e[33m[WARN] $(date +'%Y-%m-%d %H:%M:%S') $1\e[0m" >&2
}
log_error() {
echo -e "\e[31m[ERROR] $(date +'%Y-%m-%d %H:%M:%S') $1\e[0m" >&2
exit 1
}
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "此脚本必须以 root 用户或使用 sudo 运行。"
fi
}
install_package() {
PACKAGE="$1"
if ! dpkg -s "$PACKAGE" &>/dev/null; then
log_info "安装 $PACKAGE..."
sudo apt install -y "$PACKAGE" || log_error "安装 $PACKAGE 失败。"
else
log_info "$PACKAGE 已安装。"
fi
}
# ==============================================================================
# 0. 前置检查与环境初始化
# ==============================================================================
check_root
log_info "开始网关主机配置脚本..."
log_info "更新系统软件包列表..."
sudo apt update || log_error "apt update 失败。"
log_info "禁用 UFW 以避免与 iptables 冲突..."
sudo ufw disable || log_warn "UFW 未运行或禁用失败,请手动确认。"
log_info "安装必要工具net-tools, iptables-persistent, ipset, dnsmasq, redsocks, git, python3-pip, isc-dhcp-server..."
install_package net-tools
install_package iptables-persistent
install_package ipset
install_package dnsmasq
install_package redsocks
install_package git
install_package python3-pip
install_package isc-dhcp-server # 新增 DHCP 服务器安装
# ==============================================================================
# 1. 配置内网网卡 IP 和 IP 转发
# ==============================================================================
log_info "配置网关主机内网网卡 (${LAN_INTERFACE}) 静态 IP..."
# Netplan 配置
NETPLAN_FILE="/etc/netplan/01-netcfg.yaml"
# 备份现有配置
sudo cp ${NETPLAN_FILE} ${NETPLAN_FILE}.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份Netplan文件失败。"
cat <<EOF | sudo tee ${NETPLAN_FILE} > /dev/null
network:
version: 2
renderer: networkd
ethernets:
{{ wan_interface }}:
dhcp4: true # 外网网卡通常通过DHCP获取IP
optional: true # 允许此接口暂时不可用
{{ lan_interface }}:
addresses:
- ${GATEWAY_LAN_IP}/24
# 由于 dnsmasq 也会提供 DNS 服务,这里不需要单独配置 nameservers
EOF
sudo netplan try
sudo netplan apply || log_error "应用 Netplan 配置失败请检查网卡名称和IP地址。"
log_info "内网网卡 ${LAN_INTERFACE} 已配置 IP: ${GATEWAY_LAN_IP}。"
log_info "开启 IP 转发功能..."
sudo sed -i '/^#net.ipv4.ip_forward=1/s/^#//' /etc/sysctl.conf || true # 取消注释
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf > /dev/null # 确保添加
sudo sysctl -p > /dev/null || log_error "应用 sysctl 配置失败。"
log_info "IP 转发已开启。"
# ==============================================================================
# 2. 配置 DHCP 服务器 (ISC DHCP Server)
# ==============================================================================
log_info "配置 ISC DHCP Server..."
# 确保 DHCP 服务器只监听内网接口
sudo sed -i "s/^INTERFACESv4=.*/INTERFACESv4=\"${LAN_INTERFACE}\"/g" /etc/default/isc-dhcp-server || log_error "配置 isc-dhcp-server 监听接口失败。"
# 备份 DHCP 主配置文件
sudo cp /etc/dhcp/dhcpd.conf /etc/dhcp/dhcpd.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 dhcpd.conf 失败。"
# 清空并写入新的 DHCP 配置
cat <<EOF | sudo tee /etc/dhcp/dhcpd.conf > /dev/null
# DHCPD CONFIGURATION FILE
# The ddns-update-style parameter to use for DDNS updates.
ddns-update-style none;
# Default lease time
default-lease-time ${DHCP_LEASE_TIME};
max-lease-time ${DHCP_LEASE_TIME};
# If this DHCP server is the official DHCP server for the local network segment
# then uncomment the authoritative directive.
authoritative;
# A slightly different configuration for an internal subnet.
subnet {{ gateway_lan_cidr%.* }}.0 netmask 255.255.255.0 {
range ${DHCP_START_IP} ${DHCP_END_IP};
option routers ${GATEWAY_LAN_IP};
option domain-name-servers ${GATEWAY_LAN_IP}; # DNS 指向网关主机本身
option broadcast-address {{ gateway_lan_cidr%.* }}.255;
default-lease-time ${DHCP_LEASE_TIME};
max-lease-time ${DHCP_LEASE_TIME};
}
# No service will be given on this subnet, but DECLINEs from hosts on this
# subnet will be processed.
# subnet 192.168.1.0 netmask 255.255.255.0 {
# }
EOF
sudo systemctl restart isc-dhcp-server || log_error "重启 isc-dhcp-server 服务失败。"
sudo systemctl enable isc-dhcp-server || log_error "启用 isc-dhcp-server 服务失败。"
log_info "ISC DHCP Server 已配置并启动,在 ${LAN_INTERFACE} 上提供 DHCP 服务。"
# ==============================================================================
# 3. 启动 SSH SOCKS5 代理 (保持不变)
# ==============================================================================
log_info "${curuser}:配置 SSH SOCKS5 代理 Systemd 服务..."
SSH_SOCKS5_SERVICE_FILE="/etc/systemd/system/ssh-socks5.service"
# 动态创建 Service 文件
cat <<EOF | sudo tee ${SSH_SOCKS5_SERVICE_FILE} > /dev/null
[Unit]
Description=SSH SOCKS5 Proxy Service
After=network-online.target
[Service]
User=${curuser}
Type=simple
# 注意:这里需要确保用户 {{ remote_ssh_user }} 是一个实际存在的用户,并且可以访>问其 $HOME/.ssh
# 为了简化我们暂时用root运行但更推荐使用非root用户
ExecStart=/usr/bin/ssh -D ${LOCAL_SOCKS5_PORT} -N -p ${REMOTE_SSH_PORT} ${REMOTE_SSH_USER}@${REMOTE_SSH_IP} -o ExitOnForwardFailure=yes -o ServerAliveInterval=60 -o ServerAliveCountMax=3
# 使用 Restart 策略确保连接断开时自动重连
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
log_info "启动并启用 SSH SOCKS5 代理服务..."
sudo systemctl daemon-reload
sudo systemctl enable ssh-socks5.service || log_error "启用 ssh-socks5 服务失败>。"
sudo systemctl restart ssh-socks5.service || log_error "启动 ssh-socks5 服务失败
。请检查连接和免密登录配置。"
sleep 5 # 留出时间让服务启动和重试
if ! ss -tnlp | grep ":${LOCAL_SOCKS5_PORT}" &>/dev/null; then
log_error "SSH SOCKS5 代理端口 ${LOCAL_SOCKS5_PORT} 未在监听。请手动检查 SSH 进程。"
fi
log_info "SSH SOCKS5 代理已通过 Systemd 启动,并在 127.0.0.1:${LOCAL_SOCKS5_PORT} 监听,支持自动重连。"
# ==============================================================================
# 4. 配置 redsocks (透明 SOCKS5 代理) (保持不变)
# ==============================================================================
log_info "配置 redsocks 透明代理..."
# 备份现有配置
sudo cp /etc/redsocks.conf /etc/redsocks.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 redsocks.conf 失败。"
cat <<EOF | sudo tee /etc/redsocks.conf > /dev/null
base {
log_debug = off;
log_info = on;
log = "syslog:daemon";
daemon = on; # 后台运行
redirector = iptables;
}
redsocks {
local_ip = 127.0.0.1;
local_port = ${REDSOCKS_PORT};
ip = 127.0.0.1; # SSH SOCKS5 代理的地址
port = ${LOCAL_SOCKS5_PORT}; # SSH SOCKS5 代理的端口
type = socks5; # SOCKS5 代理
}
EOF
sudo systemctl restart redsocks || log_error "重启 redsocks 服务失败。"
sudo systemctl enable redsocks || log_error "启用 redsocks 服务失败。"
log_info "redsocks 透明代理已配置并启动,监听 127.0.0.1:${REDSOCKS_PORT}。"
# ==============================================================================
# 5. 配置 dnsmasq 智能 DNS 转发 (保持不变)
# ==============================================================================
log_info "配置 dnsmasq 智能 DNS 转发..."
# 备份现有配置
sudo cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 dnsmasq.conf 失败。"
sudo rm -f /etc/dnsmasq.d/* # 清理旧的额外配置
cat <<EOF | sudo tee /etc/dnsmasq.conf > /dev/null
# 指定监听地址只监听内网IP和本地环回
listen-address=${DNSMASQ_LISTEN_IP},127.0.0.1
# 不使用 /etc/resolv.conf 中的 DNS 服务器
no-resolv
no-poll
# 国内域名直连公共DNS
server={{ domestic_dns1 }}
server={{ domestic_dns2 }}
# 国外域名通过 gfwlist2new 生成的配置文件转发到代理
# dnsmasq will read additional configuration files from /etc/dnsmasq.d
conf-dir=/etc/dnsmasq.d
EOF
# 注意DHCP 服务器功能由 isc-dhcp-server 提供dnsmasq 不再提供 DHCP。
# 确保 dnsmasq 不会干扰 DHCP
echo "dhcp-option=option:router,${GATEWAY_LAN_IP}" | sudo tee -a /etc/dnsmasq.conf > /dev/null
echo "dhcp-option=option:dns-server,${GATEWAY_LAN_IP}" | sudo tee -a /etc/dnsmasq.conf > /dev/null
sudo systemctl restart dnsmasq || log_error "重启 dnsmasq 服务失败。"
sudo systemctl enable dnsmasq || log_error "启用 dnsmasq 服务失败。"
log_info "dnsmasq 智能 DNS 转发已初步配置。"
# ==============================================================================
# 6. 安装和配置 gfwlist2new (保持不变)
# ==============================================================================
log_info "集成和配置 GFW 规则生成器 (gfw_rules_generator.py)..."
LOCAL_SCRIPT_NAME="gfw_rules_generator.py"
if [ ! -d "${GFWLIST2NEW_DIR}" ]; then
log_info "创建脚本目录..."
sudo mkdir -p "${GFWLIST2NEW_DIR}" || log_error "创建目录 ${GFWLIST2NEW_DIR} 失败。"
fi
cp $LOCAL_SCRIPT_NAME ${GFWLIST2NEW_DIR}
# 确保安装 requests 依赖
log_info "安装 Python 依赖requests..."
sudo pip3 install requests || log_error "安装 requests 依赖失败。"
# 写入新的 Python 脚本(假设您已将上面的内容保存到临时文件并复制到这里)
# 推荐您手动将上面的 Python 代码保存到 ${GFWLIST2NEW_DIR}/${LOCAL_SCRIPT_NAME}
# 如果要用脚本自动写入,代码会非常长,这里跳过写入步骤,假设文件已存在。
log_info "请确保 gfw_rules_generator.py 文件已存在于 ${GFWLIST2NEW_DIR}/"
cd "${GFWLIST2NEW_DIR}"
# 定义 SOCKS5 代理地址
SOCKS5_SERVER_ADDR="127.0.0.1:${LOCAL_SOCKS5_PORT}"
log_info "执行 GFW 规则生成脚本..."
# 使用 -p, -f, -d 参数执行新脚本
sudo python3 "${LOCAL_SCRIPT_NAME}" -p "${SOCKS5_SERVER_ADDR}" -f "{{ foreign_dns1 }} {{foreign_dns2 }}" -d "{{ domestic_dns1 }} {{ domestic_dns2 }}" || log_error "规则生成脚本运行失败。"
sudo systemctl restart dnsmasq || log_error "重启 dnsmasq (gfwlist) 失败。"
log_info "设置 GFW 规则定时更新任务 (每天凌晨 3:00)..."
# 设置定时任务
(sudo crontab -l 2>/dev/null; echo "0 3 * * * cd ${GFWLIST2NEW_DIR} && sudo python3 ${LOCAL_SCRIPT_NAME} -p ${SOCKS5_SERVER_ADDR} -f "{{ foreign_dns1 }} {{ foreign_dns2 }}" -d "{{ domestic_dns1 }} {{domestic_dns1}}" && sudo systemctl restart dnsmasq") | sudo crontab -
log_info "规则生成器配置完成并设置定时更新。"
cd - > /dev/null
# ==============================================================================
# 7. 配置 IPTABLES 规则实现透明代理和 NAT (保持不变)
# ==============================================================================
log_info "配置 IPTABLES 规则 (NAT 和透明代理)..."
# 清除现有规则,避免冲突
sudo iptables -F
sudo iptables -X
sudo iptables -t nat -F
sudo iptables -t nat -X
sudo iptables -t mangle -F
sudo iptables -t mangle -X
# 1. 开启 NAT (使内网访问外网)
sudo iptables -t nat -A POSTROUTING -o {{ wan_interface }} -j MASQUERADE
log_info "已配置 NAT 规则。"
# 2. IP 转发规则 (允许内网到外网,并允许已建立连接回传)
sudo iptables -A FORWARD -i {{ lan_interface }} -o {{ wan_interface }} -j ACCEPT
sudo iptables -A FORWARD -o {{ lan_interface }} -i {{ wan_interface }} -m state --state RELATED,ESTABLISHED -j ACCEPT
log_info "已配置 IP 转发规则。"
# 3. 透明代理规则 (使用 redsocks 和 ipset)
# 重定向到 redsocks 的流量,不处理来自 redsocks 本身的流量
sudo iptables -t nat -A PREROUTING -i {{ lan_interface }} -p tcp -s {{ gateway_lan_cidr }} -m set --match-set gfwlist dst -j REDIRECT --to-ports ${REDSOCKS_PORT}
log_info "已配置透明代理重定向规则 (所有端口目标IP在 gfwlist 中的内网TCP流量到 redsocks)。"
# 排除 redsocks 自身流量循环
# 这一步非常重要,避免 redsocks 自己产生流量又被 iptables 捕获
sudo iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport ${REDSOCKS_PORT} -j RETURN
sudo iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport ${LOCAL_SOCKS5_PORT} -j RETURN
log_info "已配置排除 redsocks 自身流量循环的规则。"
# 保存 iptables 规则
sudo netfilter-persistent save || log_error "保存 iptables 规则失败。"
sudo systemctl enable netfilter-persistent || log_error "启用 netfilter-persistent 服务失败。"
log_info "IPTABLES 规则已配置并保存。"
log_info "----------------------------------------------------------------------------------"
log_info "网关主机配置完成!"
log_info "请检查 redsocks 和 ssh -D 进程是否正常运行。"
log_info "请注意SSH SOCKS5 代理可能需要手动输入密码或配置免密登录才能持久运行。"
log_info "内网主机现在应该可以自动通过 DHCP 获取 IP 并访问网络。"
log_info "----------------------------------------------------------------------------------"