From 5f10c27b0fedde9890fcce2a5e58ae0b3e901db5 Mon Sep 17 00:00:00 2001 From: Steven Polley Date: Sun, 14 Apr 2024 18:14:24 -0600 Subject: [PATCH] add knock sequence timeout This provides another layer of additional protection against sweep attacks by ensuring the correct sequence be entered rapidly, within 3 seconds by default. It also prevents a client from sitting stuck forever part way through an old knock sequence. --- hypd/server/packet.go | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/hypd/server/packet.go b/hypd/server/packet.go index 97b5b7c..edf5486 100644 --- a/hypd/server/packet.go +++ b/hypd/server/packet.go @@ -25,9 +25,8 @@ import ( // Client is used to keep track of a client attempting to perform an authentic knock sequence type Client struct { - Progress int // index of current progress in sequence. Value of 1 means first port has been matched - Sequence [4]uint16 // stores the knock sequence the current client is attempting. It's set and tracked here to prevent race conditions during a knock sequence being received and key rotations - LastUpdated time.Time // The last time the client sent a correct packet in the sequence + Progress int // index of current progress in sequence. Value of 1 means first port has been matched + Sequence [4]uint16 // stores the knock sequence the current client is attempting. It's set and tracked here to prevent race conditions during a knock sequence being received and key rotations } // KnockSequence is used keep track of an ordered knock sequence and whether it's been marked for use (to prevent replay attacks) @@ -36,6 +35,10 @@ type KnockSequence struct { PortSequence [4]uint16 // Each knock sequence is four ports long } +const ( + KnockSequenceTimeout = 3 // TBD: Make this a configurable value +) + var ( clients map[uint32]*Client // Contains a map of clients, key is IPv4 address knockSequences []KnockSequence // We have 3 valid knock sequences at any time to account for clock skew @@ -137,6 +140,7 @@ func handleKnock(knockEvent hyp_bpfKnockData) { // Create the client and mark the knock sequence as used clients[knockEvent.Srcip] = &Client{Progress: 1, Sequence: knockSequence.PortSequence} knockSequences[i].Used = true + go timeoutKnockSequence(knockEvent.Srcip) } } return @@ -160,10 +164,21 @@ func handleKnock(knockEvent hyp_bpfKnockData) { } } +// Remove the client after the timeout value has elapsed. This prevents a client from +// being indefinitely stuck part way through an old knock sequence. It's also helpful +// in preventing sweep attacks as the authentic knock sequence must be correctly entered +// within the timeout value from start to finish. +func timeoutKnockSequence(srcip uint32) { + time.Sleep(time.Second * KnockSequenceTimeout) + _, ok := clients[srcip] + if ok { + delete(clients, srcip) + } +} + // Used to rotate the authentic port knock sequence func rotateSequence() { for { - // Generate new knock sequences with time skew support t := time.Now().Add(time.Second * -30) for i := len(knockSequences); i < 3; i++ {