implement nonce per-route check

This commit is contained in:
mykola2312 2025-01-13 08:49:28 +02:00
parent 6ae1fee758
commit 15897003a0
3 changed files with 42 additions and 7 deletions

View file

@ -41,6 +41,10 @@ func (list *LuxNonceList) RotateOrFail(newNonce uint64) bool {
return true
}
func (list *LuxNonceList) Flush() {
list.nonces = make([]uint64, 0)
}
func (list *LuxNonceList) Get(idx int) uint64 {
return list.nonces[idx]
}

View file

@ -18,7 +18,7 @@ const (
LuxPacketTypeSync = 1
)
const LUX_PROTO_PACKET_HDRLEN = proto.LUX_PROTO_ID_SIZE + 2
const LUX_PROTO_PACKET_HDRLEN = 8 + proto.LUX_PROTO_ID_SIZE + 2
// Target, Type are decoded from header
// Buffer contains LuxBuffer with stripped headers
@ -28,6 +28,7 @@ const LUX_PROTO_PACKET_HDRLEN = proto.LUX_PROTO_ID_SIZE + 2
// Target (ID) is rather confusing. What it actually describes is
// associated key with route.
type LuxPacket struct {
Nonce uint64
Target proto.LuxID
Type LuxPacketType
Buffer proto.LuxBuffer
@ -52,6 +53,13 @@ func DecryptLuxPacket(dgram LuxDatagram, key crypto.LuxKey) (LuxPacket, error) {
decrypter.CryptBlocks(payload, dgram.Payload)
packet.Buffer = proto.FromSlice(payload)
if nonce, err := packet.Buffer.ReadUint64(); err == nil {
packet.Nonce = nonce
} else {
return packet, err
}
if err := packet.Target.Read(&packet.Buffer); err != nil {
return packet, err
@ -99,6 +107,8 @@ func EncryptLuxPacket(packet LuxPacket, key crypto.LuxKey, target *net.UDPAddr)
}
wd := proto.AllocLuxBuffer(packetLen + paddingLen)
wd.WriteUint64(packet.Nonce)
key.Id.Write(&wd)
wd.WriteUint16(uint16(packet.Type))
wd.WriteBytes(packet.Buffer.AllBytes())

View file

@ -14,6 +14,7 @@ type LuxRoute struct {
Key crypto.LuxKey
Destination *net.UDPAddr
Associated *LuxChannel
Nonces LuxNonceList
}
type LuxRouter struct {
@ -83,6 +84,7 @@ func (r *LuxRouter) CreateOutboundRoute(id proto.LuxID, chType LuxChannelType, u
Key: key,
Destination: channel.Address,
Associated: r.addOutboundChannel(channel),
Nonces: NewLuxNonceList(),
})
return nil
}
@ -97,6 +99,7 @@ func (r *LuxRouter) CreateInboundChannel(chType LuxChannelType, udpAddr string)
Key: r.thisKey,
Destination: channel.Address,
Associated: r.addInboundChannel(channel),
Nonces: NewLuxNonceList(),
})
return nil
}
@ -216,6 +219,11 @@ func (r *LuxRouter) Recv() (LuxPacket, error) {
var err error
var packet LuxPacket
/* BUG:
* nodes share same UUID. When updating routes by UUID, it will overwrite others' nodes routes.
* this is current limitation of protocol
*/
// first we look key from routes
if route, ok := r.GetRoute(dgram.Target); ok {
packet, err = DecryptLuxPacket(dgram, route.Key)
@ -230,11 +238,11 @@ func (r *LuxRouter) Recv() (LuxPacket, error) {
r.DeleteRoute(&route)
return packet, errors.New("bogus packet from established route")
/* NOTE:
* there may be rare situation where multiple clients behind NAT/CGNAT
* reusing same IP:Port of established route, confusing routing table.
* This is not critical, since hosts and nodes are expected to send
* data again after interval of time, and packet loss is expected and
* tolerated at protocol design level.
* there may be rare situation where multiple clients behind NAT/CGNAT
* reusing same IP:Port of established route, confusing routing table.
* This is not critical, since hosts and nodes are expected to send
* data again after interval of time, and packet loss is expected and
* tolerated at protocol design level.
*/
}
@ -250,16 +258,27 @@ func (r *LuxRouter) Recv() (LuxPacket, error) {
if bytes.Equal(packet.Target.UUID[:], key.Id.UUID[:]) {
// key UUID and decrypted UUID matching - create OR update route and return packet
var route *LuxRoute
if _, idx := r.getRouteIndexByID(packet.Target); idx != -1 {
route := &r.routes[idx]
route = &r.routes[idx]
route.Destination = dgram.Target
route.Associated = dgram.Channel
// since packet arrived from different transport, we flush nonces
route.Nonces.Flush()
} else {
r.routes = append(r.routes, LuxRoute{
Key: key,
Destination: dgram.Target,
Associated: dgram.Channel,
Nonces: NewLuxNonceList(),
})
route = &r.routes[len(r.routes)-1]
}
// rotate nonce
if !route.Nonces.RotateOrFail(packet.Nonce) {
// failed nonce, discard packet
return packet, fmt.Errorf("packet failed nonce check")
}
packet.ChannelType = dgram.Channel.Type
@ -277,6 +296,7 @@ func (r *LuxRouter) Send(packet LuxPacket) error {
return errors.New("no route to peer")
}
packet.Nonce = GenerateLuxNonce()
dgram, err := EncryptLuxPacket(packet, route.Key, route.Destination)
if err != nil {
return err
@ -289,6 +309,7 @@ func (r *LuxRouter) Send(packet LuxPacket) error {
func (r *LuxRouter) Multicast(packet LuxPacket) error {
for _, route := range r.routes {
if bytes.Equal(route.Key.Id.UUID[:], packet.Target.UUID[:]) {
packet.Nonce = GenerateLuxNonce()
dgram, err := EncryptLuxPacket(packet, route.Key, route.Destination)
if err != nil {
return err