OpenNHP/opennhp · warning
received flood packet
Error message
received flood packet
What it means
validatePeer rejects packets that arrive sooner than MinimalRecvIntervalMs after the last accepted packet from the same peer (remoteSendTime < LastRemoteSendTime + minimal interval). This is a rate-limit/flood control: a peer (or attacker) sending packets faster than the allowed minimum interval is dropped and increments the threat count, eventually blocking the source address.
Solutions
- Increase the client's knock/send interval so it is at or above the responder's MinimalRecvIntervalMs.
- Add exponential backoff with jitter to client retry loops instead of fixed tight retries.
- Check for duplicate-send bugs in wrappers or plugins that might fire the same knock multiple times per event.
- If the source was blocked after repeated floods, unblock the address (firewall/block list on the AC or host) after fixing the client's send rate.
Example fix
// before: agent config knocks faster than server minimum [knock] intervalMs = 100 // after: respect server MinimalRecvIntervalMs [knock] intervalMs = 1000
Defensive patterns
Strategy: validation
Validate before calling
// client-side: enforce the server's minimum interval before sending
const minimalRecvIntervalMs = int64(1000) // match server MinimalRecvIntervalMs
if now-lastSendMs < minimalRecvIntervalMs {
time.Sleep(time.Duration(minimalRecvIntervalMs-(now-lastSendMs)) * time.Millisecond)
}
lastSendMs = time.Now().UnixMilli() Try / catch
if err := sendKnock(pkt); err != nil && strings.Contains(err.Error(), "flood packet") {
// back off exponentially before the next attempt
backoff := min(2*backoff, maxBackoff)
time.Sleep(backoff + jitter())
} Prevention
- Configure client intervals at or above the server's MinimalRecvIntervalMs
- Use exponential backoff with jitter in all retry loops
- Audit plugins/wrappers for duplicate sends per event
- Watch threat-count/block logs to detect runaway clients before they get blocked
When it happens
Trigger: A remote endpoint sends NHP packets with send timestamps less than MinimalRecvIntervalMs apart from the previously accepted one — e.g. a tight knock retry loop, a misconfigured agent with an interval below the server's MinimalRecvIntervalMs, or a flood attack.
Common situations: Agent retry/backoff configured shorter than the server's minimum recv interval, a bug causing duplicate sends per knock, stress-testing or load tooling hammering the responder, deliberate DoS attempts (which escalate to SendBlockSignal once the threat count passes ThreatCountBeforeBlock).
Related errors
- peer does not match its previous address on this connection
- received replay packet
- invalid resource ID: potential path traversal attack
- invalid file name
- unexpected signing method
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/31d7b304dec3f41f.
Report an issue: GitHub.
Appendix: source
Thrown at nhp/core/responder.go:594
atomic.StoreInt32(&ppd.ConnData.RecvThreatCount, ThreatCountBeforeBlock)
// block source address
ppd.ConnData.SendBlockSignal()
}
err = fmt.Errorf("received replay packet")
return err
}
if remoteSendTime < ppd.ConnData.LastRemoteSendTime+MinimalRecvIntervalMs*int64(time.Millisecond) {
// flood packet, drop
log.Critical("received flood packet from %s, drop packet", ppd.ConnData.RemoteAddr.String())
// threat plus 1
threat := atomic.AddInt32(&ppd.ConnData.RecvThreatCount, 1)
if threat > ThreatCountBeforeBlock && !ppd.ConnData.IsClosed() {
// clamp threat count to avoid overflow
atomic.StoreInt32(&ppd.ConnData.RecvThreatCount, ThreatCountBeforeBlock)
// block source address
ppd.ConnData.SendBlockSignal()
}
err = fmt.Errorf("received flood packet")
return err
}
}
if remoteSendTime < (ppd.LocalInitTime - 600*int64(time.Second)) {
// send remote timestamp is too old than receive local time, drop
// note there might be time calibration error between remote and local devices
log.Critical("received stale packet from %s, drop packet", ppd.ConnData.RemoteAddr.String())
threat := atomic.AddInt32(&ppd.ConnData.RecvThreatCount, 1)
if threat > ThreatCountBeforeBlock && !ppd.ConnData.IsClosed() {
// clamp threat count to avoid overflow
atomic.StoreInt32(&ppd.ConnData.RecvThreatCount, ThreatCountBeforeBlock)
// block source address
ppd.ConnData.SendBlockSignal()
}
err = fmt.Errorf("received stale packet")
return err
}
View on GitHub (pinned to 6e04ca5ff0)