mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
fix: 修复扫描逻辑
This commit is contained in:
+88
-467
@@ -5,7 +5,6 @@ import (
|
||||
"github.com/schollz/progressbar/v3"
|
||||
"github.com/shadow1ng/fscan/Common"
|
||||
"github.com/shadow1ng/fscan/WebScan/lib"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -13,31 +12,59 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 全局状态
|
||||
var (
|
||||
LocalScan bool // 本地扫描模式标识
|
||||
WebScan bool // Web扫描模式标识
|
||||
)
|
||||
|
||||
// ScanTask 表示单个扫描任务
|
||||
type ScanTask struct {
|
||||
pluginName string // 插件名称
|
||||
target Common.HostInfo // 目标信息
|
||||
}
|
||||
|
||||
// 添加一个本地插件集合,用于识别哪些插件是本地信息收集插件
|
||||
var localPlugins = map[string]bool{
|
||||
"localinfo": true,
|
||||
"dcinfo": true,
|
||||
"minidump": true,
|
||||
// ScanStrategy 定义扫描策略接口
|
||||
type ScanStrategy interface {
|
||||
// 名称和描述
|
||||
Name() string
|
||||
Description() string
|
||||
|
||||
// 执行扫描的主要方法
|
||||
Execute(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup)
|
||||
|
||||
// 插件管理方法
|
||||
GetPlugins() ([]string, bool)
|
||||
LogPluginInfo()
|
||||
|
||||
// 任务准备方法
|
||||
PrepareTargets(info Common.HostInfo) []Common.HostInfo
|
||||
IsPluginApplicable(plugin Common.ScanPlugin, targetPort int, isCustomMode bool) bool
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 主扫描流程
|
||||
// -----------------------------------------------------------------------------
|
||||
// Scanner 扫描器结构体
|
||||
type Scanner struct {
|
||||
strategy ScanStrategy
|
||||
}
|
||||
|
||||
// Scan 执行整体扫描流程的入口函数
|
||||
func Scan(info Common.HostInfo) {
|
||||
// NewScanner 创建新的扫描器并选择合适的策略
|
||||
func NewScanner(info Common.HostInfo) *Scanner {
|
||||
scanner := &Scanner{}
|
||||
scanner.selectStrategy(info)
|
||||
return scanner
|
||||
}
|
||||
|
||||
// selectStrategy 根据扫描配置选择适当的扫描策略
|
||||
func (s *Scanner) selectStrategy(info Common.HostInfo) {
|
||||
switch {
|
||||
case Common.LocalMode:
|
||||
s.strategy = NewLocalScanStrategy()
|
||||
Common.LogInfo("已选择本地扫描模式")
|
||||
case len(Common.URLs) > 0:
|
||||
s.strategy = NewWebScanStrategy()
|
||||
Common.LogInfo("已选择Web扫描模式")
|
||||
default:
|
||||
s.strategy = NewServiceScanStrategy()
|
||||
Common.LogInfo("已选择服务扫描模式")
|
||||
}
|
||||
}
|
||||
|
||||
// Scan 执行整体扫描流程
|
||||
func (s *Scanner) Scan(info Common.HostInfo) {
|
||||
Common.LogInfo("开始信息扫描")
|
||||
lib.Inithttp()
|
||||
|
||||
@@ -45,30 +72,16 @@ func Scan(info Common.HostInfo) {
|
||||
ch := make(chan struct{}, Common.ThreadNum)
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
// 选择并执行扫描模式
|
||||
selectScanMode(info, &ch, &wg)
|
||||
// 执行策略
|
||||
s.strategy.Execute(info, &ch, &wg)
|
||||
|
||||
// 等待所有扫描完成
|
||||
wg.Wait()
|
||||
finishScan()
|
||||
s.finishScan()
|
||||
}
|
||||
|
||||
// 根据配置选择扫描模式
|
||||
func selectScanMode(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
switch {
|
||||
case Common.LocalMode:
|
||||
LocalScan = true
|
||||
executeLocalScan(info, ch, wg)
|
||||
case len(Common.URLs) > 0:
|
||||
WebScan = true
|
||||
executeWebScan(info, ch, wg)
|
||||
default:
|
||||
executeHostScan(info, ch, wg)
|
||||
}
|
||||
}
|
||||
|
||||
// 完成扫描并输出结果
|
||||
func finishScan() {
|
||||
// finishScan 完成扫描并输出结果
|
||||
func (s *Scanner) finishScan() {
|
||||
if Common.ProgressBar != nil {
|
||||
Common.ProgressBar.Finish()
|
||||
fmt.Println()
|
||||
@@ -76,391 +89,13 @@ func finishScan() {
|
||||
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 三种扫描模式实现
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 执行本地信息收集
|
||||
func executeLocalScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
Common.LogInfo("执行本地信息收集")
|
||||
|
||||
// 验证插件配置
|
||||
if err := validateScanPlugins(); err != nil {
|
||||
Common.LogError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 输出插件信息
|
||||
logPluginInfo()
|
||||
|
||||
// 执行扫描任务
|
||||
executeScanTasks([]Common.HostInfo{info}, ch, wg)
|
||||
}
|
||||
|
||||
// 执行Web扫描
|
||||
func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
Common.LogInfo("开始Web扫描")
|
||||
|
||||
// 验证插件配置
|
||||
if err := validateScanPlugins(); err != nil {
|
||||
Common.LogError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 准备URL目标
|
||||
targetInfos := prepareURLTargets(info)
|
||||
|
||||
// 输出插件信息
|
||||
logPluginInfo()
|
||||
|
||||
// 执行扫描任务
|
||||
executeScanTasks(targetInfos, ch, wg)
|
||||
}
|
||||
|
||||
// 执行主机扫描
|
||||
func executeHostScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
// 验证扫描目标
|
||||
if info.Host == "" {
|
||||
Common.LogError("未指定扫描目标")
|
||||
return
|
||||
}
|
||||
|
||||
// 验证插件配置
|
||||
if err := validateScanPlugins(); err != nil {
|
||||
Common.LogError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 解析目标主机
|
||||
hosts, err := Common.ParseIP(info.Host, Common.HostsFile, Common.ExcludeHosts)
|
||||
if err != nil {
|
||||
Common.LogError(fmt.Sprintf("解析主机错误: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
Common.LogInfo("开始主机扫描")
|
||||
|
||||
// 输出插件信息
|
||||
logPluginInfo()
|
||||
|
||||
// 执行主机扫描
|
||||
performHostScan(hosts, info, ch, wg)
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 主机扫描流程详细实现
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 执行主机扫描的完整流程
|
||||
func performHostScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
var targetInfos []Common.HostInfo
|
||||
|
||||
// 主机存活性检测和端口扫描
|
||||
if len(hosts) > 0 || len(Common.HostPort) > 0 {
|
||||
// 主机存活检测
|
||||
if shouldPerformLivenessCheck(hosts) {
|
||||
hosts = CheckLive(hosts, Common.UsePing)
|
||||
Common.LogInfo(fmt.Sprintf("存活主机数量: %d", len(hosts)))
|
||||
}
|
||||
|
||||
// 端口扫描
|
||||
targetInfos = scanPortsAndPrepareTargets(hosts, info)
|
||||
}
|
||||
|
||||
// 添加URL目标
|
||||
targetInfos = appendURLTargets(targetInfos, info)
|
||||
|
||||
// 执行漏洞扫描
|
||||
if len(targetInfos) > 0 {
|
||||
Common.LogInfo("开始漏洞扫描")
|
||||
executeScanTasks(targetInfos, ch, wg)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否需要执行存活性检测
|
||||
func shouldPerformLivenessCheck(hosts []string) bool {
|
||||
return Common.DisablePing == false && len(hosts) > 1
|
||||
}
|
||||
|
||||
// 扫描端口并准备目标信息
|
||||
func scanPortsAndPrepareTargets(hosts []string, info Common.HostInfo) []Common.HostInfo {
|
||||
// 扫描存活端口
|
||||
alivePorts := discoverAlivePorts(hosts)
|
||||
if len(alivePorts) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 转换为目标信息
|
||||
return convertToTargetInfos(alivePorts, info)
|
||||
}
|
||||
|
||||
// 发现存活的端口
|
||||
func discoverAlivePorts(hosts []string) []string {
|
||||
var alivePorts []string
|
||||
|
||||
// 根据扫描模式选择端口扫描方式
|
||||
if WebScan || len(Common.URLs) > 0 {
|
||||
alivePorts = NoPortScan(hosts, Common.Ports)
|
||||
} else if len(hosts) > 0 {
|
||||
alivePorts = PortScan(hosts, Common.Ports, Common.Timeout)
|
||||
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
|
||||
}
|
||||
|
||||
// 合并额外指定的端口
|
||||
if len(Common.HostPort) > 0 {
|
||||
alivePorts = append(alivePorts, Common.HostPort...)
|
||||
alivePorts = Common.RemoveDuplicate(alivePorts)
|
||||
Common.HostPort = nil
|
||||
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
|
||||
}
|
||||
|
||||
return alivePorts
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 插件管理和解析
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// getAllLocalPlugins 返回所有本地插件的名称列表
|
||||
func getAllLocalPlugins() []string {
|
||||
var localPluginList []string
|
||||
for plugin := range localPlugins {
|
||||
localPluginList = append(localPluginList, plugin)
|
||||
}
|
||||
sort.Strings(localPluginList)
|
||||
return localPluginList
|
||||
}
|
||||
|
||||
// parsePluginList 解析逗号分隔的插件列表
|
||||
// pluginStr: 逗号分隔的插件字符串,如 "ssh,ftp,telnet"
|
||||
// 返回: 插件名称的字符串切片
|
||||
func parsePluginList(pluginStr string) []string {
|
||||
if pluginStr == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 按逗号分割并去除每个插件名称两端的空白
|
||||
plugins := strings.Split(pluginStr, ",")
|
||||
for i, p := range plugins {
|
||||
plugins[i] = strings.TrimSpace(p)
|
||||
}
|
||||
|
||||
// 过滤空字符串
|
||||
var result []string
|
||||
for _, p := range plugins {
|
||||
if p != "" {
|
||||
result = append(result, p)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// validateScanPlugins 验证扫描插件的有效性
|
||||
// 返回: 错误信息
|
||||
func validateScanPlugins() error {
|
||||
// 如果未指定扫描模式或使用All模式,则无需验证
|
||||
if Common.ScanMode == "" || Common.ScanMode == "All" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 解析插件列表
|
||||
plugins := parsePluginList(Common.ScanMode)
|
||||
if len(plugins) == 0 {
|
||||
plugins = []string{Common.ScanMode}
|
||||
}
|
||||
|
||||
// 验证每个插件是否有效
|
||||
var invalidPlugins []string
|
||||
for _, plugin := range plugins {
|
||||
if _, exists := Common.PluginManager[plugin]; !exists {
|
||||
invalidPlugins = append(invalidPlugins, plugin)
|
||||
}
|
||||
}
|
||||
|
||||
if len(invalidPlugins) > 0 {
|
||||
return fmt.Errorf("无效的插件: %s", strings.Join(invalidPlugins, ", "))
|
||||
}
|
||||
|
||||
// 如果是本地模式,验证是否包含非本地插件
|
||||
if Common.LocalMode {
|
||||
var nonLocalPlugins []string
|
||||
for _, plugin := range plugins {
|
||||
if !isLocalPlugin(plugin) {
|
||||
nonLocalPlugins = append(nonLocalPlugins, plugin)
|
||||
}
|
||||
}
|
||||
|
||||
if len(nonLocalPlugins) > 0 {
|
||||
Common.LogInfo(fmt.Sprintf("本地模式下,以下非本地插件将被忽略: %s", strings.Join(nonLocalPlugins, ", ")))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isLocalPlugin 判断插件是否为本地信息收集插件
|
||||
func isLocalPlugin(pluginName string) bool {
|
||||
return localPlugins[pluginName]
|
||||
}
|
||||
|
||||
// getPluginsToRun 获取要执行的插件列表
|
||||
// 返回: 插件列表和是否为自定义插件模式
|
||||
func getPluginsToRun() ([]string, bool) {
|
||||
// 本地模式处理
|
||||
if Common.LocalMode {
|
||||
// 在本地模式下只执行本地插件
|
||||
|
||||
// 如果指定了特定插件(单个或多个)
|
||||
if Common.ScanMode != "" && Common.ScanMode != "All" {
|
||||
requestedPlugins := parsePluginList(Common.ScanMode)
|
||||
if len(requestedPlugins) == 0 {
|
||||
requestedPlugins = []string{Common.ScanMode}
|
||||
}
|
||||
|
||||
// 过滤出本地插件
|
||||
var localPluginsToRun []string
|
||||
for _, plugin := range requestedPlugins {
|
||||
if isLocalPlugin(plugin) {
|
||||
localPluginsToRun = append(localPluginsToRun, plugin)
|
||||
}
|
||||
}
|
||||
|
||||
return localPluginsToRun, true
|
||||
}
|
||||
|
||||
// 如果是All模式或未指定,则返回所有本地插件
|
||||
return getAllLocalPlugins(), true
|
||||
}
|
||||
|
||||
// 非本地模式处理(保持原有行为)
|
||||
// 如果指定了插件列表(逗号分隔)
|
||||
if Common.ScanMode != "" && Common.ScanMode != "All" {
|
||||
plugins := parsePluginList(Common.ScanMode)
|
||||
if len(plugins) > 0 {
|
||||
return plugins, true
|
||||
}
|
||||
return []string{Common.ScanMode}, true
|
||||
}
|
||||
|
||||
// 默认情况:使用所有非本地插件
|
||||
allPlugins := GetAllPlugins()
|
||||
filteredPlugins := make([]string, 0, len(allPlugins))
|
||||
|
||||
for _, plugin := range allPlugins {
|
||||
if !isLocalPlugin(plugin) {
|
||||
filteredPlugins = append(filteredPlugins, plugin)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPlugins, false
|
||||
}
|
||||
|
||||
// logPluginInfo 输出插件信息
|
||||
func logPluginInfo() {
|
||||
if Common.LocalMode {
|
||||
if Common.ScanMode == "" || Common.ScanMode == "All" {
|
||||
Common.LogInfo("本地模式: 使用所有本地信息收集插件")
|
||||
} else {
|
||||
plugins := parsePluginList(Common.ScanMode)
|
||||
if len(plugins) == 0 {
|
||||
plugins = []string{Common.ScanMode}
|
||||
}
|
||||
|
||||
// 过滤出本地插件
|
||||
var localPluginsToRun []string
|
||||
for _, plugin := range plugins {
|
||||
if isLocalPlugin(plugin) {
|
||||
localPluginsToRun = append(localPluginsToRun, plugin)
|
||||
}
|
||||
}
|
||||
|
||||
if len(localPluginsToRun) > 1 {
|
||||
Common.LogInfo(fmt.Sprintf("本地模式: 使用本地插件: %s", strings.Join(localPluginsToRun, ", ")))
|
||||
} else if len(localPluginsToRun) == 1 {
|
||||
Common.LogInfo(fmt.Sprintf("本地模式: 使用本地插件: %s", localPluginsToRun[0]))
|
||||
} else {
|
||||
Common.LogInfo("本地模式: 未指定有效的本地插件,将不执行任何扫描")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 非本地模式的原有逻辑
|
||||
if Common.ScanMode == "" || Common.ScanMode == "All" {
|
||||
Common.LogInfo("使用所有可用插件(已排除本地敏感插件)")
|
||||
} else {
|
||||
plugins := parsePluginList(Common.ScanMode)
|
||||
if len(plugins) > 1 {
|
||||
Common.LogInfo(fmt.Sprintf("使用插件: %s", strings.Join(plugins, ", ")))
|
||||
} else {
|
||||
Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 目标准备
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 准备URL目标列表
|
||||
func prepareURLTargets(baseInfo Common.HostInfo) []Common.HostInfo {
|
||||
var targetInfos []Common.HostInfo
|
||||
|
||||
for _, url := range Common.URLs {
|
||||
urlInfo := baseInfo
|
||||
// 确保URL包含协议头
|
||||
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
||||
url = "http://" + url
|
||||
}
|
||||
urlInfo.Url = url
|
||||
targetInfos = append(targetInfos, urlInfo)
|
||||
}
|
||||
|
||||
return targetInfos
|
||||
}
|
||||
|
||||
// 将端口列表转换为目标信息
|
||||
func convertToTargetInfos(ports []string, baseInfo Common.HostInfo) []Common.HostInfo {
|
||||
var infos []Common.HostInfo
|
||||
|
||||
for _, targetIP := range ports {
|
||||
hostParts := strings.Split(targetIP, ":")
|
||||
if len(hostParts) != 2 {
|
||||
Common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP))
|
||||
continue
|
||||
}
|
||||
|
||||
info := baseInfo
|
||||
info.Host = hostParts[0]
|
||||
info.Ports = hostParts[1]
|
||||
infos = append(infos, info)
|
||||
}
|
||||
|
||||
return infos
|
||||
}
|
||||
|
||||
// 添加URL扫描目标
|
||||
func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) []Common.HostInfo {
|
||||
for _, url := range Common.URLs {
|
||||
urlInfo := baseInfo
|
||||
urlInfo.Url = url
|
||||
targetInfos = append(targetInfos, urlInfo)
|
||||
}
|
||||
return targetInfos
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 任务执行
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// 执行扫描任务集合
|
||||
func executeScanTasks(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
// 任务执行通用框架
|
||||
func ExecuteScanTasks(targets []Common.HostInfo, strategy ScanStrategy, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||
// 获取要执行的插件
|
||||
pluginsToRun, isCustomMode := getPluginsToRun()
|
||||
pluginsToRun, isCustomMode := strategy.GetPlugins()
|
||||
|
||||
// 准备扫描任务
|
||||
tasks := prepareScanTasks(targets, pluginsToRun, isCustomMode)
|
||||
tasks := prepareScanTasks(targets, pluginsToRun, isCustomMode, strategy)
|
||||
|
||||
// 输出扫描计划
|
||||
if Common.ShowScanPlan && len(tasks) > 0 {
|
||||
@@ -478,6 +113,35 @@ func executeScanTasks(targets []Common.HostInfo, ch *chan struct{}, wg *sync.Wai
|
||||
}
|
||||
}
|
||||
|
||||
// 准备扫描任务列表
|
||||
func prepareScanTasks(targets []Common.HostInfo, pluginsToRun []string, isCustomMode bool, strategy ScanStrategy) []ScanTask {
|
||||
var tasks []ScanTask
|
||||
|
||||
for _, target := range targets {
|
||||
targetPort := 0
|
||||
if target.Ports != "" {
|
||||
targetPort, _ = strconv.Atoi(target.Ports)
|
||||
}
|
||||
|
||||
for _, pluginName := range pluginsToRun {
|
||||
plugin, exists := Common.PluginManager[pluginName]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查插件是否适用于当前目标 (通过策略判断)
|
||||
if strategy.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
||||
tasks = append(tasks, ScanTask{
|
||||
pluginName: pluginName,
|
||||
target: target,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tasks
|
||||
}
|
||||
|
||||
// logScanPlan 输出扫描计划信息
|
||||
func logScanPlan(tasks []ScanTask) {
|
||||
// 统计每个插件的目标数量
|
||||
@@ -497,55 +161,6 @@ func logScanPlan(tasks []ScanTask) {
|
||||
Common.LogInfo(planInfo.String())
|
||||
}
|
||||
|
||||
// 准备扫描任务列表
|
||||
func prepareScanTasks(targets []Common.HostInfo, pluginsToRun []string, isCustomMode bool) []ScanTask {
|
||||
var tasks []ScanTask
|
||||
|
||||
for _, target := range targets {
|
||||
targetPort, _ := strconv.Atoi(target.Ports)
|
||||
|
||||
for _, pluginName := range pluginsToRun {
|
||||
plugin, exists := Common.PluginManager[pluginName]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查插件是否适用于当前目标
|
||||
if isPluginApplicable(plugin, targetPort, isCustomMode, pluginName) {
|
||||
tasks = append(tasks, ScanTask{
|
||||
pluginName: pluginName,
|
||||
target: target,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tasks
|
||||
}
|
||||
|
||||
// isPluginApplicable 判断插件是否适用于目标
|
||||
func isPluginApplicable(plugin Common.ScanPlugin, targetPort int, isCustomMode bool, pluginName string) bool {
|
||||
// 本地模式下,只执行本地插件
|
||||
if LocalScan {
|
||||
return isLocalPlugin(pluginName)
|
||||
}
|
||||
|
||||
// 非本地模式下,本地插件特殊处理
|
||||
if isLocalPlugin(pluginName) {
|
||||
// 只有在自定义模式下明确指定时才执行本地插件
|
||||
return isCustomMode
|
||||
}
|
||||
|
||||
// 特殊扫描模式下的处理
|
||||
if WebScan || isCustomMode {
|
||||
return true
|
||||
}
|
||||
|
||||
// 端口匹配检查
|
||||
// 无端口限制的插件或端口匹配的插件
|
||||
return len(plugin.Ports) == 0 || plugin.HasPort(targetPort)
|
||||
}
|
||||
|
||||
// 初始化进度条
|
||||
func initProgressBar(totalTasks int) {
|
||||
Common.ProgressBar = progressbar.NewOptions(totalTasks,
|
||||
@@ -623,3 +238,9 @@ func updateProgress() {
|
||||
Common.ProgressBar.Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
// 入口函数,向后兼容旧的调用方式
|
||||
func Scan(info Common.HostInfo) {
|
||||
scanner := NewScanner(info)
|
||||
scanner.Scan(info)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user