388 lines
16 KiB
Django/Jinja
388 lines
16 KiB
Django/Jinja
#!/bin/bash
|
||
set -eo pipefail
|
||
|
||
# ==============================================================================
|
||
# 网关主机配置变量 - 请根据你的实际环境修改!
|
||
# ==============================================================================
|
||
# 网关主机内网IP (用于其他内网主机连接)
|
||
curuser=$(id -un)
|
||
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_NAME="{{ remote_ssh_name }}" # 远程服务器的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.
|
||
{% set net_base = gateway_lan_ip.split('.') | slice(3) | join('.') %}
|
||
subnet {{ net_base }}.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 {{ net_base }}.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_NAME} -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 和透明代理)..."
|
||
|
||
# 变量定义检查(确保这些变量在脚本前面已正确定义)
|
||
# REMOTE_SSH_IP: 远程SOCKS5服务器的公网IP
|
||
# WAN_INTERFACE: 外网网卡名,如 eth0
|
||
# LAN_INTERFACE: 内网网卡名,如 enx...
|
||
|
||
# 清除现有规则,避免冲突
|
||
log_info "清除现有 IPTABLES 规则..."
|
||
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. 透明代理规则 (核心的 PREROUTING 链)
|
||
log_info "配置透明代理 PREROUTING 排除和重定向规则..."
|
||
|
||
# --- 排除规则(必须在重定向规则之前) ---
|
||
|
||
# 3.1 排除所有重定向到本地的流量(已经通过 OUTPUT 排除,这里可以再加一层保险)
|
||
sudo iptables -t nat -A PREROUTING -d 127.0.0.0/8 -j RETURN || log_error "排除本地回环失败。"
|
||
|
||
# 3.2 排除局域网内流量 (不代理内网互访)
|
||
sudo iptables -t nat -A PREROUTING -i {{ lan_interface }} -d {{ gateway_lan_cidr }} -j RETURN || log_error "排除内网流量失败。"
|
||
|
||
# 3.3 【❗ 补充:排除远程 SSH 服务器 IP ❗】
|
||
# 避免 SSH 连接本身被重定向,防止无限循环。
|
||
# 假设变量 REMOTE_SSH_IP 已经正确替换。
|
||
sudo iptables -t nat -A PREROUTING -d {{ remote_ssh_ip }} -j RETURN || log_error "排除远程 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 核心重定向规则:
|
||
# 只有流量目标 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}
|
||
log_info "已配置透明代理重定向规则 (目标IP在 gfwlist 中的内网TCP流量到 redsocks)。"
|
||
|
||
|
||
# 4. 排除 redsocks 自身流量循环 (OUTPUT 链)
|
||
# 这一步非常重要,避免 redsocks/ssh 客户端自己产生流量又被 iptables 捕获
|
||
# 排除目标地址是 127.0.0.1 的流量,它们是 SSH 和 Redsocks 的内部通信。
|
||
sudo iptables -t nat -A OUTPUT -d 127.0.0.1 -p tcp -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 规则已配置并保存。"
|
||
|