Skip to content

Commit 9189a23

Browse files
authored
feat(daemon): wildcard '*' bypass for rate-limit whitelists (PILOT-343/344/345) (#226)
* feat(daemon): SYN-whitelist wildcard + MatchAll proxies (PILOT-343) * feat(keyexchange): reply-whitelist wildcard (PILOT-344) * feat(tunnel): rekey-whitelist wildcard + reply-MatchAll proxy (PILOT-344/345) * feat(cmd): wildcard '*' parsing for whitelist envs (PILOT-343/344/345)
1 parent ecf5dd6 commit 9189a23

4 files changed

Lines changed: 96 additions & 9 deletions

File tree

cmd/daemon/main.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,9 @@ func main() {
272272
// first inbound SYN/PILA/encrypted-frame already sees them. Each
273273
// helper tolerates empty/garbage input — bad tokens log a warning
274274
// 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)
275+
applyNodeIDWhitelist("syn", *synWhitelist, "PILOT_SYN_WHITELIST", d.SetSYNWhitelist, d.SetSYNWhitelistMatchAll)
276+
applyNodeIDWhitelist("reply", *replyWhitelist, "PILOT_REPLY_WHITELIST", d.SetReplyWhitelist, d.SetReplyWhitelistMatchAll)
277+
applyNodeIDWhitelist("rekey", *rekeyWhitelist, "PILOT_REKEY_WHITELIST", d.SetRekeyWhitelist, d.SetRekeyWhitelistMatchAll)
278278

279279
if err := d.Start(); err != nil {
280280
log.Fatalf("daemon start: %v", err)
@@ -361,14 +361,34 @@ func parseNodeIDs(s string) []uint32 {
361361
// comma-separated list, and applies via the provided setter. Logs one
362362
// line on success showing the count so deployments can sanity-check
363363
// what landed.
364-
func applyNodeIDWhitelist(name, flagVal, envName string, set func([]uint32)) {
364+
//
365+
// PILOT-343/344/345 wildcard: the literal tokens "*" and "all" mean
366+
// "every source bypasses this rate limit." Used on service-agent boxes
367+
// where the rate limit interferes with legitimate high-volume query
368+
// traffic. Wildcard takes effect via the matchAll setter; the per-ID
369+
// list is still applied (so a mixed list like "*,12345" works the
370+
// same as "*" alone — the bool just short-circuits the map lookup).
371+
func applyNodeIDWhitelist(name, flagVal, envName string, set func([]uint32), setAll func(bool)) {
365372
raw := flagVal
366373
if raw == "" {
367374
raw = os.Getenv(envName)
368375
}
369376
if raw == "" {
370377
return
371378
}
379+
all := false
380+
for _, t := range strings.Split(raw, ",") {
381+
t = strings.TrimSpace(t)
382+
if t == "*" || t == "all" {
383+
all = true
384+
break
385+
}
386+
}
387+
if all {
388+
setAll(true)
389+
log.Printf("%s-rate-limit whitelist: wildcard '*' — every source bypasses", name)
390+
return
391+
}
372392
ids := parseNodeIDs(raw)
373393
set(ids)
374394
log.Printf("%s-rate-limit whitelist configured: %d node(s)", name, len(ids))

pkg/daemon/daemon.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,13 @@ type Daemon struct {
372372
// under atomic.Pointer on the hot path to avoid locking. Populated
373373
// at startup via SetSYNWhitelist.
374374
synWhitelist atomic.Pointer[map[uint32]struct{}]
375+
// PILOT-343 wildcard: when true, every source bypasses both SYN
376+
// gates regardless of the synWhitelist contents. Set by passing
377+
// "*" via env / -syn-whitelist, or directly via
378+
// SetSYNWhitelistMatchAll(true). Used on service-agent boxes
379+
// where the SYN-flood protection blocks legitimate high-volume
380+
// query traffic.
381+
synWhitelistAll atomic.Bool
375382

376383
// Network port policies: netID -> allowed ports (nil/empty = all allowed)
377384
netPolicyMu sync.RWMutex
@@ -563,6 +570,30 @@ func (d *Daemon) SetSYNWhitelist(nodeIDs []uint32) {
563570
d.synWhitelist.Store(&m)
564571
}
565572

573+
// SetSYNWhitelistMatchAll toggles SYN wildcard mode (PILOT-343). When
574+
// true, every source bypasses both SYN gates regardless of the
575+
// SetSYNWhitelist contents. Use on service-agent boxes that should
576+
// accept all callers without SYN-rate limiting.
577+
func (d *Daemon) SetSYNWhitelistMatchAll(on bool) {
578+
d.synWhitelistAll.Store(on)
579+
}
580+
581+
// SetReplyWhitelistMatchAll proxies to the embedded keyexchange.Manager
582+
// (PILOT-344 wildcard).
583+
func (d *Daemon) SetReplyWhitelistMatchAll(on bool) {
584+
if d.tunnels != nil {
585+
d.tunnels.SetReplyWhitelistMatchAll(on)
586+
}
587+
}
588+
589+
// SetRekeyWhitelistMatchAll proxies to the TunnelManager (PILOT-345
590+
// wildcard).
591+
func (d *Daemon) SetRekeyWhitelistMatchAll(on bool) {
592+
if d.tunnels != nil {
593+
d.tunnels.SetRekeyWhitelistMatchAll(on)
594+
}
595+
}
596+
566597
// SetReplyWhitelist proxies to the embedded keyexchange.Manager (PILOT-344).
567598
// Trusted peers bypass the 1-second asymmetric-recovery reply gate.
568599
func (d *Daemon) SetReplyWhitelist(nodeIDs []uint32) {
@@ -2745,7 +2776,9 @@ func (d *Daemon) handleStreamPacket(pkt *protocol.Packet) {
27452776
// where the SYN-flood protection would otherwise interfere with
27462777
// legitimate high-rate connection bursts.
27472778
synWhitelisted := false
2748-
if wl := d.synWhitelist.Load(); wl != nil {
2779+
if d.synWhitelistAll.Load() {
2780+
synWhitelisted = true
2781+
} else if wl := d.synWhitelist.Load(); wl != nil {
27492782
if _, ok := (*wl)[pkt.Src.Node]; ok {
27502783
synWhitelisted = true
27512784
}

pkg/daemon/keyexchange/keyexchange.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ type Manager struct {
251251
// Read on the hot path under atomic.Pointer; populated at startup
252252
// via SetReplyWhitelist.
253253
replyWhitelist atomic.Pointer[map[uint32]struct{}]
254+
// PILOT-344 wildcard: when true, every peer bypasses the reply
255+
// interval gate regardless of replyWhitelist contents. Used on
256+
// service-agent boxes that respond to many distinct callers.
257+
replyWhitelistAll atomic.Bool
254258

255259
// Side-effect hooks plumbed in from the daemon.
256260
sender FrameSender
@@ -584,9 +588,12 @@ func (m *Manager) MarkReplyKeyExchangeSent(peerNodeID uint32) bool {
584588
// PILOT-344: trusted-peer whitelist bypasses the interval gate.
585589
// The check is outside rkPendingMu so an atomic.Pointer load is all
586590
// we need; we still record the timestamp below for consistency with
587-
// the cleanup loop.
591+
// the cleanup loop. The wildcard (replyWhitelistAll) lets
592+
// service-agent boxes pass every caller.
588593
whitelisted := false
589-
if wl := m.replyWhitelist.Load(); wl != nil {
594+
if m.replyWhitelistAll.Load() {
595+
whitelisted = true
596+
} else if wl := m.replyWhitelist.Load(); wl != nil {
590597
if _, ok := (*wl)[peerNodeID]; ok {
591598
whitelisted = true
592599
}
@@ -620,6 +627,12 @@ func (m *Manager) SetReplyWhitelist(nodeIDs []uint32) {
620627
m.replyWhitelist.Store(&wm)
621628
}
622629

630+
// SetReplyWhitelistMatchAll toggles wildcard mode (PILOT-344). When
631+
// true, every peer bypasses MarkReplyKeyExchangeSent's interval gate.
632+
func (m *Manager) SetReplyWhitelistMatchAll(on bool) {
633+
m.replyWhitelistAll.Store(on)
634+
}
635+
623636
// RemovePeer wipes per-peer L5 state (called from TunnelManager.RemovePeer).
624637
func (m *Manager) RemovePeer(nodeID uint32) {
625638
m.pubKeysMu.Lock()

pkg/daemon/tunnel.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ type TunnelManager struct {
143143
// Whitelisted peers can always trigger a rekey request without
144144
// being throttled or counted against the 4096 bound.
145145
rekeyWhitelist atomic.Pointer[map[uint32]struct{}]
146+
// PILOT-345 wildcard: when true, every peer bypasses both the
147+
// rekeyRequestInterval gate and the maxRekeyRequesters map cap.
148+
// Used on service-agent boxes where all rekey requests should be
149+
// honored without rate-limiting.
150+
rekeyWhitelistAll atomic.Bool
146151

147152
// routing is the L4 manager. It owns:
148153
// - relayPeers, relayPinned, blackholeMissCount, directClearCount,
@@ -411,9 +416,12 @@ func (tm *TunnelManager) maybeRequestRekey(peerNodeID uint32, from *net.UDPAddr)
411416
}
412417
// PILOT-345: whitelisted peers skip both the interval gate and the
413418
// map cap. They still record a timestamp so the prune sweep can
414-
// reclaim entries if the whitelist shrinks later.
419+
// reclaim entries if the whitelist shrinks later. The wildcard
420+
// (rekeyWhitelistAll) lets service-agent boxes pass every peer.
415421
whitelisted := false
416-
if wl := tm.rekeyWhitelist.Load(); wl != nil {
422+
if tm.rekeyWhitelistAll.Load() {
423+
whitelisted = true
424+
} else if wl := tm.rekeyWhitelist.Load(); wl != nil {
417425
if _, ok := (*wl)[peerNodeID]; ok {
418426
whitelisted = true
419427
}
@@ -559,6 +567,19 @@ func (tm *TunnelManager) SetRekeyWhitelist(nodeIDs []uint32) {
559567
tm.rekeyWhitelist.Store(&wm)
560568
}
561569

570+
// SetRekeyWhitelistMatchAll toggles wildcard mode (PILOT-345). When
571+
// true, every peer bypasses both the rekeyRequestInterval gate and
572+
// the maxRekeyRequesters cap.
573+
func (tm *TunnelManager) SetRekeyWhitelistMatchAll(on bool) {
574+
tm.rekeyWhitelistAll.Store(on)
575+
}
576+
577+
// SetReplyWhitelistMatchAll proxies wildcard toggle to the embedded
578+
// keyexchange.Manager (PILOT-344 wildcard).
579+
func (tm *TunnelManager) SetReplyWhitelistMatchAll(on bool) {
580+
tm.kx.SetReplyWhitelistMatchAll(on)
581+
}
582+
562583
// SetReplyWhitelist is the cmd/daemon-facing proxy that forwards to the
563584
// embedded keyexchange.Manager (PILOT-344). Trusted peers bypass the
564585
// 1-second asymmetric-recovery reply gate.

0 commit comments

Comments
 (0)