The phone/wearable gate used a manual OUI check that missed privately-addressed MACs (iOS 14+/Android 10+ randomize per network). Any phone not pre-configured in device_labels was silently enrolled with no alert, causing ARRIVED/OCCUPIED to never fire. Replacing the gate with is_personal_device() catches OUI, labels, and LAA bit uniformly. ARP scan interval drops from 30s to 15s so worst-case arrival detection is 15s.
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.