#!/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) # 透明代理工具 redsocks2 监听端口 REDSOCKS_PORT="{{ redsocks_port }}" # redsocks2 在本机监听的端口 # DNSMASQ 配置 DNSMASQ_LISTEN_IP="${GATEWAY_LAN_IP}" # dnsmasq 监听的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, isc-dhcp-server..." 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 服务器安装 # ============================================================================== # 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 < /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 < /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 "启动 SSH SOCKS5 代理 (${REMOTE_SSH_USER}@${REMOTE_SSH_IP}:${REMOTE_SSH_PORT})..." # 检查 SSH 密钥是否存在,否则可能需要密码或生成密钥 if [ ! -f "$HOME/.ssh/id_rsa" ] && [ ! -f "$HOME/.ssh/id_dsa" ]; then log_warn "SSH 密钥文件不存在。SSH 连接可能需要输入密码或先生成密钥对。" log_warn "请确保可以无密码SSH登录到远程服务器,或手动输入密码完成连接。" fi # 确保旧的代理进程被杀死 sudo pkill -f "ssh -D ${LOCAL_SOCKS5_PORT}" || true # 启动 SSH SOCKS5 代理,后台运行 sudo ssh -D ${LOCAL_SOCKS5_PORT} -N -f -p ${REMOTE_SSH_PORT} ${REMOTE_SSH_USER}@${REMOTE_SSH_IP} -o ExitOnForwardFailure=yes if [ $? -ne 0 ]; then log_error "SSH SOCKS5 代理启动失败。请检查远程SSH服务器信息和连接。" fi log_info "SSH SOCKS5 代理已在 127.0.0.1:${LOCAL_SOCKS5_PORT} 启动。" # 验证代理是否在监听 (需要一点时间启动) sleep 2 if ! ss -tnlp | grep ":${LOCAL_SOCKS5_PORT}" &>/dev/null; then log_error "SSH SOCKS5 代理端口 ${LOCAL_SOCKS5_PORT} 未在监听。请手动检查 SSH 进程。" fi # ============================================================================== # 4. 配置 redsocks2 (透明 SOCKS5 代理) (保持不变) # ============================================================================== log_info "配置 redsocks2 透明代理..." # 备份现有配置 sudo cp /etc/redsocks.conf /etc/redsocks.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 redsocks.conf 失败。" cat < /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 redsocks2 || log_error "重启 redsocks2 服务失败。" sudo systemctl enable redsocks2 || log_error "启用 redsocks2 服务失败。" log_info "redsocks2 透明代理已配置并启动,监听 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 < /dev/null # 指定监听地址,只监听内网IP和本地环回 listen-address=${DNSMASQ_LISTEN_IP},127.0.0.1 # 不使用 /etc/resolv.conf 中的 DNS 服务器 no-resolv no-poll # 国内域名直连公共DNS server={{ domestic_dns }} # 国外域名通过 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 "安装和配置 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 失败。" # 更新 config.conf 以适应我们的需求 # gfwlist2new 默认会将 gfwlist 中的域名指向代理IP # IPSET_NAME 是 ipset 列表的名称 # DNSMASQ_CONF_PATH 是 dnsmasq 配置文件路径 # SOCKS5_SERVER 是代理服务器的IP和端口 (这里是 redsocks2 监听的IP和端口) cat < /dev/null [DEFAULT] # IPSet Config IPSET_NAME = gfwlist IPSET_FILE = /etc/ipset/gfwlist.conf # Dnsmasq Config 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代理 # Other 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 运行失败。" # 重启 dnsmasq 应用新规则 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 # ============================================================================== # 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. 透明代理规则 (使用 redsocks2 和 ipset) # 重定向到 redsocks2 的流量,不处理来自 redsocks2 本身的流量 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流量到 redsocks2)。" # 排除 redsocks2 自身流量循环 # 这一步非常重要,避免 redsocks2 自己产生流量又被 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 "已配置排除 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 "内网主机现在应该可以自动通过 DHCP 获取 IP 并访问网络。" log_info "----------------------------------------------------------------------------------"