Skip to content

Commit

Permalink
refactored
Browse files Browse the repository at this point in the history
  • Loading branch information
mfreeman451 committed Jan 20, 2025
1 parent c96988c commit 3be1ed6
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 107 deletions.
9 changes: 5 additions & 4 deletions pkg/agent/sweep_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ import (
"time"

"github.com/mfreeman451/serviceradar/pkg/models"
"github.com/mfreeman451/serviceradar/pkg/scan"
"github.com/mfreeman451/serviceradar/pkg/sweeper"
"github.com/mfreeman451/serviceradar/proto"
)

// SweepService implements sweeper.SweepService and provides network scanning capabilities.
type SweepService struct {
scanner sweeper.Scanner
scanner scan.Scanner
store sweeper.Store
processor sweeper.ResultProcessor
processor scan.ResultProcessor
mu sync.RWMutex
closed chan struct{}
config *models.Config
Expand All @@ -32,7 +33,7 @@ func NewSweepService(config *models.Config) (*SweepService, error) {
log.Printf("Creating sweep service with config: %+v", config)

// Create components
scanner := sweeper.NewCombinedScanner(config.Timeout, config.Concurrency, config.ICMPCount)
scanner := scan.NewCombinedScanner(config.Timeout, config.Concurrency, config.ICMPCount)
store := sweeper.NewInMemoryStore()
processor := sweeper.NewDefaultProcessor()

Expand Down Expand Up @@ -223,7 +224,7 @@ func generateTargets(config *models.Config) ([]models.Target, error) {
// For each network
for _, network := range config.Networks {
// Generate IP addresses for the network
ips, err := sweeper.GenerateIPsFromCIDR(network)
ips, err := scan.GenerateIPsFromCIDR(network)
if err != nil {
return nil, fmt.Errorf("failed to generate IPs for %s: %w", network, err)
}
Expand Down
39 changes: 39 additions & 0 deletions pkg/models/sweeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,42 @@ func ContainsMode(modes []SweepMode, mode SweepMode) bool {

return false
}

// HostResult represents all results for a single host.
type HostResult struct {
Host string `json:"host"`
Available bool `json:"available"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
ICMPStatus *ICMPStatus `json:"icmp_status,omitempty"`
PortResults []*PortResult `json:"port_results,omitempty"`
}

// ICMPStatus represents ICMP ping results.
type ICMPStatus struct {
Available bool `json:"available"`
RoundTrip time.Duration `json:"round_trip"`
PacketLoss float64 `json:"packet_loss"`
}

// PortResult represents a single port scan result.
type PortResult struct {
Port int `json:"port"`
Available bool `json:"available"`
RespTime time.Duration `json:"response_time"`
Service string `json:"service,omitempty"` // Optional service identification
}
type PortCount struct {
Port int `json:"port"`
Available int `json:"available"`
}

// SweepSummary provides aggregated sweep results.
type SweepSummary struct {
Network string `json:"network"`
TotalHosts int `json:"total_hosts"`
AvailableHosts int `json:"available_hosts"`
LastSweep int64 `json:"last_sweep"` // Unix timestamp
Ports []PortCount `json:"ports"`
Hosts []HostResult `json:"hosts"`
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sweeper
package scan

import (
"context"
Expand Down
2 changes: 1 addition & 1 deletion pkg/sweeper/icmp_scanner.go → pkg/scan/icmp_scanner.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sweeper
package scan

import (
"context"
Expand Down
25 changes: 25 additions & 0 deletions pkg/scan/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package scan

import (
"context"

"github.com/mfreeman451/serviceradar/pkg/models"
)

// Scanner defines how to perform network sweeps.
type Scanner interface {
// Scan performs the sweep and returns results through the channel
Scan(context.Context, []models.Target) (<-chan models.Result, error)
// Stop gracefully stops any ongoing scans
Stop() error
}

// ResultProcessor defines how to process and aggregate sweep results.
type ResultProcessor interface {
// Process takes a Result and updates internal state
Process(result *models.Result) error
// GetSummary returns the current summary of all processed results
GetSummary() (*models.SweepSummary, error)
// Reset clears the processor's state
Reset()
}
2 changes: 1 addition & 1 deletion pkg/sweeper/tcp_scanner.go → pkg/scan/tcp_scanner.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sweeper
package scan

import (
"context"
Expand Down
14 changes: 7 additions & 7 deletions pkg/sweeper/utils.go → pkg/scan/utils.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sweeper
package scan

import (
"net"
Expand All @@ -13,9 +13,9 @@ func GenerateIPsFromCIDR(network string) ([]net.IP, error) {

var ips []net.IP

for i := ip.Mask(ipnet.Mask); ipnet.Contains(i); inc(i) {
for i := ip.Mask(ipnet.Mask); ipnet.Contains(i); Inc(i) {
// Skip network and broadcast addresses for IPv4
if i.To4() != nil && isFirstOrLastAddress(i, ipnet) {
if i.To4() != nil && IsFirstOrLastAddress(i, ipnet) {
continue
}

Expand All @@ -28,8 +28,8 @@ func GenerateIPsFromCIDR(network string) ([]net.IP, error) {
return ips, nil
}

// inc increments an IP address.
func inc(ip net.IP) {
// Inc increments an IP address.
func Inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++

Expand All @@ -39,8 +39,8 @@ func inc(ip net.IP) {
}
}

// isFirstOrLastAddress checks if the IP is the network or broadcast address.
func isFirstOrLastAddress(ip net.IP, network *net.IPNet) bool {
// IsFirstOrLastAddress checks if the IP is the network or broadcast address.
func IsFirstOrLastAddress(ip net.IP, network *net.IPNet) bool {
// Get the IP address as 4-byte slice for IPv4
ipv4 := ip.To4()
if ipv4 == nil {
Expand Down
64 changes: 3 additions & 61 deletions pkg/sweeper/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,6 @@ import (
"github.com/mfreeman451/serviceradar/pkg/models"
)

// HostResult represents all results for a single host.
type HostResult struct {
Host string `json:"host"`
Available bool `json:"available"`
FirstSeen time.Time `json:"first_seen"`
LastSeen time.Time `json:"last_seen"`
ICMPStatus *ICMPStatus `json:"icmp_status,omitempty"`
PortResults []*PortResult `json:"port_results,omitempty"`
}

// ICMPStatus represents ICMP ping results.
type ICMPStatus struct {
Available bool `json:"available"`
RoundTrip time.Duration `json:"round_trip"`
PacketLoss float64 `json:"packet_loss"`
}

// PortResult represents a single port scan result.
type PortResult struct {
Port int `json:"port"`
Available bool `json:"available"`
RespTime time.Duration `json:"response_time"`
Service string `json:"service,omitempty"` // Optional service identification
}

type PortCount struct {
Port int `json:"port"`
Available int `json:"available"`
}

// Sweeper defines the main interface for network sweeping.
type Sweeper interface {
// Start begins periodic sweeping based on configuration
Expand All @@ -55,40 +25,22 @@ type Sweeper interface {
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, []models.Target) (<-chan models.Result, error)
// Stop gracefully stops any ongoing scans
Stop() error
}

// Store defines storage operations for sweep results.
type Store interface {
// SaveResult persists a single scan result
SaveResult(context.Context, *models.Result) error
// GetResults retrieves results matching the filter
GetResults(context.Context, *models.ResultFilter) ([]models.Result, error)
// GetSweepSummary gets the latest sweep summary
GetSweepSummary(context.Context) (*SweepSummary, error)
GetSweepSummary(context.Context) (*models.SweepSummary, error)
// PruneResults removes results older than given duration
PruneResults(context.Context, time.Duration) error
}

// ResultProcessor defines how to process and aggregate sweep results.
type ResultProcessor interface {
// Process takes a Result and updates internal state
Process(result *models.Result) error
// GetSummary returns the current summary of all processed results
GetSummary() (*SweepSummary, error)
// Reset clears the processor's state
Reset()
}

// Reporter defines how to report sweep results.
type Reporter interface {
// Report sends a summary somewhere (e.g., to a cloud service)
Report(context.Context, *SweepSummary) error
Report(context.Context, *models.SweepSummary) error
}

// SweepService combines scanning, storage, and reporting.
Expand All @@ -98,17 +50,7 @@ type SweepService interface {
// Stop gracefully stops sweeping
Stop() error
// GetStatus returns current sweep status
GetStatus(context.Context) (*SweepSummary, error)
GetStatus(context.Context) (*models.SweepSummary, error)
// UpdateConfig updates service configuration
UpdateConfig(models.Config) error
}

// SweepSummary provides aggregated sweep results.
type SweepSummary struct {
Network string `json:"network"`
TotalHosts int `json:"total_hosts"`
AvailableHosts int `json:"available_hosts"`
LastSweep int64 `json:"last_sweep"` // Unix timestamp
Ports []PortCount `json:"ports"`
Hosts []HostResult `json:"hosts"`
}
30 changes: 15 additions & 15 deletions pkg/sweeper/memory_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func NewInMemoryStore() Store {
// SaveHostResult updates the last-seen time (and possibly availability)
// for the given host. For in-memory store, we'll store the latest host
// result for each host.
func (s *InMemoryStore) SaveHostResult(_ context.Context, result *HostResult) error {
func (s *InMemoryStore) SaveHostResult(_ context.Context, result *models.HostResult) error {
s.mu.Lock()
defer s.mu.Unlock()

Expand All @@ -50,12 +50,12 @@ 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 *models.ResultFilter) ([]HostResult, error) {
func (s *InMemoryStore) GetHostResults(_ context.Context, filter *models.ResultFilter) ([]models.HostResult, error) {
s.mu.RLock()
defer s.mu.RUnlock()

// group results by host
hostMap := make(map[string]*HostResult)
hostMap := make(map[string]*models.HostResult)

for i := range s.results {
r := &s.results[i]
Expand All @@ -65,12 +65,12 @@ func (s *InMemoryStore) GetHostResults(_ context.Context, filter *models.ResultF

host, exists := hostMap[r.Target.Host]
if !exists {
host = &HostResult{
host = &models.HostResult{
Host: r.Target.Host,
FirstSeen: r.FirstSeen,
LastSeen: r.LastSeen,
Available: false,
PortResults: make([]*PortResult, 0),
PortResults: make([]*models.PortResult, 0),
}
hostMap[r.Target.Host] = host
}
Expand All @@ -79,7 +79,7 @@ func (s *InMemoryStore) GetHostResults(_ context.Context, filter *models.ResultF
host.Available = true

if r.Target.Mode == models.ModeTCP {
portResult := &PortResult{
portResult := &models.PortResult{
Port: r.Target.Port,
Available: true,
RespTime: r.RespTime,
Expand All @@ -99,7 +99,7 @@ func (s *InMemoryStore) GetHostResults(_ context.Context, filter *models.ResultF
}

// Convert map to slice
hosts := make([]HostResult, 0, len(hostMap))
hosts := make([]models.HostResult, 0, len(hostMap))
for _, host := range hostMap {
hosts = append(hosts, *host)
}
Expand All @@ -108,11 +108,11 @@ func (s *InMemoryStore) GetHostResults(_ context.Context, filter *models.ResultF
}

// GetSweepSummary gathers high-level sweep information.
func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*SweepSummary, error) {
func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*models.SweepSummary, error) {
s.mu.RLock()
defer s.mu.RUnlock()

hostMap := make(map[string]*HostResult)
hostMap := make(map[string]*models.HostResult)
portCounts := make(map[int]int)
totalHosts := 0

Expand All @@ -135,12 +135,12 @@ func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*SweepSummary, error
host, exists := hostMap[r.Target.Host]
if !exists {
totalHosts++
host = &HostResult{
host = &models.HostResult{
Host: r.Target.Host,
FirstSeen: r.FirstSeen,
LastSeen: r.LastSeen,
Available: false,
PortResults: make([]*PortResult, 0),
PortResults: make([]*models.PortResult, 0),
}
hostMap[r.Target.Host] = host
}
Expand All @@ -152,7 +152,7 @@ func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*SweepSummary, error

// Count available hosts
availableHosts := 0
hosts := make([]HostResult, 0, len(hostMap))
hosts := make([]models.HostResult, 0, len(hostMap))

for _, host := range hostMap {
if host.Available {
Expand All @@ -163,15 +163,15 @@ func (s *InMemoryStore) GetSweepSummary(_ context.Context) (*SweepSummary, error
}

// Create port counts
ports := make([]PortCount, 0, len(portCounts))
ports := make([]models.PortCount, 0, len(portCounts))
for port, count := range portCounts {
ports = append(ports, PortCount{
ports = append(ports, models.PortCount{
Port: port,
Available: count,
})
}

summary := &SweepSummary{
summary := &models.SweepSummary{
Network: "",
TotalHosts: totalHosts,
AvailableHosts: availableHosts,
Expand Down
Loading

0 comments on commit 3be1ed6

Please sign in to comment.