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 -4
View File
@@ -1,6 +1,7 @@
package main
import (
"context"
"flag"
"log/slog"
"net"
@@ -12,8 +13,10 @@ import (
"git.wntrmute.dev/kyle/sift/internal/api"
"git.wntrmute.dev/kyle/sift/internal/auth"
"git.wntrmute.dev/kyle/sift/internal/config"
"git.wntrmute.dev/kyle/sift/internal/fetch"
"git.wntrmute.dev/kyle/sift/internal/guard"
"git.wntrmute.dev/kyle/sift/internal/selfip"
)
type denyFlags []netip.Prefix
@@ -54,12 +57,30 @@ func serveMain() {
registerTestFlags(fs, g)
_ = fs.Parse(os.Args[1:])
g.DenyPrefixes = deny
log := slog.New(slog.NewTextHandler(os.Stdout, nil))
cfg, err := config.Load(*configPath)
if err != nil {
log.Error("config", "err", err, "path", *configPath)
os.Exit(1)
}
if *listen == "127.0.0.1:8890" && cfg.Listen != "" {
*listen = cfg.Listen
}
if *ua == "sift/"+version && cfg.UserAgent != "" {
*ua = cfg.UserAgent
}
for _, s := range cfg.DenyPrefixes {
p, err := netip.ParsePrefix(s)
if err != nil {
log.Error("deny_prefixes", "err", err, "value", s)
os.Exit(1)
}
deny = append(deny, p)
}
g.DenyPrefixes = deny
if n := len(deny); n > 0 {
log.Info("deny prefixes loaded", "count", n)
}
_ = configPath
store, err := auth.Load(*keysPath)
if err != nil {
@@ -68,9 +89,33 @@ func serveMain() {
}
fetcher := &fetch.Fetcher{Guard: g, UA: *ua}
srv := api.New(version, g, fetcher, store, log)
hs := srv.HTTPServer(*listen)
parent, stop := context.WithCancel(context.Background())
defer stop()
srv := api.New(version, g, fetcher, store, log)
if len(cfg.SelfIP.Sources) > 0 {
disc := &selfip.Discoverer{
Cfg: selfip.Config{
Sources: cfg.SelfIP.Sources,
Interval: config.ParseDuration(cfg.SelfIP.Interval, selfip.DefaultInterval),
KeepPrevious: config.ParseDuration(cfg.SelfIP.KeepPrevious, selfip.DefaultKeepPrevious),
Path: cfg.SelfIP.Path,
},
Guard: g,
Log: log,
Get: func(ctx context.Context, u string) ([]byte, error) {
res, err := fetcher.Fetch(ctx, u)
if err != nil {
return nil, err
}
return res.Body, nil
},
}
disc.Start(parent)
srv.SelfIP = disc
}
hs := srv.HTTPServer(*listen)
ln, err := net.Listen("tcp", *listen)
if err != nil {
log.Error("listen", "err", err)
@@ -96,8 +141,10 @@ func serveMain() {
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
select {
case <-sig:
stop()
_ = hs.Close()
case err := <-errCh:
stop()
if err != nil {
log.Error("serve", "err", err)
os.Exit(1)