feat: SDK agent integration + UDP plugin framework + SNMP plugin

SDK enhancements for endpoint agent embedding:
- ScanWithController for pause/resume and live stats
- OnProgress callback for periodic progress reporting
- TaskID injection into every scan result
- ScanController with goroutine-safe pause/resume/stats
- Multi-target stats aggregation (race-free)

UDP plugin infrastructure:
- PluginTypeUDP registry with dedicated dispatch path
- DialUDP on ScanSession with rate limiting and packet counting
- UDP plugins bypass TCP port scan, probe targets directly
- FilterService excludes UDP plugins from TCP port matching

SNMP plugin (first UDP plugin):
- SNMPv2c GetRequest probe for sysDescr detection
- Community string brute force (public/private/community/etc)
- Pure stdlib implementation (encoding/asn1)
- Registered as safe default plugin on port 161/UDP

Tests: 95.7% SDK coverage, race-free, 50+ new test cases
This commit is contained in:
ZacharyZcR
2026-05-18 23:11:39 +08:00
parent eb4fa38fea
commit a1588a321f
16 changed files with 1881 additions and 72 deletions
+34
View File
@@ -10,6 +10,7 @@ import (
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/common/parsers"
"github.com/shadow1ng/fscan/plugins"
)
// ServiceScanStrategy 服务扫描策略
@@ -161,6 +162,11 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
return
}
// UDP 插件并行分发:直接对存活主机发协议探测包,不走端口扫描
if len(hosts) > 0 {
s.dispatchUDPPlugins(ctx, session, hosts, info, config, ch, wg)
}
// 流式 channel:端口扫描发现开放端口后立即通知插件执行
stream := make(chan string, 64)
@@ -213,6 +219,34 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
}
}
// dispatchUDPPlugins 分发UDP协议插件,跳过TCP端口扫描链路
func (s *ServiceScanStrategy) dispatchUDPPlugins(ctx context.Context, session *common.ScanSession, hosts []string, baseInfo common.HostInfo, config *common.Config, ch chan struct{}, wg *sync.WaitGroup) {
allPlugins, isCustomMode := s.GetPlugins(config)
var udpPlugins []string
for _, name := range allPlugins {
if plugins.IsUDP(name) {
if isCustomMode || plugins.IsSafe(name) {
udpPlugins = append(udpPlugins, name)
}
}
}
if len(udpPlugins) == 0 {
return
}
for _, host := range hosts {
for _, pluginName := range udpPlugins {
for _, port := range plugins.GetPluginPorts(pluginName) {
target := baseInfo
target.Host = host
target.Port = port
executeScanTask(ctx, session, pluginName, target, ch, wg)
}
}
}
}
// PrepareTargets 准备目标信息
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo, session *common.ScanSession) []common.HostInfo {
// 发现目标主机和端口