add knock sequence timeout
All checks were successful
continuous-integration/drone/push Build is passing

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.
This commit is contained in:
Steven Polley 2024-04-14 18:14:24 -06:00
parent 0b876665d5
commit 5f10c27b0f

View File

@ -27,7 +27,6 @@ import (
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
}
// 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++ {