p1.1: dynamic self-IP deny (DDNS/trace, keep previous, atomic swap)

Discover WAN via ddns:<host> then trace:<url> before listen. Persist to
self_ip.json. Previous addresses stay denied for keep_previous. Failure
keeps the last known set. /healthz reports age and source.
This commit is contained in:
2026-09-22 22:59:08 -07:00
parent dca635fb62
commit 447842f860
8 changed files with 767 additions and 20 deletions
+51
View File
@@ -0,0 +1,51 @@
package config
import (
"os"
"time"
"github.com/pelletier/go-toml/v2"
)
// File is the on-disk /etc/sift/config.toml.
type File struct {
Listen string `toml:"listen"`
UserAgent string `toml:"user_agent"`
DenyPrefixes []string `toml:"deny_prefixes"`
SelfIP SelfIP `toml:"self_ip"`
}
// SelfIP is the [self_ip] block.
type SelfIP struct {
Sources []string `toml:"sources"`
Interval string `toml:"interval"`
KeepPrevious string `toml:"keep_previous"`
Path string `toml:"path"`
}
// Load reads path. A missing file returns a zero File and a nil error.
func Load(path string) (File, error) {
var f File
b, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return f, nil
}
return f, err
}
if err := toml.Unmarshal(b, &f); err != nil {
return File{}, err
}
return f, nil
}
func ParseDuration(s string, def time.Duration) time.Duration {
if s == "" {
return def
}
d, err := time.ParseDuration(s)
if err != nil {
return def
}
return d
}