feat: reload also scrubs expired leases from lease file before reloading dnsmasq
This commit is contained in:
parent
efeb993d20
commit
da01893aa3
1 changed files with 51 additions and 0 deletions
51
server.go
51
server.go
|
|
@ -197,6 +197,11 @@ func unpinLease(mac string) error {
|
||||||
|
|
||||||
// reloadDnsmasq runs the reload command (e.g. sudo systemctl reload dnsmasq).
|
// reloadDnsmasq runs the reload command (e.g. sudo systemctl reload dnsmasq).
|
||||||
func reloadDnsmasq() error {
|
func reloadDnsmasq() error {
|
||||||
|
// Scrub expired leases before reloading so the UI stays clean.
|
||||||
|
if err := cleanLeaseFile(); err != nil {
|
||||||
|
log.Printf("WARNING: failed to clean lease file: %v", err)
|
||||||
|
// Continue — reload is still useful even if cleaning fails.
|
||||||
|
}
|
||||||
cmd := exec.Command(reloadCmd, reloadArgs...)
|
cmd := exec.Command(reloadCmd, reloadArgs...)
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -205,6 +210,52 @@ func reloadDnsmasq() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cleanLeaseFile reads the lease file, removes expired entries, writes back atomically.
|
||||||
|
func cleanLeaseFile() error {
|
||||||
|
leases, err := parseLeases()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
var kept []string
|
||||||
|
for _, l := range leases {
|
||||||
|
if l.Expiry.After(now) {
|
||||||
|
kept = append(kept, fmt.Sprintf("%d %s %s %s %s",
|
||||||
|
l.Expiry.Unix(), l.MAC, l.IP, l.Hostname, l.ClientID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing changed, skip the write.
|
||||||
|
if len(kept) == len(leases) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpFile := leasesFile + ".tmp"
|
||||||
|
f, err := os.Create(tmpFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create temp lease file: %w", err)
|
||||||
|
}
|
||||||
|
writeErr := func() error {
|
||||||
|
defer f.Close()
|
||||||
|
for _, line := range kept {
|
||||||
|
if _, err := fmt.Fprintln(f, line); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}()
|
||||||
|
if writeErr != nil {
|
||||||
|
os.Remove(tmpFile)
|
||||||
|
return writeErr
|
||||||
|
}
|
||||||
|
if err := os.Rename(tmpFile, leasesFile); err != nil {
|
||||||
|
os.Remove(tmpFile)
|
||||||
|
return fmt.Errorf("rename lease file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// getAllLeases returns merged active (non-expired) and pinned lease info.
|
// getAllLeases returns merged active (non-expired) and pinned lease info.
|
||||||
func getAllLeases() ([]LeaseEntry, error) {
|
func getAllLeases() ([]LeaseEntry, error) {
|
||||||
activeLeases, err := parseLeases()
|
activeLeases, err := parseLeases()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue