news 2026/10/7 8:13:34

Portmaster SPN 测试指南:多身份路由验证与本地测试网络搭建

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Portmaster SPN 测试指南:多身份路由验证与本地测试网络搭建
  • 网络安全

【免费下载链接】portmaster

🏔 Love Freedom - ❌ Block Mass Surveillance

项目地址:https://gitcode.com/gh_mirrors/po/portmaster
点击查看免费下载

Portmaster 的 SPN(Safing Privacy Network)是其对抗大规模监控、提供匿名出口的关键模块。本文围绕仓库中的 spn/TESTING.md 官方测试文档,讲解如何验证 SPN 的多身份路由(Multi-Identity Routing)是否按预期工作,并结合源码深入剖析其底层原理,最后给出搭建隔离测试网络的完整实操步骤。读完本文,你将掌握一套可复制、可验证的 SPN 功能测试方法,以及如何读懂测试结果、排查误判。

先理解你在测试什么:SPN 与多身份路由

SPN 是一个去中心化的隐私网络:客户端(Client)通过多个公开的 Hub 建立加密隧道,把流量在多个跳点之间接力转发,最终由某个"出口 Hub"代表用户访问目标网站。在 spn/instance.go 中可以看到 SPN 的完整模块组成:access(访问与认证)、cabin(身份)、navigator(路由规划)、captain(连接管理)、crew(隧道处理)、docks(终端管理)、ships(底层连接)、patrol(连通性巡检)、sluice(流量闸口)与terminal(终端协议)。

多身份路由(Multi-Identity Routing)的核心思想是:SPN 不为所有流量只分配单一出口,而是可以为不同的连接选择不同的出口 Hub。路由选择由 spn/navigator/route.go 实现——每条Route由一串Hop(跳点)组成,每个 Hop 记录 Hub ID 与代价(Cost),TotalCost是所有跳点与目标出口代价之和;Routes.clean()会按代价排序并裁剪到配置上限,randomizeTop()还会在代价相近的顶级路由中做随机化,以均衡网络负载。当客户端建立隧道时,spn/crew/connect.go 中的establishRoute会沿路由逐跳执行docks.ExpandTo扩展终端,并经access.AuthorizeToTerminal完成逐跳认证。

因此,多身份路由正常工作时,不同连接会从不同出口 Hub 出网,看到的公网 IP 也就不同。这正是官方测试文档的验证思路。

官方推荐的多身份路由测试法

spn/TESTING.md 给出的测试方法非常直接:同时请求多个显示公网 IP 的网站,如果它们返回不同的 IP 值,说明多身份路由正在工作。

测试原理

  • 在 SPN 未启用(或仅单一路由)时,所有请求的出口一致,各网站返回相同的公网 IP;
  • 在多身份路由启用后,不同连接可能被分配到不同出口 Hub,各网站返回的公网 IP 会出现差异;
  • 出现差异即证明:SPN 隧道链路建立成功、出口 IP 已成功切换、多出口路由分配生效。

推荐测试网站

原文档推荐了以下 4 个可显示公网 IP 的服务(以域名形式给出,避免链接跳转干扰测试):

  • icanhazip.com
  • ipecho.net
  • ipinfo.io
  • ipinfo.tw

终端命令

在任意终端中依次执行:

curl https://icanhazip.com curl https://ipecho.net/plain curl https://ipinfo.io/ip curl https://ipinfo.tw/ip

对比四条命令的输出:如果它们返回不同的 IP,则多身份路由工作正常;如果全部相同,则说明当前流量只走了单一出口。

测试结果的解读与常见误判

拿到测试结果后,需要区分以下情形,避免误判:

现象可能原因处理建议
四个网站返回不同 IP多身份路由正常符合预期
返回相同 IP流量仅经单一出口确认 SPN 已连接、连接分配策略是否允许多出口
请求超时或连接失败出口 Hub 的 HTTPS 连通性异常查看 SPN 状态与日志,参考 patrol 巡检结论
返回 IP 与本地公网 IP 一致SPN 未接管该流量(旁路)检查应用是否走代理、SPN 隧道是否建立

另外要注意结果缓存:个别浏览器或 HTTP 客户端会缓存响应,建议使用curl这类无缓存的命令行工具,并多次刷新对比。

源码视角:SPN 内部如何让出口"变多"

理解测试原理后,可以深入源码确认其实现。整个过程由三个层面协作:

  1. 路由规划(navigator):navigator.FindRoutes(ip, opts)针对目标 IP 计算多条候选 Route,每条 Route 的Path记录了从 Home Hub 到目标出口 Hub 的跳点序列,见 spn/navigator/route.go。recalculateTotalCost()甚至会对已建立活跃终端的跳点只计 80% 代价,鼓励复用已有链路。

  2. 隧道建立(crew + docks):spn/crew/connect.go 的establishRoute逐跳调用expand():先用docks.ExpandTo在上一跳与下一跳之间创建ExpansionTerminal,再发起认证操作AuthorizeOp,成功后把该 Pin 标记为可达并存入活跃终端;若某跳认证失败或超时,对应 Pin 会被MarkAsFailingFor标记为故障,路由尝试随即切换下一条。

  3. 底层连接(ships):spn/ships/launch.go 的Launch会按 Hub 发布的 transports(如http:80、tcp:17)与 IPv4/IPv6 地址逐一尝试建立Ship(网络层连接),接口定义见 spn/ships/ship.go。不同出口 Hub 意味着不同的Ship与不同的公网出口,这正是多 IP 差异的物理来源。

从这条链路可以推断:只要 navigator 能同时维护多条候选路由,且 crew 能分别为它们建立终端,多身份路由就会为不同连接分配不同出口。测试时观察到的 IP 差异,本质是上述模块协同工作的外在表现。

补充测试手段:自动 HTTPS 连通性巡检

除手动 curl 外,SPN 还内置了自动巡检模块patrol,可用于持续验证隧道出口的连通性,作为多身份路由测试的补充:

  • spn/patrol/http.go 中的runHTTPSConnectivityChecks会分三档执行 HTTPS 连通性检查:先 1 个域名要求 100% 成功;失败则升级为 5 个域名要求 80%;再失败则升级为 20 个域名要求 70%。检查会分别针对tcp4与tcp6进行(取决于 Hub 是否具备对应地址族)。
  • 探测使用的测试域名来自 spn/patrol/domains.go 维护的固定列表(如wikipedia.org、cloudflare.com、debian.org等,源自 Tranco 榜单并经过清洗),每次从列表中随机选取,见getRandomTestDomain()。
  • CheckHTTPSConnection强制使用 HTTPS 并校验状态码位于[200, 400)区间,且禁用了 keep-alive 与压缩、跳过重定向,确保探测的是真实的出口链路而非中间层缓存,相关细节均在该文件源码中。

如果你的 SPN 出口在该巡检中被判定失败,HTTPSConnectivityConfirmed()会变为false并触发状态事件,此时手动 curl 大概率也会失败——这可以帮助你把"IP 是否不同"与"出口是否健康"两个问题分开排查。

搭建隔离的本地 SPN 测试网络

官方在 spn/testing/simple/README.md 中提供了一套基于 Docker Compose 的简易测试网络,可以在完全隔离的环境里验证 SPN 行为,避免污染生产状态。整套脚本位于 spn/testing/simple/。

1. 构建 Hub 二进制

cd ../../../cmds/hub/ ./build

2. 重置旧状态(保证测试干净)

./reset-databases.sh

3. 按需修改配置

测试网络的拓扑与 Hub 参数由两个文件控制:

  • docker-compose.yml:定义了 10 个 Hub 容器(hub1~hub10),分布在6.0.0.0/24子网内(如6.0.0.11~6.0.0.20)。前 5 个使用最新构建的二进制,后 5 个默认使用同一二进制;如果你把旧版本放到testdata/old-hub,后 5 个会自动改用旧版本,从而形成混合版本测试场景(run.sh会输出对应告警)。
  • config-template.json:Hub 的基础配置模板,其中spn.publicHub段的关键参数如下:
{ "core": { "log": { "level": "trace" }, "metrics": { "instance": "test_$HUBNAME", "push": "" } }, "spn": { "publicHub": { "name": "test-$HUBNAME", "transports": ["http:80", "http:8080", "tcp:17"], "allowUnencrypted": true, "bindToAdvertised": true } } }

参数说明($HUBNAME会被每个容器替换为对应 Hub 名):

参数含义
nameHub 在测试网络中的名称,此处统一加test-前缀以示区分
transports该 Hub 对外提供的传输方式,http:80、http:8080表示 HTTP 传输及端口,tcp:17表示原始 TCP 传输及端口
allowUnencrypted允许未加密的传输(测试网络专用,生产环境不应开启)
bindToAdvertised绑定到公告的地址进行监听

4. 启动测试网络

./run.sh

脚本会清理残留容器、校验 Hub 二进制存在、把模板文件与entrypoint.sh复制进共享目录,然后执行docker compose -p spn-test-simple up --remove-orphans拉起全部 10 个 Hub。

5. 以 Hub 身份加入(方案一)

只想用不同构建或配置测试单个 Hub 时,可直接用最新构建的 Hub 二进制加入网络:

./join.sh

6. 以 Portmaster 客户端身份接入(方案二)

连接测试网络时,按官方文档执行(注意--spn-map test指定了独立地图,测试网络与生产main地图完全隔离,不会污染已安装 Portmaster 的 SPN 状态):

sudo ../../../cmds/portmaster-core/portmaster-core --disable-shutdown-event --devmode --log debug --data /opt/safing/portmaster --spn-map test --bootstrap-file ./testdata/shared/bootstrap.dsd

其中--spn-map test对应 spn/conf/map.go 中注册的-spn-map命令行参数(默认值为main,该参数本身标注为"仅用于测试")。

若需要以纯客户端二进制模拟多客户端场景,可参考 spn/testing/simple/clientsim.sh:它把编译好的client二进制挂载进spn-simpletest-network网络的容器,以--bootstrap-file /opt/shared/bootstrap.dsd --log trace方式启动,并把数据目录隔离到testdata/clientsim。

7. 停止测试网络

这一步必须执行——直接中断run.sh会遗留带有公网 IP 的接口:

./stop.sh

综合测试流程清单

把上述内容串起来,一套完整的 SPN 功能测试流程如下:

  1. 准备环境:按上文搭建本地测试网络(或直接使用已连接生产 SPN 的 Portmaster)。
  2. 基线对比:断开/禁用 SPN,执行 4 条curl命令记录本地真实公网 IP。
  3. 启用 SPN:确认 Portmaster 显示 SPN 已连接(可参考SPNConnected状态事件,见 spn/instance.go 的GetEventSPNConnected)。
  4. 执行测试:再次执行 4 条curl命令,对比输出 IP。
  5. 结果判定:出现多个不同 IP 即通过;全部相同则检查隧道状态与 patrol 巡检结论。
  6. 恢复与清理:测试完毕执行./stop.sh清理测试网络,避免遗留公网接口。

这套方法既适用于快速人工验证,也适合作为 CI 或回归测试的基线:多身份路由的多出口特性,最终都可以归结为"同一客户端、多个出口、多个公网 IP"这一可观测事实。

  • 网络安全

【免费下载链接】portmaster

🏔 Love Freedom - ❌ Block Mass Surveillance

项目地址:https://gitcode.com/gh_mirrors/po/portmaster
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 8:13:33

193、MLIR与OpenAI Triton(编译器)的对比

MLIR与OpenAI Triton(编译器)的对比 从一次深夜调试说起 凌晨两点,盯着屏幕上跳出的“CUDA error: misaligned address”,我第N次检查了Triton kernel的指针偏移计算。明明MLIR的affine map推导出的地址是16字节对齐的,怎么Triton生成的PTX就给我搞了个非对齐访问?这个…

作者头像 李华
网站建设 2026/10/7 8:12:14

pstack的thermo-nuclear-code-quality-review:终极可维护性审计详解

pstack的thermo-nuclear-code-quality-review:终极可维护性审计详解 【免费下载链接】pstack-claude Claude Code, Codex, Copilot, Pi, OpenCode, Gemini, and Prime Agent versions of Potetos pstack. Rigorous agent workflows with Cursor primitives translat…

作者头像 李华
网站建设 2026/10/7 8:10:58

数据类型转换与日期时间处理

摘要 数据类型决定了字段可以进行什么运算。字符串形式的金额不能可靠求和,未转换的日期不能正确排序,带时区和不带时区的时间也不能直接比较。 本文介绍 pandas 中数字、字符串、布尔值、分类值和日期时间的转换方法,重点讲解错误值处理、…

作者头像 李华
网站建设 2026/10/7 8:10:41

FIGMENT-SOL正式放弃SOL资金池权限:“权限丢弃”的四大核心利好

2026年10月3日,FIGMENT-SOL 亚太区运营中心正式宣布:生态 SOL 资金池管理权限已全面完成放弃程序。此举标志着 FIGMENT-SOL 在完全去中心化的道路上迈出了关键一步,也为市场投资者带来了实质性的长期利好。对于投资者而言,“权限丢…

作者头像 李华
网站建设 2026/10/7 8:10:40

课程论文总是拿低分?科迅捷AI教你写出有学术感的课程作业

为什么你的课程论文总是拿不到高分?很多同学觉得课程论文不就是写个几千字的作业吗,随便找点资料拼一拼,交上去就行。结果成绩出来发现别人都是90分,自己只有70多分,还不知道问题出在哪。其实课程论文虽然不像毕业论文…

作者头像 李华
网站建设 2026/10/7 8:10:00

做一个小程序需要多少钱?手机自助制作费用明细清单与省钱攻略

先算清楚这笔账,心里才有底“做一个小程序需要多少钱?”这是被问得最多的问题。有人说出几千,有人说出几万,也有人说出几百,价格差距大到让人不敢轻信。其实,费用高低主要看你怎么做:找开发公司…

作者头像 李华