feat: optional per-device IP address tracking via periodic ARP scan - #1
Draft
mwpastore wants to merge 5 commits into
Draft
feat: optional per-device IP address tracking via periodic ARP scan#1mwpastore wants to merge 5 commits into
mwpastore wants to merge 5 commits into
Conversation
mwpastore
force-pushed
the
claude/upsnap-magic-packet-routing-dc13ba
branch
from
August 7, 2026 22:40
a99973f to
d49656a
Compare
Adds a per-device "Track IP address" toggle (disabled by default) and a global cron interval setting. When enabled, upsnap periodically arp-scans the local subnets of opted-in devices with nmap and updates a device's ip address whenever its mac address is found at a different one. Subnets are skipped unless directly attached to the host, so routed devices are never scanned. Uses the same nmap + CAP_NET_RAW requirements as the existing network scan feature; no new privileges needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwpastore
force-pushed
the
claude/upsnap-magic-packet-routing-dc13ba
branch
from
August 7, 2026 23:00
d49656a to
c828f3a
Compare
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…verage Move the arp scan sweep out of cronjobs into a new iptracking package with two entry points: TrackAllSubnets (the cron sweep) and TrackOneSubnet (a single validated scan). Device lookup is now by mac address across all tracked devices, with updates constrained to the device's own subnet. The scannability check becomes networking.ValidateScannableSubnet, which reports why a subnet can't be scanned and accepts any subnet overlapping a directly attached network, so sub-blocks of an attached prefix are now scannable. The mac-to-ip mapping moves to networking as Nmaprun.MacToIP. Cover the subnet guard, mac normalization, skip paths, and sweep orchestration with tests against a stubbed scanner and a real migrated schema. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
With lazy_ping turned on, the periodic tracking sweep now skips its tick while no realtime clients are connected, just like the ping cron, and owes a catch-up sweep to the next client that connects: the realtime connect hook runs one sweep only when a tick was actually skipped (or none has run since boot), so page reloads during active use trigger nothing. This extends lazy_ping's meaning from "pause pings when idle" to "pause periodic network activity when idle"; the setting's description is updated accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an opt-in, per-device IP address tracking feature: when enabled, UpSnap periodically ARP-scans the local subnets of opted-in devices and updates a device's IP address whenever its MAC address shows up at a different IP. This keeps WOL and ping working for DHCP devices whose leases change.
track_ipbool on thedevicescollection).track_ip_intervalonsettings_private, cron syntax, same validation UX as the ping interval). Empty = feature off.SetPingJobs, so it re-arms on settings changes): fetches devices withtrack_ip = true, computes each device's subnet from ip+netmask, keeps only subnets directly attached to the host (a host interface address lies inside the subnet — routed devices are never scanned), skips /32 and anything broader than /16, dedupes, runs onenmap -snper subnet, and updates any opted-in device whose MAC now sits at a different IP. Saves useIgnoreUnchangedFields(true)so concurrent status writes from the ping/wake crons are never clobbered. No devices opted in or no local subnets → the tick is a no-op.Related work
This PR is intended as complementary to seriousm4x#1760, not competing: name resolution covers devices that have a resolvable name (AD, avahi, dynamic DNS) and works across routed subnets, while ARP tracking covers devices with no name at all (headless/IoT boxes, plain DHCP networks without dynamic DNS) but only on directly attached subnets. A device answers to a MAC even when nothing answers for its name. The two features touch adjacent parts of the device form, so whichever lands second will need a small rebase — happy to be the one to rebase over seriousm4x#1760 if it merges first.
Design notes
arp_accept=0ignores gratuitous ARP). A privilegednmap -snon the local segment does the ARP probing directly and reports MACs in its XML output — the same mechanism the existing network scan feature relies on.CAP_NET_RAW, exactly like the existing network scan. Docker images already ship both; host network mode is already required for WOL. The docker-compose capability comment and README are updated accordingly.WakeDevice/SendMagicPacketare unchanged.scan_linux.go/scan_other.go), mirroring the existing ping/scan pattern.Deliberate duplication / follow-up refactor opportunity
networking/scan.go+scan_linux.gointentionally duplicate the nmap exec + capability-raising code frompb/handlerscan_linux.goso that no existing files inbackend/pbare touched by this PR. If desired, a natural follow-up (or squash into this PR) would collapsehandlerscan_linux.go/handlerscan_other.gointo a single cross-platform handler that calls the sharednetworking.NmapScan, removing ~120 lines of duplicated handler code. I have that refactor working and can push it as a separate commit/PR on request — kept it out of this one to keep the diff strictly feature-scoped.Translations
The 4 new UI strings are added to
en-US.jsononly; other locales fall back to English for these keys until translated. Happy to add translations for the other 22 locales if you'd prefer complete files.Testing
go buildfor darwin and linux/amd64,go vet,gofmt, and existingnetworkingtests all pass.pb_data: both migrations apply and the newtrack_ip/track_ip_intervalcolumns are created with correct defaults (off / empty).pnpm buildandeslintpass;svelte-checkclean apart from a pre-existing error in paraglide's generated output.Save()writes all columns); fixed viaIgnoreUnchangedFields(true)..142→.143→.142, driven by netplan changes on the device) within one sweep interval each way. Running with--devSQL logging confirmed the tracking save writes only theipcolumn while the ping cron's concurrent full-row status updates continued unharmed, and state survived service restarts.AI disclosure
This feature was developed with Claude Code (Anthropic). The design decisions, scope choices, and review/testing direction were mine; I've reviewed the changes and stand behind them.
🤖 Generated with Claude Code