Skip to content

fix: 修复高并发下自适应超时过低导致开放端口漏扫#598

Merged
ZacharyZcR merged 2 commits into
shadow1ng:devfrom
fyihang:fix/issue-503-adaptive-timeout
Jul 15, 2026
Merged

fix: 修复高并发下自适应超时过低导致开放端口漏扫#598
ZacharyZcR merged 2 commits into
shadow1ng:devfrom
fyihang:fix/issue-503-adaptive-timeout

Conversation

@fyihang

@fyihang fyihang commented Jul 11, 2026

Copy link
Copy Markdown

问题

Issue #503 反映 fscan 2.x 扫描本机时部分端口漏扫,而 1.8.4 不存在此问题。

原因

2.x 引入的 AdaptiveTimeout(自适应超时)在高并发场景下下限过低:

  1. 扫描本机时 RTT 接近 0,自适应超时在 10 次采样后迅速降到 100ms 下限
  2. 600+ 并发下 TCP 握手存在尾延迟(OS 调度抖动、backlog 溢出、端口竞争),部分开放端口的连接耗时超过 100ms
  3. 超时错误不会被重试(connectWithRetry 只重试资源耗尽错误),开放端口被永久漏扫

修复

1. 提高自适应超时下限(core/adaptive_timeout.go)

minTO 从固定 100ms 改为 max(500ms, maxTimeout/5):

  • 默认 3s 超时:下限 100ms -> 600ms
  • LAN 环境 1s 超时:下限 100ms -> 500ms

2. 超时错误重试(core/port_scan.go)

connectWithRetry 新增 fallbackTimeout 参数,连接超时时用完整超时再试一次,避免自适应超时过低导致误判。

3. 任务丢弃日志(core/port_scan.go)

slidingWindowSchedule 中 pool.Invoke 失败不再静默丢弃,改为记录日志和总计统计,方便排查漏扫。

测试

全部测试通过,包括自适应超时收敛测试验证新下限工作正常:

  • TestReal_AdaptiveTimeout_Convergence: 3s -> 600ms (20 samples)
  • TestIntegration_DualRTTTracking: AdaptiveTO=600ms, Ratio=1.00

Closes #503

@ZacharyZcR
ZacharyZcR self-requested a review July 11, 2026 11:57
@ZacharyZcR

Copy link
Copy Markdown
Collaborator

马上审计下,另外指向dev分支

@fyihang
fyihang changed the base branch from main to dev July 12, 2026 06:44
@fyihang

fyihang commented Jul 12, 2026

Copy link
Copy Markdown
Author

马上审计下,另外指向dev分支

has been changed

@ZacharyZcR ZacharyZcR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review:Request Changes

感谢 PR,问题定位是对的——#503 在本机/低 RTT + 高并发场景下,AdaptiveTimeout 地板过低导致开放端口被误判,这个根因我认可。CI 也是绿的,方向没问题。

但当前实现里有一块会伤到自适应超时本身的设计目标,建议改完再合,不要直接合入。


可以保留

  1. minTO 从 100ms 调整为 max(500ms, maxTimeout/5)
    这是对症的核心修复。默认 3s → 600ms 地板合理,也能覆盖绝大多数高并发握手尾延迟。

  2. pool.Invoke 失败时的丢弃日志
    无害、有助于排查漏扫,可以留。


需要改:超时后无条件用完整 maxTO 再拨一次

connectWithRetry 里:

  • 自适应超时失败 → 再用 fallbackTimeout(完整超时,常为 3s)重试一次

端口扫描里,timeout 的大头是 filtered / 防火墙丢弃 / 无响应,不是「开放但稍慢」。对这类端口:

  • 关闭(RST)→ refused,不重试(没问题)
  • 开放且慢 → 重试可能捞回来(这是你想修的)
  • 过滤/无响应 → 每次都先等 adaptive,再白等一整段 maxTO,且几乎必然失败

AdaptiveTimeout 存在的意义,就是网络学完之后别再对每个无响应端口傻等满 -time。现在这刀等于在 每个 timeout 端口 上把这个收益吃掉大半。默认 -t 600 扫带防火墙的网段时,耗时会明显恶化。

另外:「超时不重试」本身不是纯 bug,而是端口扫描的常见取舍——timeout ≈ 无响应,盲目重试多半只烧时间。资源耗尽才该重试(现有逻辑已经做了)。

#503 主场景(本机/低 RTT/高并发)靠抬高 minTO 通常就够。
无条件 full-timeout 重试是高价保险,保费却摊在所有 filtered 端口上。

建议(二选一)

A(更推荐)
去掉 timeout → full maxTO 重试,本 PR 只保留 minTO 抬升 + 丢弃日志。先合这个,用 #503 场景回归;若仍有漏扫,再单独讨论有条件的重试。

B(若坚持要保险) 至少同时收紧:

  • 仅当当前 adaptive 已经贴着地板时才 fallback(例如 timeout 接近 minTO
  • fallback 不要直接拉满 maxTO,用更温和的上探(例如 min(maxTO, timeout*2)
  • 避免对所有 timeout 无差别二次满超时

需要移出本 PR:webscan/lib/Client.go

gmtls handshake 的 stdout 噪声抑制和 #503 / 端口漏扫无关,属于范围污染。请从这个 PR 拿掉,另开 PR(或另找时机)处理。


测试建议

  • NewAdaptiveTimeout(3*time.Second) 的下限收敛补一条断言(描述里写了 3s → 600ms,代码里最好有测试钉死)
  • 若保留任何形式的 timeout 重试,请说明 filtered 端口的预期耗时变化,最好有前后对比

小结

改动 意见
minTO 抬升 ✅ 认可,保留
丢弃日志 ✅ 可保留
timeout → 完整 maxTO 无条件重试 ❌ 请删除或改为有条件/更温和
Client.go gmtls stdout ❌ 移出本 PR

问题找对了,核心药方也对;把「无条件 full-timeout 重试」和无关 diff 拿掉后,这个 PR 就可以再 review 一次。

fyihang added 2 commits July 13, 2026 11:37
扫描本机/低 RTT 目标时,AdaptiveTimeout 在 10 次采样后迅速收敛到 100ms 下限。高并发(600+ 线程)下 TCP 握手尾延迟可能超过 100ms,加上超时错误不会重试,导致开放端口被误判为关闭。

- AdaptiveTimeout 下限从 100ms 提升至 max(500ms, maxTimeout/5)
- connectWithRetry 对超时错误用完整超时重试一次
- slidingWindowSchedule 任务丢弃时记录日志,便于排查漏扫
根据 shadow1ng#598 review 反馈:

1. 移除 connectWithRetry 中 timeout->full maxTO 无条件重试
   - filtered/无响应端口占超时大头,盲目重试只烧时间
   - shadow1ng#503 主场景靠 minTO 抬升已足够覆盖
2. 移除不再使用的 MaxTimeout() 方法和 port_scan_timeout_retry i18n 条目
3. AdaptiveTimeout 收敛测试补充 minTO 下限断言(3s->600ms)
@fyihang
fyihang force-pushed the fix/issue-503-adaptive-timeout branch from 78bbcc0 to 4966e09 Compare July 13, 2026 04:02
@fyihang

fyihang commented Jul 13, 2026

Copy link
Copy Markdown
Author

已按 review 意见修改,force push 更新了 PR:

已移除:

  • \connectWithRetry\ 中 timeout -> full maxTO 无条件重试(采纳方案 A)
  • 不再使用的 \MaxTimeout()\ 方法
  • \port_scan_timeout_retry\ i18n 条目

已保留:

  • minTO 从 100ms 抬升至 max(500ms, maxTimeout/5)
  • \pool.Invoke\ 失败时的丢弃日志

已补充:

  • \TestReal_AdaptiveTimeout_Convergence\ 增加 minTO 下限断言:3s maxTimeout -> 600ms floor

关于 Client.go:
rebase 到 dev 分支后 diff 已自动清理,现在只包含本 PR 相关的 4 个文件:

  • core/adaptive_timeout.go
  • core/port_scan.go
  • core/real_network_test.go
  • common/i18n/locales/{en,zh}.yaml

全部测试通过。

@ZacharyZcR ZacharyZcR left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复核最新提交:review 意见均已处理,改动范围干净,完整 go test ./... 通过,可以合并。

@ZacharyZcR
ZacharyZcR merged commit 9d00109 into shadow1ng:dev Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

新版本扫描内网端口存在问题

2 participants