Network monitoring service written in Go that performs ICMP ping monitoring of discovered devices and stores metrics in InfluxDB.
Performs decoupled network discovery and monitoring with four independent tickers: ICMP discovery finds new devices, scheduled SNMP scans enrich device data, pinger reconciliation ensures continuous monitoring, and state pruning removes stale devices. This architecture provides efficient resource usage and fast response to network changes.
- Multi-Ticker Architecture: Four independent tickers for decoupled operations
- ICMP Discovery (every 5m) - Finds new responsive devices
- Daily SNMP Scan (scheduled) - Enriches all devices with SNMP data
- Pinger Reconciliation (every 5s) - Ensures all devices monitored
- State Pruning (every 1h) - Removes stale devices
- Dual-Trigger SNMP: Immediate scan for new devices + scheduled daily scan for all devices
- Concurrent Processing: Configurable worker pool patterns for scalable network operations
- State-Centric Design: StateManager as single source of truth for all devices
- InfluxDB v2: Time-series metrics storage with point-based writes
- Configuration: YAML-based config with duration parsing and environment variable support
- Security: Linux capabilities (CAP_NET_RAW) for non-root ICMP access, input validation, and secure credential handling
- Single Binary: No runtime dependencies
The application uses a multi-ticker architecture with four independent, concurrent loops:
- ICMP Discovery Ticker - Scans networks for responsive devices
- Daily SNMP Scan Ticker - Enriches devices with SNMP data at scheduled time
- Pinger Reconciliation Ticker - Ensures all devices have active monitoring
- State Pruning Ticker - Removes devices not seen in 24 hours
cmd/netscan/main.go # Four-ticker orchestration and CLI interface
internal/
├── config/config.go # YAML parsing with SNMPDailySchedule support
├── discovery/scanner.go # RunICMPSweep() and RunSNMPScan() functions
├── monitoring/pinger.go # ICMP monitoring with StateManager integration
├── state/manager.go # Thread-safe device state (single source of truth)
└── influx/writer.go # InfluxDB client wrapper with health checks
github.com/gosnmp/gosnmp v1.42.1
- SNMPv2c protocolgithub.com/influxdata/influxdb-client-go/v2 v2.14.0
- InfluxDB v2 clientgithub.com/prometheus-community/pro-bing v0.7.0
- ICMP ping librarygopkg.in/yaml.v3 v3.0.1
- YAML configuration parser
- Go 1.21+ (tested with 1.25.1)
- InfluxDB 2.x
- Root privileges for ICMP socket access
sudo apt update
sudo apt install golang-go docker.io docker-compose
sudo systemctl enable docker
sudo systemctl start docker
sudo pacman -S go docker docker-compose
sudo systemctl enable docker
sudo systemctl start docker
git clone https://github.com/extkljajicm/netscan.git
cd netscan
go mod download
sudo docker-compose up -d # Start test InfluxDB
go build -o netscan ./cmd/netscan
# Or use build script
./build.sh
The repository includes both deployment and undeployment scripts for safe testing:
# Deploy netscan as a systemd service
sudo ./deploy.sh
# Completely uninstall and clean up (for testing)
sudo ./undeploy.sh
The undeployment script provides a 100% clean removal of all components installed by deploy.sh
.
Copy and edit configuration:
cp config.yml.example config.yml
- Environment Variables: Sensitive values (tokens, passwords) can use environment variables with
${VAR_NAME}
syntax - Secure .env File: Deployment creates a separate
.env
file with restrictive permissions (600) for sensitive credentials - Input Validation: Configuration is validated at startup for security and sanity
- Network Range Validation: Prevents scanning dangerous networks (loopback, multicast, link-local, overly broad ranges)
- Runtime Validation: SNMP responses, IP addresses, and database writes are validated and sanitized
- SNMP Security: Community string validation with weak password detection
- Resource Protection: Configurable limits prevent DoS attacks and resource exhaustion
- Rate limiting for discovery scans and database writes
- Memory usage monitoring with configurable limits
- Concurrent operation bounds to prevent goroutine exhaustion
- Device count limits with automatic cleanup
Sensitive configuration values are loaded from a .env
file created during deployment:
# .env file (created by deploy.sh with 600 permissions)
INFLUXDB_URL=http://localhost:8086 # InfluxDB server URL
INFLUXDB_TOKEN=netscan-token # InfluxDB API token
INFLUXDB_ORG=test-org # InfluxDB organization
INFLUXDB_BUCKET=netscan # InfluxDB bucket name
SNMP_COMMUNITY=your-community # SNMPv2c community string
Supported Environment Variables:
INFLUXDB_URL
: InfluxDB server endpointINFLUXDB_TOKEN
: API token for authenticationINFLUXDB_ORG
: Organization nameINFLUXDB_BUCKET
: Target bucket for metricsSNMP_COMMUNITY
: SNMPv2c community string for device access
Security Best Practices:
- Never commit
.env
files to version control - Set restrictive permissions:
chmod 600 .env
- Rotate credentials regularly
- Use strong, unique tokens for each environment
For Production:
- Generate unique, strong tokens for InfluxDB
- Use different organizations per environment
- Change SNMP community strings from defaults
- Consider using a secret management system
# Network Discovery
networks:
- "192.168.0.0/24"
- "10.0.0.0/16"
icmp_discovery_interval: "5m" # How often to scan for new devices
snmp_daily_schedule: "02:00" # Daily SNMP scan time (HH:MM)
# SNMP Settings
snmp:
community: "${SNMP_COMMUNITY}" # From .env file
port: 161
timeout: "5s"
retries: 1
# Monitoring
ping_interval: "2s"
ping_timeout: "2s"
# Performance
icmp_workers: 64 # Concurrent ICMP workers
snmp_workers: 32 # Concurrent SNMP workers
# InfluxDB (credentials from .env file)
influxdb:
url: "${INFLUXDB_URL}"
token: "${INFLUXDB_TOKEN}"
org: "${INFLUXDB_ORG}"
bucket: "netscan"
# Resource Limits
max_concurrent_pingers: 1000
max_devices: 10000
min_scan_interval: "1m"
memory_limit_mb: 512
docker-compose.yml
provides InfluxDB v2.7 with:
- Organization:
test-org
- Bucket:
netscan
- Token:
netscan-token
./netscan
Runs the multi-ticker architecture with:
- ICMP discovery every 5 minutes (configurable via
icmp_discovery_interval
) - Daily SNMP scan at configured time (e.g., 02:00)
- Continuous monitoring of all discovered devices
- Automatic state pruning of stale devices
./netscan -config /path/to/config.yml
-config string
: Path to configuration file (default "config.yml")-help
: Display usage information
sudo ./deploy.sh
Creates:
/opt/netscan/
with binary, config, and secure.env
filenetscan
user with minimal privilegesCAP_NET_RAW
capability on binary- Systemd service with network-compatible security settings
- Secure credential management via environment variables
go build -o netscan ./cmd/netscan
sudo mkdir -p /opt/netscan
sudo cp netscan /opt/netscan/
sudo cp config.yml /opt/netscan/
sudo setcap cap_net_raw+ep /opt/netscan/netscan
sudo useradd -r -s /bin/false netscan
sudo chown -R netscan:netscan /opt/netscan
sudo tee /etc/systemd/system/netscan.service > /dev/null <<EOF
[Unit]
Description=netscan network monitoring
After=network.target
[Service]
Type=simple
ExecStart=/opt/netscan/netscan
WorkingDirectory=/opt/netscan
Restart=always
User=netscan
Group=netscan
# Security settings (relaxed for network access)
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
AmbientCapabilities=CAP_NET_RAW
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable netscan
sudo systemctl start netscan
sudo systemctl status netscan
sudo journalctl -u netscan -f
sudo systemctl restart netscan
sudo systemctl stop netscan
./build.sh
Builds the netscan binary with optimized settings.
go build -o netscan ./cmd/netscan
The CI/CD pipeline builds for Linux amd64 only.
Current Build Target:
- Linux (amd64)
go test ./... # All tests
go test -v ./... # Verbose output
go test ./internal/config # Specific package
go test -race ./... # Race detection
go test -cover ./... # Coverage report
Test Coverage:
- Configuration parsing and validation
- Network discovery algorithms
- State management concurrency
- InfluxDB client operations
- ICMP ping monitoring
- SNMP polling functionality
# Start test InfluxDB
sudo docker-compose up -d
# Run netscan with test config
./netscan -config config.yml
Automated testing runs on push, pull requests, and version tags.
Features:
- Linux amd64 binary builds
- Automated changelog generation
- Code coverage reporting
- Release artifact creation
sudo ./netscan # Manual execution
getcap /opt/netscan/netscan # Check capability
- Verify InfluxDB running:
docker ps
- Check config credentials and API token
- Confirm network connectivity
- Verify network ranges in config
- Check firewall rules for ICMP/SNMP
- Confirm SNMP community string is correct
- Start with lower worker counts (8 ICMP, 4 SNMP)
- Monitor CPU usage with
htop
ortop
- Adjust based on network latency and CPU cores
Default Configuration:
- ICMP Workers: 64 (lightweight, network-bound operations)
- SNMP Workers: 32 (CPU-intensive protocol parsing)
- Memory: ~50MB baseline + ~1KB per device
Recommended Worker Counts:
System Type | CPU Cores | ICMP Workers | SNMP Workers | Max Devices |
---|---|---|---|---|
Raspberry Pi | 4 | 8 | 4 | 100 |
Home 8000 Server | 4-8 | 16 | 8 | 500 |
Workstation | 8-16 | 32 | 16 | 1000 |
Server | 16+ | 64 | 32 | 10000 |
Start with conservative values and monitor CPU usage to adjust for your environment.
The new architecture uses four independent tickers:
-
ICMP Discovery Ticker (every
icmp_discovery_interval
, default 5m):- Performs ICMP ping sweep across all configured networks
- Adds responsive IPs to StateManager
- Triggers immediate SNMP scan for newly discovered devices
-
Daily SNMP Scan Ticker (at
snmp_daily_schedule
, e.g., 02:00):- Full SNMP scan of all devices in StateManager
- Enriches devices with hostname and sysDescr
- Updates device info in InfluxDB
-
Pinger Reconciliation Ticker (every 5 seconds):
- Ensures every device in StateManager has an active pinger goroutine
- Starts pingers for new devices
- Stops pingers for removed devices
- Maintains consistency between state and running pingers
-
State Pruning Ticker (every 1 hour):
- Removes devices not seen in last 24 hours
- Prevents memory growth from stale devices
- Producer-consumer pattern with buffered channels (256 slots)
- Context-based cancellation for graceful shutdown
- sync.WaitGroup for worker lifecycle management
-
Measurement: "ping"
-
Tags: "ip", "hostname"
-
Fields: "rtt_ms" (float), "success" (boolean)
-
Point-based writes with error handling
-
Measurement: "device_info"
-
Tags: "ip"
-
Fields: "hostname" (string), "snmp_description" (string)
-
Stored once per device or when SNMP data changes
- Linux capabilities: CAP_NET_RAW for raw socket access
- Dedicated service user: Non-root execution
- Systemd hardening: NoNewPrivileges, PrivateTmp, ProtectSystem with AmbientCapabilities for network access
git clone https://github.com/extkljajicm/netscan.git
cd netscan
go mod download
docker-compose up -d # Start test InfluxDB
go test ./... # Run tests
go fmt ./... # Format code
go vet ./... # Static analysis
go mod tidy # Clean dependencies
go test -race ./... # Race detection
feat: add new feature
fix: resolve bug
perf: optimize performance
docs: update documentation
test: add tests
refactor: restructure code
netscan/
├── cmd/netscan/ # CLI application and main orchestration
│ ├── main.go # Service startup, signal handling, discovery loops
│ └── main_test.go # Basic package test placeholder
├── internal/ # Private application packages
│ ├── config/ # Configuration parsing and validation
│ │ ├── config.go # YAML loading, environment expansion, validation
│ │ └── config_test.go # Configuration parsing tests
│ ├── discovery/ # Network device discovery
│ │ ├── scanner.go # ICMP/SNMP concurrent scanning workers
│ │ └── scanner_test.go # Discovery algorithm tests
│ ├── monitoring/ # Continuous device monitoring
│ │ ├── pinger.go # ICMP ping goroutines with metrics collection
│ │ └── pinger_test.go # Ping monitoring tests
│ ├── state/ # Thread-safe device state management
│ │ ├── manager.go # RWMutex-protected device registry
│ │ └── manager_test.go # State management concurrency tests
│ └── influx/ # Time-series data persistence
│ ├── writer.go # InfluxDB client wrapper with rate limiting
│ └── writer_test.go # Database write operation tests
├── docker-compose.yml # Test environment (InfluxDB v2.7)
├── build.sh # Simple binary build script
├── deploy.sh # Production deployment automation
├── undeploy.sh # Complete uninstallation script
├── config.yml.example # Configuration template
├── cliff.toml # Changelog generation configuration
└── .github/workflows/ # CI/CD automation
└── ci-cd.yml # GitHub Actions pipeline
MIT