From a08af0a27c1f1f20d802c432f9ef55b02a8857cd Mon Sep 17 00:00:00 2001 From: Michael Freeman Date: Sun, 19 Jan 2025 23:21:48 -0600 Subject: [PATCH] adding models pkg --- pkg/agent/errors.go | 12 ++++++ pkg/agent/server.go | 13 +----- pkg/agent/sweep_service.go | 31 +++++++------- pkg/models/sweeper.go | 74 +++++++++++++++++++++++++++++++++ pkg/poller/poller.go | 3 +- pkg/poller/types.go | 15 ------- pkg/sweeper/combined_scanner.go | 24 ++++++----- pkg/sweeper/icmp_scanner.go | 23 +++++----- pkg/sweeper/interfaces.go | 61 ++++----------------------- pkg/sweeper/memory_store.go | 32 +++++++------- pkg/sweeper/result_processor.go | 8 ++-- pkg/sweeper/sqlite_store.go | 12 +++--- pkg/sweeper/sweeper.go | 40 ++++++++++-------- pkg/sweeper/tcp_scanner.go | 14 ++++--- pkg/sweeper/utils.go | 11 ----- 15 files changed, 199 insertions(+), 174 deletions(-) create mode 100644 pkg/agent/errors.go create mode 100644 pkg/models/sweeper.go diff --git a/pkg/agent/errors.go b/pkg/agent/errors.go new file mode 100644 index 0000000..1931372 --- /dev/null +++ b/pkg/agent/errors.go @@ -0,0 +1,12 @@ +package agent + +import "errors" + +var ( + errGrpcAddressRequired = errors.New("address is required for gRPC checker") + errUnknownCheckerType = errors.New("unknown checker type") + errGrpcMissingConfig = errors.New("no configuration or address provided for gRPC checker") + errNoLocalConfig = errors.New("no local config found") + errShutdown = errors.New("error while shutting down") + errServiceStartup = errors.New("error while starting services") +) diff --git a/pkg/agent/server.go b/pkg/agent/server.go index f99313b..a34c746 100644 --- a/pkg/agent/server.go +++ b/pkg/agent/server.go @@ -13,7 +13,7 @@ import ( "time" "github.com/mfreeman451/serviceradar/pkg/checker" - "github.com/mfreeman451/serviceradar/pkg/sweeper" + "github.com/mfreeman451/serviceradar/pkg/models" "github.com/mfreeman451/serviceradar/proto" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -25,15 +25,6 @@ const ( processConfigurationName = "process" ) -var ( - errGrpcAddressRequired = errors.New("address is required for gRPC checker") - errUnknownCheckerType = errors.New("unknown checker type") - errGrpcMissingConfig = errors.New("no configuration or address provided for gRPC checker") - errNoLocalConfig = errors.New("no local config found") - errShutdown = errors.New("error while shutting down") - errServiceStartup = errors.New("error while starting services") -) - type Duration time.Duration // SweepConfig represents sweep service configuration from JSON. @@ -153,7 +144,7 @@ func loadSweepService(configDir string) (Service, error) { } // Convert to sweeper.Config - config := &sweeper.Config{ + config := &models.Config{ Networks: sweepConfig.Networks, Ports: sweepConfig.Ports, Interval: time.Duration(sweepConfig.Interval), diff --git a/pkg/agent/sweep_service.go b/pkg/agent/sweep_service.go index f956bbb..2d3542e 100644 --- a/pkg/agent/sweep_service.go +++ b/pkg/agent/sweep_service.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/mfreeman451/serviceradar/pkg/models" "github.com/mfreeman451/serviceradar/pkg/sweeper" "github.com/mfreeman451/serviceradar/proto" ) @@ -20,11 +21,11 @@ type SweepService struct { processor sweeper.ResultProcessor mu sync.RWMutex closed chan struct{} - config *sweeper.Config + config *models.Config } // NewSweepService creates a new sweep service with default configuration. -func NewSweepService(config *sweeper.Config) (*SweepService, error) { +func NewSweepService(config *models.Config) (*SweepService, error) { // Apply default configuration config = applyDefaultConfig(config) @@ -44,12 +45,12 @@ func NewSweepService(config *sweeper.Config) (*SweepService, error) { }, nil } -func applyDefaultConfig(config *sweeper.Config) *sweeper.Config { +func applyDefaultConfig(config *models.Config) *models.Config { // Ensure we have default sweep modes if len(config.SweepModes) == 0 { - config.SweepModes = []sweeper.SweepMode{ - sweeper.ModeTCP, - sweeper.ModeICMP, + config.SweepModes = []models.SweepMode{ + models.ModeTCP, + models.ModeICMP, } } @@ -200,7 +201,7 @@ func (s *SweepService) GetStatus(_ context.Context) (*proto.StatusResponse, erro } // UpdateConfig updates the sweep configuration. -func (s *SweepService) UpdateConfig(config *sweeper.Config) error { +func (s *SweepService) UpdateConfig(config *models.Config) error { s.mu.Lock() defer s.mu.Unlock() @@ -216,8 +217,8 @@ func (s *SweepService) Close() error { return s.Stop() } -func generateTargets(config *sweeper.Config) ([]sweeper.Target, error) { - var targets []sweeper.Target +func generateTargets(config *models.Config) ([]models.Target, error) { + var targets []models.Target // For each network for _, network := range config.Networks { @@ -230,20 +231,20 @@ func generateTargets(config *sweeper.Config) ([]sweeper.Target, error) { // For each IP, create appropriate targets for _, ip := range ips { // Add ICMP target if enabled - if sweeper.ContainsMode(config.SweepModes, sweeper.ModeICMP) { - targets = append(targets, sweeper.Target{ + if models.ContainsMode(config.SweepModes, models.ModeICMP) { + targets = append(targets, models.Target{ Host: ip.String(), - Mode: sweeper.ModeICMP, + Mode: models.ModeICMP, }) } // Add TCP targets if enabled - if sweeper.ContainsMode(config.SweepModes, sweeper.ModeTCP) { + if models.ContainsMode(config.SweepModes, models.ModeTCP) { for _, port := range config.Ports { - targets = append(targets, sweeper.Target{ + targets = append(targets, models.Target{ Host: ip.String(), Port: port, - Mode: sweeper.ModeTCP, + Mode: models.ModeTCP, }) } } diff --git a/pkg/models/sweeper.go b/pkg/models/sweeper.go new file mode 100644 index 0000000..ece22ed --- /dev/null +++ b/pkg/models/sweeper.go @@ -0,0 +1,74 @@ +package models + +import "time" + +// SweepData represents network sweep results. +type SweepData struct { + Network string `json:"network"` + TotalHosts int32 `json:"total_hosts"` + AvailableHosts int32 `json:"available_hosts"` + LastSweep int64 `json:"last_sweep"` + Ports []PortStatus `json:"ports"` +} + +// PortStatus represents port availability information. +type PortStatus struct { + Port int32 `json:"port"` + Available int32 `json:"available"` +} + +// Config defines sweeper configuration. +type Config struct { + Networks []string `json:"networks"` + Ports []int `json:"ports"` + SweepModes []SweepMode `json:"sweep_modes"` + Interval time.Duration `json:"interval"` + Concurrency int `json:"concurrency"` + Timeout time.Duration `json:"timeout"` + ICMPCount int `json:"icmp_count"` +} + +type SweepMode string + +const ( + ModeTCP SweepMode = "tcp" + ModeICMP SweepMode = "icmp" +) + +// Target represents a network target to be scanned. +type Target struct { + Host string + Port int + Mode SweepMode +} + +// Result represents the outcome of a sweep against a target. +type Result struct { + Target Target + Available bool + FirstSeen time.Time + LastSeen time.Time + RespTime time.Duration + PacketLoss float64 + Error error +} + +// ResultFilter defines criteria for retrieving results. +type ResultFilter struct { + Host string + Port int + StartTime time.Time + EndTime time.Time + Available *bool +} + +// ContainsMode checks if a mode is in a list of modes. +func ContainsMode(modes []SweepMode, mode SweepMode) bool { + for _, m := range modes { + if m == mode { + return true + } + } + + return false +} diff --git a/pkg/poller/poller.go b/pkg/poller/poller.go index e9d00cf..1987e9f 100644 --- a/pkg/poller/poller.go +++ b/pkg/poller/poller.go @@ -11,6 +11,7 @@ import ( "time" "github.com/mfreeman451/serviceradar/pkg/grpc" + "github.com/mfreeman451/serviceradar/pkg/models" "github.com/mfreeman451/serviceradar/proto" ) @@ -75,7 +76,7 @@ func (p *Poller) ensureAgentHealth(ctx context.Context, agentName string, config // processSweepStatus handles sweep status processing. func (*Poller) processSweepStatus(status *proto.ServiceStatus) error { - var sweepData SweepData + var sweepData models.SweepData if err := json.Unmarshal([]byte(status.Message), &sweepData); err != nil { return fmt.Errorf("failed to parse sweep data: %w", err) } diff --git a/pkg/poller/types.go b/pkg/poller/types.go index 4404112..dd8246d 100644 --- a/pkg/poller/types.go +++ b/pkg/poller/types.go @@ -37,21 +37,6 @@ type Poller struct { agents map[string]*AgentConnection } -// SweepData represents network sweep results. -type SweepData struct { - Network string `json:"network"` - TotalHosts int32 `json:"total_hosts"` - AvailableHosts int32 `json:"available_hosts"` - LastSweep int64 `json:"last_sweep"` - Ports []PortStatus `json:"ports"` -} - -// PortStatus represents port availability information. -type PortStatus struct { - Port int32 `json:"port"` - Available int32 `json:"available"` -} - // Duration is a wrapper around time.Duration for JSON unmarshaling. type Duration time.Duration diff --git a/pkg/sweeper/combined_scanner.go b/pkg/sweeper/combined_scanner.go index 7adcf2c..a4e4661 100644 --- a/pkg/sweeper/combined_scanner.go +++ b/pkg/sweeper/combined_scanner.go @@ -5,6 +5,8 @@ import ( "log" "sync" "time" + + "github.com/mfreeman451/serviceradar/pkg/models" ) type CombinedScanner struct { @@ -30,12 +32,12 @@ func (s *CombinedScanner) Stop() error { } type scanTargets struct { - tcp []Target - icmp []Target + tcp []models.Target + icmp []models.Target } -func (s *CombinedScanner) Scan(ctx context.Context, targets []Target) (<-chan Result, error) { - results := make(chan Result) +func (s *CombinedScanner) Scan(ctx context.Context, targets []models.Target) (<-chan models.Result, error) { + results := make(chan models.Result) separated := s.separateTargets(targets) var wg sync.WaitGroup @@ -50,14 +52,14 @@ func (s *CombinedScanner) Scan(ctx context.Context, targets []Target) (<-chan Re return results, nil } -func (*CombinedScanner) separateTargets(targets []Target) scanTargets { +func (*CombinedScanner) separateTargets(targets []models.Target) scanTargets { var separated scanTargets for _, target := range targets { switch target.Mode { - case ModeTCP: + case models.ModeTCP: separated.tcp = append(separated.tcp, target) - case ModeICMP: + case models.ModeICMP: separated.icmp = append(separated.icmp, target) default: log.Printf("Unknown scan mode for target %v: %v", target, target.Mode) @@ -67,7 +69,7 @@ func (*CombinedScanner) separateTargets(targets []Target) scanTargets { return separated } -func (s *CombinedScanner) startScanners(ctx context.Context, wg *sync.WaitGroup, targets scanTargets, results chan<- Result) { +func (s *CombinedScanner) startScanners(ctx context.Context, wg *sync.WaitGroup, targets scanTargets, results chan<- models.Result) { if len(targets.tcp) > 0 { wg.Add(1) @@ -81,7 +83,7 @@ func (s *CombinedScanner) startScanners(ctx context.Context, wg *sync.WaitGroup, } } -func (s *CombinedScanner) runTCPScanner(ctx context.Context, wg *sync.WaitGroup, targets []Target, results chan<- Result) { +func (s *CombinedScanner) runTCPScanner(ctx context.Context, wg *sync.WaitGroup, targets []models.Target, results chan<- models.Result) { defer wg.Done() tcpResults, err := s.tcpScanner.Scan(ctx, targets) @@ -93,7 +95,7 @@ func (s *CombinedScanner) runTCPScanner(ctx context.Context, wg *sync.WaitGroup, s.processResults(ctx, tcpResults, results) } -func (s *CombinedScanner) runICMPScanner(ctx context.Context, wg *sync.WaitGroup, targets []Target, results chan<- Result) { +func (s *CombinedScanner) runICMPScanner(ctx context.Context, wg *sync.WaitGroup, targets []models.Target, results chan<- models.Result) { defer wg.Done() icmpResults, err := s.icmpScanner.Scan(ctx, targets) @@ -105,7 +107,7 @@ func (s *CombinedScanner) runICMPScanner(ctx context.Context, wg *sync.WaitGroup s.processResults(ctx, icmpResults, results) } -func (s *CombinedScanner) processResults(ctx context.Context, scanResults <-chan Result, results chan<- Result) { +func (s *CombinedScanner) processResults(ctx context.Context, scanResults <-chan models.Result, results chan<- models.Result) { for result := range scanResults { select { case <-ctx.Done(): diff --git a/pkg/sweeper/icmp_scanner.go b/pkg/sweeper/icmp_scanner.go index 5cbea77..560f5e5 100644 --- a/pkg/sweeper/icmp_scanner.go +++ b/pkg/sweeper/icmp_scanner.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "github.com/mfreeman451/serviceradar/pkg/models" "golang.org/x/net/icmp" "golang.org/x/net/ipv4" ) @@ -30,7 +31,7 @@ type ICMPScanner struct { type ICMPWorkerConfig struct { conn *icmp.PacketConn - target Target + target models.Target attempts int timeout time.Duration } @@ -54,9 +55,9 @@ func (s *ICMPScanner) Stop() error { return nil } -func (s *ICMPScanner) Scan(ctx context.Context, targets []Target) (<-chan Result, error) { - results := make(chan Result) - targetChan := make(chan Target) +func (s *ICMPScanner) Scan(ctx context.Context, targets []models.Target) (<-chan models.Result, error) { + results := make(chan models.Result) + targetChan := make(chan models.Target) conn, err := s.createICMPConnection() if err != nil { @@ -116,7 +117,7 @@ func (*ICMPScanner) createICMPConnection() (*icmp.PacketConn, error) { return icmp.ListenPacket("ip4:icmp", "0.0.0.0") } -func (s *ICMPScanner) worker(ctx context.Context, config *ICMPWorkerConfig, targets <-chan Target, results chan<- Result) { +func (s *ICMPScanner) worker(ctx context.Context, config *ICMPWorkerConfig, targets <-chan models.Target, results chan<- models.Result) { for { select { case <-ctx.Done(): @@ -142,9 +143,9 @@ func (s *ICMPScanner) worker(ctx context.Context, config *ICMPWorkerConfig, targ } } -func (s *ICMPScanner) pingHost(ctx context.Context, config *ICMPWorkerConfig) Result { +func (s *ICMPScanner) pingHost(ctx context.Context, config *ICMPWorkerConfig) models.Result { start := time.Now() - result := Result{ + result := models.Result{ Target: config.target, FirstSeen: start, LastSeen: start, @@ -255,15 +256,15 @@ func (*ICMPScanner) sendPing(_ context.Context, config *ICMPWorkerConfig) (bool, return success, elapsed } -func (s *ICMPScanner) fallbackScan(ctx context.Context, targets []Target) (<-chan Result, error) { +func (s *ICMPScanner) fallbackScan(ctx context.Context, targets []models.Target) (<-chan models.Result, error) { // Convert ICMP targets to TCP targets - tcpTargets := make([]Target, len(targets)) + tcpTargets := make([]models.Target, len(targets)) for i, target := range targets { - tcpTargets[i] = Target{ + tcpTargets[i] = models.Target{ Host: target.Host, Port: 80, // Try a common port for host discovery - Mode: ModeTCP, + Mode: models.ModeTCP, } } diff --git a/pkg/sweeper/interfaces.go b/pkg/sweeper/interfaces.go index a95b8cc..472066e 100644 --- a/pkg/sweeper/interfaces.go +++ b/pkg/sweeper/interfaces.go @@ -3,13 +3,8 @@ package sweeper import ( "context" "time" -) - -type SweepMode string -const ( - ModeTCP SweepMode = "tcp" - ModeICMP SweepMode = "icmp" + "github.com/mfreeman451/serviceradar/pkg/models" ) // HostResult represents all results for a single host. @@ -51,19 +46,19 @@ type Sweeper interface { Stop() error // GetResults retrieves sweep results based on filter - GetResults(context.Context, *ResultFilter) ([]Result, error) + GetResults(context.Context, *models.ResultFilter) ([]models.Result, error) // GetConfig returns current sweeper configuration - GetConfig() Config + GetConfig() models.Config // UpdateConfig updates sweeper configuration - UpdateConfig(Config) error + UpdateConfig(models.Config) error } // Scanner defines how to perform network sweeps. type Scanner interface { // Scan performs the sweep and returns results through the channel - Scan(context.Context, []Target) (<-chan Result, error) + Scan(context.Context, []models.Target) (<-chan models.Result, error) // Stop gracefully stops any ongoing scans Stop() error } @@ -71,9 +66,9 @@ type Scanner interface { // Store defines storage operations for sweep results. type Store interface { // SaveResult persists a single scan result - SaveResult(context.Context, *Result) error + SaveResult(context.Context, *models.Result) error // GetResults retrieves results matching the filter - GetResults(context.Context, *ResultFilter) ([]Result, error) + GetResults(context.Context, *models.ResultFilter) ([]models.Result, error) // GetSweepSummary gets the latest sweep summary GetSweepSummary(context.Context) (*SweepSummary, error) // PruneResults removes results older than given duration @@ -83,7 +78,7 @@ type Store interface { // ResultProcessor defines how to process and aggregate sweep results. type ResultProcessor interface { // Process takes a Result and updates internal state - Process(*Result) error + Process(result *models.Result) error // GetSummary returns the current summary of all processed results GetSummary() (*SweepSummary, error) // Reset clears the processor's state @@ -105,25 +100,7 @@ type SweepService interface { // GetStatus returns current sweep status GetStatus(context.Context) (*SweepSummary, error) // UpdateConfig updates service configuration - UpdateConfig(Config) error -} - -// Result represents the outcome of a sweep against a target. -type Result struct { - Target Target - Available bool - FirstSeen time.Time - LastSeen time.Time - RespTime time.Duration - PacketLoss float64 - Error error -} - -// Target represents a network target to be scanned. -type Target struct { - Host string - Port int - Mode SweepMode + UpdateConfig(models.Config) error } // SweepSummary provides aggregated sweep results. @@ -135,23 +112,3 @@ type SweepSummary struct { Ports []PortCount `json:"ports"` Hosts []HostResult `json:"hosts"` } - -// Config defines sweeper configuration. -type Config struct { - Networks []string `json:"networks"` - Ports []int `json:"ports"` - SweepModes []SweepMode `json:"sweep_modes"` - Interval time.Duration `json:"interval"` - Concurrency int `json:"concurrency"` - Timeout time.Duration `json:"timeout"` - ICMPCount int `json:"icmp_count"` -} - -// ResultFilter defines criteria for retrieving results. -type ResultFilter struct { - Host string - Port int - StartTime time.Time - EndTime time.Time - Available *bool -} diff --git a/pkg/sweeper/memory_store.go b/pkg/sweeper/memory_store.go index 185ca9a..516d663 100644 --- a/pkg/sweeper/memory_store.go +++ b/pkg/sweeper/memory_store.go @@ -4,18 +4,20 @@ import ( "context" "sync" "time" + + "github.com/mfreeman451/serviceradar/pkg/models" ) // InMemoryStore implements Store interface for temporary storage. type InMemoryStore struct { mu sync.RWMutex - results []Result + results []models.Result } // NewInMemoryStore creates a new in-memory store for sweep results. func NewInMemoryStore() Store { return &InMemoryStore{ - results: make([]Result, 0), + results: make([]models.Result, 0), } } @@ -48,7 +50,7 @@ func (s *InMemoryStore) SaveHostResult(_ context.Context, result *HostResult) er } // GetHostResults returns a slice of HostResult based on the provided filter. -func (s *InMemoryStore) GetHostResults(_ context.Context, filter *ResultFilter) ([]HostResult, error) { +func (s *InMemoryStore) GetHostResults(_ context.Context, filter *models.ResultFilter) ([]HostResult, error) { s.mu.RLock() defer s.mu.RUnlock() @@ -76,7 +78,7 @@ func (s *InMemoryStore) GetHostResults(_ context.Context, filter *ResultFilter) if r.Available { host.Available = true - if r.Target.Mode == ModeTCP { + if r.Target.Mode == models.ModeTCP { portResult := &PortResult{ Port: r.Target.Port, Available: true, @@ -125,7 +127,7 @@ func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*SweepSummary, error } // count ports - if r.Available && r.Target.Mode == ModeTCP { + if r.Available && r.Target.Mode == models.ModeTCP { portCounts[r.Target.Port]++ } @@ -182,7 +184,7 @@ func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*SweepSummary, error } // SaveResult stores (or updates) a Result in memory. -func (s *InMemoryStore) SaveResult(_ context.Context, result *Result) error { +func (s *InMemoryStore) SaveResult(_ context.Context, result *models.Result) error { s.mu.Lock() defer s.mu.Unlock() @@ -201,11 +203,11 @@ func (s *InMemoryStore) SaveResult(_ context.Context, result *Result) error { } // GetResults returns a list of Results that match the filter. -func (s *InMemoryStore) GetResults(_ context.Context, filter *ResultFilter) ([]Result, error) { +func (s *InMemoryStore) GetResults(_ context.Context, filter *models.ResultFilter) ([]models.Result, error) { s.mu.RLock() defer s.mu.RUnlock() - filtered := make([]Result, 0, len(s.results)) + filtered := make([]models.Result, 0, len(s.results)) for i := range s.results { r := &s.results[i] @@ -223,7 +225,7 @@ func (s *InMemoryStore) PruneResults(_ context.Context, age time.Duration) error defer s.mu.Unlock() cutoff := time.Now().Add(-age) - newResults := make([]Result, 0, len(s.results)) + newResults := make([]models.Result, 0, len(s.results)) for i := range s.results { r := &s.results[i] @@ -238,8 +240,8 @@ func (s *InMemoryStore) PruneResults(_ context.Context, age time.Duration) error } // matchesFilter checks if a Result matches the provided filter. -func (*InMemoryStore) matchesFilter(result *Result, filter *ResultFilter) bool { - checks := []func(*Result, *ResultFilter) bool{ +func (*InMemoryStore) matchesFilter(result *models.Result, filter *models.ResultFilter) bool { + checks := []func(*models.Result, *models.ResultFilter) bool{ checkTimeRange, checkHost, checkPort, @@ -256,7 +258,7 @@ func (*InMemoryStore) matchesFilter(result *Result, filter *ResultFilter) bool { } // checkTimeRange verifies if the result falls within the specified time range. -func checkTimeRange(result *Result, filter *ResultFilter) bool { +func checkTimeRange(result *models.Result, filter *models.ResultFilter) bool { if !filter.StartTime.IsZero() && result.LastSeen.Before(filter.StartTime) { return false } @@ -269,16 +271,16 @@ func checkTimeRange(result *Result, filter *ResultFilter) bool { } // checkHost verifies if the result matches the specified host. -func checkHost(result *Result, filter *ResultFilter) bool { +func checkHost(result *models.Result, filter *models.ResultFilter) bool { return filter.Host == "" || result.Target.Host == filter.Host } // checkPort verifies if the result matches the specified port. -func checkPort(result *Result, filter *ResultFilter) bool { +func checkPort(result *models.Result, filter *models.ResultFilter) bool { return filter.Port == 0 || result.Target.Port == filter.Port } // checkAvailability verifies if the result matches the specified availability. -func checkAvailability(result *Result, filter *ResultFilter) bool { +func checkAvailability(result *models.Result, filter *models.ResultFilter) bool { return filter.Available == nil || result.Available == *filter.Available } diff --git a/pkg/sweeper/result_processor.go b/pkg/sweeper/result_processor.go index 7c21ec4..42ce39e 100644 --- a/pkg/sweeper/result_processor.go +++ b/pkg/sweeper/result_processor.go @@ -3,6 +3,8 @@ package sweeper import ( "sync" "time" + + "github.com/mfreeman451/serviceradar/pkg/models" ) // DefaultProcessor implements ResultProcessor with in-memory state. @@ -21,7 +23,7 @@ func NewDefaultProcessor() *DefaultProcessor { } } -func (p *DefaultProcessor) Process(result *Result) error { +func (p *DefaultProcessor) Process(result *models.Result) error { p.mu.Lock() defer p.mu.Unlock() @@ -31,7 +33,7 @@ func (p *DefaultProcessor) Process(result *Result) error { } // Update port counts - if result.Available && result.Target.Mode == ModeTCP { + if result.Available && result.Target.Mode == models.ModeTCP { p.portCounts[result.Target.Port]++ } @@ -52,7 +54,7 @@ func (p *DefaultProcessor) Process(result *Result) error { if result.Available { host.Available = true - if result.Target.Mode == ModeTCP { + if result.Target.Mode == models.ModeTCP { port := &PortResult{ Port: result.Target.Port, Available: true, diff --git a/pkg/sweeper/sqlite_store.go b/pkg/sweeper/sqlite_store.go index d73b355..37f0d2e 100644 --- a/pkg/sweeper/sqlite_store.go +++ b/pkg/sweeper/sqlite_store.go @@ -7,6 +7,8 @@ import ( "fmt" "log" "time" + + "github.com/mfreeman451/serviceradar/pkg/models" ) var ( @@ -24,7 +26,7 @@ type queryBuilder struct { args []interface{} } -func (s *SQLiteStore) SaveResult(ctx context.Context, result *Result) error { +func (s *SQLiteStore) SaveResult(ctx context.Context, result *models.Result) error { // Use upsert to handle both new and existing results const query = ` INSERT INTO sweep_results ( @@ -119,8 +121,8 @@ func (qb *queryBuilder) finalize() (queryString string, queryArgs []interface{}) } // scanRow scans a single row into a Result struct. -func scanRow(rows *sql.Rows) (*Result, error) { - var r Result +func scanRow(rows *sql.Rows) (*models.Result, error) { + var r models.Result var errStr sql.NullString @@ -147,7 +149,7 @@ func scanRow(rows *sql.Rows) (*Result, error) { return &r, nil } -func (s *SQLiteStore) GetResults(ctx context.Context, filter *ResultFilter) ([]Result, error) { +func (s *SQLiteStore) GetResults(ctx context.Context, filter *models.ResultFilter) ([]models.Result, error) { // Build query qb := newQueryBuilder() qb.addHostFilter(filter.Host) @@ -169,7 +171,7 @@ func (s *SQLiteStore) GetResults(ctx context.Context, filter *ResultFilter) ([]R }(rows) // Process results - var results []Result + var results []models.Result for rows.Next() { result, err := scanRow(rows) diff --git a/pkg/sweeper/sweeper.go b/pkg/sweeper/sweeper.go index cf9b147..1cb1517 100644 --- a/pkg/sweeper/sweeper.go +++ b/pkg/sweeper/sweeper.go @@ -11,6 +11,8 @@ import ( "strings" "sync" "time" + + "github.com/mfreeman451/serviceradar/pkg/models" ) var ( @@ -19,7 +21,7 @@ var ( // NetworkSweeper implements the Sweeper interface. type NetworkSweeper struct { - config *Config + config *models.Config scanner *CombinedScanner store Store mu sync.RWMutex @@ -27,7 +29,7 @@ type NetworkSweeper struct { } // NewNetworkSweeper creates a new instance of NetworkSweeper. -func NewNetworkSweeper(config *Config) *NetworkSweeper { +func NewNetworkSweeper(config *models.Config) *NetworkSweeper { scanner := NewCombinedScanner(config.Timeout, config.Concurrency, config.ICMPCount) store := NewInMemoryStore() @@ -69,18 +71,18 @@ func (s *NetworkSweeper) Stop() error { return s.scanner.Stop() } -func (s *NetworkSweeper) GetResults(ctx context.Context, filter *ResultFilter) ([]Result, error) { +func (s *NetworkSweeper) GetResults(ctx context.Context, filter *models.ResultFilter) ([]models.Result, error) { return s.store.GetResults(ctx, filter) } -func (s *NetworkSweeper) GetConfig() *Config { +func (s *NetworkSweeper) GetConfig() *models.Config { s.mu.RLock() defer s.mu.RUnlock() return s.config } -func (s *NetworkSweeper) UpdateConfig(config *Config) error { +func (s *NetworkSweeper) UpdateConfig(config *models.Config) error { s.mu.Lock() defer s.mu.Unlock() s.config = config @@ -88,6 +90,8 @@ func (s *NetworkSweeper) UpdateConfig(config *Config) error { return nil } +type SweepMode models.SweepMode + // UnmarshalJSON implements json.Unmarshaler for SweepMode. func (m *SweepMode) UnmarshalJSON(data []byte) error { var s string @@ -97,9 +101,9 @@ func (m *SweepMode) UnmarshalJSON(data []byte) error { switch strings.ToLower(s) { case "tcp": - *m = ModeTCP + *m = SweepMode(models.ModeTCP) case "icmp": - *m = ModeICMP + *m = SweepMode(models.ModeICMP) default: return fmt.Errorf("%w: %s", errInvalidSweepMode, s) } @@ -112,8 +116,8 @@ func (m *SweepMode) MarshalJSON() ([]byte, error) { return json.Marshal(string(*m)) } -func (s *NetworkSweeper) generateTargets() ([]Target, error) { - var allTargets []Target +func (s *NetworkSweeper) generateTargets() ([]models.Target, error) { + var allTargets []models.Target for _, network := range s.config.Networks { // First generate all IP addresses @@ -123,23 +127,23 @@ func (s *NetworkSweeper) generateTargets() ([]Target, error) { } // For each IP, create ICMP target if enabled - if containsMode(s.config.SweepModes, ModeICMP) { + if containsMode(s.config.SweepModes, models.ModeICMP) { for _, ip := range ips { - allTargets = append(allTargets, Target{ + allTargets = append(allTargets, models.Target{ Host: ip.String(), - Mode: ModeICMP, + Mode: models.ModeICMP, }) } } // For each IP, create TCP targets for each port if enabled - if containsMode(s.config.SweepModes, ModeTCP) { + if containsMode(s.config.SweepModes, models.ModeTCP) { for _, ip := range ips { for _, port := range s.config.Ports { - allTargets = append(allTargets, Target{ + allTargets = append(allTargets, models.Target{ Host: ip.String(), Port: port, - Mode: ModeTCP, + Mode: models.ModeTCP, }) } } @@ -178,12 +182,12 @@ func (s *NetworkSweeper) runSweep(ctx context.Context) error { // Log based on scan type switch result.Target.Mode { - case ModeICMP: + case models.ModeICMP: if result.Available { log.Printf("Host %s responded to ICMP ping (%.2fms)", result.Target.Host, float64(result.RespTime)/float64(time.Millisecond)) } - case ModeTCP: + case models.ModeTCP: if result.Available { log.Printf("Host %s has port %d open (%.2fms)", result.Target.Host, result.Target.Port, @@ -195,7 +199,7 @@ func (s *NetworkSweeper) runSweep(ctx context.Context) error { return nil } -func containsMode(modes []SweepMode, mode SweepMode) bool { +func containsMode(modes []models.SweepMode, mode models.SweepMode) bool { for _, m := range modes { if m == mode { return true diff --git a/pkg/sweeper/tcp_scanner.go b/pkg/sweeper/tcp_scanner.go index 9ad24c2..ae20240 100644 --- a/pkg/sweeper/tcp_scanner.go +++ b/pkg/sweeper/tcp_scanner.go @@ -7,6 +7,8 @@ import ( "strconv" "sync" "time" + + "github.com/mfreeman451/serviceradar/pkg/models" ) type TCPScanner struct { @@ -28,9 +30,9 @@ func (s *TCPScanner) Stop() error { return nil } -func (s *TCPScanner) Scan(ctx context.Context, targets []Target) (<-chan Result, error) { - results := make(chan Result) - targetChan := make(chan Target) +func (s *TCPScanner) Scan(ctx context.Context, targets []models.Target) (<-chan models.Result, error) { + results := make(chan models.Result) + targetChan := make(chan models.Target) var wg sync.WaitGroup // Start worker pool @@ -64,7 +66,7 @@ func (s *TCPScanner) Scan(ctx context.Context, targets []Target) (<-chan Result, return results, nil } -func (s *TCPScanner) worker(ctx context.Context, wg *sync.WaitGroup, targets <-chan Target, results chan<- Result) { +func (s *TCPScanner) worker(ctx context.Context, wg *sync.WaitGroup, targets <-chan models.Target, results chan<- models.Result) { defer wg.Done() for { @@ -83,9 +85,9 @@ func (s *TCPScanner) worker(ctx context.Context, wg *sync.WaitGroup, targets <-c } } -func (s *TCPScanner) scanTarget(ctx context.Context, target Target, results chan<- Result) { +func (s *TCPScanner) scanTarget(ctx context.Context, target models.Target, results chan<- models.Result) { start := time.Now() - result := Result{ + result := models.Result{ Target: target, FirstSeen: start, LastSeen: start, diff --git a/pkg/sweeper/utils.go b/pkg/sweeper/utils.go index 2774efc..f5362cc 100644 --- a/pkg/sweeper/utils.go +++ b/pkg/sweeper/utils.go @@ -28,17 +28,6 @@ func GenerateIPsFromCIDR(network string) ([]net.IP, error) { return ips, nil } -// ContainsMode checks if a mode is in a list of modes. -func ContainsMode(modes []SweepMode, mode SweepMode) bool { - for _, m := range modes { - if m == mode { - return true - } - } - - return false -} - // inc increments an IP address. func inc(ip net.IP) { for j := len(ip) - 1; j >= 0; j-- {