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

  1. Increase the client's knock/send interval so it is at or above the responder's MinimalRecvIntervalMs.
  2. Add exponential backoff with jitter to client retry loops instead of fixed tight retries.
  3. Check for duplicate-send bugs in wrappers or plugins that might fire the same knock multiple times per event.
  4. 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

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


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)