CN to EN from Core

This commit is contained in:
Budi Komarudin 2025-03-19 10:31:08 +00:00
parent 968064c240
commit 50a53e1fd8
6 changed files with 616 additions and 616 deletions

View File

@ -14,38 +14,38 @@ import (
)
var (
AliveHosts []string // 存活主机列表
ExistHosts = make(map[string]struct{}) // 已发现主机记录
livewg sync.WaitGroup // 存活检测等待组
AliveHosts []string // List of alive hosts
ExistHosts = make(map[string]struct{}) // Record of discovered hosts
livewg sync.WaitGroup // Wait group for live detection
)
// CheckLive 检测主机存活状态
// CheckLive checks the live status of hosts
func CheckLive(hostslist []string, Ping bool) []string {
// 创建主机通道
// Create host channel
chanHosts := make(chan string, len(hostslist))
// 处理存活主机
// Handle alive hosts
go handleAliveHosts(chanHosts, hostslist, Ping)
// 根据Ping参数选择检测方式
// Choose detection method based on Ping parameter
if Ping {
// 使用ping方式探测
// Use ping method
RunPing(hostslist, chanHosts)
} else {
probeWithICMP(hostslist, chanHosts)
}
// 等待所有检测完成
// Wait for all detections to complete
livewg.Wait()
close(chanHosts)
// 输出存活统计信息
// Print alive statistics
printAliveStats(hostslist)
return AliveHosts
}
// IsContain 检查切片中是否包含指定元素
// IsContain checks if the slice contains the specified element
func IsContain(items []string, item string) bool {
for _, eachItem := range items {
if eachItem == item {
@ -61,7 +61,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
ExistHosts[ip] = struct{}{}
AliveHosts = append(AliveHosts, ip)
// 使用Output系统保存存活主机信息
// Use Output system to save alive host information
protocol := "ICMP"
if isPing {
protocol = "PING"
@ -78,7 +78,7 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
}
Common.SaveResult(result)
// 保留原有的控制台输出
// Keep original console output
if !Common.Silent {
Common.LogSuccess(Common.GetText("target_alive", ip, protocol))
}
@ -87,9 +87,9 @@ func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
}
}
// probeWithICMP 使用ICMP方式探测
// probeWithICMP probes using ICMP method
func probeWithICMP(hostslist []string, chanHosts chan string) {
// 尝试监听本地ICMP
// Try to listen on local ICMP
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err == nil {
RunIcmp1(hostslist, conn, chanHosts)
@ -99,7 +99,7 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
Common.LogError(Common.GetText("icmp_listen_failed", err))
Common.LogInfo(Common.GetText("trying_no_listen_icmp"))
// 尝试无监听ICMP探测
// Try no-listen ICMP probe
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
if err == nil {
defer conn2.Close()
@ -111,22 +111,22 @@ func probeWithICMP(hostslist []string, chanHosts chan string) {
Common.LogInfo(Common.GetText("insufficient_privileges"))
Common.LogInfo(Common.GetText("switching_to_ping"))
// 降级使用ping探测
// Fallback to ping probe
RunPing(hostslist, chanHosts)
}
// printAliveStats 打印存活统计信息
// printAliveStats prints alive statistics
func printAliveStats(hostslist []string) {
// 大规模扫描时输出 /16 网段统计
if len(hostslist) > 1000 {
// Output /16 subnet statistics for large-scale scans
if (len(hostslist) > 1000) {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
for i := 0; i < len(arrTop); i++ {
Common.LogSuccess(Common.GetText("subnet_16_alive", arrTop[i], arrLen[i]))
}
}
// 输出 /24 网段统计
if len(hostslist) > 256 {
// Output /24 subnet statistics
if (len(hostslist) > 256) {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
for i := 0; i < len(arrTop); i++ {
Common.LogSuccess(Common.GetText("subnet_24_alive", arrTop[i], arrLen[i]))
@ -134,17 +134,17 @@ func printAliveStats(hostslist []string) {
}
}
// RunIcmp1 使用ICMP批量探测主机存活(监听模式)
// RunIcmp1 uses ICMP to probe host liveliness (listen mode)
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
endflag := false
// 启动监听协程
// Start listening goroutine
go func() {
for {
if endflag {
return
}
// 接收ICMP响应
// Receive ICMP response
msg := make([]byte, 100)
_, sourceIP, _ := conn.ReadFrom(msg)
if sourceIP != nil {
@ -154,22 +154,22 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string)
}
}()
// 发送ICMP请求
// Send ICMP requests
for _, host := range hostslist {
dst, _ := net.ResolveIPAddr("ip", host)
IcmpByte := makemsg(host)
conn.WriteTo(IcmpByte, dst)
}
// 等待响应
// Wait for responses
start := time.Now()
for {
// 所有主机都已响应则退出
// Exit if all hosts have responded
if len(AliveHosts) == len(hostslist) {
break
}
// 根据主机数量设置超时时间
// Set timeout based on number of hosts
since := time.Since(start)
wait := time.Second * 6
if len(hostslist) <= 256 {
@ -185,9 +185,9 @@ func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string)
conn.Close()
}
// RunIcmp2 使用ICMP并发探测主机存活(无监听模式)
// RunIcmp2 uses ICMP to probe host liveliness (no-listen mode)
func RunIcmp2(hostslist []string, chanHosts chan string) {
// 控制并发数
// Control concurrency
num := 1000
if len(hostslist) < num {
num = len(hostslist)
@ -196,7 +196,7 @@ func RunIcmp2(hostslist []string, chanHosts chan string) {
var wg sync.WaitGroup
limiter := make(chan struct{}, num)
// 并发探测
// Concurrent probing
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
@ -218,29 +218,29 @@ func RunIcmp2(hostslist []string, chanHosts chan string) {
close(limiter)
}
// icmpalive 检测主机ICMP是否存活
// icmpalive checks if the host is alive using ICMP
func icmpalive(host string) bool {
startTime := time.Now()
// 建立ICMP连接
// Establish ICMP connection
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
if err != nil {
return false
}
defer conn.Close()
// 设置超时时间
// Set timeout
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil {
return false
}
// 构造并发送ICMP请求
// Construct and send ICMP request
msg := makemsg(host)
if _, err := conn.Write(msg); err != nil {
return false
}
// 接收ICMP响应
// Receive ICMP response
receive := make([]byte, 60)
if _, err := conn.Read(receive); err != nil {
return false
@ -249,13 +249,13 @@ func icmpalive(host string) bool {
return true
}
// RunPing 使用系统Ping命令并发探测主机存活
// RunPing uses system ping command to probe host liveliness concurrently
func RunPing(hostslist []string, chanHosts chan string) {
var wg sync.WaitGroup
// 限制并发数为50
// Limit concurrency to 50
limiter := make(chan struct{}, 50)
// 并发探测
// Concurrent probing
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
@ -276,9 +276,9 @@ func RunPing(hostslist []string, chanHosts chan string) {
wg.Wait()
}
// ExecCommandPing 执行系统Ping命令检测主机存活
// ExecCommandPing executes system ping command to check host liveliness
func ExecCommandPing(ip string) bool {
// 过滤黑名单字符
// Filter blacklist characters
forbiddenChars := []string{";", "&", "|", "`", "$", "\\", "'", "%", "\"", "\n"}
for _, char := range forbiddenChars {
if strings.Contains(ip, char) {
@ -287,7 +287,7 @@ func ExecCommandPing(ip string) bool {
}
var command *exec.Cmd
// 根据操作系统选择不同的ping命令
// Choose different ping commands based on OS
switch runtime.GOOS {
case "windows":
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false")
@ -297,11 +297,11 @@ func ExecCommandPing(ip string) bool {
command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false")
}
// 捕获命令输出
// Capture command output
var outinfo bytes.Buffer
command.Stdout = &outinfo
// 执行命令
// Execute command
if err := command.Start(); err != nil {
return false
}
@ -310,76 +310,76 @@ func ExecCommandPing(ip string) bool {
return false
}
// 分析输出结果
// Analyze output result
output := outinfo.String()
return strings.Contains(output, "true") && strings.Count(output, ip) > 2
}
// makemsg 构造ICMP echo请求消息
// makemsg constructs ICMP echo request message
func makemsg(host string) []byte {
msg := make([]byte, 40)
// 获取标识符
// Get identifier
id0, id1 := genIdentifier(host)
// 设置ICMP头部
// Set ICMP header
msg[0] = 8 // Type: Echo Request
msg[1] = 0 // Code: 0
msg[2] = 0 // Checksum高位(待计算)
msg[3] = 0 // Checksum低位(待计算)
msg[2] = 0 // Checksum high byte (to be calculated)
msg[3] = 0 // Checksum low byte (to be calculated)
msg[4], msg[5] = id0, id1 // Identifier
msg[6], msg[7] = genSequence(1) // Sequence Number
// 计算校验和
// Calculate checksum
check := checkSum(msg[0:40])
msg[2] = byte(check >> 8) // 设置校验和高位
msg[3] = byte(check & 255) // 设置校验和低位
msg[2] = byte(check >> 8) // Set checksum high byte
msg[3] = byte(check & 255) // Set checksum low byte
return msg
}
// checkSum 计算ICMP校验和
// checkSum calculates ICMP checksum
func checkSum(msg []byte) uint16 {
sum := 0
length := len(msg)
// 按16位累加
// Accumulate in 16-bit units
for i := 0; i < length-1; i += 2 {
sum += int(msg[i])*256 + int(msg[i+1])
}
// 处理奇数长度情况
// Handle odd length case
if length%2 == 1 {
sum += int(msg[length-1]) * 256
}
// 将高16位加到低16位
// Add high 16 bits to low 16 bits
sum = (sum >> 16) + (sum & 0xffff)
sum = sum + (sum >> 16)
// 取反得到校验和
// Take one's complement to get checksum
return uint16(^sum)
}
// genSequence 生成ICMP序列号
// genSequence generates ICMP sequence number
func genSequence(v int16) (byte, byte) {
ret1 := byte(v >> 8) // 高8位
ret2 := byte(v & 255) // 低8位
ret1 := byte(v >> 8) // High 8 bits
ret2 := byte(v & 255) // Low 8 bits
return ret1, ret2
}
// genIdentifier 根据主机地址生成标识符
// genIdentifier generates identifier based on host address
func genIdentifier(host string) (byte, byte) {
return host[0], host[1] // 使用主机地址前两个字节
return host[0], host[1] // Use first two bytes of host address
}
// ArrayCountValueTop 统计IP地址段存活数量并返回TOP N结果
// ArrayCountValueTop counts the number of alive IP segments and returns the top N results
func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
if len(arrInit) == 0 {
return
}
// 统计各网段出现次数
// Count occurrences of each segment
segmentCounts := make(map[string]int)
for _, ip := range arrInit {
segments := strings.Split(ip, ".")
@ -387,29 +387,29 @@ func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []strin
continue
}
// 根据flag确定统计B段还是C段
// Determine whether to count B segment or C segment based on flag
var segment string
if flag {
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B segment
} else {
segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C
segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C segment
}
segmentCounts[segment]++
}
// 创建副本用于排序
// Create a copy for sorting
sortMap := make(map[string]int)
for k, v := range segmentCounts {
sortMap[k] = v
}
// 获取TOP N结果
// Get top N results
for i := 0; i < length && len(sortMap) > 0; i++ {
maxSegment := ""
maxCount := 0
// 查找当前最大值
// Find current maximum value
for segment, count := range sortMap {
if count > maxCount {
maxCount = count
@ -417,11 +417,11 @@ func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []strin
}
}
// 添加到结果集
// Add to result set
arrTop = append(arrTop, maxSegment)
arrLen = append(arrLen, maxCount)
// 从待处理map中删除已处理项
// Remove processed item from map
delete(sortMap, maxSegment)
}

View File

@ -13,7 +13,7 @@ import (
//go:embed nmap-service-probes.txt
var ProbeString string
var v VScan // 改为VScan类型而不是指针
var v VScan // Changed to VScan type instead of pointer
type VScan struct {
Exclude string
@ -24,27 +24,27 @@ type VScan struct {
}
type Probe struct {
Name string // 探测器名称
Data string // 探测数据
Protocol string // 协议
Ports string // 端口范围
SSLPorts string // SSL端口范围
Name string // Probe name
Data string // Probe data
Protocol string // Protocol
Ports string // Port range
SSLPorts string // SSL port range
TotalWaitMS int // 总等待时间
TCPWrappedMS int // TCP包装等待时间
Rarity int // 稀有度
Fallback string // 回退探测器名称
TotalWaitMS int // Total wait time
TCPWrappedMS int // TCP wrapped wait time
Rarity int // Rarity
Fallback string // Fallback probe name
Matchs *[]Match // 匹配规则列表
Matchs *[]Match // Match rules list
}
type Match struct {
IsSoft bool // 是否为软匹配
Service string // 服务名称
Pattern string // 匹配模式
VersionInfo string // 版本信息格式
FoundItems []string // 找到的项目
PatternCompiled *regexp.Regexp // 编译后的正则表达式
IsSoft bool // Whether it's a soft match
Service string // Service name
Pattern string // Match pattern
VersionInfo string // Version info format
FoundItems []string // Found items
PatternCompiled *regexp.Regexp // Compiled regular expression
}
type Directive struct {
@ -65,43 +65,43 @@ type Extras struct {
}
func init() {
Common.LogDebug("开始初始化全局变量")
Common.LogDebug("Starting to initialize global variables")
v = VScan{} // 直接初始化VScan结构体
v = VScan{} // Directly initialize VScan struct
v.Init()
// 获取并检查 NULL 探测器
// Get and check NULL probe
if nullProbe, ok := v.ProbesMapKName["NULL"]; ok {
Common.LogDebug(fmt.Sprintf("成功获取NULL探测器Data长度: %d", len(nullProbe.Data)))
Common.LogDebug(fmt.Sprintf("Successfully obtained NULL probe, Data length: %d", len(nullProbe.Data)))
null = &nullProbe
} else {
Common.LogDebug("警告: 未找到NULL探测器")
Common.LogDebug("Warning: NULL probe not found")
}
// 获取并检查 GenericLines 探测器
// Get and check GenericLines probe
if commonProbe, ok := v.ProbesMapKName["GenericLines"]; ok {
Common.LogDebug(fmt.Sprintf("成功获取GenericLines探测器Data长度: %d", len(commonProbe.Data)))
Common.LogDebug(fmt.Sprintf("Successfully obtained GenericLines probe, Data length: %d", len(commonProbe.Data)))
common = &commonProbe
} else {
Common.LogDebug("警告: 未找到GenericLines探测器")
Common.LogDebug("Warning: GenericLines probe not found")
}
Common.LogDebug("全局变量初始化完成")
Common.LogDebug("Global variables initialization complete")
}
// 解析指令语法,返回指令结构
// Parse directive syntax, return directive structure
func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
Common.LogDebug("开始解析指令语法,输入数据: " + data)
Common.LogDebug("Starting to parse directive syntax, input data: " + data)
directive = Directive{}
// 查找第一个空格的位置
// Find the position of the first space
blankIndex := strings.Index(data, " ")
if blankIndex == -1 {
Common.LogDebug("未找到空格分隔符")
Common.LogDebug("Space separator not found")
return directive
}
// 解析各个字段
// Parse each field
directiveName := data[:blankIndex]
Flag := data[blankIndex+1 : blankIndex+2]
delimiter := data[blankIndex+2 : blankIndex+3]
@ -112,70 +112,70 @@ func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
directive.Delimiter = delimiter
directive.DirectiveStr = directiveStr
Common.LogDebug(fmt.Sprintf("指令解析结果: 名称=%s, 标志=%s, 分隔符=%s, 内容=%s",
Common.LogDebug(fmt.Sprintf("Directive parsing result: Name=%s, Flag=%s, Delimiter=%s, Content=%s",
directiveName, Flag, delimiter, directiveStr))
return directive
}
// 解析探测器信息
// Parse probe information
func (p *Probe) parseProbeInfo(probeStr string) {
Common.LogDebug("开始解析探测器信息,输入字符串: " + probeStr)
Common.LogDebug("Starting to parse probe information, input string: " + probeStr)
// 提取协议和其他信息
// Extract protocol and other information
proto := probeStr[:4]
other := probeStr[4:]
// 验证协议类型
// Validate protocol type
if !(proto == "TCP " || proto == "UDP ") {
errMsg := "探测器协议必须是 TCP 或 UDP"
Common.LogDebug("错误: " + errMsg)
errMsg := "Probe protocol must be TCP or UDP"
Common.LogDebug("Error: " + errMsg)
panic(errMsg)
}
// 验证其他信息不为空
// Validate other information is not empty
if len(other) == 0 {
errMsg := "nmap-service-probes - 探测器名称无效"
Common.LogDebug("错误: " + errMsg)
errMsg := "nmap-service-probes - Invalid probe name"
Common.LogDebug("Error: " + errMsg)
panic(errMsg)
}
// 解析指令
// Parse directive
directive := p.getDirectiveSyntax(other)
// 设置探测器属性
// Set probe attributes
p.Name = directive.DirectiveName
p.Data = strings.Split(directive.DirectiveStr, directive.Delimiter)[0]
p.Protocol = strings.ToLower(strings.TrimSpace(proto))
Common.LogDebug(fmt.Sprintf("探测器解析完成: 名称=%s, 数据=%s, 协议=%s",
Common.LogDebug(fmt.Sprintf("Probe parsing completed: Name=%s, Data=%s, Protocol=%s",
p.Name, p.Data, p.Protocol))
}
// 从字符串解析探测器信息
// Parse probe information from string
func (p *Probe) fromString(data string) error {
Common.LogDebug("开始解析探测器字符串数据")
Common.LogDebug("Starting to parse probe string data")
var err error
// 预处理数据
// Preprocess data
data = strings.TrimSpace(data)
lines := strings.Split(data, "\n")
if len(lines) == 0 {
return fmt.Errorf("输入数据为空")
return fmt.Errorf("Input data is empty")
}
probeStr := lines[0]
p.parseProbeInfo(probeStr)
// 解析匹配规则和其他配置
// Parse match rules and other configurations
var matchs []Match
for _, line := range lines {
Common.LogDebug("处理行: " + line)
Common.LogDebug("Processing line: " + line)
switch {
case strings.HasPrefix(line, "match "):
match, err := p.getMatch(line)
if err != nil {
Common.LogDebug("解析match失败: " + err.Error())
Common.LogDebug("Failed to parse match: " + err.Error())
continue
}
matchs = append(matchs, match)
@ -183,7 +183,7 @@ func (p *Probe) fromString(data string) error {
case strings.HasPrefix(line, "softmatch "):
softMatch, err := p.getSoftMatch(line)
if err != nil {
Common.LogDebug("解析softmatch失败: " + err.Error())
Common.LogDebug("Failed to parse softmatch: " + err.Error())
continue
}
matchs = append(matchs, softMatch)
@ -208,80 +208,80 @@ func (p *Probe) fromString(data string) error {
}
}
p.Matchs = &matchs
Common.LogDebug(fmt.Sprintf("解析完成,共有 %d 个匹配规则", len(matchs)))
Common.LogDebug(fmt.Sprintf("Parsing completed, total of %d match rules", len(matchs)))
return err
}
// 解析端口配置
// Parse port configuration
func (p *Probe) parsePorts(data string) {
p.Ports = data[len("ports")+1:]
Common.LogDebug("解析端口: " + p.Ports)
Common.LogDebug("Parsing ports: " + p.Ports)
}
// 解析SSL端口配置
// Parse SSL port configuration
func (p *Probe) parseSSLPorts(data string) {
p.SSLPorts = data[len("sslports")+1:]
Common.LogDebug("解析SSL端口: " + p.SSLPorts)
Common.LogDebug("Parsing SSL ports: " + p.SSLPorts)
}
// 解析总等待时间
// Parse total wait time
func (p *Probe) parseTotalWaitMS(data string) {
waitMS, err := strconv.Atoi(strings.TrimSpace(data[len("totalwaitms")+1:]))
if err != nil {
Common.LogDebug("解析总等待时间失败: " + err.Error())
Common.LogDebug("Failed to parse total wait time: " + err.Error())
return
}
p.TotalWaitMS = waitMS
Common.LogDebug(fmt.Sprintf("总等待时间: %d ms", waitMS))
Common.LogDebug(fmt.Sprintf("Total wait time: %d ms", waitMS))
}
// 解析TCP包装等待时间
// Parse TCP wrapped wait time
func (p *Probe) parseTCPWrappedMS(data string) {
wrappedMS, err := strconv.Atoi(strings.TrimSpace(data[len("tcpwrappedms")+1:]))
if err != nil {
Common.LogDebug("解析TCP包装等待时间失败: " + err.Error())
Common.LogDebug("Failed to parse TCP wrapped wait time: " + err.Error())
return
}
p.TCPWrappedMS = wrappedMS
Common.LogDebug(fmt.Sprintf("TCP包装等待时间: %d ms", wrappedMS))
Common.LogDebug(fmt.Sprintf("TCP wrapped wait time: %d ms", wrappedMS))
}
// 解析稀有度
// Parse rarity
func (p *Probe) parseRarity(data string) {
rarity, err := strconv.Atoi(strings.TrimSpace(data[len("rarity")+1:]))
if err != nil {
Common.LogDebug("解析稀有度失败: " + err.Error())
Common.LogDebug("Failed to parse rarity: " + err.Error())
return
}
p.Rarity = rarity
Common.LogDebug(fmt.Sprintf("稀有度: %d", rarity))
Common.LogDebug(fmt.Sprintf("Rarity: %d", rarity))
}
// 解析回退配置
// Parse fallback configuration
func (p *Probe) parseFallback(data string) {
p.Fallback = data[len("fallback")+1:]
Common.LogDebug("回退配置: " + p.Fallback)
Common.LogDebug("Fallback configuration: " + p.Fallback)
}
// 判断是否为十六进制编码
// Check if it's a hexadecimal code
func isHexCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\x[0-9a-fA-F]{2}`)
return matchRe.Match(b)
}
// 判断是否为八进制编码
// Check if it's an octal code
func isOctalCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\[0-7]{1,3}`)
return matchRe.Match(b)
}
// 判断是否为结构化转义字符
// Check if it's a structured escape character
func isStructCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\[aftnrv]`)
return matchRe.Match(b)
}
// 判断是否为正则表达式特殊字符
// Check if it's a regular expression special character
func isReChar(n int64) bool {
reChars := `.*?+{}()^$|\`
for _, char := range reChars {
@ -292,19 +292,19 @@ func isReChar(n int64) bool {
return false
}
// 判断是否为其他转义序列
// Check if it's another escape sequence
func isOtherEscapeCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\[^\\]`)
return matchRe.Match(b)
}
// 从内容解析探测器规则
// Parse probe rules from content
func (v *VScan) parseProbesFromContent(content string) {
Common.LogDebug("开始解析探测器规则文件内容")
Common.LogDebug("Starting to parse probe rules from file content")
var probes []Probe
var lines []string
// 过滤注释和空行
// Filter comments and empty lines
linesTemp := strings.Split(content, "\n")
for _, lineTemp := range linesTemp {
lineTemp = strings.TrimSpace(lineTemp)
@ -314,196 +314,196 @@ func (v *VScan) parseProbesFromContent(content string) {
lines = append(lines, lineTemp)
}
// 验证文件内容
// Validate file content
if len(lines) == 0 {
errMsg := "读取nmap-service-probes文件失败: 内容为空"
Common.LogDebug("错误: " + errMsg)
errMsg := "Failed to read nmap-service-probes file: Content is empty"
Common.LogDebug("Error: " + errMsg)
panic(errMsg)
}
// 检查Exclude指令
// Check Exclude directive
excludeCount := 0
for _, line := range lines {
if strings.HasPrefix(line, "Exclude ") {
excludeCount++
}
if excludeCount > 1 {
errMsg := "nmap-service-probes文件中只允许有一个Exclude指令"
Common.LogDebug("错误: " + errMsg)
errMsg := "Only one Exclude directive is allowed in nmap-service-probes file"
Common.LogDebug("Error: " + errMsg)
panic(errMsg)
}
}
// 验证第一行格式
// Validate first line format
firstLine := lines[0]
if !(strings.HasPrefix(firstLine, "Exclude ") || strings.HasPrefix(firstLine, "Probe ")) {
errMsg := "解析错误: 首行必须以\"Probe \"或\"Exclude \"开头"
Common.LogDebug("错误: " + errMsg)
errMsg := "Parsing error: First line must start with \"Probe \" or \"Exclude \""
Common.LogDebug("Error: " + errMsg)
panic(errMsg)
}
// 处理Exclude指令
// Process Exclude directive
if excludeCount == 1 {
v.Exclude = firstLine[len("Exclude")+1:]
lines = lines[1:]
Common.LogDebug("解析到Exclude规则: " + v.Exclude)
Common.LogDebug("Parsed Exclude rule: " + v.Exclude)
}
// 合并内容并分割探测器
// Merge content and split probes
content = "\n" + strings.Join(lines, "\n")
probeParts := strings.Split(content, "\nProbe")[1:]
// 解析每个探测器
// Parse each probe
for _, probePart := range probeParts {
probe := Probe{}
if err := probe.fromString(probePart); err != nil {
Common.LogDebug(fmt.Sprintf("解析探测器失败: %v", err))
Common.LogDebug(fmt.Sprintf("Failed to parse probe: %v", err))
continue
}
probes = append(probes, probe)
}
v.AllProbes = probes
Common.LogDebug(fmt.Sprintf("成功解析 %d 个探测器规则", len(probes)))
Common.LogDebug(fmt.Sprintf("Successfully parsed %d probe rules", len(probes)))
}
// 将探测器转换为名称映射
// Convert probes to name mapping
func (v *VScan) parseProbesToMapKName() {
Common.LogDebug("开始构建探测器名称映射")
Common.LogDebug("Starting to build probe name mapping")
v.ProbesMapKName = map[string]Probe{}
for _, probe := range v.AllProbes {
v.ProbesMapKName[probe.Name] = probe
Common.LogDebug("添加探测器映射: " + probe.Name)
Common.LogDebug("Added probe mapping: " + probe.Name)
}
}
// 设置使用的探测器
// Set probes to be used
func (v *VScan) SetusedProbes() {
Common.LogDebug("开始设置要使用的探测器")
Common.LogDebug("Starting to set probes to be used")
for _, probe := range v.AllProbes {
if strings.ToLower(probe.Protocol) == "tcp" {
if probe.Name == "SSLSessionReq" {
Common.LogDebug("跳过 SSLSessionReq 探测器")
Common.LogDebug("Skipping SSLSessionReq probe")
continue
}
v.Probes = append(v.Probes, probe)
Common.LogDebug("添加TCP探测器: " + probe.Name)
Common.LogDebug("Added TCP probe: " + probe.Name)
// 特殊处理TLS会话请求
// Special handling for TLS session request
if probe.Name == "TLSSessionReq" {
sslProbe := v.ProbesMapKName["SSLSessionReq"]
v.Probes = append(v.Probes, sslProbe)
Common.LogDebug("为TLSSessionReq添加SSL探测器")
Common.LogDebug("Added SSL probe for TLSSessionReq")
}
} else {
v.UdpProbes = append(v.UdpProbes, probe)
Common.LogDebug("添加UDP探测器: " + probe.Name)
Common.LogDebug("Added UDP probe: " + probe.Name)
}
}
Common.LogDebug(fmt.Sprintf("探测器设置完成TCP: %d个, UDP: %d个",
Common.LogDebug(fmt.Sprintf("Probe setting completed, TCP: %d, UDP: %d",
len(v.Probes), len(v.UdpProbes)))
}
// 解析match指令获取匹配规则
// Parse match directive to get match rule
func (p *Probe) getMatch(data string) (match Match, err error) {
Common.LogDebug("开始解析match指令" + data)
Common.LogDebug("Starting to parse match directive: " + data)
match = Match{}
// 提取match文本并解析指令语法
// Extract match text and parse directive syntax
matchText := data[len("match")+1:]
directive := p.getDirectiveSyntax(matchText)
// 分割文本获取pattern和版本信息
// Split text to get pattern and version info
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
if len(textSplited) == 0 {
return match, fmt.Errorf("无效的match指令格式")
return match, fmt.Errorf("Invalid match directive format")
}
pattern := textSplited[0]
versionInfo := strings.Join(textSplited[1:], "")
// 解码并编译正则表达式
// Decode and compile regular expression
patternUnescaped, decodeErr := DecodePattern(pattern)
if decodeErr != nil {
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
Common.LogDebug("Failed to decode pattern: " + decodeErr.Error())
return match, decodeErr
}
patternUnescapedStr := string([]rune(string(patternUnescaped)))
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
if compileErr != nil {
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
Common.LogDebug("Failed to compile regular expression: " + compileErr.Error())
return match, compileErr
}
// 设置match对象属性
// Set match object attributes
match.Service = directive.DirectiveName
match.Pattern = pattern
match.PatternCompiled = patternCompiled
match.VersionInfo = versionInfo
Common.LogDebug(fmt.Sprintf("解析match成功: 服务=%s, Pattern=%s",
Common.LogDebug(fmt.Sprintf("Match parsing successful: Service=%s, Pattern=%s",
match.Service, match.Pattern))
return match, nil
}
// 解析softmatch指令获取软匹配规则
// Parse softmatch directive to get soft match rule
func (p *Probe) getSoftMatch(data string) (softMatch Match, err error) {
Common.LogDebug("开始解析softmatch指令" + data)
Common.LogDebug("Starting to parse softmatch directive: " + data)
softMatch = Match{IsSoft: true}
// 提取softmatch文本并解析指令语法
// Extract softmatch text and parse directive syntax
matchText := data[len("softmatch")+1:]
directive := p.getDirectiveSyntax(matchText)
// 分割文本获取pattern和版本信息
// Split text to get pattern and version info
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
if len(textSplited) == 0 {
return softMatch, fmt.Errorf("无效的softmatch指令格式")
return softMatch, fmt.Errorf("Invalid softmatch directive format")
}
pattern := textSplited[0]
versionInfo := strings.Join(textSplited[1:], "")
// 解码并编译正则表达式
// Decode and compile regular expression
patternUnescaped, decodeErr := DecodePattern(pattern)
if decodeErr != nil {
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
Common.LogDebug("Failed to decode pattern: " + decodeErr.Error())
return softMatch, decodeErr
}
patternUnescapedStr := string([]rune(string(patternUnescaped)))
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
if compileErr != nil {
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
Common.LogDebug("Failed to compile regular expression: " + compileErr.Error())
return softMatch, compileErr
}
// 设置softMatch对象属性
// Set softMatch object attributes
softMatch.Service = directive.DirectiveName
softMatch.Pattern = pattern
softMatch.PatternCompiled = patternCompiled
softMatch.VersionInfo = versionInfo
Common.LogDebug(fmt.Sprintf("解析softmatch成功: 服务=%s, Pattern=%s",
Common.LogDebug(fmt.Sprintf("Softmatch parsing successful: Service=%s, Pattern=%s",
softMatch.Service, softMatch.Pattern))
return softMatch, nil
}
// 解码模式字符串,处理转义序列
// Decode pattern string, handle escape sequences
func DecodePattern(s string) ([]byte, error) {
Common.LogDebug("开始解码pattern: " + s)
Common.LogDebug("Starting to decode pattern: " + s)
sByteOrigin := []byte(s)
// 处理十六进制、八进制和结构化转义序列
// Handle hexadecimal, octal, and structured escape sequences
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) (v []byte) {
var replace []byte
// 处理十六进制转义
// Handle hexadecimal escape
if isHexCode(match) {
hexNum := match[2:]
byteNum, _ := strconv.ParseInt(string(hexNum), 16, 32)
@ -514,20 +514,20 @@ func DecodePattern(s string) ([]byte, error) {
}
}
// 处理结构化转义字符
// Handle structured escape characters
if isStructCode(match) {
structCodeMap := map[int][]byte{
97: []byte{0x07}, // \a 响铃
102: []byte{0x0c}, // \f 换页
116: []byte{0x09}, // \t 制表符
110: []byte{0x0a}, // \n 换行
114: []byte{0x0d}, // \r 回车
118: []byte{0x0b}, // \v 垂直制表符
97: []byte{0x07}, // \a bell
102: []byte{0x0c}, // \f form feed
116: []byte{0x09}, // \t tab
110: []byte{0x0a}, // \n newline
114: []byte{0x0d}, // \r carriage return
118: []byte{0x0b}, // \v vertical tab
}
replace = structCodeMap[int(match[1])]
}
// 处理八进制转义
// Handle octal escape
if isOctalCode(match) {
octalNum := match[2:]
byteNum, _ := strconv.ParseInt(string(octalNum), 8, 32)
@ -536,7 +536,7 @@ func DecodePattern(s string) ([]byte, error) {
return replace
})
// 处理其他转义序列
// Handle other escape sequences
matchRe2 := regexp.MustCompile(`\\([^\\])`)
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) (v []byte) {
if isOtherEscapeCode(match) {
@ -545,57 +545,57 @@ func DecodePattern(s string) ([]byte, error) {
return match
})
Common.LogDebug("pattern解码完成")
Common.LogDebug("Pattern decoding completed")
return sByteDec2, nil
}
// ProbesRarity 用于按稀有度排序的探测器切片
// ProbesRarity is a slice of probes for sorting by rarity
type ProbesRarity []Probe
// Len 返回切片长度,实现 sort.Interface 接口
// Len returns slice length, implements sort.Interface
func (ps ProbesRarity) Len() int {
return len(ps)
}
// Swap 交换切片中的两个元素,实现 sort.Interface 接口
// Swap exchanges two elements in the slice, implements sort.Interface
func (ps ProbesRarity) Swap(i, j int) {
ps[i], ps[j] = ps[j], ps[i]
}
// Less 比较函数,按稀有度升序排序,实现 sort.Interface 接口
// Less comparison function, sorts by rarity in ascending order, implements sort.Interface
func (ps ProbesRarity) Less(i, j int) bool {
return ps[i].Rarity < ps[j].Rarity
}
// Target 定义目标结构体
// Target defines target structure
type Target struct {
IP string // 目标IP地址
Port int // 目标端口
Protocol string // 协议类型
IP string // Target IP address
Port int // Target port
Protocol string // Protocol type
}
// ContainsPort 检查指定端口是否在探测器的端口范围内
// ContainsPort checks if the specified port is within the probe's port range
func (p *Probe) ContainsPort(testPort int) bool {
Common.LogDebug(fmt.Sprintf("检查端口 %d 是否在探测器端口范围内: %s", testPort, p.Ports))
Common.LogDebug(fmt.Sprintf("Checking if port %d is within probe port range: %s", testPort, p.Ports))
// 检查单个端口
// Check individual ports
ports := strings.Split(p.Ports, ",")
for _, port := range ports {
port = strings.TrimSpace(port)
cmpPort, err := strconv.Atoi(port)
if err == nil && testPort == cmpPort {
Common.LogDebug(fmt.Sprintf("端口 %d 匹配单个端口", testPort))
Common.LogDebug(fmt.Sprintf("Port %d matches individual port", testPort))
return true
}
}
// 检查端口范围
// Check port ranges
for _, port := range ports {
port = strings.TrimSpace(port)
if strings.Contains(port, "-") {
portRange := strings.Split(port, "-")
if len(portRange) != 2 {
Common.LogDebug("无效的端口范围格式: " + port)
Common.LogDebug("Invalid port range format: " + port)
continue
}
@ -603,62 +603,62 @@ func (p *Probe) ContainsPort(testPort int) bool {
end, err2 := strconv.Atoi(strings.TrimSpace(portRange[1]))
if err1 != nil || err2 != nil {
Common.LogDebug(fmt.Sprintf("解析端口范围失败: %s", port))
Common.LogDebug(fmt.Sprintf("Failed to parse port range: %s", port))
continue
}
if testPort >= start && testPort <= end {
Common.LogDebug(fmt.Sprintf("端口 %d 在范围 %d-%d 内", testPort, start, end))
Common.LogDebug(fmt.Sprintf("Port %d is within range %d-%d", testPort, start, end))
return true
}
}
}
Common.LogDebug(fmt.Sprintf("端口 %d 不在探测器端口范围内", testPort))
Common.LogDebug(fmt.Sprintf("Port %d is not within probe port range", testPort))
return false
}
// MatchPattern 使用正则表达式匹配响应内容
// MatchPattern uses regular expression to match response content
func (m *Match) MatchPattern(response []byte) bool {
// 将响应转换为字符串并进行匹配
// Convert response to string and match
responseStr := string([]rune(string(response)))
foundItems := m.PatternCompiled.FindStringSubmatch(responseStr)
if len(foundItems) > 0 {
m.FoundItems = foundItems
Common.LogDebug(fmt.Sprintf("匹配成功,找到 %d 个匹配项", len(foundItems)))
Common.LogDebug(fmt.Sprintf("Match successful, found %d matching items", len(foundItems)))
return true
}
return false
}
// ParseVersionInfo 解析版本信息并返回额外信息结构
// ParseVersionInfo parses version information and returns extra information structure
func (m *Match) ParseVersionInfo(response []byte) Extras {
Common.LogDebug("开始解析版本信息")
Common.LogDebug("Starting to parse version information")
var extras = Extras{}
// 替换版本信息中的占位符
foundItems := m.FoundItems[1:] // 跳过第一个完整匹配项
// Replace placeholders in version info
foundItems := m.FoundItems[1:] // Skip the first complete match item
versionInfo := m.VersionInfo
for index, value := range foundItems {
dollarName := "$" + strconv.Itoa(index+1)
versionInfo = strings.Replace(versionInfo, dollarName, value, -1)
}
Common.LogDebug("替换后的版本信息: " + versionInfo)
Common.LogDebug("Version info after replacement: " + versionInfo)
// 定义解析函数
// Define parsing function
parseField := func(field, pattern string) string {
patterns := []string{
pattern + `/([^/]*)/`, // 斜线分隔
pattern + `\|([^|]*)\|`, // 竖线分隔
pattern + `/([^/]*)/`, // Slash delimiter
pattern + `\|([^|]*)\|`, // Pipe delimiter
}
for _, p := range patterns {
if strings.Contains(versionInfo, pattern) {
regex := regexp.MustCompile(p)
if matches := regex.FindStringSubmatch(versionInfo); len(matches) > 1 {
Common.LogDebug(fmt.Sprintf("解析到%s: %s", field, matches[1]))
Common.LogDebug(fmt.Sprintf("Parsed %s: %s", field, matches[1]))
return matches[1]
}
}
@ -666,15 +666,15 @@ func (m *Match) ParseVersionInfo(response []byte) Extras {
return ""
}
// 解析各个字段
extras.VendorProduct = parseField("厂商产品", " p")
extras.Version = parseField("版本", " v")
extras.Info = parseField("信息", " i")
extras.Hostname = parseField("主机名", " h")
extras.OperatingSystem = parseField("操作系统", " o")
extras.DeviceType = parseField("设备类型", " d")
// Parse each field
extras.VendorProduct = parseField("vendor product", " p")
extras.Version = parseField("version", " v")
extras.Info = parseField("info", " i")
extras.Hostname = parseField("hostname", " h")
extras.OperatingSystem = parseField("operating system", " o")
extras.DeviceType = parseField("device type", " d")
// 特殊处理CPE
// Special handling for CPE
if strings.Contains(versionInfo, " cpe:/") || strings.Contains(versionInfo, " cpe:|") {
cpePatterns := []string{`cpe:/([^/]*)`, `cpe:\|([^|]*)`}
for _, pattern := range cpePatterns {
@ -685,7 +685,7 @@ func (m *Match) ParseVersionInfo(response []byte) Extras {
} else {
extras.CPE = cpeName[0]
}
Common.LogDebug("解析到CPE: " + extras.CPE)
Common.LogDebug("Parsed CPE: " + extras.CPE)
break
}
}
@ -694,12 +694,12 @@ func (m *Match) ParseVersionInfo(response []byte) Extras {
return extras
}
// ToMap 将 Extras 转换为 map[string]string
// ToMap converts Extras to map[string]string
func (e *Extras) ToMap() map[string]string {
Common.LogDebug("开始转换Extras为Map")
Common.LogDebug("Starting to convert Extras to Map")
result := make(map[string]string)
// 定义字段映射
// Define field mapping
fields := map[string]string{
"vendor_product": e.VendorProduct,
"version": e.Version,
@ -710,31 +710,31 @@ func (e *Extras) ToMap() map[string]string {
"cpe": e.CPE,
}
// 添加非空字段到结果map
// Add non-empty fields to result map
for key, value := range fields {
if value != "" {
result[key] = value
Common.LogDebug(fmt.Sprintf("添加字段 %s: %s", key, value))
Common.LogDebug(fmt.Sprintf("Added field %s: %s", key, value))
}
}
Common.LogDebug(fmt.Sprintf("转换完成,共有 %d 个字段", len(result)))
Common.LogDebug(fmt.Sprintf("Conversion completed, total %d fields", len(result)))
return result
}
func DecodeData(s string) ([]byte, error) {
if len(s) == 0 {
Common.LogDebug("输入数据为空")
Common.LogDebug("Input data is empty")
return nil, fmt.Errorf("empty input")
}
Common.LogDebug(fmt.Sprintf("开始解码数据,长度: %d, 内容: %q", len(s), s))
Common.LogDebug(fmt.Sprintf("Starting to decode data, length: %d, content: %q", len(s), s))
sByteOrigin := []byte(s)
// 处理十六进制、八进制和结构化转义序列
// Handle hexadecimal, octal, and structured escape sequences
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) []byte {
// 处理十六进制转义
// Handle hexadecimal escape
if isHexCode(match) {
hexNum := match[2:]
byteNum, err := strconv.ParseInt(string(hexNum), 16, 32)
@ -744,15 +744,15 @@ func DecodeData(s string) ([]byte, error) {
return []byte{uint8(byteNum)}
}
// 处理结构化转义字符
// Handle structured escape characters
if isStructCode(match) {
structCodeMap := map[int][]byte{
97: []byte{0x07}, // \a 响铃
102: []byte{0x0c}, // \f 换页
116: []byte{0x09}, // \t 制表符
110: []byte{0x0a}, // \n 换行
114: []byte{0x0d}, // \r 回车
118: []byte{0x0b}, // \v 垂直制表符
97: []byte{0x07}, // \a bell
102: []byte{0x0c}, // \f form feed
116: []byte{0x09}, // \t tab
110: []byte{0x0a}, // \n newline
114: []byte{0x0d}, // \r carriage return
118: []byte{0x0b}, // \v vertical tab
}
if replace, ok := structCodeMap[int(match[1])]; ok {
return replace
@ -760,7 +760,7 @@ func DecodeData(s string) ([]byte, error) {
return match
}
// 处理八进制转义
// Handle octal escape
if isOctalCode(match) {
octalNum := match[2:]
byteNum, err := strconv.ParseInt(string(octalNum), 8, 32)
@ -770,11 +770,11 @@ func DecodeData(s string) ([]byte, error) {
return []byte{uint8(byteNum)}
}
Common.LogDebug(fmt.Sprintf("无法识别的转义序列: %s", string(match)))
Common.LogDebug(fmt.Sprintf("Unrecognized escape sequence: %s", string(match)))
return match
})
// 处理其他转义序列
// Handle other escape sequences
matchRe2 := regexp.MustCompile(`\\([^\\])`)
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) []byte {
if len(match) < 2 {
@ -787,39 +787,39 @@ func DecodeData(s string) ([]byte, error) {
})
if len(sByteDec2) == 0 {
Common.LogDebug("解码后数据为空")
Common.LogDebug("Decoded data is empty")
return nil, fmt.Errorf("decoded data is empty")
}
Common.LogDebug(fmt.Sprintf("解码完成,结果长度: %d, 内容: %x", len(sByteDec2), sByteDec2))
Common.LogDebug(fmt.Sprintf("Decoding completed, result length: %d, content: %x", len(sByteDec2), sByteDec2))
return sByteDec2, nil
}
// GetAddress 获取目标的完整地址IP:端口)
// GetAddress gets the target's full address (IP:port)
func (t *Target) GetAddress() string {
addr := t.IP + ":" + strconv.Itoa(t.Port)
Common.LogDebug("获取目标地址: " + addr)
Common.LogDebug("Getting target address: " + addr)
return addr
}
// trimBanner 处理和清理横幅数据
// trimBanner processes and cleans banner data
func trimBanner(buf []byte) string {
Common.LogDebug("开始处理横幅数据")
Common.LogDebug("Starting to process banner data")
bufStr := string(buf)
// 特殊处理SMB协议
// Special handling for SMB protocol
if strings.Contains(bufStr, "SMB") {
banner := hex.EncodeToString(buf)
if len(banner) > 0xa+6 && banner[0xa:0xa+6] == "534d42" { // "SMB" in hex
Common.LogDebug("检测到SMB协议数据")
Common.LogDebug("Detected SMB protocol data")
plain := banner[0xa2:]
data, err := hex.DecodeString(plain)
if err != nil {
Common.LogDebug("SMB数据解码失败: " + err.Error())
Common.LogDebug("Failed to decode SMB data: " + err.Error())
return bufStr
}
// 解析domain
// Parse domain
var domain string
var index int
for i, s := range data {
@ -831,7 +831,7 @@ func trimBanner(buf []byte) string {
}
}
// 解析hostname
// Parse hostname
var hostname string
remainData := data[index:]
for i, h := range remainData {
@ -844,12 +844,12 @@ func trimBanner(buf []byte) string {
}
smbBanner := fmt.Sprintf("hostname: %s domain: %s", hostname, domain)
Common.LogDebug("SMB横幅: " + smbBanner)
Common.LogDebug("SMB banner: " + smbBanner)
return smbBanner
}
}
// 处理常规数据
// Process regular data
var src string
for _, ch := range bufStr {
if ch > 32 && ch < 125 {
@ -859,19 +859,19 @@ func trimBanner(buf []byte) string {
}
}
// 清理多余空白
// Clean up extra whitespace
re := regexp.MustCompile(`\s{2,}`)
src = re.ReplaceAllString(src, ".")
result := strings.TrimSpace(src)
Common.LogDebug("处理后的横幅: " + result)
Common.LogDebug("Processed banner: " + result)
return result
}
// Init 初始化VScan对象
// Init initializes the VScan object
func (v *VScan) Init() {
Common.LogDebug("开始初始化VScan")
Common.LogDebug("Starting to initialize VScan")
v.parseProbesFromContent(ProbeString)
v.parseProbesToMapKName()
v.SetusedProbes()
Common.LogDebug("VScan初始化完成")
Common.LogDebug("VScan initialization completed")
}

View File

@ -9,54 +9,54 @@ import (
"time"
)
// ServiceInfo 定义服务识别的结果信息
// ServiceInfo defines the service identification result information
type ServiceInfo struct {
Name string // 服务名称,如 http、ssh 等
Banner string // 服务返回的横幅信息
Version string // 服务版本号
Extras map[string]string // 其他额外信息,如操作系统、产品名等
Name string // Service name, such as http, ssh, etc.
Banner string // Banner information returned by the service
Version string // Service version number
Extras map[string]string // Other additional information, such as operating system, product name, etc.
}
// Result 定义单次探测的结果
// Result defines the result of a single detection
type Result struct {
Service Service // 识别出的服务信息
Banner string // 服务横幅
Extras map[string]string // 额外信息
Send []byte // 发送的探测数据
Recv []byte // 接收到的响应数据
Service Service // Identified service information
Banner string // Service banner
Extras map[string]string // Additional information
Send []byte // Probe data sent
Recv []byte // Response data received
}
// Service 定义服务的基本信息
// Service defines the basic information of a service
type Service struct {
Name string // 服务名称
Extras map[string]string // 服务的额外属性
Name string // Service name
Extras map[string]string // Additional service attributes
}
// Info 定义单个端口探测的上下文信息
// Info defines the context information for a single port probe
type Info struct {
Address string // 目标IP地址
Port int // 目标端口
Conn net.Conn // 网络连接
Result Result // 探测结果
Found bool // 是否成功识别服务
Address string // Target IP address
Port int // Target port
Conn net.Conn // Network connection
Result Result // Detection result
Found bool // Whether the service was successfully identified
}
// PortInfoScanner 定义端口服务识别器
// PortInfoScanner defines a port service identifier
type PortInfoScanner struct {
Address string // 目标IP地址
Port int // 目标端口
Conn net.Conn // 网络连接
Timeout time.Duration // 超时时间
info *Info // 探测上下文
Address string // Target IP address
Port int // Target port
Conn net.Conn // Network connection
Timeout time.Duration // Timeout duration
info *Info // Detection context
}
// 预定义的基础探测器
// Predefined basic probes
var (
null = new(Probe) // 空探测器,用于基本协议识别
common = new(Probe) // 通用探测器,用于常见服务识别
null = new(Probe) // Empty probe, used for basic protocol identification
common = new(Probe) // Common probe, used for common service identification
)
// NewPortInfoScanner 创建新的端口服务识别器实例
// NewPortInfoScanner creates a new port service identifier instance
func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration) *PortInfoScanner {
return &PortInfoScanner{
Address: addr,
@ -74,12 +74,12 @@ func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Durat
}
}
// Identify 执行服务识别,返回识别结果
// Identify performs service identification and returns the result
func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
Common.LogDebug(fmt.Sprintf("开始识别服务 %s:%d", s.Address, s.Port))
Common.LogDebug(fmt.Sprintf("Starting to identify service %s:%d", s.Address, s.Port))
s.info.PortInfo()
// 构造返回结果
// Construct the return result
serviceInfo := &ServiceInfo{
Name: s.info.Result.Service.Name,
Banner: s.info.Result.Banner,
@ -87,104 +87,104 @@ func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
Extras: make(map[string]string),
}
// 复制额外信息
// Copy additional information
for k, v := range s.info.Result.Service.Extras {
serviceInfo.Extras[k] = v
}
Common.LogDebug(fmt.Sprintf("服务识别完成 %s:%d => %s", s.Address, s.Port, serviceInfo.Name))
Common.LogDebug(fmt.Sprintf("Service identification completed %s:%d => %s", s.Address, s.Port, serviceInfo.Name))
return serviceInfo, nil
}
// PortInfo 执行端口服务识别的主要逻辑
// PortInfo executes the main logic of port service identification
func (i *Info) PortInfo() {
// 1. 首先尝试读取服务的初始响应
// 1. First try to read the initial response from the service
if response, err := i.Read(); err == nil && len(response) > 0 {
Common.LogDebug(fmt.Sprintf("收到初始响应: %d 字节", len(response)))
Common.LogDebug(fmt.Sprintf("Received initial response: %d bytes", len(response)))
// 使用基础探测器检查响应
Common.LogDebug("尝试使用基础探测器(null/common)检查响应")
// Check the response using basic probes
Common.LogDebug("Attempting to check response using basic probes (null/common)")
if i.tryProbes(response, []*Probe{null, common}) {
Common.LogDebug("基础探测器匹配成功")
Common.LogDebug("Basic probe matching successful")
return
}
Common.LogDebug("基础探测器未匹配")
Common.LogDebug("Basic probes did not match")
} else if err != nil {
Common.LogDebug(fmt.Sprintf("读取初始响应失败: %v", err))
Common.LogDebug(fmt.Sprintf("Failed to read initial response: %v", err))
}
// 记录已使用的探测器,避免重复使用
// Record used probes to avoid duplication
usedProbes := make(map[string]struct{})
// 2. 尝试使用端口专用探测器
Common.LogDebug(fmt.Sprintf("尝试使用端口 %d 的专用探测器", i.Port))
// 2. Try to use port-specific probes
Common.LogDebug(fmt.Sprintf("Attempting to use dedicated probes for port %d", i.Port))
if i.processPortMapProbes(usedProbes) {
Common.LogDebug("端口专用探测器匹配成功")
Common.LogDebug("Port-specific probe matching successful")
return
}
Common.LogDebug("端口专用探测器未匹配")
Common.LogDebug("Port-specific probes did not match")
// 3. 使用默认探测器列表
Common.LogDebug("尝试使用默认探测器列表")
// 3. Use the default probe list
Common.LogDebug("Attempting to use default probe list")
if i.processDefaultProbes(usedProbes) {
Common.LogDebug("默认探测器匹配成功")
Common.LogDebug("Default probe matching successful")
return
}
Common.LogDebug("默认探测器未匹配")
Common.LogDebug("Default probes did not match")
// 4. 如果所有探测都失败,标记为未知服务
// 4. If all probes fail, mark as unknown service
if strings.TrimSpace(i.Result.Service.Name) == "" {
Common.LogDebug("未识别出服务,标记为 unknown")
Common.LogDebug("Service not recognized, marking as unknown")
i.Result.Service.Name = "unknown"
}
}
// tryProbes 尝试使用指定的探测器列表检查响应
// tryProbes attempts to use the specified probe list to check the response
func (i *Info) tryProbes(response []byte, probes []*Probe) bool {
for _, probe := range probes {
Common.LogDebug(fmt.Sprintf("尝试探测器: %s", probe.Name))
Common.LogDebug(fmt.Sprintf("Attempting probe: %s", probe.Name))
i.GetInfo(response, probe)
if i.Found {
Common.LogDebug(fmt.Sprintf("探测器 %s 匹配成功", probe.Name))
Common.LogDebug(fmt.Sprintf("Probe %s matched successfully", probe.Name))
return true
}
}
return false
}
// processPortMapProbes 处理端口映射中的专用探测器
// processPortMapProbes processes dedicated probes in the port mapping
func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool {
// 检查是否存在端口专用探测器
// Check if port-specific probes exist
if len(Common.PortMap[i.Port]) == 0 {
Common.LogDebug(fmt.Sprintf("端口 %d 没有专用探测器", i.Port))
Common.LogDebug(fmt.Sprintf("Port %d has no dedicated probes", i.Port))
return false
}
// 遍历端口专用探测器
// Iterate through port-specific probes
for _, name := range Common.PortMap[i.Port] {
Common.LogDebug(fmt.Sprintf("尝试端口专用探测器: %s", name))
Common.LogDebug(fmt.Sprintf("Attempting port-specific probe: %s", name))
usedProbes[name] = struct{}{}
probe := v.ProbesMapKName[name]
// 解码探测数据
// Decode probe data
probeData, err := DecodeData(probe.Data)
if err != nil || len(probeData) == 0 {
Common.LogDebug(fmt.Sprintf("探测器 %s 数据解码失败", name))
Common.LogDebug(fmt.Sprintf("Failed to decode probe data for %s", name))
continue
}
// 发送探测数据并获取响应
Common.LogDebug(fmt.Sprintf("发送探测数据: %d 字节", len(probeData)))
// Send probe data and get response
Common.LogDebug(fmt.Sprintf("Sending probe data: %d bytes", len(probeData)))
if response := i.Connect(probeData); len(response) > 0 {
Common.LogDebug(fmt.Sprintf("收到响应: %d 字节", len(response)))
Common.LogDebug(fmt.Sprintf("Received response: %d bytes", len(response)))
// 使用当前探测器检查响应
// Check response with current probe
i.GetInfo(response, &probe)
if i.Found {
return true
}
// 根据探测器类型进行额外检查
// Perform additional checks based on probe type
switch name {
case "GenericLines":
if i.tryProbes(response, []*Probe{null}) {
@ -202,14 +202,14 @@ func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool {
return false
}
// processDefaultProbes 处理默认探测器列表
// processDefaultProbes processes the default probe list
func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
failCount := 0
const maxFailures = 10 // 最大失败次数
const maxFailures = 10 // Maximum failure count
// 遍历默认探测器列表
// Iterate through the default probe list
for _, name := range Common.DefaultMap {
// 跳过已使用的探测器
// Skip already used probes
if _, used := usedProbes[name]; used {
continue
}
@ -220,7 +220,7 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
continue
}
// 发送探测数据并获取响应
// Send probe data and get response
response := i.Connect(probeData)
if len(response) == 0 {
failCount++
@ -230,13 +230,13 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
continue
}
// 使用当前探测器检查响应
// Check response with current probe
i.GetInfo(response, &probe)
if i.Found {
return true
}
// 根据探测器类型进行额外检查
// Perform additional checks based on probe type
switch name {
case "GenericLines":
if i.tryProbes(response, []*Probe{null}) {
@ -250,7 +250,7 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
}
}
// 尝试使用端口映射中的其他探测器
// Try to use other probes in the port mapping
if len(Common.PortMap[i.Port]) > 0 {
for _, mappedName := range Common.PortMap[i.Port] {
usedProbes[mappedName] = struct{}{}
@ -265,13 +265,13 @@ func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
return false
}
// GetInfo 分析响应数据并提取服务信息
// GetInfo analyzes response data and extracts service information
func (i *Info) GetInfo(response []byte, probe *Probe) {
Common.LogDebug(fmt.Sprintf("开始分析响应数据,长度: %d", len(response)))
Common.LogDebug(fmt.Sprintf("Starting to analyze response data, length: %d", len(response)))
// 响应数据有效性检查
// Check response data validity
if len(response) <= 0 {
Common.LogDebug("响应数据为空")
Common.LogDebug("Response data is empty")
return
}
@ -281,42 +281,42 @@ func (i *Info) GetInfo(response []byte, probe *Probe) {
softFound bool
)
// 处理主要匹配规则
Common.LogDebug(fmt.Sprintf("处理探测器 %s 的主要匹配规则", probe.Name))
// Process main matching rules
Common.LogDebug(fmt.Sprintf("Processing main matching rules for probe %s", probe.Name))
if matched, match := i.processMatches(response, probe.Matchs); matched {
Common.LogDebug("找到硬匹配")
Common.LogDebug("Hard match found")
return
} else if match != nil {
Common.LogDebug("找到软匹配")
Common.LogDebug("Soft match found")
softFound = true
softMatch = *match
}
// 处理回退匹配规则
// Process fallback matching rules
if probe.Fallback != "" {
Common.LogDebug(fmt.Sprintf("尝试回退匹配: %s", probe.Fallback))
Common.LogDebug(fmt.Sprintf("Attempting fallback match: %s", probe.Fallback))
if fbProbe, ok := v.ProbesMapKName[probe.Fallback]; ok {
if matched, match := i.processMatches(response, fbProbe.Matchs); matched {
Common.LogDebug("回退匹配成功")
Common.LogDebug("Fallback match successful")
return
} else if match != nil {
Common.LogDebug("找到回退软匹配")
Common.LogDebug("Fallback soft match found")
softFound = true
softMatch = *match
}
}
}
// 处理未找到匹配的情况
// Handle case when no match is found
if !i.Found {
Common.LogDebug("未找到硬匹配,处理未匹配情况")
Common.LogDebug("No hard match found, handling no match case")
i.handleNoMatch(response, result, softFound, softMatch)
}
}
// processMatches 处理匹配规则集
// processMatches processes the set of matching rules
func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match) {
Common.LogDebug(fmt.Sprintf("开始处理匹配规则,共 %d 条", len(*matches)))
Common.LogDebug(fmt.Sprintf("Starting to process matching rules, total %d rules", len(*matches)))
var softMatch *Match
for _, match := range *matches {
@ -325,11 +325,11 @@ func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match)
}
if !match.IsSoft {
Common.LogDebug(fmt.Sprintf("找到硬匹配: %s", match.Service))
Common.LogDebug(fmt.Sprintf("Hard match found: %s", match.Service))
i.handleHardMatch(response, &match)
return true, nil
} else if softMatch == nil {
Common.LogDebug(fmt.Sprintf("找到软匹配: %s", match.Service))
Common.LogDebug(fmt.Sprintf("Soft match found: %s", match.Service))
tmpMatch := match
softMatch = &tmpMatch
}
@ -338,9 +338,9 @@ func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match)
return false, softMatch
}
// handleHardMatch 处理硬匹配结果
// handleHardMatch handles hard match results
func (i *Info) handleHardMatch(response []byte, match *Match) {
Common.LogDebug(fmt.Sprintf("处理硬匹配结果: %s", match.Service))
Common.LogDebug(fmt.Sprintf("Processing hard match result: %s", match.Service))
result := &i.Result
extras := match.ParseVersionInfo(response)
extrasMap := extras.ToMap()
@ -350,64 +350,64 @@ func (i *Info) handleHardMatch(response []byte, match *Match) {
result.Banner = trimBanner(response)
result.Service.Extras = extrasMap
// 特殊处理 microsoft-ds 服务
// Special handling for microsoft-ds service
if result.Service.Name == "microsoft-ds" {
Common.LogDebug("特殊处理 microsoft-ds 服务")
Common.LogDebug("Special handling for microsoft-ds service")
result.Service.Extras["hostname"] = result.Banner
}
i.Found = true
Common.LogDebug(fmt.Sprintf("服务识别结果: %s, Banner: %s", result.Service.Name, result.Banner))
Common.LogDebug(fmt.Sprintf("Service identification result: %s, Banner: %s", result.Service.Name, result.Banner))
}
// handleNoMatch 处理未找到匹配的情况
// handleNoMatch handles the case when no match is found
func (i *Info) handleNoMatch(response []byte, result *Result, softFound bool, softMatch Match) {
Common.LogDebug("处理未匹配情况")
Common.LogDebug("Handling no match case")
result.Banner = trimBanner(response)
if !softFound {
// 尝试识别 HTTP 服务
// Try to identify HTTP service
if strings.Contains(result.Banner, "HTTP/") ||
strings.Contains(result.Banner, "html") {
Common.LogDebug("识别为HTTP服务")
Common.LogDebug("Identified as HTTP service")
result.Service.Name = "http"
} else {
Common.LogDebug("未知服务")
Common.LogDebug("Unknown service")
result.Service.Name = "unknown"
}
} else {
Common.LogDebug("使用软匹配结果")
Common.LogDebug("Using soft match result")
extras := softMatch.ParseVersionInfo(response)
result.Service.Extras = extras.ToMap()
result.Service.Name = softMatch.Service
i.Found = true
Common.LogDebug(fmt.Sprintf("软匹配服务: %s", result.Service.Name))
Common.LogDebug(fmt.Sprintf("Soft match service: %s", result.Service.Name))
}
}
// Connect 发送数据并获取响应
// Connect sends data and gets response
func (i *Info) Connect(msg []byte) []byte {
i.Write(msg)
reply, _ := i.Read()
return reply
}
const WrTimeout = 5 // 默认读写超时时间(秒)
const WrTimeout = 5 // Default read/write timeout (seconds)
// Write 写入数据到连接
// Write writes data to the connection
func (i *Info) Write(msg []byte) error {
if i.Conn == nil {
return nil
}
// 设置写入超时
// Set write timeout
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
// 写入数据
// Write data
_, err := i.Conn.Write(msg)
if err != nil && strings.Contains(err.Error(), "close") {
i.Conn.Close()
// 连接关闭时重试
// Retry when connection is closed
i.Conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
if err == nil {
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
@ -415,7 +415,7 @@ func (i *Info) Write(msg []byte) error {
}
}
// 记录发送的数据
// Record sent data
if err == nil {
i.Result.Send = msg
}
@ -423,22 +423,22 @@ func (i *Info) Write(msg []byte) error {
return err
}
// Read 从连接读取响应
// Read reads response from the connection
func (i *Info) Read() ([]byte, error) {
if i.Conn == nil {
return nil, nil
}
// 设置读取超时
// Set read timeout
i.Conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
// 读取数据
// Read data
result, err := readFromConn(i.Conn)
if err != nil && strings.Contains(err.Error(), "close") {
return result, err
}
// 记录接收到的数据
// Record received data
if len(result) > 0 {
i.Result.Recv = result
}
@ -446,9 +446,9 @@ func (i *Info) Read() ([]byte, error) {
return result, err
}
// readFromConn 从连接读取数据的辅助函数
// readFromConn helper function to read data from connection
func readFromConn(conn net.Conn) ([]byte, error) {
size := 2 * 1024 // 读取缓冲区大小
size := 2 * 1024 // Read buffer size
var result []byte
for {

View File

@ -10,47 +10,47 @@ import (
"time"
)
// Addr 表示待扫描的地址
// Addr represents the address to be scanned
type Addr struct {
ip string // IP地址
port int // 端口号
ip string // IP address
port int // Port number
}
// ScanResult 扫描结果
// ScanResult scanning result
type ScanResult struct {
Address string // IP地址
Port int // 端口号
Service *ServiceInfo // 服务信息
Address string // IP address
Port int // Port number
Service *ServiceInfo // Service information
}
// PortScan 执行端口扫描
// hostslist: 待扫描的主机列表
// ports: 待扫描的端口范围
// timeout: 超时时间(秒)
// 返回活跃地址列表
// PortScan executes port scanning
// hostslist: List of hosts to be scanned
// ports: Port range to be scanned
// timeout: Timeout in seconds
// Returns list of active addresses
func PortScan(hostslist []string, ports string, timeout int64) []string {
var results []ScanResult
var aliveAddrs []string
var mu sync.Mutex
// 解析并验证端口列表
// Parse and validate port list
probePorts := Common.ParsePort(ports)
if len(probePorts) == 0 {
Common.LogError(fmt.Sprintf("端口格式错误: %s", ports))
Common.LogError(fmt.Sprintf("Invalid port format: %s", ports))
return aliveAddrs
}
// 排除指定端口
// Exclude specified ports
probePorts = excludeNoPorts(probePorts)
// 初始化并发控制
// Initialize concurrency control
workers := Common.ThreadNum
addrs := make(chan Addr, 100) // 待扫描地址通道
scanResults := make(chan ScanResult, 100) // 扫描结果通道
addrs := make(chan Addr, 100) // Channel for addresses to be scanned
scanResults := make(chan ScanResult, 100) // Channel for scan results
var wg sync.WaitGroup
var workerWg sync.WaitGroup
// 启动扫描工作协程
// Start scanning worker goroutines
for i := 0; i < workers; i++ {
workerWg.Add(1)
go func() {
@ -61,7 +61,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
}()
}
// 启动结果处理协程
// Start result processing goroutine
var resultWg sync.WaitGroup
resultWg.Add(1)
go func() {
@ -75,7 +75,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
}
}()
// 分发扫描任务
// Distribute scanning tasks
for _, port := range probePorts {
for _, host := range hostslist {
wg.Add(1)
@ -83,7 +83,7 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
}
}
// 等待所有任务完成
// Wait for all tasks to complete
close(addrs)
workerWg.Wait()
wg.Wait()
@ -93,11 +93,11 @@ func PortScan(hostslist []string, ports string, timeout int64) []string {
return aliveAddrs
}
// PortConnect 执行单个端口连接检测
// addr: 待检测的地址
// results: 结果通道
// timeout: 超时时间
// wg: 等待组
// PortConnect performs connection detection for a single port
// addr: Address to be detected
// results: Results channel
// timeout: Timeout duration
// wg: Wait group
func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.WaitGroup) {
defer wg.Done()
@ -105,7 +105,7 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
var err error
var conn net.Conn
// 尝试建立TCP连接
// Try to establish TCP connection
conn, err = Common.WrapperTcpWithTimeout("tcp4",
fmt.Sprintf("%s:%v", addr.ip, addr.port),
time.Duration(timeout)*time.Second)
@ -118,11 +118,11 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
return
}
// 记录开放端口
// Record open port
address := fmt.Sprintf("%s:%d", addr.ip, addr.port)
Common.LogSuccess(fmt.Sprintf("端口开放 %s", address))
Common.LogSuccess(fmt.Sprintf("Port open %s", address))
// 保存端口扫描结果
// Save port scan result
portResult := &Common.ScanResult{
Time: time.Now(),
Type: Common.PORT,
@ -134,66 +134,66 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
}
Common.SaveResult(portResult)
// 构造扫描结果
// Construct scan result
result := ScanResult{
Address: addr.ip,
Port: addr.port,
}
// 执行服务识别
// Perform service identification
if !Common.SkipFingerprint && conn != nil {
scanner := NewPortInfoScanner(addr.ip, addr.port, conn, time.Duration(timeout)*time.Second)
if serviceInfo, err := scanner.Identify(); err == nil {
result.Service = serviceInfo
// 构造服务识别日志
// Construct service identification log
var logMsg strings.Builder
logMsg.WriteString(fmt.Sprintf("服务识别 %s => ", address))
logMsg.WriteString(fmt.Sprintf("Service identification %s => ", address))
if serviceInfo.Name != "unknown" {
logMsg.WriteString(fmt.Sprintf("[%s]", serviceInfo.Name))
}
if serviceInfo.Version != "" {
logMsg.WriteString(fmt.Sprintf(" 版本:%s", serviceInfo.Version))
logMsg.WriteString(fmt.Sprintf(" Version:%s", serviceInfo.Version))
}
// 收集服务详细信息
// Collect service details
details := map[string]interface{}{
"port": addr.port,
"service": serviceInfo.Name,
}
// 添加版本信息
// Add version information
if serviceInfo.Version != "" {
details["version"] = serviceInfo.Version
}
// 添加产品信息
// Add product information
if v, ok := serviceInfo.Extras["vendor_product"]; ok && v != "" {
details["product"] = v
logMsg.WriteString(fmt.Sprintf(" 产品:%s", v))
logMsg.WriteString(fmt.Sprintf(" Product:%s", v))
}
// 添加操作系统信息
// Add operating system information
if v, ok := serviceInfo.Extras["os"]; ok && v != "" {
details["os"] = v
logMsg.WriteString(fmt.Sprintf(" 系统:%s", v))
logMsg.WriteString(fmt.Sprintf(" OS:%s", v))
}
// 添加额外信息
// Add additional information
if v, ok := serviceInfo.Extras["info"]; ok && v != "" {
details["info"] = v
logMsg.WriteString(fmt.Sprintf(" 信息:%s", v))
logMsg.WriteString(fmt.Sprintf(" Info:%s", v))
}
// 添加Banner信息
// Add Banner information
if len(serviceInfo.Banner) > 0 && len(serviceInfo.Banner) < 100 {
details["banner"] = strings.TrimSpace(serviceInfo.Banner)
logMsg.WriteString(fmt.Sprintf(" Banner:[%s]", strings.TrimSpace(serviceInfo.Banner)))
}
// 保存服务识别结果
// Save service identification result
serviceResult := &Common.ScanResult{
Time: time.Now(),
Type: Common.SERVICE,
@ -210,17 +210,17 @@ func PortConnect(addr Addr, results chan<- ScanResult, timeout int64, wg *sync.W
results <- result
}
// NoPortScan 生成端口列表(不进行扫描)
// hostslist: 主机列表
// ports: 端口范围
// 返回地址列表
// NoPortScan generates a port list (without scanning)
// hostslist: Host list
// ports: Port range
// Returns address list
func NoPortScan(hostslist []string, ports string) []string {
var AliveAddress []string
// 解析并排除端口
// Parse and exclude ports
probePorts := excludeNoPorts(Common.ParsePort(ports))
// 生成地址列表
// Generate address list
for _, port := range probePorts {
for _, host := range hostslist {
address := fmt.Sprintf("%s:%d", host, port)
@ -231,27 +231,27 @@ func NoPortScan(hostslist []string, ports string) []string {
return AliveAddress
}
// excludeNoPorts 排除指定的端口
// ports: 原始端口列表
// 返回过滤后的端口列表
// excludeNoPorts excludes specified ports
// ports: Original port list
// Returns filtered port list
func excludeNoPorts(ports []int) []int {
noPorts := Common.ParsePort(Common.ExcludePorts)
if len(noPorts) == 0 {
return ports
}
// 使用map过滤端口
// Use map to filter ports
temp := make(map[int]struct{})
for _, port := range ports {
temp[port] = struct{}{}
}
// 移除需要排除的端口
// Remove ports to be excluded
for _, port := range noPorts {
delete(temp, port)
}
// 转换为有序切片
// Convert to ordered slice
var newPorts []int
for port := range temp {
newPorts = append(newPorts, port)

View File

@ -5,11 +5,11 @@ import (
"github.com/shadow1ng/fscan/Plugins"
)
// init 初始化并注册所有扫描插件
// 包括标准端口服务扫描、特殊扫描类型和本地信息收集等
// init initializes and registers all scan plugins
// including standard port service scans, special scan types, and local information collection
func init() {
// 1. 标准网络服务扫描插件
// 文件传输和远程访问服务
// 1. Standard network service scan plugins
// File transfer and remote access services
Common.RegisterPlugin("ftp", Common.ScanPlugin{
Name: "FTP",
Ports: []int{21},
@ -28,7 +28,7 @@ func init() {
ScanFunc: Plugins.TelnetScan,
})
// Windows网络服务
// Windows network services
Common.RegisterPlugin("findnet", Common.ScanPlugin{
Name: "FindNet",
Ports: []int{135},
@ -47,7 +47,7 @@ func init() {
ScanFunc: Plugins.SmbScan,
})
// 数据库服务
// Database services
Common.RegisterPlugin("mssql", Common.ScanPlugin{
Name: "MSSQL",
Ports: []int{1433, 1434},
@ -66,7 +66,7 @@ func init() {
ScanFunc: Plugins.MysqlScan,
})
// 中间件和消息队列服务
// Middleware and message queue services
Common.RegisterPlugin("elasticsearch", Common.ScanPlugin{
Name: "Elasticsearch",
Ports: []int{9200, 9300},
@ -91,14 +91,14 @@ func init() {
ScanFunc: Plugins.ActiveMQScan,
})
// 目录和认证服务
// Directory and authentication services
Common.RegisterPlugin("ldap", Common.ScanPlugin{
Name: "LDAP",
Ports: []int{389, 636},
ScanFunc: Plugins.LDAPScan,
})
// 邮件服务
// Mail services
Common.RegisterPlugin("smtp", Common.ScanPlugin{
Name: "SMTP",
Ports: []int{25, 465, 587},
@ -117,7 +117,7 @@ func init() {
ScanFunc: Plugins.POP3Scan,
})
// 网络管理和监控服务
// Network management and monitoring services
Common.RegisterPlugin("snmp", Common.ScanPlugin{
Name: "SNMP",
Ports: []int{161, 162},
@ -130,14 +130,14 @@ func init() {
ScanFunc: Plugins.ModbusScan,
})
// 数据同步和备份服务
// Data synchronization and backup services
Common.RegisterPlugin("rsync", Common.ScanPlugin{
Name: "Rsync",
Ports: []int{873},
ScanFunc: Plugins.RsyncScan,
})
// NoSQL数据库
// NoSQL databases
Common.RegisterPlugin("cassandra", Common.ScanPlugin{
Name: "Cassandra",
Ports: []int{9042},
@ -150,7 +150,7 @@ func init() {
ScanFunc: Plugins.Neo4jScan,
})
// 远程桌面和显示服务
// Remote desktop and display services
Common.RegisterPlugin("rdp", Common.ScanPlugin{
Name: "RDP",
Ports: []int{3389, 13389, 33389},
@ -169,7 +169,7 @@ func init() {
ScanFunc: Plugins.VncScan,
})
// 缓存和键值存储服务
// Cache and key-value storage services
Common.RegisterPlugin("redis", Common.ScanPlugin{
Name: "Redis",
Ports: []int{6379, 6380, 16379},
@ -194,7 +194,7 @@ func init() {
ScanFunc: Plugins.MongodbScan,
})
// 2. 特殊漏洞扫描插件
// 2. Special vulnerability scan plugins
Common.RegisterPlugin("ms17010", Common.ScanPlugin{
Name: "MS17010",
Ports: []int{445},
@ -207,7 +207,7 @@ func init() {
ScanFunc: Plugins.SmbGhost,
})
// 3. Web应用扫描插件
// 3. Web application scan plugins
Common.RegisterPlugin("webtitle", Common.ScanPlugin{
Name: "WebTitle",
Ports: Common.ParsePortsFromString(Common.WebPorts),
@ -220,7 +220,7 @@ func init() {
ScanFunc: Plugins.WebPoc,
})
// 4. Windows系统专用插件
// 4. Windows system specific plugins
Common.RegisterPlugin("smb2", Common.ScanPlugin{
Name: "SMBScan2",
Ports: []int{445},
@ -233,7 +233,7 @@ func init() {
ScanFunc: Plugins.WmiExec,
})
// 5. 本地信息收集插件
// 5. Local information collection plugins
Common.RegisterPlugin("localinfo", Common.ScanPlugin{
Name: "LocalInfo",
Ports: []int{},

View File

@ -13,92 +13,92 @@ import (
"time"
)
// 全局变量定义
// Global variable definitions
var (
LocalScan bool // 本地扫描模式标识
WebScan bool // Web扫描模式标识
LocalScan bool // Local scan mode identifier
WebScan bool // Web scan mode identifier
)
// Scan 执行扫描主流程
// info: 主机信息结构体,包含扫描目标的基本信息
// Scan executes the main scanning process
// info: Host information structure, contains basic information about the scan target
func Scan(info Common.HostInfo) {
Common.LogInfo("开始信息扫描")
Common.LogInfo("Starting information scan")
// 初始化HTTP客户端配置
// Initialize HTTP client configuration
lib.Inithttp()
// 初始化并发控制
// Initialize concurrency control
ch := make(chan struct{}, Common.ThreadNum)
wg := sync.WaitGroup{}
// 根据扫描模式执行不同的扫描策略
// Execute different scanning strategies based on scan mode
switch {
case Common.LocalMode:
// 本地信息收集模式
// Local information collection mode
LocalScan = true
executeLocalScan(info, &ch, &wg)
case len(Common.URLs) > 0:
// Web扫描模式
// Web scanning mode
WebScan = true
executeWebScan(info, &ch, &wg)
default:
// 主机扫描模式
// Host scanning mode
executeHostScan(info, &ch, &wg)
}
// 等待所有扫描任务完成
// Wait for all scanning tasks to complete
finishScan(&wg)
}
// executeLocalScan 执行本地扫描
// info: 主机信息
// ch: 并发控制通道
// wg: 等待组
// executeLocalScan executes local scanning
// info: Host information
// ch: Concurrency control channel
// wg: Wait group
func executeLocalScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
Common.LogInfo("执行本地信息收集")
Common.LogInfo("Executing local information collection")
// 获取本地模式支持的插件列表
// Get list of plugins supported by local mode
validLocalPlugins := getValidPlugins(Common.ModeLocal)
// 验证扫描模式的合法性
// Validate scan mode legality
if err := validateScanMode(validLocalPlugins, Common.ModeLocal); err != nil {
Common.LogError(err.Error())
return
}
// 输出使用的插件信息
// Output plugin information being used
if Common.ScanMode == Common.ModeLocal {
Common.LogInfo("使用全部本地插件")
Common.LogInfo("Using all local plugins")
Common.ParseScanMode(Common.ScanMode)
} else {
Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode))
Common.LogInfo(fmt.Sprintf("Using plugin: %s", Common.ScanMode))
}
// 执行扫描任务
// Execute scanning tasks
executeScans([]Common.HostInfo{info}, ch, wg)
}
// executeWebScan 执行Web扫描
// info: 主机信息
// ch: 并发控制通道
// wg: 等待组
// executeWebScan executes Web scanning
// info: Host information
// ch: Concurrency control channel
// wg: Wait group
func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
Common.LogInfo("开始Web扫描")
Common.LogInfo("Starting Web scanning")
// 获取Web模式支持的插件列表
// Get list of plugins supported by Web mode
validWebPlugins := getValidPlugins(Common.ModeWeb)
// 验证扫描模式的合法性
// Validate scan mode legality
if err := validateScanMode(validWebPlugins, Common.ModeWeb); err != nil {
Common.LogError(err.Error())
return
}
// 处理目标URL列表
// Process target URL list
var targetInfos []Common.HostInfo
for _, url := range Common.URLs {
urlInfo := info
// 确保URL包含协议头
// Ensure URL contains protocol header
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
url = "http://" + url
}
@ -106,43 +106,43 @@ func executeWebScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup)
targetInfos = append(targetInfos, urlInfo)
}
// 输出使用的插件信息
// Output plugin information being used
if Common.ScanMode == Common.ModeWeb {
Common.LogInfo("使用全部Web插件")
Common.LogInfo("Using all Web plugins")
Common.ParseScanMode(Common.ScanMode)
} else {
Common.LogInfo(fmt.Sprintf("使用插件: %s", Common.ScanMode))
Common.LogInfo(fmt.Sprintf("Using plugin: %s", Common.ScanMode))
}
// 执行扫描任务
// Execute scanning tasks
executeScans(targetInfos, ch, wg)
}
// executeHostScan 执行主机扫描
// info: 主机信息
// ch: 并发控制通道
// wg: 等待组
// executeHostScan executes host scanning
// info: Host information
// ch: Concurrency control channel
// wg: Wait group
func executeHostScan(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
// 验证扫描目标
// Validate scan target
if info.Host == "" {
Common.LogError("未指定扫描目标")
Common.LogError("Scan target not specified")
return
}
// 解析目标主机
// Parse target host
hosts, err := Common.ParseIP(info.Host, Common.HostsFile, Common.ExcludeHosts)
if err != nil {
Common.LogError(fmt.Sprintf("解析主机错误: %v", err))
Common.LogError(fmt.Sprintf("Host parsing error: %v", err))
return
}
Common.LogInfo("开始主机扫描")
Common.LogInfo("Starting host scanning")
executeScan(hosts, info, ch, wg)
}
// getValidPlugins 获取指定模式下的有效插件列表
// mode: 扫描模式
// 返回: 有效插件映射表
// getValidPlugins gets list of valid plugins for the specified mode
// mode: Scan mode
// returns: Valid plugins mapping table
func getValidPlugins(mode string) map[string]bool {
validPlugins := make(map[string]bool)
for _, plugin := range Common.PluginGroups[mode] {
@ -151,94 +151,94 @@ func getValidPlugins(mode string) map[string]bool {
return validPlugins
}
// validateScanMode 验证扫描模式的合法性
// validPlugins: 有效插件列表
// mode: 扫描模式
// 返回: 错误信息
// validateScanMode validates the legality of scan mode
// validPlugins: Valid plugin list
// mode: Scan mode
// returns: Error information
func validateScanMode(validPlugins map[string]bool, mode string) error {
if Common.ScanMode == "" || Common.ScanMode == "All" {
Common.ScanMode = mode
} else if _, exists := validPlugins[Common.ScanMode]; !exists {
return fmt.Errorf("无效的%s插件: %s", mode, Common.ScanMode)
return fmt.Errorf("Invalid %s plugin: %s", mode, Common.ScanMode)
}
return nil
}
// executeScan 执行主扫描流程
// hosts: 目标主机列表
// info: 主机信息
// ch: 并发控制通道
// wg: 等待组
// executeScan executes main scanning process
// hosts: Target host list
// info: Host information
// ch: Concurrency control channel
// wg: Wait group
func executeScan(hosts []string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
var targetInfos []Common.HostInfo
// 处理主机和端口扫描
// Process host and port scanning
if len(hosts) > 0 || len(Common.HostPort) > 0 {
// 检查主机存活性
// Check host liveness
if shouldPingScan(hosts) {
hosts = CheckLive(hosts, Common.UsePing)
Common.LogInfo(fmt.Sprintf("存活主机数量: %d", len(hosts)))
Common.LogInfo(fmt.Sprintf("Number of live hosts: %d", len(hosts)))
if Common.IsICMPScan() {
return
}
}
// 获取存活端口
// Get alive ports
alivePorts := getAlivePorts(hosts)
if len(alivePorts) > 0 {
targetInfos = prepareTargetInfos(alivePorts, info)
}
}
// 添加URL扫描目标
// Add URL scanning targets
targetInfos = appendURLTargets(targetInfos, info)
// 执行漏洞扫描
// Execute vulnerability scanning
if len(targetInfos) > 0 {
Common.LogInfo("开始漏洞扫描")
Common.LogInfo("Starting vulnerability scanning")
executeScans(targetInfos, ch, wg)
}
}
// shouldPingScan 判断是否需要执行ping扫描
// hosts: 目标主机列表
// 返回: 是否需要ping扫描
// shouldPingScan determines if ping scanning should be executed
// hosts: Target host list
// returns: Whether ping scanning is needed
func shouldPingScan(hosts []string) bool {
return (Common.DisablePing == false && len(hosts) > 1) || Common.IsICMPScan()
}
// getAlivePorts 获取存活端口列表
// hosts: 目标主机列表
// 返回: 存活端口列表
// getAlivePorts gets list of alive ports
// hosts: Target host list
// returns: List of alive ports
func getAlivePorts(hosts []string) []string {
var alivePorts []string
// 根据扫描模式选择端口扫描方式
// Choose port scanning method based on scan mode
if Common.IsWebScan() {
alivePorts = NoPortScan(hosts, Common.Ports)
} else if len(hosts) > 0 {
alivePorts = PortScan(hosts, Common.Ports, Common.Timeout)
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
Common.LogInfo(fmt.Sprintf("Number of alive ports: %d", len(alivePorts)))
if Common.IsPortScan() {
return nil
}
}
// 合并额外指定的端口
// Merge additional specified ports
if len(Common.HostPort) > 0 {
alivePorts = append(alivePorts, Common.HostPort...)
alivePorts = Common.RemoveDuplicate(alivePorts)
Common.HostPort = nil
Common.LogInfo(fmt.Sprintf("存活端口数量: %d", len(alivePorts)))
Common.LogInfo(fmt.Sprintf("Number of alive ports: %d", len(alivePorts)))
}
return alivePorts
}
// appendURLTargets 添加URL扫描目标
// targetInfos: 现有目标列表
// baseInfo: 基础主机信息
// 返回: 更新后的目标列表
// appendURLTargets adds URL scanning targets
// targetInfos: Existing target list
// baseInfo: Base host information
// returns: Updated target list
func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) []Common.HostInfo {
for _, url := range Common.URLs {
urlInfo := baseInfo
@ -248,16 +248,16 @@ func appendURLTargets(targetInfos []Common.HostInfo, baseInfo Common.HostInfo) [
return targetInfos
}
// prepareTargetInfos 准备扫描目标信息
// alivePorts: 存活端口列表
// baseInfo: 基础主机信息
// 返回: 目标信息列表
// prepareTargetInfos prepares scanning target information
// alivePorts: Alive port list
// baseInfo: Base host information
// returns: Target information list
func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common.HostInfo {
var infos []Common.HostInfo
for _, targetIP := range alivePorts {
hostParts := strings.Split(targetIP, ":")
if len(hostParts) != 2 {
Common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP))
Common.LogError(fmt.Sprintf("Invalid target address format: %s", targetIP))
continue
}
info := baseInfo
@ -268,27 +268,27 @@ func prepareTargetInfos(alivePorts []string, baseInfo Common.HostInfo) []Common.
return infos
}
// ScanTask 扫描任务结构体
// ScanTask scan task structure
type ScanTask struct {
pluginName string // 插件名称
target Common.HostInfo // 目标信息
pluginName string // Plugin name
target Common.HostInfo // Target information
}
// executeScans 执行扫描任务
// targets: 目标列表
// ch: 并发控制通道
// wg: 等待组
// executeScans executes scanning tasks
// targets: Target list
// ch: Concurrency control channel
// wg: Wait group
func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
mode := Common.GetScanMode()
// 获取要执行的插件列表
// Get list of plugins to execute
pluginsToRun, isSinglePlugin := getPluginsToRun(mode)
var tasks []ScanTask
actualTasks := 0
loadedPlugins := make([]string, 0)
// 收集扫描任务
// Collect scanning tasks
for _, target := range targets {
targetPort, _ := strconv.Atoi(target.Ports)
for _, pluginName := range pluginsToRun {
@ -305,22 +305,22 @@ func executeScans(targets []Common.HostInfo, ch *chan struct{}, wg *sync.WaitGro
}
}
// 处理插件列表
// Process plugin list
finalPlugins := getUniquePlugins(loadedPlugins)
Common.LogInfo(fmt.Sprintf("加载的插件: %s", strings.Join(finalPlugins, ", ")))
Common.LogInfo(fmt.Sprintf("Loaded plugins: %s", strings.Join(finalPlugins, ", ")))
// 初始化进度条
// Initialize progress bar
initializeProgressBar(actualTasks)
// 执行扫描任务
// Execute scanning tasks
for _, task := range tasks {
AddScan(task.pluginName, task.target, ch, wg)
}
}
// getPluginsToRun 获取要执行的插件列表
// mode: 扫描模式
// 返回: 插件列表和是否为单插件模式
// getPluginsToRun gets list of plugins to execute
// mode: Scan mode
// returns: Plugin list and whether it's single plugin mode
func getPluginsToRun(mode string) ([]string, bool) {
var pluginsToRun []string
isSinglePlugin := false
@ -335,13 +335,13 @@ func getPluginsToRun(mode string) ([]string, bool) {
return pluginsToRun, isSinglePlugin
}
// collectScanTasks 收集扫描任务
// plugin: 插件信息
// target: 目标信息
// targetPort: 目标端口
// pluginName: 插件名称
// isSinglePlugin: 是否为单插件模式
// 返回: 是否添加任务和任务列表
// collectScanTasks collects scanning tasks
// plugin: Plugin information
// target: Target information
// targetPort: Target port
// pluginName: Plugin name
// isSinglePlugin: Whether it's single plugin mode
// returns: Whether task was added and task list
func collectScanTasks(plugin Common.ScanPlugin, target Common.HostInfo, targetPort int, pluginName string, isSinglePlugin bool) (bool, []ScanTask) {
var tasks []ScanTask
taskAdded := false
@ -357,9 +357,9 @@ func collectScanTasks(plugin Common.ScanPlugin, target Common.HostInfo, targetPo
return taskAdded, tasks
}
// getUniquePlugins 获取去重后的插件列表
// loadedPlugins: 已加载的插件列表
// 返回: 去重并排序后的插件列表
// getUniquePlugins gets deduplicated plugin list
// loadedPlugins: Already loaded plugin list
// returns: Deduplicated and sorted plugin list
func getUniquePlugins(loadedPlugins []string) []string {
uniquePlugins := make(map[string]struct{})
for _, p := range loadedPlugins {
@ -375,15 +375,15 @@ func getUniquePlugins(loadedPlugins []string) []string {
return finalPlugins
}
// initializeProgressBar 初始化进度条
// actualTasks: 实际任务数量
// initializeProgressBar initializes progress bar
// actualTasks: Actual number of tasks
func initializeProgressBar(actualTasks int) {
if Common.ShowProgress {
Common.ProgressBar = progressbar.NewOptions(actualTasks,
progressbar.OptionEnableColorCodes(true),
progressbar.OptionShowCount(),
progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[cyan]扫描进度:[reset]"),
progressbar.OptionSetDescription("[cyan]Scanning progress:[reset]"),
progressbar.OptionSetTheme(progressbar.Theme{
Saucer: "[green]=[reset]",
SaucerHead: "[green]>[reset]",
@ -398,25 +398,25 @@ func initializeProgressBar(actualTasks int) {
}
}
// finishScan 完成扫描任务
// wg: 等待组
// finishScan completes scanning tasks
// wg: Wait group
func finishScan(wg *sync.WaitGroup) {
wg.Wait()
if Common.ProgressBar != nil {
Common.ProgressBar.Finish()
fmt.Println()
}
Common.LogSuccess(fmt.Sprintf("扫描已完成: %v/%v", Common.End, Common.Num))
Common.LogSuccess(fmt.Sprintf("Scanning completed: %v/%v", Common.End, Common.Num))
}
// Mutex 用于保护共享资源的并发访问
// Mutex for protecting concurrent access to shared resources
var Mutex = &sync.Mutex{}
// AddScan 添加扫描任务并启动扫描
// plugin: 插件名称
// info: 目标信息
// ch: 并发控制通道
// wg: 等待组
// AddScan adds scanning task and starts scanning
// plugin: Plugin name
// info: Target information
// ch: Concurrency control channel
// wg: Wait group
func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
*ch <- struct{}{}
wg.Add(1)
@ -433,29 +433,29 @@ func AddScan(plugin string, info Common.HostInfo, ch *chan struct{}, wg *sync.Wa
}()
}
// ScanFunc 执行扫描插件
// name: 插件名称
// info: 目标信息
// ScanFunc executes scanning plugin
// name: Plugin name
// info: Target information
func ScanFunc(name *string, info *Common.HostInfo) {
defer func() {
if err := recover(); err != nil {
Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
Common.LogError(fmt.Sprintf("Scanning error %v:%v - %v", info.Host, info.Ports, err))
}
}()
plugin, exists := Common.PluginManager[*name]
if !exists {
Common.LogInfo(fmt.Sprintf("扫描类型 %v 无对应插件,已跳过", *name))
Common.LogInfo(fmt.Sprintf("Scan type %v has no corresponding plugin, skipped", *name))
return
}
if err := plugin.ScanFunc(info); err != nil {
Common.LogError(fmt.Sprintf("扫描错误 %v:%v - %v", info.Host, info.Ports, err))
Common.LogError(fmt.Sprintf("Scanning error %v:%v - %v", info.Host, info.Ports, err))
}
}
// updateScanProgress 更新扫描进度
// info: 目标信息
// updateScanProgress updates scanning progress
// info: Target information
func updateScanProgress(info *Common.HostInfo) {
Common.OutputMutex.Lock()
atomic.AddInt64(&Common.End, 1)