upstream prober's TEMPORARY captive-portal trigger fires before advertisement validation, repeats every 30s poll — port-80 pokes at gateways that aren't TollGates
维护者通常 1 天内回复
评估
调研方向
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 内容生成。
描述
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) GETshttp://<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 aTODO: Remove this workaround once upstream TollGate implementations properly handle automatic session creation.- It is invoked from inside
ProbeGatewayWithContext(line 110-120) the moment the:2121probe returns any HTTP 200 with a non-empty body — i.e. beforeValidateAdvertisementFromBytesruns in the caller (upstream_session_manager.go:237-245).
Three defects follow:
- Fire-then-validate. Any HTTP service on the gateway's
:2121earns 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. - Every 30 s, forever, for gateways that never validate.
upstream_detector/main.go:274reports candidate gateways on a 30 s ticker;HandleGatewayConnectedre-probes whenevergateway.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. - 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
- Gate the trigger behind successful validation — fire only after
ValidateAdvertisementFromBytesaccepts the advertisement (move the call togetUpstreamAdvertisement's success path / session bootstrap), so non-TollGates never get poked. - 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).
- Make the workaround auditable: config kill-switch (default off until an upstream needs it), and a registry (single source of truth) of every
TEMPORARY WORKAROUNDmarker 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 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
OpenTollGate/tollgate-module-basic-go 的其他 Issue
-
难度 1/5 1 小时以内 新手友好度 85/100
OpenTollGate/tollgate-module-basic-go#1159 ·
维护者通常 1 天内回复
-
Degraded-mode hygiene follow-ups: dead walletNotInitializedError() + main.go's startup log still over-promises mint recovery可能已有人在做 @Amperstrand 于 4 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
OpenTollGate/tollgate-module-basic-go#1135 · 1 条评论 ·
维护者通常 1 天内回复
-
setup_uhttpd_portal hardcodes the GUEST portal docroot to the TollGate path — the brand token cannot select a re-brand guest portal可能已有人在做 @Amperstrand 于 4 天前认领。 未关闭
难度 2/5 1-3 小时 新手友好度 72/100
OpenTollGate/tollgate-module-basic-go#1122 ·
维护者通常 1 天内回复
-
changelog: dependency-security sweep missing from [Unreleased] [Amperstrand fork #105 review debt]未关闭
难度 1/5 1 小时以内 新手友好度 72/100
OpenTollGate/tollgate-module-basic-go#1055 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 78/100
OpenTollGate/tollgate-module-basic-go#1027 · 1 条评论 ·
维护者通常 1 天内回复
查看 OpenTollGate/tollgate-module-basic-go 的全部 Issue
相似的 Issue
-
Query cache: a failed cache page read leaves the set request's read lock held, so the scan hangs未关闭
难度 2/5 1-3 小时 新手友好度 78/100
turbot/steampipe-plugin-sdk#986 · 1 条评论 ·
-
难度 2/5 1-3 小时 新手友好度 76/100
router-for-me/CLIProxyAPI#7307 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 72/100
betterleaks/betterleaks#460 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 79/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 85/100
openmcp-project/service-provider-crossplane#330 ·
维护者通常 1 天内回复