@@ -34,7 +34,9 @@ type Transport struct {
3434 ipToTarget map [string ]abstraction.TransportTarget
3535 idToTarget map [abstraction.PacketId ]abstraction.TransportTarget
3636
37- propagateFault bool
37+ propagateFault bool
38+ maxPacketInterval time.Duration
39+ lastPacketTime map [abstraction.PacketId ]time.Time
3840
3941 api abstraction.TransportAPI
4042
@@ -413,6 +415,8 @@ func (transport *Transport) handleUDPPacket(udpPacket udp.Packet) {
413415 transport .replicateFault (packet , transport .logger )
414416 }
415417
418+ transport .checkPacketInterval (packet .Id (), udpPacket .Timestamp )
419+
416420 // Send notification
417421 transport .api .Notification (NewPacketNotification (packet , srcAddr , dstAddr , udpPacket .Timestamp ))
418422
@@ -421,6 +425,34 @@ func (transport *Transport) handleUDPPacket(udpPacket udp.Packet) {
421425 }
422426}
423427
428+ // checkPacketInterval propagates a fault when the time between two consecutive
429+ // UDP packets with the same id exceeds maxPacketInterval. Fault packets (id 0)
430+ // are excluded. lastPacketTime needs no locking because this is only called
431+ // from the HandleUDPServer goroutine.
432+ func (transport * Transport ) checkPacketInterval (id abstraction.PacketId , timestamp time.Time ) {
433+ if ! transport .propagateFault || transport .maxPacketInterval <= 0 || id == 0 {
434+ return
435+ }
436+
437+ last , seen := transport .lastPacketTime [id ]
438+ transport .lastPacketTime [id ] = timestamp
439+ if ! seen {
440+ return
441+ }
442+
443+ interval := timestamp .Sub (last )
444+ if interval <= transport .maxPacketInterval {
445+ return
446+ }
447+
448+ transport .logger .Warn ().
449+ Uint16 ("id" , uint16 (id )).
450+ Dur ("interval" , interval ).
451+ Dur ("threshold" , transport .maxPacketInterval ).
452+ Msg ("packet interval exceeded, propagating fault" )
453+ transport .SendFault ()
454+ }
455+
424456// handleConversation is called when the sniffer detects a new conversation and handles its specific packets
425457func (transport * Transport ) handleConversation (socket network.Socket , reader io.Reader ) {
426458 srcAddr := fmt .Sprintf ("%s:%d" , socket .SrcIP , socket .SrcPort )
@@ -473,3 +505,10 @@ func (transport *Transport) SendFault() {
473505func (transport * Transport ) SetpropagateFault (enabled bool ) {
474506 transport .propagateFault = enabled
475507}
508+
509+ // SetMaxPacketInterval sets the maximum allowed interval between two
510+ // consecutive UDP packets of the same id before a fault is propagated.
511+ // A non-positive interval disables the check.
512+ func (transport * Transport ) SetMaxPacketInterval (interval time.Duration ) {
513+ transport .maxPacketInterval = interval
514+ }
0 commit comments