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

@ -8,116 +8,124 @@ import sys
GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt" GFWLIST_URL = "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"
def log_info(message): def log_info(message):
print(f"[INFO] {message}") print(f"[INFO] {message}")
def generate_rules(proxy_server, foreign_dns_list, domestic_dns_list, ipset_name="gfwlist"): def generate_rules(proxy_server, foreign_dns_list, domestic_dns_list, ipset_name="gfwlist"):
""" """
生成 Dnsmasq IPSet 规则文件 生成 Dnsmasq IPSet 规则文件
""" """
if not foreign_dns_list or not domestic_dns_list: if not foreign_dns_list or not domestic_dns_list:
log_info("错误:必须提供至少一个国内 DNS 和一个国外 DNS。") log_info("错误:必须提供至少一个国内 DNS 和一个国外 DNS。")
sys.exit(1) sys.exit(1)
# --- 代理配置:通过本地 SOCKS5 隧道下载 GFWList --- # --- 代理配置:通过本地 SOCKS5 隧道下载 GFWList ---
proxies = { proxies = {
'http': f'socks5h://{proxy_server}', # socks5h 使用远程 DNS 解析 'http': f'socks5h://{proxy_server}', # socks5h 使用远程 DNS 解析
'https': f'socks5h://{proxy_server}' 'https': f'socks5h://{proxy_server}'
} }
log_info(f"配置代理:使用 {proxy_server} 通过隧道下载 GFWList...") log_info(f"配置代理:使用 {proxy_server} 通过隧道下载 GFWList...")
# ---------------------------------------------------- # ----------------------------------------------------
try: try:
log_info(f"正在从 {GFWLIST_URL} 下载 GFWList...") log_info(f"正在从 {GFWLIST_URL} 下载 GFWList...")
# 传入 proxies 参数,强制 requests 走代理 # 传入 proxies 参数,强制 requests 走代理
response = requests.get(GFWLIST_URL, timeout=30, proxies=proxies) response = requests.get(GFWLIST_URL, timeout=30, proxies=proxies)
response.raise_for_status() response.raise_for_status()
# 1. 解码 GFWList # 1. 解码 GFWList
try: try:
content = base64.b64decode(response.text).decode('utf-8') content = base64.b64decode(response.text).decode('utf-8')
except: except:
# 如果内容不是 base64 编码,则直接使用 # 如果内容不是 base64 编码,则直接使用
content = response.text content = response.text
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
log_info(f"致命错误:通过代理下载 GFWList 失败,请检查 SSH SOCKS5 隧道状态!: {e}") log_info(f"致命错误:通过代理下载 GFWList 失败,请检查 SSH SOCKS5 隧道状态!: {e}")
# 如果下载失败,中止脚本以避免生成空文件 # 如果下载失败,中止脚本以避免生成空文件
sys.exit(1) sys.exit(1)
domains = set() domains = set()
for line in content.splitlines(): for line in content.splitlines():
line = line.strip() line = line.strip()
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: else:
continue domain = line
else:
domain = line # 2. 移除 URL 路径和查询参数
if '/' in domain:
domain = domain.split('/')[0]
# 3. 过滤掉 IP 地址和通配符,只保留域名
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)
# 过滤掉 IP 地址,只保留域名 # 2. 生成 DNSMasq 配置文件
if domain and '.' in domain and not domain.startswith('*.'): dnsmasq_conf_path = "/etc/dnsmasq.d/gfwlist_router.conf"
domains.add(domain)
# 代理的上游 DNS (只使用提供的第一个国外 DNS)
primary_foreign_dns = foreign_dns_list[0]
proxy_port = proxy_server.split(':')[1]
proxy_dns_server = f"{primary_foreign_dns}#53"
# 2. 生成 DNSMasq 配置文件 try:
dnsmasq_conf_path = "/etc/dnsmasq.d/gfwlist_router.conf" with open(dnsmasq_conf_path, 'w') as f:
f.write(f"# Dnsmasq rules generated by {os.path.basename(__file__)} on {os.uname().nodename}\n")
# 代理的上游 DNS (只使用提供的第一个国外 DNS)
primary_foreign_dns = foreign_dns_list[0] # 写入所有国内 DNS 服务器
proxy_port = proxy_server.split(':')[1] for dns in domestic_dns_list:
proxy_dns_server = f"{primary_foreign_dns}#{proxy_port}" f.write(f"server={dns}\n")
# GFWList 域名设置
for domain in sorted(list(domains)):
# 1. 将域名加入 IPSet 集合 (由 dnsmasq 动态处理)
f.write(f"ipset=/{domain}/{ipset_name}\n")
# 2. 通过代理的 DNS 服务器解析 (流量会走 redsocks/ssh)
f.write(f"server=/{domain}/{proxy_dns_server}\n")
log_info(f"已生成 Dnsmasq 规则到 {dnsmasq_conf_path},包含 {len(domains)} 个域名。")
except IOError as e:
log_info(f"写入 Dnsmasq 文件失败: {e}")
sys.exit(1)
try: # 3. 确保 IPSet 集合存在 (必须在 Dnsmasq 启动前存在)
with open(dnsmasq_conf_path, 'w') as f: try:
f.write(f"# Dnsmasq rules generated by {os.path.basename(__file__)} on {os.uname().nodename}\n") # 使用 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}")
# 写入所有国内 DNS 服务器 log_info(f"已确保 IPSet 集合 '{ipset_name}' 存在。")
for dns in domestic_dns_list: except Exception as e:
f.write(f"server={dns}\n") log_info(f"创建 IPSet 失败: {e}")
sys.exit(1)
# GFWList 域名设置
for domain in sorted(list(domains)): return True
# 1. 将域名加入 IPSet 集合 (由 dnsmasq 动态处理)
f.write(f"ipset=/{domain}/{ipset_name}\n")
# 2. 通过代理的 DNS 服务器解析 (流量会走 redsocks/ssh)
f.write(f"server=/{domain}/{proxy_dns_server}\n")
log_info(f"已生成 Dnsmasq 规则到 {dnsmasq_conf_path},包含 {len(domains)} 个域名。")
except IOError as e:
log_info(f"写入 Dnsmasq 文件失败: {e}")
sys.exit(1)
# 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:
log_info(f"创建 IPSet 失败: {e}")
sys.exit(1)
return True
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="GFWList Rules Generator for Dnsmasq/IPSet") parser = argparse.ArgumentParser(description="GFWList Rules Generator for Dnsmasq/IPSet")
# 允许接受多个参数 (nargs='+') # 允许接受多个参数 (nargs='+')
parser.add_argument("-p", "--proxy", required=True, help="SOCKS5 Proxy server (e.g., 127.0.0.1:1086)") parser.add_argument("-p", "--proxy", required=True, help="SOCKS5 Proxy server (e.g., 127.0.0.1:1086)")
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("-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("-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") parser.add_argument("-n", "--name", default="gfwlist", help="IPSet Name")
args = parser.parse_args() args = parser.parse_args()
# 在开始生成规则之前,必须确保 requests 库已经安装 socks5 支持 # 在开始生成规则之前,必须确保 requests 库已经安装 socks5 支持
# 确保在 Bash 脚本中已经执行: sudo pip3 install requests PySocks # 确保在 Bash 脚本中已经执行: sudo pip3 install requests PySocks
log_info("开始生成 GFWList 规则...") log_info("开始生成 GFWList 规则...")
generate_rules(args.proxy, args.foreign_dns, args.domestic_dns, args.name) generate_rules(args.proxy, args.foreign_dns, args.domestic_dns, args.name)
log_info("规则生成完成。") log_info("规则生成完成。")

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