Skip to content

Commit ecf5dd6

Browse files
authored
feat(daemon): wire rate-limit whitelist CLI flags + env (PILOT-343/344/345) (#225)
* feat(tunnel): SetReplyWhitelist proxy for keyexchange Manager (PILOT-344 wiring) * feat(daemon): SetReplyWhitelist + SetRekeyWhitelist proxies (PILOT-344, PILOT-345) * feat(cmd): wire -syn/reply/rekey-whitelist CLI flags + env (PILOT-343/344/345)
1 parent d04faee commit ecf5dd6

3 files changed

Lines changed: 80 additions & 0 deletions

File tree

cmd/daemon/main.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ func main() {
6767
synRate := flag.Int("syn-rate-limit", 0, "max SYN packets per second (default 100)")
6868
maxConnsPerPort := flag.Int("max-conns-per-port", 0, "max connections per port (default 1024)")
6969
maxConnsTotal := flag.Int("max-conns-total", 0, "max total connections (default 4096)")
70+
// PILOT-343/344/345 rate-limit whitelists. Comma-separated trusted-peer
71+
// node IDs (decimal uint32). Env fallbacks let deployments configure
72+
// without editing flag strings. Empty default preserves backwards
73+
// compatibility — fleets that don't set them behave exactly as before.
74+
synWhitelist := flag.String("syn-whitelist", "", "PILOT-343: comma-separated trusted source node IDs that bypass the SYN rate limit. Env: PILOT_SYN_WHITELIST.")
75+
replyWhitelist := flag.String("reply-whitelist", "", "PILOT-344: comma-separated trusted peer node IDs that bypass the keyexchange reply interval gate. Env: PILOT_REPLY_WHITELIST.")
76+
rekeyWhitelist := flag.String("rekey-whitelist", "", "PILOT-345: comma-separated trusted peer node IDs that bypass the tunnel-rekey interval and 4096 cap. Env: PILOT_REKEY_WHITELIST.")
7077
timeWait := flag.Duration("time-wait", 0, "TIME_WAIT duration (default 10s)")
7178
public := flag.Bool("public", false, "make this node's endpoint publicly visible (default: private)")
7279
relayOnly := flag.Bool("relay-only", false, "hide real_addr from peers; reach this node only via beacon-relay path. Privacy stance: peers cannot enumerate this daemon's public IP. Trade-off: relay adds one beacon hop. Default false (current direct-first behavior).")
@@ -260,6 +267,15 @@ func main() {
260267
if err := rt.StartPlugins(context.Background()); err != nil {
261268
log.Fatalf("plugin startup: %v", err)
262269
}
270+
271+
// PILOT-343/344/345: apply rate-limit whitelists BEFORE Start so the
272+
// first inbound SYN/PILA/encrypted-frame already sees them. Each
273+
// helper tolerates empty/garbage input — bad tokens log a warning
274+
// and are dropped so a typo in env doesn't fail-fast the daemon.
275+
applyNodeIDWhitelist("syn", *synWhitelist, "PILOT_SYN_WHITELIST", d.SetSYNWhitelist)
276+
applyNodeIDWhitelist("reply", *replyWhitelist, "PILOT_REPLY_WHITELIST", d.SetReplyWhitelist)
277+
applyNodeIDWhitelist("rekey", *rekeyWhitelist, "PILOT_REKEY_WHITELIST", d.SetRekeyWhitelist)
278+
263279
if err := d.Start(); err != nil {
264280
log.Fatalf("daemon start: %v", err)
265281
}
@@ -317,3 +333,43 @@ func parseNetworkIDs(s string) []uint16 {
317333
}
318334
return ids
319335
}
336+
337+
// parseNodeIDs parses a comma-separated string of uint32 node IDs.
338+
// Garbage tokens are logged and skipped — a typo in env shouldn't
339+
// fail-fast the daemon.
340+
func parseNodeIDs(s string) []uint32 {
341+
if s == "" {
342+
return nil
343+
}
344+
var ids []uint32
345+
for _, p := range strings.Split(s, ",") {
346+
p = strings.TrimSpace(p)
347+
if p == "" {
348+
continue
349+
}
350+
n, err := strconv.ParseUint(p, 10, 32)
351+
if err != nil {
352+
log.Printf("warning: invalid node ID %q: %v", p, err)
353+
continue
354+
}
355+
ids = append(ids, uint32(n))
356+
}
357+
return ids
358+
}
359+
360+
// applyNodeIDWhitelist resolves flag, falls back to env, parses the
361+
// comma-separated list, and applies via the provided setter. Logs one
362+
// line on success showing the count so deployments can sanity-check
363+
// what landed.
364+
func applyNodeIDWhitelist(name, flagVal, envName string, set func([]uint32)) {
365+
raw := flagVal
366+
if raw == "" {
367+
raw = os.Getenv(envName)
368+
}
369+
if raw == "" {
370+
return
371+
}
372+
ids := parseNodeIDs(raw)
373+
set(ids)
374+
log.Printf("%s-rate-limit whitelist configured: %d node(s)", name, len(ids))
375+
}

pkg/daemon/daemon.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,23 @@ func (d *Daemon) SetSYNWhitelist(nodeIDs []uint32) {
563563
d.synWhitelist.Store(&m)
564564
}
565565

566+
// SetReplyWhitelist proxies to the embedded keyexchange.Manager (PILOT-344).
567+
// Trusted peers bypass the 1-second asymmetric-recovery reply gate.
568+
func (d *Daemon) SetReplyWhitelist(nodeIDs []uint32) {
569+
if d.tunnels != nil {
570+
d.tunnels.SetReplyWhitelist(nodeIDs)
571+
}
572+
}
573+
574+
// SetRekeyWhitelist proxies to the TunnelManager (PILOT-345). Trusted
575+
// peers bypass the 3-second rekey-request interval and the 4096
576+
// requester-map cap.
577+
func (d *Daemon) SetRekeyWhitelist(nodeIDs []uint32) {
578+
if d.tunnels != nil {
579+
d.tunnels.SetRekeyWhitelist(nodeIDs)
580+
}
581+
}
582+
566583
func (d *Daemon) Start() error {
567584
// Warm the hostname cache from disk before the IPC server comes up,
568585
// so the first send-message after restart hits the cache instead of

pkg/daemon/tunnel.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,13 @@ func (tm *TunnelManager) SetRekeyWhitelist(nodeIDs []uint32) {
559559
tm.rekeyWhitelist.Store(&wm)
560560
}
561561

562+
// SetReplyWhitelist is the cmd/daemon-facing proxy that forwards to the
563+
// embedded keyexchange.Manager (PILOT-344). Trusted peers bypass the
564+
// 1-second asymmetric-recovery reply gate.
565+
func (tm *TunnelManager) SetReplyWhitelist(nodeIDs []uint32) {
566+
tm.kx.SetReplyWhitelist(nodeIDs)
567+
}
568+
562569
// SetBeaconAddr configures the beacon address for NAT hole-punching and relay.
563570
// Thin shim over routing.Manager.SetBeaconAddr.
564571
func (tm *TunnelManager) SetBeaconAddr(addr string) error {

0 commit comments

Comments
 (0)