fscan/core/PortDiscoveryService.go
ZacharyZcR 31e59c9bee fix: 修复指定host:port时缺少端口开放信息显示的问题
问题:
- 使用 ./fscan -h 127.0.0.1:22 时没有显示端口开放信息
- 直接跳到漏洞扫描阶段,缺少端口发现过程的可见性
- 原因:预设host:port直接return,跳过了EnhancedPortScan调用

修复方案:
- 新增 validatePresetPorts 方法
- 对预设的host:port也执行端口验证和服务识别
- 调用 EnhancedPortScan 显示完整的端口开放信息

修复前:
[0ms] 开始主机扫描 → [0ms] 存活端口数量: 1 → [0ms] 开始漏洞扫描

修复后:
[0ms] 开始主机扫描 → [5ms] 端口开放 127.0.0.1:22 [ssh] → [5ms] 开始漏洞扫描

效果:
- 保持了统一的扫描流程显示
- 用户能看到端口连通性验证过程
- 预设端口也显示服务识别结果
2025-09-02 07:05:16 +00:00

160 lines
4.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package core
import (
"fmt"
"github.com/shadow1ng/fscan/common"
"github.com/shadow1ng/fscan/common/i18n"
"github.com/shadow1ng/fscan/common/parsers"
"strings"
)
/*
PortDiscoveryService.go - 端口发现服务
负责主机存活检测、端口扫描等端口发现相关功能,
从ServiceScanner中分离出来提高代码可维护性。
*/
// PortDiscoveryService 端口发现服务
type PortDiscoveryService struct{}
// NewPortDiscoveryService 创建端口发现服务
func NewPortDiscoveryService() *PortDiscoveryService {
return &PortDiscoveryService{}
}
// DiscoverTargets 发现目标主机和端口
func (p *PortDiscoveryService) DiscoverTargets(hostInput string, baseInfo common.HostInfo) ([]common.HostInfo, error) {
// 解析目标主机
hosts, err := parsers.ParseIP(hostInput, common.HostsFile, common.ExcludeHosts)
if err != nil {
return nil, fmt.Errorf(i18n.GetText("parse_error_target_failed"), err)
}
var targetInfos []common.HostInfo
// 主机存活性检测和端口扫描
if len(hosts) > 0 || len(common.HostPort) > 0 {
// 主机存活检测
if p.shouldPerformLivenessCheck(hosts) {
hosts = CheckLive(hosts, false)
common.LogBase(i18n.GetText("scan_alive_hosts_count", len(hosts)))
}
// 端口扫描
alivePorts := p.discoverAlivePorts(hosts)
if len(alivePorts) > 0 {
targetInfos = p.convertToTargetInfos(alivePorts, baseInfo)
}
}
return targetInfos, nil
}
// shouldPerformLivenessCheck 判断是否需要执行存活性检测
func (p *PortDiscoveryService) shouldPerformLivenessCheck(hosts []string) bool {
return common.DisablePing == false && len(hosts) > 1
}
// discoverAlivePorts 发现存活的端口
func (p *PortDiscoveryService) discoverAlivePorts(hosts []string) []string {
var alivePorts []string
// 如果已经有明确指定的host:port验证连通性并显示端口信息
if len(common.HostPort) > 0 {
alivePorts = p.validatePresetPorts(common.HostPort)
alivePorts = common.RemoveDuplicate(alivePorts)
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
common.HostPort = nil
return alivePorts
}
// 根据扫描模式选择端口扫描方式
if len(hosts) > 0 {
alivePorts = EnhancedPortScan(hosts, common.Ports, common.Timeout)
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
}
// UDP端口特殊处理当前仅支持SNMP的161端口
udpPorts := p.handleUDPPorts(hosts)
if len(udpPorts) > 0 {
alivePorts = append(alivePorts, udpPorts...)
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
}
return alivePorts
}
// convertToTargetInfos 将端口列表转换为目标信息
func (p *PortDiscoveryService) 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(i18n.GetText("parse_error_invalid_target_format", targetIP))
continue
}
info := baseInfo
info.Host = hostParts[0]
info.Ports = hostParts[1]
infos = append(infos, info)
}
return infos
}
// handleUDPPorts 处理UDP端口的特殊逻辑
func (p *PortDiscoveryService) handleUDPPorts(hosts []string) []string {
var udpPorts []string
// 检查是否包含SNMP端口161
portList := parsers.ParsePort(common.Ports)
hasPort161 := false
for _, port := range portList {
if port == 161 {
hasPort161 = true
break
}
}
// 如果端口列表包含161则为每个主机添加UDP 161端口
if hasPort161 {
for _, host := range hosts {
udpPorts = append(udpPorts, fmt.Sprintf("%s:161", host))
}
if len(udpPorts) > 0 {
common.LogBase(i18n.GetText("scan_snmp_udp_ports_added"))
}
}
return udpPorts
}
// validatePresetPorts 验证预设的host:port并显示端口信息模拟端口扫描过程
func (p *PortDiscoveryService) validatePresetPorts(hostPorts []string) []string {
var validPorts []string
for _, hostPort := range hostPorts {
// 解析host:port
hostParts := strings.Split(hostPort, ":")
if len(hostParts) != 2 {
continue
}
host := hostParts[0]
port := hostParts[1]
// 模拟单端口扫描,显示端口开放信息和服务识别
mockHosts := []string{host}
portResult := EnhancedPortScan(mockHosts, port, common.Timeout)
// 如果端口验证成功,添加到结果中
if len(portResult) > 0 {
validPorts = append(validPorts, portResult...)
}
}
return validPorts
}