API — 端口与流量
打开、关闭、列出和配置代理端口,并在正式使用前测试上游代理。这些是集成 BlankTrail Proxy 时最常用的接口。
打开端口
一个请求即可启动本地代理端口并一次性设定其全部行为。字段很多,但必填的只有一个——port;其余取默认值,之后也可在端口运行时修改。
/api/v1/ports/open需要鉴权以给定的身份与行为启动一个代理端口。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
port | int | 是 | 端口号,1–65535。 |
protocol | string | 否 | http(默认)、socks5 或 mtproto。 |
upstream | string | 否 | 出口代理;留空表示直连。 |
mode | string | 否 | 如何选择身份:random、db、auto、specific、custom。 |
browser | string | 否 | 浏览器过滤条件;与 mode=random 不兼容。 |
os | string | 否 | 操作系统过滤条件;与 mode=random 不兼容。 |
{
"port": 20134,
"protocol": "socks5",
"mode": "db",
"browser": "chrome",
"os": "windows",
"upstream": "socks5://user:pass@host:1080"
}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… 密钥,包括自动生成的)。
网络出口
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
upstream | string | — | 出口代理:scheme://[user:pass@]host:port,支持 socks5、socks5h、http。为空表示直连出口。 |
chain_proxy | string | — | 出口代理之前的链路首跳。 |
upstream_gateway | string | — | 已保存网关的名称;其本地 SOCKS5 将作为出口。 |
chain_gateway | string | — | 用于链路首跳的已保存网关名称。 |
ovpn_config | string | — | upstream_gateway 的旧别名,为兼容旧客户端而保留。 |
upstream_tls_insecure | bool | false | 对 https 代理关闭证书校验。仅适用于使用自签名证书的自有代理。 |
allow_mitm_upstream | bool | false | 允许自行拆解 TLS 的出口。默认禁止:此类出口会抹掉指纹。 |
egress_force_ipv4 | bool | true | 仅通过 IPv4 出口——防止 IPv6 泄漏。 |
block_private_targets | bool | true | 拒绝连接到私有、回环、链路本地与 CGNAT 地址:否则该代理会变成局域网的地图。 |
身份与协议
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
mode | string | random | random、db(别名 database)、auto、specific 或 custom。random 模式与 browser/os 过滤条件不兼容。 |
browser | string | — | 浏览器过滤条件:chrome、firefox、safari、edge、random;可带版本——chrome_145。 |
os | string | — | 操作系统过滤条件:windows、macos、linux、ios、android、random。 |
specific_profile | string | — | mode=specific 时的配置文件名称,例如 chrome_152_windows。 |
custom_tls | object | — | 用于 mode=custom 的完整已采集指纹;形态与 PUT /port/{port}/custom_tls 相同。 |
auto_profile_from_ua | bool | false | 按请求的 User-Agent 选择配置文件。 |
h2_spoofing | bool | — | 把 HTTP/2 设置伪装为浏览器配置文件的形态。 |
spoof_user_agent | bool | — | 伪装 User-Agent。关闭时逐字节转发客户端自身的请求头。 |
spoof_headers | bool | — | 把请求头的集合与顺序调整为浏览器的形态。 |
tls_passthrough | bool | false | TLS 原样透传、不做拆解:保留客户端指纹,不读取内容。 |
tls_mirror | bool | false | 拆解 TLS,但对外重放客户端自身的已采集指纹。 |
session_resumption | bool | — | 允许 TLS 会话恢复(会话票据)。 |
enable_http3 | bool | false | 当站点提供 h3 且出口支持 UDP 时,改用 HTTP/3 重新发起连接。 |
decompress | bool | — | 在交付客户端前解压 br/gzip/zstd。挑战解题器会强制开启该项。 |
负载与超时
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
max_concurrent | int | — | 并发请求上限;0 表示不限。 |
sem_timeout | int | — | 请求在该上限内等待空位的秒数。🔴 此处字段名为 sem_timeout——与独立接口中的 timeout_seconds 不同。 |
skip_retry | bool | false | 网络错误后不重试请求。 |
retry_delay_ms | int | — | 重试之间的间隔(毫秒)。 |
timeout_seconds | int | — | 连接(而非端口)的空闲超时,单位为秒。 |
connect_timeout_seconds | int | 5 | 单次拨号尝试的上限。 |
request_timeout_seconds | int | 30 | 包含重试在内的整个建立阶段的上限;0 表示不限。 |
idle_seconds | int | null | null | 端口的空闲超时,覆盖全局值(默认 30 分钟);0 表示永不关闭。 |
缓存、日志与采集
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
cache_enabled | bool | false | 在端口上启用响应缓存。 |
cache_mode | string | normal | normal、hard、hard-media 或 hard-autowarm。 |
cache_ignore_no_cache | bool | false | 忽略 no-cache 头进行缓存。 |
traffic_log | bool | false | 把端口请求日志写入 data/traffic_port_<端口>.jsonl。 |
debug_capture | bool | false | 打开指纹采集端口。🔴 需要 Pro 许可:否则返回 403。 |
debug_capture_n | int | 500 | 采集端口上环形缓冲区的大小。 |
挑战与会话
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
js_solver | bool | false | 挑战解题器:遇到验证的请求会转入解题池。需要拆解 TLS(与 tls_passthrough 不兼容)。 |
keep_sessions | bool | false | 端口维护自己的按域名 Cookie 罐:吸收 Set-Cookie、注入 Cookie 并跟随重定向。与 js_solver 无关。 |
DNS 与泄漏防护
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
leak_guard | string | — | 启动前的出口 DNS/IPv6 泄漏检查:off、warn 或 enforce。 |
vdns_mode | string | off | 虚拟 DNS:off、on_leak(发现泄漏时启用)或 forced。Standard 及以上套餐:在 Lite 上该字段会被接受,端口以关闭 vdns 的状态打开,其 vdns_path_reason 为 plan。 |
resolver_strategy | string | auto | auto 或 custom——解析器的来源。 |
custom_resolvers | array | — | resolver_strategy=custom 时使用的 host:port 列表。 |
ecs_enabled | bool | true | 在 DNS 查询中传递客户端子网(EDNS Client Subnet)。 |
vdns_strict_bypass | bool | false | 严格绕过:只发送 IP 字面量,主机名不会离开本机。 |
require_udp_dns | bool | false | 仅在出口已证明可为 DNS 转发 UDP 时才打开端口。要求 vdns_mode 为 on_leak 或 forced,否则返回 400。 |
系统流量拦截
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
intercept | bool | false | 在应用无需配置代理的情况下把系统流量引入该端口。 |
intercept_scope | string | system | 🔴 system 表示整台机器(默认值),process 表示仅所列出的程序。 |
intercept_apps | array | — | scope=process 时的可执行文件路径。 |
MTProto(Telegram 代理)
以下字段仅在 protocol=mtproto 时有意义。该模式下端口使用 Telegram 的协议,而不是 HTTP 或 SOCKS5,Telegram 客户端通过响应中的链接连接它。
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
mtproto_secret | string | — | 形如 ee… 的规范密钥;留空则生成新的。 |
mtproto_camouflage_domain | string | www.google.com | 伪装域名——同时也是 Telegram 客户端所提供的 SNI。 |
mtproto_fallback_real | bool | true | 把探测者与密钥错误的客户端转接到真实的伪装站点。 |
mtproto_egress | string | auto | auto、obfuscated 或 faketls——如何连接上游 MTProto 代理。 |
mtproto_faketls_upstream | string | — | egress=faketls 时上游 MTProto 代理的 host:port。 |
mtproto_faketls_secret | string | — | 该上游代理的 ee… 密钥。 |
关闭端口
/api/v1/ports/close需要鉴权关闭已打开的端口,并断开经由它的所有连接。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
port | int | 是 | 要关闭的端口。 |
{ "port": 20134 }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。
- 启用拦截的端口在关闭时会同时移除其拦截规则——流量回到常规路由。
已打开端口的列表
/api/v1/ports需要鉴权返回所有已打开的端口及其完整配置与状态。
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。
推荐一个空闲端口
/api/v1/ports/suggest需要鉴权返回 20000–29999 区间内最小的、既未被管理器占用又能在系统层面成功绑定的端口号。
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,以及是否存在泄漏。
/api/v1/upstream/test需要鉴权检查出口是否可达、SOCKS5 上的 UDP 是否可用,以及 DNS 与 IPv6 是否泄漏。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
checks | array | 是 | http、udp、leak 中的任意组合。 |
protocol | string | 否 | socks5 或 http——未来端口的协议。 |
upstream | string | 否 | 出口代理;留空则测试直连。 |
chain_proxy | string | 否 | 链路首跳。 |
upstream_gateway | string | 否 | 用已保存网关的名称替代出口地址。 |
chain_gateway | string | 否 | 用于首跳的已保存网关名称。 |
upstream_tls_insecure | bool | 否 | 与同名端口设置保持一致:否则测试所检查的配置将与您即将打开的配置不同。 |
{
"checks": ["http", "udp", "leak"],
"protocol": "socks5",
"upstream": "socks5://user:pass@host:1080"
}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 则是修改那些没有独立接口的项的唯一方式。
/api/v1/port/{port}/status需要鉴权运行端口的概要:身份、行为、出口、拒绝计数与最近活动时间。
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 不仅由流量推进,对该端口任何接口的调用同样会推进它。
/api/v1/port/{port}/config需要鉴权端口配置的完整快照——全部约六十个键,包括那些没有独立接口的项。没有取值的键不会出现在快照中。
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 的合并也按同样的名称进行。
/api/v1/port/{port}/config需要鉴权修改运行端口的配置。所发送的字段会合并到当前快照之上:请求体中未出现的项保持原样。
{ "mode": "auto", "browser": "firefox", "os": "macos" }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 在端口运行时修改它:端口不会关闭,也不会重启。
所有端口接口共有的失败:{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。
| 路径 | 方法 | 请求体字段 | 类型 | 取值与注意 |
|---|---|---|---|---|
/mode | GET, PUT | mode | string | random、db(别名 database)、auto、specific |
/browser | GET, PUT | browser | string | 空、random、chrome、firefox、safari、edge;可带版本:chrome_145 |
/os | GET, PUT | os | string | 空、random、windows、macos、linux、ios、android |
/profile | GET | — | — | 只读;固定配置文件请通过 /mode 或 /config |
/profile/view | GET | — | — | 只读:当前配置文件的构成 |
/rotate | POST | — | — | 无请求体;立即签发新的配置文件 |
/custom_tls | PUT | ja3, ja4, … | object | 完整的已采集指纹;将端口切换为 custom 模式 |
/upstream | GET, PUT | upstream | string | 出口代理地址;空字符串表示直连出口 |
/chain_proxy | GET, PUT | chain_proxy | string | 出口代理之前的链路首跳 |
/allow_mitm_upstream | GET, PUT | allow_mitm_upstream | bool | 该字段必填:缺失时返回 400,而不是按 false 处理 |
/h2_spoofing | GET, PUT | enabled | bool | true 或 false |
/spoof_user_agent | GET, PUT | enabled | bool | true 或 false |
/spoof_headers | GET, PUT | enabled | bool | true 或 false |
/tls_passthrough | GET, PUT | enabled | bool | true 或 false |
/tls_mirror | GET, PUT | enabled | bool | true 或 false |
/http3 | GET, PUT | enabled | bool | true 或 false |
/session_resumption | GET, PUT | enabled | bool | true 或 false |
/decompress | GET, PUT | enabled | bool | true 或 false |
/auto_profile_from_ua | GET, PUT | enabled | bool | GET 还会返回 last_ua |
/cache_ignore_no_cache | GET, PUT | enabled | bool | true 或 false |
/max_concurrent | GET, PUT | max_concurrent | int | 0 及以上;0 表示不限 |
/sem_timeout | GET, PUT | timeout_seconds | int | 1 及以上——字段名与路径不一致 |
/skip_retry | GET, PUT | skip_retry | bool | true 或 false |
/retry_delay | GET, PUT | retry_delay_ms | int | 0 及以上——字段名与路径不一致 |
/idle | PUT | seconds | int | null | null 表示恢复为全局超时,0 表示永不关闭;没有 GET |
/cache | GET, PUT, DELETE | enabled, mode | bool, string | 参见“响应缓存”一节 |
/traffic_log | GET, PUT, DELETE | enabled | bool | 参见“端口请求日志”一节 |
/captures | GET, 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 端口;若已经修改过,请重新读取密钥并重新分发链接。
端口的身份
端口对站点表现出的身份:如何选择配置文件、如何缩小选择范围,以及如何提供自采集的指纹。
/api/v1/port/{port}/mode需要鉴权返回配置文件的选择模式。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/mode{
"mode": "db"
}/api/v1/port/{port}/mode需要鉴权在端口运行时修改配置文件的选择模式。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
mode | string | 是 | random 生成合成指纹;db(别名 database)取用数据库中的真实配置文件;auto 按所请求的浏览器与操作系统生成;specific 按名称固定。 |
specific_profile | string | 否 | mode=specific 时使用的配置文件名称,例如 chrome_152_windows。 |
{ "mode": "specific", "specific_profile": "chrome_152_windows" }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 连接不会被断开。
/api/v1/port/{port}/browser需要鉴权返回浏览器过滤条件。空字符串表示没有过滤。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/browser{
"browser": "chrome"
}/api/v1/port/{port}/browser需要鉴权将配置文件的选择范围限定到某个浏览器,或取消该限定。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
browser | string | 是 | chrome、firefox、safari、edge、random,或空字符串(清除过滤)。可用后缀固定版本:chrome_145。 |
{ "browser": "chrome_145" }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。
/api/v1/port/{port}/os需要鉴权返回操作系统过滤条件。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/os{
"os": "windows"
}/api/v1/port/{port}/os需要鉴权将配置文件的选择范围限定到某个操作系统,或取消该限定。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
os | string | 是 | windows、macos、linux、ios、android、random,或空字符串(清除过滤)。 |
{ "os": "macos" }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。
/api/v1/port/{port}/profile需要鉴权返回端口当前使用的配置文件。只读:对该路径发送 PUT 会返回 405。
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。
- 立即更换端口身份POST /api/v1/port/{port}/rotate 可在不等待轮换的情况下签发新配置文件,GET /api/v1/port/{port}/profile/view 显示当前配置文件的构成——两者都在配置文件参考中。
/api/v1/port/{port}/custom_tls需要鉴权把在别处采集到的完整指纹交给端口,并将其切换为 custom 模式。端口由此获得取自真实浏览器的形态——例如通过 ChromeApi 或 tls.peet.ws 采集。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
ja3 | string | 否 | 完整的 JA3 字符串。 |
ja3_hash | string | 否 | 已采集的 JA3 哈希。 |
ja4 | string | 否 | JA4 字符串。 |
ciphers | array | 是 | 按 ClientHello 顺序排列的密码套件。唯一必填字段。名称按固定表匹配;以 TLS_GREASE 开头的名称按 GREASE 占位保留,无法识别的名称会被静默丢弃。若识别后为空,则返回 400。密码套件不会从 ja3 推导:该字符串仅用于扩展顺序。 |
extensions | array<object> | 否 | 按 ClientHello 顺序排列的扩展。每个元素为对象:必填 name,可选 supported_groups、signature_algorithms、versions、protocols。 |
supportedGroups | array | 否 | 支持的椭圆曲线组。 |
signatureAlgorithms | array | 否 | 签名算法。 |
alpn | array | 否 | ALPN 列表。 |
h2 | object | 否 | HTTP/2 参数:settings、windowUpdate、akamai_fingerprint、headerOrder。 |
userAgent | string | 否 | 该指纹对应的 User-Agent。 |
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 时该怎么办。
/api/v1/port/{port}/upstream需要鉴权返回端口的出口代理。空值表示直连出口。
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 相同。
/api/v1/port/{port}/upstream需要鉴权在端口运行时更换出口代理——轮换代理时无需关闭端口。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
upstream | string | 否 | 形如 scheme://[user:pass@]host:port 的地址;支持 socks5、socks5h、http。空请求体或空字符串会让端口恢复直连出口。 |
socks5_addr | string | 否 | 同一字段的旧别名;仅当 upstream 为空时才会被读取。 |
{ "upstream": "socks5://user:pass@host:1080" }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"
}- 当地址确实发生变化时的副作用:端口已解决的验证会被清除,因为通行凭据是发给旧出口地址的,在新地址上不再有效。下一个访问受保护站点的请求会再次遇到验证。
- 缓存的拨号会被重置,指向旧出口的空闲连接会被关闭。
/api/v1/port/{port}/chain_proxy需要鉴权返回中间代理——出口代理之前的链路首跳。
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"
}/api/v1/port/{port}/chain_proxy需要鉴权设置或清除中间代理:流量路径为 客户端 → 链路 → 出口 → 站点。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
chain_proxy | string | 是 | 格式与 upstream 相同的地址。空字符串表示移除该跳。 |
{ "chain_proxy": "http://10.0.0.5:3128" }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。
/api/v1/port/{port}/allow_mitm_upstream需要鉴权报告是否允许使用会替换 TLS 的出口,以及已因此拒绝了多少连接。
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 直接回答了“为什么指纹没有生效”:最近一次被替换证书的签发者会被明确列出。
/api/v1/port/{port}/allow_mitm_upstream需要鉴权允许或禁止通过会拆解并重组 TLS 的出口工作。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
allow_mitm_upstream | bool | 是 | true 表示即使经由此类出口也继续工作;false 表示拒绝经由它的连接。默认关闭:此类出口会抹掉指纹,端口会在无声无息中不再完成它被打开的目的。 |
{ "allow_mitm_upstream": true }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,响应回显所应用的值。
/api/v1/port/{port}/h2_spoofing需要鉴权报告 HTTP/2 设置是否伪装为所选浏览器。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/h2_spoofing{
"enabled": true
}/api/v1/port/{port}/h2_spoofing需要鉴权开启或关闭 HTTP/2 设置伪装。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示 SETTINGS 帧、优先级与伪头顺序均取自浏览器配置文件。 |
{ "enabled": true }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。
/api/v1/port/{port}/spoof_user_agent需要鉴权报告请求的 User-Agent 是否被伪装。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/spoof_user_agent{
"enabled": true
}/api/v1/port/{port}/spoof_user_agent需要鉴权开启或关闭 User-Agent 伪装。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示取自配置文件;false 表示逐字节转发客户端自身的请求头。 |
{ "enabled": true }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。
/api/v1/port/{port}/spoof_headers需要鉴权报告请求头的集合与顺序是否被调整为浏览器的形态。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/spoof_headers{
"enabled": true
}/api/v1/port/{port}/spoof_headers需要鉴权开启或关闭浏览器形态的请求头处理。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示请求头的集合、大小写与顺序均与浏览器配置文件一致。 |
{ "enabled": true }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。
/api/v1/port/{port}/tls_passthrough需要鉴权报告 TLS 是否在不拆解的情况下直通。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/tls_passthrough{
"enabled": true
}/api/v1/port/{port}/tls_passthrough需要鉴权开启或关闭 TLS 直通。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示连接原样透传:客户端自身的指纹得以保留,内容不被读取,此时该端口上的缓存与请求日志没有意义。 |
{ "enabled": true }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。
/api/v1/port/{port}/tls_mirror需要鉴权报告是否以客户端自身的 TLS 参数替代配置文件参数。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/tls_mirror{
"enabled": true
}/api/v1/port/{port}/tls_mirror需要鉴权开启或关闭对客户端 TLS 参数的镜像。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示对外发送取自客户端本身的形态,而非配置文件中的形态。 |
{ "enabled": true }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。
/api/v1/port/{port}/http3需要鉴权报告端口是否允许 HTTP/3(QUIC)。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/http3{
"enabled": true
}/api/v1/port/{port}/http3需要鉴权允许或禁止 HTTP/3(QUIC)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示当站点提供 HTTP/3 时端口会加以使用。 |
{ "enabled": true }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。
/api/v1/port/{port}/session_resumption需要鉴权报告是否允许 TLS 会话恢复。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/session_resumption{
"enabled": true
}/api/v1/port/{port}/session_resumption需要鉴权允许或禁止 TLS 会话恢复(会话票据)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示接受并复用会话票据;false 表示每个连接都从完整握手开始。 |
{ "enabled": true }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。
/api/v1/port/{port}/decompress需要鉴权报告是否为客户端解压响应体。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/decompress{
"enabled": true
}/api/v1/port/{port}/decompress需要鉴权开启或关闭响应体解压。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示在交付客户端之前把 br、gzip 与 zstd 解压为普通字节。 |
{ "enabled": true }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。
/api/v1/port/{port}/cache_ignore_no_cache需要鉴权报告是否忽略 no-cache 头进行缓存。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/cache_ignore_no_cache{
"enabled": true
}/api/v1/port/{port}/cache_ignore_no_cache需要鉴权开启或关闭无视 no-cache 的缓存。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示即使站点要求不缓存,响应仍会被写入缓存。 |
{ "enabled": true }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。
/api/v1/port/{port}/auto_profile_from_ua需要鉴权报告是否按请求的 User-Agent 选择配置文件,并显示最近一次的该请求头。
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) …"
}/api/v1/port/{port}/auto_profile_from_ua需要鉴权开启或关闭按请求 User-Agent 选择配置文件。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 表示由应用自行指定要伪装的身份:端口按收到的 User-Agent 选取配置文件。 |
{ "enabled": true }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。
负载、重试与空闲
端口同时承载多少请求、发生网络错误后如何处理,以及何时自行关闭。
/api/v1/port/{port}/max_concurrent需要鉴权返回端口的并发请求上限。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/max_concurrent{
"max_concurrent": 32
}/api/v1/port/{port}/max_concurrent需要鉴权修改并发请求上限。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
max_concurrent | int | 是 | 0 及以上;0 表示不限。 |
{ "max_concurrent": 32 }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。
/api/v1/port/{port}/sem_timeout需要鉴权返回请求在并发上限内等待空位的秒数。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/sem_timeout{
"timeout_seconds": 30
}/api/v1/port/{port}/sem_timeout需要鉴权修改等待空位的时长。🔴 字段名为 timeout_seconds,而非 sem_timeout。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
timeout_seconds | int | 是 | 1 及以上——等待的秒数。 |
{ "timeout_seconds": 30 }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 拒绝。
/api/v1/port/{port}/skip_retry需要鉴权报告网络错误后是否重试请求。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/skip_retry{
"skip_retry": false
}/api/v1/port/{port}/skip_retry需要鉴权开启或关闭跳过重试。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
skip_retry | bool | 是 | true 表示网络错误后不重试,立即把错误返回给客户端。 |
{ "skip_retry": true }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。
/api/v1/port/{port}/retry_delay需要鉴权返回重试之间的间隔(毫秒)。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/port/20134/retry_delay{
"retry_delay_ms": 500
}/api/v1/port/{port}/retry_delay需要鉴权修改重试间隔。🔴 字段名为 retry_delay_ms,而非 retry_delay。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
retry_delay_ms | int | 是 | 0 及以上——毫秒。 |
{ "retry_delay_ms": 500 }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 毫秒。
/api/v1/port/{port}/idle需要鉴权设置该端口的空闲超时,覆盖全局值。它没有 GET——当前值可在 GET /api/v1/port/{port}/config 的响应中以 idle_seconds 查看。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
seconds | int | null | 是 | 自动关闭前的空闲秒数。null 表示移除覆盖、恢复全局超时;0 表示永不关闭。 |
{ "seconds": 1800 }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”。
/api/v1/port/{port}/captures需要鉴权返回调试采集端口所采集的指纹,按由旧到新排列。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
since | int | 否 | 仅返回序号大于该值的采集记录。 |
limit | int | 否 | 最多返回多少条;为 0 或不传表示全部。 |
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 条;溢出时最旧的记录被丢弃。
/api/v1/port/{port}/captures需要鉴权清空调试采集端口的环形缓冲区。
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 | 硬缓存,仅在同一地址连续三次返回完全相同的响应体后才收录——即内容已证明为静态。 |
/api/v1/port/{port}/cache需要鉴权端口缓存的状态:是否启用、处于哪种模式,以及已经节省了多少。
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 表示因命中缓存而无需重新下载的字节数。
/api/v1/port/{port}/cache需要鉴权在端口运行时开启、关闭缓存或切换其模式。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
mode | string | 否 | normal、hard、hard-media、hard-autowarm,或留空。 |
enabled | bool | 否 | 仅在模式不是硬缓存时才被读取。false 关闭缓存;在硬缓存模式下该字段被忽略。 |
{ "mode": "hard-media" }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 返回的状态相同:处理程序直接以其作答。
/api/v1/port/{port}/cache需要鉴权清空该端口的缓存,不影响其他端口。
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 清空的是同一个。
/api/v1/cache/hard需要鉴权硬缓存的整体状态:条目数、占用空间与已节省的流量。
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
}/api/v1/cache/hard需要鉴权整体清空硬缓存——一次性影响所有端口。
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/cache/hard{
"status": "hard cache cleared"
}/api/v1/cache/hard/evict需要鉴权按模式列表从硬缓存中驱逐条目——精确清除,而不是整体清空。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
patterns | array | 是 | 域名或完整 URL。该列表必填。 |
{ "patterns": ["example.com", "https://cdn.example.net/img/logo.png"] }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 字段。
/api/v1/cache/evict需要鉴权对普通缓存执行同样的操作:按模式列表驱逐条目。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
patterns | array | 是 | 域名或完整 URL。该列表必填。 |
{ "patterns": ["example.com"] }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”。
/api/v1/cache/hard/save需要鉴权为旧客户端保留:硬缓存位于 SQLite 中,每次写入即落盘,无需单独刷新。该接口只是返回状态。
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"
}/api/v1/cache/hard/exclusions需要鉴权硬缓存所避开的域名与地址。
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"]
}/api/v1/cache/hard/exclusions需要鉴权把所给模式追加到硬缓存排除列表,而不是替换该列表。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
exclusions | array | 是 | 不应缓存的域名或地址掩码。 |
{ "exclusions": ["api.example.com"] }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。
- 响应为合并后的完整列表。
/api/v1/cache/hard/exclusions需要鉴权从硬缓存排除列表中删除所列出的模式。必须带请求体。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
exclusions | array | 是 | 要从列表中删除的条目。 |
{ "exclusions": ["api.example.com"] }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},而不是空数组——与普通缓存一致。
/api/v1/cache/exclusions需要鉴权对普通缓存执行同样的操作:排除列表。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/cache/exclusions{
"exclusions": ["login.example.com"]
}/api/v1/cache/exclusions需要鉴权把模式追加到普通缓存的排除列表。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
exclusions | array | 是 | 不应缓存的域名或地址掩码。 |
{ "exclusions": ["login.example.com"] }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 获取。
/api/v1/cache/exclusions需要鉴权从普通缓存排除列表中删除所列出的模式。必须带请求体。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
exclusions | array | 是 | 要从列表中删除的条目。 |
{ "exclusions": ["login.example.com"] }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:时间、方法、主机、路径、状态码、响应体类型与大小、缓存相关请求头以及缓存判定。用它来分析缓存为何未命中、流量去了哪里。
/api/v1/port/{port}/traffic_log需要鉴权报告日志是否开启、文件位置以及其中的记录数。
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 键是否存在。
/api/v1/port/{port}/traffic_log需要鉴权在端口运行时开启或关闭日志。开启时,如文件尚不存在则会创建。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
enabled | bool | 是 | true 开始写入;false 关闭文件并停止写入。 |
{ "enabled": true }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 响应关闭日志。
/api/v1/port/{port}/traffic_log/download需要鉴权返回完整的日志文件——每个请求一行 JSON(NDJSON 格式)。
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”。
/api/v1/port/{port}/traffic_log需要鉴权清空日志文件,同时保持日志处于开启状态。
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”:该接口无法清空已关闭日志的文件——请先将其开启。
系统流量拦截与泄漏审计
拦截可在应用自身无需配置代理的情况下,把某个程序或整台机器的流量引入端口。泄漏审计回答相反的问题:被观察的程序是否绕过了拦截。
/api/v1/system/intercept需要鉴权特权拦截服务当前是否可用。应在打开端口之前查询:否则只有在填完表单后才会收到拒绝。
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——已有另一份应用副本在控制拦截,服务一次只服务一个客户端。
/api/v1/system/processes需要鉴权用于选择按进程拦截目标的应用列表。
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:空数组与“没有进程”无法区分,用户会看到一张空的选择表,而不是一段说明。
/api/v1/system/leak-audit需要鉴权开始一次观察会话:查看所选程序是否绕过拦截。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
exe_paths | array | 是 | 要观察的可执行文件路径。🔴 字段名为 exe_paths,而不是 paths。 |
policy | string | 是 | observe 仅观察;block 还会切断绕过的流量。 |
{ "exe_paths": ["C:\\Program Files\\App\\app.exe"], "policy": "observe" }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。
/api/v1/system/leak-audit需要鉴权当前会话的状态:判定、聚合数据、可信边界,以及最近的事件尾部。
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 “сеанс аудита утечек не запущен”:空报告并不比沉默更诚实。
/api/v1/system/leak-audit/report需要鉴权不含事件流的报告——用于导出结果。若没有进行中的会话,则返回最近一次已结束会话的报告。
curl -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/system/leak-audit/report- 若同样没有已完成的报告,返回 404 “аудит утечек ни разу не запускался”。
/api/v1/system/leak-audit需要鉴权停止会话,并以与 GET 相同的形态返回最终报告。
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
http://127.0.0.1:8891/api/v1/system/leak-audit- 若没有会话,返回 404。会话停止后,stopped_by 字段说明是谁结束了它——是人,还是自行中止过长观察的看门狗。
端口检查
针对运行端口的两项检查,外加一个辅助接口。完整测试会让请求穿过端口,并把外部看到的形态与它本打算伪装的身份进行比对。
/api/v1/port/{port}/test需要鉴权端口配置的完整测试:出口泄漏、穿透端口的指纹以及 UDP 支持。
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 秒。
/api/v1/port/{port}/leakcheck需要鉴权仅进行出口泄漏检查:比较应答的解析器归属,以及可见的 IPv6 归属。
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 秒。
/api/v1/port/{port}/generate需要鉴权为所请求的浏览器与版本生成配置文件,并应用到该端口。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
browser | string | 是 | chrome、firefox、safari 或 edge。 |
version | int | 否 | 浏览器版本;0 表示默认版本。 |
os | string | 否 | windows、macos、linux、ios 或 android;留空表示 windows。 |
save | bool | 否 | 把配置文件保存到数据库以便重复使用。 |
{ "browser": "chrome", "version": 152, "os": "windows", "save": true }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 并附带引擎文本。