DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

yiyunet /

yiyunet/dsh-proxy-egress

Verified

本地出口代理(egress)桥:给只接受无凭据代理地址的消费方一个本地地址,账号密码在上游那一跳注入。失败即断联,无直连降级。 | DSH plugin: a local egress proxy that hands a credential-free proxy URL to consumers that reject credentials, then injects the upstream auth on the hop that needs it. Fail-closed — no direct fallback, ever.

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@af82a1ab

dsh-proxy-egress

把「只接受无凭据代理地址的消费方」接到「需要账号密码的上游代理」上。

消费方 ──► http://127.0.0.1:8899 ──► 本插件(注入 Proxy-Authorization)──► 上游代理 ──► 目标
           (无认证,消费方只填这个)        (账号密码只在这里出现一次)

MIT · 独立社区插件 · 与 DeepSeek、DeepSeek Harness 无隶属关系,亦未获其赞助或背书 安全与权限 · 卸载与残留

中文 | English


这是什么,适不适合你

有些消费方只接受一个不带账号密码的代理地址,而你的上游代理偏偏要认证。本插件站在中间:消费方连本地一个无凭据地址,账号密码由插件在上游那一跳注入,只出现一次。

典型情境:你在企业出口后面,公司代理要账号密码;Harness 里某个插件只让你填 http://host:port,没有用户名密码字段。把那个字段填成 http://127.0.0.1:8899,认证交给本插件。

它不做什么:不做系统级全局代理,不做多上游轮换,不做流量审计,也不支持 SOCKS5(写了会明确报错)。

它的两个硬特征:零构建、零运行时依赖(plugin-src/ 即真源);凭据不进模型通道(工具只查状态、只跑验证,回传里只有指纹——sha256 前 8 位)。

它能保证什么,不能保证什么

层 内容 可证明性
L1 代理层 进入本地监听的每一条连接只经上游转发;失败不创建到目标的直连 代码级,可测(scripts/smoke.mjs + scripts/faultcheck.mjs)
L2 消费方层 消费方是否真的把请求交给本监听、失败后是否自己 fallback 本插件管不了,只能取证
L3 系统层 整机强制出口 未实现、未验收。需要防火墙白名单或独立网络环境

说人话:本插件保证「进来的一定走代理」,不保证「该进来的都进来了」。

同一条纪律的另一种说法:失败即断联——上游不通、认证失败、被拒、超时,一律关闭连接并给出分类原因。没有直连降级,没有兜底重试,代码里不存在可以打开直连的开关(配置里写 allowDirectFallback 会直接报错)。

安装前准备

要求 取值
宿主 任一可用 DSH profile(下文以 web 为例)
Node.js >=22.19(package.json 的 engines)
上游代理 一个支持 CONNECT 的 HTTP 代理,且你持有账号密码
本地端口 默认 127.0.0.1:8899,被占用时不会自增换端口(见 V6)

校验规则(不满足就不启动,不监听任何端口)

编号 规则
V1 upstream.host 不能含端口、不能带协议前缀;IPv6 必须写 [地址]
V2 username / password 必须同时提供或同时留空
V3 任何输出(状态、日志、错误)都不含密码,也不含完整账号
V4 域名做 IDN → punycode 归一
V5 配置变了,旧的检查结果要作废
V6 校验不过就不启动;端口被占用也不自增换端口

安装

本插件是一个 DSH bundle(package.json 声明了 dsh.bundle.patch)。

A · 从 npm 安装(推荐)

dsh plugin --profile web add dsh-proxy-egress

一条命令做两件事:装包,并自动把它登记进 dsh.profile.bundles。DSH 装完会回读新增依赖的 dsh.bundle 声明再行登记;没有该声明的包只当普通依赖装上,终端会给出 installed as a plain dependency, not a profile layer 的警告。把 web 换成你自己的 profile 名。

命令里写包名而不写版本号,所以发版不需要改这份文档。

B · 从源码安装(改造或调试时用)

  1. 把本仓库放到本机任意目录。
  2. profile 的 package.json:dependencies 加 "dsh-proxy-egress": "link:<本仓库绝对路径>",并在 dsh.profile.bundles 里加 "dsh-proxy-egress"。
  3. 装出符号链接:dsh plugin --profile web install。(bundles 是手改的,但链接不装出来,加载器就解析不到这个包。)

两种方式共同的收尾

  1. 在 profile 的 cordis.patch.yml 加同 id 覆盖行(见设置面板 → 配置覆盖行)。包自带的 patch 里上游主机与凭据路径是占位符——不写覆盖行插件不会启动(但四个工具仍可用,proxy_egress_status 会把缺什么直接列出来)。
  2. 重启前预检:dsh --profile web --dump-config 应当只看到一行 proxy-egress,且带 patched by …cordis.patch.yml。这一步能验证 YAML 语法与包解析,不用等重启才发现。
  3. 重启宿主,然后问模型 proxy_egress_status。

不要手写 $DSH_HOME 下的插件包,也不要在 profile 目录里跑 pnpm —— 那是 install_bundle 的活。

想撤掉它:见更新、回滚、卸载。卸载不等于清凭据文件与设置文件。

快速开始:跑通一次真实出口

装好不等于能用。下面四步的落点是一次可验证的出口请求——诊断通过、面板显示 listening 都只说明进程起来了。

  1. 给什么输入 —— 上游协议/主机/端口、账号密码,以及你想用的本地端口。
  2. 做什么操作 —— 在 设置 → ANB 工具 → 出口代理 里填上游并录入凭据(面板是唯一合法入口,见设置面板);保存。然后把消费方的代理地址填成 http://127.0.0.1:8899——不带任何账号密码。
  3. 结果出现在哪 —— 面板显示监听状态与上游(脱敏);工具 proxy_egress_status 里 proxy.state 为 listening、connections.total 随请求增长。
  4. 怎样判断符合预期 —— 跑 proxy_egress_selfcheck:它经本地监听 → 上游 → 回显服务量一次实际出口 IP。返回 OK 即通;EGRESS_IP_MISMATCH 说明真实出口不是 expectedEgressIps 里的那个;UPSTREAM_AUTH_FAILED 说明账号密码不对。看到 OK 才算成功。

日常使用

主线,端到端。 消费方填本地无凭据地址 → 请求进本地监听 → 插件注入上游认证 → 上游转发 → 响应回到消费方。

第二次及以后的最短路径。 什么都不用做——配置与凭据持久化,重启后自动监听。想确认它还活着,跑一次 proxy_egress_status。

会改变状态的三件事:

  • 改上游或改密码 → 保存后新连接即用新配置;已建立的隧道不受影响。
  • 上游不通 → 连接直接失败断开,不降级直连。这是设计取舍,不是故障。
  • 进入阻断态(出口 IP 不匹配且 egressMismatchAction: block)→ 新连接被拒,已建立的隧道不被中断(原因见必须说清楚的限制第 3 条)。

设置面板

装好后在 设置 → ANB 工具 → 出口代理 有一个面板(零构建客户端,plugin-src/client/client.js)。

「ANB 工具」是本插件自带的栏目,不是需要另装的东西。只装这一个插件时栏目里只有一个标签(选中态),不会出现空壳;以后装更多 ANB 系列插件,它们出现在同一栏目的标签行里。

分区 作用
状态 监听、上游(脱敏)、凭据是否已配置(只给指纹)、连接计数、最近失败
验证 代理链路检查 / 故障注入检查 / 重启
上游与监听 协议、主机、端口、本地端口、期望出口 IP、不匹配时 warn/block
凭据 录入账号密码(宿主写进凭据文件并重启代理);清除(删凭据文件,上游要认证时代理会停止,这是预期状态)

三条设计约束,读者需要知道:

  1. 面板是全项目唯一合法的凭据写入口。 模型工具永远收不到密码——工具参数会进对话记录、调用日志与宿主审计;面板走本机 HTTP,只在人的通道里。
  2. 凭据只写不读。 保存后输入框清空,界面只显示指纹。
  3. 面板的改动存在插件自己的状态文件 $DSH_HOME/proxy-egress/settings.json,不写进宿主的启动配置——面板写启动配置,一次手误就是宿主起不来,而纠正它的入口恰恰是这个面板。两个来源并存时,面板会标出每个字段当前来自「面板」还是「配置文件」。

配置覆盖行

# ⚠️ 用「同 id 顶层覆盖」,不要写 `- insert:`。
# 本包自带的 patch 已经插入过这一行;再 insert 一次会变成两个同 id 的行,
# 两个实例抢同一个端口(症状是 EADDRINUSE)。
- id: proxy-egress
  config:
    listen: { host: '127.0.0.1', port: 8899 }   # 只允许回环
    upstream:
      type: 'http'             # http | https
      host: '203.0.113.9'      # 只写主机名/IP,端口另写
      port: 8080
    credentialSource: 'file'
    credentialFile: '<凭据文件绝对路径>'
    allowConnectPorts: [443]
    expectedEgressIps: ['203.0.113.9']
    egressMismatchAction: 'warn'   # warn | block
    selfCheck:
      enabled: true
      url: 'https://api.ipify.org?format=json'

凭据文件(UTF-8):

{ "username": "<账号>", "password": "<密码>" }

出问题时怎么办

服务端失败时回 X-Egress-Reason 头,按下表定位:

X-Egress-Reason 含义 下一步
UPSTREAM_UNREACHABLE 连不上上游(网络/端口/超时) 核对主机端口;确认本机能出网到该地址
UPSTREAM_AUTH_FAILED 上游回 401 或 407:账号密码不对,或凭据改过但没重启 重录凭据并重启代理,再跑自检
UPSTREAM_REJECTED 上游明确拒绝该目标 确认上游是否允许访问这个目标
UPSTREAM_MALFORMED_RESPONSE 上游响应解析不出来(按失败处理,不当成功) 检查上游是否为兼容的 HTTP 代理
TUNNEL_HANDSHAKE_TIMEOUT 上游接受了连接但不说话 排查上游负载或链路
HANDSHAKE_HEADER_TOO_LARGE 上游响应头超过上限 上游返回异常,换上游或修上游
CONNECT_PORT_NOT_ALLOWED 目标端口不在白名单 需要就加进 allowConnectPorts
PROXY_BLOCKED 处于阻断态(出口 IP 不匹配等) 查 proxy_egress_status 的 blocked 字段
EGRESS_IP_MISMATCH 观测出口不在 expectedEgressIps 先确认真实出口,再改期望值
CHECK_SERVICE_UNAVAILABLE 回显服务本身不可用(不代表代理坏) 换一个自检 URL 再试

别把自检当成一切:proxy_egress_selfcheck 的分类结果几乎能直接定位问题,值得贴进 issue——但请先删掉上游凭据、抹掉真实出口 IP(那是你这个网络的身份信息)。

更新、回滚、卸载

动作 怎么做 你的数据会怎样
更新 同一条 dsh plugin --profile web add dsh-proxy-egress 重装 设置与凭据保留
回滚 装回上一个精确版本 设置保留;旧版本不认识的字段被忽略,不会被删
卸载 dsh plugin --profile web remove dsh-proxy-egress 插件代码移除;凭据文件与 settings.json 保留
清理设置 手动删除 $DSH_HOME/proxy-egress/settings.json 不可恢复
清理凭据 手动删除你配置的凭据文件 不可恢复;删前确认没有别的插件在用它

卸载与残留什么

卸载不是清空配置:凭据文件与状态文件仍留在磁盘上,因为移除一个插件不该静默销毁你可能还需要的数据。要一起清掉,见上表"清理"两行。

数据、权限与隐私

  • 读什么 —— 插件配置(上游地址与端口、端口白名单、期望出口 IP、自检 URL);你指定凭据文件里的上游账号密码。
  • 是否外发及目标域名 —— 只向你配置的上游代理地址转发;自检时另向 selfCheck.url(默认 https://api.ipify.org?format=json)请求一次。不向本项目维护者发送任何数据,没有遥测端点。
  • 是否落盘及位置 —— 面板改动在 $DSH_HOME/proxy-egress/settings.json;覆盖行在 profile 的 cordis.patch.yml;凭据在你配置的文件里。除此之外不写别处。
  • 谁可读写 —— 只有运行 DSH 的那个操作系统账户。请把凭据文件当密码对待。
  • 关键默认开关 —— listen 默认 127.0.0.1:8899(只允许回环);allowConnectPorts 默认只放 443;egressMismatchAction 默认 warn;上游认证始终注入,没有"关闭认证"开关。
  • 凭据存哪、是否进日志 —— 只在凭据文件里;状态输出只给指纹与来源类型,不打印密码,也不含完整账号(V3)。

兼容性:要求、已验证、仍未确认

  • 要求 —— Node >=22.19;DSH 提供 dsh-client-ui-slots、dsh-client-connection、dsh-client-ui-settings-general 三个注入点(package.json 的 dsh.client.inject)。
  • 已验证 —— 本机在当前 DSH 版本上加载、面板出图、proxy_egress_selfcheck 返回 OK(2026-10-12,出口 IP 与 expectedEgressIps 一致)。
  • 仍未确认 —— 跨 DSH 版本矩阵未系统验证;http 上游在公网链路下的账号安全(见限制第 4 条);SOCKS5 未实现。

验证与开发

npm test           # 纯逻辑 + 沙箱里真跑客户端面板(不需要宿主、不联网)
npm run smoke      # 离线端到端(假上游 + 假目标)
npm run faultcheck # 证明上游坏掉时不会直连
npm run verify     # 发布契约断言(入口存在、白名单自洽、无安装期脚本…)
npm run scan       # 公开前脱敏扫描(词表由 DSH_PRIVATE_TERMS 挂入,未设置则跳过)
npm run check      # 上面全部串起来跑;prepublishOnly 用的就是它

npm test 覆盖六个层次:

文件 守什么
test/parse.test.mjs IPv6 三分法、CONNECT 状态行、Basic、逐跳头剥离
test/config.test.mjs V1–V6、直连降级开关被拒、端口白名单非空
test/credentials.test.mjs 凭据文件只有两个键、密码逐字、BOM 容忍
test/overrides.test.mjs 改端口不能把上游账号搞丢、白名单外的键不生效、来源标注
test/rpc.test.mjs 面板 RPC 信封、错误分级、业务 ok:false 不走错误通道
test/client.test.mjs 客户端文件能在沙箱里执行、只 require react、面板挂载与首帧渲染

smoke.mjs 用假上游代理 + TCP 回声目标跑六件事:

  1. 正常隧道建立、认证头由本插件注入
  2. 上游 407 → 502 UPSTREAM_AUTH_FAILED,目标零连接
  3. 上游不可达 → 502 UPSTREAM_UNREACHABLE,目标零连接
  4. 非白名单端口 → 403 CONNECT_PORT_NOT_ALLOWED
  5. 普通 HTTP 走绝对形式,业务状态码原样透传(429 不被改成 502)
  6. 停止后端口释放(再连是 ECONNREFUSED)

装到宿主后还有两个模型工具:proxy_egress_selfcheck(量实际出口 IP)、proxy_egress_faultcheck(独立实例 + 诱饵端口,验证不直连)。

必须说清楚的限制

  1. 一次检查不能替代持续约束。 自检只证明"那一刻、那条路径"。
  2. 回显服务只观测它自己的出口。 上游若按目标分流,不能推论模型 API 走同一出口。
  3. 阻断态不中断已建立的隧道。 隧道里的字节已经看不到边界;要更强的效果只能用系统隔离。
  4. HTTP 上游的 Basic 认证只是 Base64。 上游若在公网,账号密码在链路上可被还原。走公网请优先 type: 'https'。
  5. SOCKS5 尚未实现。 写了会明确报错,不会静默忽略。

反馈

遇到问题或想要新功能,提一个 issue。 报问题时写上 DSH 版本和插件版本(版本看包清单或 CHANGELOG.md,本文不重复记录),修起来最快。贴 proxy_egress_selfcheck 结果前请删掉上游凭据、抹掉真实出口 IP。

许可

MIT,全文见 LICENSE。作者 yiyunet。与 DeepSeek、DeepSeek Harness 无隶属关系,亦未获其赞助或背书。

—/ 5

No ratings yet

Verified DSH bundle

Commit af82a1ab1a59

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout