API — 端口与流量

打开、关闭、列出和配置代理端口,并在正式使用前测试上游代理。这些是集成 BlankTrail Proxy 时最常用的接口。

打开端口

一个请求即可启动本地代理端口并一次性设定其全部行为。字段很多,但必填的只有一个——port;其余取默认值,之后也可在端口运行时修改。

POST/api/v1/ports/open需要鉴权

以给定的身份与行为启动一个代理端口。

参数类型必填说明
portint是端口号,1–65535。
protocolstring否http(默认)、socks5 或 mtproto。
upstreamstring否出口代理;留空表示直连。
modestring否如何选择身份:random、db、auto、specific、custom。
browserstring否浏览器过滤条件;与 mode=random 不兼容。
osstring否操作系统过滤条件;与 mode=random 不兼容。
请求体
{
  "port": 20134,
  "protocol": "socks5",
  "mode": "db",
  "browser": "chrome",
  "os": "windows",
  "upstream": "socks5://user:pass@host:1080"
}
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"port":20134,"protocol":"socks5","mode":"db","browser":"chrome","os":"windows"}' \
  http://127.0.0.1:8891/api/v1/ports/open
响应
{
  "port": 20134,
  "protocol": "socks5",
  "status": "opened",
  "current_profile": {
    "name": "chrome_152_windows",
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) …",
    "browser": "chrome",
    "os": "windows"
  }
}
  • 400 “port is required”——字段缺失或为 0;400 “invalid port number: N (must be 1-65535)”。
  • mode、browser、os、vdns_mode、resolver_strategy 或 intercept_scope 取值无效时返回 400——拒绝文本会列出允许的取值。
  • 若 mode=random 与 browser 或 os 过滤条件同时出现,返回 400;400 “require_udp_dns requires vdns_mode to be on_leak or forced”;若请求了网关但网关管理器未启用,返回 400;若 upstream_gateway 或 chain_gateway 指定的网关不在已保存列表中,返回 400 “gateway config … not found — upload it first via POST /api/v1/ovpn”——名称拼写错误与网关尚未上传得到相同的拒绝,因此请先用 GET /api/v1/ovpn 核对,而不是怀疑管理器被关闭。
  • 在没有 Pro 的情况下使用 debug_capture,返回 403 “the debug fingerprint port requires a Pro license”。
  • 若端口已打开或被其他程序占用,返回 409——文本来自端口管理器。
  • 当 protocol=mtproto 时,响应还会包含两个字段:tg_link(交给 Telegram 客户端的 tg://proxy… 链接)与 mtproto_secret(规范的 ee… 密钥,包括自动生成的)。

网络出口

字段类型默认值作用
upstreamstring—出口代理:scheme://[user:pass@]host:port,支持 socks5、socks5h、http。为空表示直连出口。
chain_proxystring—出口代理之前的链路首跳。
upstream_gatewaystring—已保存网关的名称;其本地 SOCKS5 将作为出口。
chain_gatewaystring—用于链路首跳的已保存网关名称。
ovpn_configstring—upstream_gateway 的旧别名,为兼容旧客户端而保留。
upstream_tls_insecureboolfalse对 https 代理关闭证书校验。仅适用于使用自签名证书的自有代理。
allow_mitm_upstreamboolfalse允许自行拆解 TLS 的出口。默认禁止:此类出口会抹掉指纹。
egress_force_ipv4booltrue仅通过 IPv4 出口——防止 IPv6 泄漏。
block_private_targetsbooltrue拒绝连接到私有、回环、链路本地与 CGNAT 地址:否则该代理会变成局域网的地图。

身份与协议

字段类型默认值作用
modestringrandomrandom、db(别名 database)、auto、specific 或 custom。random 模式与 browser/os 过滤条件不兼容。
browserstring—浏览器过滤条件:chrome、firefox、safari、edge、random;可带版本——chrome_145。
osstring—操作系统过滤条件:windows、macos、linux、ios、android、random。
specific_profilestring—mode=specific 时的配置文件名称,例如 chrome_152_windows。
custom_tlsobject—用于 mode=custom 的完整已采集指纹;形态与 PUT /port/{port}/custom_tls 相同。
auto_profile_from_uaboolfalse按请求的 User-Agent 选择配置文件。
h2_spoofingbool—把 HTTP/2 设置伪装为浏览器配置文件的形态。
spoof_user_agentbool—伪装 User-Agent。关闭时逐字节转发客户端自身的请求头。
spoof_headersbool—把请求头的集合与顺序调整为浏览器的形态。
tls_passthroughboolfalseTLS 原样透传、不做拆解:保留客户端指纹,不读取内容。
tls_mirrorboolfalse拆解 TLS,但对外重放客户端自身的已采集指纹。
session_resumptionbool—允许 TLS 会话恢复(会话票据)。
enable_http3boolfalse当站点提供 h3 且出口支持 UDP 时,改用 HTTP/3 重新发起连接。
decompressbool—在交付客户端前解压 br/gzip/zstd。挑战解题器会强制开启该项。

负载与超时

字段类型默认值作用
max_concurrentint—并发请求上限;0 表示不限。
sem_timeoutint—请求在该上限内等待空位的秒数。🔴 此处字段名为 sem_timeout——与独立接口中的 timeout_seconds 不同。
skip_retryboolfalse网络错误后不重试请求。
retry_delay_msint—重试之间的间隔(毫秒)。
timeout_secondsint—连接(而非端口)的空闲超时,单位为秒。
connect_timeout_secondsint5单次拨号尝试的上限。
request_timeout_secondsint30包含重试在内的整个建立阶段的上限;0 表示不限。
idle_secondsint | nullnull端口的空闲超时,覆盖全局值(默认 30 分钟);0 表示永不关闭。

缓存、日志与采集

字段类型默认值作用
cache_enabledboolfalse在端口上启用响应缓存。
cache_modestringnormalnormal、hard、hard-media 或 hard-autowarm。
cache_ignore_no_cacheboolfalse忽略 no-cache 头进行缓存。
traffic_logboolfalse把端口请求日志写入 data/traffic_port_<端口>.jsonl。
debug_captureboolfalse打开指纹采集端口。🔴 需要 Pro 许可:否则返回 403。
debug_capture_nint500采集端口上环形缓冲区的大小。

挑战与会话

字段类型默认值作用
js_solverboolfalse挑战解题器:遇到验证的请求会转入解题池。需要拆解 TLS(与 tls_passthrough 不兼容)。
keep_sessionsboolfalse端口维护自己的按域名 Cookie 罐:吸收 Set-Cookie、注入 Cookie 并跟随重定向。与 js_solver 无关。

DNS 与泄漏防护

字段类型默认值作用
leak_guardstring—启动前的出口 DNS/IPv6 泄漏检查:off、warn 或 enforce。
vdns_modestringoff虚拟 DNS:off、on_leak(发现泄漏时启用)或 forced。Standard 及以上套餐:在 Lite 上该字段会被接受,端口以关闭 vdns 的状态打开,其 vdns_path_reason 为 plan。
resolver_strategystringautoauto 或 custom——解析器的来源。
custom_resolversarray—resolver_strategy=custom 时使用的 host:port 列表。
ecs_enabledbooltrue在 DNS 查询中传递客户端子网(EDNS Client Subnet)。
vdns_strict_bypassboolfalse严格绕过:只发送 IP 字面量,主机名不会离开本机。
require_udp_dnsboolfalse仅在出口已证明可为 DNS 转发 UDP 时才打开端口。要求 vdns_mode 为 on_leak 或 forced,否则返回 400。

系统流量拦截

警告intercept_scope 的默认值是 system,即整台机器,而不是选定的程序。启用拦截的端口会把全部流量引入隧道,包括您对该机器的远程控制。若只想引导选定的应用,请设置 intercept_scope=process 并在 intercept_apps 中列出它们。
字段类型默认值作用
interceptboolfalse在应用无需配置代理的情况下把系统流量引入该端口。
intercept_scopestringsystem🔴 system 表示整台机器(默认值),process 表示仅所列出的程序。
intercept_appsarray—scope=process 时的可执行文件路径。

MTProto(Telegram 代理)

以下字段仅在 protocol=mtproto 时有意义。该模式下端口使用 Telegram 的协议,而不是 HTTP 或 SOCKS5,Telegram 客户端通过响应中的链接连接它。

字段类型默认值作用
mtproto_secretstring—形如 ee… 的规范密钥;留空则生成新的。
mtproto_camouflage_domainstringwww.google.com伪装域名——同时也是 Telegram 客户端所提供的 SNI。
mtproto_fallback_realbooltrue把探测者与密钥错误的客户端转接到真实的伪装站点。
mtproto_egressstringautoauto、obfuscated 或 faketls——如何连接上游 MTProto 代理。
mtproto_faketls_upstreamstring—egress=faketls 时上游 MTProto 代理的 host:port。
mtproto_faketls_secretstring—该上游代理的 ee… 密钥。

关闭端口

POST/api/v1/ports/close需要鉴权

关闭已打开的端口,并断开经由它的所有连接。

参数类型必填说明
portint是要关闭的端口。
请求体
{ "port": 20134 }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"port":20134}' \
  http://127.0.0.1:8891/api/v1/ports/close
响应
{
  "port": 20134,
  "status": "closed"
}
  • 字段缺失或为 0 时返回 400 “port is required”;端口未打开时返回 404。
  • 启用拦截的端口在关闭时会同时移除其拦截规则——流量回到常规路由。

已打开端口的列表

GET/api/v1/ports需要鉴权

返回所有已打开的端口及其完整配置与状态。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/ports
响应
{
  "ports": [
    {
      "port": 20134,
      "protocol": "socks5",
      "created_at": "2026-09-06T09:12:44Z",
      "last_activity": "2026-09-06T11:03:01Z",
      "current_profile": "chrome_152_windows",
      "mode": "db",
      "upstream": "socks5://host:1080",
      "chain_proxy": "",
      "browser_filter": "chrome",
      "os_filter": "windows",
      "h2_spoofing": true,
      "spoof_user_agent": true,
      "spoof_headers": true,
      "decompress": true,
      "max_concurrent": 0,
      "skip_retry": false,
      "retry_delay_ms": 0,
      "cache_enabled": false,
      "cache_mode": "",
      "cache_normalize_ids": false,
      "debug_capture": false,
      "capture_count": 0,
      "auto_profile_from_ua": false,
      "effective_idle_seconds": 1800,
      "js_solver": false,
      "keep_sessions": false,
      "captcha_action": "rotate_retry",
      "captcha_max_attempts": 3,
      "intercept": false,
      "vdns_active": false
    }
  ],
  "total_open": 1,
  "max_ports": 1000
}
  • max_ports 是同时打开端口的实际生效上限:配置上限(portmanager.max_ports)与许可上限中的较小者。它与 GET /api/v1/status 返回的数值完全相同——不再需要交叉核对两个接口。
  • 🔴 在本次发布之前的构建中,此处的该字段无论套餐与配置如何都返回常量 1000,而 /status 的同名字段当时已经给出真实上限。若在明知上限更小的情况下仍看到恰好 1000,请升级客户端;在此之前请按 /status 的 max_ports 规划端口池。
  • 列表项中没有 status 字段:已打开的端口本就是打开的。leak_report、last_ua、last_auto_profile、idle_override_seconds、leak_guard、upstream_gateway、chain_gateway、intercept_scope、intercept_apps、intercept_state、intercept_reason、vdns_mode、vdns_transport 与 vdns_udp_reason 只在有内容时才出现;protocol=mtproto 的端口还会带上 tg_link 与 mtproto_secret(与打开端口所返回的是同样两个字段)。其余字段在每一项中都会出现,即使为空——包括上面示例中的 cache_normalize_ids、captcha_action、captcha_max_attempts 与 vdns_active。
  • effective_idle_seconds 是端口覆盖值叠加到全局值(默认 30 分钟)之后的最终空闲阈值;0 表示不关闭。
  • vdns_active 表示虚拟 DNS 此刻是否正在改写连接——这与仅声明模式的 vdns_mode 不同。vdns_transport 是最近一次成功解析实际所用的传输方式:udp、tcp、dot 或 doh;为空表示尚未有过成功解析。vdns_udp_reason 在 VDNS 已启用但当前未走 udp 时出现,并给出原因:refused、accepted_but_silent、control_error、chain_unsupported 或 not_probed。

推荐一个空闲端口

GET/api/v1/ports/suggest需要鉴权

返回 20000–29999 区间内最小的、既未被管理器占用又能在系统层面成功绑定的端口号。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/ports/suggest
响应
{
  "port": 20134
}
  • 若整个区间内都没有空闲端口,返回 503 “no_free_port”。
  • 在推荐与打开之间,端口可能被他人占用——这很正常:此时打开会返回 409,再请求下一个即可。

在打开端口前测试出口

该测试会在请求期间临时组装出口链路并运行所选探测,而不会打开任何端口。由此可在依赖某个代理开展工作之前,确认它是否可用、能否为 DNS 转发 UDP,以及是否存在泄漏。

POST/api/v1/upstream/test需要鉴权

检查出口是否可达、SOCKS5 上的 UDP 是否可用,以及 DNS 与 IPv6 是否泄漏。

参数类型必填说明
checksarray是http、udp、leak 中的任意组合。
protocolstring否socks5 或 http——未来端口的协议。
upstreamstring否出口代理;留空则测试直连。
chain_proxystring否链路首跳。
upstream_gatewaystring否用已保存网关的名称替代出口地址。
chain_gatewaystring否用于首跳的已保存网关名称。
upstream_tls_insecurebool否与同名端口设置保持一致:否则测试所检查的配置将与您即将打开的配置不同。
请求体
{
  "checks": ["http", "udp", "leak"],
  "protocol": "socks5",
  "upstream": "socks5://user:pass@host:1080"
}
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"checks":["http","leak"],"upstream":"socks5://user:pass@host:1080"}' \
  http://127.0.0.1:8891/api/v1/upstream/test
响应
{
  "http": { "ok": true, "detail": "200 in 45ms" },
  "udp": { "ok": false, "detail": "UDP ASSOCIATE granted but nothing came back",
            "code": "accepted_but_silent" },
  "leak": { "ok": true, "detail": "no DNS/IPv6 leak — exit 203.0.113.45" }
}
  • 除 ok 与 detail 外,每项探测还可能带有 skipped(该探测未执行)与 code——便于程序分支的机器可读原因。
  • 许可未激活时返回 403:该接口位于许可之后。400 “invalid JSON body”;除 POST 外的方法返回 405。请求体上限为 64 KiB。

端口的状态与配置

三个接口以不同粒度描述同一件事:/status 是运行端口的概要,/config 是配置的完整快照,PUT /config 则是修改那些没有独立接口的项的唯一方式。

GET/api/v1/port/{port}/status需要鉴权

运行端口的概要:身份、行为、出口、拒绝计数与最近活动时间。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/status
响应
{
  "port": 20134,
  "protocol": "socks5",
  "mode": "db",
  "browser_filter": "chrome",
  "os_filter": "windows",
  "h2_spoofing": true,
  "spoof_user_agent": true,
  "spoof_headers": true,
  "session_resumption": true,
  "max_concurrent": 0,
  "sem_timeout_seconds": 30,
  "connect_timeout_seconds": 5,
  "request_timeout_seconds": 30,
  "skip_retry": false,
  "retry_delay_ms": 0,
  "cache_enabled": false,
  "cache_mode": "",
  "traffic_log": false,
  "tls_passthrough": false,
  "tls_mirror": false,
  "cache_ignore_no_cache": false,
  "allow_mitm_upstream": false,
  "mitm_blocked": 0,
  "current_profile": { "name": "chrome_152_windows", "user_agent": "Mozilla/5.0 …",
                       "browser": "chrome", "os": "windows" },
  "upstream": "socks5://host:1080",
  "chain_proxy": "",
  "created_at": "2026-09-06T09:12:44Z",
  "last_activity": "2026-09-06T11:03:01Z"
}
  • mitm_blocked 与 mitm_last_issuer 以同一快照读取:它们同时变化,分别读取会导致一次拒绝的计数与另一次拒绝的责任方被并排显示。
  • last_activity 不仅由流量推进,对该端口任何接口的调用同样会推进它。
GET/api/v1/port/{port}/config需要鉴权

端口配置的完整快照——全部约六十个键,包括那些没有独立接口的项。没有取值的键不会出现在快照中。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/config
响应
{
  "port": 20134,
  "protocol": "socks5",
  "upstream": "socks5://host:1080",
  "mode": "db",
  "browser": "chrome",
  "os": "windows",
  "timeout_seconds": 0,
  "connect_timeout_seconds": 5,
  "request_timeout_seconds": 30,
  "egress_force_ipv4": true,
  "block_private_targets": true,
  "js_solver": false,
  "keep_sessions": false,
  "sessions_per_port": 1,
  "captcha_action": "rotate_retry",
  "captcha_max_attempts": 3,
  "ecs_enabled": true
}
  • 示例中的响应已截断,但所列的键确实会由端口返回。没有取值的键根本不会出现在响应中:leak_guard、vdns_mode、resolver_strategy 在默认值下直接缺失,而不是返回空字符串;idle_seconds 只在端口设有自己的空闲阈值时出现,继承全局阈值时该键缺失,且永远不会返回 null;intercept 与 intercept_scope 只在以拦截方式打开的端口上出现,此时 intercept 恒为 true,intercept_scope 为 system 或 process。因此 cfg.intercept === false 与 cfg.idle_seconds === null 得到的是 undefined:请改为判断键是否存在,例如 "intercept" in cfg。
  • 相反,端口的布尔与数值设置始终会返回——包括 0 与 false:js_solver、keep_sessions、timeout_seconds、egress_force_ipv4 等。键名与 POST /api/v1/ports/open 的请求体字段一致——PUT /config 的合并也按同样的名称进行。
PUT/api/v1/port/{port}/config需要鉴权

修改运行端口的配置。所发送的字段会合并到当前快照之上:请求体中未出现的项保持原样。

请求体
{ "mode": "auto", "browser": "firefox", "os": "macos" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"mode":"auto","browser":"firefox","os":"macos"}' \
  http://127.0.0.1:8891/api/v1/port/20134/config
响应
{
  "port": 20134,
  "protocol": "socks5",
  "status": "reconfigured",
  "current_profile": { "name": "firefox_152_macos", "user_agent": "Mozilla/5.0 …",
                       "browser": "firefox", "os": "macos" }
}
  • 🔴 响应中的 status 字段不是端口状态,而是所执行操作的名称:本接口固定返回 reconfigured,而 POST /api/v1/ports/open 返回 opened。用 open 去比对这两个响应都不会匹配。
  • 它接受与 POST /api/v1/ports/open 相同的字段与取值,并以相同的 400 拒绝——包括禁止把 mode=random 与过滤条件组合使用。
  • 若无法读取快照,返回 500 “cannot read the port's current configuration”——此时无法合并,端口保持不变。
  • 这是修改 js_solver、keep_sessions、leak_guard、vdns_mode、resolver_strategy、custom_resolvers、ecs_enabled、timeout_seconds、connect_timeout_seconds、request_timeout_seconds、intercept 以及其他没有独立接口的键的唯一方式。
  • 若请求体改变已打开端口的拦截设置,返回 400:在端口运行时无法开启、关闭或重新配置拦截——请关闭端口后重新打开。未提及拦截的请求体可以通过:比较的是状态,而不是键是否存在。

单个端口的设置

每项设置都有自己的路径,形如 /api/v1/port/{port}/名称。GET 读取当前值,PUT 在端口运行时修改它:端口不会关闭,也不会重启。

警告所有这些接口都没有 value 字段。每个接口都有自己的字段名——下表用单独一列列出,其中三个接口(/sem_timeout、/retry_delay、/idle)的字段名与路径最后一段并不相同。服务器会静默丢弃未知字段:对布尔设置发送 {"value":true} 会返回 200 并将其关闭,对字符串设置则会清空过滤条件。

所有端口接口共有的失败:{port} 不是数字时返回 400 “invalid port number”;端口已关闭时返回 404 “port N is not open”;请求体无法解析时返回 400 “invalid JSON body”。此处的 404 表示端口已关闭,而不是路径不存在。对未知的设置名,响应取决于方法:GET 会落到控制面板的兜底路由,返回正文为 “404 page not found” 的 404;而 PUT、POST 与 DELETE 返回 405。已知名称加上不支持的方法同样返回 405,但仅限该方法不是 GET 时(例如 PUT /profile):对未注册 GET 的接口发起 GET,同样会落到兜底路由并返回 404。

注意对端口接口的任何调用都会被计为活动并重置空闲超时。每分钟轮询一次 GET /status 的监控会让端口永远不会关闭。
路径方法请求体字段类型取值与注意
/modeGET, PUTmodestringrandom、db(别名 database)、auto、specific
/browserGET, PUTbrowserstring空、random、chrome、firefox、safari、edge;可带版本:chrome_145
/osGET, PUTosstring空、random、windows、macos、linux、ios、android
/profileGET——只读;固定配置文件请通过 /mode 或 /config
/profile/viewGET——只读:当前配置文件的构成
/rotatePOST——无请求体;立即签发新的配置文件
/custom_tlsPUTja3, ja4, …object完整的已采集指纹;将端口切换为 custom 模式
/upstreamGET, PUTupstreamstring出口代理地址;空字符串表示直连出口
/chain_proxyGET, PUTchain_proxystring出口代理之前的链路首跳
/allow_mitm_upstreamGET, PUTallow_mitm_upstreambool该字段必填:缺失时返回 400,而不是按 false 处理
/h2_spoofingGET, PUTenabledbooltrue 或 false
/spoof_user_agentGET, PUTenabledbooltrue 或 false
/spoof_headersGET, PUTenabledbooltrue 或 false
/tls_passthroughGET, PUTenabledbooltrue 或 false
/tls_mirrorGET, PUTenabledbooltrue 或 false
/http3GET, PUTenabledbooltrue 或 false
/session_resumptionGET, PUTenabledbooltrue 或 false
/decompressGET, PUTenabledbooltrue 或 false
/auto_profile_from_uaGET, PUTenabledboolGET 还会返回 last_ua
/cache_ignore_no_cacheGET, PUTenabledbooltrue 或 false
/max_concurrentGET, PUTmax_concurrentint0 及以上;0 表示不限
/sem_timeoutGET, PUTtimeout_secondsint1 及以上——字段名与路径不一致
/skip_retryGET, PUTskip_retrybooltrue 或 false
/retry_delayGET, PUTretry_delay_msint0 及以上——字段名与路径不一致
/idlePUTsecondsint | nullnull 表示恢复为全局超时,0 表示永不关闭;没有 GET
/cacheGET, PUT, DELETEenabled, modebool, string参见“响应缓存”一节
/traffic_logGET, PUT, DELETEenabledbool参见“端口请求日志”一节
/capturesGET, DELETE——仅适用于以 debug_capture 打开的端口

其余端口配置项没有各自的接口:timeout_seconds、connect_timeout_seconds、request_timeout_seconds、js_solver、keep_sessions、sessions_per_port、captcha_action、captcha_max_attempts、leak_guard、egress_force_ipv4、block_private_targets、h3_profile、cache_normalize_ids、vdns_mode、resolver_strategy、custom_resolvers、ecs_enabled、require_udp_dns、intercept、intercept_scope、intercept_apps、debug_capture、debug_capture_n 以及 mtproto_* 字段。请用 GET /api/v1/port/{port}/config 读取,用 PUT /api/v1/port/{port}/config 修改;它们没有各自的路径。对 /api/v1/port/{port}/js_solver 发送 GET 会返回 404,正文为纯文本 “404 page not found”——由控制面板的兜底路由给出;而对同一路径发送 PUT、POST 或 DELETE 则返回 405,响应头为 Allow: GET, HEAD,正文为 “Method Not Allowed”。两者都不是带 error 字段的 JSON。

🔴 上列键中有七个 PUT /api/v1/port/{port}/config 并不会应用,尽管它仍返回 200 “reconfigured”:sessions_per_port、captcha_action、captcha_max_attempts、cache_normalize_ids、h3_profile、debug_capture 与 debug_capture_n。处理程序不会把它们带入交给端口管理器的配置,因此不会报错,端口也保持原样。debug_capture 与 debug_capture_n 只能在打开端口时设置,即 POST /api/v1/ports/open 的请求体;要修改它们,请关闭端口后重新打开。这一点可以从 GET /api/v1/port/{port}/captures 看出:对通过 PUT 补发 debug_capture 的端口,它依旧返回 400 “port is not a debug fingerprint-capture port”。其余五个连打开端口的请求体也不接受:captcha_action 与 captcha_max_attempts 只能在端口池上配置(参见“端口池”),sessions_per_port 在当前版本中恒为 1,而 h3_profile 与 cache_normalize_ids 没有任何接口可以设置——h3_profile 还始终为空,因此 GET /config 的响应中没有该键。

mtproto_* 字段在 PUT /config 中遵循通用规则:请求体未提及的保持原样,提及的才会应用。修改其他任何设置都不会影响密钥与伪装域名,因此已经分发出去的 tg://proxy 链接仍然有效;而显式传入 mtproto_secret 正是不关闭端口即可更换密钥的正规做法。更换不会切断已建立的连接,新连接使用新密钥。

🔴 无法解析的密钥不会被拒绝:接口会静默签发一个新的,并且仍然返回 200 “reconfigured”。请将 GET /api/v1/port/{port}/config 响应中的密钥与您发送的值核对。

🔴 在本次发布之前的构建中情况正相反:在 mtproto 端口上修改任何设置都会签发新密钥并把伪装域名重置为默认值,使已分发的链接失效。若客户端尚未升级,请不要通过 PUT /config 修改 mtproto 端口;若已经修改过,请重新读取密钥并重新分发链接。

端口的身份

端口对站点表现出的身份:如何选择配置文件、如何缩小选择范围,以及如何提供自采集的指纹。

GET/api/v1/port/{port}/mode需要鉴权

返回配置文件的选择模式。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/mode
响应
{
  "mode": "db"
}
PUT/api/v1/port/{port}/mode需要鉴权

在端口运行时修改配置文件的选择模式。

参数类型必填说明
modestring是random 生成合成指纹;db(别名 database)取用数据库中的真实配置文件;auto 按所请求的浏览器与操作系统生成;specific 按名称固定。
specific_profilestring否mode=specific 时使用的配置文件名称,例如 chrome_152_windows。
请求体
{ "mode": "specific", "specific_profile": "chrome_152_windows" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"mode":"specific","specific_profile":"chrome_152_windows"}' \
  http://127.0.0.1:8891/api/v1/port/20134/mode
响应
{
  "mode": "specific"
}
  • 该接口并不接受 custom,尽管错误文本提到了它:“mode must be one of: random, db, auto, specific, custom”。端口只能通过 PUT /custom_tls 或 PUT /config 进入 custom 模式。
  • 若端口设置了 browser 或 os 过滤条件而又切换到 random,则返回 400:合成指纹不属于任何真实浏览器,无法满足这些条件。请先用空字符串清除过滤条件。
  • 若 specific_profile 不存在,会返回 400 并附带引擎的文本——但此时模式已经切换。出现该错误后请重新读取 GET /api/v1/port/{port}/config:端口仍处于 specific 且沿用旧名称。
  • 新值从下一个连接开始生效:已建立的 keep-alive 连接不会被断开。
GET/api/v1/port/{port}/browser需要鉴权

返回浏览器过滤条件。空字符串表示没有过滤。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/browser
响应
{
  "browser": "chrome"
}
PUT/api/v1/port/{port}/browser需要鉴权

将配置文件的选择范围限定到某个浏览器,或取消该限定。

参数类型必填说明
browserstring是chrome、firefox、safari、edge、random,或空字符串(清除过滤)。可用后缀固定版本:chrome_145。
请求体
{ "browser": "chrome_145" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"browser":"chrome_145"}' \
  http://127.0.0.1:8891/api/v1/port/20134/browser
响应
{
  "browser": "chrome_145"
}
  • 其他取值一律返回 400 “browser must be one of: "", random, chrome, firefox, safari, edge (optionally with version: chrome_145)”。
  • 若端口处于 random 模式则返回 400:它生成合成指纹,无法满足过滤条件。在 random 端口上用空字符串清除过滤仍然允许。
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/os需要鉴权

返回操作系统过滤条件。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/os
响应
{
  "os": "windows"
}
PUT/api/v1/port/{port}/os需要鉴权

将配置文件的选择范围限定到某个操作系统,或取消该限定。

参数类型必填说明
osstring是windows、macos、linux、ios、android、random,或空字符串(清除过滤)。
请求体
{ "os": "macos" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"os":"macos"}' \
  http://127.0.0.1:8891/api/v1/port/20134/os
响应
{
  "os": "macos"
}
  • 其他取值一律返回 400 “os must be one of: "", random, windows, macos, linux, ios, android”。
  • 在 random 模式端口上返回 400——原因与浏览器过滤相同。
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/profile需要鉴权

返回端口当前使用的配置文件。只读:对该路径发送 PUT 会返回 405。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/profile
响应
{
  "name": "chrome_152_windows",
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) …",
  "browser": "chrome",
  "os": "windows"
}
  • 如需按名称固定配置文件,请使用 PUT /api/v1/port/{port}/mode,请求体为 {"mode":"specific","specific_profile":"…"},或使用 PUT /api/v1/port/{port}/config。
PUT/api/v1/port/{port}/custom_tls需要鉴权

把在别处采集到的完整指纹交给端口,并将其切换为 custom 模式。端口由此获得取自真实浏览器的形态——例如通过 ChromeApi 或 tls.peet.ws 采集。

参数类型必填说明
ja3string否完整的 JA3 字符串。
ja3_hashstring否已采集的 JA3 哈希。
ja4string否JA4 字符串。
ciphersarray是按 ClientHello 顺序排列的密码套件。唯一必填字段。名称按固定表匹配;以 TLS_GREASE 开头的名称按 GREASE 占位保留,无法识别的名称会被静默丢弃。若识别后为空,则返回 400。密码套件不会从 ja3 推导:该字符串仅用于扩展顺序。
extensionsarray<object>否按 ClientHello 顺序排列的扩展。每个元素为对象:必填 name,可选 supported_groups、signature_algorithms、versions、protocols。
supportedGroupsarray否支持的椭圆曲线组。
signatureAlgorithmsarray否签名算法。
alpnarray否ALPN 列表。
h2object否HTTP/2 参数:settings、windowUpdate、akamai_fingerprint、headerOrder。
userAgentstring否该指纹对应的 User-Agent。
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  --data-binary @captured.json \
  http://127.0.0.1:8891/api/v1/port/20134/custom_tls
响应
{
  "ok": true,
  "mode": "custom",
  "profile": {
    "name": "custom_1757116800123",
    "ja3_hash": "cd08e31494f9531f560d64c695473da9",
    "ja4": "t13d1516h2_8daaf6152771_b0da82dd1658",
    "userAgent": "Mozilla/5.0 …"
  }
}
  • 副作用:h2_spoofing 与 spoof_user_agent 会被强制关闭——在所提供形态之上再伪装 HTTP/2 会破坏重连。如需启用,请在该请求之后用各自的接口单独开启。
  • 第二个副作用:端口先前的 custom 配置文件会被删除,且现有连接会被关闭——否则部分流量仍会沿用旧形态。
  • 第三个副作用:端口已解决的验证会被清除——新的 TLS 形态与 User-Agent 会使在旧身份下获取的通行凭据失效,下一个访问受保护站点的请求会再次遇到验证。PUT /api/v1/port/{port}/upstream 中地址确实发生变化时也是同样的效果。
  • 请求体无法解析时返回 400 “invalid JSON: …”;引擎拒绝该形态时返回 400 “failed to set custom TLS: …”。后者最常见的原因是请求体缺少 ciphers 或名称不在表内:400 “failed to set custom TLS: building custom profile: building ClientHelloSpec: no recognized cipher suites”。仅含 ja3、ja4 与 userAgent 的精简采集并不够;POST /api/v1/fingerprint/parse 会返回形态正确的请求体。
  • 该路径未注册 GET,请求会落到控制面板的兜底路由:返回的是纯文本 “404 page not found” 的 404,而非 JSON;此处的 404 并不表示端口已关闭——请勿据此重新打开端口。当前构成请通过 /profile/view 读取;其他方法(POST、DELETE)返回 405。
  • 🔴 响应中的配置文件名称不是 custom:服务器每次请求都会重新生成,形如 custom_<毫秒时间戳>(例如 custom_1757116800123),GET /api/v1/port/{port}/profile 与 GET /api/v1/port/{port}/profile/view 返回的也是该名称。请勿与固定字符串比较;也无法通过 mode=specific 配合 specific_profile=custom 固定该配置文件——会返回 400 “fingerprint: profile "custom" not found”。

网络出口

端口以何种方式访问外网,以及当出口替换 TLS 时该怎么办。

GET/api/v1/port/{port}/upstream需要鉴权

返回端口的出口代理。空值表示直连出口。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/upstream
响应
{
  "socks5_addr": "socks5://user:pass@host:1080",
  "upstream": "socks5://user:pass@host:1080"
}
  • socks5_addr 字段是为旧客户端保留的旧名称;其值始终与 upstream 相同。
PUT/api/v1/port/{port}/upstream需要鉴权

在端口运行时更换出口代理——轮换代理时无需关闭端口。

参数类型必填说明
upstreamstring否形如 scheme://[user:pass@]host:port 的地址;支持 socks5、socks5h、http。空请求体或空字符串会让端口恢复直连出口。
socks5_addrstring否同一字段的旧别名;仅当 upstream 为空时才会被读取。
请求体
{ "upstream": "socks5://user:pass@host:1080" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"upstream":"socks5://user:pass@host:1080"}' \
  http://127.0.0.1:8891/api/v1/port/20134/upstream
响应
{
  "socks5_addr": "socks5://user:pass@host:1080",
  "upstream": "socks5://user:pass@host:1080"
}
  • 当地址确实发生变化时的副作用:端口已解决的验证会被清除,因为通行凭据是发给旧出口地址的,在新地址上不再有效。下一个访问受保护站点的请求会再次遇到验证。
  • 缓存的拨号会被重置,指向旧出口的空闲连接会被关闭。
GET/api/v1/port/{port}/chain_proxy需要鉴权

返回中间代理——出口代理之前的链路首跳。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/chain_proxy
响应
{
  "chain_proxy": "http://10.0.0.5:3128"
}
PUT/api/v1/port/{port}/chain_proxy需要鉴权

设置或清除中间代理:流量路径为 客户端 → 链路 → 出口 → 站点。

参数类型必填说明
chain_proxystring是格式与 upstream 相同的地址。空字符串表示移除该跳。
请求体
{ "chain_proxy": "http://10.0.0.5:3128" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"chain_proxy":"http://10.0.0.5:3128"}' \
  http://127.0.0.1:8891/api/v1/port/20134/chain_proxy
响应
{
  "chain_proxy": "http://10.0.0.5:3128"
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/allow_mitm_upstream需要鉴权

报告是否允许使用会替换 TLS 的出口,以及已因此拒绝了多少连接。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/allow_mitm_upstream
响应
{
  "allow_mitm_upstream": false,
  "mitm_blocked": 17,
  "mitm_last_issuer": "CN=Corporate Proxy CA"
}
  • mitm_blocked 与 mitm_last_issuer 直接回答了“为什么指纹没有生效”:最近一次被替换证书的签发者会被明确列出。
PUT/api/v1/port/{port}/allow_mitm_upstream需要鉴权

允许或禁止通过会拆解并重组 TLS 的出口工作。

参数类型必填说明
allow_mitm_upstreambool是true 表示即使经由此类出口也继续工作;false 表示拒绝经由它的连接。默认关闭:此类出口会抹掉指纹,端口会在无声无息中不再完成它被打开的目的。
请求体
{ "allow_mitm_upstream": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"allow_mitm_upstream":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/allow_mitm_upstream
响应
{
  "allow_mitm_upstream": true,
  "mitm_blocked": 17,
  "mitm_last_issuer": "CN=Corporate Proxy CA"
}
  • 若请求体中没有该字段,返回 400 “allow_mitm_upstream is required”。这是唯一一个能区分“未发送”与 false 的布尔端口接口,它会拒绝而不是静默关闭。

协议行为

端口如何处理 TLS、HTTP/2 与请求头。本组接口结构相同:请求体字段名为 enabled,响应回显所应用的值。

GET/api/v1/port/{port}/h2_spoofing需要鉴权

报告 HTTP/2 设置是否伪装为所选浏览器。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/h2_spoofing
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/h2_spoofing需要鉴权

开启或关闭 HTTP/2 设置伪装。

参数类型必填说明
enabledbool是true 表示 SETTINGS 帧、优先级与伪头顺序均取自浏览器配置文件。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/h2_spoofing
响应
{
  "enabled": true
}
  • PUT /custom_tls 会强制关闭该设置——请在提交自有指纹之后再开启。
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/spoof_user_agent需要鉴权

报告请求的 User-Agent 是否被伪装。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/spoof_user_agent
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/spoof_user_agent需要鉴权

开启或关闭 User-Agent 伪装。

参数类型必填说明
enabledbool是true 表示取自配置文件;false 表示逐字节转发客户端自身的请求头。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/spoof_user_agent
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/spoof_headers需要鉴权

报告请求头的集合与顺序是否被调整为浏览器的形态。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/spoof_headers
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/spoof_headers需要鉴权

开启或关闭浏览器形态的请求头处理。

参数类型必填说明
enabledbool是true 表示请求头的集合、大小写与顺序均与浏览器配置文件一致。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/spoof_headers
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/tls_passthrough需要鉴权

报告 TLS 是否在不拆解的情况下直通。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/tls_passthrough
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/tls_passthrough需要鉴权

开启或关闭 TLS 直通。

参数类型必填说明
enabledbool是true 表示连接原样透传:客户端自身的指纹得以保留,内容不被读取,此时该端口上的缓存与请求日志没有意义。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/tls_passthrough
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/tls_mirror需要鉴权

报告是否以客户端自身的 TLS 参数替代配置文件参数。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/tls_mirror
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/tls_mirror需要鉴权

开启或关闭对客户端 TLS 参数的镜像。

参数类型必填说明
enabledbool是true 表示对外发送取自客户端本身的形态,而非配置文件中的形态。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/tls_mirror
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/http3需要鉴权

报告端口是否允许 HTTP/3(QUIC)。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/http3
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/http3需要鉴权

允许或禁止 HTTP/3(QUIC)。

参数类型必填说明
enabledbool是true 表示当站点提供 HTTP/3 时端口会加以使用。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/http3
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/session_resumption需要鉴权

报告是否允许 TLS 会话恢复。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/session_resumption
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/session_resumption需要鉴权

允许或禁止 TLS 会话恢复(会话票据)。

参数类型必填说明
enabledbool是true 表示接受并复用会话票据;false 表示每个连接都从完整握手开始。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/session_resumption
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/decompress需要鉴权

报告是否为客户端解压响应体。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/decompress
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/decompress需要鉴权

开启或关闭响应体解压。

参数类型必填说明
enabledbool是true 表示在交付客户端之前把 br、gzip 与 zstd 解压为普通字节。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/decompress
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/cache_ignore_no_cache需要鉴权

报告是否忽略 no-cache 头进行缓存。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/cache_ignore_no_cache
响应
{
  "enabled": true
}
PUT/api/v1/port/{port}/cache_ignore_no_cache需要鉴权

开启或关闭无视 no-cache 的缓存。

参数类型必填说明
enabledbool是true 表示即使站点要求不缓存,响应仍会被写入缓存。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/cache_ignore_no_cache
响应
{
  "enabled": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/auto_profile_from_ua需要鉴权

报告是否按请求的 User-Agent 选择配置文件,并显示最近一次的该请求头。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/auto_profile_from_ua
响应
{
  "enabled": true,
  "last_ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) …"
}
PUT/api/v1/port/{port}/auto_profile_from_ua需要鉴权

开启或关闭按请求 User-Agent 选择配置文件。

参数类型必填说明
enabledbool是true 表示由应用自行指定要伪装的身份:端口按收到的 User-Agent 选取配置文件。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/auto_profile_from_ua
响应
{
  "enabled": true
}
  • PUT 的响应中没有 last_ua——它只出现在 GET 的响应里,且要等端口收到第一个请求之后。这是验证该模式在真实流量上生效的唯一方法。
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。

负载、重试与空闲

端口同时承载多少请求、发生网络错误后如何处理,以及何时自行关闭。

GET/api/v1/port/{port}/max_concurrent需要鉴权

返回端口的并发请求上限。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/max_concurrent
响应
{
  "max_concurrent": 32
}
PUT/api/v1/port/{port}/max_concurrent需要鉴权

修改并发请求上限。

参数类型必填说明
max_concurrentint是0 及以上;0 表示不限。
请求体
{ "max_concurrent": 32 }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"max_concurrent":32}' \
  http://127.0.0.1:8891/api/v1/port/20134/max_concurrent
响应
{
  "max_concurrent": 32
}
  • 取负值时返回 400 “max_concurrent must be >= 0 (0 = unlimited)”。
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/sem_timeout需要鉴权

返回请求在并发上限内等待空位的秒数。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/sem_timeout
响应
{
  "timeout_seconds": 30
}
PUT/api/v1/port/{port}/sem_timeout需要鉴权

修改等待空位的时长。🔴 字段名为 timeout_seconds,而非 sem_timeout。

参数类型必填说明
timeout_secondsint是1 及以上——等待的秒数。
请求体
{ "timeout_seconds": 30 }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"timeout_seconds":30}' \
  http://127.0.0.1:8891/api/v1/port/20134/sem_timeout
响应
{
  "timeout_seconds": 30
}
  • 为 0 或负数时返回 400 “timeout_seconds must be >= 1”。
  • 写成 {"sem_timeout": 30}——按路径而非字段命名——会被解析为 0 并以 400 拒绝。
GET/api/v1/port/{port}/skip_retry需要鉴权

报告网络错误后是否重试请求。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/skip_retry
响应
{
  "skip_retry": false
}
PUT/api/v1/port/{port}/skip_retry需要鉴权

开启或关闭跳过重试。

参数类型必填说明
skip_retrybool是true 表示网络错误后不重试,立即把错误返回给客户端。
请求体
{ "skip_retry": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"skip_retry":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/skip_retry
响应
{
  "skip_retry": true
}
  • 字段名必须与此完全一致。服务器会静默丢弃未知字段名,请求随即写入零值:布尔为 false,字符串为空——并且返回 200。
GET/api/v1/port/{port}/retry_delay需要鉴权

返回重试之间的间隔(毫秒)。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/retry_delay
响应
{
  "retry_delay_ms": 500
}
PUT/api/v1/port/{port}/retry_delay需要鉴权

修改重试间隔。🔴 字段名为 retry_delay_ms,而非 retry_delay。

参数类型必填说明
retry_delay_msint是0 及以上——毫秒。
请求体
{ "retry_delay_ms": 500 }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"retry_delay_ms":500}' \
  http://127.0.0.1:8891/api/v1/port/20134/retry_delay
响应
{
  "retry_delay_ms": 500
}
  • 取负值时返回 400 “retry_delay_ms must be >= 0”。
  • 写成 {"retry_delay": 500} 会被当作 0 通过校验,并以 200 响应把间隔设为 0 毫秒。
PUT/api/v1/port/{port}/idle需要鉴权

设置该端口的空闲超时,覆盖全局值。它没有 GET——当前值可在 GET /api/v1/port/{port}/config 的响应中以 idle_seconds 查看。

参数类型必填说明
secondsint | null是自动关闭前的空闲秒数。null 表示移除覆盖、恢复全局超时;0 表示永不关闭。
请求体
{ "seconds": 1800 }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"seconds":1800}' \
  http://127.0.0.1:8891/api/v1/port/20134/idle
响应
{
  "status": "ok"
}
  • 响应中不包含所设置的值——只有 status。请通过 GET /config 核对。
  • 取负值时返回 400 “seconds must be >= 0”;端口已关闭时返回 404。
  • 这是唯一不把调用计为活动的端口接口:它自行解析端口号,绕过了共用的辅助函数。

调试指纹采集

以 debug_capture 打开的端口会把所有连接者的指纹保存在环形缓冲区中。由此可以查看网络本身看到的客户端形态。采集端口需要 Pro 许可:没有它时,带 debug_capture 的 POST /api/v1/ports/open 会返回 403 “the debug fingerprint port requires a Pro license”。

GET/api/v1/port/{port}/captures需要鉴权

返回调试采集端口所采集的指纹,按由旧到新排列。

参数类型必填说明
sinceint否仅返回序号大于该值的采集记录。
limitint否最多返回多少条;为 0 或不传表示全部。
示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  "http://127.0.0.1:8891/api/v1/port/20134/captures?since=0&limit=50"
响应
{
  "count": 128,
  "captures": [
    {
      "seq": 1,
      "time": "2026-09-06T12:34:56.789+03:00",
      "domain": "example.com",
      "client_addr": "127.0.0.1:54321",
      "alpn": "h2",
      "method": "GET",
      "path": "/",
      "ua": "Mozilla/5.0 …",
      "status": "ok",
      "tls": {
        "ja3": "771,4865-4866-4867-…",
        "ja3_hash": "cd08e31494f9531f560d64c695473da9",
        "ja4": "t13d1516h2_8daaf6152771_b0da82dd1658",
        "client_hello_hex": "16030103…"
      },
      "h2": {
        "available": true,
        "akamai": "1:65536;2:0;4:6291456;6:262144|15663105|0|m,a,s,p",
        "settings": [ { "id": 1, "val": 65536 } ],
        "window_update": 15663105,
        "pseudo_order": ["m", "a", "s", "p"],
        "header_order": ["accept", "user-agent", "accept-encoding"]
      }
    }
  ]
}
  • 🔴 指纹位于采集记录内部:TLS 在 captures[].tls(ja3、ja3_hash、ja4、client_hello_hex),HTTP/2 在 captures[].h2(available、akamai、settings、window_update、pseudo_order、header_order),User-Agent 则是 captures[].ua。顶层没有 ja3_hash、ja4 和 user_agent 字段。
  • 当 TLS 与 HTTP/2 都采集到时 status 为 ok;当客户端未完成 h2 握手(证书固定或普通 HTTP/1.1)时为 tls-only:此时 captures[].h2.available 为 false,h2 块的其余字段缺失。
  • method、path、ua、tls.client_hello_hex 以及 h2 块中除 available 外的所有字段均为可选:未采集到该值时,响应中不会出现该键。
  • count 表示缓冲区中的采集总数,与 since、limit 无关。
  • 若端口未以 debug_capture 打开,返回 400 “port is not a debug fingerprint-capture port”。
  • 环形缓冲区的大小在打开端口时用 debug_capture_n 字段设定,默认 500 条;溢出时最旧的记录被丢弃。
DELETE/api/v1/port/{port}/captures需要鉴权

清空调试采集端口的环形缓冲区。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/captures
响应
{
  "count": 0,
  "captures": []
}
  • 在普通端口上返回 400 “port is not a debug fingerprint-capture port”。

响应缓存

缓存按端口启用,并以四种模式之一工作。普通缓存与硬缓存是两个不同的存储,而不是同一存储的不同设置。

模式含义
normal普通缓存:随应用运行而存在,遵循响应头,并在条目过期时向服务器重新校验。
hard硬缓存:可跨重启保留(SQLite 存储),并且从不重新校验——因此易变的响应根本不会被收录。
hard-media仅对图片、字体、音频与视频使用硬缓存:其余内容一概不缓存。
hard-autowarm硬缓存,仅在同一地址连续三次返回完全相同的响应体后才收录——即内容已证明为静态。
警告缓存条目由所有端口共享:键由方法、协议、主机以及带查询的路径构成,其中不含端口号。存储中不存在按身份的隔离,防护以另一种方式实现:带 Set-Cookie、Cache-Control: no-store 或 private、Vary: *、Vary: Cookie 或 Vary: Authorization 的响应一律不收录;并且在返回时会剥离 ETag 与 Last-Modified,使发给某一身份的校验器不会经由另一身份回显,从而把两者关联起来。
GET/api/v1/port/{port}/cache需要鉴权

端口缓存的状态:是否启用、处于哪种模式,以及已经节省了多少。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/cache
响应
{
  "enabled": true,
  "mode": "hard",
  "hits": 18420,
  "misses": 2210,
  "entries": 1842,
  "used_bytes": 268435456,
  "max_bytes": 2147483648,
  "saved_bytes": 913000000
}
  • 缓存关闭时 mode 为空。saved_bytes 表示因命中缓存而无需重新下载的字节数。
PUT/api/v1/port/{port}/cache需要鉴权

在端口运行时开启、关闭缓存或切换其模式。

参数类型必填说明
modestring否normal、hard、hard-media、hard-autowarm,或留空。
enabledbool否仅在模式不是硬缓存时才被读取。false 关闭缓存;在硬缓存模式下该字段被忽略。
请求体
{ "mode": "hard-media" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"mode":"hard-media"}' \
  http://127.0.0.1:8891/api/v1/port/20134/cache
响应
{
  "enabled": true,
  "mode": "hard-media",
  "hits": 18420,
  "misses": 2210,
  "entries": 1842,
  "used_bytes": 268435456,
  "max_bytes": 2147483648,
  "saved_bytes": 913000000
}
  • 🔴 关闭缓存只有一种请求体:{"enabled": false} 且不带 mode。其他任何请求体——包括空的 {}——都会以 normal 模式开启缓存。
  • 其他模式一律返回 400 “invalid cache mode: must be one of normal, hard, hard-media, hard-autowarm”。
  • 🔴 响应返回的是精确的模式名:hard-media 与 hard-autowarm 不会折叠为 hard。校验是否生效时,应将 mode 与您所发送的值比较,而不是与字符串 hard 比较。GET /api/v1/port/{port}/cache 以及 /status、/ports 的 cache_mode 字段返回同一字符串。
  • 响应与 GET 返回的状态相同:处理程序直接以其作答。
DELETE/api/v1/port/{port}/cache需要鉴权

清空该端口的缓存,不影响其他端口。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/cache
响应
{
  "status": "cleared"
}
  • 处于硬缓存模式的端口清空的是共享硬存储——与 DELETE /api/v1/cache/hard 清空的是同一个。
GET/api/v1/cache/hard需要鉴权

硬缓存的整体状态:条目数、占用空间与已节省的流量。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/cache/hard
响应
{
  "enabled": true,
  "mode": "hard",
  "hits": 18420,
  "misses": 2210,
  "entries": 1842,
  "used_bytes": 268435456,
  "max_bytes": 2147483648,
  "saved_bytes": 913000000
}
DELETE/api/v1/cache/hard需要鉴权

整体清空硬缓存——一次性影响所有端口。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/cache/hard
响应
{
  "status": "hard cache cleared"
}
POST/api/v1/cache/hard/evict需要鉴权

按模式列表从硬缓存中驱逐条目——精确清除,而不是整体清空。

参数类型必填说明
patternsarray是域名或完整 URL。该列表必填。
请求体
{ "patterns": ["example.com", "https://cdn.example.net/img/logo.png"] }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"patterns":["example.com"]}' \
  http://127.0.0.1:8891/api/v1/cache/hard/evict
响应
{
  "evicted": 37
}
  • 列表为空时返回 400 “patterns list is required”。该接口没有 domain 字段。
POST/api/v1/cache/evict需要鉴权

对普通缓存执行同样的操作:按模式列表驱逐条目。

参数类型必填说明
patternsarray是域名或完整 URL。该列表必填。
请求体
{ "patterns": ["example.com"] }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"patterns":["example.com"]}' \
  http://127.0.0.1:8891/api/v1/cache/evict
响应
{
  "evicted": 12
}
  • 列表为空时返回 400 “patterns list is required”。
POST/api/v1/cache/hard/save需要鉴权

为旧客户端保留:硬缓存位于 SQLite 中,每次写入即落盘,无需单独刷新。该接口只是返回状态。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/cache/hard/save
响应
{
  "status": "persisted",
  "entries": 1842,
  "info": "SQLite-backed cache is already persistent"
}
GET/api/v1/cache/hard/exclusions需要鉴权

硬缓存所避开的域名与地址。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/cache/hard/exclusions
响应
{
  "exclusions": ["api.example.com", "*.example.net/checkout"]
}
PUT/api/v1/cache/hard/exclusions需要鉴权

把所给模式追加到硬缓存排除列表,而不是替换该列表。

参数类型必填说明
exclusionsarray是不应缓存的域名或地址掩码。
请求体
{ "exclusions": ["api.example.com"] }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"exclusions":["api.example.com"]}' \
  http://127.0.0.1:8891/api/v1/cache/hard/exclusions
响应
{
  "exclusions": ["api.example.com", "*.example.net/checkout"]
}
  • 🔴 用 PUT 发送更短的列表不会删除任何条目:列表只会增长,所发送的内容会与原有内容去重合并。删除请使用 DELETE。
  • 响应为合并后的完整列表。
DELETE/api/v1/cache/hard/exclusions需要鉴权

从硬缓存排除列表中删除所列出的模式。必须带请求体。

参数类型必填说明
exclusionsarray是要从列表中删除的条目。
请求体
{ "exclusions": ["api.example.com"] }
示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"exclusions":["api.example.com"]}' \
  http://127.0.0.1:8891/api/v1/cache/hard/exclusions
响应
{
  "exclusions": ["*.example.net/checkout"]
}
  • 🔴 这不是“清空列表”。不带请求体的 DELETE 会返回 400 “invalid JSON body”。若要清空列表,请在请求体中列出 GET 返回的全部条目。
  • 🔴 如果列出全部条目导致列表清空,响应会是 {"exclusions": null},而不是空数组——与普通缓存一致。
GET/api/v1/cache/exclusions需要鉴权

对普通缓存执行同样的操作:排除列表。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/cache/exclusions
响应
{
  "exclusions": ["login.example.com"]
}
PUT/api/v1/cache/exclusions需要鉴权

把模式追加到普通缓存的排除列表。

参数类型必填说明
exclusionsarray是不应缓存的域名或地址掩码。
请求体
{ "exclusions": ["login.example.com"] }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"exclusions":["login.example.com"]}' \
  http://127.0.0.1:8891/api/v1/cache/exclusions
响应
{
  "exclusions": ["login.example.com"]
}
  • 🔴 该接口的响应只显示您所发送的内容,而不是合并后的完整列表——这一点与硬缓存不同。完整列表请通过 GET 获取。
DELETE/api/v1/cache/exclusions需要鉴权

从普通缓存排除列表中删除所列出的模式。必须带请求体。

参数类型必填说明
exclusionsarray是要从列表中删除的条目。
请求体
{ "exclusions": ["login.example.com"] }
示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"exclusions":["login.example.com"]}' \
  http://127.0.0.1:8891/api/v1/cache/exclusions
响应
{
  "exclusions": null
}
  • 🔴 当删除后列表为空时,该字段返回 null,而不是 []。此接口永远不会返回空数组,因此写成 resp.exclusions.map(…) 或 for … of 的客户端恰恰会在“完全清空成功”时抛错——请先判 null。同一列表的 GET 在该状态下返回 []:GET 与 DELETE 的响应形态不同。
  • 不带请求体的 DELETE 会返回 400 “invalid JSON body”。

端口请求日志

日志为每个经过该端口的请求写入一行 JSON:时间、方法、主机、路径、状态码、响应体类型与大小、缓存相关请求头以及缓存判定。用它来分析缓存为何未命中、流量去了哪里。

警告该日志是磁盘上的访问历史。它写入应用旁的 data/traffic_port_<端口>.jsonl,可跨重启保留(文件是追加写入,而非重新开始),并会增长到上限,超出后旧记录会被淘汰。关闭日志只会关闭文件,并不会删除它。
GET/api/v1/port/{port}/traffic_log需要鉴权

报告日志是否开启、文件位置以及其中的记录数。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/traffic_log
响应
{
  "enabled": true,
  "path": "data/traffic_port_20134.jsonl",
  "entries": 4821
}
  • 🔴 entries 是记录的数量,而不是记录本身。记录请通过 /traffic_log/download 获取。
  • 该计数描述的是文件而非本次会话:重启后它显示磁盘上已有的全部记录。
  • 日志关闭时,响应为 {"enabled": false, "entries": 0}:不含 path,但 entries 始终存在且为 0。请通过 enabled 区分“已关闭”与“已开启但为空”,而不是通过 entries 键是否存在。
PUT/api/v1/port/{port}/traffic_log需要鉴权

在端口运行时开启或关闭日志。开启时,如文件尚不存在则会创建。

参数类型必填说明
enabledbool是true 开始写入;false 关闭文件并停止写入。
请求体
{ "enabled": true }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"enabled":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/traffic_log
响应
{
  "enabled": true,
  "path": "data/traffic_port_20134.jsonl",
  "entries": 4821
}
  • 响应与 GET 返回的状态相同。
  • 若无法创建文件(例如 data 目录不可写),返回 500 “failed to create traffic log: …”。
  • 字段必须命名为 enabled:未知字段名会被视为 false,即以 200 响应关闭日志。
GET/api/v1/port/{port}/traffic_log/download需要鉴权

返回完整的日志文件——每个请求一行 JSON(NDJSON 格式)。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" -o traffic.jsonl \
  http://127.0.0.1:8891/api/v1/port/20134/traffic_log/download
响应
{"ts":"2026-09-06T11:22:33Z","method":"GET","scheme":"https","host":"example.com",
 "path":"/static/app.js","status":200,"content_type":"application/javascript",
 "content_len":184320,"cache_control":"max-age=31536000","cache":"hit","proto":"h2","port":20134}
  • Content-Type 为 application/x-ndjson,附件名为 traffic_port_<端口>.jsonl。cache 字段的取值为 hit、miss、stale、excluded 与 skip。
  • 若日志已关闭,返回 400 “traffic logging is not enabled”。
DELETE/api/v1/port/{port}/traffic_log需要鉴权

清空日志文件,同时保持日志处于开启状态。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/traffic_log
响应
{
  "status": "cleared"
}
  • 若日志已关闭,返回 400 “traffic logging is not enabled”:该接口无法清空已关闭日志的文件——请先将其开启。

系统流量拦截与泄漏审计

拦截可在应用自身无需配置代理的情况下,把某个程序或整台机器的流量引入端口。泄漏审计回答相反的问题:被观察的程序是否绕过了拦截。

GET/api/v1/system/intercept需要鉴权

特权拦截服务当前是否可用。应在打开端口之前查询:否则只有在填完表单后才会收到拒绝。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/system/intercept
响应
{
  "available": false,
  "code": "not_installed",
  "reason": "привилегированная служба перехвата не установлена — установите её из установщика BlankTrail"
}
  • code 与 reason 并非重复:程序依据 code 分支,人阅读 reason。两个字段始终存在——当 available=true 时它们为空。
  • code 的取值:off——该构建或该平台不支持拦截;not_installed——服务未安装;unreachable——服务无响应;busy——已有另一份应用副本在控制拦截,服务一次只服务一个客户端。
GET/api/v1/system/processes需要鉴权

用于选择按进程拦截目标的应用列表。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/system/processes
响应
[
  { "name": "chrome.exe", "path": "C:\\Program Files\\Google\\Chrome\\chrome.exe",
    "count": 7 },
  { "name": "curl.exe", "path": "C:\\Windows\\System32\\curl.exe", "count": 1 }
]
  • 列表项是可执行文件而非进程:拦截规则绑定到 exe,因此七个浏览器窗口只对应一行且 count = 7。路径已归一化——正是它应当写入 intercept_apps。
  • 在无法枚举进程的平台上返回 501:空数组与“没有进程”无法区分,用户会看到一张空的选择表,而不是一段说明。
POST/api/v1/system/leak-audit需要鉴权

开始一次观察会话:查看所选程序是否绕过拦截。

参数类型必填说明
exe_pathsarray是要观察的可执行文件路径。🔴 字段名为 exe_paths,而不是 paths。
policystring是observe 仅观察;block 还会切断绕过的流量。
请求体
{ "exe_paths": ["C:\\Program Files\\App\\app.exe"], "policy": "observe" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"exe_paths":["C:\\Program Files\\App\\app.exe"],"policy":"observe"}' \
  http://127.0.0.1:8891/api/v1/system/leak-audit
响应
{
  "started": true,
  "code": "",
  "reason": ""
}
  • 🔴 启动被拒绝时会以 200 与 started=false 返回:此处的 200 并不表示观察已开始。应检查 started 字段,而不是响应状态码。
  • 返回 200 时的拒绝代码:ipv6_present——本机存在有效的全局 IPv6,而路由捕获无法覆盖它;session_active——已有会话在运行;rule_conflict——规则与当前拦截冲突;service_outdated 与 service_version_unknown——服务版本过旧或无法确定。
  • 列表为空时返回 400 且 code 为 no_paths;请求体无法解析或 policy 既非 observe 也非 block 时,code 为 invalid_request。若端口管理器未启动,返回 503。
GET/api/v1/system/leak-audit需要鉴权

当前会话的状态:判定、聚合数据、可信边界,以及最近的事件尾部。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/system/leak-audit
响应
{
  "exe_paths": ["C:\\Program Files\\App\\app.exe"],
  "policy": "observe",
  "started_at": "2026-09-06T11:00:00Z",
  "verdict": "leaking",
  "confirmed": true,
  "by_class": { "dns_direct": 12, "ip_direct": 3 },
  "top_targets": [ { "addr": "203.0.113.7:443", "count": 9 } ],
  "dropped": 0,
  "udp_exhausted": 0,
  "client_trimmed": 0,
  "connection_interrupted": false,
  "audit_unavailable": false,
  "stopped_by": "",
  "limits": ["attribution_by_exe"],
  "recent_events": []
}
  • verdict 有三种取值:clean、leaking 与 inconclusive。最后一种是诚实的“无法确定”——例如审计日志不可用或事件被丢弃时。
  • limits 列出本次运行的可信边界:attribution_by_exe(规则绑定到 exe 而非进程)、start_window(从请求规则到其生效之间的窗口)、events_dropped、udp_exhausted、connection_interrupted、audit_unavailable、stopped_by_watchdog 等。脱离它们不能解读判定。
  • 在会话开始之前返回 404 “сеанс аудита утечек не запущен”:空报告并不比沉默更诚实。
GET/api/v1/system/leak-audit/report需要鉴权

不含事件流的报告——用于导出结果。若没有进行中的会话,则返回最近一次已结束会话的报告。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/system/leak-audit/report
  • 若同样没有已完成的报告,返回 404 “аудит утечек ни разу не запускался”。
DELETE/api/v1/system/leak-audit需要鉴权

停止会话,并以与 GET 相同的形态返回最终报告。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/system/leak-audit
  • 若没有会话,返回 404。会话停止后,stopped_by 字段说明是谁结束了它——是人,还是自行中止过长观察的看门狗。

端口检查

针对运行端口的两项检查,外加一个辅助接口。完整测试会让请求穿过端口,并把外部看到的形态与它本打算伪装的身份进行比对。

POST/api/v1/port/{port}/test需要鉴权

端口配置的完整测试:出口泄漏、穿透端口的指纹以及 UDP 支持。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/test
响应
{
  "leak": {
    "exit_ip": "203.0.113.45",
    "egress_resolver": "203.0.113.53",
    "host_resolver": "192.0.2.1",
    "dns": "pass",
    "ipv6": "pass",
    "latency_ms": 214,
    "checked_at": "2026-09-06T11:03:01Z"
  },
  "leak_skipped": false,
  "fingerprint": {
    "ran": true,
    "skipped": false,
    "observed_ja3": "cd08e31494f9531f560d64c695473da9",
    "observed_ja4": "t13d1516h2_8daaf6152771_b0da82dd1658",
    "observed_ua": "Mozilla/5.0 …",
    "expected_ja4": "t13d1516h2_8daaf6152771_b0da82dd1658",
    "expected_ua": "Mozilla/5.0 …",
    "match": true
  },
  "udp": { "checked": true, "supported": true, "detail": "DNS round-trip via UDP ASSOCIATE",
           "verdict": "relays" },
  "ok": true,
  "messages": [],
  "checked_at": "2026-09-06T11:03:01Z"
}
  • 指纹检查会经由该端口访问外部指纹服务:match=false 表示实际发出的形态与端口所承诺的不一致。
  • leak_skipped=true 与 leak_skip_reason 区分两种情况:disabled——端口设置中关闭了该检查;direct——出口为直连,没有可探测的内容。这并不等于“没有泄漏”。
  • fingerprint.skipped 且原因为 passthrough 并非失败:TLS 直通时不存在替换,无从观察。
  • udp.supported=true 表示经由出口完成了一次 DNS 往返。仅获准 UDP ASSOCIATE 而无响应不算支持——判定为 accepted_but_silent。
  • 该测试上限为 15 秒。
POST/api/v1/port/{port}/leakcheck需要鉴权

仅进行出口泄漏检查:比较应答的解析器归属,以及可见的 IPv6 归属。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/port/20134/leakcheck
响应
{
  "report": {
    "exit_ip": "203.0.113.45",
    "egress_resolver": "203.0.113.53",
    "host_resolver": "192.0.2.1",
    "dns": "pass",
    "ipv6": "leak",
    "ipv6_addr": "2001:db8::1",
    "host_ipv6": "2001:db8::1",
    "latency_ms": 214,
    "checked_at": "2026-09-06T11:03:01Z"
  }
}
  • dns 与 ipv6 字段有三种取值:pass、leak 与 inconclusive。该接口没有 webrtc 与 verdict 字段。
  • 🔴 在直连出口的端口上,响应为 {"skipped": true} 且不含报告,状态码 200。这表示“未检查”,而不是“没有泄漏”。
  • ipv6_addr 与 host_ipv6 并列本身就是证据:两者相同即表示外部看到的是本机地址,说明绕过了隧道。该检查上限为 12 秒。
POST/api/v1/port/{port}/generate需要鉴权

为所请求的浏览器与版本生成配置文件,并应用到该端口。

参数类型必填说明
browserstring是chrome、firefox、safari 或 edge。
versionint否浏览器版本;0 表示默认版本。
osstring否windows、macos、linux、ios 或 android;留空表示 windows。
savebool否把配置文件保存到数据库以便重复使用。
请求体
{ "browser": "chrome", "version": 152, "os": "windows", "save": true }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"browser":"chrome","version":152,"os":"windows"}' \
  http://127.0.0.1:8891/api/v1/port/20134/generate
  • 400 “browser is required (chrome, firefox, safari, edge)”、400 “browser must be one of: chrome, firefox, safari, edge”、400 “os must be one of: windows, macos, linux, ios, android”;若无法生成配置文件,返回 500 并附带引擎文本。