Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions cmd/daemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,9 @@ func main() {
// first inbound SYN/PILA/encrypted-frame already sees them. Each
// helper tolerates empty/garbage input — bad tokens log a warning
// and are dropped so a typo in env doesn't fail-fast the daemon.
applyNodeIDWhitelist("syn", *synWhitelist, "PILOT_SYN_WHITELIST", d.SetSYNWhitelist)
applyNodeIDWhitelist("reply", *replyWhitelist, "PILOT_REPLY_WHITELIST", d.SetReplyWhitelist)
applyNodeIDWhitelist("rekey", *rekeyWhitelist, "PILOT_REKEY_WHITELIST", d.SetRekeyWhitelist)
applyNodeIDWhitelist("syn", *synWhitelist, "PILOT_SYN_WHITELIST", d.SetSYNWhitelist, d.SetSYNWhitelistMatchAll)
applyNodeIDWhitelist("reply", *replyWhitelist, "PILOT_REPLY_WHITELIST", d.SetReplyWhitelist, d.SetReplyWhitelistMatchAll)
applyNodeIDWhitelist("rekey", *rekeyWhitelist, "PILOT_REKEY_WHITELIST", d.SetRekeyWhitelist, d.SetRekeyWhitelistMatchAll)

if err := d.Start(); err != nil {
log.Fatalf("daemon start: %v", err)
Expand Down Expand Up @@ -361,14 +361,34 @@ func parseNodeIDs(s string) []uint32 {
// comma-separated list, and applies via the provided setter. Logs one
// line on success showing the count so deployments can sanity-check
// what landed.
func applyNodeIDWhitelist(name, flagVal, envName string, set func([]uint32)) {
//
// PILOT-343/344/345 wildcard: the literal tokens "*" and "all" mean
// "every source bypasses this rate limit." Used on service-agent boxes
// where the rate limit interferes with legitimate high-volume query
// traffic. Wildcard takes effect via the matchAll setter; the per-ID
// list is still applied (so a mixed list like "*,12345" works the
// same as "*" alone — the bool just short-circuits the map lookup).
func applyNodeIDWhitelist(name, flagVal, envName string, set func([]uint32), setAll func(bool)) {
raw := flagVal
if raw == "" {
raw = os.Getenv(envName)
}
if raw == "" {
return
}
all := false
for _, t := range strings.Split(raw, ",") {
t = strings.TrimSpace(t)
if t == "*" || t == "all" {
all = true
break
}
}
if all {
setAll(true)
log.Printf("%s-rate-limit whitelist: wildcard '*' — every source bypasses", name)
return
}
ids := parseNodeIDs(raw)
set(ids)
log.Printf("%s-rate-limit whitelist configured: %d node(s)", name, len(ids))
Expand Down
35 changes: 34 additions & 1 deletion pkg/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,13 @@ type Daemon struct {
// under atomic.Pointer on the hot path to avoid locking. Populated
// at startup via SetSYNWhitelist.
synWhitelist atomic.Pointer[map[uint32]struct{}]
// PILOT-343 wildcard: when true, every source bypasses both SYN
// gates regardless of the synWhitelist contents. Set by passing
// "*" via env / -syn-whitelist, or directly via
// SetSYNWhitelistMatchAll(true). Used on service-agent boxes
// where the SYN-flood protection blocks legitimate high-volume
// query traffic.
synWhitelistAll atomic.Bool

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

// SetSYNWhitelistMatchAll toggles SYN wildcard mode (PILOT-343). When
// true, every source bypasses both SYN gates regardless of the
// SetSYNWhitelist contents. Use on service-agent boxes that should
// accept all callers without SYN-rate limiting.
func (d *Daemon) SetSYNWhitelistMatchAll(on bool) {
d.synWhitelistAll.Store(on)
}

// SetReplyWhitelistMatchAll proxies to the embedded keyexchange.Manager
// (PILOT-344 wildcard).
func (d *Daemon) SetReplyWhitelistMatchAll(on bool) {
if d.tunnels != nil {
d.tunnels.SetReplyWhitelistMatchAll(on)
}
}

// SetRekeyWhitelistMatchAll proxies to the TunnelManager (PILOT-345
// wildcard).
func (d *Daemon) SetRekeyWhitelistMatchAll(on bool) {
if d.tunnels != nil {
d.tunnels.SetRekeyWhitelistMatchAll(on)
}
}

// SetReplyWhitelist proxies to the embedded keyexchange.Manager (PILOT-344).
// Trusted peers bypass the 1-second asymmetric-recovery reply gate.
func (d *Daemon) SetReplyWhitelist(nodeIDs []uint32) {
Expand Down Expand Up @@ -2745,7 +2776,9 @@ func (d *Daemon) handleStreamPacket(pkt *protocol.Packet) {
// where the SYN-flood protection would otherwise interfere with
// legitimate high-rate connection bursts.
synWhitelisted := false
if wl := d.synWhitelist.Load(); wl != nil {
if d.synWhitelistAll.Load() {
synWhitelisted = true
} else if wl := d.synWhitelist.Load(); wl != nil {
if _, ok := (*wl)[pkt.Src.Node]; ok {
synWhitelisted = true
}
Expand Down
17 changes: 15 additions & 2 deletions pkg/daemon/keyexchange/keyexchange.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ type Manager struct {
// Read on the hot path under atomic.Pointer; populated at startup
// via SetReplyWhitelist.
replyWhitelist atomic.Pointer[map[uint32]struct{}]
// PILOT-344 wildcard: when true, every peer bypasses the reply
// interval gate regardless of replyWhitelist contents. Used on
// service-agent boxes that respond to many distinct callers.
replyWhitelistAll atomic.Bool

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

// SetReplyWhitelistMatchAll toggles wildcard mode (PILOT-344). When
// true, every peer bypasses MarkReplyKeyExchangeSent's interval gate.
func (m *Manager) SetReplyWhitelistMatchAll(on bool) {
m.replyWhitelistAll.Store(on)
}

// RemovePeer wipes per-peer L5 state (called from TunnelManager.RemovePeer).
func (m *Manager) RemovePeer(nodeID uint32) {
m.pubKeysMu.Lock()
Expand Down
25 changes: 23 additions & 2 deletions pkg/daemon/tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ type TunnelManager struct {
// Whitelisted peers can always trigger a rekey request without
// being throttled or counted against the 4096 bound.
rekeyWhitelist atomic.Pointer[map[uint32]struct{}]
// PILOT-345 wildcard: when true, every peer bypasses both the
// rekeyRequestInterval gate and the maxRekeyRequesters map cap.
// Used on service-agent boxes where all rekey requests should be
// honored without rate-limiting.
rekeyWhitelistAll atomic.Bool

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

// SetRekeyWhitelistMatchAll toggles wildcard mode (PILOT-345). When
// true, every peer bypasses both the rekeyRequestInterval gate and
// the maxRekeyRequesters cap.
func (tm *TunnelManager) SetRekeyWhitelistMatchAll(on bool) {
tm.rekeyWhitelistAll.Store(on)
}

// SetReplyWhitelistMatchAll proxies wildcard toggle to the embedded
// keyexchange.Manager (PILOT-344 wildcard).
func (tm *TunnelManager) SetReplyWhitelistMatchAll(on bool) {
tm.kx.SetReplyWhitelistMatchAll(on)
}

// SetReplyWhitelist is the cmd/daemon-facing proxy that forwards to the
// embedded keyexchange.Manager (PILOT-344). Trusted peers bypass the
// 1-second asymmetric-recovery reply gate.
Expand Down
Loading