Finally moving Sequence code into protocol package

This commit is contained in:
Kleissner
2021-10-18 02:41:55 +02:00
parent 5d93a74981
commit f1e8e0cab8
4 changed files with 27 additions and 31 deletions

View File

@@ -48,8 +48,8 @@ const (
// MessageRaw is a high-level message between peers that has not been decoded
type MessageRaw struct {
protocol.PacketRaw
SenderPublicKey *btcec.PublicKey // Sender Public Key, ECDSA (secp256k1) 257-bit
SequenceInfo *SequenceExpiry // Sequence
SenderPublicKey *btcec.PublicKey // Sender Public Key, ECDSA (secp256k1) 257-bit
SequenceInfo *protocol.SequenceExpiry // Sequence
}
// MessageAnnouncement is the decoded announcement message.

View File

@@ -186,12 +186,14 @@ func (nets *Networks) packetWorker() {
case protocol.CommandResponse: // Response
if response, _ := msgDecodeResponse(raw); response != nil {
// Validate sequence number which prevents unsolicited responses.
if valid, rtt := nets.Sequences.ValidateSequence(raw, response.Actions&(1<<ActionSequenceLast) > 0); !valid {
sequenceInfo, valid, rtt := nets.Sequences.ValidateSequence(raw.SenderPublicKey, raw.Sequence, response.Actions&(1<<ActionSequenceLast) > 0, true)
if !valid {
//Filters.LogError("packetWorker", "message with invalid sequence %d command %d from %s\n", raw.Sequence, raw.Command, raw.connection.Address.String()) // Only log for debug purposes.
continue
} else if rtt > 0 {
connection.RoundTripTime = rtt
}
raw.SequenceInfo = sequenceInfo
// Update known internal/external port and User Agent
connection.PortInternal = response.PortInternal
@@ -228,12 +230,14 @@ func (nets *Networks) packetWorker() {
case protocol.CommandPong: // Ping
// Validate sequence number which prevents unsolicited responses.
if valid, rtt := nets.Sequences.ValidateSequence(raw, true); !valid {
sequenceInfo, valid, rtt := nets.Sequences.ValidateSequence(raw.SenderPublicKey, raw.Sequence, true, false)
if !valid {
//Filters.LogError("packetWorker", "message with invalid sequence %d command %d from %s\n", raw.Sequence, raw.Command, raw.connection.Address.String()) // Only log for debug purposes.
continue
} else if rtt > 0 {
connection.RoundTripTime = rtt
}
raw.SequenceInfo = sequenceInfo
Filters.MessageIn(peer, raw, nil)

View File

@@ -6,7 +6,11 @@ Author: Peter Kleissner
package core
import "sync"
import (
"sync"
"github.com/PeernetOfficial/core/protocol"
)
// Networks is the collection of all connected networks
type Networks struct {
@@ -24,7 +28,7 @@ type Networks struct {
rawPacketsIncoming chan networkWire
// Sequences keeps track of all message sequence number, regardless of the network connection.
Sequences *SequenceManager
Sequences *protocol.SequenceManager
// ipListen keeps a simple list of IPs listened to. This allows quickly identifying if an IP matches with a listened one.
ipListen *ipList
@@ -40,7 +44,7 @@ func initMessageSequence() {
networks.rawPacketsIncoming = make(chan networkWire, 1000) // buffer up to 1000 UDP packets before they get buffered by the OS network stack and eventually dropped
networks.Sequences = NewSequenceManager(ReplyTimeout)
networks.Sequences = protocol.NewSequenceManager(ReplyTimeout)
networks.ipListen = NewIPList()
}

View File

@@ -1,9 +1,10 @@
/*
File Name: Message Sequence.go
File Name: Sequence.go
Copyright: 2021 Peernet s.r.o.
Author: Peter Kleissner
Records and verifies message sequences. Sequence numbers are valid on a peer level, independent of which network connection was used.
This code caches and verifies message sequences. Sequence numbers are valid on a peer level, independent of which network connection was used.
They can be used to map incoming response messages to previous outgoing requests. The remote peer ID is used together with a consecutive sequence number as unique key.
Advantages:
* This secures against replay and poisoning attacks.
@@ -12,7 +13,7 @@ Advantages:
* (future) It can be used to detect missed and lost replies.
*/
package core
package protocol
import (
"math/rand"
@@ -21,7 +22,6 @@ import (
"sync/atomic"
"time"
"github.com/PeernetOfficial/core/protocol"
"github.com/btcsuite/btcd/btcec"
)
@@ -111,13 +111,8 @@ func (manager *SequenceManager) ArbitrarySequence(publicKey *btcec.PublicKey, da
}
// ValidateSequence validates the sequence number of an incoming message. It will set raw.sequence if valid.
func (manager *SequenceManager) ValidateSequence(raw *MessageRaw, invalidate bool) (valid bool, rtt time.Duration) {
// Only Response and Pong
if raw.Command != protocol.CommandResponse && raw.Command != protocol.CommandPong {
return true, rtt
}
key := string(raw.SenderPublicKey.SerializeCompressed()) + strconv.FormatUint(uint64(raw.Sequence), 10)
func (manager *SequenceManager) ValidateSequence(publicKey *btcec.PublicKey, sequenceNumber uint32, invalidate, extendValidity bool) (sequenceInfo *SequenceExpiry, valid bool, rtt time.Duration) {
key := string(publicKey.SerializeCompressed()) + strconv.FormatUint(uint64(sequenceNumber), 10)
manager.Lock()
defer manager.Unlock()
@@ -125,7 +120,7 @@ func (manager *SequenceManager) ValidateSequence(raw *MessageRaw, invalidate boo
// lookup the sequence
sequence, ok := manager.sequences[key]
if !ok {
return false, rtt
return nil, false, rtt
}
// Initial reply: Store latest roundtrip time. That value might be distorted on Response vs Pong since Response messages might send data
@@ -139,24 +134,17 @@ func (manager *SequenceManager) ValidateSequence(raw *MessageRaw, invalidate boo
// invalidate the sequence immediately?
if invalidate {
delete(manager.sequences, key)
} else if raw.Command == protocol.CommandResponse {
// Special case CommandResponse: Extend validity in case there are follow-up responses by half of the round-trip time since they will be sent one-way.
} else if extendValidity {
// Special case CommandResponse: Extend validity in case there are follow-up responses, by half of the round-trip time since they will be sent one-way.
sequence.expires = time.Now().Add(time.Duration(manager.ReplyTimeout) * time.Second / 2)
}
raw.SequenceInfo = sequence
return sequence.expires.After(time.Now()), rtt
return sequence, sequence.expires.After(time.Now()), rtt
}
// InvalidateSequence invalidates the sequence number.
func (manager *SequenceManager) InvalidateSequence(raw *MessageRaw) {
// Only Response
if raw.Command != protocol.CommandResponse {
return
}
key := string(raw.SenderPublicKey.SerializeCompressed()) + strconv.FormatUint(uint64(raw.Sequence), 10)
func (manager *SequenceManager) InvalidateSequence(publicKey *btcec.PublicKey, sequenceNumber uint32) {
key := string(publicKey.SerializeCompressed()) + strconv.FormatUint(uint64(sequenceNumber), 10)
manager.Lock()
delete(manager.sequences, key)