This commit is contained in:
yumoqing 2025-11-30 23:31:29 +08:00
parent 9c99d67db3
commit f2456fe033
3 changed files with 152 additions and 134 deletions

View File

@ -74,6 +74,14 @@ install_package() {
# 0. 前置检查与环境初始化 # 0. 前置检查与环境初始化
# ============================================================================== # ==============================================================================
# check_root # check_root
# 释放53端口
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
sudo rm /etc/resolv.conf
# 创建新的 resolv.conf 文件,将本机地址作为唯一的 DNS 服务器
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf > /dev/null
log_info "开始网关主机配置脚本..." log_info "开始网关主机配置脚本..."
log_info "更新系统软件包列表..." log_info "更新系统软件包列表..."
@ -151,7 +159,6 @@ max-lease-time ${DHCP_LEASE_TIME};
authoritative; authoritative;
# A slightly different configuration for an internal subnet. # A slightly different configuration for an internal subnet.
{% set net_base = gateway_lan_ip.split('.') | slice(3) | join('.') %}
subnet {{ net_base }}.0 netmask 255.255.255.0 { subnet {{ net_base }}.0 netmask 255.255.255.0 {
range ${DHCP_START_IP} ${DHCP_END_IP}; range ${DHCP_START_IP} ${DHCP_END_IP};
option routers ${GATEWAY_LAN_IP}; option routers ${GATEWAY_LAN_IP};
@ -211,18 +218,20 @@ fi
log_info "SSH SOCKS5 代理已通过 Systemd 启动,并在 127.0.0.1:${LOCAL_SOCKS5_PORT} 监听,支持自动重连。" log_info "SSH SOCKS5 代理已通过 Systemd 启动,并在 127.0.0.1:${LOCAL_SOCKS5_PORT} 监听,支持自动重连。"
# ============================================================================== # ==============================================================================
# 4. 配置 redsocks (透明 SOCKS5 代理) (保持不变) # 4. 配置 redsocks (透明 SOCKS5 代理) (请替换为以下修正代码!)
# ============================================================================== # ==============================================================================
log_info "配置 redsocks 透明代理..." log_info "配置 redsocks 透明代理..."
# 备份现有配置 # 备份现有配置
sudo cp /etc/redsocks.conf /etc/redsocks.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 redsocks.conf 失败。" sudo cp /etc/redsocks.conf /etc/redsocks.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 redsocks.conf 失败。"
# ----------------------------------------------------------------------------------
# ❗❗ 关键修正:移除所有注释和分号,以避免 redsocks 配置文件解析错误 ❗❗
cat <<EOF | sudo tee /etc/redsocks.conf > /dev/null cat <<EOF | sudo tee /etc/redsocks.conf > /dev/null
base { base {
log_debug = off; log_debug = off;
log_info = on; log_info = on;
log = "syslog:daemon"; log = "syslog:daemon";
daemon = on; # 后台运行 daemon = on;
redirector = iptables; redirector = iptables;
} }
@ -230,11 +239,12 @@ redsocks {
local_ip = 127.0.0.1; local_ip = 127.0.0.1;
local_port = ${REDSOCKS_PORT}; local_port = ${REDSOCKS_PORT};
ip = 127.0.0.1; # SSH SOCKS5 代理的地址 ip = 127.0.0.1;
port = ${LOCAL_SOCKS5_PORT}; # SSH SOCKS5 代理的端口 port = ${LOCAL_SOCKS5_PORT};
type = socks5; # SOCKS5 代理 type = socks5;
} }
EOF EOF
# ----------------------------------------------------------------------------------
sudo systemctl restart redsocks || log_error "重启 redsocks 服务失败。" sudo systemctl restart redsocks || log_error "重启 redsocks 服务失败。"
sudo systemctl enable redsocks || log_error "启用 redsocks 服务失败。" sudo systemctl enable redsocks || log_error "启用 redsocks 服务失败。"
@ -263,6 +273,7 @@ server={{ domestic_dns2 }}
# 国外域名通过 gfwlist2new 生成的配置文件转发到代理 # 国外域名通过 gfwlist2new 生成的配置文件转发到代理
# dnsmasq will read additional configuration files from /etc/dnsmasq.d # dnsmasq will read additional configuration files from /etc/dnsmasq.d
conf-dir=/etc/dnsmasq.d conf-dir=/etc/dnsmasq.d
user=root
EOF EOF
# 注意DHCP 服务器功能由 isc-dhcp-server 提供dnsmasq 不再提供 DHCP。 # 注意DHCP 服务器功能由 isc-dhcp-server 提供dnsmasq 不再提供 DHCP。
@ -275,7 +286,7 @@ sudo systemctl enable dnsmasq || log_error "启用 dnsmasq 服务失败。"
log_info "dnsmasq 智能 DNS 转发已初步配置。" log_info "dnsmasq 智能 DNS 转发已初步配置。"
# ============================================================================== # ==============================================================================
# 6. 安装和配置 gfwlist2new (保持不变) # 6. 安装和配置 gfwlist2new (已修正 crontab 参数和 PySocks 依赖)
# ============================================================================== # ==============================================================================
log_info "集成和配置 GFW 规则生成器 (gfw_rules_generator.py)..." log_info "集成和配置 GFW 规则生成器 (gfw_rules_generator.py)..."
LOCAL_SCRIPT_NAME="gfw_rules_generator.py" LOCAL_SCRIPT_NAME="gfw_rules_generator.py"
@ -284,15 +295,12 @@ if [ ! -d "${GFWLIST2NEW_DIR}" ]; then
log_info "创建脚本目录..." log_info "创建脚本目录..."
sudo mkdir -p "${GFWLIST2NEW_DIR}" || log_error "创建目录 ${GFWLIST2NEW_DIR} 失败。" sudo mkdir -p "${GFWLIST2NEW_DIR}" || log_error "创建目录 ${GFWLIST2NEW_DIR} 失败。"
fi fi
cp $LOCAL_SCRIPT_NAME ${GFWLIST2NEW_DIR} sudo cp $LOCAL_SCRIPT_NAME ${GFWLIST2NEW_DIR}
# 确保安装 requests 依赖 # 确保安装 requests 和 PySocks 依赖
log_info "安装 Python 依赖requests..." log_info "安装 Python 依赖requests 和 PySocks..."
sudo pip3 install requests || log_error "安装 requests 依赖失败。" sudo pip3 install requests PySocks || log_error "安装 requests/PySocks 依赖失败。"
# 写入新的 Python 脚本(假设您已将上面的内容保存到临时文件并复制到这里)
# 推荐您手动将上面的 Python 代码保存到 ${GFWLIST2NEW_DIR}/${LOCAL_SCRIPT_NAME}
# 如果要用脚本自动写入,代码会非常长,这里跳过写入步骤,假设文件已存在。
log_info "请确保 gfw_rules_generator.py 文件已存在于 ${GFWLIST2NEW_DIR}/" log_info "请确保 gfw_rules_generator.py 文件已存在于 ${GFWLIST2NEW_DIR}/"
cd "${GFWLIST2NEW_DIR}" cd "${GFWLIST2NEW_DIR}"
@ -301,14 +309,18 @@ cd "${GFWLIST2NEW_DIR}"
SOCKS5_SERVER_ADDR="127.0.0.1:${LOCAL_SOCKS5_PORT}" SOCKS5_SERVER_ADDR="127.0.0.1:${LOCAL_SOCKS5_PORT}"
log_info "执行 GFW 规则生成脚本..." 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 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) 失败。" sudo systemctl restart dnsmasq || log_error "重启 dnsmasq (gfwlist) 失败。"
log_info "设置 GFW 规则定时更新任务 (每天凌晨 3:00)..." log_info "设置 GFW 规则定时更新任务 (每天凌晨 3:00)..."
# 设置定时任务 # 设置定时任务(已修正国内 DNS 变量)
(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 - (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_dns2 }} && sudo systemctl restart dnsmasq") | sudo crontab -
log_info "规则生成器配置完成并设置定时更新。" log_info "规则生成器配置完成并设置定时更新。"
cd - > /dev/null cd - > /dev/null
@ -351,35 +363,32 @@ sudo iptables -t nat -A PREROUTING -d 127.0.0.0/8 -j RETURN || log_error "排除
# 3.2 排除局域网内流量 (不代理内网互访) # 3.2 排除局域网内流量 (不代理内网互访)
sudo iptables -t nat -A PREROUTING -i {{ lan_interface }} -d {{ gateway_lan_cidr }} -j RETURN || log_error "排除内网流量失败。" sudo iptables -t nat -A PREROUTING -i {{ lan_interface }} -d {{ gateway_lan_cidr }} -j RETURN || log_error "排除内网流量失败。"
# 3.3 【❗ 补充:排除远程 SSH 服务器 IP ❗】 # 3.3 排除远程 SSH 服务器 IP (防止 SSH 连接本身被重定向)
# 避免 SSH 连接本身被重定向,防止无限循环。
# 假设变量 REMOTE_SSH_IP 已经正确替换。
sudo iptables -t nat -A PREROUTING -d {{ remote_ssh_ip }} -j RETURN || log_error "排除远程 SSH IP 失败。" sudo iptables -t nat -A PREROUTING -d {{ remote_ssh_ip }} -j RETURN || log_error "排除远程 SSH IP 失败。"
log_info "已添加规则:排除远程 SSH 服务器 {{ remote_ssh_ip }}。" log_info "已添加规则:排除远程 SSH 服务器 {{ remote_ssh_ip }}。"
# 3.4 【❗ 补充:排除国内 IP ❗】
# 排除目标 IP 在 china_ip 集合中的流量(国内流量直连)
# 假设 china_ip 集合通过其他脚本/步骤创建
# 注意:您的 gfwlist2new/gfw_rules_generator 脚本只处理 gfwlist这里不需要 china_ip 的 ipset 排除
# 而是依赖 gfwlist ipset 的精准捕获。我们移除这个容易出错的步骤,只依赖 gfwlist。
# 如果需要排除国内 IP 段,需要有外部脚本维护 china_ip 集合。
# --- 重定向规则 --- # --- 重定向规则 ---
# 3.5 核心重定向规则: # 3.4 核心重定向规则:
# 只有流量目标 IP 在 gfwlist ipset 集合中,才重定向到 redsocks。 # 只有流量目标 IP 在 gfwlist ipset 集合中,才重定向到 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} 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)。" log_info "已配置透明代理重定向规则 (目标IP在 gfwlist 中的内网TCP流量到 redsocks)。"
# ❗❗ 关键修正:必须排除远程 SSH 服务器的 IP ❗❗
# 确保 SSH 隧道本身可以直连建立,不被代理。
sudo iptables -t nat -A OUTPUT -d {{ remote_ssh_ip }} -p tcp -j RETURN
log_info "已配置排除远程 SSH 服务器 {{ remote_ssh_ip }} 的规则。"
# 4. 排除 redsocks 自身流量循环 (OUTPUT 链) # 4. 排除 redsocks 自身流量循环 (OUTPUT 链)
# 这一步非常重要,避免 redsocks/ssh 客户端自己产生流量又被 iptables 捕获
# 排除目标地址是 127.0.0.1 的流量,它们是 SSH 和 Redsocks 的内部通信。 # 排除目标地址是 127.0.0.1 的流量,它们是 SSH 和 Redsocks 的内部通信。
sudo iptables -t nat -A OUTPUT -d 127.0.0.1 -p tcp -j RETURN sudo iptables -t nat -A OUTPUT -d 127.0.0.1 -p tcp -j RETURN
log_info "已配置排除 redsocks 自身流量循环的规则。" log_info "已配置排除 redsocks 自身流量循环的规则。"
# 核心 OUTPUT 重定向规则捕获所有目标IP在 gfwlist ipset 集合中的网关主机自身TCP流量重定向到 redsocks。
sudo iptables -t nat -A OUTPUT -p tcp -m set --match-set gfwlist dst -j REDIRECT --to-ports ${REDSOCKS_PORT}
# 保存 iptables 规则 # 保存 iptables 规则
sudo netfilter-persistent save || log_error "保存 iptables 规则失败。" sudo netfilter-persistent save || log_error "保存 iptables 规则失败。"
sudo systemctl enable netfilter-persistent || log_error "启用 netfilter-persistent 服务失败。" sudo systemctl enable netfilter-persistent || log_error "启用 netfilter-persistent 服务失败。"

View File

@ -50,18 +50,26 @@ def generate_rules(proxy_server, foreign_dns_list, domestic_dns_list, ipset_name
if not line or line.startswith(('#', '!')): if not line or line.startswith(('#', '!')):
continue continue
# 简单提取域名 # 1. 清理前缀
if line.startswith('||'): if line.startswith('||'):
domain = line[2:] domain = line[2:]
elif line.startswith('.'): elif line.startswith('.'):
domain = line[1:] domain = line[1:]
elif '/' in line:
continue
else: else:
domain = line domain = line
# 过滤掉 IP 地址,只保留域名 # 2. 移除 URL 路径和查询参数
if '/' in domain:
domain = domain.split('/')[0]
# 3. 过滤掉 IP 地址和通配符,只保留域名
if domain and '.' in domain and not domain.startswith('*.'): if domain and '.' in domain and not domain.startswith('*.'):
# dnsmasq只接受不带前导点的域名例如: example.com
if domain.startswith('.'):
domain = domain[1:]
# 确保域名不包含非法字符
if not any(c in domain for c in ('&', '?', '=', ':', '@', '%')):
domains.add(domain) domains.add(domain)
# 2. 生成 DNSMasq 配置文件 # 2. 生成 DNSMasq 配置文件
@ -70,7 +78,7 @@ def generate_rules(proxy_server, foreign_dns_list, domestic_dns_list, ipset_name
# 代理的上游 DNS (只使用提供的第一个国外 DNS) # 代理的上游 DNS (只使用提供的第一个国外 DNS)
primary_foreign_dns = foreign_dns_list[0] primary_foreign_dns = foreign_dns_list[0]
proxy_port = proxy_server.split(':')[1] proxy_port = proxy_server.split(':')[1]
proxy_dns_server = f"{primary_foreign_dns}#{proxy_port}" proxy_dns_server = f"{primary_foreign_dns}#53"
try: try:
with open(dnsmasq_conf_path, 'w') as f: with open(dnsmasq_conf_path, 'w') as f:

View File

@ -12,6 +12,7 @@ config_vars = {
# 网关主机独有变量 # 网关主机独有变量
"dhcp_start_ip": "192.168.2.100", "dhcp_start_ip": "192.168.2.100",
"dhcp_end_ip": "192.168.2.200", "dhcp_end_ip": "192.168.2.200",
"net_base": "192.168.2",
"dhcp_lease_time": "7200", "dhcp_lease_time": "7200",
"remote_ssh_user": "kww", "remote_ssh_user": "kww",
"remote_ssh_ip": "8.222.165.87", # !!! 替换为你的远程SSH服务器IP "remote_ssh_ip": "8.222.165.87", # !!! 替换为你的远程SSH服务器IP