0.3.5
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
@@ -16,6 +15,7 @@ import (
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/buffer"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/channel"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/common"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/destination"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/identity"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/interfaces"
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/packet"
|
||||
@@ -44,6 +44,8 @@ const (
|
||||
DEBUG_TRACE = 5 // Very detailed tracing
|
||||
DEBUG_PACKETS = 6 // Packet-level details
|
||||
DEBUG_ALL = 7 // Everything including identity operations
|
||||
APP_NAME = "Go Client"
|
||||
APP_ASPECT = "node"
|
||||
)
|
||||
|
||||
type Reticulum struct {
|
||||
@@ -52,18 +54,15 @@ type Reticulum struct {
|
||||
interfaces []interfaces.Interface
|
||||
channels map[string]*channel.Channel
|
||||
buffers map[string]*buffer.Buffer
|
||||
announceHandlers map[string][]announce.AnnounceHandler
|
||||
pathRequests map[string]*common.PathRequest
|
||||
announceHistory map[string]announceRecord
|
||||
announceHistoryMu sync.RWMutex
|
||||
identity *identity.Identity
|
||||
destination *destination.Destination
|
||||
}
|
||||
|
||||
type announceRecord struct {
|
||||
lastSeen time.Time
|
||||
seenCount int
|
||||
violations int
|
||||
interfaces map[string]bool
|
||||
// All fields were unused, so entire struct can be removed
|
||||
}
|
||||
|
||||
func NewReticulum(cfg *common.ReticulumConfig) (*Reticulum, error) {
|
||||
@@ -85,16 +84,36 @@ func NewReticulum(cfg *common.ReticulumConfig) (*Reticulum, error) {
|
||||
}
|
||||
debugLog(2, "Created new identity: %x", identity.Hash())
|
||||
|
||||
// Create destination
|
||||
debugLog(DEBUG_INFO, "Creating destination...")
|
||||
dest, err := destination.New(
|
||||
identity,
|
||||
destination.IN,
|
||||
destination.SINGLE,
|
||||
APP_NAME,
|
||||
APP_ASPECT,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create destination: %v", err)
|
||||
}
|
||||
debugLog(DEBUG_INFO, "Created destination with hash: %x", dest.GetHash())
|
||||
|
||||
// Enable destination features
|
||||
dest.AcceptsLinks(true)
|
||||
dest.EnableRatchets("") // Empty string for default path
|
||||
dest.SetProofStrategy(destination.PROVE_APP)
|
||||
debugLog(DEBUG_VERBOSE, "Configured destination features")
|
||||
|
||||
r := &Reticulum{
|
||||
config: cfg,
|
||||
transport: t,
|
||||
interfaces: make([]interfaces.Interface, 0),
|
||||
channels: make(map[string]*channel.Channel),
|
||||
buffers: make(map[string]*buffer.Buffer),
|
||||
announceHandlers: make(map[string][]announce.AnnounceHandler),
|
||||
pathRequests: make(map[string]*common.PathRequest),
|
||||
announceHistory: make(map[string]announceRecord),
|
||||
identity: identity,
|
||||
config: cfg,
|
||||
transport: t,
|
||||
interfaces: make([]interfaces.Interface, 0),
|
||||
channels: make(map[string]*channel.Channel),
|
||||
buffers: make(map[string]*buffer.Buffer),
|
||||
pathRequests: make(map[string]*common.PathRequest),
|
||||
announceHistory: make(map[string]announceRecord),
|
||||
identity: identity,
|
||||
destination: dest,
|
||||
}
|
||||
|
||||
// Initialize interfaces from config
|
||||
@@ -163,11 +182,7 @@ func (r *Reticulum) handleInterface(iface common.NetworkInterface) {
|
||||
|
||||
if len(data) > 0 {
|
||||
debugLog(DEBUG_TRACE, "Interface %s: Received packet type 0x%02x", iface.GetName(), data[0])
|
||||
if data[0] == announce.PACKET_TYPE_ANNOUNCE {
|
||||
r.handleAnnounce(data, iface)
|
||||
} else {
|
||||
r.transport.HandlePacket(data, iface)
|
||||
}
|
||||
r.transport.HandlePacket(data, iface)
|
||||
}
|
||||
|
||||
debugLog(5, "Processed %d bytes from interface %s", size, iface.GetName())
|
||||
@@ -386,61 +401,83 @@ func initializeDirectories() error {
|
||||
func (r *Reticulum) Start() error {
|
||||
debugLog(2, "Starting Reticulum...")
|
||||
|
||||
// Create announce using r.identity
|
||||
announce, err := announce.NewAnnounce(
|
||||
r.identity,
|
||||
[]byte("Reticulum-Go"),
|
||||
nil,
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create announce: %v", err)
|
||||
}
|
||||
|
||||
// Start transport
|
||||
// Start transport first
|
||||
if err := r.transport.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start transport: %v", err)
|
||||
}
|
||||
debugLog(3, "Transport started successfully")
|
||||
|
||||
// Start interfaces
|
||||
// Start interfaces and set up handlers
|
||||
for _, iface := range r.interfaces {
|
||||
debugLog(2, "Starting interface %s...", iface.GetName())
|
||||
if err := iface.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start interface %s: %v", iface.GetName(), err)
|
||||
if r.config.PanicOnInterfaceErr {
|
||||
return fmt.Errorf("failed to start interface %s: %v", iface.GetName(), err)
|
||||
}
|
||||
debugLog(1, "Error starting interface %s: %v", iface.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
if netIface, ok := iface.(common.NetworkInterface); ok {
|
||||
r.handleInterface(netIface)
|
||||
}
|
||||
r.handleInterface(iface)
|
||||
debugLog(3, "Interface %s started successfully", iface.GetName())
|
||||
}
|
||||
|
||||
// Wait for interfaces to be ready
|
||||
// Create initial announce packet
|
||||
announceData := []byte("Reticulum-Go")
|
||||
announcePacket := transport.CreateAnnouncePacket(
|
||||
r.identity.Hash(),
|
||||
r.identity,
|
||||
announceData,
|
||||
0,
|
||||
)
|
||||
|
||||
// Wait briefly for interfaces to initialize
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Send initial announces
|
||||
// Send initial announces on all enabled interfaces
|
||||
for _, iface := range r.interfaces {
|
||||
if netIface, ok := iface.(common.NetworkInterface); ok {
|
||||
if netIface.IsEnabled() && netIface.IsOnline() {
|
||||
debugLog(2, "Sending initial announce on interface %s", netIface.GetName())
|
||||
if err := announce.Propagate([]common.NetworkInterface{netIface}); err != nil {
|
||||
debugLog(1, "Failed to propagate initial announce: %v", err)
|
||||
if err := netIface.Send(announcePacket, ""); err != nil {
|
||||
debugLog(1, "Failed to send initial announce on interface %s: %v", netIface.GetName(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start periodic announces
|
||||
// Start periodic announce goroutine
|
||||
go func() {
|
||||
ticker := time.NewTicker(5 * time.Minute)
|
||||
ticker := time.NewTicker(ANNOUNCE_RATE_TARGET * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
announceCount := 0
|
||||
for range ticker.C {
|
||||
debugLog(3, "Starting periodic announce cycle")
|
||||
announceCount++
|
||||
debugLog(3, "Starting periodic announce cycle #%d", announceCount)
|
||||
|
||||
// Create fresh announce packet for each cycle
|
||||
announcePacket := transport.CreateAnnouncePacket(
|
||||
r.identity.Hash(),
|
||||
r.identity,
|
||||
announceData,
|
||||
0,
|
||||
)
|
||||
|
||||
for _, iface := range r.interfaces {
|
||||
if netIface, ok := iface.(common.NetworkInterface); ok {
|
||||
if netIface.IsEnabled() && netIface.IsOnline() {
|
||||
debugLog(2, "Sending periodic announce on interface %s", netIface.GetName())
|
||||
if err := announce.Propagate([]common.NetworkInterface{netIface}); err != nil {
|
||||
debugLog(1, "Failed to propagate periodic announce: %v", err)
|
||||
if err := netIface.Send(announcePacket, ""); err != nil {
|
||||
debugLog(1, "Failed to send periodic announce on interface %s: %v", netIface.GetName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Apply rate limiting after grace period
|
||||
if announceCount > ANNOUNCE_RATE_GRACE {
|
||||
time.Sleep(time.Duration(ANNOUNCE_RATE_PENALTY) * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,6 +485,9 @@ func (r *Reticulum) Start() error {
|
||||
}
|
||||
}()
|
||||
|
||||
// Start interface monitoring
|
||||
go r.monitorInterfaces()
|
||||
|
||||
debugLog(2, "Reticulum started successfully")
|
||||
return nil
|
||||
}
|
||||
@@ -481,103 +521,6 @@ func (r *Reticulum) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reticulum) handleAnnounce(data []byte, iface common.NetworkInterface) {
|
||||
debugLog(DEBUG_INFO, "Received announce packet on interface %s (%d bytes)", iface.GetName(), len(data))
|
||||
|
||||
a := &announce.Announce{}
|
||||
if err := a.HandleAnnounce(data); err != nil {
|
||||
debugLog(DEBUG_ERROR, "Error handling announce: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Log announce details
|
||||
debugLog(DEBUG_ALL, "Announce details:")
|
||||
debugLog(DEBUG_ALL, " Hash: %x", a.Hash())
|
||||
|
||||
// Get fields using packet data
|
||||
packet := a.GetPacket()
|
||||
if len(packet) > 2 {
|
||||
destHash := packet[2:18]
|
||||
hops := packet[50]
|
||||
debugLog(DEBUG_ALL, " Destination Hash: %x", destHash)
|
||||
debugLog(DEBUG_ALL, " Hops: %d", hops)
|
||||
}
|
||||
|
||||
// Check announce history
|
||||
announceKey := fmt.Sprintf("%x", a.Hash())
|
||||
r.announceHistoryMu.Lock()
|
||||
record, exists := r.announceHistory[announceKey]
|
||||
|
||||
if exists {
|
||||
// Check if this interface has already seen this announce
|
||||
if record.interfaces[iface.GetName()] {
|
||||
r.announceHistoryMu.Unlock()
|
||||
debugLog(4, "Duplicate announce from %s, ignoring", iface.GetName())
|
||||
return
|
||||
}
|
||||
|
||||
// Check rate limiting
|
||||
timeSinceLastSeen := time.Since(record.lastSeen)
|
||||
if timeSinceLastSeen < time.Duration(ANNOUNCE_RATE_TARGET)*time.Second {
|
||||
if record.seenCount > ANNOUNCE_RATE_GRACE {
|
||||
record.violations++
|
||||
waitTime := ANNOUNCE_RATE_TARGET + (record.violations * ANNOUNCE_RATE_PENALTY)
|
||||
r.announceHistoryMu.Unlock()
|
||||
debugLog(3, "Rate limit exceeded for announce %s, waiting %d seconds", announceKey, waitTime)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
record.seenCount++
|
||||
record.lastSeen = time.Now()
|
||||
record.interfaces[iface.GetName()] = true
|
||||
} else {
|
||||
record = announceRecord{
|
||||
lastSeen: time.Now(),
|
||||
seenCount: 1,
|
||||
interfaces: make(map[string]bool),
|
||||
}
|
||||
record.interfaces[iface.GetName()] = true
|
||||
r.announceHistory[announceKey] = record
|
||||
}
|
||||
r.announceHistoryMu.Unlock()
|
||||
|
||||
// Add random delay before propagation (0-2 seconds)
|
||||
delay := time.Duration(rand.Float64() * 2 * float64(time.Second))
|
||||
time.Sleep(delay)
|
||||
|
||||
// Propagate to other interfaces according to RNS rules
|
||||
for _, otherIface := range r.interfaces {
|
||||
if otherIface.GetName() == iface.GetName() {
|
||||
continue
|
||||
}
|
||||
|
||||
srcMode := iface.GetMode()
|
||||
dstMode := otherIface.GetMode()
|
||||
|
||||
// Skip propagation based on interface modes
|
||||
if srcMode == common.IF_MODE_ACCESS_POINT && dstMode != common.IF_MODE_FULL {
|
||||
debugLog(4, "Skipping announce propagation from AP to non-full mode interface")
|
||||
continue
|
||||
}
|
||||
if srcMode == common.IF_MODE_ROAMING && dstMode == common.IF_MODE_ACCESS_POINT {
|
||||
debugLog(4, "Skipping announce propagation from roaming to AP interface")
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if interface has bandwidth available
|
||||
if netIface, ok := otherIface.(common.NetworkInterface); ok {
|
||||
if netIface.GetBandwidthAvailable() {
|
||||
if err := a.Propagate([]common.NetworkInterface{netIface}); err != nil {
|
||||
debugLog(1, "Error propagating announce: %v", err)
|
||||
}
|
||||
} else {
|
||||
debugLog(3, "Interface %s has insufficient bandwidth for announce", netIface.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AnnounceHandler struct {
|
||||
aspectFilter []string
|
||||
}
|
||||
@@ -617,3 +560,7 @@ func (h *AnnounceHandler) ReceivedAnnounce(destHash []byte, id interface{}, appD
|
||||
func (h *AnnounceHandler) ReceivePathResponses() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *Reticulum) GetDestination() *destination.Destination {
|
||||
return r.destination
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package announce
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
@@ -111,23 +112,34 @@ func (a *Announce) Propagate(interfaces []common.NetworkInterface) error {
|
||||
a.mutex.RLock()
|
||||
defer a.mutex.RUnlock()
|
||||
|
||||
// Use cached packet if available, otherwise create new one
|
||||
log.Printf("[DEBUG-7] Propagating announce across %d interfaces", len(interfaces))
|
||||
|
||||
var packet []byte
|
||||
if a.packet != nil {
|
||||
log.Printf("[DEBUG-7] Using cached packet (%d bytes)", len(a.packet))
|
||||
packet = a.packet
|
||||
} else {
|
||||
log.Printf("[DEBUG-7] Creating new packet")
|
||||
packet = a.CreatePacket()
|
||||
a.packet = packet
|
||||
}
|
||||
|
||||
for _, iface := range interfaces {
|
||||
if !iface.IsEnabled() || !iface.GetBandwidthAvailable() {
|
||||
if !iface.IsEnabled() {
|
||||
log.Printf("[DEBUG-7] Skipping disabled interface: %s", iface.GetName())
|
||||
continue
|
||||
}
|
||||
if !iface.GetBandwidthAvailable() {
|
||||
log.Printf("[DEBUG-7] Skipping interface with insufficient bandwidth: %s", iface.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG-7] Sending announce on interface %s", iface.GetName())
|
||||
if err := iface.Send(packet, ""); err != nil {
|
||||
log.Printf("[DEBUG-7] Failed to send on interface %s: %v", iface.GetName(), err)
|
||||
return fmt.Errorf("failed to propagate on interface %s: %w", iface.GetName(), err)
|
||||
}
|
||||
log.Printf("[DEBUG-7] Successfully sent announce on interface %s", iface.GetName())
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -271,48 +283,70 @@ func CreateHeader(ifacFlag byte, headerType byte, contextFlag byte, propType byt
|
||||
}
|
||||
|
||||
func (a *Announce) CreatePacket() []byte {
|
||||
packet := make([]byte, 0)
|
||||
|
||||
// Create header according to spec
|
||||
header := CreateHeader(
|
||||
IFAC_NONE, // No interface auth
|
||||
HEADER_TYPE_1, // One address field
|
||||
0x00, // Context flag unset
|
||||
PROP_TYPE_BROADCAST, // Broadcast propagation
|
||||
DEST_TYPE_SINGLE, // Single destination
|
||||
PACKET_TYPE_ANNOUNCE, // Announce packet type
|
||||
a.hops, // Current hop count
|
||||
log.Printf("[DEBUG-7] Creating announce packet")
|
||||
|
||||
headerByte := byte(
|
||||
(IFAC_NONE) |
|
||||
(HEADER_TYPE_1 << 6) |
|
||||
(0 << 5) |
|
||||
(PROP_TYPE_BROADCAST << 4) |
|
||||
(DEST_TYPE_SINGLE << 2) |
|
||||
PACKET_TYPE_ANNOUNCE,
|
||||
)
|
||||
packet = append(packet, header...)
|
||||
|
||||
log.Printf("[DEBUG-7] Created header byte: %02x, hops: %d", headerByte, a.hops)
|
||||
packet := []byte{headerByte, a.hops}
|
||||
|
||||
// Add destination hash (16 bytes)
|
||||
log.Printf("[DEBUG-7] Adding destination hash (16 bytes): %x", a.destinationHash)
|
||||
packet = append(packet, a.destinationHash...)
|
||||
|
||||
// Add public key
|
||||
packet = append(packet, a.identity.GetPublicKey()...)
|
||||
// Split public key into encryption and signing keys (32 bytes each)
|
||||
pubKey := a.identity.GetPublicKey()
|
||||
encKey := pubKey[:32]
|
||||
signKey := pubKey[32:]
|
||||
|
||||
log.Printf("[DEBUG-7] Adding encryption key (32 bytes): %x", encKey)
|
||||
packet = append(packet, encKey...)
|
||||
|
||||
log.Printf("[DEBUG-7] Adding signing key (32 bytes): %x", signKey)
|
||||
packet = append(packet, signKey...)
|
||||
|
||||
// Add hop count byte
|
||||
packet = append(packet, byte(a.hops))
|
||||
// Add name hash (10 bytes)
|
||||
nameHash := a.identity.GetNameHash()
|
||||
log.Printf("[DEBUG-7] Adding name hash (10 bytes): %x", nameHash)
|
||||
packet = append(packet, nameHash...)
|
||||
|
||||
// Add app data with length prefix
|
||||
appDataLen := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(appDataLen, uint16(len(a.appData)))
|
||||
packet = append(packet, appDataLen...)
|
||||
packet = append(packet, a.appData...)
|
||||
// Add random hash (5 random + 5 timestamp bytes = 10 bytes)
|
||||
randomHash := make([]byte, 5)
|
||||
rand.Read(randomHash)
|
||||
timeBytes := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix()))
|
||||
log.Printf("[DEBUG-7] Adding random hash (10 bytes): %x%x", randomHash, timeBytes[:5])
|
||||
packet = append(packet, randomHash...)
|
||||
packet = append(packet, timeBytes[:5]...)
|
||||
|
||||
// Add ratchet ID if present
|
||||
// Add ratchet if present (32 bytes)
|
||||
if a.ratchetID != nil {
|
||||
log.Printf("[DEBUG-7] Adding ratchet ID (32 bytes): %x", a.ratchetID)
|
||||
packet = append(packet, a.ratchetID...)
|
||||
}
|
||||
|
||||
// Add signature
|
||||
// Add app data
|
||||
log.Printf("[DEBUG-7] Adding app data (%d bytes): %x", len(a.appData), a.appData)
|
||||
packet = append(packet, a.appData...)
|
||||
|
||||
// Add signature (64 bytes)
|
||||
signData := append(a.destinationHash, a.appData...)
|
||||
if a.ratchetID != nil {
|
||||
signData = append(signData, a.ratchetID...)
|
||||
}
|
||||
signature := a.identity.Sign(signData)
|
||||
log.Printf("[DEBUG-7] Adding signature (64 bytes): %x", signature)
|
||||
packet = append(packet, signature...)
|
||||
|
||||
log.Printf("[DEBUG-7] Final packet size: %d bytes", len(packet))
|
||||
a.packet = packet
|
||||
return packet
|
||||
}
|
||||
|
||||
@@ -347,60 +381,38 @@ func NewAnnouncePacket(pubKey []byte, appData []byte, announceID []byte) *Announ
|
||||
|
||||
// NewAnnounce creates a new announce packet for a destination
|
||||
func NewAnnounce(identity *identity.Identity, appData []byte, ratchetID []byte, pathResponse bool) (*Announce, error) {
|
||||
log.Printf("[DEBUG-7] Creating new announce: appDataLen=%d, hasRatchet=%v, pathResponse=%v",
|
||||
len(appData), ratchetID != nil, pathResponse)
|
||||
|
||||
if identity == nil {
|
||||
log.Printf("[DEBUG-7] Error: nil identity provided")
|
||||
return nil, errors.New("identity cannot be nil")
|
||||
}
|
||||
|
||||
destHash := identity.Hash()
|
||||
log.Printf("[DEBUG-7] Generated destination hash: %x", destHash)
|
||||
|
||||
a := &Announce{
|
||||
identity: identity,
|
||||
appData: appData,
|
||||
ratchetID: ratchetID,
|
||||
pathResponse: pathResponse,
|
||||
destinationHash: identity.Hash(),
|
||||
destinationHash: destHash,
|
||||
hops: 0,
|
||||
mutex: &sync.RWMutex{},
|
||||
handlers: make([]AnnounceHandler, 0),
|
||||
}
|
||||
|
||||
// Create announce packet
|
||||
packet := make([]byte, 0)
|
||||
|
||||
// Add header (2 bytes)
|
||||
packet = append(packet, PACKET_TYPE_ANNOUNCE)
|
||||
packet = append(packet, byte(a.hops))
|
||||
|
||||
// Add destination hash (16 bytes)
|
||||
packet = append(packet, a.destinationHash...)
|
||||
|
||||
// Add public key (32 bytes)
|
||||
packet = append(packet, identity.GetPublicKey()...)
|
||||
|
||||
// Add hop count (1 byte)
|
||||
packet = append(packet, byte(a.hops))
|
||||
|
||||
// Add app data with length prefix (2 bytes + data)
|
||||
appDataLen := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(appDataLen, uint16(len(appData)))
|
||||
packet = append(packet, appDataLen...)
|
||||
packet = append(packet, appData...)
|
||||
|
||||
// Add ratchet ID if present
|
||||
if ratchetID != nil {
|
||||
packet = append(packet, ratchetID...)
|
||||
}
|
||||
|
||||
// Add signature
|
||||
signData := append(a.destinationHash, appData...)
|
||||
if ratchetID != nil {
|
||||
signData = append(signData, ratchetID...)
|
||||
}
|
||||
signature := identity.Sign(signData)
|
||||
packet = append(packet, signature...)
|
||||
log.Printf("[DEBUG-7] Created announce object: destHash=%x, hops=%d",
|
||||
a.destinationHash, a.hops)
|
||||
|
||||
// Create initial packet
|
||||
packet := a.CreatePacket()
|
||||
a.packet = packet
|
||||
|
||||
|
||||
// Generate hash
|
||||
a.Hash()
|
||||
hash := a.Hash()
|
||||
log.Printf("[DEBUG-7] Generated announce hash: %x", hash)
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
@@ -31,6 +31,15 @@ const (
|
||||
|
||||
RATCHET_COUNT = 512 // Default number of retained ratchet keys
|
||||
RATCHET_INTERVAL = 1800 // Minimum interval between ratchet rotations in seconds
|
||||
|
||||
// Debug levels
|
||||
DEBUG_CRITICAL = 1 // Critical errors
|
||||
DEBUG_ERROR = 2 // Non-critical errors
|
||||
DEBUG_INFO = 3 // Important information
|
||||
DEBUG_VERBOSE = 4 // Detailed information
|
||||
DEBUG_TRACE = 5 // Very detailed tracing
|
||||
DEBUG_PACKETS = 6 // Packet-level details
|
||||
DEBUG_ALL = 7 // Everything
|
||||
)
|
||||
|
||||
type PacketCallback = common.PacketCallback
|
||||
@@ -69,15 +78,17 @@ type Destination struct {
|
||||
mutex sync.RWMutex
|
||||
|
||||
requestHandlers map[string]*RequestHandler
|
||||
callbacks struct {
|
||||
packetReceived common.PacketCallback
|
||||
proofRequested common.ProofRequestedCallback
|
||||
linkEstablished common.LinkEstablishedCallback
|
||||
}
|
||||
}
|
||||
|
||||
func debugLog(level int, format string, v ...interface{}) {
|
||||
log.Printf("[DEBUG-%d] %s", level, fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
func New(id *identity.Identity, direction byte, destType byte, appName string, aspects ...string) (*Destination, error) {
|
||||
debugLog(DEBUG_INFO, "Creating new destination: app=%s type=%d direction=%d", appName, destType, direction)
|
||||
|
||||
if id == nil {
|
||||
debugLog(DEBUG_ERROR, "Cannot create destination: identity is nil")
|
||||
return nil, errors.New("identity cannot be nil")
|
||||
}
|
||||
|
||||
@@ -96,18 +107,27 @@ func New(id *identity.Identity, direction byte, destType byte, appName string, a
|
||||
|
||||
// Generate destination hash
|
||||
d.hashValue = d.calculateHash()
|
||||
debugLog(DEBUG_VERBOSE, "Created destination with hash: %x", d.hashValue)
|
||||
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *Destination) calculateHash() []byte {
|
||||
debugLog(DEBUG_TRACE, "Calculating hash for destination %s", d.ExpandName())
|
||||
|
||||
nameHash := sha256.Sum256([]byte(d.ExpandName()))
|
||||
identityHash := sha256.Sum256(d.identity.GetPublicKey())
|
||||
|
||||
debugLog(DEBUG_ALL, "Name hash: %x", nameHash)
|
||||
debugLog(DEBUG_ALL, "Identity hash: %x", identityHash)
|
||||
|
||||
combined := append(nameHash[:], identityHash[:]...)
|
||||
finalHash := sha256.Sum256(combined)
|
||||
|
||||
return finalHash[:16] // Truncated to 128 bits
|
||||
truncated := finalHash[:16]
|
||||
debugLog(DEBUG_VERBOSE, "Calculated destination hash: %x", truncated)
|
||||
|
||||
return truncated
|
||||
}
|
||||
|
||||
func (d *Destination) ExpandName() string {
|
||||
@@ -131,52 +151,31 @@ func (d *Destination) Announce(appData []byte) error {
|
||||
}
|
||||
|
||||
// Create announce packet
|
||||
packet := make([]byte, 0)
|
||||
packet := make([]byte, 0, 256) // Pre-allocate reasonable size
|
||||
|
||||
// Add destination hash
|
||||
// Add packet type and header
|
||||
packet = append(packet, 0x01) // PACKET_TYPE_ANNOUNCE
|
||||
packet = append(packet, 0x00) // Initial hop count
|
||||
|
||||
// Add destination hash (16 bytes)
|
||||
packet = append(packet, d.hashValue...)
|
||||
log.Printf("[DEBUG-4] Added destination hash %x to announce", d.hashValue[:8])
|
||||
|
||||
// Add identity public key
|
||||
// Add identity public key (32 bytes)
|
||||
pubKey := d.identity.GetPublicKey()
|
||||
packet = append(packet, pubKey...)
|
||||
log.Printf("[DEBUG-4] Added public key %x to announce", pubKey[:8])
|
||||
|
||||
// Add flags byte
|
||||
flags := byte(0)
|
||||
if d.acceptsLinks {
|
||||
flags |= 0x01
|
||||
}
|
||||
if d.ratchetsEnabled {
|
||||
flags |= 0x02
|
||||
}
|
||||
packet = append(packet, flags)
|
||||
log.Printf("[DEBUG-4] Added flags byte 0x%02x to announce", flags)
|
||||
|
||||
// Add proof strategy
|
||||
packet = append(packet, d.proofStrategy)
|
||||
log.Printf("[DEBUG-4] Added proof strategy 0x%02x to announce", d.proofStrategy)
|
||||
|
||||
// Add app data
|
||||
if appData != nil {
|
||||
appDataLen := uint16(len(appData))
|
||||
lenBytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(lenBytes, appDataLen)
|
||||
packet = append(packet, lenBytes...)
|
||||
packet = append(packet, appData...)
|
||||
log.Printf("[DEBUG-4] Added %d bytes of app data to announce", appDataLen)
|
||||
} else {
|
||||
packet = append(packet, 0x00, 0x00)
|
||||
log.Printf("[DEBUG-4] Added empty app data to announce")
|
||||
}
|
||||
// Add app data with length prefix
|
||||
appDataLen := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(appDataLen, uint16(len(appData)))
|
||||
packet = append(packet, appDataLen...)
|
||||
packet = append(packet, appData...)
|
||||
log.Printf("[DEBUG-4] Added %d bytes of app data to announce", len(appData))
|
||||
|
||||
// Add ratchet data if enabled
|
||||
if d.ratchetsEnabled {
|
||||
log.Printf("[DEBUG-4] Adding ratchet data to announce")
|
||||
intervalBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(intervalBytes, uint32(d.ratchetInterval))
|
||||
packet = append(packet, intervalBytes...)
|
||||
|
||||
ratchetKey := d.identity.GetCurrentRatchetKey()
|
||||
if ratchetKey == nil {
|
||||
log.Printf("[DEBUG-3] Failed to get current ratchet key")
|
||||
@@ -186,16 +185,16 @@ func (d *Destination) Announce(appData []byte) error {
|
||||
log.Printf("[DEBUG-4] Added ratchet key %x to announce", ratchetKey[:8])
|
||||
}
|
||||
|
||||
// Sign the announce packet
|
||||
signature, err := d.Sign(packet)
|
||||
if err != nil {
|
||||
log.Printf("[DEBUG-3] Failed to sign announce packet: %v", err)
|
||||
return fmt.Errorf("failed to sign announce packet: %w", err)
|
||||
// Sign the announce packet (64 bytes)
|
||||
signData := append(d.hashValue, appData...)
|
||||
if d.ratchetsEnabled {
|
||||
signData = append(signData, d.identity.GetCurrentRatchetKey()...)
|
||||
}
|
||||
signature := d.identity.Sign(signData)
|
||||
packet = append(packet, signature...)
|
||||
log.Printf("[DEBUG-4] Added signature to announce packet (total size: %d bytes)", len(packet))
|
||||
|
||||
// Send announce packet
|
||||
// Send announce packet through transport
|
||||
log.Printf("[DEBUG-4] Sending announce packet through transport layer")
|
||||
return transport.SendAnnounce(packet)
|
||||
}
|
||||
@@ -288,7 +287,7 @@ func (d *Destination) RegisterRequestHandler(path string, responseGen func(strin
|
||||
return errors.New("invalid allow mode")
|
||||
}
|
||||
|
||||
if allow == ALLOW_LIST && (allowedList == nil || len(allowedList) == 0) {
|
||||
if allow == ALLOW_LIST && len(allowedList) == 0 {
|
||||
return errors.New("allowed list required for ALLOW_LIST mode")
|
||||
}
|
||||
|
||||
|
||||
@@ -152,10 +152,11 @@ func New() (*Identity, error) {
|
||||
}
|
||||
|
||||
func (i *Identity) GetPublicKey() []byte {
|
||||
combined := make([]byte, KEYSIZE/8)
|
||||
copy(combined[:KEYSIZE/16], i.publicKey)
|
||||
copy(combined[KEYSIZE/16:], i.verificationKey)
|
||||
return combined
|
||||
// Combine encryption and signing public keys in correct order
|
||||
fullKey := make([]byte, 64)
|
||||
copy(fullKey[:32], i.publicKey) // First 32 bytes: X25519 encryption key
|
||||
copy(fullKey[32:], i.verificationKey) // Last 32 bytes: Ed25519 verification key
|
||||
return fullKey
|
||||
}
|
||||
|
||||
func (i *Identity) GetPrivateKey() []byte {
|
||||
@@ -838,7 +839,23 @@ func (i *Identity) ValidateAnnounce(data []byte, destHash []byte, appData []byte
|
||||
|
||||
signatureStart := len(data) - ed25519.SignatureSize
|
||||
signature := data[signatureStart:]
|
||||
signedData := append(destHash, appData...)
|
||||
signedData := append(destHash, i.GetPublicKey()...)
|
||||
signedData = append(signedData, appData...)
|
||||
|
||||
return ed25519.Verify(i.verificationKey, signedData, signature)
|
||||
}
|
||||
|
||||
// GetNameHash returns a 10-byte hash derived from the identity's public key
|
||||
func (i *Identity) GetNameHash() []byte {
|
||||
if i == nil || i.publicKey == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate hash from combined public key
|
||||
h := sha256.New()
|
||||
h.Write(i.GetPublicKey())
|
||||
fullHash := h.Sum(nil)
|
||||
|
||||
// Return first 10 bytes (NAME_HASH_LENGTH/8)
|
||||
return fullHash[:NAME_HASH_LENGTH/8]
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/Sudo-Ivan/reticulum-go/pkg/identity"
|
||||
@@ -110,24 +111,29 @@ func (p *Packet) Pack() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
flags := (p.HeaderType << 6) | (p.ContextFlag << 5) |
|
||||
(p.TransportType << 4) | (p.DestinationType << 2) | p.PacketType
|
||||
log.Printf("[DEBUG-6] Packing packet: type=%d, header=%d", p.PacketType, p.HeaderType)
|
||||
|
||||
header := make([]byte, 0)
|
||||
header = append(header, flags)
|
||||
header = append(header, p.Hops)
|
||||
// Create header byte
|
||||
flags := byte(p.HeaderType<<6) | byte(p.ContextFlag<<5) |
|
||||
byte(p.TransportType<<4) | byte(p.DestinationType<<2) | byte(p.PacketType)
|
||||
|
||||
if p.HeaderType == HeaderType2 && p.TransportID != nil {
|
||||
header := []byte{flags, p.Hops}
|
||||
log.Printf("[DEBUG-5] Created packet header: flags=%08b, hops=%d", flags, p.Hops)
|
||||
|
||||
if p.HeaderType == HeaderType2 {
|
||||
if p.TransportID == nil {
|
||||
return errors.New("transport ID required for header type 2")
|
||||
}
|
||||
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")
|
||||
log.Printf("[DEBUG-7] Added transport ID to header: %x", p.TransportID)
|
||||
}
|
||||
|
||||
header = append(header, p.DestinationHash...)
|
||||
header = append(header, p.Context)
|
||||
log.Printf("[DEBUG-6] Final header length: %d bytes", len(header))
|
||||
|
||||
p.Raw = append(header, p.Data...)
|
||||
log.Printf("[DEBUG-5] Final packet size: %d bytes", len(p.Raw))
|
||||
|
||||
if len(p.Raw) > MTU {
|
||||
return errors.New("packet size exceeds MTU")
|
||||
@@ -135,6 +141,7 @@ func (p *Packet) Pack() error {
|
||||
|
||||
p.Packed = true
|
||||
p.updateHash()
|
||||
log.Printf("[DEBUG-7] Packet hash: %x", p.PacketHash)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -210,19 +217,25 @@ func (p *Packet) Serialize() ([]byte, error) {
|
||||
}
|
||||
|
||||
func NewAnnouncePacket(destHash []byte, identity *identity.Identity, appData []byte, transportID []byte) (*Packet, error) {
|
||||
log.Printf("[DEBUG-7] Creating new announce packet: destHash=%x, appData=%s", destHash, string(appData))
|
||||
|
||||
// Create combined public key
|
||||
pubKey := identity.GetPublicKey()
|
||||
log.Printf("[DEBUG-6] Using public key: %x", pubKey)
|
||||
|
||||
// Create signed data
|
||||
signedData := append(destHash, pubKey...)
|
||||
signedData = append(signedData, appData...)
|
||||
log.Printf("[DEBUG-5] Created signed data (%d bytes)", len(signedData))
|
||||
|
||||
// Sign the data
|
||||
signature := identity.Sign(signedData)
|
||||
log.Printf("[DEBUG-6] Generated signature: %x", signature)
|
||||
|
||||
// Combine all data
|
||||
data := append(pubKey, appData...)
|
||||
data = append(data, signature...)
|
||||
log.Printf("[DEBUG-5] Combined packet data (%d bytes)", len(data))
|
||||
|
||||
p := &Packet{
|
||||
HeaderType: HeaderType2,
|
||||
@@ -232,5 +245,6 @@ func NewAnnouncePacket(destHash []byte, identity *identity.Identity, appData []b
|
||||
Data: data,
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG-4] Created announce packet: type=%d, header=%d", p.PacketType, p.HeaderType)
|
||||
return p, nil
|
||||
}
|
||||
|
||||
@@ -70,6 +70,29 @@ const (
|
||||
|
||||
MAX_HOPS = 128 // Default m value for announce propagation
|
||||
PROPAGATION_RATE = 0.02 // 2% bandwidth cap for announces
|
||||
|
||||
// Announce packet types
|
||||
PACKET_TYPE_ANNOUNCE = 0x01
|
||||
PACKET_TYPE_LINK = 0x02
|
||||
|
||||
// Announce flags
|
||||
ANNOUNCE_NONE = 0x00
|
||||
ANNOUNCE_PATH = 0x01
|
||||
ANNOUNCE_IDENTITY = 0x02
|
||||
|
||||
// Header types
|
||||
HEADER_TYPE_1 = 0x00 // One address field
|
||||
HEADER_TYPE_2 = 0x01 // Two address fields
|
||||
|
||||
// Propagation types
|
||||
PROP_TYPE_BROADCAST = 0x00
|
||||
PROP_TYPE_TRANSPORT = 0x01
|
||||
|
||||
// Destination types
|
||||
DEST_TYPE_SINGLE = 0x00
|
||||
DEST_TYPE_GROUP = 0x01
|
||||
DEST_TYPE_PLAIN = 0x02
|
||||
DEST_TYPE_LINK = 0x03
|
||||
)
|
||||
|
||||
type PathInfo struct {
|
||||
@@ -590,27 +613,41 @@ func SendAnnounce(packet []byte) error {
|
||||
}
|
||||
|
||||
func (t *Transport) HandlePacket(data []byte, iface common.NetworkInterface) {
|
||||
if len(data) < 1 {
|
||||
if len(data) < 2 {
|
||||
log.Printf("[DEBUG-3] Dropping packet: insufficient length (%d bytes)", len(data))
|
||||
return
|
||||
}
|
||||
|
||||
packetType := data[0]
|
||||
log.Printf("[DEBUG-4] Transport handling packet type 0x%02x from interface %s, size: %d bytes",
|
||||
packetType, iface.GetName(), len(data))
|
||||
headerByte := data[0]
|
||||
packetType := headerByte & 0x03
|
||||
headerType := (headerByte & 0x40) >> 6
|
||||
contextFlag := (headerByte & 0x20) >> 5
|
||||
propType := (headerByte & 0x10) >> 4
|
||||
destType := (headerByte & 0x0C) >> 2
|
||||
|
||||
log.Printf("[DEBUG-4] Packet received - Type: 0x%02x, Header: %d, Context: %d, PropType: %d, DestType: %d, Size: %d bytes",
|
||||
packetType, headerType, contextFlag, propType, destType, len(data))
|
||||
log.Printf("[DEBUG-5] Interface: %s, Raw header: 0x%02x", iface.GetName(), headerByte)
|
||||
|
||||
// Update interface stats before processing
|
||||
if tcpIface, ok := iface.(*interfaces.TCPClientInterface); ok {
|
||||
tcpIface.UpdateStats(uint64(len(data)), true)
|
||||
log.Printf("[DEBUG-6] Updated TCP interface stats - RX bytes: %d", len(data))
|
||||
}
|
||||
|
||||
switch packetType {
|
||||
case announce.PACKET_TYPE_ANNOUNCE:
|
||||
t.handleAnnouncePacket(data[1:], iface)
|
||||
case announce.PACKET_TYPE_LINK:
|
||||
case PACKET_TYPE_ANNOUNCE:
|
||||
log.Printf("[DEBUG-4] Processing announce packet")
|
||||
if err := t.handleAnnouncePacket(data, iface); err != nil {
|
||||
log.Printf("[DEBUG-3] Announce handling failed: %v", err)
|
||||
}
|
||||
case PACKET_TYPE_LINK:
|
||||
log.Printf("[DEBUG-4] Processing link packet")
|
||||
t.handleLinkPacket(data[1:], iface)
|
||||
case 0x03: // Path response
|
||||
case 0x03:
|
||||
log.Printf("[DEBUG-4] Processing path response")
|
||||
t.handlePathResponse(data[1:], iface)
|
||||
case 0x04: // Transport packet
|
||||
case 0x00:
|
||||
log.Printf("[DEBUG-4] Processing transport packet")
|
||||
t.handleTransportPacket(data[1:], iface)
|
||||
default:
|
||||
log.Printf("[DEBUG-3] Unknown packet type 0x%02x from %s", packetType, iface.GetName())
|
||||
@@ -618,18 +655,66 @@ func (t *Transport) HandlePacket(data []byte, iface common.NetworkInterface) {
|
||||
}
|
||||
|
||||
func (t *Transport) handleAnnouncePacket(data []byte, iface common.NetworkInterface) error {
|
||||
// Validate minimum packet size (1 byte hop count + 32 bytes dest hash + 16 bytes min identity + 1 byte min app data)
|
||||
if len(data) < 50 {
|
||||
return fmt.Errorf("announce packet too small: %d bytes", len(data))
|
||||
if len(data) < 2 {
|
||||
return fmt.Errorf("packet too small for header")
|
||||
}
|
||||
|
||||
// Parse header bytes according to RNS spec
|
||||
headerByte1 := data[0]
|
||||
hopCount := data[1]
|
||||
|
||||
// Extract header fields
|
||||
ifacFlag := (headerByte1 & 0x80) >> 7 // IFAC flag in highest bit
|
||||
headerType := (headerByte1 & 0x40) >> 6 // Header type in next bit
|
||||
contextFlag := (headerByte1 & 0x20) >> 5 // Context flag
|
||||
propType := (headerByte1 & 0x10) >> 4 // Propagation type
|
||||
destType := (headerByte1 & 0x0C) >> 2 // Destination type in next 2 bits
|
||||
packetType := headerByte1 & 0x03 // Packet type in lowest 2 bits
|
||||
|
||||
log.Printf("[DEBUG-5] Announce header: IFAC=%d, headerType=%d, context=%d, propType=%d, destType=%d, packetType=%d",
|
||||
ifacFlag, headerType, contextFlag, propType, destType, packetType)
|
||||
|
||||
// Skip IFAC code if present
|
||||
startIdx := 2
|
||||
if ifacFlag == 1 {
|
||||
startIdx += 1 // For now assume 1 byte IFAC code
|
||||
}
|
||||
|
||||
// Calculate address field size
|
||||
addrSize := 16
|
||||
if headerType == 1 {
|
||||
addrSize = 32 // Two address fields
|
||||
}
|
||||
|
||||
// Validate minimum packet size
|
||||
minSize := startIdx + addrSize + 1 // Header + addresses + context
|
||||
if len(data) < minSize {
|
||||
return fmt.Errorf("packet too small: %d bytes", len(data))
|
||||
}
|
||||
|
||||
// Extract fields
|
||||
hopCount := data[0]
|
||||
destHash := data[1:33]
|
||||
identityBytes := data[33:49]
|
||||
appData := data[49:]
|
||||
addresses := data[startIdx : startIdx+addrSize]
|
||||
context := data[startIdx+addrSize]
|
||||
payload := data[startIdx+addrSize+1:]
|
||||
|
||||
// Check for duplicate announces
|
||||
log.Printf("[DEBUG-6] Addresses: %x", addresses)
|
||||
log.Printf("[DEBUG-7] Context: %02x, Payload length: %d", context, len(payload))
|
||||
|
||||
// Process payload (should contain pubkey + app data)
|
||||
if len(payload) < 32 { // Minimum size for pubkey
|
||||
return fmt.Errorf("payload too small for announce")
|
||||
}
|
||||
|
||||
pubKey := payload[:32]
|
||||
appData := payload[32:]
|
||||
|
||||
// Create identity from public key
|
||||
id := identity.FromPublicKey(pubKey)
|
||||
if id == nil {
|
||||
return fmt.Errorf("invalid identity")
|
||||
}
|
||||
|
||||
// Generate announce hash to check for duplicates
|
||||
announceHash := sha256.Sum256(data)
|
||||
hashStr := string(announceHash[:])
|
||||
|
||||
@@ -642,12 +727,6 @@ func (t *Transport) handleAnnouncePacket(data []byte, iface common.NetworkInterf
|
||||
t.seenAnnounces[hashStr] = true
|
||||
t.mutex.Unlock()
|
||||
|
||||
// Validate announce signature and store destination
|
||||
id := identity.FromPublicKey(identityBytes)
|
||||
if id == nil || !id.ValidateAnnounce(data, destHash, appData) {
|
||||
return fmt.Errorf("invalid announce signature")
|
||||
}
|
||||
|
||||
// Don't forward if max hops reached
|
||||
if hopCount >= MAX_HOPS {
|
||||
log.Printf("[DEBUG-7] Announce exceeded max hops: %d", hopCount)
|
||||
@@ -660,43 +739,36 @@ func (t *Transport) handleAnnouncePacket(data []byte, iface common.NetworkInterf
|
||||
|
||||
// Check bandwidth allocation for announces
|
||||
if !t.announceRate.Allow() {
|
||||
log.Printf("[DEBUG-7] Announce rate limit exceeded, dropping")
|
||||
log.Printf("[DEBUG-7] Announce rate limit exceeded, queuing...")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Increment hop count for forwarding
|
||||
forwardData := make([]byte, len(data))
|
||||
copy(forwardData, data)
|
||||
forwardData[0] = hopCount + 1
|
||||
// Increment hop count
|
||||
data[1]++
|
||||
|
||||
// Forward to other interfaces
|
||||
// Broadcast to all other interfaces
|
||||
var lastErr error
|
||||
for name, outIface := range t.interfaces {
|
||||
if outIface == iface || !outIface.IsEnabled() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check interface mode restrictions
|
||||
// if outIface.GetMode() == interfaces.ModeAccessPoint {
|
||||
// log.Printf("[DEBUG-7] Blocking announce broadcast on %s due to AP mode", name)
|
||||
// continue
|
||||
// }
|
||||
|
||||
log.Printf("[DEBUG-7] Forwarding announce on interface %s", name)
|
||||
if err := outIface.Send(forwardData, ""); err != nil {
|
||||
log.Printf("[DEBUG-3] Failed to forward announce on %s: %v", name, err)
|
||||
if err := outIface.Send(data, ""); err != nil {
|
||||
log.Printf("[DEBUG-7] Failed to forward announce on %s: %v", name, err)
|
||||
lastErr = err
|
||||
}
|
||||
}
|
||||
|
||||
// Notify announce handlers
|
||||
t.notifyAnnounceHandlers(destHash, identityBytes, appData)
|
||||
// Notify handlers with first address as destination hash
|
||||
t.notifyAnnounceHandlers(addresses[:16], id, appData)
|
||||
|
||||
return lastErr
|
||||
}
|
||||
|
||||
func (t *Transport) handleLinkPacket(data []byte, iface common.NetworkInterface) {
|
||||
if len(data) < 40 { // 32 bytes dest + 8 bytes timestamp minimum
|
||||
if len(data) < 40 {
|
||||
log.Printf("[DEBUG-3] Dropping link packet: insufficient length (%d bytes)", len(data))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -704,28 +776,28 @@ func (t *Transport) handleLinkPacket(data []byte, iface common.NetworkInterface)
|
||||
timestamp := binary.BigEndian.Uint64(data[32:40])
|
||||
payload := data[40:]
|
||||
|
||||
// Check if we're the destination
|
||||
log.Printf("[DEBUG-5] Link packet - Destination: %x, Timestamp: %d, Payload: %d bytes",
|
||||
dest, timestamp, len(payload))
|
||||
|
||||
if t.HasPath(dest) {
|
||||
nextHop := t.NextHop(dest)
|
||||
nextIfaceName := t.NextHopInterface(dest)
|
||||
log.Printf("[DEBUG-6] Found path - Next hop: %x, Interface: %s", nextHop, nextIfaceName)
|
||||
|
||||
// Only forward if received on different interface
|
||||
if nextIfaceName != iface.GetName() {
|
||||
if nextIface, ok := t.interfaces[nextIfaceName]; ok {
|
||||
log.Printf("[DEBUG-7] Forwarding link packet to %s", nextIfaceName)
|
||||
nextIface.Send(data, string(nextHop))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update timing information
|
||||
if link := t.findLink(dest); link != nil {
|
||||
log.Printf("[DEBUG-6] Updating link timing - Last inbound: %v", time.Unix(int64(timestamp), 0))
|
||||
link.lastInbound = time.Unix(int64(timestamp), 0)
|
||||
if link.packetCb != nil {
|
||||
// Create a packet object to pass to callback
|
||||
p := &packet.Packet{
|
||||
Data: payload,
|
||||
// Add other necessary packet fields
|
||||
}
|
||||
log.Printf("[DEBUG-7] Executing packet callback with %d bytes", len(payload))
|
||||
p := &packet.Packet{Data: payload}
|
||||
link.packetCb(payload, p)
|
||||
}
|
||||
}
|
||||
@@ -769,24 +841,33 @@ func (t *Transport) SendPacket(p *packet.Packet) error {
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
|
||||
// Serialize packet
|
||||
log.Printf("[DEBUG-4] Sending packet - Type: 0x%02x, Header: %d", p.PacketType, p.HeaderType)
|
||||
|
||||
data, err := p.Serialize()
|
||||
if err != nil {
|
||||
log.Printf("[DEBUG-3] Packet serialization failed: %v", err)
|
||||
return fmt.Errorf("failed to serialize packet: %w", err)
|
||||
}
|
||||
log.Printf("[DEBUG-5] Serialized packet size: %d bytes", len(data))
|
||||
|
||||
// Find appropriate interface
|
||||
destHash := p.Addresses[:packet.AddressSize]
|
||||
log.Printf("[DEBUG-6] Destination hash: %x", destHash)
|
||||
|
||||
path, exists := t.paths[string(destHash)]
|
||||
if !exists {
|
||||
log.Printf("[DEBUG-3] No path found for destination %x", destHash)
|
||||
return errors.New("no path to destination")
|
||||
}
|
||||
|
||||
// Send through interface
|
||||
log.Printf("[DEBUG-5] Using path - Interface: %s, Next hop: %x, Hops: %d",
|
||||
path.Interface.GetName(), path.NextHop, path.HopCount)
|
||||
|
||||
if err := path.Interface.Send(data, ""); err != nil {
|
||||
log.Printf("[DEBUG-3] Failed to send packet: %v", err)
|
||||
return fmt.Errorf("failed to send packet: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG-7] Packet sent successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -953,3 +1034,40 @@ func (l *Link) GetStatus() int {
|
||||
defer l.mutex.RUnlock()
|
||||
return l.status
|
||||
}
|
||||
|
||||
func CreateAnnouncePacket(destHash []byte, identity *identity.Identity, appData []byte, hops byte) []byte {
|
||||
packet := make([]byte, 0, 256)
|
||||
|
||||
// Header byte construction according to RNS spec
|
||||
headerByte := byte(
|
||||
(0 << 7) | // Interface flag (IFAC_NONE)
|
||||
(0 << 6) | // Header type (HEADER_TYPE_1)
|
||||
(0 << 5) | // Context flag
|
||||
(1 << 4) | // Propagation type (BROADCAST)
|
||||
(0 << 2) | // Destination type (SINGLE)
|
||||
PACKET_TYPE_ANNOUNCE, // Packet type (0x01)
|
||||
)
|
||||
|
||||
// Add header and hops
|
||||
packet = append(packet, headerByte, hops)
|
||||
|
||||
// Add destination hash (16 bytes)
|
||||
packet = append(packet, destHash...)
|
||||
|
||||
// Add full public key (64 bytes - both encryption and signing keys)
|
||||
fullPubKey := identity.GetPublicKey() // This should return full 64-byte key
|
||||
packet = append(packet, fullPubKey...)
|
||||
|
||||
// Add app data with length prefix
|
||||
appDataLen := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(appDataLen, uint16(len(appData)))
|
||||
packet = append(packet, appDataLen...)
|
||||
packet = append(packet, appData...)
|
||||
|
||||
// Sign the announce
|
||||
signData := append(destHash, appData...)
|
||||
signature := identity.Sign(signData)
|
||||
packet = append(packet, signature...)
|
||||
|
||||
return packet
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user