Compare commits

..

17 Commits

Author SHA1 Message Date
ZacharyZcR
4054c767dd refactor: 为MS17010插件添加包控制功能
- 在checkMS17010Vulnerability和checkDoublePulsar方法中添加包控制检查
- 统一错误处理和包计数逻辑
- 确保所有TCP连接遵循发包限制
2025-09-02 12:04:26 +00:00
ZacharyZcR
2385a730eb refactor: 为SMBGhost插件添加包控制功能
- 在detectVulnerability和gatherSystemInfo方法中添加包控制检查
- 统一错误处理和包计数逻辑
- 确保所有TCP连接遵循发包限制
2025-09-02 12:03:27 +00:00
ZacharyZcR
5bf3f7a2d9 refactor: 为SMB2插件添加包控制功能
- 在testCredential和detectProtocol方法中添加包控制检查
- 统一错误处理和包计数逻辑
- 确保所有TCP连接遵循发包限制
2025-09-02 12:02:27 +00:00
ZacharyZcR
53ab64669a refactor: 为SMBInfo插件添加包控制功能
- 在主TCP连接和SMBv2连接中添加包控制检查
- 统一错误处理和包计数逻辑
- 确保所有网络操作遵循发包限制
2025-09-02 12:01:18 +00:00
ZacharyZcR
767cb2dd21 refactor: 重构NetBIOS和FindNet插件使用统一发包控制
- 修改NetBIOS插件,在UDP和TCP连接中添加发包控制
- 修改FindNet插件,在RPC TCP连接中添加发包控制
- 统一包计数逻辑,支持UDP和TCP协议的包计数
- 保持现有Windows网络发现和主机信息收集功能
2025-09-02 11:58:52 +00:00
ZacharyZcR
f806a186e4 refactor: 重构ActiveMQ和Rsync插件使用统一发包控制
- 修改ActiveMQ插件,在STOMP连接中添加发包控制检查
- 修改Rsync插件,在TCP连接和服务识别中添加发包控制
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有消息队列和文件同步服务检测功能
2025-09-02 11:57:30 +00:00
ZacharyZcR
9e9485814d refactor: 重构Neo4j和Cassandra插件使用统一发包控制
- 修改Neo4j插件,在HTTP连接和服务识别中添加发包控制
- 修改Cassandra插件,在CQL连接和会话创建中添加发包控制
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有图数据库和分布式数据库检测功能
2025-09-02 11:56:23 +00:00
ZacharyZcR
36f0e5076d refactor: 重构Memcached和RabbitMQ插件使用统一发包控制
- 修改Memcached插件,在TCP连接和服务识别中添加发包控制
- 修改RabbitMQ插件,在AMQP连接、HTTP连接和管理接口中添加发包控制
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有缓存服务和消息队列检测功能
2025-09-02 11:52:59 +00:00
ZacharyZcR
98a9a4e1c2 refactor: 重构Elasticsearch和Kafka插件使用统一发包控制
- 修改Elasticsearch插件,在HTTP连接和服务识别中添加发包控制
- 修改Kafka插件,在Sarama客户端连接中添加发包控制和计数
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有搜索引擎和消息队列检测功能
2025-09-02 11:51:34 +00:00
ZacharyZcR
d9d0271d5b refactor: 重构VNC和RDP插件使用统一发包控制
- 修改VNC插件,在所有网络连接点添加发包控制和计数
- 修改RDP插件,在testRDPConnection和checkNLAStatus中添加发包控制
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有远程桌面检测功能完整性
2025-09-02 11:50:06 +00:00
ZacharyZcR
1febb54fe6 refactor: 重构SMB和LDAP插件使用统一发包控制
- 修改SMB插件,在testCredential和identifyService中添加发包控制
- 修改LDAP插件,在connectLDAP中添加发包控制和包计数
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有功能不变,提升网络操作一致性
2025-09-02 11:48:52 +00:00
ZacharyZcR
f8c8f3d1eb refactor: 重构MSSQL和Oracle插件使用统一发包控制
- 修改MSSQL插件,在testCredential和identifyService中添加发包控制
- 修改Oracle插件,虽然是占位代码,但为一致性添加发包检查
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 完成数据库插件系列的发包控制统一改造
2025-09-02 11:46:42 +00:00
ZacharyZcR
622795740f refactor: 重构PostgreSQL和MongoDB插件使用统一发包控制
- 修改PostgreSQL插件,在testCredential和identifyService中添加发包控制
- 修改MongoDB插件,在checkMongoAuth和testMongoCredential中添加发包控制
- 统一包计数逻辑,确保TCP连接成功和失败都正确计数
- 保持现有功能完整性,提升发包控制一致性
2025-09-02 11:45:12 +00:00
ZacharyZcR
a23c82142d refactor: 重构SMTP和Telnet插件使用统一发包控制
- 修改SMTP插件,在多个连接点添加发包控制
- 修改Telnet插件,在identifyService中使用SafeTCPDial包装器
- 保持现有功能不变,统一发包控制逻辑
2025-09-02 11:43:42 +00:00
ZacharyZcR
5f7669a537 refactor: 引入统一网络包装器,提升发包控制一致性
- 新增common/network.go统一网络操作包装器
- 重构MySQL/FTP/SSH/SNMP插件使用统一包装器
- 简化发包控制逻辑,避免重复代码
- 为未来代理、重试等功能扩展奠定基础
2025-09-02 11:35:46 +00:00
ZacharyZcR
d19abcac36 feat: 新增发包频率控制功能
- 添加-rate参数:控制每分钟最大发包次数
- 添加-maxpkts参数:控制整个程序最大发包总数
- 在所有网络操作点集成发包限制检查
- 支持端口扫描、Web检测、服务插件、POC扫描等场景
- 默认不限制,保持向后兼容性
2025-09-02 11:24:09 +00:00
ZacharyZcR
a36767c158 feat: 实现进度条网络包统计功能,支持TCP成功失败分类
- 新增全局原子操作包计数器,支持TCP成功/失败、UDP分类统计
- 端口扫描TCP连接区分成功失败计数,提供准确的网络活动监控
- HTTP请求统一归类到TCP统计,简化显示逻辑
- 进度条实时显示发包统计:发包:总数[TCP:成功✓失败✗,UDP:数量]
- 服务插件TCP/UDP连接同步计数,确保统计完整性
- 使用原子操作保证高并发环境下计数准确性
2025-09-02 08:45:44 +00:00
37 changed files with 947 additions and 33 deletions

View File

@ -63,6 +63,10 @@ var (
DownloadURL string // 下载文件的URL DownloadURL string // 下载文件的URL
DownloadSavePath string // 下载文件保存路径 DownloadSavePath string // 下载文件保存路径
// 发包频率控制相关变量
PacketRateLimit int64 // 每分钟最大发包次数 (0表示不限制)
MaxPacketCount int64 // 整个程序最大发包总数 (0表示不限制)
// Parse.go 使用的变量 // Parse.go 使用的变量
HostPort []string HostPort []string
URLs []string URLs []string
@ -199,6 +203,12 @@ func Flag(Info *HostInfo) {
flag.BoolVar(&DisableBrute, "nobr", false, i18n.GetText("flag_disable_brute")) flag.BoolVar(&DisableBrute, "nobr", false, i18n.GetText("flag_disable_brute"))
flag.IntVar(&MaxRetries, "retry", 3, i18n.GetText("flag_max_retries")) flag.IntVar(&MaxRetries, "retry", 3, i18n.GetText("flag_max_retries"))
// ═════════════════════════════════════════════════
// 发包频率控制参数
// ═════════════════════════════════════════════════
flag.Int64Var(&PacketRateLimit, "rate", 0, i18n.GetText("flag_packet_rate_limit"))
flag.Int64Var(&MaxPacketCount, "maxpkts", 0, i18n.GetText("flag_max_packet_count"))
// ═════════════════════════════════════════════════ // ═════════════════════════════════════════════════
// 输出与显示控制参数 // 输出与显示控制参数
// ═════════════════════════════════════════════════ // ═════════════════════════════════════════════════

View File

@ -1,7 +1,10 @@
package common package common
import ( import (
"fmt"
"strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/shadow1ng/fscan/common/config" "github.com/shadow1ng/fscan/common/config"
@ -101,6 +104,19 @@ var (
End int64 // 结束计数器 End int64 // 结束计数器
Num int64 // 数量计数器 Num int64 // 数量计数器
// 网络包计数器 - 使用原子操作确保线程安全
PacketCount int64 // 总发包数量
TCPPacketCount int64 // TCP包数量总计
TCPSuccessPacketCount int64 // TCP成功连接包数量
TCPFailedPacketCount int64 // TCP失败连接包数量
UDPPacketCount int64 // UDP包数量
HTTPPacketCount int64 // HTTP请求数量
// 发包频率控制变量
PacketRateStartTime int64 // 当前分钟的开始时间戳
PacketRateCurrentCount int64 // 当前分钟内的发包数量
PacketRateMutex sync.Mutex // 发包频率控制互斥锁
// ============================================================================= // =============================================================================
// 初始化控制 // 初始化控制
// ============================================================================= // =============================================================================
@ -172,4 +188,146 @@ const (
) )
// LogWithProgress 已在progressmanager.go中定义此处不重复 // LogWithProgress 已在progressmanager.go中定义此处不重复
// =============================================================================
// 网络包计数器功能
// =============================================================================
// IncrementPacketCount 增加总包计数(原子操作)
func IncrementPacketCount() int64 {
return atomic.AddInt64(&PacketCount, 1)
}
// IncrementTCPSuccessPacketCount 增加TCP成功连接包计数原子操作
func IncrementTCPSuccessPacketCount() int64 {
atomic.AddInt64(&TCPSuccessPacketCount, 1)
atomic.AddInt64(&TCPPacketCount, 1)
return atomic.AddInt64(&PacketCount, 1)
}
// IncrementTCPFailedPacketCount 增加TCP失败连接包计数原子操作
func IncrementTCPFailedPacketCount() int64 {
atomic.AddInt64(&TCPFailedPacketCount, 1)
atomic.AddInt64(&TCPPacketCount, 1)
return atomic.AddInt64(&PacketCount, 1)
}
// IncrementUDPPacketCount 增加UDP包计数原子操作
func IncrementUDPPacketCount() int64 {
atomic.AddInt64(&UDPPacketCount, 1)
return atomic.AddInt64(&PacketCount, 1)
}
// IncrementHTTPPacketCount 增加HTTP包计数原子操作
func IncrementHTTPPacketCount() int64 {
atomic.AddInt64(&HTTPPacketCount, 1)
return atomic.AddInt64(&PacketCount, 1)
}
// GetPacketCount 获取总包计数(原子操作)
func GetPacketCount() int64 {
return atomic.LoadInt64(&PacketCount)
}
// GetTCPPacketCount 获取TCP包计数原子操作
func GetTCPPacketCount() int64 {
return atomic.LoadInt64(&TCPPacketCount)
}
// GetTCPSuccessPacketCount 获取TCP成功连接包计数原子操作
func GetTCPSuccessPacketCount() int64 {
return atomic.LoadInt64(&TCPSuccessPacketCount)
}
// GetTCPFailedPacketCount 获取TCP失败连接包计数原子操作
func GetTCPFailedPacketCount() int64 {
return atomic.LoadInt64(&TCPFailedPacketCount)
}
// GetUDPPacketCount 获取UDP包计数原子操作
func GetUDPPacketCount() int64 {
return atomic.LoadInt64(&UDPPacketCount)
}
// GetHTTPPacketCount 获取HTTP包计数原子操作
func GetHTTPPacketCount() int64 {
return atomic.LoadInt64(&HTTPPacketCount)
}
// ResetPacketCounters 重置所有包计数器(原子操作)
func ResetPacketCounters() {
atomic.StoreInt64(&PacketCount, 0)
atomic.StoreInt64(&TCPPacketCount, 0)
atomic.StoreInt64(&TCPSuccessPacketCount, 0)
atomic.StoreInt64(&TCPFailedPacketCount, 0)
atomic.StoreInt64(&UDPPacketCount, 0)
atomic.StoreInt64(&HTTPPacketCount, 0)
}
// =============================================================================
// 发包频率控制功能
// =============================================================================
// CanSendPacket 检查是否可以发包 - 同时检查频率限制和总数限制
// 返回值: (可以发包, 错误信息)
func CanSendPacket() (bool, string) {
// 检查总数限制
if MaxPacketCount > 0 {
currentTotal := atomic.LoadInt64(&PacketCount)
if currentTotal >= MaxPacketCount {
return false, fmt.Sprintf("已达到最大发包数量限制: %d", MaxPacketCount)
}
}
// 检查频率限制
if PacketRateLimit > 0 {
PacketRateMutex.Lock()
defer PacketRateMutex.Unlock()
currentTime := time.Now().Unix() / 60 // 当前分钟
// 如果是新的分钟,重置计数器
if PacketRateStartTime != currentTime {
PacketRateStartTime = currentTime
atomic.StoreInt64(&PacketRateCurrentCount, 0)
}
// 检查当前分钟的发包数是否超限
currentCount := atomic.LoadInt64(&PacketRateCurrentCount)
if currentCount >= PacketRateLimit {
return false, fmt.Sprintf("已达到每分钟发包频率限制: %d", PacketRateLimit)
}
// 增加当前分钟的发包计数
atomic.AddInt64(&PacketRateCurrentCount, 1)
}
return true, ""
}
// WaitForPacketLimit 等待直到可以发包 - 智能等待策略
func WaitForPacketLimit() error {
maxWaitTime := 60 * time.Second // 最大等待1分钟
startWait := time.Now()
for {
canSend, reason := CanSendPacket()
if canSend {
return nil
}
// 如果是总数限制,直接返回错误
if MaxPacketCount > 0 && strings.Contains(reason, "最大发包数量") {
return fmt.Errorf(reason)
}
// 如果等待超时,返回错误
if time.Since(startWait) > maxWaitTime {
return fmt.Errorf("等待发包权限超时: %s", reason)
}
// 短暂休眠后重试
time.Sleep(100 * time.Millisecond)
}
}

View File

@ -187,6 +187,14 @@ var FlagMessages = map[string]map[string]string{
LangZH: "最大重试次数", LangZH: "最大重试次数",
LangEN: "Maximum retries", LangEN: "Maximum retries",
}, },
"flag_packet_rate_limit": {
LangZH: "每分钟最大发包次数 (0表示不限制)",
LangEN: "Maximum packets per minute (0 means no limit)",
},
"flag_max_packet_count": {
LangZH: "整个程序最大发包总数 (0表示不限制)",
LangEN: "Maximum total packet count for entire program (0 means no limit)",
},
"flag_output_file": { "flag_output_file": {
LangZH: "输出文件", LangZH: "输出文件",
LangEN: "Output file", LangEN: "Output file",

90
common/network.go Normal file
View File

@ -0,0 +1,90 @@
package common
import (
"fmt"
"net"
"net/http"
"time"
)
/*
network.go - 统一网络操作包装器
提供带发包控制统计和代理支持的统一网络操作接口
消除在每个插件中重复添加发包控制检查的需要
*/
// =============================================================================
// 统一网络连接包装器
// =============================================================================
// SafeDialTimeout 带发包控制的TCP连接
// 自动处理发包限制检查和统计计数
func SafeDialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
// 检查发包限制
if canSend, reason := CanSendPacket(); !canSend {
LogError(fmt.Sprintf("网络连接 %s 受限: %s", address, reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
// 建立连接 - 支持SOCKS5代理
// 注意WrapperTcpWithTimeout内部已经有计数逻辑这里不重复计数
conn, err := WrapperTcpWithTimeout(network, address, timeout)
return conn, err
}
// SafeUDPDial 带发包控制的UDP连接
func SafeUDPDial(network, address string, timeout time.Duration) (net.Conn, error) {
// 检查发包限制
if canSend, reason := CanSendPacket(); !canSend {
LogError(fmt.Sprintf("UDP连接 %s 受限: %s", address, reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
// 建立UDP连接
conn, err := net.DialTimeout(network, address, timeout)
// 统计UDP包数量
if err == nil {
IncrementUDPPacketCount()
}
return conn, err
}
// SafeHTTPDo 带发包控制的HTTP请求
func SafeHTTPDo(client *http.Client, req *http.Request) (*http.Response, error) {
// 检查发包限制
if canSend, reason := CanSendPacket(); !canSend {
LogError(fmt.Sprintf("HTTP请求 %s 受限: %s", req.URL.String(), reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
// 执行HTTP请求
resp, err := client.Do(req)
// 统计TCP包数量 (HTTP本质上是TCP)
if err != nil {
IncrementTCPFailedPacketCount()
} else {
IncrementTCPSuccessPacketCount()
}
return resp, err
}
// =============================================================================
// 便捷函数封装
// =============================================================================
// SafeTCPDial TCP连接的便捷封装
func SafeTCPDial(address string, timeout time.Duration) (net.Conn, error) {
return SafeDialTimeout("tcp", address, timeout)
}
// SafeTCPDialContext 带Context的TCP连接
func SafeTCPDialContext(network, address string, timeout time.Duration) (net.Conn, error) {
// 这个函数为将来扩展Context支持预留
return SafeDialTimeout(network, address, timeout)
}

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
"strings"
"sync" "sync"
"time" "time"
@ -171,7 +172,32 @@ func (pm *ProgressManager) generateProgressBar() string {
if pm.total == 0 { if pm.total == 0 {
spinner := pm.getActivityIndicator() spinner := pm.getActivityIndicator()
memInfo := pm.getMemoryInfo() memInfo := pm.getMemoryInfo()
return fmt.Sprintf("%s %s 等待中... %s", pm.description, spinner, memInfo)
// 获取TCP包统计包含原HTTP请求
packetCount := GetPacketCount()
tcpSuccess := GetTCPSuccessPacketCount()
tcpFailed := GetTCPFailedPacketCount()
udpCount := GetUDPPacketCount()
packetInfo := ""
if packetCount > 0 {
// 构建简化的包统计信息只显示TCP和UDP
details := make([]string, 0, 2)
if tcpSuccess > 0 || tcpFailed > 0 {
details = append(details, fmt.Sprintf("TCP:%d✓%d✗", tcpSuccess, tcpFailed))
}
if udpCount > 0 {
details = append(details, fmt.Sprintf("UDP:%d", udpCount))
}
if len(details) > 0 {
packetInfo = fmt.Sprintf(" 发包:%d[%s]", packetCount, strings.Join(details, ","))
} else {
packetInfo = fmt.Sprintf(" 发包:%d", packetCount)
}
}
return fmt.Sprintf("%s %s 等待中...%s %s", pm.description, spinner, packetInfo, memInfo)
} }
percentage := float64(pm.current) / float64(pm.total) * 100 percentage := float64(pm.current) / float64(pm.total) * 100
@ -231,9 +257,33 @@ func (pm *ProgressManager) generateProgressBar() string {
// 生成活跃指示器 // 生成活跃指示器
spinner := pm.getActivityIndicator() spinner := pm.getActivityIndicator()
// 获取TCP包统计包含原HTTP请求
packetCount := GetPacketCount()
tcpSuccess := GetTCPSuccessPacketCount()
tcpFailed := GetTCPFailedPacketCount()
udpCount := GetUDPPacketCount()
packetInfo := ""
if packetCount > 0 {
// 构建简化的包统计信息只显示TCP和UDP
details := make([]string, 0, 2)
if tcpSuccess > 0 || tcpFailed > 0 {
details = append(details, fmt.Sprintf("TCP:%d✓%d✗", tcpSuccess, tcpFailed))
}
if udpCount > 0 {
details = append(details, fmt.Sprintf("UDP:%d", udpCount))
}
if len(details) > 0 {
packetInfo = fmt.Sprintf(" 发包:%d[%s]", packetCount, strings.Join(details, ","))
} else {
packetInfo = fmt.Sprintf(" 发包:%d", packetCount)
}
}
// 构建基础进度条 // 构建基础进度条
baseProgress := fmt.Sprintf("%s %s %6.1f%% %s (%d/%d)%s%s", baseProgress := fmt.Sprintf("%s %s %6.1f%% %s (%d/%d)%s%s%s",
pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta) pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta, packetInfo)
// 添加内存信息 // 添加内存信息
memInfo := pm.getMemoryInfo() memInfo := pm.getMemoryInfo()

View File

@ -77,12 +77,24 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
common.UpdateProgressBar(1) common.UpdateProgressBar(1)
}() }()
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("端口扫描 %s 受限: %s", addr, reason))
return nil
}
// 连接测试 - 支持SOCKS5代理 // 连接测试 - 支持SOCKS5代理
conn, err := common.WrapperTcpWithTimeout("tcp", addr, to) conn, err := common.WrapperTcpWithTimeout("tcp", addr, to)
if err != nil { if err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
return nil return nil
} }
defer conn.Close() defer conn.Close()
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
// 记录开放端口(先记录到内存,延迟输出直到服务识别完成) // 记录开放端口(先记录到内存,延迟输出直到服务识别完成)
atomic.AddInt64(&count, 1) atomic.AddInt64(&count, 1)

View File

@ -253,12 +253,24 @@ func (w *WebPortDetector) tryHTTPConnectionDirect(ctx context.Context, host stri
req.Header.Set("User-Agent", "fscan-web-detector/2.2") req.Header.Set("User-Agent", "fscan-web-detector/2.2")
req.Header.Set("Accept", "*/*") req.Header.Set("Accept", "*/*")
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("HTTP请求 %s 受限: %s", req.URL.String(), reason))
return false
}
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
// HTTP请求失败计为TCP失败
common.IncrementTCPFailedPacketCount()
// 检查错误类型某些错误也表明是HTTP服务 // 检查错误类型某些错误也表明是HTTP服务
return w.analyzeHTTPError(err) return w.analyzeHTTPError(err)
} }
defer resp.Body.Close() defer resp.Body.Close()
// HTTP请求成功计为TCP成功
common.IncrementTCPSuccessPacketCount()
// 分析HTTP响应 // 分析HTTP响应
return w.analyzeHTTPResponse(resp, url) return w.analyzeHTTPResponse(resp, url)

View File

@ -61,6 +61,12 @@ func (p *ActiveMQPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanR
} }
func (p *ActiveMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *ActiveMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("ActiveMQ连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
@ -104,6 +110,17 @@ func (p *ActiveMQPlugin) authenticateSTOMP(conn net.Conn, username, password str
func (p *ActiveMQPlugin) identifyService(info *common.HostInfo) *ScanResult { func (p *ActiveMQPlugin) identifyService(info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("ActiveMQ识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "activemq",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout) conn, err := common.WrapperTcpWithTimeout("tcp", target, timeout)

View File

@ -61,6 +61,12 @@ func (p *CassandraPlugin) Scan(ctx context.Context, info *common.HostInfo) *Scan
} }
func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Cassandra连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
port, err := strconv.Atoi(info.Ports) port, err := strconv.Atoi(info.Ports)
if err != nil { if err != nil {
return false return false
@ -81,8 +87,10 @@ func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostI
session, err := cluster.CreateSession() session, err := cluster.CreateSession()
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false return false
} }
common.IncrementTCPSuccessPacketCount()
defer session.Close() defer session.Close()
var dummy interface{} var dummy interface{}
@ -94,6 +102,17 @@ func (p *CassandraPlugin) testCredential(ctx context.Context, info *common.HostI
func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Cassandra识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "cassandra",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
port, err := strconv.Atoi(info.Ports) port, err := strconv.Atoi(info.Ports)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
@ -111,6 +130,7 @@ func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.Host
session, err := cluster.CreateSession() session, err := cluster.CreateSession()
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
if strings.Contains(strings.ToLower(err.Error()), "authentication") { if strings.Contains(strings.ToLower(err.Error()), "authentication") {
banner := "Cassandra (需要认证)" banner := "Cassandra (需要认证)"
common.LogSuccess(fmt.Sprintf("Cassandra %s %s", target, banner)) common.LogSuccess(fmt.Sprintf("Cassandra %s %s", target, banner))
@ -126,6 +146,7 @@ func (p *CassandraPlugin) identifyService(ctx context.Context, info *common.Host
Error: err, Error: err,
} }
} }
common.IncrementTCPSuccessPacketCount()
defer session.Close() defer session.Close()
banner := "Cassandra" banner := "Cassandra"

View File

@ -63,6 +63,12 @@ func (p *ElasticsearchPlugin) Scan(ctx context.Context, info *common.HostInfo) *
func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Elasticsearch连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
client := &http.Client{ client := &http.Client{
Timeout: time.Duration(common.Timeout) * time.Second, Timeout: time.Duration(common.Timeout) * time.Second,
Transport: &http.Transport{ Transport: &http.Transport{
@ -89,8 +95,10 @@ func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.H
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false return false
} }
common.IncrementTCPSuccessPacketCount()
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode == 200 { if resp.StatusCode == 200 {
@ -110,6 +118,17 @@ func (p *ElasticsearchPlugin) testCredential(ctx context.Context, info *common.H
func (p *ElasticsearchPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *ElasticsearchPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
common.LogError(fmt.Sprintf("Elasticsearch识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "elasticsearch",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
if p.testCredential(ctx, info, Credential{Username: "", Password: ""}) { if p.testCredential(ctx, info, Credential{Username: "", Password: ""}) {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
banner := "Elasticsearch" banner := "Elasticsearch"

View File

@ -44,15 +44,27 @@ func (p *FindNetPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRe
} }
} }
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("FindNet连接 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "findnet",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
// 建立连接 // 建立连接
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "findnet", Service: "findnet",
Error: fmt.Errorf("连接RPC端口失败: %v", err), Error: fmt.Errorf("连接RPC端口失败: %v", err),
} }
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 设置超时 // 设置超时

View File

@ -63,7 +63,20 @@ func (p *FTPPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("FTP连接 %s 受限: %s", target, reason))
return nil
}
conn, err := ftplib.DialTimeout(target, timeout) conn, err := ftplib.DialTimeout(target, timeout)
if err == nil {
// 计数成功连接
common.IncrementTCPSuccessPacketCount()
} else {
// 计数失败连接
common.IncrementTCPFailedPacketCount()
}
if err != nil { if err != nil {
return nil return nil
} }
@ -83,7 +96,24 @@ func (p *FTPPlugin) identifyService(info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("FTP服务识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "ftp",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
conn, err := ftplib.DialTimeout(target, timeout) conn, err := ftplib.DialTimeout(target, timeout)
if err == nil {
// 计数成功连接
common.IncrementTCPSuccessPacketCount()
} else {
// 计数失败连接
common.IncrementTCPFailedPacketCount()
}
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,

View File

@ -72,6 +72,12 @@ func (p *KafkaPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins.
func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) sarama.Client { func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) sarama.Client {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Kafka连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return nil
}
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
@ -92,8 +98,10 @@ func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo,
brokers := []string{target} brokers := []string{target}
client, err := sarama.NewClient(brokers, config) client, err := sarama.NewClient(brokers, config)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return nil return nil
} }
common.IncrementTCPSuccessPacketCount()
return client return client
} }
@ -102,6 +110,16 @@ func (p *KafkaPlugin) testCredential(ctx context.Context, info *common.HostInfo,
func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result { func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Kafka识别 %s 受限: %s", target, reason))
return &plugins.Result{
Success: false,
Service: "kafka",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
// 尝试无认证连接 // 尝试无认证连接
emptyCred := plugins.Credential{Username: "", Password: ""} emptyCred := plugins.Credential{Username: "", Password: ""}
client := p.testCredential(ctx, info, emptyCred) client := p.testCredential(ctx, info, emptyCred)
@ -124,6 +142,7 @@ func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo
brokers := []string{target} brokers := []string{target}
client, err := sarama.NewClient(brokers, config) client, err := sarama.NewClient(brokers, config)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
// 如果连接失败尝试检查是否是Kafka协议错误 // 如果连接失败尝试检查是否是Kafka协议错误
if p.isKafkaProtocolError(err) { if p.isKafkaProtocolError(err) {
banner := "Kafka (需要认证)" banner := "Kafka (需要认证)"
@ -140,6 +159,7 @@ func (p *KafkaPlugin) identifyService(ctx context.Context, info *common.HostInfo
Error: fmt.Errorf("无法识别为Kafka服务: %v", err), Error: fmt.Errorf("无法识别为Kafka服务: %v", err),
} }
} }
common.IncrementTCPSuccessPacketCount()
defer client.Close() defer client.Close()
banner := "Kafka" banner := "Kafka"

View File

@ -84,17 +84,46 @@ func (p *LDAPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
} }
func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, creds plugins.Credential) (*ldaplib.Conn, error) { func (p *LDAPPlugin) connectLDAP(ctx context.Context, info *common.HostInfo, creds plugins.Credential) (*ldaplib.Conn, error) {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("LDAP连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
var conn *ldaplib.Conn
var err error
if info.Ports == "636" { if info.Ports == "636" {
return ldaplib.DialTLS("tcp", target, nil) conn, err = ldaplib.DialTLS("tcp", target, nil)
} else {
conn, err = ldaplib.Dial("tcp", target)
} }
return ldaplib.Dial("tcp", target)
// 统计包数量
if err != nil {
common.IncrementTCPFailedPacketCount()
} else {
common.IncrementTCPSuccessPacketCount()
}
return conn, err
} }
func (p *LDAPPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result { func (p *LDAPPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("LDAP识别 %s 受限: %s", target, reason))
return &plugins.Result{
Success: false,
Service: "ldap",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
conn, err := p.connectLDAP(ctx, info, plugins.Credential{}) conn, err := p.connectLDAP(ctx, info, plugins.Credential{})
if err != nil { if err != nil {
return &plugins.Result{ return &plugins.Result{

View File

@ -59,12 +59,21 @@ func (p *MemcachedPlugin) Scan(ctx context.Context, info *common.HostInfo) *Scan
func (p *MemcachedPlugin) connectToMemcached(ctx context.Context, info *common.HostInfo) net.Conn { func (p *MemcachedPlugin) connectToMemcached(ctx context.Context, info *common.HostInfo) net.Conn {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Memcached连接 %s 受限: %s", target, reason))
return nil
}
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
conn, err := net.DialTimeout("tcp", target, timeout) conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return nil return nil
} }
common.IncrementTCPSuccessPacketCount()
conn.SetDeadline(time.Now().Add(timeout)) conn.SetDeadline(time.Now().Add(timeout))
@ -100,6 +109,16 @@ func (p *MemcachedPlugin) testBasicCommand(conn net.Conn) bool {
func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *MemcachedPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Memcached识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "memcached",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
conn := p.connectToMemcached(ctx, info) conn := p.connectToMemcached(ctx, info)
if conn == nil { if conn == nil {
return &ScanResult{ return &ScanResult{

View File

@ -135,6 +135,12 @@ func (p *MongoDBPlugin) mongodbUnauth(ctx context.Context, info *common.HostInfo
// checkMongoAuth 检查MongoDB认证状态 - 基于原始工作版本 // checkMongoAuth 检查MongoDB认证状态 - 基于原始工作版本
func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, packet []byte) (string, error) { func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, packet []byte) (string, error) {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MongoDB连接 %s 受限: %s", address, reason))
return "", fmt.Errorf("发包受限: %s", reason)
}
// 创建连接超时上下文 // 创建连接超时上下文
connCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second) connCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
defer cancel() defer cancel()
@ -143,8 +149,11 @@ func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, pack
var d net.Dialer var d net.Dialer
conn, err := d.DialContext(connCtx, "tcp", address) conn, err := d.DialContext(connCtx, "tcp", address)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return "", fmt.Errorf("连接失败: %v", err) return "", fmt.Errorf("连接失败: %v", err)
} }
// 连接成功计数TCP成功包
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 检查上下文是否已取消 // 检查上下文是否已取消
@ -216,6 +225,12 @@ func (p *MongoDBPlugin) createOpQueryPacket() []byte {
// testMongoCredential 使用官方MongoDB驱动测试凭据 // testMongoCredential 使用官方MongoDB驱动测试凭据
func (p *MongoDBPlugin) testMongoCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool { func (p *MongoDBPlugin) testMongoCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MongoDB认证测试 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
// 构建MongoDB连接URI // 构建MongoDB连接URI
var uri string var uri string
if cred.Username != "" && cred.Password != "" { if cred.Username != "" && cred.Password != "" {
@ -242,13 +257,17 @@ func (p *MongoDBPlugin) testMongoCredential(ctx context.Context, info *common.Ho
// 连接到MongoDB // 连接到MongoDB
client, err := mongo.Connect(authCtx, clientOptions) client, err := mongo.Connect(authCtx, clientOptions)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false return false
} }
// 连接成功计数TCP成功包
common.IncrementTCPSuccessPacketCount()
defer client.Disconnect(authCtx) defer client.Disconnect(authCtx)
// 测试连接 - 尝试ping数据库 // 测试连接 - 尝试ping数据库
err = client.Ping(authCtx, nil) err = client.Ping(authCtx, nil)
if err != nil { if err != nil {
// ping失败但已经连接成功了不需要额外计数
return false return false
} }

View File

@ -296,11 +296,18 @@ func init() {
// checkMS17010Vulnerability 检测MS17-010漏洞 (从原始MS17010.go复制和适配) // checkMS17010Vulnerability 检测MS17-010漏洞 (从原始MS17010.go复制和适配)
func (p *MS17010Plugin) checkMS17010Vulnerability(ip string) (bool, string, error) { func (p *MS17010Plugin) checkMS17010Vulnerability(ip string) (bool, string, error) {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
return false, "", fmt.Errorf("发包受限: %s", reason)
}
// 连接目标 // 连接目标
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false, "", fmt.Errorf("连接错误: %v", err) return false, "", fmt.Errorf("连接错误: %v", err)
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
if err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)); err != nil { if err = conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)); err != nil {
@ -401,10 +408,17 @@ func (p *MS17010Plugin) checkMS17010Vulnerability(ip string) (bool, string, erro
// checkDoublePulsar 检测DOUBLEPULSAR后门 // checkDoublePulsar 检测DOUBLEPULSAR后门
func (p *MS17010Plugin) checkDoublePulsar(ip string) bool { func (p *MS17010Plugin) checkDoublePulsar(ip string) bool {
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second) // 检查发包限制
if err != nil { if canSend, _ := common.CanSendPacket(); !canSend {
return false return false
} }
conn, err := net.DialTimeout("tcp", ip+":445", time.Duration(common.Timeout)*time.Second)
if err != nil {
common.IncrementTCPFailedPacketCount()
return false
}
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 简化的后门检测逻辑 // 简化的后门检测逻辑

View File

@ -64,6 +64,12 @@ func (p *MSSQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResu
func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB { func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MSSQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return nil
}
connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%s;database=master;connection timeout=%d", connStr := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%s;database=master;connection timeout=%d",
info.Host, cred.Username, cred.Password, info.Ports, common.Timeout) info.Host, cred.Username, cred.Password, info.Ports, common.Timeout)
@ -81,9 +87,13 @@ func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
err = db.PingContext(pingCtx) err = db.PingContext(pingCtx)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
db.Close() db.Close()
return nil return nil
} }
// 连接成功计数TCP成功包
common.IncrementTCPSuccessPacketCount()
return db return db
} }
@ -97,6 +107,16 @@ func (p *MSSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MSSQL识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "mssql",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
connStr := fmt.Sprintf("server=%s;user id=invalid;password=invalid;port=%s;database=master;connection timeout=%d", connStr := fmt.Sprintf("server=%s;user id=invalid;password=invalid;port=%s;database=master;connection timeout=%d",
info.Host, info.Ports, common.Timeout) info.Host, info.Ports, common.Timeout)
@ -115,6 +135,13 @@ func (p *MSSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo
err = db.PingContext(pingCtx) err = db.PingContext(pingCtx)
// 统计包数量
if err != nil {
common.IncrementTCPFailedPacketCount()
} else {
common.IncrementTCPSuccessPacketCount()
}
var banner string var banner string
if err != nil && (strings.Contains(strings.ToLower(err.Error()), "login failed") || if err != nil && (strings.Contains(strings.ToLower(err.Error()), "login failed") ||
strings.Contains(strings.ToLower(err.Error()), "mssql") || strings.Contains(strings.ToLower(err.Error()), "mssql") ||

View File

@ -61,6 +61,13 @@ func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResu
} }
func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("MySQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
// 建立MySQL连接
connStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/mysql?charset=utf8&timeout=%ds", connStr := fmt.Sprintf("%s:%s@tcp(%s:%s)/mysql?charset=utf8&timeout=%ds",
cred.Username, cred.Password, info.Host, info.Ports, common.Timeout) cred.Username, cred.Password, info.Host, info.Ports, common.Timeout)
@ -75,6 +82,12 @@ func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
db.SetMaxIdleConns(0) db.SetMaxIdleConns(0)
err = db.PingContext(ctx) err = db.PingContext(ctx)
// 统计MySQL连接结果
if err == nil {
common.IncrementTCPSuccessPacketCount()
} else {
common.IncrementTCPFailedPacketCount()
}
return err == nil return err == nil
} }
@ -82,7 +95,7 @@ func (p *MySQLPlugin) testCredential(ctx context.Context, info *common.HostInfo,
func (p *MySQLPlugin) identifyService(info *common.HostInfo) *ScanResult { func (p *MySQLPlugin) identifyService(info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := common.WrapperTcpWithTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,

View File

@ -67,6 +67,12 @@ func (p *Neo4jPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResu
func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.HostInfo) *ScanResult {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Neo4j未授权检测 %s:%s 受限: %s", info.Host, info.Ports, reason))
return nil
}
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports) baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
client := &http.Client{ client := &http.Client{
@ -80,8 +86,10 @@ func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.H
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return nil return nil
} }
common.IncrementTCPSuccessPacketCount()
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode == 200 { if resp.StatusCode == 200 {
@ -96,6 +104,12 @@ func (p *Neo4jPlugin) testUnauthorizedAccess(ctx context.Context, info *common.H
} }
func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Neo4j凭据测试 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports) baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
client := &http.Client{ client := &http.Client{
@ -112,8 +126,10 @@ func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo,
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false return false
} }
common.IncrementTCPSuccessPacketCount()
defer resp.Body.Close() defer resp.Body.Close()
return resp.StatusCode == 200 return resp.StatusCode == 200
@ -127,6 +143,17 @@ func (p *Neo4jPlugin) testCredential(ctx context.Context, info *common.HostInfo,
func (p *Neo4jPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *Neo4jPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Neo4j识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "neo4j",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports) baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
client := &http.Client{ client := &http.Client{
@ -144,12 +171,14 @@ func (p *Neo4jPlugin) identifyService(ctx context.Context, info *common.HostInfo
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "neo4j", Service: "neo4j",
Error: err, Error: err,
} }
} }
common.IncrementTCPSuccessPacketCount()
defer resp.Body.Close() defer resp.Body.Close()
var banner string var banner string

View File

@ -158,10 +158,19 @@ func (p *NetBIOSPlugin) queryNetBIOSNames(host string) (*NetBIOSInfo, error) {
} }
target := fmt.Sprintf("%s:137", host) target := fmt.Sprintf("%s:137", host)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("NetBIOS UDP连接 %s 受限: %s", target, reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementUDPPacketCount()
return nil, fmt.Errorf("连接NetBIOS名称服务失败: %v", err) return nil, fmt.Errorf("连接NetBIOS名称服务失败: %v", err)
} }
common.IncrementUDPPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
@ -183,10 +192,19 @@ func (p *NetBIOSPlugin) queryNetBIOSNames(host string) (*NetBIOSInfo, error) {
// queryNetBIOSSession 查询NetBIOS会话服务(TCP 139) // queryNetBIOSSession 查询NetBIOS会话服务(TCP 139)
func (p *NetBIOSPlugin) queryNetBIOSSession(host string) (*NetBIOSInfo, error) { func (p *NetBIOSPlugin) queryNetBIOSSession(host string) (*NetBIOSInfo, error) {
target := fmt.Sprintf("%s:139", host) target := fmt.Sprintf("%s:139", host)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("NetBIOS TCP连接 %s 受限: %s", target, reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return nil, fmt.Errorf("连接NetBIOS会话服务失败: %v", err) return nil, fmt.Errorf("连接NetBIOS会话服务失败: %v", err)
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))

View File

@ -25,6 +25,16 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRes
return p.identifyService(ctx, info) return p.identifyService(ctx, info)
} }
// Oracle驱动未安装但保持与其他插件一致的发包检查
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Oracle连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return &ScanResult{
Success: false,
Service: "oracle",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "oracle", Service: "oracle",
@ -41,6 +51,16 @@ func (p *OraclePlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRes
func (p *OraclePlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *OraclePlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
// 保持与其他插件一致的发包检查
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Oracle识别 %s:%s 受限: %s", info.Host, info.Ports, reason))
return &ScanResult{
Success: false,
Service: "oracle",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "oracle", Service: "oracle",

View File

@ -64,6 +64,12 @@ func (p *PostgreSQLPlugin) Scan(ctx context.Context, info *common.HostInfo) *Sca
func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB { func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) *sql.DB {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("PostgreSQL连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return nil
}
connStr := fmt.Sprintf("postgres://%s:%s@%s:%s/postgres?sslmode=disable&connect_timeout=%d", connStr := fmt.Sprintf("postgres://%s:%s@%s:%s/postgres?sslmode=disable&connect_timeout=%d",
cred.Username, cred.Password, info.Host, info.Ports, common.Timeout) cred.Username, cred.Password, info.Host, info.Ports, common.Timeout)
@ -81,9 +87,13 @@ func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.Host
err = db.PingContext(pingCtx) err = db.PingContext(pingCtx)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
db.Close() db.Close()
return nil return nil
} }
// 连接成功计数TCP成功包
common.IncrementTCPSuccessPacketCount()
return db return db
} }
@ -96,6 +106,16 @@ func (p *PostgreSQLPlugin) testCredential(ctx context.Context, info *common.Host
func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("PostgreSQL识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "postgresql",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
connStr := fmt.Sprintf("postgres://invalid:invalid@%s:%s/postgres?sslmode=disable&connect_timeout=%d", connStr := fmt.Sprintf("postgres://invalid:invalid@%s:%s/postgres?sslmode=disable&connect_timeout=%d",
info.Host, info.Ports, common.Timeout) info.Host, info.Ports, common.Timeout)
@ -114,6 +134,13 @@ func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.Hos
err = db.PingContext(pingCtx) err = db.PingContext(pingCtx)
// 统计包数量
if err != nil {
common.IncrementTCPFailedPacketCount()
} else {
common.IncrementTCPSuccessPacketCount()
}
// 改进识别逻辑任何PostgreSQL相关的响应都认为是有效服务 // 改进识别逻辑任何PostgreSQL相关的响应都认为是有效服务
var banner string var banner string
if err != nil { if err != nil {

View File

@ -90,15 +90,27 @@ func (p *RabbitMQPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugi
func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.HostInfo) *plugins.Result { func (p *RabbitMQPlugin) testAMQPProtocol(ctx context.Context, info *common.HostInfo) *plugins.Result {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("RabbitMQ AMQP连接 %s 受限: %s", target, reason))
return &plugins.Result{
Success: false,
Service: "rabbitmq",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
// 连接到AMQP端口 // 连接到AMQP端口
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return &plugins.Result{ return &plugins.Result{
Success: false, Success: false,
Service: "rabbitmq", Service: "rabbitmq",
Error: err, Error: err,
} }
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 设置超时 // 设置超时
@ -174,6 +186,12 @@ func min(a, b int) int {
} }
func (p *RabbitMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool { func (p *RabbitMQPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("RabbitMQ HTTP连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports) baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
client := &http.Client{ client := &http.Client{
@ -190,8 +208,10 @@ func (p *RabbitMQPlugin) testCredential(ctx context.Context, info *common.HostIn
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false return false
} }
common.IncrementTCPSuccessPacketCount()
defer resp.Body.Close() defer resp.Body.Close()
return resp.StatusCode == 200 return resp.StatusCode == 200
@ -217,6 +237,17 @@ func (p *RabbitMQPlugin) identifyService(ctx context.Context, info *common.HostI
// testManagementInterface 检测RabbitMQ管理界面 // testManagementInterface 检测RabbitMQ管理界面
func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *common.HostInfo) *plugins.Result { func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *common.HostInfo) *plugins.Result {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("RabbitMQ管理接口 %s 受限: %s", target, reason))
return &plugins.Result{
Success: false,
Service: "rabbitmq",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports) baseURL := fmt.Sprintf("http://%s:%s", info.Host, info.Ports)
client := &http.Client{ client := &http.Client{
@ -234,12 +265,14 @@ func (p *RabbitMQPlugin) testManagementInterface(ctx context.Context, info *comm
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return &plugins.Result{ return &plugins.Result{
Success: false, Success: false,
Service: "rabbitmq", Service: "rabbitmq",
Error: err, Error: err,
} }
} }
common.IncrementTCPSuccessPacketCount()
defer resp.Body.Close() defer resp.Body.Close()
var banner string var banner string

View File

@ -100,10 +100,18 @@ func (p *RDPPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult
func (p *RDPPlugin) testRDPConnection(ctx context.Context, info *common.HostInfo) bool { func (p *RDPPlugin) testRDPConnection(ctx context.Context, info *common.HostInfo) bool {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) // 检查发包限制
if err != nil { if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("RDP连接 %s 受限: %s", target, reason))
return false return false
} }
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil {
common.IncrementTCPFailedPacketCount()
return false
}
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
@ -136,13 +144,19 @@ func (p *RDPPlugin) testRDPConnection(ctx context.Context, info *common.HostInfo
// checkNLAStatus 检查网络级别身份验证状态 // checkNLAStatus 检查网络级别身份验证状态
func (p *RDPPlugin) checkNLAStatus(ctx context.Context, info *common.HostInfo) string { func (p *RDPPlugin) checkNLAStatus(ctx context.Context, info *common.HostInfo) string {
// 简化实现实际需要解析RDP协商响应 // 检查发包限制
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("RDP NLA检测 %s 受限: %s", target, reason))
return "检测失败"
}
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return "检测失败" return "检测失败"
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))

View File

@ -121,15 +121,26 @@ func (p *RedisPlugin) testCredential(ctx context.Context, info *common.HostInfo,
err error err error
} }
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Redis连接 %s 受限: %s", target, reason))
return nil
}
connChan := make(chan connResult, 1) connChan := make(chan connResult, 1)
go func() { go func() {
// 建立TCP连接 // 建立TCP连接
conn, err := net.DialTimeout("tcp", target, timeout) conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil { if err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
connChan <- connResult{nil, err} connChan <- connResult{nil, err}
return return
} }
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
// 如果有密码,进行认证 // 如果有密码,进行认证
if cred.Password != "" { if cred.Password != "" {
@ -350,9 +361,21 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Redis服务识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "redis",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
// 尝试连接Redis服务 // 尝试连接Redis服务
conn, err := net.DialTimeout("tcp", target, timeout) conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil { if err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "redis", Service: "redis",
@ -360,6 +383,9 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
} }
} }
defer conn.Close() defer conn.Close()
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
// 发送PING命令识别 // 发送PING命令识别
pingCmd := "PING\r\n" pingCmd := "PING\r\n"

View File

@ -91,12 +91,21 @@ func (p *RsyncPlugin) testCredential(ctx context.Context, info *common.HostInfo,
func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo) net.Conn { func (p *RsyncPlugin) connectToRsync(ctx context.Context, info *common.HostInfo) net.Conn {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Rsync连接 %s 受限: %s", target, reason))
return nil
}
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
conn, err := net.DialTimeout("tcp", target, timeout) conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return nil return nil
} }
common.IncrementTCPSuccessPacketCount()
conn.SetDeadline(time.Now().Add(timeout)) conn.SetDeadline(time.Now().Add(timeout))
return conn return conn
@ -137,6 +146,16 @@ func (p *RsyncPlugin) getModules(conn net.Conn) []string {
func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *RsyncPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Rsync识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "rsync",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
conn := p.connectToRsync(ctx, info) conn := p.connectToRsync(ctx, info)
if conn == nil { if conn == nil {
return &ScanResult{ return &ScanResult{

View File

@ -105,6 +105,12 @@ func (p *SmbPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult
// testCredential 测试单个凭据 // testCredential 测试单个凭据
func (p *SmbPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *SmbPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("SMB连接 %s:%s 受限: %s", info.Host, info.Ports, reason))
return false
}
options := smb.Options{ options := smb.Options{
Host: info.Host, Host: info.Host,
Port: 445, Port: 445,
@ -124,8 +130,10 @@ func (p *SmbPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
session, err := smb.NewSession(options, false) session, err := smb.NewSession(options, false)
if err == nil { if err == nil {
defer session.Close() defer session.Close()
common.IncrementTCPSuccessPacketCount()
resultChan <- session.IsAuthenticated resultChan <- session.IsAuthenticated
} else { } else {
common.IncrementTCPFailedPacketCount()
resultChan <- false resultChan <- false
} }
}() }()
@ -199,6 +207,17 @@ func (p *SmbPlugin) testShareAccess(ctx context.Context, info *common.HostInfo,
// identifyService 服务识别 // identifyService 服务识别
func (p *SmbPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *SmbPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
common.LogError(fmt.Sprintf("SMB识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "smb",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
if p.testCredential(ctx, info, Credential{Username: "", Password: ""}) { if p.testCredential(ctx, info, Credential{Username: "", Password: ""}) {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
banner := "SMB文件共享服务" banner := "SMB文件共享服务"

View File

@ -105,6 +105,11 @@ func (p *Smb2Plugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResul
// testCredential 测试单个凭据 - 简化的SMB2协议检测 // testCredential 测试单个凭据 - 简化的SMB2协议检测
func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
// 检查发包限制
if canSend, _ := common.CanSendPacket(); !canSend {
return false
}
// 基于TCP连接的简单SMB2检测 // 基于TCP连接的简单SMB2检测
timeoutCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second) timeoutCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
defer cancel() defer cancel()
@ -112,8 +117,10 @@ func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo,
dialer := &net.Dialer{} dialer := &net.Dialer{}
conn, err := dialer.DialContext(timeoutCtx, "tcp", fmt.Sprintf("%s:445", info.Host)) conn, err := dialer.DialContext(timeoutCtx, "tcp", fmt.Sprintf("%s:445", info.Host))
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false return false
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 发送SMB2协商请求 // 发送SMB2协商请求
@ -153,10 +160,17 @@ func (p *Smb2Plugin) testCredential(ctx context.Context, info *common.HostInfo,
// detectProtocol 检测SMB2协议信息 // detectProtocol 检测SMB2协议信息
func (p *Smb2Plugin) detectProtocol(ctx context.Context, info *common.HostInfo) string { func (p *Smb2Plugin) detectProtocol(ctx context.Context, info *common.HostInfo) string {
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:445", info.Host), 5*time.Second) // 检查发包限制
if err != nil { if canSend, _ := common.CanSendPacket(); !canSend {
return "" return ""
} }
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:445", info.Host), 5*time.Second)
if err != nil {
common.IncrementTCPFailedPacketCount()
return ""
}
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 发送SMB2协商请求获取版本信息 // 发送SMB2协商请求获取版本信息

View File

@ -156,11 +156,18 @@ func (p *SmbGhostPlugin) detectVulnerability(ctx context.Context, info *common.H
addr := fmt.Sprintf("%s:445", info.Host) addr := fmt.Sprintf("%s:445", info.Host)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
return false, fmt.Errorf("发包受限: %s", reason)
}
// 建立TCP连接 // 建立TCP连接
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout) conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return false, fmt.Errorf("连接失败: %v", err) return false, fmt.Errorf("连接失败: %v", err)
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 设置连接超时 // 设置连接超时
@ -200,10 +207,17 @@ func (p *SmbGhostPlugin) gatherSystemInfo(ctx context.Context, info *common.Host
addr := fmt.Sprintf("%s:445", info.Host) addr := fmt.Sprintf("%s:445", info.Host)
timeout := time.Duration(common.Timeout) * time.Second timeout := time.Duration(common.Timeout) * time.Second
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout) // 检查发包限制
if err != nil { if canSend, _ := common.CanSendPacket(); !canSend {
return "" return ""
} }
conn, err := common.WrapperTcpWithTimeout("tcp", addr, timeout)
if err != nil {
common.IncrementTCPFailedPacketCount()
return ""
}
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
// 发送标准SMB协商请求获取系统信息 // 发送标准SMB协商请求获取系统信息

View File

@ -41,15 +41,27 @@ func (p *SMBInfoPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRe
} }
} }
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("SMBInfo连接 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "smbinfo",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
// 建立连接 // 建立连接
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "smbinfo", Service: "smbinfo",
Error: fmt.Errorf("连接失败: %v", err), Error: fmt.Errorf("连接失败: %v", err),
} }
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
@ -253,11 +265,18 @@ func (p *SMBInfoPlugin) handleSMBv1(conn net.Conn, target string) (*SMBInfo, err
// handleSMBv2 处理SMBv2协议信息收集 // handleSMBv2 处理SMBv2协议信息收集
func (p *SMBInfoPlugin) handleSMBv2(target string) (*SMBInfo, error) { func (p *SMBInfoPlugin) handleSMBv2(target string) (*SMBInfo, error) {
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
return nil, fmt.Errorf("SMBv2连接受限: %s", reason)
}
// 重新建立连接处理SMBv2 // 重新建立连接处理SMBv2
conn2, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn2, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return nil, fmt.Errorf("SMBv2连接失败: %v", err) return nil, fmt.Errorf("SMBv2连接失败: %v", err)
} }
common.IncrementTCPSuccessPacketCount()
defer conn2.Close() defer conn2.Close()
conn2.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn2.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))

View File

@ -90,12 +90,23 @@ func (p *SMTPPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins.R
func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo) *plugins.Result { func (p *SMTPPlugin) testOpenRelay(ctx context.Context, info *common.HostInfo) *plugins.Result {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("SMTP连接 %s 受限: %s", target, reason))
return nil
}
// 设置超时的Dialer // 设置超时的Dialer
dialer := &net.Dialer{ dialer := &net.Dialer{
Timeout: time.Duration(common.Timeout) * time.Second, Timeout: time.Duration(common.Timeout) * time.Second,
} }
conn, err := dialer.DialContext(ctx, "tcp", target) conn, err := dialer.DialContext(ctx, "tcp", target)
if err == nil {
common.IncrementTCPSuccessPacketCount()
} else {
common.IncrementTCPFailedPacketCount()
}
if err != nil { if err != nil {
return nil return nil
} }
@ -132,12 +143,23 @@ func (p *SMTPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
common.LogDebug(fmt.Sprintf("SMTP测试凭据: %s:%s", cred.Username, cred.Password)) common.LogDebug(fmt.Sprintf("SMTP测试凭据: %s:%s", cred.Username, cred.Password))
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("SMTP凭据测试 %s 受限: %s", target, reason))
return false
}
// 设置连接超时 // 设置连接超时
dialer := &net.Dialer{ dialer := &net.Dialer{
Timeout: timeout, Timeout: timeout,
} }
conn, err := dialer.DialContext(ctx, "tcp", target) conn, err := dialer.DialContext(ctx, "tcp", target)
if err == nil {
common.IncrementTCPSuccessPacketCount()
} else {
common.IncrementTCPFailedPacketCount()
}
if err != nil { if err != nil {
common.LogDebug(fmt.Sprintf("SMTP连接失败: %v", err)) common.LogDebug(fmt.Sprintf("SMTP连接失败: %v", err))
return false return false
@ -177,7 +199,8 @@ func (p *SMTPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo) string { func (p *SMTPPlugin) getServerInfo(ctx context.Context, info *common.HostInfo) string {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) // 使用统一TCP包装器
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
return "" return ""
} }
@ -207,11 +230,8 @@ func (p *SMTPPlugin) identifyService(ctx context.Context, info *common.HostInfo)
if serverInfo != "" { if serverInfo != "" {
banner = fmt.Sprintf("SMTP邮件服务 (%s)", serverInfo) banner = fmt.Sprintf("SMTP邮件服务 (%s)", serverInfo)
} else { } else {
// 简单连接测试 // 使用统一TCP包装器进行简单连接测试
dialer := &net.Dialer{ conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
Timeout: time.Duration(common.Timeout) * time.Second,
}
conn, err := dialer.DialContext(ctx, "tcp", target)
if err != nil { if err != nil {
return &plugins.Result{ return &plugins.Result{
Success: false, Success: false,

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"net"
"time" "time"
"github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common"
@ -62,7 +61,8 @@ func (p *SNMPPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResul
func (p *SNMPPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *SNMPPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second) // 使用统一UDP包装器
conn, err := common.SafeUDPDial("udp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
return false return false
} }
@ -120,7 +120,8 @@ func (p *SNMPPlugin) identifyService(ctx context.Context, info *common.HostInfo)
} }
} }
conn, err := net.DialTimeout("udp", target, time.Duration(common.Timeout)*time.Second) // 使用统一UDP包装器
conn, err := common.SafeUDPDial("udp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,

View File

@ -164,6 +164,12 @@ func (p *SSHPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
err error err error
} }
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("SSH连接 %s 受限: %s", target, reason))
return nil
}
resultChan := make(chan sshResult, 1) resultChan := make(chan sshResult, 1)
go func() { go func() {
client, err := ssh.Dial("tcp", target, config) client, err := ssh.Dial("tcp", target, config)
@ -173,8 +179,12 @@ func (p *SSHPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
select { select {
case result := <-resultChan: case result := <-resultChan:
if result.err != nil { if result.err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
return nil return nil
} }
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
return result.client return result.client
case <-ctx.Done(): case <-ctx.Done():
return nil return nil
@ -197,8 +207,8 @@ func (p *SSHPlugin) executeCommand(client *ssh.Client, cmd string) (string, erro
func (p *SSHPlugin) identifyService(info *common.HostInfo) *ScanResult { func (p *SSHPlugin) identifyService(info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 尝试连接获取SSH Banner // 使用统一TCP包装器获取SSH Banner
conn, err := common.WrapperTcpWithTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
return &ScanResult{ return &ScanResult{
Success: false, Success: false,

View File

@ -65,8 +65,19 @@ func (p *TelnetPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins
func (p *TelnetPlugin) testTelnetCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool { func (p *TelnetPlugin) testTelnetCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
address := fmt.Sprintf("%s:%s", info.Host, info.Ports) address := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("Telnet连接 %s 受限: %s", address, reason))
return false
}
// 创建带超时的连接 // 创建带超时的连接
conn, err := net.DialTimeout("tcp", address, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", address, time.Duration(common.Timeout)*time.Second)
if err == nil {
common.IncrementTCPSuccessPacketCount()
} else {
common.IncrementTCPFailedPacketCount()
}
if err != nil { if err != nil {
return false return false
} }
@ -304,7 +315,8 @@ func (p *TelnetPlugin) isLoginFailed(data string) bool {
func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result { func (p *TelnetPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) // 使用统一TCP包装器
conn, err := common.SafeTCPDial(target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
return &plugins.Result{ return &plugins.Result{
Success: false, Success: false,

View File

@ -70,10 +70,18 @@ func (p *VNCPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult
func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) // 检查发包限制
if err != nil { if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("VNC未授权检测 %s 受限: %s", target, reason))
return nil return nil
} }
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil {
common.IncrementTCPFailedPacketCount()
return nil
}
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
@ -105,10 +113,18 @@ func (p *VNCPlugin) testUnauthAccess(ctx context.Context, info *common.HostInfo)
func (p *VNCPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool { func (p *VNCPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) // 检查发包限制
if err != nil { if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("VNC认证测试 %s 受限: %s", target, reason))
return false return false
} }
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil {
common.IncrementTCPFailedPacketCount()
return false
}
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
@ -229,14 +245,26 @@ func (p *VNCPlugin) reverseBits(b byte) byte {
func (p *VNCPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult { func (p *VNCPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
target := fmt.Sprintf("%s:%s", info.Host, info.Ports) target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("VNC识别 %s 受限: %s", target, reason))
return &ScanResult{
Success: false,
Service: "vnc",
Error: fmt.Errorf("发包受限: %s", reason),
}
}
conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) conn, err := net.DialTimeout("tcp", target, time.Duration(common.Timeout)*time.Second)
if err != nil { if err != nil {
common.IncrementTCPFailedPacketCount()
return &ScanResult{ return &ScanResult{
Success: false, Success: false,
Service: "vnc", Service: "vnc",
Error: err, Error: err,
} }
} }
common.IncrementTCPSuccessPacketCount()
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))

View File

@ -675,6 +675,12 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) {
} }
// 执行请求 // 执行请求
// 检查发包限制
if canSend, reason := common.CanSendPacket(); !canSend {
common.LogError(fmt.Sprintf("POC HTTP请求 %s 受限: %s", req.URL.String(), reason))
return nil, fmt.Errorf("发包受限: %s", reason)
}
var ( var (
oResp *http.Response oResp *http.Response
err error err error
@ -685,10 +691,15 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) {
} else { } else {
oResp, err = ClientNoRedirect.Do(req) oResp, err = ClientNoRedirect.Do(req)
} }
if err != nil { if err != nil {
// HTTP请求失败计为TCP失败
common.IncrementTCPFailedPacketCount()
return nil, fmt.Errorf("请求执行失败: %w", err) return nil, fmt.Errorf("请求执行失败: %w", err)
} }
// HTTP请求成功计为TCP成功
common.IncrementTCPSuccessPacketCount()
defer oResp.Body.Close() defer oResp.Body.Close()
// 解析响应 // 解析响应