This commit is contained in:
Sudo-Ivan
2025-01-01 02:03:12 -06:00
parent 73af84e24f
commit 3ffd5b72a1
5 changed files with 259 additions and 69 deletions

View File

@@ -6,6 +6,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"log"
"sync"
"time"
@@ -153,23 +154,32 @@ func (a *Announce) HandleAnnounce(data []byte) error {
a.mutex.Lock()
defer a.mutex.Unlock()
log.Printf("[DEBUG-7] Handling announce packet of %d bytes", len(data))
// Minimum packet size validation (2 header + 16 hash + 32 pubkey + 1 hops + 2 appdata len + 64 sig)
if len(data) < 117 {
log.Printf("[DEBUG-7] Invalid announce data length: %d bytes", len(data))
return errors.New("invalid announce data length")
}
// Parse header
header := data[:2]
hopCount := header[1]
log.Printf("[DEBUG-7] Announce header: type=%x, hops=%d", header[0], hopCount)
if hopCount > MAX_HOPS {
log.Printf("[DEBUG-7] Announce exceeded max hops: %d", hopCount)
return errors.New("announce exceeded maximum hop count")
}
// Extract fields
// Extract fields with detailed logging
destHash := data[2:18]
publicKey := data[18:50]
hopsByte := data[50]
log.Printf("[DEBUG-7] Announce fields: destHash=%x, pubKeyLen=%d, hops=%d",
destHash, len(publicKey), hopsByte)
// Validate hop count matches header
if hopsByte != hopCount {
return errors.New("inconsistent hop count in packet")
@@ -410,3 +420,43 @@ func (a *Announce) Hash() []byte {
}
return a.hash
}
func (a *Announce) GetPacket() []byte {
a.mutex.Lock()
defer a.mutex.Unlock()
if a.packet == nil {
// Generate hash from announce data
h := sha256.New()
h.Write(a.destinationHash)
h.Write(a.identity.GetPublicKey())
h.Write([]byte{a.hops})
h.Write(a.appData)
if a.ratchetID != nil {
h.Write(a.ratchetID)
}
// Construct packet
packet := make([]byte, 0)
packet = append(packet, PACKET_TYPE_ANNOUNCE)
packet = append(packet, a.destinationHash...)
packet = append(packet, a.identity.GetPublicKey()...)
packet = append(packet, a.hops)
packet = append(packet, a.appData...)
if a.ratchetID != nil {
packet = append(packet, a.ratchetID...)
}
// Add signature
signData := append(a.destinationHash, a.appData...)
if a.ratchetID != nil {
signData = append(signData, a.ratchetID...)
}
signature := a.identity.Sign(signData)
packet = append(packet, signature...)
a.packet = packet
}
return a.packet
}

View File

@@ -5,6 +5,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"log"
"sync"
"github.com/Sudo-Ivan/reticulum-go/pkg/common"
@@ -121,8 +122,11 @@ func (d *Destination) Announce(appData []byte) error {
d.mutex.Lock()
defer d.mutex.Unlock()
log.Printf("[DEBUG-4] Creating announce packet for destination %s", d.ExpandName())
// If no specific appData provided, use default
if appData == nil {
log.Printf("[DEBUG-4] Using default app data for announce")
appData = d.defaultAppData
}
@@ -131,9 +135,12 @@ func (d *Destination) Announce(appData []byte) error {
// Add destination hash
packet = append(packet, d.hash...)
log.Printf("[DEBUG-4] Added destination hash %x to announce", d.hash[:8])
// Add identity public key
packet = append(packet, d.identity.GetPublicKey()...)
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)
@@ -144,46 +151,52 @@ func (d *Destination) Announce(appData []byte) error {
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 length and data if present
// 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 {
// No app data
packet = append(packet, 0x00, 0x00)
log.Printf("[DEBUG-4] Added empty app data to announce")
}
// Add ratchet data if enabled
if d.ratchetsEnabled {
// Add ratchet interval
log.Printf("[DEBUG-4] Adding ratchet data to announce")
intervalBytes := make([]byte, 4)
binary.BigEndian.PutUint32(intervalBytes, uint32(d.ratchetInterval))
packet = append(packet, intervalBytes...)
// Add current ratchet key
ratchetKey := d.identity.GetCurrentRatchetKey()
if ratchetKey == nil {
log.Printf("[DEBUG-3] Failed to get current ratchet key")
return errors.New("failed to get current ratchet key")
}
packet = append(packet, ratchetKey...)
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)
}
packet = append(packet, signature...)
log.Printf("[DEBUG-4] Added signature to announce packet (total size: %d bytes)", len(packet))
// Send announce packet through transport layer
// This will need to be implemented in the transport package
// Send announce packet
log.Printf("[DEBUG-4] Sending announce packet through transport layer")
return transport.SendAnnounce(packet)
}
@@ -305,26 +318,32 @@ func (d *Destination) DeregisterRequestHandler(path string) bool {
func (d *Destination) Encrypt(plaintext []byte) ([]byte, error) {
if d.destType == PLAIN {
log.Printf("[DEBUG-4] Using plaintext transmission for PLAIN destination")
return plaintext, nil
}
if d.identity == nil {
log.Printf("[DEBUG-3] Cannot encrypt: no identity available")
return nil, errors.New("no identity available for encryption")
}
log.Printf("[DEBUG-4] Encrypting %d bytes for destination type %d", len(plaintext), d.destType)
switch d.destType {
case SINGLE:
// For single destination, we need the recipient's public key
recipientKey := d.identity.GetPublicKey()
log.Printf("[DEBUG-4] Encrypting for single recipient with key %x", recipientKey[:8])
return d.identity.Encrypt(plaintext, recipientKey)
case GROUP:
key := d.identity.GetCurrentRatchetKey()
if key == nil {
log.Printf("[DEBUG-3] Cannot encrypt: no ratchet key available")
return nil, errors.New("no ratchet key available")
}
// CBC encryption with HMAC for group messages
log.Printf("[DEBUG-4] Encrypting for group with ratchet key %x", key[:8])
return d.identity.EncryptWithHMAC(plaintext, key)
default:
log.Printf("[DEBUG-3] Unsupported destination type %d for encryption", d.destType)
return nil, errors.New("unsupported destination type for encryption")
}
}

View File

@@ -184,6 +184,7 @@ func (tc *TCPClientInterface) readLoop() {
func (tc *TCPClientInterface) handlePacket(data []byte) {
if len(data) < 1 {
log.Printf("[DEBUG-7] Received invalid packet: empty")
return
}
@@ -194,19 +195,22 @@ func (tc *TCPClientInterface) handlePacket(data []byte) {
tc.lastRx = lastRx
tc.mutex.Unlock()
log.Printf("[DEBUG-5] Interface %s RX: %d bytes, total: %d, rate: %.2f Kbps",
tc.GetName(), len(data), tc.RxBytes,
float64(tc.RxBytes*8)/(time.Since(tc.startTime).Seconds()*1000))
log.Printf("[DEBUG-7] Received packet: type=0x%02x, size=%d bytes", tc.packetType, len(data))
payload := data[1:]
switch tc.packetType {
case 0x01: // Announce packet
if len(payload) >= 53 { // Minimum announce size
log.Printf("[DEBUG-7] Processing announce packet: payload=%d bytes", len(payload))
if len(payload) >= 53 {
tc.BaseInterface.ProcessIncoming(payload)
} else {
log.Printf("[DEBUG-7] Announce packet too small: %d bytes", len(payload))
}
case 0x02: // Link packet
if len(payload) < 40 { // minimum size for link packet
log.Printf("[DEBUG-7] Processing link packet: payload=%d bytes", len(payload))
if len(payload) < 40 {
log.Printf("[DEBUG-7] Link packet too small: %d bytes", len(payload))
return
}
tc.BaseInterface.ProcessIncoming(payload)

View File

@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
"log"
"sync"
"time"
@@ -104,27 +105,32 @@ func (l *Link) Establish() error {
defer l.mutex.Unlock()
if l.status != STATUS_PENDING {
log.Printf("[DEBUG-3] Cannot establish link: invalid status %d", l.status)
return errors.New("link already established or failed")
}
destPublicKey := l.destination.GetPublicKey()
if destPublicKey == nil {
log.Printf("[DEBUG-3] Cannot establish link: destination has no public key")
return errors.New("destination has no public key")
}
log.Printf("[DEBUG-4] Creating link request packet for destination %x", destPublicKey[:8])
// Create link request packet
p, err := packet.NewPacket(
packet.PACKET_TYPE_LINK,
0x00, // flags
0x00, // hops
0x00,
0x00,
destPublicKey,
l.linkID,
)
if err != nil {
log.Printf("[DEBUG-3] Failed to create link request packet: %v", err)
return err
}
// Send through transport
log.Printf("[DEBUG-4] Sending link request packet with ID %x", l.linkID[:8])
return l.transport.SendPacket(p)
}
@@ -153,26 +159,32 @@ func (l *Link) HandleIdentification(data []byte) error {
defer l.mutex.Unlock()
if len(data) < ed25519.PublicKeySize+ed25519.SignatureSize {
log.Printf("[DEBUG-3] Invalid identification data length: %d bytes", len(data))
return errors.New("invalid identification data length")
}
pubKey := data[:ed25519.PublicKeySize]
signature := data[ed25519.PublicKeySize:]
log.Printf("[DEBUG-4] Processing identification from public key %x", pubKey[:8])
remoteIdentity := identity.FromPublicKey(pubKey)
if remoteIdentity == nil {
log.Printf("[DEBUG-3] Invalid remote identity from public key %x", pubKey[:8])
return errors.New("invalid remote identity")
}
// Verify signature
signData := append(l.linkID, pubKey...)
if !remoteIdentity.Verify(signData, signature) {
log.Printf("[DEBUG-3] Invalid signature from remote identity %x", pubKey[:8])
return errors.New("invalid signature")
}
log.Printf("[DEBUG-4] Remote identity verified successfully: %x", pubKey[:8])
l.remoteIdentity = remoteIdentity
if l.identifiedCallback != nil {
log.Printf("[DEBUG-4] Executing identified callback for remote identity %x", pubKey[:8])
l.identifiedCallback(l, remoteIdentity)
}
@@ -443,28 +455,21 @@ func (l *Link) SendPacket(data []byte) error {
defer l.mutex.Unlock()
if l.status != STATUS_ACTIVE {
log.Printf("[DEBUG-3] Cannot send packet: link not active (status: %d)", l.status)
return errors.New("link not active")
}
// Compute HMAC first
messageHMAC := l.destination.GetIdentity().ComputeHMAC(l.hmacKey, data)
// Combine data and HMAC
authenticatedData := append(data, messageHMAC...)
// Encrypt authenticated data using session key
encryptedData, err := l.encrypt(authenticatedData)
log.Printf("[DEBUG-4] Encrypting packet of %d bytes", len(data))
encrypted, err := l.encrypt(data)
if err != nil {
log.Printf("[DEBUG-3] Failed to encrypt packet: %v", err)
return err
}
log.Printf("[DEBUG-4] Sending encrypted packet of %d bytes", len(encrypted))
l.lastOutbound = time.Now()
l.lastDataSent = time.Now()
if l.packetCallback != nil {
l.packetCallback(encryptedData, nil)
}
return nil
}
@@ -473,25 +478,51 @@ func (l *Link) HandleInbound(data []byte) error {
defer l.mutex.Unlock()
if l.status != STATUS_ACTIVE {
log.Printf("[DEBUG-3] Dropping inbound packet: link not active (status: %d)", l.status)
return errors.New("link not active")
}
log.Printf("[DEBUG-7] Received encrypted packet of %d bytes", len(data))
// Decrypt data using session key
decryptedData, err := l.decrypt(data)
if err != nil {
log.Printf("[DEBUG-3] Failed to decrypt packet: %v", err)
return err
}
// Split message and HMAC
if len(decryptedData) < sha256.Size {
log.Printf("[DEBUG-3] Received data too short: %d bytes", len(decryptedData))
return errors.New("received data too short")
}
message := decryptedData[:len(decryptedData)-sha256.Size]
messageHMAC := decryptedData[len(decryptedData)-sha256.Size:]
// Log packet details
log.Printf("[DEBUG-7] Decrypted packet details:")
log.Printf("[DEBUG-7] - Size: %d bytes", len(message))
log.Printf("[DEBUG-7] - First 16 bytes: %x", message[:min(16, len(message))])
if len(message) > 0 {
log.Printf("[DEBUG-7] - Type: 0x%02x", message[0])
switch message[0] {
case packet.PacketData:
log.Printf("[DEBUG-7] - Type: Data Packet")
case packet.PacketAnnounce:
log.Printf("[DEBUG-7] - Type: Announce Packet")
case packet.PacketLinkRequest:
log.Printf("[DEBUG-7] - Type: Link Request")
case packet.PacketProof:
log.Printf("[DEBUG-7] - Type: Proof Request")
default:
log.Printf("[DEBUG-7] - Type: Unknown (0x%02x)", message[0])
}
}
// Verify HMAC
if !l.destination.GetIdentity().ValidateHMAC(l.hmacKey, message, messageHMAC) {
log.Printf("[DEBUG-3] Invalid HMAC for packet")
return errors.New("invalid message authentication code")
}
@@ -637,23 +668,31 @@ func (l *Link) maintainLink() {
ticker := time.NewTicker(time.Second * KEEPALIVE)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if l.status != STATUS_ACTIVE {
return
}
for range ticker.C {
if l.status != STATUS_ACTIVE {
return
}
if l.InactiveFor() > float64(STALE_TIME) {
inactiveTime := l.InactiveFor()
if inactiveTime > float64(STALE_TIME) {
l.mutex.Lock()
l.teardownReason = STATUS_FAILED
l.mutex.Unlock()
l.Teardown()
return
}
noDataTime := l.NoDataFor()
if noDataTime > float64(KEEPALIVE) {
l.mutex.Lock()
err := l.SendPacket([]byte{})
if err != nil {
l.teardownReason = STATUS_FAILED
l.mutex.Unlock()
l.Teardown()
return
}
if l.NoDataFor() > float64(KEEPALIVE) {
// Send keepalive packet
l.SendPacket([]byte{})
}
l.mutex.Unlock()
}
}
}
@@ -697,3 +736,11 @@ func (l *Link) HandleProofRequest(packet *packet.Packet) bool {
return false
}
}
// Helper function for min of two ints
func min(a, b int) int {
if a < b {
return a
}
return b
}

View File

@@ -384,11 +384,69 @@ func (t *Transport) UpdatePath(destinationHash []byte, nextHop []byte, interface
}
}
func (t *Transport) HandleAnnounce(destinationHash []byte, identity []byte, appData []byte, announceHash []byte) {
t.mutex.RLock()
defer t.mutex.RUnlock()
func (t *Transport) HandleAnnounce(data []byte, sourceIface common.NetworkInterface) error {
if len(data) < 53 { // Minimum size for announce packet
return fmt.Errorf("announce packet too small: %d bytes", len(data))
}
t.notifyAnnounceHandlers(destinationHash, identity, appData)
log.Printf("[DEBUG-7] Transport handling announce of %d bytes from %s",
len(data), sourceIface.GetName())
// Parse announce fields according to RNS spec
destHash := data[1:33]
identity := data[33:49]
appData := data[49:]
// Generate announce hash to check for duplicates
announceHash := sha256.Sum256(data)
hashStr := string(announceHash[:])
t.mutex.Lock()
if _, seen := t.seenAnnounces[hashStr]; seen {
t.mutex.Unlock()
log.Printf("[DEBUG-7] Ignoring duplicate announce %x", announceHash[:8])
return nil
}
t.seenAnnounces[hashStr] = true
t.mutex.Unlock()
// Don't forward if max hops reached
if data[0] >= MAX_HOPS {
log.Printf("[DEBUG-7] Announce exceeded max hops: %d", data[0])
return nil
}
// Add random delay before retransmission (0-2 seconds)
delay := time.Duration(rand.Float64() * 2 * float64(time.Second))
time.Sleep(delay)
// Check bandwidth allocation for announces
if !t.announceRate.Allow() {
log.Printf("[DEBUG-7] Announce rate limit exceeded, queuing...")
return nil
}
// Increment hop count
data[0]++
// Broadcast to all other interfaces
var lastErr error
for name, iface := range t.interfaces {
if iface == sourceIface || !iface.IsEnabled() {
continue
}
log.Printf("[DEBUG-7] Forwarding announce on interface %s", name)
if err := iface.Send(data, ""); err != nil {
log.Printf("[DEBUG-7] Failed to forward announce on %s: %v", name, err)
lastErr = err
}
}
// Notify handlers
t.notifyAnnounceHandlers(destHash, identity, appData)
return lastErr
}
func (t *Transport) NewDestination(identity interface{}, direction int, destType int, appName string, aspects ...string) *Destination {
@@ -541,13 +599,13 @@ func (t *Transport) HandlePacket(data []byte, iface common.NetworkInterface) {
// Update interface stats before processing
if tcpIface, ok := iface.(*interfaces.TCPClientInterface); ok {
tcpIface.UpdateStats(uint64(len(data)), true) // true for RX
tcpIface.UpdateStats(uint64(len(data)), true)
}
switch packetType {
case 0x01: // Announce packet
case announce.PACKET_TYPE_ANNOUNCE:
t.handleAnnouncePacket(data[1:], iface)
case 0x02: // Link packet
case announce.PACKET_TYPE_LINK:
t.handleLinkPacket(data[1:], iface)
case 0x03: // Path response
t.handlePathResponse(data[1:], iface)
@@ -559,52 +617,64 @@ func (t *Transport) HandlePacket(data []byte, iface common.NetworkInterface) {
}
func (t *Transport) handleAnnouncePacket(data []byte, iface common.NetworkInterface) {
// Validate minimum packet size (1 byte hop count + 32 bytes dest + 16 bytes identity + 4 bytes min app data)
if len(data) < 53 {
log.Printf("[DEBUG-3] Announce packet too small: %d bytes", len(data))
return
}
announceHash := sha256.Sum256(data)
log.Printf("[DEBUG-3] Processing announce %x from interface %s",
announceHash[:8], iface.GetName())
if t.seenAnnounces[string(announceHash[:])] {
t.mutex.Lock()
if _, seen := t.seenAnnounces[string(announceHash[:])]; seen {
t.mutex.Unlock()
log.Printf("[DEBUG-4] Ignoring duplicate announce %x", announceHash[:8])
return
}
// Record this announce
t.seenAnnounces[string(announceHash[:])] = true
// Extract announce fields
if len(data) < 53 { // Minimum size for announce packet
return
}
t.mutex.Unlock()
// Don't forward if max hops reached
if data[0] >= MAX_HOPS {
log.Printf("[DEBUG-3] Announce exceeded max hops: %d", data[0])
return
}
// Parse announce fields
hopCount := data[0]
destHash := data[1:33]
identity := data[33:49]
appData := data[49:]
// Add random delay before retransmission (0-2 seconds)
delay := time.Duration(rand.Float64() * 2 * float64(time.Second))
time.Sleep(delay)
// Check bandwidth allocation for announces
if !t.announceRate.Allow() {
log.Printf("[DEBUG-3] Announce rate limit exceeded, dropping")
return
}
// Increment hop count and retransmit
data[0]++
t.broadcastAnnouncePacket(data)
}
// Increment hop count for forwarding
data[0] = hopCount + 1
func (t *Transport) broadcastAnnouncePacket(data []byte) error {
t.mutex.RLock()
defer t.mutex.RUnlock()
// Forward to other interfaces
for name, outIface := range t.interfaces {
if outIface == iface || !outIface.IsEnabled() {
continue
}
for _, iface := range t.interfaces {
if err := iface.Send(data, ""); err != nil {
return fmt.Errorf("failed to broadcast announce: %w", err)
log.Printf("[DEBUG-7] Forwarding announce on interface %s", name)
if err := outIface.Send(data, ""); err != nil {
log.Printf("[DEBUG-3] Failed to forward announce on %s: %v", name, err)
}
}
return nil
// Notify announce handlers
t.notifyAnnounceHandlers(destHash, identity, appData)
}
func (t *Transport) handleLinkPacket(data []byte, iface common.NetworkInterface) {