mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

- 移除所有未使用的generateCredentials方法 - 删除插件适配器中的过时函数 - 清理MySQL连接器中的无用方法 - 移除Redis利用器中的未调用函数 - 删除遗留加密函数和基础扫描器无用方法 - 完全移除未注册的VNC插件 - 优化代码结构,提升项目可维护性 清理统计: 移除25+个死代码函数,减少400+行无用代码
168 lines
5.5 KiB
Go
168 lines
5.5 KiB
Go
package mysql
|
||
|
||
import (
|
||
"context"
|
||
"database/sql"
|
||
"fmt"
|
||
"net"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/go-sql-driver/mysql"
|
||
"github.com/shadow1ng/fscan/common"
|
||
"github.com/shadow1ng/fscan/plugins/base"
|
||
)
|
||
|
||
// MySQLConnector 实现MySQL数据库服务连接器
|
||
// 遵循 base.ServiceConnector 接口规范,提供标准化的MySQL连接和认证功能
|
||
|
||
// MySQLConnector MySQL数据库连接器
|
||
type MySQLConnector struct {
|
||
host string // 目标主机地址
|
||
port int // 目标端口号
|
||
}
|
||
|
||
// NewMySQLConnector 创建新的MySQL连接器实例
|
||
// 自动注册SOCKS代理支持,统一使用Context超时控制
|
||
func NewMySQLConnector() *MySQLConnector {
|
||
connector := &MySQLConnector{}
|
||
|
||
// 注册SOCKS代理支持的dialer(如果配置了代理)
|
||
connector.registerProxyDialer()
|
||
|
||
return connector
|
||
}
|
||
|
||
// Connect 建立到MySQL服务的基础连接
|
||
// 实现 base.ServiceConnector 接口的 Connect 方法
|
||
func (c *MySQLConnector) Connect(ctx context.Context, info *common.HostInfo) (interface{}, error) {
|
||
// 解析目标端口号
|
||
port, err := strconv.Atoi(info.Ports)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("无效的端口号: %s", info.Ports)
|
||
}
|
||
|
||
// 缓存目标信息,供认证阶段使用
|
||
c.host = info.Host
|
||
c.port = port
|
||
|
||
// 构建基础连接字符串(无认证信息)
|
||
connStr := c.buildConnectionString(info.Host, port, "", "")
|
||
|
||
// 创建数据库连接实例
|
||
db, err := sql.Open("mysql", connStr)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建连接失败: %v", err)
|
||
}
|
||
|
||
// 配置连接池参数
|
||
timeout := time.Duration(common.Timeout) * time.Second
|
||
db.SetConnMaxLifetime(timeout)
|
||
db.SetConnMaxIdleTime(timeout)
|
||
db.SetMaxIdleConns(0)
|
||
|
||
return db, nil
|
||
}
|
||
|
||
// Authenticate 使用凭据对MySQL服务进行身份认证
|
||
// 实现 base.ServiceConnector 接口的 Authenticate 方法
|
||
// 关键优化:使用独立的Context避免上游超时问题,并优化内存使用
|
||
func (c *MySQLConnector) Authenticate(ctx context.Context, conn interface{}, cred *base.Credential) error {
|
||
// 直接使用传入的Context,它已经包含了正确的超时设置
|
||
|
||
// 内存优化:预构建连接字符串,避免重复分配
|
||
connStr := c.buildConnectionString(c.host, c.port, cred.Username, cred.Password)
|
||
common.LogDebug(fmt.Sprintf("MySQL尝试认证: %s@%s:%d", cred.Username, c.host, c.port))
|
||
|
||
// 内存优化:直接建立连接而不创建连接池
|
||
// 避免为单次认证创建不必要的连接池开销
|
||
rawConn, err := c.connectDirect(ctx, connStr)
|
||
if err != nil {
|
||
common.LogDebug(fmt.Sprintf("MySQL直连失败: %s@%s:%d - %v", cred.Username, c.host, c.port, err))
|
||
return fmt.Errorf("连接失败: %v", err)
|
||
}
|
||
defer rawConn.Close()
|
||
|
||
// 执行简单的认证验证
|
||
err = c.validateConnection(ctx, rawConn)
|
||
if err != nil {
|
||
common.LogDebug(fmt.Sprintf("MySQL认证失败: %s@%s:%d - %v", cred.Username, c.host, c.port, err))
|
||
return fmt.Errorf("认证失败: %v", err)
|
||
}
|
||
|
||
common.LogDebug(fmt.Sprintf("MySQL认证成功: %s@%s:%d", cred.Username, c.host, c.port))
|
||
return nil
|
||
}
|
||
|
||
// Close 关闭MySQL连接
|
||
// 实现 base.ServiceConnector 接口的 Close 方法
|
||
func (c *MySQLConnector) Close(conn interface{}) error {
|
||
if db, ok := conn.(*sql.DB); ok {
|
||
return db.Close()
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 已移除未使用的 connectWithCredentials 方法
|
||
|
||
// buildConnectionString 构建MySQL连接字符串
|
||
// 根据是否配置SOCKS代理选择合适的连接方式
|
||
// 移除timeout参数,统一使用Context控制超时
|
||
func (c *MySQLConnector) buildConnectionString(host string, port int, username, password string) string {
|
||
// 根据代理配置选择网络类型
|
||
if common.Socks5Proxy != "" {
|
||
// SOCKS代理连接模式,移除timeout参数,由Context控制
|
||
return fmt.Sprintf("%v:%v@tcp-proxy(%v:%v)/mysql?charset=utf8",
|
||
username, password, host, port)
|
||
} else {
|
||
// 标准TCP直连模式,移除timeout参数,由Context控制
|
||
return fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8",
|
||
username, password, host, port)
|
||
}
|
||
}
|
||
|
||
// 已移除未使用的 buildConnectionStringWithCredentials 方法
|
||
|
||
// connectDirect 内存优化:直接建立MySQL连接,避免连接池开销
|
||
// 用于单次认证场景,减少内存分配和资源浪费
|
||
func (c *MySQLConnector) connectDirect(ctx context.Context, connStr string) (*sql.Conn, error) {
|
||
// 创建最小化配置的临时数据库实例
|
||
db, err := sql.Open("mysql", connStr)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("创建连接实例失败: %v", err)
|
||
}
|
||
defer db.Close() // 确保临时db实例被清理
|
||
|
||
// 禁用连接池以减少内存开销
|
||
db.SetMaxOpenConns(1)
|
||
db.SetMaxIdleConns(0)
|
||
db.SetConnMaxLifetime(0)
|
||
|
||
// 获取原始连接
|
||
conn, err := db.Conn(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("获取连接失败: %v", err)
|
||
}
|
||
|
||
return conn, nil
|
||
}
|
||
|
||
// validateConnection 内存优化:轻量级连接验证
|
||
// 使用最小开销的方式验证MySQL连接有效性
|
||
func (c *MySQLConnector) validateConnection(ctx context.Context, conn *sql.Conn) error {
|
||
// 使用传入的Context进行验证,统一超时控制
|
||
return conn.PingContext(ctx)
|
||
}
|
||
|
||
// registerProxyDialer 注册SOCKS代理支持的网络拨号器
|
||
// 仅在配置了SOCKS代理时才注册,避免不必要的开销
|
||
func (c *MySQLConnector) registerProxyDialer() {
|
||
if common.Socks5Proxy == "" {
|
||
return // 未配置代理,跳过注册
|
||
}
|
||
|
||
// 向MySQL驱动注册自定义的代理拨号器
|
||
mysql.RegisterDialContext("tcp-proxy", func(ctx context.Context, addr string) (net.Conn, error) {
|
||
return common.WrapperTcpWithContext(ctx, "tcp", addr)
|
||
})
|
||
} |