update
This commit is contained in:
@@ -1,116 +1,208 @@
|
||||
package packet
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// Packet Types
|
||||
PacketTypeData = 0x00
|
||||
PacketTypeAnnounce = 0x01
|
||||
PacketTypeLink = 0x02
|
||||
PacketTypeProof = 0x03
|
||||
PACKET_TYPE_DATA = 0x00
|
||||
PACKET_TYPE_LINK = 0x01
|
||||
PACKET_TYPE_IDENTIFY = 0x02
|
||||
PacketTypeData = 0x00
|
||||
PacketTypeAnnounce = 0x01
|
||||
PacketTypeLinkReq = 0x02
|
||||
PacketTypeProof = 0x03
|
||||
|
||||
// Sizes
|
||||
HeaderSize = 2
|
||||
AddressSize = 16
|
||||
ContextSize = 1
|
||||
MaxDataSize = 465
|
||||
RandomBlobSize = 16
|
||||
// Header Types
|
||||
HeaderType1 = 0x00
|
||||
HeaderType2 = 0x01
|
||||
|
||||
// Context Types
|
||||
ContextNone = 0x00
|
||||
ContextResource = 0x01
|
||||
ContextResourceAdv = 0x02
|
||||
ContextResourceReq = 0x03
|
||||
ContextResourceHMU = 0x04
|
||||
ContextResourcePRF = 0x05
|
||||
ContextResourceICL = 0x06
|
||||
ContextResourceRCL = 0x07
|
||||
ContextCacheReq = 0x08
|
||||
ContextRequest = 0x09
|
||||
ContextResponse = 0x0A
|
||||
ContextPathResponse = 0x0B
|
||||
ContextCommand = 0x0C
|
||||
ContextCmdStatus = 0x0D
|
||||
ContextChannel = 0x0E
|
||||
ContextKeepalive = 0xFA
|
||||
ContextLinkIdentify = 0xFB
|
||||
ContextLinkClose = 0xFC
|
||||
ContextLinkProof = 0xFD
|
||||
ContextLRRTT = 0xFE
|
||||
ContextLRProof = 0xFF
|
||||
|
||||
// Flag Values
|
||||
FlagSet = 0x01
|
||||
FlagUnset = 0x00
|
||||
|
||||
// Header sizes
|
||||
HeaderMaxSize = 64
|
||||
MTU = 500
|
||||
|
||||
AddressSize = 32 // Size of address/hash fields in bytes
|
||||
)
|
||||
|
||||
// Header flags and types
|
||||
const (
|
||||
// First byte flags
|
||||
IFACFlag = 0x80
|
||||
HeaderTypeFlag = 0x40
|
||||
ContextFlag = 0x20
|
||||
PropagationFlags = 0x18
|
||||
DestinationFlags = 0x06
|
||||
PacketTypeFlags = 0x01
|
||||
|
||||
// Second byte
|
||||
HopsField = 0xFF
|
||||
)
|
||||
|
||||
// Packet represents a network packet in the Reticulum protocol
|
||||
type Packet struct {
|
||||
Header [2]byte
|
||||
Addresses []byte
|
||||
Context byte
|
||||
Data []byte
|
||||
AccessCode []byte
|
||||
RandomBlob []byte
|
||||
Timestamp time.Time
|
||||
HeaderType byte
|
||||
PacketType byte
|
||||
TransportType byte
|
||||
Context byte
|
||||
ContextFlag byte
|
||||
Hops byte
|
||||
|
||||
DestinationType byte
|
||||
DestinationHash []byte
|
||||
TransportID []byte
|
||||
Data []byte
|
||||
|
||||
Raw []byte
|
||||
Packed bool
|
||||
Sent bool
|
||||
CreateReceipt bool
|
||||
FromPacked bool
|
||||
|
||||
SentAt time.Time
|
||||
PacketHash []byte
|
||||
RatchetID []byte
|
||||
|
||||
RSSI *float64
|
||||
SNR *float64
|
||||
Q *float64
|
||||
|
||||
Addresses []byte // Add this field for address storage
|
||||
}
|
||||
|
||||
// NewPacket creates a new packet with the specified parameters
|
||||
func NewPacket(packetType byte, flags byte, hops byte, destKey []byte, data []byte) (*Packet, error) {
|
||||
if len(destKey) != AddressSize {
|
||||
return nil, errors.New("invalid destination key length")
|
||||
func NewPacket(destType byte, data []byte, packetType byte, context byte,
|
||||
transportType byte, headerType byte, transportID []byte, createReceipt bool,
|
||||
contextFlag byte) *Packet {
|
||||
|
||||
return &Packet{
|
||||
HeaderType: headerType,
|
||||
PacketType: packetType,
|
||||
TransportType: transportType,
|
||||
Context: context,
|
||||
ContextFlag: contextFlag,
|
||||
Hops: 0,
|
||||
DestinationType: destType,
|
||||
Data: data,
|
||||
TransportID: transportID,
|
||||
CreateReceipt: createReceipt,
|
||||
Packed: false,
|
||||
Sent: false,
|
||||
FromPacked: false,
|
||||
}
|
||||
|
||||
p := &Packet{
|
||||
Header: [2]byte{flags, hops},
|
||||
Addresses: make([]byte, AddressSize),
|
||||
Data: data,
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
// Set packet type in flags
|
||||
p.Header[0] |= packetType & PacketTypeFlags
|
||||
|
||||
// Copy destination address
|
||||
copy(p.Addresses, destKey)
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Serialize converts the packet into a byte slice
|
||||
func (p *Packet) Pack() error {
|
||||
if p.Packed {
|
||||
return nil
|
||||
}
|
||||
|
||||
flags := (p.HeaderType << 6) | (p.ContextFlag << 5) |
|
||||
(p.TransportType << 4) | (p.DestinationType << 2) | p.PacketType
|
||||
|
||||
header := make([]byte, 0)
|
||||
header = append(header, flags)
|
||||
header = append(header, p.Hops)
|
||||
|
||||
if p.HeaderType == HeaderType2 && p.TransportID != nil {
|
||||
header = append(header, p.TransportID...)
|
||||
header = append(header, p.DestinationHash...)
|
||||
} else if p.HeaderType == HeaderType1 {
|
||||
header = append(header, p.DestinationHash...)
|
||||
} else {
|
||||
return errors.New("invalid header configuration")
|
||||
}
|
||||
|
||||
header = append(header, p.Context)
|
||||
p.Raw = append(header, p.Data...)
|
||||
|
||||
if len(p.Raw) > MTU {
|
||||
return errors.New("packet size exceeds MTU")
|
||||
}
|
||||
|
||||
p.Packed = true
|
||||
p.updateHash()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Packet) Unpack() error {
|
||||
if len(p.Raw) < 3 {
|
||||
return errors.New("packet too short")
|
||||
}
|
||||
|
||||
flags := p.Raw[0]
|
||||
p.Hops = p.Raw[1]
|
||||
|
||||
p.HeaderType = (flags & 0b01000000) >> 6
|
||||
p.ContextFlag = (flags & 0b00100000) >> 5
|
||||
p.TransportType = (flags & 0b00010000) >> 4
|
||||
p.DestinationType = (flags & 0b00001100) >> 2
|
||||
p.PacketType = flags & 0b00000011
|
||||
|
||||
dstLen := 16 // Truncated hash length
|
||||
|
||||
if p.HeaderType == HeaderType2 {
|
||||
if len(p.Raw) < 2*dstLen+3 {
|
||||
return errors.New("packet too short for header type 2")
|
||||
}
|
||||
p.TransportID = p.Raw[2 : dstLen+2]
|
||||
p.DestinationHash = p.Raw[dstLen+2 : 2*dstLen+2]
|
||||
p.Context = p.Raw[2*dstLen+2]
|
||||
p.Data = p.Raw[2*dstLen+3:]
|
||||
} else {
|
||||
if len(p.Raw) < dstLen+3 {
|
||||
return errors.New("packet too short for header type 1")
|
||||
}
|
||||
p.TransportID = nil
|
||||
p.DestinationHash = p.Raw[2 : dstLen+2]
|
||||
p.Context = p.Raw[dstLen+2]
|
||||
p.Data = p.Raw[dstLen+3:]
|
||||
}
|
||||
|
||||
p.Packed = false
|
||||
p.updateHash()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Packet) GetHash() []byte {
|
||||
hashable := p.getHashablePart()
|
||||
hash := sha256.Sum256(hashable)
|
||||
return hash[:]
|
||||
}
|
||||
|
||||
func (p *Packet) getHashablePart() []byte {
|
||||
hashable := []byte{p.Raw[0] & 0b00001111}
|
||||
if p.HeaderType == HeaderType2 {
|
||||
hashable = append(hashable, p.Raw[18:]...)
|
||||
} else {
|
||||
hashable = append(hashable, p.Raw[2:]...)
|
||||
}
|
||||
return hashable
|
||||
}
|
||||
|
||||
func (p *Packet) updateHash() {
|
||||
p.PacketHash = p.GetHash()
|
||||
}
|
||||
|
||||
func (p *Packet) Serialize() ([]byte, error) {
|
||||
totalSize := HeaderSize + len(p.Addresses) + ContextSize + len(p.Data)
|
||||
if p.AccessCode != nil {
|
||||
totalSize += len(p.AccessCode)
|
||||
if !p.Packed {
|
||||
if err := p.Pack(); err != nil {
|
||||
return nil, fmt.Errorf("failed to pack packet: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
buffer := make([]byte, totalSize)
|
||||
offset := 0
|
||||
p.Addresses = p.DestinationHash
|
||||
|
||||
// Write header
|
||||
copy(buffer[offset:], p.Header[:])
|
||||
offset += HeaderSize
|
||||
|
||||
// Write access code if present
|
||||
if p.AccessCode != nil {
|
||||
copy(buffer[offset:], p.AccessCode)
|
||||
offset += len(p.AccessCode)
|
||||
}
|
||||
|
||||
// Write addresses
|
||||
copy(buffer[offset:], p.Addresses)
|
||||
offset += len(p.Addresses)
|
||||
|
||||
// Write context
|
||||
buffer[offset] = p.Context
|
||||
offset += ContextSize
|
||||
|
||||
// Write data
|
||||
copy(buffer[offset:], p.Data)
|
||||
|
||||
return buffer, nil
|
||||
}
|
||||
|
||||
type AnnouncePacket struct {
|
||||
Header [2]byte
|
||||
DestHash []byte
|
||||
PublicKey []byte
|
||||
AppData []byte
|
||||
RandomBlob []byte
|
||||
Signature []byte
|
||||
HopCount byte
|
||||
Timestamp time.Time
|
||||
return p.Raw, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user