mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-25 12:41:53 +08:00
perf: 六项性能优化
- DNS 解析缓存:sync.Map 缓存避免重复系统调用 - 凭据测试 TCP 预检:不可达目标直接跳过全部凭据 - Web 探测 HTTP Client 复用:全局共享连接池 - 端口扫描 Bloom Filter 去重:替代 map 降低内存 - 进度条 atomic 累加 + 50ms 节流渲染:消除锁竞争 - 服务探针预解码:Init 时预编译,运行时零解码开销
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DNSCache 并发安全的 DNS 解析缓存
|
||||||
|
// 对纯 IP 输入零开销(直接返回),对域名避免重复系统调用
|
||||||
|
var DNSCache = &dnsCache{}
|
||||||
|
|
||||||
|
type dnsCache struct {
|
||||||
|
m sync.Map // host -> *net.IPAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveIP 解析 host 为 *net.IPAddr,结果缓存
|
||||||
|
func (c *dnsCache) ResolveIP(host string) (*net.IPAddr, error) {
|
||||||
|
if v, ok := c.m.Load(host); ok {
|
||||||
|
return v.(*net.IPAddr), nil
|
||||||
|
}
|
||||||
|
addr, err := net.ResolveIPAddr("ip", host)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
c.m.Store(host, addr)
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
+26
-17
@@ -143,16 +143,24 @@ func (pm *ProgressManager) UpdateProgress(increment int64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.mu.Lock()
|
// 原子累加,避免高并发下的锁竞争
|
||||||
defer pm.mu.Unlock()
|
newCurrent := atomic.AddInt64(&pm.current, increment)
|
||||||
|
if newCurrent > pm.total {
|
||||||
pm.current += increment
|
atomic.StoreInt64(&pm.current, pm.total)
|
||||||
if pm.current > pm.total {
|
|
||||||
pm.current = pm.total
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新活跃时间
|
// 节流渲染:距上次渲染不足 50ms 则跳过
|
||||||
pm.lastActivity = time.Now()
|
now := time.Now()
|
||||||
|
pm.mu.RLock()
|
||||||
|
lastAct := pm.lastActivity
|
||||||
|
pm.mu.RUnlock()
|
||||||
|
if now.Sub(lastAct) < 50*time.Millisecond {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pm.mu.Lock()
|
||||||
|
pm.lastActivity = now
|
||||||
|
pm.mu.Unlock()
|
||||||
|
|
||||||
pm.renderProgress()
|
pm.renderProgress()
|
||||||
}
|
}
|
||||||
@@ -170,7 +178,7 @@ func (pm *ProgressManager) FinishProgress() {
|
|||||||
pm.mu.Lock()
|
pm.mu.Lock()
|
||||||
defer pm.mu.Unlock()
|
defer pm.mu.Unlock()
|
||||||
|
|
||||||
pm.current = pm.total
|
atomic.StoreInt64(&pm.current, pm.total)
|
||||||
pm.renderProgress()
|
pm.renderProgress()
|
||||||
|
|
||||||
// 停止活跃指示器
|
// 停止活跃指示器
|
||||||
@@ -220,11 +228,12 @@ func (pm *ProgressManager) generateProgressBar() string {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
percentage := float64(pm.current) / float64(pm.total) * 100
|
percentage := float64(atomic.LoadInt64(&pm.current)) / float64(pm.total) * 100
|
||||||
elapsed := time.Since(pm.startTime)
|
elapsed := time.Since(pm.startTime)
|
||||||
|
current := atomic.LoadInt64(&pm.current)
|
||||||
|
|
||||||
// 计算速度
|
// 计算速度
|
||||||
speed := float64(pm.current) / elapsed.Seconds()
|
speed := float64(current) / elapsed.Seconds()
|
||||||
speedStr := ""
|
speedStr := ""
|
||||||
if speed > 0 {
|
if speed > 0 {
|
||||||
speedStr = fmt.Sprintf(" %.0f/s", speed)
|
speedStr = fmt.Sprintf(" %.0f/s", speed)
|
||||||
@@ -232,8 +241,8 @@ func (pm *ProgressManager) generateProgressBar() string {
|
|||||||
|
|
||||||
// 计算预估剩余时间
|
// 计算预估剩余时间
|
||||||
var eta string
|
var eta string
|
||||||
if pm.current > 0 && pm.current < pm.total {
|
if current > 0 && current < pm.total {
|
||||||
totalTime := elapsed * time.Duration(pm.total) / time.Duration(pm.current)
|
totalTime := elapsed * time.Duration(pm.total) / time.Duration(current)
|
||||||
remaining := totalTime - elapsed
|
remaining := totalTime - elapsed
|
||||||
if remaining > 0 {
|
if remaining > 0 {
|
||||||
eta = fmt.Sprintf(" ETA:%s", formatDuration(remaining))
|
eta = fmt.Sprintf(" ETA:%s", formatDuration(remaining))
|
||||||
@@ -245,7 +254,7 @@ func (pm *ProgressManager) generateProgressBar() string {
|
|||||||
|
|
||||||
// 计算固定部分的宽度
|
// 计算固定部分的宽度
|
||||||
fixedPart := fmt.Sprintf("%s %s %5.1f%% [] (%d/%d)%s%s %s",
|
fixedPart := fmt.Sprintf("%s %s %5.1f%% [] (%d/%d)%s%s %s",
|
||||||
pm.description, spinner, percentage, pm.current, pm.total, speedStr, eta, packetInfo)
|
pm.description, spinner, percentage, current, pm.total, speedStr, eta, packetInfo)
|
||||||
fixedWidth := displayWidth(fixedPart)
|
fixedWidth := displayWidth(fixedPart)
|
||||||
|
|
||||||
// 计算进度条槽位可用宽度(预留2字符余量)
|
// 计算进度条槽位可用宽度(预留2字符余量)
|
||||||
@@ -272,7 +281,7 @@ func (pm *ProgressManager) generateProgressBar() string {
|
|||||||
|
|
||||||
// 构建最终进度条
|
// 构建最终进度条
|
||||||
result := fmt.Sprintf("%s %s %5.1f%% %s (%d/%d)%s%s",
|
result := fmt.Sprintf("%s %s %5.1f%% %s (%d/%d)%s%s",
|
||||||
pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta)
|
pm.description, spinner, percentage, bar, current, pm.total, speedStr, eta)
|
||||||
|
|
||||||
if packetInfo != "" {
|
if packetInfo != "" {
|
||||||
result += " " + packetInfo
|
result += " " + packetInfo
|
||||||
@@ -470,7 +479,7 @@ func (pm *ProgressManager) GetPercent() float64 {
|
|||||||
if !pm.isActive || pm.total == 0 {
|
if !pm.isActive || pm.total == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return float64(pm.current) / float64(pm.total) * 100
|
return float64(atomic.LoadInt64(&pm.current)) / float64(pm.total) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -512,7 +521,7 @@ func (pm *ProgressManager) renderProgressUnsafe() {
|
|||||||
// 计算当前百分比(避免除零)
|
// 计算当前百分比(避免除零)
|
||||||
currentPercent := 0
|
currentPercent := 0
|
||||||
if pm.total > 0 {
|
if pm.total > 0 {
|
||||||
currentPercent = int((pm.current * 100) / pm.total)
|
currentPercent = int((atomic.LoadInt64(&pm.current) * 100) / pm.total)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只在百分比变化时更新,减少不必要的渲染
|
// 只在百分比变化时更新,减少不必要的渲染
|
||||||
|
|||||||
+1
-1
@@ -391,7 +391,7 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string,
|
|||||||
}
|
}
|
||||||
packets := make([]icmpPacket, 0, len(hostslist))
|
packets := make([]icmpPacket, 0, len(hostslist))
|
||||||
for _, host := range hostslist {
|
for _, host := range hostslist {
|
||||||
dst, _ := net.ResolveIPAddr("ip", host)
|
dst, _ := common.DNSCache.ResolveIP(host)
|
||||||
packets = append(packets, icmpPacket{data: makemsg(host), dst: dst})
|
packets = append(packets, icmpPacket{data: makemsg(host), dst: dst})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-10
@@ -39,17 +39,22 @@ var resourceExhaustedPatterns = []string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resultCollector 结果收集器,用于并发安全地收集扫描结果
|
// resultCollector 结果收集器,用于并发安全地收集扫描结果
|
||||||
// 使用 map 实现:O(1) 的添加和删除,无顺序依赖问题
|
// 使用 Bloom Filter 去重 + slice 存储,大规模扫描时内存更优
|
||||||
type resultCollector struct {
|
type resultCollector struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
addrs map[string]struct{}
|
addrs []string
|
||||||
|
bloom *BloomFilter
|
||||||
stream chan<- string // 可选:流式通知 channel
|
stream chan<- string // 可选:流式通知 channel
|
||||||
}
|
}
|
||||||
|
|
||||||
// newResultCollector 创建结果收集器
|
// newResultCollector 创建结果收集器
|
||||||
func newResultCollector(stream chan<- string) *resultCollector {
|
func newResultCollector(stream chan<- string, expectedSize int) *resultCollector {
|
||||||
|
if expectedSize < 1024 {
|
||||||
|
expectedSize = 1024
|
||||||
|
}
|
||||||
return &resultCollector{
|
return &resultCollector{
|
||||||
addrs: make(map[string]struct{}),
|
addrs: make([]string, 0, expectedSize/10),
|
||||||
|
bloom: NewBloomFilter(expectedSize, 0.001),
|
||||||
stream: stream,
|
stream: stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,7 +62,12 @@ func newResultCollector(stream chan<- string) *resultCollector {
|
|||||||
// Add 添加一个扫描结果
|
// Add 添加一个扫描结果
|
||||||
func (c *resultCollector) Add(addr string) {
|
func (c *resultCollector) Add(addr string) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.addrs[addr] = struct{}{}
|
if c.bloom.Contains(addr) {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.bloom.Add(addr)
|
||||||
|
c.addrs = append(c.addrs, addr)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
if c.stream != nil {
|
if c.stream != nil {
|
||||||
c.stream <- addr
|
c.stream <- addr
|
||||||
@@ -67,10 +77,8 @@ func (c *resultCollector) Add(addr string) {
|
|||||||
// GetAll 获取所有结果
|
// GetAll 获取所有结果
|
||||||
func (c *resultCollector) GetAll() []string {
|
func (c *resultCollector) GetAll() []string {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
result := make([]string, 0, len(c.addrs))
|
result := make([]string, len(c.addrs))
|
||||||
for addr := range c.addrs {
|
copy(result, c.addrs)
|
||||||
result = append(result, addr)
|
|
||||||
}
|
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -181,7 +189,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
|
|||||||
to := time.Duration(timeout) * time.Second
|
to := time.Duration(timeout) * time.Second
|
||||||
adaptiveTO := NewAdaptiveTimeout(to)
|
adaptiveTO := NewAdaptiveTimeout(to)
|
||||||
var count int64
|
var count int64
|
||||||
collector := newResultCollector(stream)
|
collector := newResultCollector(stream, totalTasks)
|
||||||
failedCollector := &failedPortCollector{}
|
failedCollector := &failedPortCollector{}
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,23 @@ func (vs *VScan) Init() {
|
|||||||
vs.parseProbesToMapKName()
|
vs.parseProbesToMapKName()
|
||||||
vs.SetusedProbes()
|
vs.SetusedProbes()
|
||||||
vs.compileFallbacks() // 编译 fallback 数组
|
vs.compileFallbacks() // 编译 fallback 数组
|
||||||
|
vs.preDecodeProbeData() // 预解码探针数据
|
||||||
|
}
|
||||||
|
|
||||||
|
// preDecodeProbeData 预解码所有探针的 Data 字段,避免运行时重复解码
|
||||||
|
func (vs *VScan) preDecodeProbeData() {
|
||||||
|
for i := range vs.Probes {
|
||||||
|
if vs.Probes[i].Data != "" {
|
||||||
|
decoded, err := DecodeData(vs.Probes[i].Data)
|
||||||
|
if err == nil {
|
||||||
|
vs.Probes[i].DecodedData = decoded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 同步到 map
|
||||||
|
for i := range vs.Probes {
|
||||||
|
vs.ProbesMapKName[vs.Probes[i].Name] = vs.Probes[i]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileFallbacks 编译所有探测器的 fallback 数组
|
// compileFallbacks 编译所有探测器的 fallback 数组
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ const MaxFallbacks = 20
|
|||||||
type Probe struct {
|
type Probe struct {
|
||||||
Name string // 探测器名称
|
Name string // 探测器名称
|
||||||
Data string // 探测数据
|
Data string // 探测数据
|
||||||
|
DecodedData []byte // 预解码的探测数据
|
||||||
Protocol string // 协议
|
Protocol string // 协议
|
||||||
Ports string // 端口范围
|
Ports string // 端口范围
|
||||||
SSLPorts string // SSL端口范围
|
SSLPorts string // SSL端口范围
|
||||||
|
|||||||
+26
-7
@@ -219,9 +219,14 @@ func (s *SmartPortInfoScanner) tryProbeList(probes []*Probe, usedProbes map[stri
|
|||||||
}
|
}
|
||||||
usedProbes[probe.Name] = struct{}{}
|
usedProbes[probe.Name] = struct{}{}
|
||||||
|
|
||||||
probeData, err := DecodeData(probe.Data)
|
// 优先使用预解码数据
|
||||||
if err != nil {
|
probeData := probe.DecodedData
|
||||||
continue
|
if probeData == nil {
|
||||||
|
var err error
|
||||||
|
probeData, err = DecodeData(probe.Data)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 TotalWaitMS 设置动态超时
|
// 使用 TotalWaitMS 设置动态超时
|
||||||
@@ -282,8 +287,15 @@ func (s *SmartPortInfoScanner) performSSLSecondStage(serviceInfo *ServiceInfo) *
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
probeData, err := DecodeData(probe.Data)
|
probeData := probe.DecodedData
|
||||||
if err != nil || len(probeData) == 0 {
|
if probeData == nil {
|
||||||
|
var decErr error
|
||||||
|
probeData, decErr = DecodeData(probe.Data)
|
||||||
|
if decErr != nil || len(probeData) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(probeData) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
response := s.info.Connect(probeData)
|
response := s.info.Connect(probeData)
|
||||||
@@ -317,8 +329,15 @@ func (s *SmartPortInfoScanner) tryHTTPSProbe() *ServiceInfo {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
probeData, err := DecodeData(probe.Data)
|
probeData := probe.DecodedData
|
||||||
if err != nil || len(probeData) == 0 {
|
if probeData == nil {
|
||||||
|
var decErr error
|
||||||
|
probeData, decErr = DecodeData(probe.Data)
|
||||||
|
if decErr != nil || len(probeData) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(probeData) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
response := s.info.Connect(probeData)
|
response := s.info.Connect(probeData)
|
||||||
|
|||||||
+21
-10
@@ -19,6 +19,25 @@ import (
|
|||||||
// Web服务检测
|
// Web服务检测
|
||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
|
// 全局共享 HTTP Client,复用连接池减少 TLS 握手和 TCP 建连开销
|
||||||
|
var (
|
||||||
|
sharedHTTPClientOnce sync.Once
|
||||||
|
sharedHTTPClient *http.Client
|
||||||
|
)
|
||||||
|
|
||||||
|
func getSharedHTTPClient(config *common.Config) *http.Client {
|
||||||
|
sharedHTTPClientOnce.Do(func() {
|
||||||
|
sharedHTTPClient = createHTTPClient(config)
|
||||||
|
// 启用 keep-alive 复用连接
|
||||||
|
if t, ok := sharedHTTPClient.Transport.(*http.Transport); ok {
|
||||||
|
t.DisableKeepAlives = false
|
||||||
|
t.MaxIdleConns = 100
|
||||||
|
t.MaxIdleConnsPerHost = 2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return sharedHTTPClient
|
||||||
|
}
|
||||||
|
|
||||||
// WebPortDetector 简化的Web检测器 - 保持API兼容
|
// WebPortDetector 简化的Web检测器 - 保持API兼容
|
||||||
type WebPortDetector struct{}
|
type WebPortDetector struct{}
|
||||||
|
|
||||||
@@ -59,15 +78,7 @@ func DetectHTTPScheme(host string, port int, config *common.Config, session *com
|
|||||||
// TLS握手失败,记录原因
|
// TLS握手失败,记录原因
|
||||||
|
|
||||||
// 第二步:尝试HTTP请求(回退检测HTTP)
|
// 第二步:尝试HTTP请求(回退检测HTTP)
|
||||||
client := &http.Client{
|
client := getSharedHTTPClient(config)
|
||||||
Timeout: timeout,
|
|
||||||
Transport: &http.Transport{
|
|
||||||
DisableKeepAlives: true,
|
|
||||||
},
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
return http.ErrUseLastResponse // 不跟随重定向
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用HEAD请求(更轻量)
|
// 使用HEAD请求(更轻量)
|
||||||
httpURL := fmt.Sprintf("http://%s", addr)
|
httpURL := fmt.Sprintf("http://%s", addr)
|
||||||
@@ -132,7 +143,7 @@ func (w *WebPortDetector) DetectHTTPServiceOnly(host string, port int, config *c
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
client := createHTTPClient(config)
|
client := getSharedHTTPClient(config)
|
||||||
|
|
||||||
// 尝试HTTP
|
// 尝试HTTP
|
||||||
if w.tryHTTP(client, host, port, "http") {
|
if w.tryHTTP(client, host, port, "http") {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "activemq", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "activemq", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo, sessi
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "cassandra", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "cassandra", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -109,6 +110,7 @@ type ConcurrentTestConfig struct {
|
|||||||
MaxRetries int // 最大重试次数,默认 3
|
MaxRetries int // 最大重试次数,默认 3
|
||||||
RetryDelay time.Duration // 重试延迟,默认 1s
|
RetryDelay time.Duration // 重试延迟,默认 1s
|
||||||
MaxConsecutiveNetErrors int // 连续网络错误阈值,超过则认为目标不可达,默认 5
|
MaxConsecutiveNetErrors int // 连续网络错误阈值,超过则认为目标不可达,默认 5
|
||||||
|
TargetAddr string // 目标地址 host:port,用于 TCP 预检(可选)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultConcurrentTestConfig 默认配置
|
// DefaultConcurrentTestConfig 默认配置
|
||||||
@@ -125,6 +127,13 @@ func DefaultConcurrentTestConfig(config *common.Config) ConcurrentTestConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DefaultConcurrentTestConfigWithTarget 带目标预检的默认配置
|
||||||
|
func DefaultConcurrentTestConfigWithTarget(config *common.Config, info *common.HostInfo) ConcurrentTestConfig {
|
||||||
|
cfg := DefaultConcurrentTestConfig(config)
|
||||||
|
cfg.TargetAddr = fmt.Sprintf("%s:%d", info.Host, info.Port)
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
// TestCredentialsConcurrently 并发测试多个凭据
|
// TestCredentialsConcurrently 并发测试多个凭据
|
||||||
// 找到成功凭据后立即通知其他 worker 停止
|
// 找到成功凭据后立即通知其他 worker 停止
|
||||||
func TestCredentialsConcurrently(
|
func TestCredentialsConcurrently(
|
||||||
@@ -142,6 +151,19 @@ func TestCredentialsConcurrently(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TCP 预检:快速验证目标可达,避免对不可达目标浪费全部凭据尝试
|
||||||
|
if testConfig.TargetAddr != "" {
|
||||||
|
preConn, err := net.DialTimeout("tcp", testConfig.TargetAddr, 3*time.Second)
|
||||||
|
if err != nil {
|
||||||
|
return &ScanResult{
|
||||||
|
Success: false,
|
||||||
|
Service: serviceName,
|
||||||
|
Error: fmt.Errorf("目标不可达: %w", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = preConn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// 调整并发数
|
// 调整并发数
|
||||||
concurrency := testConfig.Concurrency
|
concurrency := testConfig.Concurrency
|
||||||
if concurrency > len(credentials) {
|
if concurrency > len(credentials) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (p *FTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ftp", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ftp", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "kafka", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "kafka", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func (p *LDAPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ldap", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ldap", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo, session
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "mongodb", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "mongodb", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func (p *MSSQLPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "mssql", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "mssql", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "mysql", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "mysql", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (p *Neo4jPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "neo4j", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "neo4j", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo, session
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "oracle", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "oracle", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (p *PostgreSQLPlugin) Scan(ctx context.Context, info *common.HostInfo, sess
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "postgresql", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "postgresql", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo, sessio
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, config, state)
|
authFn := p.createAuthFunc(info, config, state)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "rabbitmq", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "rabbitmq", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func (p *RedisPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
testConfig.Concurrency = 20 // Redis 默认并发度更高
|
testConfig.Concurrency = 20 // Redis 默认并发度更高
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "redis", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "redis", testConfig)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func (p *RsyncPlugin) Scan(ctx context.Context, info *common.HostInfo, session *
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, creds, authFn, "rsync", testConfig)
|
result := TestCredentialsConcurrently(ctx, creds, authFn, "rsync", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
|
|||||||
}
|
}
|
||||||
|
|
||||||
authFn := p.createAuthFunc(info, auth, session)
|
authFn := p.createAuthFunc(info, auth, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, creds, authFn, "smb", testConfig)
|
result := TestCredentialsConcurrently(ctx, creds, authFn, "smb", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo, session *c
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, creds, authFn, "smtp", testConfig)
|
result := TestCredentialsConcurrently(ctx, creds, authFn, "smtp", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func (p *SSHPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ssh", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "ssh", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo, session
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, creds, authFn, "telnet", testConfig)
|
result := TestCredentialsConcurrently(ctx, creds, authFn, "telnet", testConfig)
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo, session *co
|
|||||||
|
|
||||||
// 使用公共框架进行并发凭据测试
|
// 使用公共框架进行并发凭据测试
|
||||||
authFn := p.createAuthFunc(info, session)
|
authFn := p.createAuthFunc(info, session)
|
||||||
testConfig := DefaultConcurrentTestConfig(config)
|
testConfig := DefaultConcurrentTestConfigWithTarget(config, info)
|
||||||
|
|
||||||
result := TestCredentialsConcurrently(ctx, credentials, authFn, "vnc", testConfig)
|
result := TestCredentialsConcurrently(ctx, credentials, authFn, "vnc", testConfig)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user