update packet creation

This commit is contained in:
Sudo-Ivan
2025-01-01 19:12:32 -06:00
parent 5acbef454f
commit 9508e6e195
4 changed files with 158 additions and 77 deletions

View File

@@ -62,7 +62,6 @@ type Reticulum struct {
} }
type announceRecord struct { type announceRecord struct {
// All fields were unused, so entire struct can be removed
} }
func NewReticulum(cfg *common.ReticulumConfig) (*Reticulum, error) { func NewReticulum(cfg *common.ReticulumConfig) (*Reticulum, error) {
@@ -70,6 +69,14 @@ func NewReticulum(cfg *common.ReticulumConfig) (*Reticulum, error) {
cfg = config.DefaultConfig() cfg = config.DefaultConfig()
} }
// Set default app name and aspect if not provided
if cfg.AppName == "" {
cfg.AppName = "Go Client"
}
if cfg.AppAspect == "" {
cfg.AppAspect = "node"
}
if err := initializeDirectories(); err != nil { if err := initializeDirectories(); err != nil {
return nil, fmt.Errorf("failed to initialize directories: %v", err) return nil, fmt.Errorf("failed to initialize directories: %v", err)
} }
@@ -269,6 +276,7 @@ func main() {
[]byte("HELLO WORLD"), []byte("HELLO WORLD"),
nil, nil,
false, false,
r.config,
) )
if err != nil { if err != nil {
log.Fatalf("Failed to create announce: %v", err) log.Fatalf("Failed to create announce: %v", err)
@@ -424,24 +432,27 @@ func (r *Reticulum) Start() error {
debugLog(3, "Interface %s started successfully", iface.GetName()) debugLog(3, "Interface %s started successfully", iface.GetName())
} }
// Create initial announce packet // Create initial announce
announceData := []byte("Reticulum-Go") initialAnnounce, err := announce.NewAnnounce(
announcePacket := transport.CreateAnnouncePacket(
r.identity.Hash(),
r.identity, r.identity,
announceData, []byte("Reticulum-Go"),
0, nil, // ratchetID
false, // pathResponse
r.config,
) )
if err != nil {
return fmt.Errorf("failed to create announce: %v", err)
}
// Wait briefly for interfaces to initialize // Wait briefly for interfaces to initialize
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
// Send initial announces on all enabled interfaces // Send initial announces
for _, iface := range r.interfaces { for _, iface := range r.interfaces {
if netIface, ok := iface.(common.NetworkInterface); ok { if netIface, ok := iface.(common.NetworkInterface); ok {
if netIface.IsEnabled() && netIface.IsOnline() { if netIface.IsEnabled() && netIface.IsOnline() {
debugLog(2, "Sending initial announce on interface %s", netIface.GetName()) debugLog(2, "Sending initial announce on interface %s", netIface.GetName())
if err := netIface.Send(announcePacket, ""); err != nil { if err := initialAnnounce.Propagate([]common.NetworkInterface{netIface}); err != nil {
debugLog(1, "Failed to send initial announce on interface %s: %v", netIface.GetName(), err) debugLog(1, "Failed to send initial announce on interface %s: %v", netIface.GetName(), err)
} }
} }
@@ -458,19 +469,24 @@ func (r *Reticulum) Start() error {
announceCount++ announceCount++
debugLog(3, "Starting periodic announce cycle #%d", announceCount) debugLog(3, "Starting periodic announce cycle #%d", announceCount)
// Create fresh announce packet for each cycle // Create fresh announce for each cycle
announcePacket := transport.CreateAnnouncePacket( periodicAnnounce, err := announce.NewAnnounce(
r.identity.Hash(),
r.identity, r.identity,
announceData, []byte("Reticulum-Go"),
0, nil, // ratchetID
false, // pathResponse
r.config,
) )
if err != nil {
debugLog(1, "Failed to create periodic announce: %v", err)
continue
}
for _, iface := range r.interfaces { for _, iface := range r.interfaces {
if netIface, ok := iface.(common.NetworkInterface); ok { if netIface, ok := iface.(common.NetworkInterface); ok {
if netIface.IsEnabled() && netIface.IsOnline() { if netIface.IsEnabled() && netIface.IsOnline() {
debugLog(2, "Sending periodic announce on interface %s", netIface.GetName()) debugLog(2, "Sending periodic announce on interface %s", netIface.GetName())
if err := netIface.Send(announcePacket, ""); err != nil { if err := periodicAnnounce.Propagate([]common.NetworkInterface{netIface}); err != nil {
debugLog(1, "Failed to send periodic announce on interface %s: %v", netIface.GetName(), err) debugLog(1, "Failed to send periodic announce on interface %s: %v", netIface.GetName(), err)
continue continue
} }

View File

@@ -60,6 +60,7 @@ type Announce struct {
destinationHash []byte destinationHash []byte
identity *identity.Identity identity *identity.Identity
appData []byte appData []byte
config *common.ReticulumConfig
hops uint8 hops uint8
timestamp int64 timestamp int64
signature []byte signature []byte
@@ -71,7 +72,7 @@ type Announce struct {
hash []byte hash []byte
} }
func New(dest *identity.Identity, appData []byte, pathResponse bool) (*Announce, error) { func New(dest *identity.Identity, appData []byte, pathResponse bool, config *common.ReticulumConfig) (*Announce, error) {
if dest == nil { if dest == nil {
return nil, errors.New("destination identity required") return nil, errors.New("destination identity required")
} }
@@ -80,6 +81,7 @@ func New(dest *identity.Identity, appData []byte, pathResponse bool) (*Announce,
mutex: &sync.RWMutex{}, mutex: &sync.RWMutex{},
identity: dest, identity: dest,
appData: appData, appData: appData,
config: config,
hops: 0, hops: 0,
timestamp: time.Now().Unix(), timestamp: time.Now().Unix(),
pathResponse: pathResponse, pathResponse: pathResponse,
@@ -287,11 +289,11 @@ func (a *Announce) CreatePacket() []byte {
headerByte := byte( headerByte := byte(
(IFAC_NONE) | (IFAC_NONE) |
(HEADER_TYPE_1 << 6) | (HEADER_TYPE_1 << 6) |
(0 << 5) | (0 << 5) |
(PROP_TYPE_BROADCAST << 4) | (PROP_TYPE_BROADCAST << 4) |
(DEST_TYPE_SINGLE << 2) | (DEST_TYPE_SINGLE << 2) |
PACKET_TYPE_ANNOUNCE, PACKET_TYPE_ANNOUNCE,
) )
log.Printf("[DEBUG-7] Created header byte: %02x, hops: %d", headerByte, a.hops) log.Printf("[DEBUG-7] Created header byte: %02x, hops: %d", headerByte, a.hops)
@@ -301,29 +303,31 @@ func (a *Announce) CreatePacket() []byte {
log.Printf("[DEBUG-7] Adding destination hash (16 bytes): %x", a.destinationHash) log.Printf("[DEBUG-7] Adding destination hash (16 bytes): %x", a.destinationHash)
packet = append(packet, a.destinationHash...) packet = append(packet, a.destinationHash...)
// Split public key into encryption and signing keys (32 bytes each) // Get full public key and split into encryption and signing keys
pubKey := a.identity.GetPublicKey() pubKey := a.identity.GetPublicKey()
encKey := pubKey[:32] encKey := pubKey[:32] // x25519 public key for encryption
signKey := pubKey[32:] signKey := pubKey[32:] // Ed25519 public key for signing
// Add encryption key (32 bytes)
log.Printf("[DEBUG-7] Adding encryption key (32 bytes): %x", encKey) log.Printf("[DEBUG-7] Adding encryption key (32 bytes): %x", encKey)
packet = append(packet, encKey...) packet = append(packet, encKey...)
// Add signing key (32 bytes)
log.Printf("[DEBUG-7] Adding signing key (32 bytes): %x", signKey) log.Printf("[DEBUG-7] Adding signing key (32 bytes): %x", signKey)
packet = append(packet, signKey...) packet = append(packet, signKey...)
// Add name hash (10 bytes) // Add name hash (10 bytes) - SHA256 hash of full name truncated to 10 bytes
nameHash := a.identity.GetNameHash() nameHash := sha256.Sum256([]byte(fmt.Sprintf("%s.%s", a.config.AppName, a.config.AppAspect)))
log.Printf("[DEBUG-7] Adding name hash (10 bytes): %x", nameHash) log.Printf("[DEBUG-7] Adding name hash (10 bytes): %x", nameHash[:10])
packet = append(packet, nameHash...) packet = append(packet, nameHash[:10]...)
// Add random hash (5 random + 5 timestamp bytes = 10 bytes) // Add random hash (5 random + 5 timestamp bytes = 10 bytes)
randomHash := make([]byte, 5) randomBytes := make([]byte, 5)
rand.Read(randomHash) rand.Read(randomBytes)
timeBytes := make([]byte, 8) timeBytes := make([]byte, 8)
binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix())) binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix()))
log.Printf("[DEBUG-7] Adding random hash (10 bytes): %x%x", randomHash, timeBytes[:5]) log.Printf("[DEBUG-7] Adding random hash (10 bytes): %x%x", randomBytes, timeBytes[:5])
packet = append(packet, randomHash...) packet = append(packet, randomBytes...)
packet = append(packet, timeBytes[:5]...) packet = append(packet, timeBytes[:5]...)
// Add ratchet if present (32 bytes) // Add ratchet if present (32 bytes)
@@ -332,12 +336,23 @@ func (a *Announce) CreatePacket() []byte {
packet = append(packet, a.ratchetID...) packet = append(packet, a.ratchetID...)
} }
// Add app data // Create msgpack array for app data
log.Printf("[DEBUG-7] Adding app data (%d bytes): %x", len(a.appData), a.appData) appData := []byte{
packet = append(packet, a.appData...) 0x92, // msgpack array of 2 elements
0xc4, // bin 8 format for byte array
}
// Add signature (64 bytes) // Add name bytes
signData := append(a.destinationHash, a.appData...) nameBytes := []byte(fmt.Sprintf("%s.%s", a.config.AppName, a.config.AppAspect))
appData = append(appData, byte(len(nameBytes))) // length prefix
appData = append(appData, nameBytes...) // name bytes
appData = append(appData, 0x00) // ticket value = 0
// Add app data to packet
packet = append(packet, appData...)
// Create signature
signData := append(a.destinationHash, appData...)
if a.ratchetID != nil { if a.ratchetID != nil {
signData = append(signData, a.ratchetID...) signData = append(signData, a.ratchetID...)
} }
@@ -346,7 +361,6 @@ func (a *Announce) CreatePacket() []byte {
packet = append(packet, signature...) packet = append(packet, signature...)
log.Printf("[DEBUG-7] Final packet size: %d bytes", len(packet)) log.Printf("[DEBUG-7] Final packet size: %d bytes", len(packet))
a.packet = packet
return packet return packet
} }
@@ -380,7 +394,7 @@ func NewAnnouncePacket(pubKey []byte, appData []byte, announceID []byte) *Announ
} }
// NewAnnounce creates a new announce packet for a destination // NewAnnounce creates a new announce packet for a destination
func NewAnnounce(identity *identity.Identity, appData []byte, ratchetID []byte, pathResponse bool) (*Announce, error) { func NewAnnounce(identity *identity.Identity, appData []byte, ratchetID []byte, pathResponse bool, config *common.ReticulumConfig) (*Announce, error) {
log.Printf("[DEBUG-7] Creating new announce: appDataLen=%d, hasRatchet=%v, pathResponse=%v", log.Printf("[DEBUG-7] Creating new announce: appDataLen=%d, hasRatchet=%v, pathResponse=%v",
len(appData), ratchetID != nil, pathResponse) len(appData), ratchetID != nil, pathResponse)
@@ -389,6 +403,10 @@ func NewAnnounce(identity *identity.Identity, appData []byte, ratchetID []byte,
return nil, errors.New("identity cannot be nil") return nil, errors.New("identity cannot be nil")
} }
if config == nil {
return nil, errors.New("config cannot be nil")
}
destHash := identity.Hash() destHash := identity.Hash()
log.Printf("[DEBUG-7] Generated destination hash: %x", destHash) log.Printf("[DEBUG-7] Generated destination hash: %x", destHash)
@@ -401,6 +419,7 @@ func NewAnnounce(identity *identity.Identity, appData []byte, ratchetID []byte,
hops: 0, hops: 0,
mutex: &sync.RWMutex{}, mutex: &sync.RWMutex{},
handlers: make([]AnnounceHandler, 0), handlers: make([]AnnounceHandler, 0),
config: config,
} }
log.Printf("[DEBUG-7] Created announce object: destHash=%x, hops=%d", log.Printf("[DEBUG-7] Created announce object: destHash=%x, hops=%d",

View File

@@ -50,6 +50,8 @@ type ReticulumConfig struct {
PanicOnInterfaceErr bool PanicOnInterfaceErr bool
LogLevel int LogLevel int
Interfaces map[string]*InterfaceConfig Interfaces map[string]*InterfaceConfig
AppName string
AppAspect string
} }
// NewReticulumConfig creates a new ReticulumConfig with default values // NewReticulumConfig creates a new ReticulumConfig with default values
@@ -75,3 +77,17 @@ func (c *ReticulumConfig) Validate() error {
} }
return nil return nil
} }
func DefaultConfig() *ReticulumConfig {
return &ReticulumConfig{
EnableTransport: true,
ShareInstance: false,
SharedInstancePort: DEFAULT_SHARED_INSTANCE_PORT,
InstanceControlPort: DEFAULT_INSTANCE_CONTROL_PORT,
PanicOnInterfaceErr: false,
LogLevel: DEFAULT_LOG_LEVEL,
Interfaces: make(map[string]*InterfaceConfig),
AppName: "Go Client",
AppAspect: "node",
}
}

View File

@@ -1,12 +1,13 @@
package transport package transport
import ( import (
"crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"log" "log"
"math/rand" mathrand "math/rand"
"net" "net"
"sync" "sync"
"time" "time"
@@ -120,6 +121,9 @@ type Path struct {
HopCount byte HopCount byte
} }
var randSource = mathrand.NewSource(time.Now().UnixNano())
var rng = mathrand.New(randSource)
func NewTransport(cfg *common.ReticulumConfig) *Transport { func NewTransport(cfg *common.ReticulumConfig) *Transport {
t := &Transport{ t := &Transport{
interfaces: make(map[string]common.NetworkInterface), interfaces: make(map[string]common.NetworkInterface),
@@ -441,7 +445,7 @@ func (t *Transport) HandleAnnounce(data []byte, sourceIface common.NetworkInterf
} }
// Add random delay before retransmission (0-2 seconds) // Add random delay before retransmission (0-2 seconds)
delay := time.Duration(rand.Float64() * 2 * float64(time.Second)) delay := time.Duration(rng.Float64() * 2 * float64(time.Second))
time.Sleep(delay) time.Sleep(delay)
// Check bandwidth allocation for announces // Check bandwidth allocation for announces
@@ -734,7 +738,7 @@ func (t *Transport) handleAnnouncePacket(data []byte, iface common.NetworkInterf
} }
// Add random delay before retransmission (0-2 seconds) // Add random delay before retransmission (0-2 seconds)
delay := time.Duration(rand.Float64() * 2 * float64(time.Second)) delay := time.Duration(rng.Float64() * 2 * float64(time.Second))
time.Sleep(delay) time.Sleep(delay)
// Check bandwidth allocation for announces // Check bandwidth allocation for announces
@@ -1035,39 +1039,65 @@ func (l *Link) GetStatus() int {
return l.status return l.status
} }
func CreateAnnouncePacket(destHash []byte, identity *identity.Identity, appData []byte, hops byte) []byte { func CreateAnnouncePacket(destHash []byte, identity *identity.Identity, appData []byte, hops byte, config *common.ReticulumConfig) []byte {
packet := make([]byte, 0, 256) log.Printf("[DEBUG-7] Creating announce packet")
// Header byte construction according to RNS spec
headerByte := byte( headerByte := byte(
(0 << 7) | // Interface flag (IFAC_NONE) (0 << 7) | // Interface flag (IFAC_NONE)
(0 << 6) | // Header type (HEADER_TYPE_1) (0 << 6) | // Header type (HEADER_TYPE_1)
(0 << 5) | // Context flag (0 << 5) | // Context flag
(1 << 4) | // Propagation type (BROADCAST) (1 << 4) | // Propagation type (BROADCAST)
(0 << 2) | // Destination type (SINGLE) (0 << 2) | // Destination type (SINGLE)
PACKET_TYPE_ANNOUNCE, // Packet type (0x01) PACKET_TYPE_ANNOUNCE, // Packet type (0x01)
) )
// Add header and hops log.Printf("[DEBUG-7] Created header byte: %02x, hops: %d", headerByte, hops)
packet = append(packet, headerByte, hops) packet := []byte{headerByte, hops}
// Add destination hash (16 bytes) log.Printf("[DEBUG-7] Adding destination hash (16 bytes): %x", destHash)
packet = append(packet, destHash...) packet = append(packet, destHash...)
// Add full public key (64 bytes - both encryption and signing keys) pubKey := identity.GetPublicKey()
fullPubKey := identity.GetPublicKey() // This should return full 64-byte key encKey := pubKey[:32]
packet = append(packet, fullPubKey...) signKey := pubKey[32:]
// Add app data with length prefix log.Printf("[DEBUG-7] Adding encryption key (32 bytes): %x", encKey)
appDataLen := make([]byte, 2) packet = append(packet, encKey...)
binary.BigEndian.PutUint16(appDataLen, uint16(len(appData)))
packet = append(packet, appDataLen...)
packet = append(packet, appData...)
// Sign the announce log.Printf("[DEBUG-7] Adding signing key (32 bytes): %x", signKey)
signData := append(destHash, appData...) packet = append(packet, signKey...)
nameHash := sha256.Sum256([]byte(fmt.Sprintf("%s.%s", config.AppName, config.AppAspect)))
log.Printf("[DEBUG-7] Adding name hash (10 bytes): %x", nameHash[:10])
packet = append(packet, nameHash[:10]...)
randomBytes := make([]byte, 5)
rand.Read(randomBytes)
timeBytes := make([]byte, 8)
binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix()))
log.Printf("[DEBUG-7] Adding random hash (10 bytes): %x%x", randomBytes, timeBytes[:5])
packet = append(packet, randomBytes...)
packet = append(packet, timeBytes[:5]...)
nameBytes := []byte(fmt.Sprintf("%s.%s", config.AppName, config.AppAspect))
appDataMsg := []byte{
0x92, // msgpack array of 2 elements
0xc4, // bin 8 format for byte array
byte(len(nameBytes)), // length prefix
}
appDataMsg = append(appDataMsg, nameBytes...)
appDataMsg = append(appDataMsg, 0x00)
signData := append(destHash, appDataMsg...)
signature := identity.Sign(signData) signature := identity.Sign(signData)
log.Printf("[DEBUG-7] Adding signature (64 bytes): %x", signature)
packet = append(packet, signature...) packet = append(packet, signature...)
packet = append(packet, appDataMsg...)
log.Printf("[DEBUG-7] Final packet size: %d bytes", len(packet))
announceHash := sha256.Sum256(packet)
log.Printf("[DEBUG-7] Generated announce hash: %x", announceHash)
return packet return packet
} }