When on_departure popped the device from known_devices, rapid RTM_NEWNEIGH events during ARP cache rebuild each triggered on_arrival as if the device was brand new, flooding the Matrix room with 5-10+ duplicate ARRIVED alerts. Fix: keep device in known_devices with departing=True flag. on_arrival silently cancels pending departure timers and returns without alerting when it sees this flag. Timer callback checks flag before sending the alert and only pops the device when departure is confirmed after 15 minutes.
Net Alerter — Device Presence Tripwire Daemon
Persistent systemd daemon that passively monitors device presence on the network via DHCP sniffing and Netlink kernel events. Sends Matrix alerts on device arrival/departure.
Files
| File | Purpose |
|---|---|
net_alerter.py |
Main daemon (stdlib-only, 15K) |
net_alerter.service |
Systemd unit file |
deploy-daemon.sh |
Universal deployment script |
DAEMON_DEPLOYMENT.md |
General deployment guide |
ORANGE_PI_DEPLOYMENT.md |
Orange Pi Zero 3 specific guide |
deploy.sh |
Legacy cron-based deployer (deprecated) |
Quick Start (Orange Pi Zero 3 @ 10.0.0.0)
cd ~/tools/bigbrother/net_alerter
./deploy-daemon.sh root@10.0.0.0
Then configure Matrix credentials:
ssh root@10.0.0.0 "cat > /opt/net_alerter/.env <<EOF
MATRIX_HOMESERVER=https://m.example.org
MATRIX_ACCESS_TOKEN=<your_token>
MATRIX_ROOM_ID=!REDACTED:example.org
EOF
chmod 600 /opt/net_alerter/.env
systemctl restart net_alerter"
Verify:
ssh root@10.0.0.0 "journalctl -u net_alerter -n 30"
How It Works
Three Concurrent Threads
-
DHCP Sniffer — AF_PACKET raw socket captures DHCP traffic
- Extracts MAC, IP, hostname from DHCP packets
- Triggers arrival on Discover/Request, departure on Release
-
Netlink RTM_NEWNEIGH Watcher — Kernel ARP neighbor creation events
- Fires when device reaches REACHABLE state
- Handles static-IP devices
-
Netlink RTM_DELNEIGH Watcher — Kernel ARP neighbor deletion events
- Fires when device times out from ARP cache (5-10 minutes)
- Triggers departure alert
Zero Active Probing
- No nmap, nping, arp-scan, ping
- Only passive listening on raw sockets
- No traffic generated by this daemon
Dependencies
- Runtime: Python 3.6+, root access
- Libraries: stdlib only (socket, struct, threading, time, logging, os)
- Data: OUI database at
/usr/share/hwdata/oui.txtor/usr/share/misc/oui.txt(usually present on Debian)
Configuration
.env file at /opt/net_alerter/.env:
MATRIX_HOMESERVER=https://m.example.org
MATRIX_ACCESS_TOKEN=syt_...
MATRIX_ROOM_ID=!REDACTED:example.org
Optional Environment Variables
NET_ALERTER_ENV— Path to config file (default:/opt/net_alerter/.env)
Deployment Methods
Method 1: Automated Script (Recommended)
./deploy-daemon.sh root@10.0.0.0
Method 2: Manual
See DAEMON_DEPLOYMENT.md → Manual Deployment section
Method 3: Orange Pi Specific
See ORANGE_PI_DEPLOYMENT.md for step-by-step guide with troubleshooting
Monitoring
Service Status
ssh root@10.0.0.0 "systemctl status net_alerter"
Real-Time Logs
ssh root@10.0.0.0 "journalctl -u net_alerter -f"
Check Device Count
ssh root@10.0.0.0 "journalctl -u net_alerter | grep 'Tracking.*devices'"
Example Alerts
Arrival
[NET] ARRIVED: iphone.local (10.0.0.0) [Apple Inc.] MAC:a4:5e:60:ab:cd:ef
Departure
[NET] DEPARTED: iphone.local (10.0.0.0) [Apple Inc.] MAC:a4:5e:60:ab:cd:ef — present 2h 34m
Performance
| Metric | Value |
|---|---|
| CPU | <1% (idle, thread sleeping on sockets) |
| Memory | ~15-20 MB |
| Network Traffic | 0 (passive only) |
| Detection Latency | <100ms for Netlink events, 5-10min for ARP timeouts |
| Startup Time | ~2 seconds |
Troubleshooting
See DAEMON_DEPLOYMENT.md → Troubleshooting section for:
- Service won't start
- No alerts being sent
- Not detecting devices
- High CPU usage
Migration from Cron
The legacy cron-based implementation (deploy.sh) ran every 5 minutes with active probing (nmap). The new daemon:
- Runs continuously
- Zero active probing
- Real-time detection via kernel Netlink notifications
- Lower CPU and network overhead
To migrate, stop the old cron and deploy the daemon.
Development
Code Structure
load_env()— Parse.envconfigurationseed_from_arp_cache()— Bootstrap known devices on startuplookup_oui()— MAC vendor lookupon_arrival()/on_departure()— Event handlers, trigger Matrix alertsdhcp_sniffer()— DHCP packet capture threadparse_dhcp()— Extract MAC/IP/hostname from DHCP payloadsnetlink_watcher()— Netlink event listener threadparse_netlink()/parse_ndmsg()— Kernel neighbor event parsingsend_alert()— POST to Matrix API
Testing
python3 -m py_compile net_alerter.py # Syntax check
python3 -c "import net_alerter" # Import check
Note: Full functional tests require root, raw sockets, and live DHCP traffic.
References
- Netlink: https://man7.org/linux/man-pages/man7/netlink.7.html
- RTnetlink: https://man7.org/linux/man-pages/man7/rtnetlink.7.html
- AF_PACKET: https://man7.org/linux/man-pages/man7/packet.7.html
- DHCP (RFC 2131): https://tools.ietf.org/html/rfc2131
License
Part of BigBrother project.