fix: harden scan edge cases

This commit is contained in:
ZacharyZcR
2026-06-01 03:32:13 +08:00
parent 8b558b4f12
commit 8ec96bfe6d
21 changed files with 534 additions and 67 deletions
+6 -1
View File
@@ -67,7 +67,12 @@ func (s *AliveScanStrategy) Execute(ctx context.Context, session *common.ScanSes
// performAliveScan 执行存活探测
func (s *AliveScanStrategy) performAliveScan(ctx context.Context, info common.HostInfo, session *common.ScanSession) {
iter, err := parsers.NewHostIterator(info.Host, session.Params.HostsFile, session.Params.ExcludeHosts)
excludes, err := loadHostExcludes(session.Params)
if err != nil {
session.LogError(i18n.Tr("parse_target_failed", err))
return
}
iter, err := parsers.NewHostIterator(info.Host, session.Params.HostsFile, excludes...)
if err != nil {
session.LogError(i18n.Tr("parse_target_failed", err))
return
+28
View File
@@ -0,0 +1,28 @@
package core
import (
"strings"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/parsers"
)
func loadHostExcludes(params *common.FlagVars) ([]string, error) {
if params == nil {
return nil, nil
}
excludes := make([]string, 0, 1)
if strings.TrimSpace(params.ExcludeHosts) != "" {
excludes = append(excludes, params.ExcludeHosts)
}
if strings.TrimSpace(params.ExcludeHostsFile) == "" {
return excludes, nil
}
lines, err := parsers.ReadLinesFromFile(params.ExcludeHostsFile)
if err != nil {
return nil, err
}
return append(excludes, lines...), nil
}
+29
View File
@@ -0,0 +1,29 @@
package core
import (
"os"
"reflect"
"testing"
"github.com/shadow1ng/fscan/common"
)
func TestLoadHostExcludesIncludesExcludeFile(t *testing.T) {
path := t.TempDir() + "/exclude.txt"
if err := os.WriteFile(path, []byte("192.168.1.2\n# comment\n192.168.1.3\n"), 0o600); err != nil {
t.Fatalf("WriteFile error = %v", err)
}
got, err := loadHostExcludes(&common.FlagVars{
ExcludeHosts: "192.168.1.1",
ExcludeHostsFile: path,
})
if err != nil {
t.Fatalf("loadHostExcludes error = %v", err)
}
want := []string{"192.168.1.1", "192.168.1.2", "192.168.1.3"}
if !reflect.DeepEqual(got, want) {
t.Fatalf("loadHostExcludes = %#v, want %#v", got, want)
}
}
+1 -1
View File
@@ -203,7 +203,7 @@ func EnhancedPortScan(ctx context.Context, hosts []string, ports string, timeout
// 初始化端口扫描进度条
if totalTasks > 0 && config.Output.ShowProgress {
description := i18n.Tr("port_scan_progress_description", threadNum)
common.InitProgressBar(int64(totalTasks), description)
common.InitProgressBar(totalTasks, description)
}
session.LogDebug(i18n.GetText("port_scan_debug_progress_ready"))
+14 -7
View File
@@ -145,7 +145,12 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
config := session.Config
state := session.State
iter, err := parsers.NewHostIterator(info.Host, session.Params.HostsFile, session.Params.ExcludeHosts)
excludes, err := loadHostExcludes(session.Params)
if err != nil {
session.LogError(fmt.Sprintf("%s: %v", i18n.GetText("parse_target_failed"), err))
return
}
iter, err := parsers.NewHostIterator(info.Host, session.Params.HostsFile, excludes...)
if err != nil {
session.LogError(fmt.Sprintf("%s: %v", i18n.GetText("parse_target_failed"), err))
return
@@ -157,6 +162,7 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
pluginsToRun, isCustomMode := s.GetPlugins(config)
totalAlive := 0
sawHosts := false
performedLiveness := false
for {
hosts, err := iter.NextBatch(ctx, targetHostBatchSize(config))
@@ -170,6 +176,7 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
sawHosts = true
if s.shouldPerformLivenessCheck(hosts, config) {
performedLiveness = true
hosts = CheckLive(ctx, hosts, false, session)
}
totalAlive += len(hosts)
@@ -181,7 +188,7 @@ func (s *ServiceScanStrategy) performHostScan(ctx context.Context, session *comm
s.scanHostBatch(ctx, session, hosts, info, pluginsToRun, isCustomMode, ch, wg)
}
if sawHosts && s.shouldReportAliveCount(config) {
if sawHosts && performedLiveness {
session.LogInfo(i18n.Tr("alive_hosts_count_info", totalAlive))
}
@@ -234,10 +241,6 @@ func (s *ServiceScanStrategy) scanHostBatch(ctx context.Context, session *common
}
}
func (s *ServiceScanStrategy) shouldReportAliveCount(config *common.Config) bool {
return !config.DisablePing
}
// dispatchUDPPlugins 分发UDP协议插件,跳过TCP端口扫描链路
func (s *ServiceScanStrategy) dispatchUDPPlugins(ctx context.Context, session *common.ScanSession, hosts []string, baseInfo common.HostInfo, config *common.Config, ch chan struct{}, wg *sync.WaitGroup) {
_, isCustomMode := s.GetPlugins(config)
@@ -341,7 +344,11 @@ func (s *ServiceScanStrategy) discoverTargets(ctx context.Context, hostInput str
config := session.Config
state := session.State
// 标准流程:解析目标主机
hosts, err := parsers.ParseIP(hostInput, session.Params.HostsFile, session.Params.ExcludeHosts)
excludes, err := loadHostExcludes(session.Params)
if err != nil {
return nil, fmt.Errorf("%s: %w", i18n.GetText("parse_target_failed"), err)
}
hosts, err := parsers.ParseIP(hostInput, session.Params.HostsFile, excludes...)
if err != nil {
return nil, fmt.Errorf("%s: %w", i18n.GetText("parse_target_failed"), err)
}
+3 -3
View File
@@ -39,7 +39,7 @@ type SocketIterator struct {
ports []int
hostIdx int
portIdx int
total int
total int64
mu sync.Mutex
}
@@ -51,7 +51,7 @@ func NewSocketIterator(hosts []string, ports []int, exclude map[int]struct{}) *S
return &SocketIterator{
hosts: hosts,
ports: sortedPorts,
total: len(hosts) * len(sortedPorts),
total: int64(len(hosts)) * int64(len(sortedPorts)),
}
}
@@ -113,7 +113,7 @@ func (it *SocketIterator) Next() (string, int, bool) {
}
// Total 返回总任务数(用于进度条)
func (it *SocketIterator) Total() int {
func (it *SocketIterator) Total() int64 {
return it.total
}
+11
View File
@@ -182,6 +182,17 @@ func TestSocketIterator_EmptyInputs(t *testing.T) {
})
}
func TestSocketIteratorTotalUsesInt64(t *testing.T) {
hosts := make([]string, 1<<20)
ports := make([]int, 4096)
it := NewSocketIterator(hosts, ports, nil)
want := int64(len(hosts)) * int64(len(ports))
if it.Total() != want {
t.Fatalf("Total() = %d, want %d", it.Total(), want)
}
}
// TestSocketIterator_PortPrioritySort 验证端口优先级排序
// 高价值端口(80, 443, 22等)应该排在前面
func TestSocketIterator_PortPrioritySort(t *testing.T) {