bugfix
This commit is contained in:
parent
c23c5f1979
commit
41a086d7ec
@ -22,8 +22,8 @@ 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 在本机监听的端口
|
||||
# 透明代理工具 redsocks 监听端口
|
||||
REDSOCKS_PORT="{{ redsocks_port }}" # redsocks 在本机监听的端口
|
||||
|
||||
# DNSMASQ 配置
|
||||
DNSMASQ_LISTEN_IP="${GATEWAY_LAN_IP}" # dnsmasq 监听的IP
|
||||
@ -80,12 +80,12 @@ 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..."
|
||||
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 redsocks2
|
||||
install_package redsocks
|
||||
install_package git
|
||||
install_package python3-pip
|
||||
install_package isc-dhcp-server # 新增 DHCP 服务器安装
|
||||
@ -172,32 +172,45 @@ log_info "ISC DHCP Server 已配置并启动,在 ${LAN_INTERFACE} 上提供 DH
|
||||
# ==============================================================================
|
||||
# 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
|
||||
log_info "${curuser}:配置 SSH SOCKS5 代理 Systemd 服务..."
|
||||
SSH_SOCKS5_SERVICE_FILE="/etc/systemd/system/ssh-socks5.service"
|
||||
|
||||
# 确保旧的代理进程被杀死
|
||||
sudo pkill -f "ssh -D ${LOCAL_SOCKS5_PORT}" || true
|
||||
# 动态创建 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 # 留出时间让服务启动和重试
|
||||
|
||||
# 启动 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
|
||||
log_info "SSH SOCKS5 代理已通过 Systemd 启动,并在 127.0.0.1:${LOCAL_SOCKS5_PORT} 监听,支持自动重连。"
|
||||
|
||||
# ==============================================================================
|
||||
# 4. 配置 redsocks2 (透明 SOCKS5 代理) (保持不变)
|
||||
# 4. 配置 redsocks (透明 SOCKS5 代理) (保持不变)
|
||||
# ==============================================================================
|
||||
log_info "配置 redsocks2 透明代理..."
|
||||
log_info "配置 redsocks 透明代理..."
|
||||
# 备份现有配置
|
||||
sudo cp /etc/redsocks.conf /etc/redsocks.conf.bak_$(date +%Y%m%d%H%M%S) || log_warn "备份 redsocks.conf 失败。"
|
||||
|
||||
@ -216,14 +229,13 @@ redsocks {
|
||||
|
||||
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}。"
|
||||
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 转发 (保持不变)
|
||||
@ -262,55 +274,40 @@ log_info "dnsmasq 智能 DNS 转发已初步配置。"
|
||||
# ==============================================================================
|
||||
# 6. 安装和配置 gfwlist2new (保持不变)
|
||||
# ==============================================================================
|
||||
log_info "安装和配置 gfwlist2new 工具..."
|
||||
log_info "集成和配置 GFW 规则生成器 (gfw_rules_generator.py)..."
|
||||
LOCAL_SCRIPT_NAME="gfw_rules_generator.py"
|
||||
|
||||
if [ ! -d "${GFWLIST2NEW_DIR}" ]; then
|
||||
log_info "克隆 gfwlist2new 仓库..."
|
||||
sudo git clone "{{ gfwlist2new_repo }}" "${GFWLIST2NEW_DIR}" || log_error "克隆 gfwlist2new 仓库失败。"
|
||||
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}"
|
||||
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 失败。"
|
||||
# 定义 SOCKS5 代理地址
|
||||
SOCKS5_SERVER_ADDR="127.0.0.1:${LOCAL_SOCKS5_PORT}"
|
||||
|
||||
# 更新 config.conf 以适应我们的需求
|
||||
# gfwlist2new 默认会将 gfwlist 中的域名指向代理IP
|
||||
# IPSET_NAME 是 ipset 列表的名称
|
||||
# DNSMASQ_CONF_PATH 是 dnsmasq 配置文件路径
|
||||
# SOCKS5_SERVER 是代理服务器的IP和端口 (这里是 redsocks2 监听的IP和端口)
|
||||
cat <<EOF | sudo tee config.conf > /dev/null
|
||||
[DEFAULT]
|
||||
# IPSet Config
|
||||
IPSET_NAME = gfwlist
|
||||
IPSET_FILE = /etc/ipset/gfwlist.conf
|
||||
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 "规则生成脚本运行失败。"
|
||||
|
||||
# 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 配置完成并设置定时更新。"
|
||||
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 (保持不变)
|
||||
# ==============================================================================
|
||||
@ -333,16 +330,16 @@ 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 本身的流量
|
||||
# 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流量到 redsocks2)。"
|
||||
log_info "已配置透明代理重定向规则 (所有端口,目标IP在 gfwlist 中的内网TCP流量到 redsocks)。"
|
||||
|
||||
# 排除 redsocks2 自身流量循环
|
||||
# 这一步非常重要,避免 redsocks2 自己产生流量又被 iptables 捕获
|
||||
# 排除 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 "已配置排除 redsocks2 自身流量循环的规则。"
|
||||
log_info "已配置排除 redsocks 自身流量循环的规则。"
|
||||
|
||||
# 保存 iptables 规则
|
||||
sudo netfilter-persistent save || log_error "保存 iptables 规则失败。"
|
||||
@ -351,7 +348,7 @@ log_info "IPTABLES 规则已配置并保存。"
|
||||
|
||||
log_info "----------------------------------------------------------------------------------"
|
||||
log_info "网关主机配置完成!"
|
||||
log_info "请检查 redsocks2 和 ssh -D 进程是否正常运行。"
|
||||
log_info "请检查 redsocks 和 ssh -D 进程是否正常运行。"
|
||||
log_info "请注意:SSH SOCKS5 代理可能需要手动输入密码或配置免密登录才能持久运行。"
|
||||
log_info "内网主机现在应该可以自动通过 DHCP 获取 IP 并访问网络。"
|
||||
log_info "----------------------------------------------------------------------------------"
|
||||
|
||||
@ -10,12 +10,18 @@ GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.
|
||||
def log_info(message):
|
||||
print(f"[INFO] {message}")
|
||||
|
||||
def generate_rules(proxy_server, foreign_dns, domestic_dns, ipset_name="gfwlist"):
|
||||
# 注意:foreign_dns_list 和 domestic_dns_list 现在是列表
|
||||
def generate_rules(proxy_server, foreign_dns_list, domestic_dns_list, ipset_name="gfwlist"):
|
||||
"""
|
||||
生成 Dnsmasq 和 IPSet 规则文件。
|
||||
"""
|
||||
if not foreign_dns_list or not domestic_dns_list:
|
||||
log_info("错误:必须提供至少一个国内 DNS 和一个国外 DNS。")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
log_info(f"正在从 {GFWLIST_URL} 下载 GFWList...")
|
||||
# 尝试通过代理下载 GFWList (这里假设环境已配置或可以直接访问 GitHub)
|
||||
response = requests.get(GFWLIST_URL, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
@ -27,9 +33,9 @@ def generate_rules(proxy_server, foreign_dns, domestic_dns, ipset_name="gfwlist"
|
||||
content = response.text
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
log_info(f"下载 GFWList 失败,使用本地缓存:{e}")
|
||||
# 允许继续运行,依赖旧的规则文件
|
||||
content = ""
|
||||
log_info(f"下载 GFWList 失败,请检查网络连接: {e}")
|
||||
# 如果下载失败,中止脚本以避免生成空文件
|
||||
sys.exit(1)
|
||||
|
||||
domains = set()
|
||||
for line in content.splitlines():
|
||||
@ -37,7 +43,7 @@ def generate_rules(proxy_server, foreign_dns, domestic_dns, ipset_name="gfwlist"
|
||||
if not line or line.startswith(('#', '!')):
|
||||
continue
|
||||
|
||||
# 提取域名(忽略 IP、通配符规则和特殊标记)
|
||||
# 简单提取域名
|
||||
if line.startswith('||'):
|
||||
domain = line[2:]
|
||||
elif line.startswith('.'):
|
||||
@ -47,28 +53,31 @@ def generate_rules(proxy_server, foreign_dns, domestic_dns, ipset_name="gfwlist"
|
||||
else:
|
||||
domain = line
|
||||
|
||||
# 简单过滤,确保是域名
|
||||
# 过滤掉 IP 地址,只保留域名
|
||||
if domain and '.' in domain and not domain.startswith('*.'):
|
||||
domains.add(domain)
|
||||
|
||||
# 2. 生成 DNSMasq 配置文件
|
||||
dnsmasq_conf_path = "/etc/dnsmasq.d/gfwlist_router.conf"
|
||||
|
||||
# 确保 foreign_dns 包含端口 (例如 127.0.0.1#1086)
|
||||
proxy_dns_server = f"{foreign_dns}#{proxy_server.split(':')[1]}"
|
||||
# 代理的上游 DNS (只使用提供的第一个国外 DNS)
|
||||
primary_foreign_dns = foreign_dns_list[0]
|
||||
proxy_port = proxy_server.split(':')[1]
|
||||
proxy_dns_server = f"{primary_foreign_dns}#{proxy_port}"
|
||||
|
||||
try:
|
||||
with open(dnsmasq_conf_path, 'w') as f:
|
||||
f.write(f"# Dnsmasq rules generated by gfw_rules_generator.py\n")
|
||||
f.write(f"# Dnsmasq rules generated by gfw_rules_generator.py on {os.path.basename(__file__)}\n")
|
||||
|
||||
# 设置国内 DNS
|
||||
f.write(f"server={domestic_dns}\n")
|
||||
# 写入所有国内 DNS 服务器
|
||||
for dns in domestic_dns_list:
|
||||
f.write(f"server={dns}\n")
|
||||
|
||||
# GFWList 域名设置
|
||||
# GFWList 域名设置 (通过代理的上游 DNS 解析,并加入 IPSet)
|
||||
for domain in sorted(list(domains)):
|
||||
# 1. 将域名加入 IPSet 集合
|
||||
# 1. 将域名加入 IPSet 集合 (由 dnsmasq 动态处理)
|
||||
f.write(f"ipset=/{domain}/{ipset_name}\n")
|
||||
# 2. 通过代理的 DNS 服务器解析
|
||||
# 2. 通过代理的 DNS 服务器解析 (流量会走 redsocks/ssh)
|
||||
f.write(f"server=/{domain}/{proxy_dns_server}\n")
|
||||
|
||||
log_info(f"已生成 Dnsmasq 规则到 {dnsmasq_conf_path},包含 {len(domains)} 个域名。")
|
||||
@ -76,10 +85,9 @@ def generate_rules(proxy_server, foreign_dns, domestic_dns, ipset_name="gfwlist"
|
||||
log_info(f"写入 Dnsmasq 文件失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# 3. 确保 IPSet 存在
|
||||
# 脚本不负责添加 IP 地址(由 Dnsmasq 在运行时动态添加)
|
||||
# 但需要确保 IPSet 集合本身存在。
|
||||
# 3. 确保 IPSet 集合存在 (必须在 Dnsmasq 启动前存在)
|
||||
try:
|
||||
# 使用 hash:ip 集合,如果集合已存在则清除其内容 (flush)
|
||||
os.system(f"sudo ipset create {ipset_name} hash:ip family inet hashsize 1024 maxelem 65536 &>/dev/null || sudo ipset flush {ipset_name}")
|
||||
log_info(f"已确保 IPSet 集合 '{ipset_name}' 存在。")
|
||||
except Exception as e:
|
||||
@ -90,9 +98,11 @@ def generate_rules(proxy_server, foreign_dns, domestic_dns, ipset_name="gfwlist"
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="GFWList Rules Generator for Dnsmasq/IPSet")
|
||||
|
||||
# 允许接受多个参数 (nargs='+')
|
||||
parser.add_argument("-p", "--proxy", required=True, help="SOCKS5 Proxy server (e.g., 127.0.0.1:1086)")
|
||||
parser.add_argument("-f", "--foreign-dns", required=True, help="Foreign DNS IP (e.g., 8.8.8.8)")
|
||||
parser.add_argument("-d", "--domestic-dns", required=True, help="Domestic DNS IP (e.g., 223.5.5.5)")
|
||||
parser.add_argument("-f", "--foreign-dns", nargs='+', required=True, help="Foreign DNS IP(s) (e.g., 8.8.8.8 9.9.9.9)")
|
||||
parser.add_argument("-d", "--domestic-dns", nargs='+', required=True, help="Domestic DNS IP(s) (e.g., 223.5.5.5 114.114.114.114)")
|
||||
parser.add_argument("-n", "--name", default="gfwlist", help="IPSet Name")
|
||||
|
||||
args = parser.parse_args()
|
||||
@ -100,3 +110,4 @@ if __name__ == "__main__":
|
||||
log_info("开始生成 GFWList 规则...")
|
||||
generate_rules(args.proxy, args.foreign_dns, args.domestic_dns, args.name)
|
||||
log_info("规则生成完成。")
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user