Skip to content

Discovery Agent Overview

The FreeSDN Agent (freesdn-agent) is a lightweight network discovery daemon that runs on a machine inside your LAN and feeds real device intelligence back to the FreeSDN control plane.

The FreeSDN control plane runs as a Docker stack. Docker containers operate in isolated network namespaces with Layer 3+ access only - they cannot open raw sockets, listen for Layer 2 frames (LLDP/CDP/ARP), enter promiscuous mode, or bind privileged ports like UDP 162 (SNMP traps) or UDP 514 (syslog) without special host-mode setup.

An agent running as a native system service on a host inside the LAN has full OS-level access:

Capability Docker container FreeSDN Agent
Raw sockets / ARP No Yes
L2 frames (LLDP, CDP) No Yes
Promiscuous mode No Yes
SNMP trap receiver (UDP 162) Port-map only Yes
Syslog receiver (UDP 514) Port-map only Yes
DHCP snooping No Yes
Multi-VLAN access No Yes
mDNS / SSDP / ONVIF multicast Partial Yes

A single control plane can manage agents at multiple sites simultaneously - each agent scans its local LAN and streams results back over an outbound HTTPS/WebSocket connection, with no inbound firewall holes required.

Daemon Desktop app
Mode Headless system service, runs 24/7 Interactive PySide6 GUI application
Target user Sysadmin deploying at a remote site Network technician on-site
Connection Persistent WebSocket to control plane REST API
Platforms Windows, Linux, macOS (Py >= 3.11) Windows, Linux, macOS
Approximate size ~30 MB (no Qt) ~150 MB (includes Qt)

Both share the same scanner engine. The 14 active scanners in freesdn_agent/scanners/ are pure Python with zero Qt dependency - only the orchestration layer differs (asyncio event loop for the daemon, QThread for the desktop app).

Scanner Protocol / Layer Root required?
arp ARP (L2) Yes - raw L2 sockets via Scapy
ping ICMP via subprocess No
tcp_port TCP connect No
http_service HTTP/HTTPS (L7) No
banner SSH/Telnet banner grab No
snmp SNMP v1/v2c (UDP 161) No
netbios NetBIOS/SMB (UDP 137) No
mdns mDNS/Bonjour (UDP 5353) No
ssdp SSDP/UPnP (UDP 1900) No
sip SIP OPTIONS (UDP 5060) No
dns DNS reverse lookup No
rtsp RTSP (TCP 554) No
onvif ONVIF WS-Discovery (UDP 3702) No (Scapy library needed)
sadp Hikvision SADP (UDP 37020) No (Scapy library needed)

Passive listeners run as long-lived background tasks alongside the daemon. They are off by default and must be enabled in PassiveConfig.

Listener What it captures Root required?
lldp LLDP neighbor frames (ethertype 0x88CC) Yes
cdp Cisco CDP frames (multicast 01:00:0C:CC:CC:CC) Yes
snmp_trap SNMP trap PDUs (UDP 162) Yes (privileged port)
syslog Syslog messages (UDP 514) Yes (privileged port)
dhcp DHCP traffic (UDP 67/68) - detects new devices via DHCP DISCOVER/REQUEST/ACK Yes

With each heartbeat the agent sends a capability advertisement to the control plane so the UI knows exactly what this agent can run:

{
"scanners": ["arp", "icmp", "ports", "http", "banner", "netbios", "sip", "mdns", "ssdp", "snmp", "onvif", "sadp"],
"listeners": ["lldp", "cdp"],
"scan_types": ["quick", "camera", "voip", "iot", "port", "windows", "full"],
"platform": "linux",
"python_version": "3.12.3",
"agent_version": "1.0.0",
"has_scapy": true,
"has_root": true,
"interfaces": ["eth0", "eth1"]
}

The backend uses scan_types to filter the scan-type choices when creating a scheduled scan for a specific agent - if the agent lacks Scapy, the camera scan type is not offered.

The agent maintains a persistent WebSocket to the control plane at:

wss://<server>/api/v1/agents/ws/<agent_id>

The agent_id is embedded in the WebSocket URL path. Immediately after connecting, the agent sends a JSON authentication message:

{"agent_key": "<key>", "site_id": "<uuid>"}

The backend verifies the key against the stored SHA-256 hash. The agent key is a 32-byte random token issued once at registration; the backend stores only its SHA-256 hash. The key is kept in the OS keyring (Windows Credential Manager, macOS Keychain, Linux Secret Service) - never in plaintext config files.

Commands flow server → agent (e.g. scan_network, fingerprint_device). Results, heartbeats, and scan progress flow agent → server over the same connection. If the connection drops, the agent reconnects with exponential backoff (initial 5 s, max 5 min).

Required outbound access: HTTPS (port 443) to your FreeSDN server. No inbound ports are needed on the agent machine.

Every 30 seconds (configurable, 10 s-1 h) the agent sends a heartbeat containing CPU/memory/disk utilisation, active task count, uptime, and current subnet list. (A managed_devices field is present in the payload but is not available in this release; the daemon always emits 0 for that value.) Heartbeats are stored in the TimescaleDB time-series DB and drive the online/offline/error status indicator in the Agents UI.

All product names, logos, and brands are property of their respective owners. FreeSDN is an independent project and is not affiliated with or endorsed by the vendors it integrates with. See Trademarks.