softroute/README.md
2025-11-28 23:23:00 +08:00

644 lines
29 KiB
Markdown
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.

# softroute
## 物理机软路由环境
### 实现的能力:
完整软路由功能: 将一台物理机完全转变为家庭或小型办公室网络的路由器。
内外网隔离: 通过物理双网卡区分内外网,隔离内网与公网。
NAT (网络地址转换) 内网主机共享网关的公网 IP 访问外部网络。
IP 转发: 允许数据包在内外网接口之间路由。
DHCP 服务器: 自动为内网主机分配 IP 地址、网关和 DNS实现即插即用内网主机无需手动配置。
智能 DNS 转发 (Dnsmasq + GFWList) 根据域名类型(国内/国外)进行分流解析,国内域名直连,国外域名通过代理解析。
透明 SOCKS5 代理 (Redsocks2 + IPTables + IPSet) 自动识别并重定向所有端口的国外流量到 SOCKS5 代理,实现“国内直连,国外走代理”的无感访问。
SOCKS5 代理客户端 (SSH -D) 通过 SSH 连接到远程服务器,建立一个本地 SOCKS5 代理。
防火墙 (IPTables) 完全取代 UFW通过精细的 iptables 规则实现网络过滤和流量控制。
规则持久化: 配置在重启后依然生效。
### 主要操作:
硬件准备: 一台至少双网卡的物理机作为网关主机。
网卡连接:
WAN_INTERFACE 连接到外网 (光猫/上一级路由器)。
LAN_INTERFACE 连接到内网交换机,内网主机连接到此交换机。
网关主机运行脚本:
修改 render_configs.py 中的 WAN_INTERFACE, LAN_INTERFACE, gateway_lan_ip, dhcp_start_ip, dhcp_end_ip 以及 REMOTE_SSH_USER, REMOTE_SSH_IP 等定制化参数。
运行 python3 render_configs.py 生成 gateway_config.sh。
在网关主机上执行 sudo ./gateway_config.sh。
内网主机操作:
无需脚本。 确保内网主机的网卡配置为 DHCP 客户端模式 (Ubuntu 默认),并连接到内网交换机。它们将自动获取 IP、网关和 DNS (指向网关主机的内网 IP)。
测试验证: 在内网主机上检查 IP、网关、DNS 是否正确,并测试内外网访问。
## 云服务器软路由环境
### 实现的能力:
云环境下的软路由功能: 在云主机上实现路由和代理功能。
单网卡路由 (或多网卡私有网关) 通常在单块网卡上同时处理公网和内网流量,或者通过私有网络接口充当内网网关。
NAT (网络地址转换) 内网云主机通过网关云主机的公网 IP 访问外部网络。
IP 转发: 允许数据包在云主机的不同网络之间(或通过同一接口)路由。
不提供 DHCP 服务器 (依赖云平台) 避免与云平台自带的 DHCP 冲突,内网云主机从云平台获取 IP 和默认网关。
智能 DNS 转发 (Dnsmasq + GFWList) 同物理机环境,根据域名类型分流解析,监听网关云主机的内网 IP。
透明 SOCKS5 代理 (Redsocks2 + IPTables + IPSet) 同物理机环境,自动识别并重定向所有端口的国外流量到 SOCKS5 代理。
SOCKS5 代理客户端 (SSH -D) 同物理机环境。
防火墙 (IPTables) 完全取代 UFW通过精细的 iptables 规则进行流量控制和透明代理。
规则持久化: 配置在重启后依然生效。
### 主要操作:
云主机准备:
一台带有公网 IP 的云主机作为网关云主机。
若干只有内网 IP 的云主机作为内网云主机,它们都位于同一个云平台私有网络 (VPC/VNet) 中,确保可以与网关云主机内网互通。
网卡配置:
网关云主机的主网卡 (gateway_main_interface) 保持云平台默认的 DHCP 模式。
内网云主机的主网卡 (client_main_interface) 也保持云平台默认的 DHCP 模式。
网关云主机运行脚本:
修改 render_configs.py 中的 gateway_main_interface, internal_network_range (云平台私有网络 IP 范围) 以及 REMOTE_SSH_USER, REMOTE_SSH_IP 等定制化参数。
运行 python3 render_configs.py 生成 gateway_config.sh。
在网关云主机上执行 sudo ./gateway_config.sh。
内网云主机操作 (手动 DNS 配置)
无需脚本。 关键是将内网云主机的 DNS 服务器设置为网关云主机的内网 IP。
这可以通过云平台控制台(如果支持)或在内网云主机上手动修改 Netplan 配置文件来实现。
测试验证: 在内网云主机上检查 IP、网关是否正确由云平台 DHCP 提供DNS 是否指向网关云主机,并测试内外网访问。
云平台安全组/防火墙配置: 确保安全组或防火墙规则允许内网主机到网关主机的流量,以及网关主机到境外代理服务器的 SSH 流量。
## 核心差异总结:
特性 物理机软路由环境 云服务器软路由环境
网卡数量/类型 至少双网卡 (一外网,一内网) 通常是单网卡(同时承载内外网 IP
DHCP 服务器 网关主机提供 DHCP 服务 云平台提供 DHCP 服务,网关主机不运行 DHCP
内网主机 IP 从网关主机 DHCP 获取 从云平台 DHCP 获取
内网主机 DNS 从网关主机 DHCP 获取 (指向网关内网 IP) 需手动/云平台配置为网关云主机的内网 IP
IP 地址规划 完全自定义 (192.168.10.x) 依赖云平台的私有网络 IP 范围 (10.0.0.x 等)
物理隔离 有 (物理网线区分内外网) 无 (单网卡逻辑区分) 或通过云平台虚拟网络功能实现隔离
外部防火墙 iptables 完全控制 iptables + 云平台安全组/防火墙 共同控制
两种方案都实现了你所需的强大智能分流代理功能,但在部署细节和网络环境适配上有所不同。选择哪种取决于你的实际基础设施。
如果我是云服务器一个配置了外网IP其他主机只有内网ip上述脚本要怎么修改
## 云主机技术说明
这是一个非常常见的云服务器场景。在这种情况下,你需要对脚本做一些关键的调整,因为云环境的网络接口和 IP 分配方式与物理机有所不同。
核心区别:
网卡名称: 云服务器的网卡名称通常是 ensX 或 ethX但更常见的是 ensX需要通过 ip a 确认。
“内网网卡”的含义: 在云环境中,通常一个实例可能只有一块网卡 (ensX)。这块网卡上可能同时绑定了公网 IP 和内网 IP。或者如果你创建了多块网卡其中一块是私有网络接口另一块是公有网络接口。
内网互通: 云平台通常会提供一个私有网络 (VPC/VNet) 功能,所有相同私有网络中的云主机可以通过它们的内网 IP 相互访问,即使它们在不同的子网或区域,只要私有网络配置允许。
IP 地址规划: 云平台会为你的内网 IP 地址范围。
假设的云环境拓扑:
网关云主机 (Gateway Cloud Server):
主网卡 (e.g., ens5): 绑定了 公网 IP 和 内网 IP (例如 10.0.0.10)。
我们仍将其 ens5 视为**“外网网卡”** (因为公网 IP 在其上)。
同时,该网卡也是**“内网网卡”** (因为内网 IP 在其上,其他内网主机通过此 IP 访问)。
这将是一个 “单臂路由” 或 “单网卡路由” 的配置,所有流量都通过这一个接口进出。
内网云主机 (Internal Cloud Server):
主网卡 (e.g., ens5): 绑定了 内网 IP (例如 10.0.0.11, 10.0.0.12 等)。
默认网关通常由云平台在 DHCP 中提供,指向其私有网络的网关。
挑战:
单网卡作为内外网接口: iptables 规则需要更仔细地定义,区分进入网卡的内网流量和从网卡出去的公网流量。
云平台 DHCP 的冲突: 云平台通常自带 DHCP 服务,如果你在网关主机上搭建 DHCP 服务器,可能会和云平台冲突。更推荐的做法是:内网主机继续使用云平台提供的 DHCP 获取 IP但将其 DNS 指向网关主机。默认网关仍然是云平台提供的。然后,网关主机使用 iptables 拦截和重定向所有出站流量到代理。
修正后的核心思路 (云服务器环境)
网关主机:
Netplan 保持其主网卡 (ensX) 使用 DHCP 获取 IP包括公网和内网 IP或者配置静态内网 IP (但要确保不和云平台 DHCP 冲突)。通常,保持 DHCP 模式,然后由脚本获取网卡名和内网 IP。
IP 转发: 保持开启。
SSH SOCKS5 代理: 保持不变。
Redsocks2 透明代理: 保持不变。
Dnsmasq 智能 DNS 转发: 保持不变,监听其内网 IP。
ISC DHCP Server 不再需要在网关主机上运行 DHCP 服务器! 因为云平台已经提供了。
IPTables 这是最关键的改动。不再有明确的 WAN_INTERFACE 和 LAN_INTERFACE 区别。所有流量都通过一个接口。PREROUTING 规则需要捕获来自所有内网 IP 段的流量。POSTROUTING 仍然将流量伪装成网关主机的公网 IP (或其主内网 IP 如果流量不出公网)。
内网主机:
Netplan 保持 DHCP 客户端模式(默认),让它们从云平台获取 IP 和默认网关。
DNS 这是唯一需要手动或通过云平台配置的地方。 将内网主机的 DNS 服务器手动或通过云平台提供的机制,设置为 网关云主机的内网 IP。
客制化参数 (Jinja2 变量) 调整
新/修改的变量:
gateway_main_interface: 网关云主机的主网卡名称 (e.g., ens5)
client_main_interface: 内网云主机的主网卡名称 (e.g., ens5)
internal_network_range: 你的云平台提供的内部网络 IP 范围 (e.g., 10.0.0.0/16)
移除的变量:
wan_interface
lan_interface
dhcp_start_ip, dhcp_end_ip, dhcp_lease_time (因为不再运行 DHCP 服务器)
gateway_config.sh.j2 模板 (云服务器版)
代码段
```
#!/bin/bash
set -eo pipefail
# ==============================================================================
# 网关主机配置变量 - 请根据你的实际环境修改!
# ==============================================================================
# 网关主机的主网卡名称 (例如 eth0, ens5 等)
GATEWAY_MAIN_INTERFACE="{{ gateway_main_interface }}"
# 网关主机的内网IP (脚本会自动获取用于监听和DNS)
# 我们假设该网卡上有一个内网IP例如 10.0.0.10
GATEWAY_LAN_IP=""
GATEWAY_PUBLIC_IP="" # 网关主机的公网IP脚本会尝试获取
GATEWAY_LAN_CIDR="{{ internal_network_range }}" # 你的云平台内部网络的IP范围例如 10.0.0.0/16
# 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)
# 透明代理工具 redsocks2 监听端口
REDSOCKS_PORT="{{ redsocks_port }}" # redsocks2 在本机监听的端口
# DNSMASQ 配置
DNSMASQ_LISTEN_IP="" # 脚本会自动获取 GATEWAY_LAN_IP
DOMESTIC_DNS="{{ domestic_dns }}" # 国内DNS服务器
FOREIGN_DNS="{{ foreign_dns }}" # 国外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, redsocks2, git, python3-pip..."
install_package net-tools
install_package iptables-persistent
install_package ipset
install_package dnsmasq
install_package redsocks2
install_package git
install_package python3-pip
# install_package isc-dhcp-server # 云服务器环境不需要运行 DHCP 服务器
# 动态获取网关主机的内网IP和公网IP
log_info "获取网关主机的 IP 地址..."
GATEWAY_LAN_IP=$(ip -4 addr show dev ${GATEWAY_MAIN_INTERFACE} | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
if [ -z "${GATEWAY_LAN_IP}" ]; then
log_error "无法获取网卡 ${GATEWAY_MAIN_INTERFACE} 的内网 IP 地址。请检查网卡名称或网络配置。"
fi
log_info "网关主机的内网 IP: ${GATEWAY_LAN_IP}"
# 尝试获取公网IP (可能需要专门的服务或配置这里假设通常第一个IP是公网或路由器的出口IP)
# 更准确的获取公网IP方式是 curl ifconfig.me 但这取决于网络能否访问外网
# 这里我们直接使用网卡IP进行MASQUERADE或如果云平台有专门的公网IP需要替换
GATEWAY_PUBLIC_IP=$(curl -s ifconfig.me) # 尝试通过外部服务获取公网IP如果无法访问则MASQUERADE会使用网卡主IP
if [ -z "${GATEWAY_PUBLIC_IP}" ]; then
log_warn "无法通过外部服务获取公网 IP。MASQUERADE 将使用网卡主 IP。"
# 另一种方式是获取该网卡上的任何一个非10. 172.16-31. 192.168. 的IP
# GATEWAY_PUBLIC_IP=$(ip -4 addr show dev ${GATEWAY_MAIN_INTERFACE} | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -vE '^(10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.)' | head -1)
fi
log_info "网关主机的公网 IP (或出口 IP): ${GATEWAY_PUBLIC_IP:-Using main interface IP}"
DNSMASQ_LISTEN_IP="${GATEWAY_LAN_IP}"
# ==============================================================================
# 1. 配置网卡和 IP 转发
# ==============================================================================
log_info "确保网关主机主网卡 (${GATEWAY_MAIN_INTERFACE}) 为 DHCP 模式..."
# Netplan 配置 (通常云服务器默认就是 DHCP)
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:
{{ gateway_main_interface }}:
dhcp4: true # 云服务器通常使用DHCP获取IP
optional: true
EOF
sudo netplan try
sudo netplan apply || log_error "应用 Netplan 配置失败,请检查网卡名称。"
log_info "网卡 ${GATEWAY_MAIN_INTERFACE} 已配置为 DHCP 模式。"
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. SSH SOCKS5 代理 (使用 Systemd 持久化)
# ==============================================================================
log_info "配置 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]
Type=simple
# 注意:这里需要确保用户 {{ remote_ssh_user }} 是一个实际存在的用户,并且可以访问其 $HOME/.ssh
# 为了简化我们暂时用root运行但更推荐使用非root用户
User=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} 监听,支持自动重连。"
# ==============================================================================
# 3. Redsocks2 透明代理 (保持不变)
# ==============================================================================
log_info "配置 redsocks2 透明代理..."
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;
port = ${LOCAL_SOCKS5_PORT};
type = socks5;
}
EOF
sudo systemctl restart redsocks2 || log_error "重启 redsocks2 服务失败。"
sudo systemctl enable redsocks2 || log_error "启用 redsocks2 服务失败。"
log_info "redsocks2 透明代理已配置并启动,监听 127.0.0.1:${REDSOCKS_PORT}。"
# ==============================================================================
# 4. Dnsmasq 智能 DNS 转发 (保持不变监听内网IP)
# ==============================================================================
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
listen-address=${DNSMASQ_LISTEN_IP},127.0.0.1
no-resolv
no-poll
server={{ domestic_dns }}
conf-dir=/etc/dnsmasq.d
EOF
# 确保 dnsmasq 不会干扰云平台的DHCP (不再是 isc-dhcp-server)
# 这些选项只是建议如果云平台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 转发已初步配置,监听 ${DNSMASQ_LISTEN_IP}。"
# ==============================================================================
# 5. 安装和配置 gfwlist2new (保持不变)
# ==============================================================================
log_info "安装和配置 gfwlist2new 工具..."
if [ ! -d "${GFWLIST2NEW_DIR}" ]; then
log_info "克隆 gfwlist2new 仓库..."
sudo git clone "{{ gfwlist2new_repo }}" "${GFWLIST2NEW_DIR}" || log_error "克隆 gfwlist2new 仓库失败。"
fi
cd "${GFWLIST2NEW_DIR}"
log_info "安装 gfwlist2new 依赖..."
sudo pip3 install -r requirements.txt || log_error "安装 gfwlist2new 依赖失败。"
log_info "配置 gfwlist2new 的配置文件 config.conf..."
sudo cp config.conf config.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 gfwlist2new config.conf 失败。"
cat <<EOF | sudo tee config.conf > /dev/null
[DEFAULT]
IPSET_NAME = gfwlist
IPSET_FILE = /etc/ipset/gfwlist.conf
DNSMASQ_CONF_PATH = /etc/dnsmasq.d/gfwlist_router.conf
DNSMASQ_LOG_PATH = /var/log/dnsmasq.log
DNS_PROXY_SERVER = 127.0.0.1#${REDSOCKS_PORT} # 这里的端口要指向 redsocks2
Proxy Config
SOCKS5_SERVER = 127.0.0.1:${LOCAL_SOCKS5_PORT} # 这里的端口是SSH SOCKS5代理
GITHUB_RAW_URL = raw.githubusercontent.com
EOF
log_info "执行 gfwlist2new 生成 ipset 和 dnsmasq 规则..."
sudo python3 gfwlist2new.py -s "${SOCKS5_SERVER}" -f "{{ foreign_dns }}" -d "{{ domestic_dns }}" || log_error "gfwlist2new 运行失败。"
sudo systemctl restart dnsmasq || log_error "重启 dnsmasq (gfwlist) 失败。"
log_info "设置 gfwlist2new 定时更新任务 (每天凌晨 3:00)..."
(sudo crontab -l 2>/dev/null; echo "0 3 * * * cd ${GFWLIST2NEW_DIR} && sudo python3 gfwlist2new.py -s ${SOCKS5_SERVER} -f {{ foreign_dns }} -d {{ domestic_dns }} && sudo systemctl restart dnsmasq") | sudo crontab -
log_info "gfwlist2new 配置完成并设置定时更新。"
cd - > /dev/null
# ==============================================================================
# 6. 配置 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 (使内网访问外网)
# MASQUERADE 应该基于出口接口,这里就是 GATEWAY_MAIN_INTERFACE
# --to-source 可以明确指定公网IP如果GATEWAY_PUBLIC_IP能获取到
if [ -n "${GATEWAY_PUBLIC_IP}" ]; then
sudo iptables -t nat -A POSTROUTING -o ${GATEWAY_MAIN_INTERFACE} -s ${GATEWAY_LAN_CIDR} -j SNAT --to-source ${GATEWAY_PUBLIC_IP}
log_info "已配置 NAT 规则出口IP为 ${GATEWAY_PUBLIC_IP}。"
else
sudo iptables -t nat -A POSTROUTING -o ${GATEWAY_MAIN_INTERFACE} -s ${GATEWAY_LAN_CIDR} -j MASQUERADE
log_info "已配置 NAT 规则,使用 ${GATEWAY_MAIN_INTERFACE} 主IP作为出口。"
fi
# 2. IP 转发规则 (允许所有来自内网段的流量通过 GATEWAY_MAIN_INTERFACE 转发)
# 这里更简化,所有来自内网段的流量都接受转发
sudo iptables -A FORWARD -s ${GATEWAY_LAN_CIDR} -o ${GATEWAY_MAIN_INTERFACE} -j ACCEPT
sudo iptables -A FORWARD -i ${GATEWAY_MAIN_INTERFACE} -d ${GATEWAY_LAN_CIDR} -m state --state RELATED,ESTABLISHED -j ACCEPT
log_info "已配置 IP 转发规则。"
# 3. 透明代理规则 (使用 redsocks2 和 ipset)
# 重定向所有来自内网段的 TCP 流量如果目标IP在 gfwlist 中,则到 redsocks2
sudo iptables -t nat -A PREROUTING -i ${GATEWAY_MAIN_INTERFACE} -p tcp -s ${GATEWAY_LAN_CIDR} -m set --match-set gfwlist dst -j REDIRECT --to-ports ${REDSOCKS_PORT}
log_info "已配置透明代理重定向规则 (所有端口目标IP在 gfwlist 中的内网TCP流量到 redsocks2)。"
# 4. 排除 redsocks2 自身流量循环 (保持不变)
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 "已配置排除 redsocks2 自身流量循环的规则。"
# 保存 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 "请检查 redsocks2 和 ssh -D 进程是否正常运行。"
log_info "请注意SSH SOCKS5 代理可能需要手动输入密码或配置免密登录才能持久运行。"
log_info "----------------------------------------------------------------------------------"
```
render_configs.py 脚本 (云服务器版)
Python
```
from jinja2 import Environment, FileSystemLoader
# 1. 定义你的客制化参数字典
config_vars = {
# 全局/网关主机变量
"gateway_main_interface": "ens5", # !!! 网关云主机的主网卡名称,请根据实际情况修改!
"internal_network_range": "10.0.0.0/16", # !!! 你的云平台私有网络IP范围例如 10.0.0.0/16, 172.16.0.0/12, 192.168.0.0/16
# SSH SOCKS5 代理配置
"remote_ssh_user": "your_remote_user", # !!! 替换为你的远程SSH服务器用户名
"remote_ssh_ip": "your_remote_server_ip", # !!! 替换为你的远程SSH服务器IP
"remote_ssh_port": "22",
# 其他默认值,通常无需修改
"local_socks5_port": "1080",
"redsocks_port": "12345",
"domestic_dns": "223.5.5.5,114.114.114.114",
"foreign_dns": "8.8.8.8,1.1.1.1",
"gfwlist2new_repo": "https://github.com/louisabrahams/gfwlist2new.git",
"gfwlist2new_dir": "/opt/gfwlist2new",
}
# 2. 设置 Jinja2 环境
env = Environment(loader=FileSystemLoader('.'))
# 3. 渲染 gateway_config.sh
gateway_template = env.get_template('gateway_config.sh.j2')
rendered_gateway_script = gateway_template.render(config_vars)
with open('gateway_config.sh', 'w') as f:
f.write(rendered_gateway_script)
print("Generated gateway_config.sh for Cloud Server Environment.")
# 4. 提供内网主机配置说明
print("\n--- 内网云主机配置说明 ---")
print("内网云主机无需运行任何脚本!它们会从云平台 DHCP 获取 IP 和默认网关。")
print("\n您唯一需要做的是")
print("1. 确保内网云主机的网卡 (例如 {{ config_vars['client_main_interface'] | default('ens5') }}) 是 DHCP 客户端模式 (云平台默认)。")
print("2. **最关键的步骤:将内网云主机的 DNS 服务器设置为网关云主机的内网 IP。**")
print(" - 这通常通过云平台的管理控制台进行配置,或者在内网云主机上手动修改 Netplan。")
print(" - 例如,如果网关云主机的内网 IP 是 10.0.0.10,则内网云主机的 DNS 应该设置为 10.0.0.10。")
print("\n 示例 Netplan 配置 (内网云主机,如果需要手动修改):")
print(f" network:")
print(f" version: 2")
print(f" renderer: networkd")
print(f" ethernets:")
print(f" {{ config_vars['client_main_interface'] | default('ens5') }}: # 替换为内网主机的实际网卡名称")
print(f" dhcp4: true")
print(f" nameservers:")
print(f" addresses: [{{ config_vars['gateway_lan_ip'] }}] # DNS 指向网关云主机的内网 IP")
print(f" optional: true")
print("\n 修改后,应用 Netplan 配置sudo netplan try && sudo netplan apply")
print(" 或者重启内网云主机。")
print("--------------------------")
print("\n!!! 请务必检查生成的 gateway_config.sh 文件,特别是 SSH 代理、网卡名称和云平台私有网络范围等配置。")
print("在执行前给它添加可执行权限chmod +x gateway_config.sh")
```
使用步骤 (云服务器环境)
保存模板和 Python 脚本:
将上面修改后的 gateway_config.sh.j2 模板保存好。
将修改后的 render_configs.py 脚本保存好。
修改 render_configs.py 中的变量:
gateway_main_interface 非常重要! 在网关云主机上运行 ip a 确认主网卡名称 (例如 ens5 或 eth0)。
internal_network_range 非常重要! 查阅你的云平台文档,了解你的私有网络的 IP 范围,例如 10.0.0.0/16。
remote_ssh_user, remote_ssh_ip, remote_ssh_port 你的境外代理服务器信息。
client_main_interface: 客户端网卡名称,主要用于说明文档。
运行 Python 渲染脚本:
```
python3 render_configs.py
```
这将生成 gateway_config.sh 文件。
在网关云主机上执行 gateway_config.sh
Bash
```
sudo chmod +x gateway_config.sh
sudo ./gateway_config.sh
```
执行过程中,脚本会尝试动态获取网关主机的内网 IP并可能会询问 SSH 密码。
配置内网云主机:
关键: 登录到每个内网云主机,将其 DNS 服务器设置为网关云主机的内网 IP (例如 10.0.0.10)。
如何配置 DNS
云平台控制台: 许多云平台允许你在实例的网络配置中指定自定义 DNS 服务器。这是最推荐的方式。
手动修改 Netplan 如果云平台不支持,或者你想验证,可以登录到内网主机,编辑 01-netcfg.yaml确保其 nameservers 部分指向网关主机的内网 IP。
然后应用 Netplan 或重启内网主机。
测试: 在内网云主机上测试网络连接。
重要提示:
SSH 免密登录: 在云环境中,强烈建议为 SSH SOCKS5 代理配置 SSH 密钥对进行免密登录,否则每次重启 SSH 代理或网关主机都可能需要手动输入密码。
云平台安全组/防火墙: 确保你的云平台安全组或防火墙允许以下流量:
网关云主机:
允许来自内网主机的流量到网关主机的内网 IP。
允许网关主机访问外部网络 (SSH 到远程代理服务器,以及正常的出站流量)。
允许内网主机访问网关主机的 53 端口 (DNS)。
内网云主机:
允许内网主机访问网关主机的内网 IP (默认网关和 DNS)。
允许内网主机访问其他内网主机。