关注

【Rust 工程级扫描器实战】07|工程骨架期:lscan 扫描器架构大升级(全3篇) 第一篇:架构分层重构与核心设计模式落地

📌 关键词:#Rust 工程级扫描器实战 #Rust 红队开发 #Rust 网络扫描 #扫描器工程骨架期 #红队工具开发

📌 专栏说明:本专栏聚焦 Rust 红队扫描器(LSCAN)从脚本到工程化落地的全流程,核心探讨工程架构、模块划分、并发模型与设计取舍,不涉及基础语法教学,适合有 Rust 基础的红队工具开发者参考。


🔥 前言

上一篇我们通过统一上下文、标准化会话优化了 Stage 框架,提升了工程化程度与易用性。但随着扫描器功能迭代,原架构暴露出“组件耦合高、扩展困难、测试成本高”等问题。本次架构大升级将基于 RustMap 优秀设计理念,从“分层架构”和“设计模式”两大核心维度重构,打造可扩展、易维护、符合现代 Rust 应用最佳实践的工程化架构。


一、核心升级背景与目标

1.1 升级背景

原架构存在以下核心痛点,已无法满足长期迭代需求:

  • 组件耦合紧密:扫描逻辑、配置管理、输出处理等功能交织,修改一处需联动调整多处;

  • 缺乏抽象层:直接依赖具体实现,新增扫描类型(如资产探测)需大幅修改核心代码;

  • 扩展能力不足:输出格式、扫描策略等扩展场景需修改原有逻辑,不符合“开闭原则”;

  • 测试成本高昂:核心逻辑难以mock,单元测试覆盖率低;

  • 配置管理混乱:部分配置硬编码,缺乏统一的配置加载与验证机制。

1.2 升级目标

本次升级核心目标是构建“分层清晰、抽象完备、解耦彻底、易于扩展”的工程化架构,具体实现:

  • 明确架构分层,实现“职责单一”原则;

  • 引入核心设计模式,降低组件耦合;

  • 统一抽象接口,提升扩展灵活性;

  • 完善配置与事件系统,支撑模块化协作;

  • 提升代码可测试性,降低维护成本。


二、核心升级思路

本次升级围绕“分层架构+设计模式”双核心展开,核心思路:

  1. 按“用户交互-应用编排-业务逻辑-基础设施”划分架构分层,明确各层职责;

  2. 基于 Rust Trait 实现抽象接口,落地依赖倒置原则,解耦“抽象”与“实现”;

  3. 引入观察者、工厂、策略等设计模式,解决组件通信、实例创建、多策略扩展问题;

  4. 构建事件总线与统一配置中心,支撑模块化协作与灵活配置。


三、核心结构设计说明

3.1 四层架构设计

优化后的架构分为四层,每层职责单一,依赖关系自上而下(上层依赖下层抽象,不依赖具体实现):


┌─────────────────────────────────────────┐
│         CLI Layer (cli/)                │  ← 用户交互层:处理命令行输入,解析用户指令
├─────────────────────────────────────────┤
│    Application Layer (core.rs)          │  ← 应用编排层:协调各模块工作,通过事件总线通信
│  - Application 编排器                    │
│  - EventBus 事件总线                     │
├─────────────────────────────────────────┤
│   Business Logic Layer (scanner/)       │  ← 业务逻辑层:实现核心扫描功能,基于Trait抽象
│  - Scanner (trait)                      │
│  - HostDetector (trait)                 │
│  - PortScanner (trait)                  │
│  - ServiceDetector (trait)              │
│  - PocScanner (trait)                   │
├─────────────────────────────────────────┤
│  Infrastructure Layer                   │  ← 基础设施层:提供通用能力,支撑上层功能
│  - Config (配置管理)                     │
│  - Output (输出格式化)                   │
│  - Error (错误处理)                      │
│  - Logging (日志系统)                    │
└─────────────────────────────────────────┘

3.2 核心设计模式解析

本次升级落地5大核心设计模式,解决不同场景下的工程化问题:

模式1:Trait 抽象(面向接口编程)

所有核心业务功能均定义为 Trait 抽象接口,具体实现与接口分离,落地依赖倒置原则:

// 定义扫描器抽象接口
pub trait Scanner {
    fn scan(&self, session: &Session) -> Result<Vec<ScanContext>>;
    fn name(&self) -> &str; // 获取扫描器名称
}
​
// 实现具体的默认扫描器
pub struct DefaultScanner { 
    host_detector: Box<dyn HostDetector>,
    port_scanner: Box<dyn PortScanner>,
    // 组合其他检测器
}
​
impl Scanner for DefaultScanner {
    fn scan(&self, session: &Session) -> Result<Vec<ScanContext>> {
        // 实现扫描逻辑,调用组合的检测器
        let alive_hosts = self.host_detector.detect(&session.targets)?;
        let port_results = self.port_scanner.scan(&alive_hosts, &session.ports)?;
        Ok(port_results)
    }
    
    fn name(&self) -> &str {
        "default_scanner"
    }
}
​
// 使用抽象(依赖抽象而非具体实现)
let scanner: Box<dyn Scanner> = create_scanner(&config);
let results = scanner.scan(&session)?;

优势:

① 易于测试(可通过mock实现Trait模拟依赖);

② 易于扩展(新增扫描器只需实现Trait,无需修改原有逻辑);

③ 松耦合(上层模块仅依赖Trait接口,不依赖具体实现)。

模式2:观察者模式(事件驱动)

通过 EventBus 事件总线实现组件间解耦通信,核心扫描流程中发布事件,其他模块订阅处理:

// 定义扫描事件枚举
pub enum ScanEvent {
    PortDiscovered { ip: String, port: u16 },    // 端口发现事件
    ServiceDetected { ip: String, service: String }, // 服务识别事件
    VulnerabilityFound { ip: String, poc: String }, // 漏洞发现事件
}
​
// 事件处理器接口
pub trait EventHandler {
    fn handle(&self, event: &ScanEvent);
}
​
// 事件总线实现(简化版)
pub struct EventBus {
    handlers: Vec<Box<dyn EventHandler>>,
}
​
impl EventBus {
    // 发布事件:通知所有订阅者
    pub fn publish(&self, event: ScanEvent) {
        for handler in &self.handlers {
            handler.handle(&event);
        }
    }
    
    // 订阅事件:注册处理器
    pub fn subscribe(&mut self, handler: Box<dyn EventHandler>) {
        self.handlers.push(handler);
    }
}
​
// 使用示例:扫描过程中发布事件
event_bus.publish(ScanEvent::PortDiscovered { ip: "192.168.1.1".into(), port: 80 });
​
// 订阅事件:控制台输出处理器
struct ConsoleEventHandler;
impl EventHandler for ConsoleEventHandler {
    fn handle(&self, event: &ScanEvent) {
        match event {
            ScanEvent::PortDiscovered { ip, port } => println!("发现开放端口:{}:{}", ip, port),
            _ => {}
        }
    }
}
event_bus.subscribe(Box::new(ConsoleEventHandler));

优势:

① 组件解耦(发布者与订阅者无直接依赖);

② 实时反馈(扫描过程中实时推送状态);

③ 易于扩展(新增事件处理逻辑只需新增订阅者)。

模式3:工厂模式(实例创建)

通过工厂函数隐藏实例创建细节,根据配置动态生成具体实现,降低上层模块对实例创建的耦合:

// 扫描器工厂函数
pub fn create_scanner(config: &AppConfig) -> Box<dyn Scanner> {
    // 根据配置创建不同的扫描器实例
    Box::new(DefaultScanner::new(config.clone()))
}
​
// 输出格式化器工厂函数
pub fn create_formatter(format: &OutputFormat) -> Box<dyn OutputFormatter> {
    match format {
        OutputFormat::Json => Box::new(JsonFormatter),
        OutputFormat::Text => Box::new(TextFormatter),
        OutputFormat::Csv => Box::new(CsvFormatter),
    }
}
模式4:策略模式(多策略扩展)

针对“输出格式化”等多策略场景,通过 Trait 定义统一接口,不同策略实现不同逻辑:

​
// 输出格式化器抽象接口
pub trait OutputFormatter {
    fn format(&self, results: &[ScanContext]) -> Result<String>;
}
​
// 不同策略实现:JSON格式
pub struct JsonFormatter;
impl OutputFormatter for JsonFormatter {
    fn format(&self, results: &[ScanContext]) -> Result<String> {
        serde_json::to_string_pretty(results).map_err(|e| e.into())
    }
}
​
// 文本格式
pub struct TextFormatter;
impl OutputFormatter for TextFormatter {
    fn format(&self, results: &[ScanContext]) -> Result<String> {
        // 文本格式化逻辑
        Ok(format!("扫描结果总计:{}条", results.len()))
    }
}
模式5:组合模式(功能组合)

DefaultScanner 组合多个检测器(HostDetector、PortScanner 等),将复杂扫描功能拆解为多个子功能的组合:


pub struct DefaultScanner {
    host_detector: Box<dyn HostDetector>,    // 主机发现检测器
    port_scanner: Box<dyn PortScanner>,      // 端口扫描器
    service_detector: Box<dyn ServiceDetector>, // 服务识别器
    poc_scanner: Box<dyn PocScanner>,        // POC扫描器
}
​
impl DefaultScanner {
    pub fn new(config: AppConfig) -> Self {
        Self {
            host_detector: create_host_detector(&config),
            port_scanner: create_port_scanner(&config),
            service_detector: create_service_detector(&config),
            poc_scanner: create_poc_scanner(&config),
        }
    }
}

四、核心代码解析(架构核心组件)

4.1 应用编排器:Application

Application 位于应用编排层,负责协调各模块工作,是整个扫描器的“中枢”:

pub struct Application {
    config: AppConfig,          // 应用配置
    event_bus: EventBus,        // 事件总线
    scanner: Box<dyn Scanner>,  // 扫描器实例
    formatter: Box<dyn OutputFormatter>, // 输出格式化器
}
​
impl Application {
    pub fn new(config: AppConfig) -> Result<Self> {
        // 初始化事件总线
        let mut event_bus = EventBus::new();
        // 订阅默认事件处理器(控制台输出)
        event_bus.subscribe(Box::new(ConsoleEventHandler));
        
        // 通过工厂函数创建实例
        let scanner = create_scanner(&config);
        let formatter = create_formatter(&config.output.format);
        
        Ok(Self {
            config,
            event_bus,
            scanner,
            formatter,
        })
    }
    
    // 执行扫描流程
    pub fn run(&self, session: Session) -> Result<()> {
        // 执行扫描
        let results = self.scanner.scan(&session)?;
        // 格式化输出
        let formatted_result = self.formatter.format(&results)?;
        // 输出结果(打印或保存文件)
        if self.config.output.save_to_file {
            std::fs::write(&self.config.output.output_path, formatted_result)?;
        } else {
            println!("{}", formatted_result);
        }
        Ok(())
    }
    
    // 获取事件总线(用于扩展订阅)
    pub fn event_bus_mut(&mut self) -> &mut EventBus {
        &mut self.event_bus
    }
}

4.2 事件总线核心实现

use std::sync::Mutex;
​
// 线程安全的事件总线(支持多线程扫描场景)
pub struct EventBus {
    handlers: Mutex<Vec<Box<dyn EventHandler + Send + Sync>>>,
}
​
impl EventBus {
    pub fn new() -> Self {
        Self {
            handlers: Mutex::new(Vec::new()),
        }
    }
    
    // 发布事件
    pub fn publish(&self, event: ScanEvent) {
        let handlers = self.handlers.lock().unwrap();
        for handler in &*handlers {
            handler.handle(&event);
        }
    }
    
    // 订阅事件(支持动态添加)
    pub fn subscribe(&self, handler: Box<dyn EventHandler + Send + Sync>) {
        let mut handlers = self.handlers.lock().unwrap();
        handlers.push(handler);
    }
}
​
// 事件处理器Trait(支持线程安全)
pub trait EventHandler: Send + Sync {
    fn handle(&self, event: &ScanEvent);
}

五、核心特点与知识点总结

5.1 架构核心特点

  • 分层清晰:四层架构职责明确,降低跨层耦合;

  • 抽象完备:基于Trait实现接口抽象,落地依赖倒置;

  • 解耦彻底:通过事件总线实现组件通信解耦,无直接依赖;

  • 扩展灵活:新增功能只需实现Trait或新增订阅者,符合开闭原则;

  • 线程安全:事件总线支持多线程场景,适配后续并发优化。

5.2 核心知识点

  • Rust Trait 抽象:理解“接口”与“实现”的分离,掌握 dyn Trait 动态分发;

  • 设计模式落地:学会在 Rust 中实现观察者、工厂、策略等经典模式;

  • 线程安全设计:使用 Mutex 实现线程安全的事件总线,理解 Send/Sync Trait 约束;

  • 依赖注入:通过工厂函数将实例创建与使用分离,提升可测试性。

六、下篇预告

本篇我们完成了架构分层重构与核心设计模式落地,明确了各层职责与组件协作方式。下一篇将聚焦“项目结构优化与配置管理”,详细解析优化后的项目目录组织、统一配置体系实现,以及核心模块的职责划分。

📌 温馨提示:如需要本次架构升级后的完整源码,可关注微信公众号【砺石安全】回复:【20260105】 进行领取

📌 互动交流:如果本文对你理解 Rust 红队工具的工程化架构有帮助,欢迎点赞、收藏、关注!如果有疑问或优化建议,也可以在评论区留言讨论~

📚 专栏导航:

上一篇:【Rust 工程级扫描器实战】06|工程骨架期:Stage 版框架优化

下一篇:【Rust 工程级扫描器实战】07-2|工程骨架期:项目结构优化与配置管理

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_44616217/article/details/156616498

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--