feat: 实现进度条网络包统计功能,支持TCP成功失败分类

- 新增全局原子操作包计数器,支持TCP成功/失败、UDP分类统计
- 端口扫描TCP连接区分成功失败计数,提供准确的网络活动监控
- HTTP请求统一归类到TCP统计,简化显示逻辑
- 进度条实时显示发包统计:发包:总数[TCP:成功✓失败✗,UDP:数量]
- 服务插件TCP/UDP连接同步计数,确保统计完整性
- 使用原子操作保证高并发环境下计数准确性
This commit is contained in:
ZacharyZcR 2025-09-02 08:45:44 +00:00
parent a7ea2f5198
commit a36767c158
8 changed files with 176 additions and 5 deletions

View File

@ -2,6 +2,7 @@ package common
import (
"sync"
"sync/atomic"
"time"
"github.com/shadow1ng/fscan/common/config"
@ -101,6 +102,14 @@ var (
End int64 // 结束计数器
Num int64 // 数量计数器
// 网络包计数器 - 使用原子操作确保线程安全
PacketCount int64 // 总发包数量
TCPPacketCount int64 // TCP包数量总计
TCPSuccessPacketCount int64 // TCP成功连接包数量
TCPFailedPacketCount int64 // TCP失败连接包数量
UDPPacketCount int64 // UDP包数量
HTTPPacketCount int64 // HTTP请求数量
// =============================================================================
// 初始化控制
// =============================================================================
@ -173,3 +182,78 @@ const (
// 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)
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"runtime"
"strings"
"sync"
"time"
@ -171,7 +172,32 @@ func (pm *ProgressManager) generateProgressBar() string {
if pm.total == 0 {
spinner := pm.getActivityIndicator()
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
@ -231,9 +257,33 @@ func (pm *ProgressManager) generateProgressBar() string {
// 生成活跃指示器
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",
pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta)
baseProgress := fmt.Sprintf("%s %s %6.1f%% %s (%d/%d)%s%s%s",
pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta, packetInfo)
// 添加内存信息
memInfo := pm.getMemoryInfo()

View File

@ -79,11 +79,17 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
// 连接测试 - 支持SOCKS5代理
conn, err := common.WrapperTcpWithTimeout("tcp", addr, to)
if err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
return nil
}
defer conn.Close()
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
// 记录开放端口(先记录到内存,延迟输出直到服务识别完成)
atomic.AddInt64(&count, 1)
aliveMap.Store(addr, struct{}{})

View File

@ -254,12 +254,18 @@ func (w *WebPortDetector) tryHTTPConnectionDirect(ctx context.Context, host stri
req.Header.Set("Accept", "*/*")
resp, err := client.Do(req)
if err != nil {
// HTTP请求失败计为TCP失败
common.IncrementTCPFailedPacketCount()
// 检查错误类型某些错误也表明是HTTP服务
return w.analyzeHTTPError(err)
}
defer resp.Body.Close()
// HTTP请求成功计为TCP成功
common.IncrementTCPSuccessPacketCount()
// 分析HTTP响应
return w.analyzeHTTPResponse(resp, url)
}

View File

@ -127,10 +127,15 @@ func (p *RedisPlugin) testCredential(ctx context.Context, info *common.HostInfo,
// 建立TCP连接
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
connChan <- connResult{nil, err}
return
}
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
// 如果有密码,进行认证
if cred.Password != "" {
authCmd := fmt.Sprintf("AUTH %s\r\n", cred.Password)
@ -353,6 +358,8 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
// 尝试连接Redis服务
conn, err := net.DialTimeout("tcp", target, timeout)
if err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
return &ScanResult{
Success: false,
Service: "redis",
@ -361,6 +368,9 @@ func (p *RedisPlugin) identifyService(ctx context.Context, info *common.HostInfo
}
defer conn.Close()
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
// 发送PING命令识别
pingCmd := "PING\r\n"
conn.SetWriteDeadline(time.Now().Add(timeout))

View File

@ -68,6 +68,9 @@ func (p *SNMPPlugin) testCredential(ctx context.Context, info *common.HostInfo,
}
defer conn.Close()
// 计数UDP连接包
common.IncrementUDPPacketCount()
packet := p.buildSNMPGetRequest(cred.Username, "1.3.6.1.2.1.1.1.0")
conn.SetWriteDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second))
@ -130,6 +133,9 @@ func (p *SNMPPlugin) identifyService(ctx context.Context, info *common.HostInfo)
}
defer conn.Close()
// 计数UDP连接包
common.IncrementUDPPacketCount()
banner := "SNMP网络管理服务"
common.LogSuccess(fmt.Sprintf("SNMP %s %s", target, banner))

View File

@ -173,8 +173,12 @@ func (p *SSHPlugin) testCredential(ctx context.Context, info *common.HostInfo, c
select {
case result := <-resultChan:
if result.err != nil {
// 计数TCP连接失败包
common.IncrementTCPFailedPacketCount()
return nil
}
// 计数TCP连接成功包
common.IncrementTCPSuccessPacketCount()
return result.client
case <-ctx.Done():
return nil

View File

@ -687,8 +687,13 @@ func DoRequest(req *http.Request, redirect bool) (*Response, error) {
}
if err != nil {
// HTTP请求失败计为TCP失败
common.IncrementTCPFailedPacketCount()
return nil, fmt.Errorf("请求执行失败: %w", err)
}
// HTTP请求成功计为TCP成功
common.IncrementTCPSuccessPacketCount()
defer oResp.Body.Close()
// 解析响应