22 KiB
TCP 端口映射
共享网络代理(2026-09-27,当前创建流程)
新建 TCP 纯端口转发网关时,先直接选择 Kubeconfig、SSH、SOCKS5 或 sing-box,再选择已保存的代理。Kubeconfig 的凭据、Context、命名空间与资源在代理管理中维护,网关仅设置资源端口;其他代理还需设置目的地址。保存为 tcpForward.mode="proxy" 和 outboundId 引用,不复制凭据。普通协议网关通过关联目标继承其代理。
下文两种旧转发模式的字段、端口候选与预检行为作为兼容说明保留:已保存的 inline K8s 网关仍能打开原配置,空 mode/SOCKS5 网关也继续有效;新的共享代理网关不能交给不认识 proxy mode 的旧执行程序。新流程及引用保护详见 网络代理管理。无数据库迁移。
Kubeconfig 端口候选与权限预检(2026-09-27)
Kubernetes 资源查询会返回声明的 TCP 端口。选择资源后,界面提供这些端口作为候选;只有当前端口为空或仍是组件上一次自动建议值时才自动带入首个候选,已有保存值和用户手工输入不会被资源切换静默覆盖。多个端口由用户明确选择,最终仍保存为 tcpForward.port。
Kubeconfig 纯端口转发新增可选的“预检 Kubernetes 权限”。预检通过 SelfSubjectAccessReview 检查运行时所需的目标资源读取权限、非 Pod 资源的 Pod 列表权限,以及 create pods/portforward 权限。返回仅包含固定的动作、资源、子资源、allowed/denied/unknown 状态和稳定错误码,不回传 Kubeconfig、Token、证书、API Server 原始原因或评估错误。
预检是配置阶段的诊断,不参与保存,也不会替代启动和连接测试:ready 只说明授权检查允许,不证明资源存在、Pod 正在运行、Service 端口匹配或 SPDY 转发成功;unknown 表示集群不支持或不允许权限审查,仍应以实际启动/测试为准。上传/内联的 Kubeconfig 必须使用 certificate-authority-data、client-certificate-data、client-key-data 或内联 Token,不能通过 tokenFile、certificate-authority、client-certificate 或 client-key 读取 linkport 主机文件,也不能使用 exec/auth-provider 登录插件。显式本地 Kubeconfig 文件路径及其中登录插件的兼容边界保持不变。
验证状态:权限预检后端 fixture、API 回归、前端类型检查和 7 项端口/预检逻辑测试通过,全量 go vet 通过。生产前端构建受当前 Windows 沙箱 spawn EPERM 阻止,未生成包含本次界面的新程序,因此没有执行 Playwright 或真实 Kubernetes 集群验收;详细结果见 测试记录。
独立纯端口转发支持 Kubeconfig(2026-09-26)
验证状态:新增模型、存储、API、既有 SOCKS5 边界与前端逻辑测试通过,Go 1.25.0 的串行全量 vet 通过。全量 Go 仅复现 6 个既有 Windows ACL/SQLite 快照环境失败。前端生产构建在 Vue 类型检查后受 Vite/esbuild spawn EPERM 阻塞,因此相关 3 个 Playwright 场景只完成发现,未使用新程序执行;不能据此宣称浏览器或真实 Kubernetes 集群验收通过。
TCP 网关的「纯端口转发」现在可以选择两种转发方式:已有 SOCKS5 代理,或 Kubeconfig / Kubernetes port-forward。Kubeconfig 方式不需要新建或关联目标服务,也不需要选择连接资产中的代理;数据路径为「客户端 → 本机监听端口 → Kubernetes API port-forward → 所选资源端口」。Service 填 Service 端口并由运行时解析 targetPort;Pod、Deployment 和 StatefulSet 填容器端口。它仍然只透传 TCP 字节,不解析业务协议、不替换账号密码、不终止 TLS,也不支持 UDP。
配置 Kubeconfig 映射
- 在资产管理中保存类型为 Kubeconfig 的文件资产。
- 在「网关服务」新建 TCP 端口映射,选择「纯端口转发」,再选择「Kubeconfig / K8s port-forward」。
- 选择 Kubeconfig 资产及 Context。Context 留空时使用文件的
current-context;命名空间留空时使用所选 Context 的命名空间,文件也未指定时由 Kubernetes 客户端使用default。 - 查询命名空间和 Kubernetes 资源,选择
pod/名称、service/名称、deployment/名称或statefulset/名称,再选择或填写 Kubernetes 资源端口。 - 保存后先执行手动连接测试,再启动网关。测试成功只表示 port-forward 的 TCP 连接可以建立,不证明上层协议认证、TLS 或业务功能正常。
例如,以下配置把本机 127.0.0.1:15432 映射到 payments 命名空间中 service/postgres 的端口 5432:
{
"type": "tcp",
"listenHost": "127.0.0.1",
"listenPort": 15432,
"targetId": "",
"targetAccountId": "",
"gatewayAccounts": [],
"tcpForward": {
"mode": "k8s",
"kubeConfigAssetId": "existing-kubeconfig-asset-id",
"kubeContext": "production",
"namespace": "payments",
"resource": "service/postgres",
"port": 5432
}
}
tcpForward 中只保存 Kubeconfig 资产 ID、Context、命名空间、资源和端口。Kubeconfig 正文仍只保存在加密资产记录中,读取网关时才注入运行时出口;网关记录、网关 API、配置历史和脱敏预览不包含正文。完整备份仍会在 assets 中包含一次资产正文,但备份整体使用口令加密,网关条目只保留引用。
两种转发方式的字段严格互斥:Kubeconfig 方式不能包含 host 或 outboundId,SOCKS5 方式不能包含 Kubeconfig 字段。切换方式时界面会建立新的配置对象并清除另一种方式的字段,避免部分更新遗留旧路由。缺省或空 mode 继续解释为旧版 SOCKS5 配置;新建 Kubeconfig 映射必须显式使用 mode: "k8s"。
被映射直接引用的 Kubeconfig 资产不能删除。相关网关运行时不能更新该资产;网关停止后,资产更新仍会先用新正文校验已保存的 Context 和资源配置,失败时保持旧资产不变。完整备份预览和恢复会拒绝缺失资产、资产类型错误或 Kubeconfig 配置无效的映射。此功能不新增 SQLite schema 迁移,既有 SOCKS5 映射及目标关联模式保持原行为;旧程序不识别 Kubeconfig 独立映射,回退或向旧节点同步前应先处理这些配置。
本轮实际验证
Go 1.25.0 的模型专项覆盖 Kubeconfig 运行时解析、两种模式字段互斥、缺失运行时正文拒绝、无效 Context/命名空间/资源/端口及旧 SOCKS5 空 mode 兼容;存储专项覆盖加密持久化不复制正文、Get/List 运行时注入、直接资产引用、无效资产更新原子拒绝、加密备份及缺失/错误类型资产恢复拒绝。API 专项覆盖创建/读取脱敏、缺失或错误类型资产、删除与运行中更新保护,以及同一网关双向切换方式不遗留字段。前端领域测试覆盖资产校验、启动前检查、摘要/测试视图、模式切换和干净 payload。
Kubernetes 网络验证使用本机隔离 TLS API fixture,检查实际拨号读取所选 Kubeconfig、Bearer Token 和资源请求路径;既有 Kubernetes 传输测试使用模拟 API 与 SPDY fixture。它们不是对真实 Kubernetes 集群、RBAC、网络策略、API 代理或具体业务服务的验收。本轮未修改或迁移真实 data 目录;完整命令和最终结果见 测试与版本矩阵。
独立纯端口转发:SOCKS5(2026-09-22)
只转发端口时,不需要创建目标服务,也不会自动生成目标记录。 在「网关服务」选择 TCP 类型,再选择「纯端口转发」,直接填写监听地址/端口、已有 SOCKS5 代理以及目的地址/端口。目标服务用于需要目标关联、协议处理或账号映射的配置,不是独立转发的前置条件。原有「关联已有 TCP 目标」模式保持不变;本文后续原有配置步骤、运行中目标切换和目标定时检查说明适用于该关联模式。
配置两个独立映射
先在代理管理中保存可用的 SOCKS5 代理,然后新建两条 TCP「纯端口转发」网关,共用该代理:
| 监听地址 | 转发代理 | 目的地址 | 目的端口 |
|---|---|---|---|
127.0.0.1:1081 |
已有 SOCKS5 代理 | 192.168.11.16 |
8080 |
127.0.0.1:1082 |
同一个已有 SOCKS5 代理 | 192.168.11.16 |
8082 |
即 127.0.0.1:1081 → 已有 SOCKS5 → 192.168.11.16:8080,以及 127.0.0.1:1082 → 已有 SOCKS5 → 192.168.11.16:8082。这里 192.168.11.16:8080/8082 是经代理访问的目的服务,不是 SOCKS5 代理自身的监听地址。每条网关保存、手动测试后分别启动;客户端连接本机的 1081 或 1082。
每条网关对应一组监听与目的端口。现有批量创建只递增监听端口,不递增目的端口;以上两条映射应分别创建,或复制后显式把第二条目的端口改为 8082,不要仅依赖批量递增。
默认监听仍为 0.0.0.0;以上例子显式使用 127.0.0.1,仅供本机客户端。需要向其他机器开放时,应另行设置监听地址、来源 IP/CIDR 白名单和系统防火墙,不把全网卡监听视为认证保护。
数据与安全边界
- 网关只透传 TCP 原始字节,不解析或转换业务协议,不替换业务账号密码,不终止 TLS,也不提供网关应用层认证;业务认证和 TLS 校验仍由客户端与目的服务处理。不支持 UDP。
- SOCKS5 连接需要认证时,复用所选代理已保存的凭据;独立网关只保存代理引用,不额外保存业务凭据,也不创建目标或目标账号。
- SOCKS5 方式只选择已有 SOCKS5 代理,不在该方式内配置 SSH/Kubernetes 出口;Kubeconfig 独立方式见上文。旧目标关联模式及其出口能力保持不变。
- 被独立网关引用的代理禁止删除或改成其他类型;相关网关运行时仍禁止编辑该共享代理。网关自身的监听、目的地址和映射可以运行中保存,新连接使用新快照,已有连接保持原链路;监听变化先绑定候选端口,失败时原映射继续运行。停止所有相关网关后可以更改代理的 SOCKS5 配置;引用仍存在时仍不能删除代理或改类型,须先解除引用。
- 独立模式不使用运行中目标切换。只有手动连接测试和运行指标,没有目标周期健康检查;手动测试只证明 TCP 链路可建立,不证明业务认证、TLS 或应用功能正常。
- 「拖拽连线」图视图中,纯端口转发网关不显示“未关联目标”提示,也不允许拖到目标进行绑定;仍保留手动测试按钮。
API、备份与回退
沿用现有网关创建/更新接口,网关配置的关键字段如下(名称等其余必填字段按现有接口填写,创建后再启动):
{
"type": "tcp",
"listenHost": "127.0.0.1",
"listenPort": 1081,
"targetId": "",
"targetAccountId": "",
"gatewayAccounts": [],
"tcpForward": {
"mode": "socks5",
"host": "192.168.11.16",
"port": 8080,
"outboundId": "existing-socks5-profile-id"
}
}
outboundId 必须引用已有 SOCKS5 代理。旧记录省略 mode 时仍按 SOCKS5 处理;新界面会为新记录显式保存 mode: "socks5"。tcpForward 仅适用于 type: "tcp",与目标服务引用及账号映射互斥。提交 tcpForward: null 可清除独立模式,再按原有流程关联 TCP 目标;运行中保存时只影响新连接,清除字段不会自动生成或绑定目标。
配置保存在既有网关数据中,无需 SQLite schema 迁移。备份导出/导入与 WebDAV 同步沿用 bundle 校验,检查代理引用存在且为 SOCKS5,不能把缺少代理的配置当作可用映射恢复。旧版程序不支持新的 tcpForward 字段,即使旧版已支持 tcp 类型也不能据此认定可用;回退前应备份数据、核对版本兼容性并处理独立转发配置,避免直接用旧程序覆盖或导入新配置。
本轮实际验证
Go 1.25.0 的全量 go test ./... -count=1 -timeout=120s 和 go vet ./... 已通过。首次 scripts/build.ps1 -SkipTests 在 Node 22.10 下构建成功,但触发 Vite 版本要求警告;这不表示该 Node 版本满足 Vite 支持要求。补充图视图调整后,使用机器已有 Node 22.22.3 重新执行同一构建脚本,完成 npm build 和 Go 1.25.0 编译,生成最终程序 artifacts/tcp-independent/linkport.exe;此次无 Node 版本警告,仅保留 chunk 大小警告。
最终重建前,Playwright tcp-independent.spec.ts、tcp-forwarding.spec.ts 共 2 项通过。新增 API 测试 TestIndependentTCPForwardTwoRoutes 使用本地带密码 SOCKS5 fixture,将两条映射转发到本地 TCP fixtures 并校验二进制字节;不是对用户真实 192.168.11.16 网络或业务服务的验收。新增 tcp_independent_validation_test.go 的 5 项边界测试(21 项子测试)通过,覆盖无效代理/字段、账号冲突、部分更新、模式切换、引用重绑定、代理改类型及影响范围响应脱敏。
最终使用 Node 22.22.3,设置 LINKPORT_E2E_BINARY=artifacts/tcp-independent/linkport.exe,在隔离端口 19281/19282 完整运行 Playwright,121/121 通过(6.6 分钟),包含最终图视图修复;日志为 artifacts/tcp-independent-playwright-final.log。此前 Node 22.10 因 node:sqlite 不可用导致测试发现失败;仅在当前 shell 通过 fnm use 22.22.3 切换机器已有版本后,一次运行在 59 项时被工具 200 秒时限中断,该中断不代表用例失败。最终延长时限后的完整重跑已通过;详细记录见 testing.md。
用途和边界
服务类型 tcp 将一个监听端口映射到一个 TCP 目标端口,不解析应用协议,不替换账号,不终止 TLS。可以传输 MongoDB、HTTP 或其他 TCP 服务的原始字节;客户端直接使用目标服务自己的认证方式和凭据。此版本不支持 UDP。
默认监听 0.0.0.0,即所有 IPv4 网卡;网关不提供应用层认证。请配置来源 IP/CIDR 白名单及系统防火墙,只允许可信客户端访问。白名单留空意味着不限制来源。需要仅本机使用时,将监听地址改为 127.0.0.1。应用层认证、权限和 TLS 证书校验由客户端与目标负责。
原目标关联模式的配置步骤
- 在「目标服务」新建「TCP 端口映射」目标,填写主机和目标端口;不配置目标账号或 TLS 终止。
- 连接方式可选直连、SSH/SOCKS5 连接资产,或 K8s 资源 port-forward。K8s 目标配置 Kubeconfig、命名空间和 StatefulSet 等资源以及 Kubernetes 资源端口(工作负载资源对应容器端口),不维护 Pod IP。
- 在「网关服务」新建相同类型,填写监听端口、来源白名单和最大连接数。默认监听地址为
0.0.0.0,不需要网关账号。 - 选择 TCP 目标,或在「拖拽连线」将网关卡片内的连接区拖到 TCP 目标卡片。卡片顶部用于移动节点位置,画板支持缩放和全屏,见 服务连线画板。TCP 映射不使用账号行,也不绑定其他协议类型的目标;已有数据库目标保持原来的账号映射语义。
- 测试连接后启动。客户端连接网关的地址和监听端口,由目标服务完成认证。运行中切换目标会保持监听,但保存成功后断开现有连接;客户端重连后使用新目标。停止网关同样会断开现有连接。
例如:0.0.0.0:27018 → K8s StatefulSet:27017。客户端的 MongoDB authSource、认证机制和密码直接交给 MongoDB,此模式不执行 LinkPort 的 MongoDB SCRAM 认证。
测试、监控与审计
- 「测试连接」只建立并关闭 TCP 连接,不发送应用探测数据;定时健康检查仅针对目标关联模式,并采用相同的 TCP 可达性检查,独立纯端口转发模式不提供目标周期健康检查。成功仅表示端口可达,不证明 TLS、账号密码或业务服务正常。
- 保留连接生命周期记录、来源白名单、并发连接数限制、启停和运行中目标切换;不提供命令内容审计、只读控制、账号级选路或应用层认证成功计数。
- 支持双向转发和底层连接支持的写半关闭,停止或取消时清理两端连接;SSH/K8s 包装连接透出底层半关闭能力,最终语义仍受远端转发实现影响。
- 每条配置映射一对端口;可创建多条网关配置,也可使用现有批量创建流程。只支持 TCP,不提供 NAT/路由器规则管理。
兼容性
监听预检与流量可观测性(2026-09-22)
为避免启动失败时只能看到模糊的端口错误,新增 gateway.PreflightListen 和 API handler Server.listenPreflight。预检只短暂绑定本机 TCP socket 后释放,不连接目标、不发送协议数据、不保留端口。它不能消除预检到启动之间的竞争;启动仍执行真实 bind 并返回包含明确监听地址、稳定错误码和操作建议的安全错误,不回显操作系统原始诊断或凭据。错误区分端口占用、地址不可用、权限不足及其他监听失败;Windows 使用 Winsock 错误码,其他系统使用 errno。
- 预检输入
{listenHost,listenPort,allowCIDRs};监听地址要求显式 IPv4/IPv6 字面量,不解析 DNS。空地址/主机名应改为明确本地 IP;端口范围 0–65535,0 用于测试或临时监听。 - 返回
available,requestedAddress,boundAddress,clientDestinations,warnings,code,action。boundAddress是本次临时 socket 的真实绑定结果,不是已运行网关,也不是端口预约。冲突返回 200 +available:false;非法地址返回 400。 0.0.0.0或::会返回listen_wildcard_requires_client_address;同时没有来源白名单时增加listen_wildcard_without_allowlist。警告不阻止监听,操作者应配置白名单、防火墙并向客户端提供实际可达的服务器 IP/DNS。- 网关现有 API 的
runtime.boundAddress来自运行中的 listener;runtime.clientDestinations对明确非通配绑定地址给出该地址,对通配绑定给出相同实际地址族的 loopback 候选(127.0.0.1:port或[::1]:port),绝不宣称0.0.0.0/::可拨号。预检和 runtime 都附带clientDestinationScope:loopback 候选为local_only,其他为reachability_unverified。loopback 仅供网关所在主机使用,仍受来源 ACL 限制;远端客户端必须使用实际可达的服务器接口 IP/DNS,候选不证明远端路由或防火墙放行。不根据浏览器 Host 或枚举网卡猜测公开地址。预检增加listen_client_destination_local_only警告,父层需提供对应文案。 - 现有
GET /api/v1/monitoring的每网关metrics新增totalConnections,rxBytes,txBytes,recentError,recentErrorAt,继续使用activeConnections。累计连接数仅计通过来源/并发限制的连接,不等同上游连接或认证成功。RX 是客户端向网关读取的字节,TX 是网关成功写给客户端的字节;不是仅业务载荷,也不证明 RX 已转发成功。现有活动连接数据增加同向的rxBytes,txBytes。 - 累计值及最近安全错误在网关停启后保留,进程重启清零,不写入 SQLite。最近错误仅保存安全分类与时间,正常停止/主动断开导致的取消不覆盖它;一次后续成功不会清掉历史错误。计数包装保留 TCP 写半关闭,不读取或记录数据内容。
界面与路由集成
server.go在认证、权限、CSRF 检查后将listen-preflight分派给s.listenPreflight(w,r);仅 POST,沿用写入权限检查。App.vue的监听编辑页通过GatewayListenCheck.vue调用预检并渲染ListenPreflight.vue;监听字段或白名单改变后将旧结果置 stale。已有运行 listener 占用端口时如实报告冲突,不通过客户端提交网关 ID 绕过检查。- 网关表格展开项使用
GatewayRuntimePanel.vue展示实际地址、客户端候选、复制操作和GatewayTraffic.vue的统计。未启动网关可在展开项预检;回环候选明确仅供本机客户端,不表示远端可达。 - 展示组件通过 labels 接收文案,当前仓库没有 Shopee i18n API,沿用现有中文界面。完整构建与端到端验证记录见
testing.md。
本次实际验证
使用 GOTOOLCHAIN=go1.25.0,focused 命令通过:
go test ./internal/gateway ./internal/api ./internal/protocol/tcpproxy -run 'TestListenPreflight|TestTCP|TestOpaqueStreamAndHalfClose|TestCancellationClosesBothStreams|TestConnectionProbeDoesNotSendApplicationData' -count=1 -timeout=120s
覆盖临时端口释放/冲突、显式地址校验、通配警告、不泄漏输入秘密、真实 bound 地址、活动/累计连接与 RX/TX、停启保留、既有 TCP 半关闭及取消。全部使用隔离 SQLite 与 loopback 临时 TCP fixture;不是生产服务或真实远端验收,不修改本地真实 data。合并后的全量 Go、前端构建和 Playwright 结果见 testing.md。
新增类型不修改现有数据库网关,无 SQLite 结构迁移。旧版本不识别 tcp 配置,导入或回退到旧程序前应注意版本兼容性。必须运行包含 TCP handler 的新程序才生效,本次开发未替换正在运行的程序或修改实际数据。
验证范围
新增后端测试使用隔离 SQLite、本机 TCP 测试服务和受控 handler,覆盖字节透传、半关闭、取消清理、来源/连接数限制、目标切换断开旧会话并让重连使用新目标、无账号创建与测试、各类出口配置和定时健康检查。
Playwright 使用新构建程序,验证界面默认 0.0.0.0,运行测试时显式改为 loopback 并分配临时端口,实际传输包含 NUL 和非 UTF-8 的测试字节。不是生产服务、真实 Kubernetes 或 MongoDB 的连接验收;验证命令与结果见 testing.md。