Documentation
¶
Overview ¶
Package scanning provides core network scanning functionality for Scanorama.
This package contains the essential scanning engine that powers Scanorama's network discovery and port scanning capabilities. It handles scan execution, result processing, XML parsing, and provides the core data structures used throughout the application.
Overview ¶
The scanning package is built around the ScanConfig structure which defines scan parameters, and the ScanResult structure which contains scan outcomes. The main entry points are RunScanWithContext and RunScanWithDB functions that execute scans with different database integration levels.
Main Components ¶
## Scan Execution
The core scanning functionality is provided through:
- ScanConfig: Configuration structure defining scan parameters
- RunScanWithContext: Execute scans with context and optional database
- RunScanWithDB: Execute scans with database integration
- PrintResults: Display scan results in human-readable format
## Result Processing
Scan results are processed and structured through:
- ScanResult: Main result structure containing discovered hosts and services
- Host: Individual host information including open ports and services
- Port: Port-specific information including state and service details
- Service: Service identification and version information
## XML Processing
Nmap XML output parsing is handled by:
- NmapRun: Root structure for parsing nmap XML output
- NmapHost: Host-specific data from nmap scans
- NmapPort: Port-specific data from nmap scans
- ParseNmapXML: Parse nmap XML output into structured data
Usage Examples ¶
## Basic Scan
config := &scanning.ScanConfig{
Targets: []string{"192.168.1.1/24"},
Ports: "80,443,22",
ScanType: "syn",
Timeout: 300,
Concurrency: 10,
}
ctx := context.Background()
result, err := scanning.RunScanWithContext(ctx, config, nil)
if err != nil {
log.Fatal(err)
}
scanning.PrintResults(result)
## Database-Integrated Scan
db, err := db.NewDB(dbConfig)
if err != nil {
log.Fatal(err)
}
config := &scanning.ScanConfig{
Targets: []string{"10.0.0.0/8"},
Ports: "1-1000",
ScanType: "connect",
Timeout: 600,
Concurrency: 50,
}
result, err := scanning.RunScanWithDB(config, db)
if err != nil {
log.Fatal(err)
}
// Results are automatically stored in the database
## XML Parsing
xmlData, err := os.ReadFile("scan_results.xml")
if err != nil {
log.Fatal(err)
}
nmapResult, err := scanning.ParseNmapXML(xmlData)
if err != nil {
log.Fatal(err)
}
// Process structured nmap data
for _, host := range nmapResult.Hosts {
fmt.Printf("Host: %s\n", host.Address.Addr)
for _, port := range host.Ports.Ports {
if port.State.State == "open" {
fmt.Printf(" Port %d/%s: %s\n",
port.PortID, port.Protocol, port.State.State)
}
}
}
Configuration Options ¶
ScanConfig supports various scanning modes and options:
- Targets: IP addresses, ranges, or hostnames to scan
- Ports: Port specifications (ranges, lists, or named services)
- ScanType: Scan technique (syn, connect, udp, etc.)
- Timeout: Maximum scan duration in seconds
- Concurrency: Number of parallel scanning threads
- Rate: Packets per second limit
- HostTimeout: Per-host timeout in seconds
Scan Types ¶
Supported scan types include:
- "syn": TCP SYN scan (default, requires privileges)
- "connect": TCP connect scan (no privileges required)
- "udp": UDP scan
- "ping": Host discovery only
- "ack": TCP ACK scan
- "window": TCP Window scan
- "maimon": TCP Maimon scan
Error Handling ¶
All functions return descriptive errors that can be used for:
- User feedback in CLI applications
- API error responses in web services
- Logging and monitoring in daemon processes
Common error scenarios include:
- Invalid target specifications
- Network connectivity issues
- Permission errors (for privileged scans)
- Timeout errors for long-running scans
- Database connection failures (for DB-integrated scans)
Thread Safety ¶
The scanning package is designed to be thread-safe:
- Multiple scans can run concurrently
- ScanConfig and result structures are immutable after creation
- Database operations use connection pooling
- Context cancellation is properly handled
Performance Considerations ¶
For optimal performance:
- Use appropriate concurrency levels based on target network capacity
- Set reasonable timeouts to avoid hanging scans
- Consider rate limiting for large networks
- Use database integration for persistent storage of large result sets
- Monitor memory usage for very large scans
Integration ¶
This package integrates with other Scanorama components:
- internal/db: Database storage and retrieval of scan results
- internal/discovery: Network discovery and host enumeration
- internal/daemon: Background scanning services
- internal/api: REST API endpoints for scan management
- internal/scheduler: Automated scanning workflows
Package scanning provides core scanning functionality and shared types for scanorama. This file defines the Job interface and its concrete scan implementation so that the ScanQueue can execute any type of work — scans, discovery, or future job types — through a single unified worker pool.
Package scanning provides core scanning functionality and shared types for scanorama. This file implements a bounded job execution queue that prevents resource exhaustion when many scans or discovery jobs are requested concurrently. Jobs are enqueued into a FIFO buffer and executed by a fixed-size worker pool.
Package scanning provides core scanning functionality and shared types for scanorama. It contains scan execution logic, result processing, XML handling, and common data structures used throughout the application.
Index ¶
- Constants
- Variables
- func CalculateTimeout(ports string, targetCount int, scanType string) int
- func PrintResults(result *ScanResult)
- func SaveResults(result *ScanResult, filePath string) error
- type ExecError
- type FixedResourceManager
- func (rm *FixedResourceManager) Acquire(ctx context.Context, scanID string) error
- func (rm *FixedResourceManager) Close() error
- func (rm *FixedResourceManager) GetActiveScans() int
- func (rm *FixedResourceManager) GetAvailableSlots() int
- func (rm *FixedResourceManager) GetStats() map[string]interface{}
- func (rm *FixedResourceManager) IsHealthy() bool
- func (rm *FixedResourceManager) Release(scanID string)
- type Host
- type HostStats
- type HostXML
- type Job
- type Port
- type PortXML
- type QueueStats
- type ResourceManager
- type ScanConfig
- type ScanJob
- type ScanJobExecutor
- type ScanQueue
- type ScanResult
- func LoadResults(filePath string) (*ScanResult, error)
- func NewScanResult() *ScanResult
- func RunScan(config *ScanConfig) (*ScanResult, error)
- func RunScanWithContext(ctx context.Context, config *ScanConfig, database *db.DB) (*ScanResult, error)
- func RunScanWithDB(config *ScanConfig, database *db.DB) (*ScanResult, error)
- type ScanXML
- type WorkerSnapshot
Constants ¶
const ( DefaultMaxConcurrent = 5 DefaultMaxQueueSize = 50 )
Default queue configuration values.
Variables ¶
var ( ErrQueueFull = errors.New("scan queue is full") ErrQueueClosed = errors.New("scan queue is closed") )
Sentinel errors for queue operations.
Functions ¶
func CalculateTimeout ¶ added in v0.17.0
CalculateTimeout estimates a reasonable scan timeout based on the number of ports, targets, and scan type.
Baseline: 1 second per port per target for TCP connect. UDP is ~4× slower due to retransmits and lack of RST responses. A floor of minTimeoutSeconds and a ceiling of 1 hour are applied.
func PrintResults ¶
func PrintResults(result *ScanResult)
PrintResults displays scan results in a human-readable format on stdout. The output includes host status, open ports, and detected services.
func SaveResults ¶
func SaveResults(result *ScanResult, filePath string) error
SaveResults writes scan results to an XML file at the specified path. The output is formatted with proper indentation for readability.
Types ¶
type ExecError ¶ added in v0.18.0
type ExecError struct {
Op string // Operation that failed
Err error // Original error
Host string // Host where the error occurred, if applicable
Port uint16 // Port where the error occurred, if applicable
}
ExecError represents error types for scan operations.
type FixedResourceManager ¶ added in v0.12.0
type FixedResourceManager struct {
// contains filtered or unexported fields
}
FixedResourceManager implements ResourceManager with a fixed number of resource slots.
func NewFixedResourceManager ¶ added in v0.12.0
func NewFixedResourceManager(capacity int) *FixedResourceManager
NewFixedResourceManager creates a new resource manager with the specified capacity.
func (*FixedResourceManager) Acquire ¶ added in v0.12.0
func (rm *FixedResourceManager) Acquire(ctx context.Context, scanID string) error
Acquire attempts to acquire a resource slot for the given scan ID.
func (*FixedResourceManager) Close ¶ added in v0.12.0
func (rm *FixedResourceManager) Close() error
Close gracefully shuts down the resource manager.
func (*FixedResourceManager) GetActiveScans ¶ added in v0.12.0
func (rm *FixedResourceManager) GetActiveScans() int
GetActiveScans returns the current number of active scans.
func (*FixedResourceManager) GetAvailableSlots ¶ added in v0.12.0
func (rm *FixedResourceManager) GetAvailableSlots() int
GetAvailableSlots returns the number of available resource slots.
func (*FixedResourceManager) GetStats ¶ added in v0.12.0
func (rm *FixedResourceManager) GetStats() map[string]interface{}
GetStats returns statistics about the resource manager.
func (*FixedResourceManager) IsHealthy ¶ added in v0.12.0
func (rm *FixedResourceManager) IsHealthy() bool
IsHealthy returns true if the resource manager is operating normally.
func (*FixedResourceManager) Release ¶ added in v0.12.0
func (rm *FixedResourceManager) Release(scanID string)
Release releases the resource slot for the given scan ID.
type Host ¶
type Host struct {
// Address is the IP address or hostname of the scanned host
Address string
// Status indicates whether the host is "up" or "down"
Status string
// Ports contains information about all scanned ports
Ports []Port
// OSName is the detected operating system name, if available
OSName string
// OSFamily is the detected operating system family (e.g. "Linux", "Windows")
OSFamily string
// OSVersion is the detected operating system version, if available
OSVersion string
// OSAccuracy is the confidence percentage (0-100) of the OS detection
OSAccuracy int
}
Host represents a scanned host and its findings.
type HostStats ¶
type HostStats struct {
// Up is the number of hosts that were up
Up int
// Down is the number of hosts that were down
Down int
// Total is the total number of hosts scanned
Total int
}
HostStats contains summary statistics about a network scan.
type HostXML ¶
type HostXML struct {
Address string `xml:"Address"`
Status string `xml:"Status"`
Ports []PortXML `xml:"Ports,omitempty"`
}
HostXML represents a scanned host for XML serialization. It contains the host's address, status, and discovered ports.
type Job ¶ added in v0.22.0
type Job interface {
// ID returns a stable identifier used for logging and deduplication.
ID() string
// Type returns the job category shown in the admin worker view (e.g. "scan", "discovery").
Type() string
// Target returns a human-readable description of the work target,
// shown in the admin worker view (e.g. "192.168.1.0/24").
Target() string
// Execute runs the job to completion, respecting ctx for cancellation.
Execute(ctx context.Context) error
}
Job is implemented by any unit of work the ScanQueue can execute. Both scan and discovery jobs implement this interface, allowing them to share the same worker pool and appear uniformly in the admin worker view.
type Port ¶
type Port struct {
// Number is the port number (1-65535)
Number uint16
// Protocol is the transport protocol ("tcp" or "udp")
Protocol string
// State indicates whether the port is "open", "closed", or "filtered"
State string
// Service is the name of the detected service, if any
Service string
// Version is the version of the detected service, if available
Version string
// ServiceInfo contains additional service details, if available
ServiceInfo string
}
Port represents the scan results for a single port.
type PortXML ¶
type PortXML struct {
Number uint16 `xml:"Number"`
Protocol string `xml:"Protocol"`
State string `xml:"State"`
Service string `xml:"Service"`
Version string `xml:"Version,omitempty"`
ServiceInfo string `xml:"ServiceInfo,omitempty"`
}
PortXML represents a scanned port for XML serialization. It includes the port number, protocol, state, and service information.
type QueueStats ¶ added in v0.13.0
type QueueStats struct {
// QueueDepth is the number of scan requests currently waiting in the queue.
QueueDepth int
// ActiveScans is the number of scans currently being executed by workers.
ActiveScans int
// MaxConcurrent is the maximum number of simultaneous scans.
MaxConcurrent int
// MaxQueueSize is the maximum number of pending scan requests.
MaxQueueSize int
// TotalSubmitted is the total number of scan requests submitted.
TotalSubmitted int64
// TotalCompleted is the total number of scans completed successfully.
TotalCompleted int64
// TotalRejected is the total number of scan requests rejected (queue full or closed).
TotalRejected int64
// TotalFailed is the total number of scans that failed with an error.
TotalFailed int64
}
QueueStats provides a snapshot of the current queue state.
type ResourceManager ¶ added in v0.12.0
type ResourceManager interface {
// Acquire attempts to acquire a resource slot for the given scan ID.
// It blocks until a slot is available or the context is cancelled.
Acquire(ctx context.Context, scanID string) error
// Release releases the resource slot for the given scan ID.
Release(scanID string)
// GetActiveScans returns the current number of active scans.
GetActiveScans() int
// GetAvailableSlots returns the number of available resource slots.
GetAvailableSlots() int
// IsHealthy returns true if the resource manager is operating normally.
IsHealthy() bool
// Close gracefully shuts down the resource manager.
Close() error
}
ResourceManager manages scan resources and concurrency limits.
type ScanConfig ¶
type ScanConfig struct {
// Targets is a list of targets to scan (IPs, hostnames, CIDR ranges)
Targets []string
// Ports specifies which ports to scan (e.g., "80,443" or "1-1000")
Ports string
// ScanType determines the type of scan: "connect", "syn", "ack", "udp", "aggressive", or "comprehensive"
ScanType string
// Timing sets the nmap timing template explicitly: "paranoid", "polite", "normal", "aggressive", "insane".
// When set, this takes precedence over any timing derived from TimeoutSec.
Timing string
// OSDetection enables nmap OS fingerprinting (-O)
OSDetection bool
// TimeoutSec specifies scan timeout in seconds (0 = default timeout)
TimeoutSec int
// Concurrency specifies the number of concurrent scans (0 = auto)
Concurrency int
// RetryCount specifies the number of retry attempts for failed scans
RetryCount int
// RetryDelay specifies the delay between retries
RetryDelay time.Duration
// ScanID is the UUID of the existing scan_jobs row that triggered this scan.
// When set, storeScanResults reuses this ID so that port_scans rows are
// linked to the same UUID exposed to the API client via GetScanResults.
// When nil a fresh UUID is generated (CLI / legacy path).
ScanID *uuid.UUID
}
ScanConfig represents the configuration for a network scan.
func (*ScanConfig) Validate ¶
func (c *ScanConfig) Validate() error
Validate checks if the scan configuration is valid.
type ScanJob ¶ added in v0.22.0
type ScanJob struct {
// contains filtered or unexported fields
}
ScanJob implements Job for nmap port-scan operations.
func NewScanJob ¶ added in v0.22.0
func NewScanJob( id string, cfg *ScanConfig, database *db.DB, executor ScanJobExecutor, onDone func(*ScanResult, error), ) *ScanJob
NewScanJob constructs a ScanJob ready for submission to a ScanQueue. executor is called to perform the actual nmap scan; onDone is invoked with the outcome (result may be nil on error) when execution finishes.
type ScanJobExecutor ¶ added in v0.22.0
type ScanJobExecutor func(ctx context.Context, cfg *ScanConfig, database *db.DB) (*ScanResult, error)
ScanJobExecutor is the function signature for the underlying nmap scan runner. RunScanWithContext is used in production; tests inject a lightweight stub.
type ScanQueue ¶ added in v0.13.0
type ScanQueue struct {
// contains filtered or unexported fields
}
ScanQueue manages a bounded worker pool for job execution. It uses a buffered channel as a FIFO queue and spawns a configurable number of worker goroutines to process jobs concurrently. Both scan and discovery jobs implement the Job interface and can be submitted.
func NewScanQueue ¶ added in v0.13.0
NewScanQueue creates a new ScanQueue with the specified concurrency and queue size limits. If maxConcurrent <= 0, DefaultMaxConcurrent is used. If maxQueueSize <= 0, DefaultMaxQueueSize is used.
func (*ScanQueue) Snapshot ¶ added in v0.22.0
func (q *ScanQueue) Snapshot() []WorkerSnapshot
Snapshot returns a point-in-time view of all worker states. It is safe to call concurrently with ongoing scan execution.
func (*ScanQueue) Start ¶ added in v0.13.0
Start launches the worker goroutines that process scan requests from the queue. The provided context controls the lifecycle of all workers. When the context is cancelled, workers will finish their current scan and exit. Start must only be called once.
func (*ScanQueue) Stats ¶ added in v0.13.0
func (q *ScanQueue) Stats() QueueStats
Stats returns a snapshot of the current queue statistics. All counters are read atomically and are safe for concurrent access.
func (*ScanQueue) Stop ¶ added in v0.13.0
func (q *ScanQueue) Stop()
Stop performs a graceful shutdown of the scan queue. It marks the queue as closed (rejecting new submissions), cancels the worker context, and waits for all in-flight scans to complete. Stop is safe to call multiple times; subsequent calls are no-ops.
func (*ScanQueue) Submit ¶ added in v0.13.0
Submit enqueues a scan request for execution by the worker pool. It returns ErrQueueClosed if the queue has been shut down, or ErrQueueFull if the queue is at capacity. Submit is non-blocking. Submit enqueues a job for execution by the worker pool. It returns ErrQueueClosed if the queue has been shut down, or ErrQueueFull if the queue is at capacity. Submit is non-blocking.
type ScanResult ¶
type ScanResult struct {
// Hosts contains all scanned hosts and their findings
Hosts []Host
// Stats contains summary statistics about the scan
Stats HostStats
// StartTime is when the scan started
StartTime time.Time
// EndTime is when the scan completed
EndTime time.Time
// Duration is how long the scan took
Duration time.Duration
// Error is any error that occurred during the scan
Error error
}
ScanResult contains the complete results of a network scan.
func LoadResults ¶
func LoadResults(filePath string) (*ScanResult, error)
LoadResults reads and parses scan results from an XML file. It returns the parsed results or an error if the file cannot be read or parsed.
func NewScanResult ¶
func NewScanResult() *ScanResult
NewScanResult creates a new scan result with the current time as start time.
func RunScan ¶
func RunScan(config *ScanConfig) (*ScanResult, error)
func RunScanWithContext ¶
func RunScanWithContext(ctx context.Context, config *ScanConfig, database *db.DB) (*ScanResult, error)
RunScanWithContext performs a network scan based on the provided configuration and context. It uses nmap to scan the specified targets and ports, returning detailed results about discovered hosts and services. If database is provided, results are stored.
func RunScanWithDB ¶
func RunScanWithDB(config *ScanConfig, database *db.DB) (*ScanResult, error)
RunScanWithDB is a convenience wrapper that includes database storage.
func (*ScanResult) Complete ¶
func (r *ScanResult) Complete()
Complete marks the scan as complete and calculates duration.
type ScanXML ¶
type ScanXML struct {
XMLName xml.Name `xml:"scanresult"`
Hosts []HostXML `xml:"host"`
StartTime string `xml:"start_time,attr"`
EndTime string `xml:"end_time,attr"`
Duration string `xml:"duration,attr"`
}
ScanXML is the root element for XML serialization of scan results.
type WorkerSnapshot ¶ added in v0.22.0
type WorkerSnapshot struct {
// ID is the worker identifier (e.g. "worker-0").
ID string
// Status is "idle" or "active".
Status string
// JobID is the ID of the job currently being processed; empty when idle.
JobID string
// JobType is the type of the current job (e.g. "scan"); empty when idle.
JobType string
// JobTarget is the scan target of the current job; empty when idle.
JobTarget string
// JobStartedAt is when the current job started; nil when idle.
JobStartedAt *time.Time
// WorkerStartedAt is when this worker goroutine was started.
WorkerStartedAt time.Time
// LastJobAt is when this worker last completed a job; zero if never.
LastJobAt time.Time
// JobsDone is the number of jobs this worker has completed successfully.
JobsDone int64
// JobsFailed is the number of jobs this worker has failed.
JobsFailed int64
}
WorkerSnapshot is a point-in-time, read-only view of a single worker's state.