项目文件夹

文件
wehub-resource-sync 161ef94b4f
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge API Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge UI Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Has been cancelled
Sirius CI/CD Pipeline / Integration Test (push) Has been cancelled
Sirius CI/CD Pipeline / Public Stack Contract (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:25 +08:00

2116 行
53 KiB
Markdown

---
title: "Sirius Scanner - Vulnerability Scanning Engine"
description: "Comprehensive documentation for the Sirius vulnerability scanning engine"
template: "TEMPLATE.documentation-standard"
version: "1.0.0"
last_updated: "2025-10-25"
author: "Sirius Team"
tags: ["scanner", "vulnerability", "nmap", "nse", "go", "rabbitmq"]
categories: ["backend", "security", "scanning"]
difficulty: "advanced"
prerequisites: ["Go 1.23+", "Docker", "RabbitMQ", "Nmap"]
related_docs:
- "documentation/dev/architecture/README.architecture.md"
- "documentation/dev/README.development.md"
dependencies:
- "../minor-projects/app-scanner"
- "../minor-projects/go-api"
- "../minor-projects/sirius-nse"
llm_context: "high"
search_keywords:
[
"scanner",
"vulnerability",
"nmap",
"nse",
"rabbitmq",
"valkey",
"scanning-engine",
]
---
# Sirius Scanner - Vulnerability Scanning Engine
## Overview
Sirius Scanner is a sophisticated, modular vulnerability scanning engine that orchestrates multiple security scanning tools (Nmap, RustScan, Naabu) through a message-driven architecture. Built in Go, it processes scan requests from RabbitMQ, executes multi-phase security assessments, and enriches vulnerability data with NVD information.
**Key Features:**
- **Message-Driven Architecture**: RabbitMQ-based scan request processing
- **Multi-Phase Scanning**: Enumeration → Discovery → Vulnerability assessment
- **Concurrent Processing**: Worker pool pattern for parallel target scanning
- **NSE Script Management**: Git-based synchronization with curated script repository
- **Template System**: Pre-configured and custom scan templates
- **Source Attribution**: Comprehensive tracking of scan origins and configurations
- **Real-Time Updates**: ValKey integration for live scan progress monitoring
**Repository Location:** `../minor-projects/app-scanner`
---
## Table of Contents
1. [Core Architecture](#core-architecture)
2. [Scanning Strategies](#scanning-strategies)
3. [NSE Script Management](#nse-script-management)
4. [Template System](#template-system)
5. [Scan Message Format](#scan-message-format)
6. [Target Processing](#target-processing)
7. [Source Attribution System](#source-attribution-system)
8. [State Management](#state-management)
9. [Docker Integration](#docker-integration)
10. [Configuration Files](#configuration-files)
11. [Development Workflow](#development-workflow)
12. [Key Files Reference](#key-files-reference)
13. [ValKey Schema Reference](#valkey-schema-reference)
14. [Profile vs Template System](#profile-vs-template-system)
15. [RabbitMQ Message Schema](#rabbitmq-message-schema)
---
## Core Architecture
### Message-Driven Design
The scanner operates as a **RabbitMQ consumer**, listening on the `scan` queue for incoming scan requests. This design enables:
- **Asynchronous Processing**: Scans don't block the API
- **Load Distribution**: Multiple scanner instances can consume from the same queue
- **Fault Tolerance**: Failed scans can be retried without data loss
- **Priority Handling**: Scan requests include priority levels (1-5)
**Entry Point:**
```go
// main.go
func main() {
scanManager := scan.NewScanManager(kvStore, toolFactory, scanUpdater)
scanManager.ListenForScans() // Blocks, listening for RabbitMQ messages
select {} // Keep service running
}
```
### Multi-Phase Scanning Workflow
Scans proceed through up to three phases based on `scan_types` configuration:
```
┌─────────────────┐
│ Enumeration │ Naabu: Fast port enumeration (SYN scan)
│ (Optional) │ Output: List of open ports
└────────┬────────┘
┌─────────────────┐
│ Discovery │ RustScan: Rapid host/port discovery
│ (Optional) │ Output: Live hosts with open ports
└────────┬────────┘
┌─────────────────┐
│ Vulnerability │ Nmap + NSE: Deep vulnerability scanning
│ (Required) │ Output: CVEs, service versions, OS detection
└─────────────────┘
```
**Phase Selection:**
```json
{
"options": {
"scan_types": ["enumeration", "discovery", "vulnerability"]
}
}
```
### Worker Pool Pattern
The scanner uses a **concurrent worker pool** (default: 10 workers) to process multiple targets simultaneously:
```go
// internal/scan/worker_pool.go
type WorkerPool struct {
workerCount int
taskQueue chan ScanTask
manager *ScanManager
}
// Each worker runs in its own goroutine
func (wp *WorkerPool) worker(ctx context.Context, id int) {
for {
select {
case task := <-wp.taskQueue:
wp.manager.scanIP(task.IP) // Execute scan
case <-ctx.Done():
return
}
}
}
```
**Benefits:**
- **Parallel Execution**: Scan multiple IPs concurrently
- **Resource Control**: Limit concurrent scans to prevent system overload
- **Graceful Shutdown**: Context-based cancellation
### Strategy Pattern
The scanner implements the **Strategy Pattern** for pluggable scan tools:
```go
// internal/scan/strategies.go
type ScanStrategy interface {
Execute(target string) (sirius.Host, error)
}
// Implementations:
type NaabuStrategy struct { ... } // Port enumeration
type RustScanStrategy struct { ... } // Discovery
type NmapStrategy struct { ... } // Vulnerability scanning
```
**Advantages:**
- **Extensibility**: Add new scanning tools without modifying core logic
- **Testability**: Mock strategies for unit testing
- **Flexibility**: Swap implementations based on requirements
### Factory Pattern
The `ScanToolFactory` dynamically creates appropriate strategies:
```go
// internal/scan/factory.go
func (f *ScanToolFactory) CreateTool(toolType string) ScanStrategy {
switch toolType {
case "enumeration":
return &NaabuStrategy{...}
case "discovery":
return &RustScanStrategy{}
case "vulnerability":
return &NmapStrategy{...}
}
}
```
---
## Scanning Strategies
### NaabuStrategy (Port Enumeration)
**Purpose:** Fast, accurate port enumeration using ProjectDiscovery's Naabu.
**Technology:** SYN-based port scanning (requires root/CAP_NET_RAW)
**Configuration:**
```go
type NaabuStrategy struct {
Ports string // Port range (e.g., "1-65535", "80,443,8080")
Retries int // Number of retry attempts
}
```
**Implementation Details:**
- Uses `github.com/projectdiscovery/naabu/v2` library
- Default timeout: 5 seconds per host
- Returns error `ErrHostDown` if no open ports found
- Outputs `sirius.Host` with populated `Ports` array
**Example Usage:**
```go
strategy := &NaabuStrategy{
Ports: "1-10000",
Retries: 3,
}
host, err := strategy.Execute("192.168.1.100")
// host.Ports: [{ID: 80, Protocol: "tcp", State: "open"}, ...]
```
**When to Use:**
- Need comprehensive port enumeration
- Scanning large port ranges (1-65535)
- Require retry logic for unstable networks
- Want detailed port state information
### RustScanStrategy (Discovery)
**Purpose:** Ultra-fast port discovery for identifying live hosts.
**Technology:** Adaptive multi-threaded port scanning (RustScan binary)
**Configuration:**
```go
type RustScanStrategy struct {
// Uses default RustScan settings
// Automatically adjusts thread count based on available resources
}
```
**Implementation Details:**
- Executes `rustscan` binary via `exec.Command`
- Parses output to extract open ports
- Filters results: hosts with no open ports are skipped
- Much faster than Nmap for initial discovery (5-20x speedup)
**Example Usage:**
```go
strategy := &RustScanStrategy{}
host, err := strategy.Execute("192.168.1.100")
// host.Ports: [{ID: 22, ...}, {ID: 80, ...}, {ID: 443, ...}]
```
**When to Use:**
- Scanning large IP ranges (entire subnets)
- Need rapid feedback on live hosts
- Initial reconnaissance phase
- Time-sensitive assessments
### NmapStrategy (Vulnerability Scanning)
**Purpose:** Deep vulnerability assessment with NSE script execution.
**Technology:** Nmap with NSE (Nmap Scripting Engine) for CVE detection
**Configuration:**
```go
type NmapStrategy struct {
Protocols []string // Legacy: protocol-based selection (e.g., ["smb", "http"])
ScriptList []string // Explicit script names (overrides Protocols)
}
```
**Implementation Details:**
- **Script Selection:**
- **Template-based**: Uses `EnabledScripts` from template
- **Protocol-based**: Selects scripts matching protocols (smb, http, ssh, ftp, rdp)
- **Wildcard**: `["*"]` runs all available NSE scripts
- **Nmap Command Construction:**
```bash
nmap -T4 -sV -Pn -p <ports> --script <scripts> --script-args-file <args.txt> <target> -oX -
```
- **CVE Extraction:** Parses Nmap XML output for CVE patterns
- **Vulnerability Enrichment:** Fetches CVE details from NVD API
- **Fallback Mechanism:** If script errors occur, retries with minimal safe scripts
**Example Usage:**
```go
// Template-based (recommended)
strategy := &NmapStrategy{
ScriptList: []string{"vulners", "smb-vuln-ms17-010", "http-shellshock"},
}
// Protocol-based
strategy := &NmapStrategy{
Protocols: []string{"smb", "http"},
}
host, err := strategy.Execute("192.168.1.100")
// host.Vulnerabilities: [{VID: "CVE-2017-0143", RiskScore: 9.3, ...}, ...]
```
**Script Processing:**
1. **Execution**: Nmap runs selected NSE scripts against target
2. **Parsing**: Extract structured data from script output
3. **CVE Detection**: Regex matching for `CVE-YYYY-NNNNN` patterns
4. **Enrichment**: Query NVD API for descriptions, CVSS scores
5. **Deduplication**: Remove duplicate CVEs from different scripts
**Fallback Scan:**
If NSE scripts fail (e.g., script syntax errors), scanner automatically retries with minimal safe scripts:
```go
safeScripts := []string{"banner", "http-title", "ssl-cert"}
```
**When to Use:**
- Deep security assessment required
- Need CVE identification
- Service version detection
- OS fingerprinting
- Protocol-specific vulnerability checks
---
## NSE Script Management
The scanner maintains a curated collection of NSE scripts via the `sirius-nse` repository.
### Repository Management (`internal/nse/repo.go`)
**Purpose:** Git-based synchronization of NSE scripts.
**Repository URL:** `https://github.com/SiriusScan/sirius-nse.git`
**Local Path:** `/opt/sirius/nse/sirius-nse` (in Docker container)
**Operations:**
```go
type RepoManager struct {
BasePath string // /opt/sirius/nse/sirius-nse
RepoURL string // GitHub repository
gitOps GitOperations
}
// Ensure repository exists and is up-to-date
func (rm *RepoManager) EnsureRepo() error {
if !rm.isGitRepo() {
// Clone on first run
return rm.gitOps.Clone(rm.RepoURL, rm.BasePath)
}
// Update existing repository
return rm.updateRepo()
}
// Update: fetch + reset to origin/main
func (rm *RepoManager) updateRepo() error {
rm.gitOps.Fetch(rm.BasePath)
rm.gitOps.Reset(rm.BasePath) // Hard reset to origin/main
return nil
}
```
**Sync Timing:**
- **Startup**: Syncs when `ScanManager` initializes
- **Before Scans**: Automatic sync before first scan (via `ListenForScans`)
- **Manual**: Can be triggered via management API (future)
**Symlink Strategy:**
Nmap's script directory is symlinked to sirius-nse:
```dockerfile
# Dockerfile
RUN ln -sf /opt/sirius/nse/sirius-nse/scripts /usr/local/share/nmap/scripts
```
This ensures **only curated scripts** are available, preventing accidental execution of default Nmap scripts.
### Script Selection (`internal/nse/script_selector.go`)
**Purpose:** Select appropriate NSE scripts based on protocols or explicit list.
**Manifest Structure:**
```json
{
"version": "1.0",
"scripts": [
{
"name": "vulners",
"category": "vuln",
"protocols": ["*"]
},
{
"name": "smb-vuln-ms17-010",
"category": "vuln",
"protocols": ["smb"]
}
]
}
```
**Script Selection Logic:**
```go
type ScriptSelector struct {
manifest *Manifest
blacklist map[string]bool
}
// Build Nmap --script flag
func (ss *ScriptSelector) BuildNmapScriptFlag(protocols ...string) (string, error) {
if len(protocols) == 1 && protocols[0] == "*" {
// Return all non-blacklisted scripts
return ss.getAllScripts(), nil
}
// Filter by protocols
scripts := []string{}
for _, script := range ss.manifest.Scripts {
if ss.matchesProtocol(script, protocols) && !ss.isBlacklisted(script.Name) {
scripts = append(scripts, script.Name)
}
}
return strings.Join(scripts, ","), nil
}
```
**Protocol Matching:**
- `*` (wildcard): Script applies to all protocols
- Exact match: `["smb"]` matches scripts with `protocols: ["smb"]`
- Multiple protocols: `["smb", "http"]` matches scripts with either protocol
**Example:**
```go
selector := nse.NewScriptSelector(manifest)
scriptFlag, _ := selector.BuildNmapScriptFlag("smb", "http")
// Result: "vulners,smb-vuln-ms17-010,smb-os-discovery,http-title,http-enum,..."
```
### Script Blacklist (`internal/nse/script_blacklist.go`)
**Purpose:** Exclude problematic or slow scripts.
**Blacklist Criteria:**
- **False Positives**: Scripts with high FP rates
- **Performance**: Extremely slow scripts (>5 minutes per host)
- **Stability**: Scripts that crash or hang frequently
- **Compatibility**: Scripts incompatible with our environment
**Example Blacklist:**
```go
var DefaultBlacklist = map[string]bool{
"broadcast-dhcp-discover": true, // Sends broadcasts
"firewalk": true, // Very slow
"http-slowloris-check": true, // DoS risk
}
```
**Blacklist Management:**
- Centrally managed in `script_blacklist.go`
- Can be overridden via environment variables (future)
- Logged when scripts are excluded
### Sync Manager (`internal/nse/sync.go`)
**Purpose:** Coordinate NSE repository updates with scan operations.
**Responsibilities:**
1. **Pre-Scan Sync**: Ensure scripts are up-to-date before scanning
2. **Concurrency Control**: Prevent multiple simultaneous syncs
3. **Error Handling**: Log sync failures but don't block scans
4. **Context Awareness**: Respect context cancellation
**Implementation:**
```go
type SyncManager struct {
repoManager *RepoManager
kvStore store.KVStore
lastSync time.Time
syncMutex sync.Mutex
}
func (sm *SyncManager) Sync(ctx context.Context) error {
sm.syncMutex.Lock()
defer sm.syncMutex.Unlock()
// Skip if recently synced (within 1 hour)
if time.Since(sm.lastSync) < time.Hour {
return nil
}
// Perform sync
if err := sm.repoManager.EnsureRepo(); err != nil {
return fmt.Errorf("failed to sync NSE repo: %w", err)
}
sm.lastSync = time.Now()
return nil
}
```
**Sync Strategy:**
- **Cooldown Period**: 1 hour between syncs
- **Non-Blocking**: Sync failures logged but don't prevent scans
- **Startup Sync**: Always sync on scanner startup
---
## Template System
Templates provide **pre-configured scan profiles** for common use cases.
### Template Structure
```go
type Template struct {
ID string // Unique identifier (e.g., "high-risk")
Name string // Human-readable name
Description string // Usage description
Type TemplateType // SystemTemplate or CustomTemplate
EnabledScripts []string // NSE scripts to run
ScanOptions TemplateOptions // Default scan options
CreatedAt time.Time
UpdatedAt time.Time
}
type TemplateOptions struct {
ScanTypes []string // ["enumeration", "discovery", "vulnerability"]
PortRange string // "1-10000"
Aggressive bool // Enable aggressive scanning
MaxRetries int // Retry attempts
Parallel bool // Parallel target scanning
ExcludePorts []string // Ports to skip
}
```
### System Templates
**Pre-defined templates initialized on startup:**
#### 1. `high-risk` - Focused Critical Vulnerability Scan
**Purpose:** Balanced scan focusing on high-impact vulnerabilities.
**Scripts:** 10 carefully selected scripts
```go
EnabledScripts: []string{
"vulners", // CVE detection (highest value)
"smb-vuln-ms17-010", // EternalBlue
"http-shellshock", // Shellshock vulnerability
"http-vuln-cve2017-5638", // Apache Struts RCE
"banner", // Service identification
"http-title", // HTTP identification
"ssl-cert", // SSL certificate info
"http-enum", // HTTP path enumeration
"smb-os-discovery", // SMB OS detection
"ftp-anon", // Anonymous FTP access
}
ScanOptions: {
ScanTypes: []string{"enumeration", "discovery", "vulnerability"},
PortRange: "1-10000",
Aggressive: true,
MaxRetries: 3,
Parallel: true,
}
```
**Use Case:** Default scan for most security assessments.
#### 2. `all` - Comprehensive Scan
**Purpose:** Exhaustive scanning with all available NSE scripts.
**Scripts:** All non-blacklisted scripts (wildcard)
```go
EnabledScripts: []string{"*"} // Special marker
ScanOptions: {
ScanTypes: []string{"enumeration", "discovery", "vulnerability"},
PortRange: "1-65535",
Aggressive: true,
MaxRetries: 3,
Parallel: false, // Sequential for thoroughness
}
```
**Use Case:** Deep penetration testing, compliance audits.
**Warning:** Can take hours per host. Use sparingly.
#### 3. `quick` - Fast Scan
**Purpose:** Rapid assessment with essential scripts.
**Scripts:** 3 lightweight scripts
```go
EnabledScripts: []string{
"vulners", // CVE detection
"banner", // Service identification
"http-title", // HTTP identification
}
ScanOptions: {
ScanTypes: []string{"enumeration", "vulnerability"},
PortRange: "top500Ports", // Most common 500 ports
Aggressive: false,
MaxRetries: 2,
Parallel: true,
}
```
**Use Case:** Initial reconnaissance, time-sensitive scans.
### Custom Templates
**Users can create custom templates via UI (future) or API.**
**Creation Example:**
```go
template := &Template{
ID: "web-app-scan",
Name: "Web Application Scan",
Description: "Focused scan for web application vulnerabilities",
Type: CustomTemplate,
EnabledScripts: []string{
"vulners",
"http-enum",
"http-shellshock",
"http-sql-injection",
"ssl-cert",
},
ScanOptions: TemplateOptions{
ScanTypes: []string{"discovery", "vulnerability"},
PortRange: "80,443,8080,8443",
Aggressive: false,
MaxRetries: 2,
Parallel: true,
},
}
templateManager.CreateTemplate(ctx, template)
```
**Template Operations:**
```go
// Get template
template, err := templateManager.GetTemplate(ctx, "high-risk")
// List all templates
templates, err := templateManager.ListTemplates(ctx)
// Update custom template (system templates are immutable)
templateManager.UpdateTemplate(ctx, template)
// Delete custom template
templateManager.DeleteTemplate(ctx, "my-template")
```
### Template Resolution
**When a scan message includes `template_id`, the scanner:**
1. **Fetches Template**: Retrieve from ValKey
2. **Applies Defaults**: Use template's `EnabledScripts` and `ScanOptions`
3. **Merges User Options**: User-provided options override template defaults
4. **Resolves Scripts**: Convert template script list to Nmap `--script` flag
**Resolution Logic:**
```go
func (sm *ScanManager) handleMessage(msg string) {
var scanMsg ScanMessage
json.Unmarshal([]byte(msg), &scanMsg)
if scanMsg.Options.TemplateID != "" {
template, _ := sm.templateManager.GetTemplate(ctx, scanMsg.Options.TemplateID)
// User options override template defaults
if scanMsg.Options.PortRange == "" {
scanMsg.Options.PortRange = template.ScanOptions.PortRange
}
if len(scanMsg.Options.ScanTypes) == 0 {
scanMsg.Options.ScanTypes = template.ScanOptions.ScanTypes
}
// ... merge other options
}
sm.processTarget(scanMsg.Targets[0])
}
```
**Priority:** User Options > Template Defaults > System Defaults
---
## Scan Message Format
Scan requests are **JSON messages** sent to the `scan` RabbitMQ queue.
### Message Structure
```go
type ScanMessage struct {
ID string // Unique scan identifier
Targets []Target // Targets to scan
Options ScanOptions // Scan configuration
Priority int // 1 (low) to 5 (high)
CallbackURL string // Optional webhook on completion
}
type Target struct {
Value string // IP, range, CIDR, or hostname
Type TargetType // Target type identifier
Timeout int // Per-target timeout (seconds, optional)
}
type TargetType string
const (
SingleIP TargetType = "single_ip" // 192.168.1.1
IPRange TargetType = "ip_range" // 192.168.1.1-192.168.1.254
CIDR TargetType = "cidr" // 192.168.1.0/24
DNSName TargetType = "dns_name" // example.com
DNSWildcard TargetType = "dns_wildcard" // *.example.com (TODO)
)
type ScanOptions struct {
TemplateID string // Template to use (optional)
PortRange string // "1-65535", "80,443,8080"
Aggressive bool // Aggressive scanning mode
ExcludePorts []string // Ports to skip
ScanTypes []string // ["enumeration", "discovery", "vulnerability"]
MaxRetries int // Retry attempts
Parallel bool // Parallel target scanning
}
```
### Example Messages
#### Simple Single-IP Scan
```json
{
"id": "scan-001",
"targets": [
{
"value": "192.168.1.100",
"type": "single_ip"
}
],
"options": {
"template_id": "high-risk",
"scan_types": ["vulnerability"]
},
"priority": 3
}
```
#### CIDR Range with Custom Options
```json
{
"id": "scan-002",
"targets": [
{
"value": "192.168.1.0/24",
"type": "cidr"
}
],
"options": {
"port_range": "1-10000",
"aggressive": true,
"scan_types": ["discovery", "vulnerability"],
"max_retries": 3,
"parallel": true
},
"priority": 4
}
```
#### Multi-Target Scan with Template
```json
{
"id": "scan-003",
"targets": [
{
"value": "192.168.1.1",
"type": "single_ip"
},
{
"value": "192.168.1.100-192.168.1.110",
"type": "ip_range"
},
{
"value": "example.com",
"type": "dns_name"
}
],
"options": {
"template_id": "quick",
"scan_types": ["enumeration", "vulnerability"]
},
"priority": 2,
"callback_url": "https://api.example.com/scan-complete"
}
```
### Validation Rules
**Required Fields:**
- `id`: Must be unique (recommended: UUID)
- `targets`: At least one target
- `options.scan_types`: At least one scan type
- `priority`: 1-5 (inclusive)
**Optional Fields:**
- `template_id`: If omitted, uses system defaults
- `callback_url`: If provided, webhook POST on completion
**Validation Errors:**
```go
func (sm *ScanManager) validateScanMessage(msg *ScanMessage) error {
if len(msg.Targets) == 0 {
return fmt.Errorf("no targets specified")
}
if msg.Priority < 1 || msg.Priority > 5 {
return fmt.Errorf("invalid priority: must be between 1 and 5")
}
return nil
}
```
---
## Target Processing
### Target Type Expansion
The scanner **expands** targets into individual IPs for worker pool processing.
#### Single IP
**Format:** `192.168.1.100`
**Processing:** Direct pass-through
```go
case SingleIP:
if !validateIP(target.Value) {
return nil, fmt.Errorf("invalid IP address: %s", target.Value)
}
return []string{target.Value}, nil
```
#### IP Range
**Format:** `192.168.1.1-192.168.1.254`
**Processing:** Expand to all IPs in range
```go
case IPRange:
return expandIPRange(target.Value)
// Returns: ["192.168.1.1", "192.168.1.2", ..., "192.168.1.254"]
```
**Implementation:**
```go
func expandIPRange(rangeStr string) ([]string, error) {
parts := strings.Split(rangeStr, "-")
startIP := net.ParseIP(parts[0])
endIP := net.ParseIP(parts[1])
// Iterate from startIP to endIP
ips := []string{}
for ip := startIP; !ip.Equal(endIP); ip = incrementIP(ip) {
ips = append(ips, ip.String())
}
return ips, nil
}
```
#### CIDR Block
**Format:** `192.168.1.0/24`
**Processing:** Expand to all IPs in subnet (excluding network/broadcast)
```go
case CIDR:
if !validateCIDR(target.Value) {
return nil, fmt.Errorf("invalid CIDR notation: %s", target.Value)
}
return expandCIDR(target.Value)
// Returns: ["192.168.1.1", "192.168.1.2", ..., "192.168.1.254"]
```
**Note:** Skips network address (`.0`) and broadcast address (`.255`)
#### DNS Name
**Format:** `example.com`
**Processing:** DNS resolution to IP(s)
```go
case DNSName:
ips, err := net.LookupIP(target.Value)
if err != nil {
return nil, fmt.Errorf("DNS lookup failed: %v", err)
}
result := make([]string, len(ips))
for i, ip := range ips {
result[i] = ip.String()
}
return result, nil
```
**Handles:**
- Multiple A/AAAA records (returns all IPs)
- IPv4 and IPv6 addresses
- DNS resolution failures (returns error)
#### DNS Wildcard (TODO)
**Format:** `*.example.com`
**Status:** Not yet implemented
**Planned Behavior:**
1. Subdomain enumeration (via DNS brute-force or Certificate Transparency logs)
2. Resolution of discovered subdomains to IPs
3. Deduplication of IPs
### Worker Pool Processing
After expansion, each IP is **enqueued as a task**:
```go
func (sm *ScanManager) processTarget(target Target) {
targetIPs, err := sm.prepareTarget(target)
if err != nil {
log.Printf("Failed to prepare target: %v", err)
return
}
// Add each IP to worker pool queue
for _, ip := range targetIPs {
task := ScanTask{
IP: ip,
Options: sm.currentScanOptions,
}
sm.workerPool.AddTask(task)
}
}
```
**Worker Pool Flow:**
```
Target Expansion
┌─────────────────┐
│ Task Queue │
│ (Channel) │
└────────┬────────┘
├─────► Worker 1 ──► scanIP(192.168.1.1)
├─────► Worker 2 ──► scanIP(192.168.1.2)
├─────► Worker 3 ──► scanIP(192.168.1.3)
│ ...
└─────► Worker 10 ─► scanIP(192.168.1.10)
```
---
## Source Attribution System
The scanner implements **comprehensive source attribution** to track scan origins and configurations.
### Purpose
- **Audit Trail**: Who/what/when/how for each scan
- **Debugging**: Troubleshoot scanning issues with full context
- **Compliance**: Demonstrate due diligence in security assessments
- **Analytics**: Understand scanning patterns and effectiveness
### Source Metadata
```go
type ScanSource struct {
Name string // Tool name (e.g., "nmap", "rustscan", "naabu")
Version string // Tool version (e.g., "7.94")
Config string // Scan configuration (semicolon-separated key:value pairs)
}
```
### Configuration Tracking
The scanner captures:
**Scan Configuration:**
- `ports`: Port range scanned
- `aggressive`: Aggressive mode enabled
- `types`: Scan types executed
- `exclude`: Excluded ports
- `template`: Template ID used
**System Information:**
- `host`: Hostname of scanning system
- `user`: User running scanner
- `scanner_id`: Unique scan identifier
- `go_version`: Go runtime version
**Example Config String:**
```
ports:1-10000;aggressive:true;types:enumeration,discovery,vulnerability;template:high-risk;host:scanner-prod-01;user:siriususer;scanner_id:scan-abc123;go_version:go1.23.0
```
### Version Detection
Automatically detects scanning tool versions:
```go
func (sm *ScanManager) detectScannerVersion(toolName string) string {
switch toolName {
case "nmap":
output, _ := exec.Command("nmap", "--version").Output()
// Parse: "Nmap version 7.94 ( https://nmap.org )"
return extractVersion(output)
case "rustscan":
output, _ := exec.Command("rustscan", "--version").Output()
// Parse: "rustscan 2.1.1"
return extractVersion(output)
case "naabu":
output, _ := exec.Command("naabu", "-version").Output()
return extractVersion(output)
}
}
```
### API Submission
Results are submitted via **source-aware API endpoint**:
```go
func (sm *ScanManager) submitHostWithSource(host sirius.Host, toolName string) error {
source := sm.createScanSource(toolName)
request := SourcedHostRequest{
Host: host,
Source: source,
}
jsonData, _ := json.Marshal(request)
url := fmt.Sprintf("%s/host/with-source", sm.apiBaseURL)
resp, _ := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
return nil
}
```
**API Endpoint:** `POST /host/with-source`
**Request Body:**
```json
{
"host": {
"ip": "192.168.1.100",
"ports": [...],
"vulnerabilities": [...]
},
"source": {
"name": "nmap",
"version": "7.94",
"config": "ports:1-10000;aggressive:true;template:high-risk;host:scanner-01;..."
}
}
```
### Database Storage
The API stores source attribution in PostgreSQL:
**Schema:**
```sql
CREATE TABLE scan_sources (
id SERIAL PRIMARY KEY,
name VARCHAR(255),
version VARCHAR(50),
config TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE hosts (
id SERIAL PRIMARY KEY,
ip VARCHAR(45),
scan_source_id INTEGER REFERENCES scan_sources(id),
...
);
```
This enables queries like:
- "Show all vulnerabilities found by Nmap 7.94"
- "List scans using the 'high-risk' template"
- "Find hosts scanned from scanner-prod-01"
---
## State Management
The scanner maintains **real-time scan state** using two systems:
### ValKey Integration
**Purpose:** Live scan progress tracking for UI display.
**Key Structure:**
```
scan:<scan_id> = {
"status": "running",
"start_time": "2025-10-25T10:30:00Z",
"end_time": null,
"hosts": ["192.168.1.1", "192.168.1.2", ...],
"hosts_completed": 45,
"vulnerabilities": [
{
"id": "CVE-2017-0143",
"severity": "critical",
"title": "EternalBlue SMB RCE",
"description": "Remote code execution..."
}
]
}
```
**Update Pattern:**
```go
type ScanUpdater struct {
kvStore store.KVStore
}
func (su *ScanUpdater) Update(ctx context.Context, updateFn func(*ScanResult) error) error {
// 1. Get current scan state from ValKey
current, _ := su.kvStore.GetValue(ctx, "scan:"+scanID)
// 2. Apply update function
var scan ScanResult
json.Unmarshal([]byte(current.Message.Value), &scan)
updateFn(&scan)
// 3. Write updated state back to ValKey
updated, _ := json.Marshal(scan)
su.kvStore.SetValue(ctx, "scan:"+scanID, string(updated))
return nil
}
```
**Update Events:**
- **Discovery Complete:** Add host to `hosts` array
- **Host Complete:** Increment `hosts_completed`
- **Vulnerability Found:** Add to `vulnerabilities` array
- **Scan Complete:** Set `status = "completed"`, set `end_time`
**Example Update:**
```go
sm.scanUpdater.Update(ctx, func(scan *ScanResult) error {
scan.HostsCompleted++
if scan.HostsCompleted >= len(scan.Hosts) {
scan.Status = "completed"
scan.EndTime = time.Now().Format(time.RFC3339)
}
return nil
})
```
### Logging System
**Purpose:** Structured audit trail for compliance and debugging.
**Implementation:** RabbitMQ-based logging to `scanner_logs` queue.
**Log Client:**
```go
type LoggingClient struct {
queueName string // "scanner_logs"
}
func (lc *LoggingClient) LogScanEvent(scanID, eventType, message string, metadata map[string]interface{}) {
logEntry := map[string]interface{}{
"timestamp": time.Now().Format(time.RFC3339),
"scan_id": scanID,
"event_type": eventType,
"message": message,
"metadata": metadata,
}
jsonData, _ := json.Marshal(logEntry)
queue.Publish("scanner_logs", string(jsonData))
}
```
**Event Types:**
| Event Type | Description | Metadata |
| --------------------- | ------------------------ | -------------------------------------------- |
| `scan_initiated` | Scan request received | targets_count, priority, template_id |
| `target_prepared` | Target expanded to IPs | target_value, target_type, ips_generated |
| `host_discovered` | Live host found | host_ip, ports, tool |
| `tool_execution` | Scanning tool completed | tool, duration, success, ports_found |
| `vulnerability_found` | CVE detected | host_ip, cve_id, severity, tool |
| `host_completed` | All phases done for host | host_ip, vulnerabilities_found |
| `scan_completed` | Entire scan finished | total_hosts, vulnerabilities_found, duration |
| `scan_error` | Error occurred | host_ip, error_type, error_message |
**Example Log Entries:**
```json
// scan_initiated
{
"timestamp": "2025-10-25T10:30:00Z",
"scan_id": "scan-abc123",
"event_type": "scan_initiated",
"message": "Scan request received",
"metadata": {
"targets_count": 3,
"priority": 4,
"template_id": "high-risk"
}
}
// vulnerability_found
{
"timestamp": "2025-10-25T10:35:22Z",
"scan_id": "scan-abc123",
"event_type": "vulnerability_found",
"message": "CVE detected",
"metadata": {
"host_ip": "192.168.1.100",
"cve_id": "CVE-2017-0143",
"severity": "critical",
"tool": "nmap"
}
}
```
**Log Consumption:**
- **Elasticsearch**: Indexing for search/analytics
- **File**: JSON lines for long-term storage
- **Monitoring**: Real-time alerting on errors
---
## Docker Integration
The scanner runs inside the `sirius-engine` container, which bundles multiple applications.
### Dockerfile Architecture
**Multi-Stage Build:**
```dockerfile
# Stage 1: Builder
FROM golang:1.23-bullseye AS builder
# Install build dependencies
RUN apt-get update && apt-get install -y \
git ca-certificates build-essential libpcap-dev
# Clone and build app-scanner
RUN git clone https://github.com/SiriusScan/app-scanner.git && \
cd app-scanner && \
CGO_ENABLED=1 GOOS=linux go build -ldflags="-w -s" -o scanner main.go
# Stage 2: Runtime
FROM debian:bullseye-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
nmap \ # Nmap binary
rustscan \ # RustScan binary
libpcap0.8 \ # Packet capture library
git # For NSE repo cloning
# Copy built scanner binary
COPY --from=builder /repos/app-scanner/scanner /app-scanner-src/scanner
# Create NSE directory
RUN mkdir -p /opt/sirius/nse/sirius-nse
# Symlink Nmap scripts to sirius-nse
RUN ln -sf /opt/sirius/nse/sirius-nse/scripts /usr/local/share/nmap/scripts
```
### Volume Mounts
**Development Mode:**
```yaml
# docker-compose.dev.yaml
services:
sirius-engine:
volumes:
- ../minor-projects/app-scanner:/app-scanner # Live code reload
- ../minor-projects/go-api:/go-api
- ../minor-projects/sirius-nse:/sirius-nse
```
**Production Mode:**
No volume mounts. Uses pre-compiled binary at `/app-scanner-src/scanner`.
### Startup Script
The scanner is started by `start-enhanced.sh`:
```bash
#!/bin/bash
# Development mode: run from source with live reload
if [ "$GO_ENV" = "development" ] && [ -d "/app-scanner" ]; then
echo "Starting scanner in development mode..."
cd /app-scanner
air -c .air.toml & # Live reload with air
fi
# Production mode: run pre-compiled binary
if [ ! "$GO_ENV" = "development" ]; then
echo "Starting scanner in production mode..."
/app-scanner-src/scanner &
fi
# Keep container running
wait
```
### NSE Script Installation
**Automatic on Startup:**
The `SyncManager` automatically clones/updates the `sirius-nse` repository when `ListenForScans()` is called:
```go
func (sm *ScanManager) ListenForScans() {
// Sync NSE scripts before listening
if err := sm.nseSync.Sync(sm.ctx); err != nil {
log.Printf("Warning: failed to sync NSE scripts: %v", err)
// Continue anyway - may use cached scripts
}
queue.Listen("scan", sm.handleMessage)
}
```
**Fallback:** If sync fails, uses existing scripts from `/opt/sirius/nse/sirius-nse`.
### Environment Variables
```bash
# Scanner configuration
SIRIUS_API_URL=http://sirius-api:9001 # API endpoint for results
RABBITMQ_URL=amqp://guest:guest@sirius-rabbitmq:5672/
VALKEY_HOST=sirius-valkey
VALKEY_PORT=6379
# Development settings
GO_ENV=development # Enable dev mode
```
---
## Configuration Files
### manifest.json
**Location:** `/app-scanner/manifest.json`
**Purpose:** Reference to external repositories (sirius-nse).
**Structure:**
```json
{
"repositories": [
{
"name": "sirius-nse",
"url": "https://github.com/SiriusScan/sirius-nse.git"
}
]
}
```
**Usage:** Read by installer scripts or future auto-update mechanisms.
### nmap-args/args.txt
**Location:** `/app-scanner/nmap-args/args.txt` (or `/opt/sirius/nse/sirius-nse/scripts/args.txt`)
**Purpose:** Default arguments for NSE scripts.
**Example Content:**
```
# Vulners script configuration
vulners.showall=false
# HTTP scripts
http.useragent=Sirius Scanner/1.0
# SMB scripts
smbdomain=WORKGROUP
smbusername=guest
smbpassword=
# Timing
timeout=30000
```
**Usage:** Passed to Nmap via `--script-args-file` flag.
**Path Resolution:**
```go
argsFilePaths := []string{
"/opt/sirius/nse/sirius-nse/scripts/args.txt",
"/app-scanner/nmap-args/args.txt",
"/app-scanner-src/nmap-args/args.txt",
"nmap-args/args.txt",
}
// Use first existing file
for _, path := range argsFilePaths {
if _, err := os.Stat(path); err == nil {
argsFilePath = path
break
}
}
```
### .air.toml
**Location:** `/app-scanner/.air.toml`
**Purpose:** Live reload configuration for development.
**Key Settings:**
```toml
[build]
cmd = "go build -o ./tmp/scanner main.go"
bin = "./tmp/scanner"
include_ext = ["go", "tpl", "tmpl", "html"]
exclude_dir = ["tmp", "vendor", "testdata"]
delay = 1000 # 1 second delay before rebuild
[log]
time = true
```
**Usage:** Automatically watches for file changes and rebuilds/restarts scanner.
---
## Development Workflow
### Running Tests
**Unit Tests:**
```bash
cd /app-scanner
go test ./internal/scan/... -v
# Specific test
go test ./internal/scan/ -run TestScanToolFactory -v
# With coverage
go test ./internal/scan/... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
```
**Integration Tests:**
```bash
# Full scan test (requires running infrastructure)
go run cmd/scan-full-test/main.go
```
### Manual Scan Testing
**Test Commands:**
```bash
# Direct Nmap test
cd cmd/direct-nmap-test
go run main.go
# NSE script test
cd cmd/nse-test
go run main.go
# Validate NSE script fixes
cd cmd/validate-nse-fix
go run main.go
```
### Debugging NSE Scripts
**Check Script Availability:**
```bash
docker exec sirius-engine nmap --script-help vulners
```
**Test Script Manually:**
```bash
docker exec sirius-engine nmap -sV --script vulners 192.168.1.100
```
**View NSE Repository:**
```bash
docker exec sirius-engine ls -la /opt/sirius/nse/sirius-nse/scripts/
```
**Check Symlink:**
```bash
docker exec sirius-engine ls -la /usr/local/share/nmap/scripts
# Should point to: /opt/sirius/nse/sirius-nse/scripts
```
### Live Reload Development
**Development Mode:**
1. Edit code in `../minor-projects/app-scanner`
2. Air detects changes and rebuilds
3. Scanner restarts automatically
4. Logs visible in `docker logs -f sirius-engine`
**Watch Logs:**
```bash
# Scanner logs
docker logs -f sirius-engine | grep scanner
# RabbitMQ messages
docker exec sirius-rabbitmq rabbitmqctl list_queues name messages
# ValKey scan state
docker exec sirius-valkey valkey-cli GET scan:scan-abc123
```
### Adding New Scan Strategies
**Step 1: Implement Strategy Interface**
```go
// internal/scan/strategies.go
type MyNewStrategy struct {
CustomOption string
}
func (s *MyNewStrategy) Execute(target string) (sirius.Host, error) {
// Your scanning logic here
return host, nil
}
```
**Step 2: Update Factory**
```go
// internal/scan/factory.go
func (f *ScanToolFactory) CreateTool(toolType string) ScanStrategy {
switch toolType {
case "my-new-tool":
return &MyNewStrategy{
CustomOption: f.currentOptions.SomeOption,
}
// ... existing cases
}
}
```
**Step 3: Add to Scan Types**
Update documentation and UI to include new scan type in `scan_types` options.
**Step 4: Write Tests**
```go
// internal/scan/strategies_test.go
func TestMyNewStrategy(t *testing.T) {
strategy := &MyNewStrategy{CustomOption: "test"}
host, err := strategy.Execute("192.168.1.100")
assert.NoError(t, err)
assert.NotEmpty(t, host.IP)
}
```
### Creating System Templates
**Step 1: Define Template**
```go
// internal/scan/template_manager.go
func (tm *TemplateManager) InitializeSystemTemplates(ctx context.Context) error {
templates := []Template{
// ... existing templates
{
ID: "my-template",
Name: "My Custom Template",
Description: "Description of what this template does",
Type: SystemTemplate,
EnabledScripts: []string{
"script1",
"script2",
},
ScanOptions: TemplateOptions{
ScanTypes: []string{"vulnerability"},
PortRange: "1-1000",
Aggressive: false,
},
},
}
// ... create templates
}
```
**Step 2: Rebuild Scanner**
```bash
cd /app-scanner
go build -o scanner main.go
```
**Step 3: Test Template**
```json
{
"id": "test-scan",
"targets": [{ "value": "192.168.1.100", "type": "single_ip" }],
"options": { "template_id": "my-template" },
"priority": 3
}
```
### Optimizing Scan Performance
**Strategies:**
1. **Adjust Worker Pool Size:**
```go
// internal/scan/manager.go
const DEFAULT_WORKERS = 20 // Increase for more parallelism
```
2. **Reduce Port Range:**
```json
{ "port_range": "1-1000" } // Instead of 1-65535
```
3. **Limit NSE Scripts:**
```json
{ "template_id": "quick" } // Use quick template
```
4. **Enable Parallel Processing:**
```json
{ "parallel": true }
```
5. **Adjust Nmap Timing:**
```go
// modules/nmap/nmap.go
args := []string{
"-T5", // Insane timing (faster but less accurate)
// ...
}
```
---
## Key Files Reference
| File | Lines | Purpose |
| ----------------------------------- | ----- | ------------------------------------------------------------------ |
| `main.go` | 37 | Application entry point, initializes ScanManager |
| `internal/scan/manager.go` | 783 | Core scan orchestration, RabbitMQ listener, worker pool |
| `internal/scan/strategies.go` | 164 | ScanStrategy interface and implementations (Naabu, RustScan, Nmap) |
| `internal/scan/factory.go` | 50 | Strategy factory for creating scan tools |
| `internal/scan/worker_pool.go` | ~150 | Concurrent worker pool for parallel scanning |
| `internal/scan/template_manager.go` | 413 | Template CRUD operations, system template initialization |
| `internal/scan/template_types.go` | ~100 | Template data structures |
| `internal/scan/updater.go` | ~150 | ValKey state update management |
| `internal/scan/logging.go` | ~200 | Structured logging to RabbitMQ |
| `internal/scan/helpers.go` | ~100 | Utility functions (severity calculation, etc.) |
| `internal/scan/network_helpers.go` | ~150 | IP/CIDR expansion, validation |
| `internal/nse/repo.go` | 138 | Git repository management for NSE scripts |
| `internal/nse/sync.go` | ~150 | NSE sync coordination |
| `internal/nse/script_selector.go` | ~200 | Protocol-based NSE script selection |
| `internal/nse/script_blacklist.go` | ~50 | Problematic script exclusion |
| `internal/nse/types.go` | ~100 | NSE data structures (Manifest, Script) |
| `modules/nmap/nmap.go` | 533 | Nmap integration, XML parsing, CVE extraction |
| `modules/rustscan/rustscan.go` | ~150 | RustScan integration |
| `modules/naabu/naabu.go` | ~150 | Naabu integration |
**Total:** ~3,800 lines of application code
---
## Code Examples
### Sending a Scan Request
**From Go:**
```go
scanMsg := ScanMessage{
ID: uuid.New().String(),
Targets: []Target{
{Value: "192.168.1.0/24", Type: CIDR},
},
Options: ScanOptions{
TemplateID: "high-risk",
ScanTypes: []string{"discovery", "vulnerability"},
},
Priority: 4,
}
msgBytes, _ := json.Marshal(scanMsg)
queue.Publish("scan", string(msgBytes))
```
**From CLI (RabbitMQ):**
```bash
rabbitmqadmin publish exchange=amq.default \
routing_key=scan \
payload='{"id":"scan-123","targets":[{"value":"192.168.1.100","type":"single_ip"}],"options":{"template_id":"quick"},"priority":3}'
```
### Monitoring Scan Progress
**ValKey Query:**
```bash
docker exec sirius-valkey valkey-cli GET scan:scan-123
```
**Output:**
```json
{
"status": "running",
"start_time": "2025-10-25T10:30:00Z",
"hosts": ["192.168.1.1", "192.168.1.2", "192.168.1.100"],
"hosts_completed": 2,
"vulnerabilities": [
{
"id": "CVE-2017-0143",
"severity": "critical",
"title": "EternalBlue SMB RCE"
}
]
}
```
---
## Troubleshooting
### NSE Script Errors
**Symptom:** "NSE: failed to initialize the script engine"
**Causes:**
- Script syntax errors
- Missing script dependencies
- Blacklisted scripts referenced
**Solutions:**
1. **Check script exists:**
```bash
docker exec sirius-engine ls /opt/sirius/nse/sirius-nse/scripts/ | grep vulners
```
2. **Test script manually:**
```bash
docker exec sirius-engine nmap --script-help vulners
```
3. **Check blacklist:**
Review `internal/nse/script_blacklist.go`
4. **Force repository sync:**
```bash
docker exec sirius-engine rm -rf /opt/sirius/nse/sirius-nse
docker restart sirius-engine # Will re-clone on startup
```
### Scan Timeouts
**Symptom:** Scans never complete, hosts stuck in "running" status
**Causes:**
- Network unreachability
- Firewall blocking scans
- Extremely large port ranges
**Solutions:**
1. **Reduce port range:**
```json
{ "port_range": "1-1000" } // Instead of 1-65535
```
2. **Enable aggressive mode:**
```json
{ "aggressive": true } // Faster but more detectable
```
3. **Check network connectivity:**
```bash
docker exec sirius-engine ping 192.168.1.100
```
4. **View scanner logs:**
```bash
docker logs -f sirius-engine | grep "ERROR\|Failed"
```
### Memory Issues
**Symptom:** Scanner crashes with OOM (Out of Memory) errors
**Causes:**
- Too many concurrent workers
- Large target ranges without pagination
- Memory leaks in scanning tools
**Solutions:**
1. **Reduce worker pool size:**
```go
const DEFAULT_WORKERS = 5 // Down from 10
```
2. **Scan smaller ranges:**
Split large CIDR blocks into smaller chunks.
3. **Increase Docker memory:**
```yaml
# docker-compose.yaml
services:
sirius-engine:
deploy:
resources:
limits:
memory: 4G # Increase from 2G
```
4. **Monitor memory usage:**
```bash
docker stats sirius-engine
```
### RabbitMQ Disconnections
**Symptom:** "Failed to consume from queue: connection closed"
**Causes:**
- RabbitMQ container crashed
- Network partition
- Connection timeout
**Solutions:**
1. **Check RabbitMQ status:**
```bash
docker exec sirius-rabbitmq rabbitmqctl status
```
2. **Restart RabbitMQ:**
```bash
docker restart sirius-rabbitmq
```
3. **Check connection string:**
```bash
echo $RABBITMQ_URL
# Should be: amqp://guest:guest@sirius-rabbitmq:5672/
```
4. **Implement reconnection logic (future):**
Add automatic reconnection with exponential backoff.
---
## Performance Benchmarks
**Environment:** 4-core CPU, 8GB RAM, 1Gbps network
| Scan Type | Target Range | Duration | Hosts/sec |
| --------------------- | ---------------------- | --------- | --------- |
| Quick (top 500 ports) | /24 subnet (254 hosts) | 3-5 min | ~50-80 |
| High-Risk | /24 subnet | 15-25 min | ~10-15 |
| All Scripts | /24 subnet | 2-4 hours | ~1-2 |
| Quick | Single host | 10-20 sec | N/A |
| High-Risk | Single host | 2-5 min | N/A |
**Optimization Tips:**
- **Parallelism:** Increase worker count for faster subnet scans
- **Port Range:** Limit to relevant ports (80, 443, 22, 3389)
- **Script Selection:** Use templates instead of wildcard `*`
- **Network:** Faster networks = faster scans (avoid VPNs)
---
## Security Considerations
### Responsible Scanning
**Always:**
- ✅ Get written authorization before scanning
- ✅ Use reasonable rate limiting (avoid DoS)
- ✅ Scan only approved IP ranges
- ✅ Document all scanning activities
**Never:**
- ❌ Scan production systems without approval
- ❌ Use aggressive mode on fragile systems
- ❌ Store vulnerability data in insecure locations
- ❌ Share scan results with unauthorized parties
### Rate Limiting
The scanner implements implicit rate limiting through:
- **Worker Pool Size:** Limits concurrent scans
- **Nmap Timing:** `-T4` (balanced) by default, not `-T5` (insane)
- **Connection Limits:** Naabu respects system limits
**Future Enhancements:**
- Configurable rate limits (scans per second)
- Per-target rate limiting
- Adaptive throttling based on network conditions
---
## Future Enhancements
**Planned Features:**
1. **DNS Wildcard Support:** Subdomain enumeration via CT logs
2. **Distributed Scanning:** Multiple scanner instances coordinating via ValKey
3. **Scan Scheduling:** Cron-based recurring scans
4. **Advanced Reporting:** PDF/HTML reports with executive summaries
5. **Machine Learning:** Anomaly detection for unusual scan results
6. **API Gateway Integration:** Direct scan triggering via REST API
7. **WebSocket Updates:** Real-time scan progress in UI
8. **Scan Comparison:** Diff scans to identify new vulnerabilities
---
## ValKey Schema Reference
ValKey (Redis-compatible) is used for live scan state. Key structure:
- **`currentScan`** – Main key storing the live scan result as JSON. Contains the full `ScanResult` object with hosts, vulnerabilities, sub-scans, and progress.
- **Encoding:** JSON may be stored as a base64-encoded string in some contexts; decode with `b64Decode` from `~/utils/std.ts` when reading from the frontend.
- **Polling:** The frontend polls this key at regular intervals (5-second refetch) to display live progress.
- **TTL:** No TTL is set; the key persists until overwritten by the next scan.
---
## Profile vs Template System
- **Scan Profiles:** High-level presets that control overall scan behavior (e.g., "quick-scan", "full-scan", "agent-only"). Stored as `ScanProfile` type. They determine which scan methods are enabled and how they are configured.
- **Agent Templates:** Specific detection templates used by the agent scanner (e.g., checks for a specific CVE). Stored in the template system. They define detection steps such as `file_content`, `file_hash`, `file_search`, and `version_cmd`. The authoritative set is `KnownDetectionTypes` in `app-agent/internal/modules/detection_types.go` (drift-checked against the runtime registry by `detection_types_registry_test.go`).
- Profiles may reference templates but are not the same thing: profiles define *what* to run and *how*; templates define the concrete detection logic.
---
## RabbitMQ Message Schema
- **Queue:** Scan queue (consumed by app-scanner).
- **Message format:** JSON with target list and scan options.
- **Scan request contents:** Includes `targets`, `scan_types` configuration, and `agent_scan` configuration.
- **Results:** app-scanner writes results back to the ValKey `currentScan` key.
---
## LLM Context
This documentation is optimized for AI assistant context. Key information:
**Architecture:** Message-driven (RabbitMQ), worker pool concurrency, strategy pattern for extensibility
**Core Flow:** Receive scan message → Expand targets → Distribute to workers → Execute strategies → Enrich results → Submit to API
**Key Components:** ScanManager (orchestration), ScanStrategies (tool integrations), TemplateManager (scan configs), NSE system (script management)
**Integration Points:** RabbitMQ (input), ValKey (state), PostgreSQL (results), NVD API (CVE enrichment)
**Development:** Go 1.23+, runs in sirius-engine container, live reload with Air, unit/integration tests
**Common Tasks:** Add strategies (implement interface + factory), create templates (InitializeSystemTemplates), debug NSE (check symlinks/manifest)
---
**Last Updated:** 2025-10-25
**Version:** 1.0.0
**Maintainer:** Sirius Team
**Repository:** https://github.com/SiriusScan/app-scanner