upstream prober's TEMPORARY captive-portal trigger fires before advertisement validation, repeats every 30s poll — port-80 pokes at gateways that aren't TollGates

已关闭
#768 2 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@Amperstrand 已经在做这个了。

开始于 2026年10月9日。

  • #795 来自 @Amperstrand —— 未关闭

评估

难度
5/5
预计耗时
一周以上
新手友好度
20/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
停滞
技术栈
go
领域
backend, security

调研方向

Start with src/upstream_session_manager/tollgate_prober.go and upstream_session_manager.go:237-245 to trace when probing triggers the port-80 request versus when advertisement validation succeeds; then read upstream_detector/main.go:274 and the related tests. Done means the trigger cannot run before validation, does not repeat for rejected gateways, and the workaround is gated and registered with a contract test. The reporter says a worktree is already in progress and plans to link a PR.

由索引模型根据 Issue 内容生成。

描述

needs:human-review

Title: upstream prober's TEMPORARY captive-portal trigger fires before advertisement validation, repeats every 30 s poll — port-80 pokes at gateways that aren't TollGates

Found live during the rc1 bench-verify campaign (rig: ai-legion:~/tollgate-vm, evidence in bench-verify/trigger/evidence.log); this is the "future ticket" promised in the #754–#757 verification comments.

What is going on

src/upstream_session_manager/tollgate_prober.go carries a self-described temporary workaround:

  • TriggerCaptivePortalSession (line 224) GETs http://<gateway>:80/ with a browser-mimicking User-Agent ("Mozilla/5.0 (compatible; TollGate-Client/1.0)") so that "the upstream TollGate's ndsctl creates a client session for our device". Its own comment: "TEMPORARY WORKAROUND … NOT a long-term solution as it goes against the TollGate protocol specification." with a TODO: Remove this workaround once upstream TollGate implementations properly handle automatic session creation.
  • It is invoked from inside ProbeGatewayWithContext (line 110-120) the moment the :2121 probe returns any HTTP 200 with a non-empty body — i.e. before ValidateAdvertisementFromBytes runs in the caller (upstream_session_manager.go:237-245).

Three defects follow:

  1. Fire-then-validate. Any HTTP service on the gateway's :2121 earns a browser-UA GET to the gateway's :80 — TollGate or not. The prober's own log line says "validating TollGate advertisement" but validation happens later in the caller, after the side effect.
  2. Every 30 s, forever, for gateways that never validate. upstream_detector/main.go:274 reports candidate gateways on a 30 s ticker; HandleGatewayConnected re-probes whenever gateway.Session == nil (in-memory map, wiped on every restart — the rc1 VM bounced the service a few times post-install, amplifying it). A gateway whose advertisement persistently fails validation is probed — and poked on :80 — every cycle, indefinitely.
  3. No gate, no expiry, no tracking. The workaround is unconditional: no config kill-switch, no added-in version, no owning issue, no removal condition. "TEMPORARY" exists only as a string in three places.

Live evidence (rc1, 2026-10-08)

The QEMU user-net gateway (10.0.2.2 = host loopback) happened to have mockgate (a TollGate mock from another lane) on :2121 and an unrelated socat JSON service on :80. The rc1 module, with no payment made and no valid advertisement accepted (mockgate's event is unsigned → ValidateAdvertisementFromBytes fails; the rejection logs at Debug so nothing shows at INFO), did this every 30 s:

📡 Reporting gateway to upstream session manager  gateway=10.0.2.2 interface=eth1 module=upstream_detector
🔍 Checking if gateway is a TollGate              gateway=10.0.2.2 module=upstream_session_manager
🚨 TEMPORARY: Triggering captive portal session for ndsctl  gateway_ip=10.0.2.2 url=http://10.0.2.2:80/ purpose=trigger_ndsctl_session protocol_note="TEMPORARY WORKAROUND - not part of TollGate protocol"
✅ Captive portal request completed - ndsctl session should be triggered  gateway_ip=10.0.2.2 status_code=401 content_type=application/json
✅ Gateway responded - validating TollGate advertisement   gateway=10.0.2.2 module=upstream_session_manager
   (validation fails → nothing at INFO → next tick repeats)

So a deployed router makes repeated, browser-spoofed, unauthenticated requests to whatever answers on its upstream gateway's port 80 — including gateways it has already rejected as non-TollGates. On a real captive-portal upstream that is session-probe spam against a third-party box; on hostile upstreams it's a scripted, predictable, self-identifying request pattern ("compatible; TollGate-Client") from a payment device.

Ask

  1. Gate the trigger behind successful validation — fire only after ValidateAdvertisementFromBytes accepts the advertisement (move the call to getUpstreamAdvertisement's success path / session bootstrap), so non-TollGates never get poked.
  2. Fire once per gateway adoption, not per poll — skip when a session is active; consider persisting the gateway-decision so restarts don't re-run discovery side effects (AGENTS.md already flags process-memory state as a known gap class).
  3. Make the workaround auditable: config kill-switch (default off until an upstream needs it), and a registry (single source of truth) of every TEMPORARY WORKAROUND marker with owning issue, added-in version, removal condition, and review-by — plus a contract test that fails the build when a marker exists unregistered (fail fast on workaround debt).

I have a worktree in progress with (1), the unit tests for the misfire class, and (3); will link the PR here.

主要语言
Go
星标
12
派生
14
平均合并
3 天 22 小时
30 天内合并 PR
262

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

OpenTollGate/tollgate-module-basic-go 的其他 Issue

查看 OpenTollGate/tollgate-module-basic-go 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。