From 3ffd5b72a113b00e9b0f9299772cef2b830d4934 Mon Sep 17 00:00:00 2001 From: Sudo-Ivan Date: Wed, 1 Jan 2025 02:03:12 -0600 Subject: [PATCH] update --- pkg/announce/announce.go | 52 +++++++++++++- pkg/destination/destination.go | 37 +++++++--- pkg/interfaces/tcp.go | 14 ++-- pkg/link/link.go | 103 ++++++++++++++++++++-------- pkg/transport/transport.go | 122 ++++++++++++++++++++++++++------- 5 files changed, 259 insertions(+), 69 deletions(-) diff --git a/pkg/announce/announce.go b/pkg/announce/announce.go index 5bf0ad3..ea64e72 100644 --- a/pkg/announce/announce.go +++ b/pkg/announce/announce.go @@ -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 +} diff --git a/pkg/destination/destination.go b/pkg/destination/destination.go index 2096650..09e014c 100644 --- a/pkg/destination/destination.go +++ b/pkg/destination/destination.go @@ -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") } } diff --git a/pkg/interfaces/tcp.go b/pkg/interfaces/tcp.go index 4e87cae..24a1d0d 100644 --- a/pkg/interfaces/tcp.go +++ b/pkg/interfaces/tcp.go @@ -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) diff --git a/pkg/link/link.go b/pkg/link/link.go index 927d942..a1c20a3 100644 --- a/pkg/link/link.go +++ b/pkg/link/link.go @@ -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 +} diff --git a/pkg/transport/transport.go b/pkg/transport/transport.go index 7ec9170..d72a5e3 100644 --- a/pkg/transport/transport.go +++ b/pkg/transport/transport.go @@ -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) {