From 139926be054ec44feacf003ec12bdec72ac1a73f Mon Sep 17 00:00:00 2001 From: Sudo-Ivan Date: Mon, 30 Dec 2024 04:00:52 -0600 Subject: [PATCH] 0.2.5 --- To-Do | 57 +++++++++++++++-- cmd/client/client.go | 53 ++++++++------- pkg/announce/announce.go | 135 +++++++++++++++++++++++++++++---------- pkg/identity/identity.go | 11 +++- 4 files changed, 196 insertions(+), 60 deletions(-) diff --git a/To-Do b/To-Do index e89ac6e..af813dc 100644 --- a/To-Do +++ b/To-Do @@ -89,12 +89,22 @@ Basic Features [✓] Connection management [✓] Packet framing [✓] Transport integration + [ ] Auto Interface support + [ ] Interface modes (full, gateway, ap, roaming, boundary) + [ ] Interface bandwidth control + [ ] Interface statistics + [ ] Interface health monitoring + [ ] Interface reconnection logic + [ ] Multi-interface routing + [ ] Interface priority handling [✓] Announce System [✓] Announce creation [✓] Announce propagation [✓] Path requests [✓] Announce validation + [ ] Announce rate limiting + [ ] Interface-specific announce rules [✓] Resource Management [✓] Resource tracking @@ -109,22 +119,61 @@ Basic Features [✓] Message sending/receiving [✓] Identity management -Next Immediate Tasks: 1. [✓] Fix import cycles by creating common package 2. [✓] Complete NetworkInterface implementation 3. [✓] Add comprehensive interface tests 4. [✓] Implement connection retry logic 5. [✓] Add client reconnection handling 6. [ ] Implement Interface discovery + - [ ] Auto interface detection + - [ ] Interface capability detection + - [ ] Interface mode configuration + - [ ] Interface bandwidth detection + 7. [ ] Test network layer integration end-to-end + - [ ] Multi-interface testing + - [ ] Interface failover testing + - [ ] Mode-specific behavior testing + 8. [ ] Add error handling for network failures + - [ ] Interface reconnection logic + - [ ] Packet retry mechanisms + - [ ] Interface fallback handling + 9. [ ] Implement interface auto-configuration + - [ ] IPv6 link-local detection + - [ ] Interface mode auto-selection + - [ ] MTU discovery + - [ ] Bandwidth detection + 10. [ ] Add metrics collection for interfaces + - [ ] Bandwidth usage tracking + - [ ] Packet success/failure rates + - [ ] Latency measurements + - [ ] Interface health metrics + 11. [ ] Implement client-side path caching 12. [ ] Add support for additional transport types -13. [ ] Implement perfect forward secrecy -14. [ ] Add post-quantum cryptographic primitives +14. [ ] Add post-quantum cryptographic primitives (Future) 15. [ ] Implement secure key rotation 16. [ ] Add support for encrypted storage of identities 17. [ ] Implement secure memory handling -18. [ ] Add support for hardware security modules \ No newline at end of file +18. [ ] Add support for hardware security modules (HSM) +19. [ ] Implement interface modes + - [ ] Full mode implementation + - [ ] Gateway mode implementation + - [ ] Access point mode implementation + - [ ] Roaming mode implementation + - [ ] Boundary mode implementation + +20. [ ] Add interface bandwidth management + - [ ] Rate limiting + - [ ] QoS implementation + - [ ] Priority queuing + - [ ] Congestion control + +21. [ ] Implement interface discovery system + - [ ] Auto interface detection + - [ ] Interface capability probing + - [ ] Dynamic interface configuration + - [ ] Interface health checking \ No newline at end of file diff --git a/cmd/client/client.go b/cmd/client/client.go index 84f65d4..d636b48 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -13,6 +13,7 @@ import ( "time" "github.com/Sudo-Ivan/reticulum-go/internal/config" + "github.com/Sudo-Ivan/reticulum-go/pkg/announce" "github.com/Sudo-Ivan/reticulum-go/pkg/common" "github.com/Sudo-Ivan/reticulum-go/pkg/destination" "github.com/Sudo-Ivan/reticulum-go/pkg/identity" @@ -156,25 +157,26 @@ func (c *Client) handleAnnounce(data []byte) { func (c *Client) sendAnnounce() { announceData := make([]byte, 0) - // Packet type (1 byte) - announceData = append(announceData, 0x04) + // Create header + header := announce.CreateHeader( + announce.IFAC_NONE, + announce.HEADER_TYPE_1, + 0x00, + announce.PROP_TYPE_BROADCAST, + announce.DEST_TYPE_SINGLE, + announce.PACKET_TYPE_ANNOUNCE, + 0x00, + ) + announceData = append(announceData, header...) - // Destination hash (16 bytes) - destHash := identity.TruncatedHash(c.identity.GetPublicKey()) - announceData = append(announceData, destHash...) + // Add destination hash (16 bytes truncated) + identityHash := c.identity.Hash() + announceData = append(announceData, identityHash...) - // Timestamp (8 bytes) - timeBytes := make([]byte, 8) - binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix())) - announceData = append(announceData, timeBytes...) + // Add context byte + announceData = append(announceData, announce.ANNOUNCE_IDENTITY) - // Hops (1 byte) - announceData = append(announceData, 0x00) - - // Flags (1 byte) - announceData = append(announceData, 0x00) - - // Public key + // Add public key announceData = append(announceData, c.identity.GetPublicKey()...) // App data with length prefix @@ -184,21 +186,26 @@ func (c *Client) sendAnnounce() { announceData = append(announceData, lenBytes...) announceData = append(announceData, appData...) - // Sign the announce data - signData := append(destHash, c.identity.GetPublicKey()...) + // Add signature + signData := append(identityHash, c.identity.GetPublicKey()...) signData = append(signData, appData...) signature := c.identity.Sign(signData) announceData = append(announceData, signature...) - log.Printf("Sending announce for identity: %s", c.identity.Hex()) - log.Printf("Announce packet length: %d bytes", len(announceData)) - log.Printf("Announce packet hex: %x", announceData) + log.Printf("Sending announce:") + log.Printf(" Identity Hash: %x", identityHash) + log.Printf(" Packet Length: %d bytes", len(announceData)) + log.Printf(" Full Packet: %x", announceData) + // Send on all interfaces for _, iface := range c.interfaces { + log.Printf("Sending on interface %s (%s):", iface.GetName(), iface.GetType()) + log.Printf(" MTU: %d bytes", iface.GetMTU()) + if err := iface.Send(announceData, ""); err != nil { - log.Printf("Failed to send announce on interface %s: %v", iface.GetName(), err) + log.Printf(" Failed to send: %v", err) } else { - log.Printf("Sent announce on interface %s", iface.GetName()) + log.Printf(" Successfully sent announce") } } } diff --git a/pkg/announce/announce.go b/pkg/announce/announce.go index 94cd23b..0942af9 100644 --- a/pkg/announce/announce.go +++ b/pkg/announce/announce.go @@ -2,19 +2,46 @@ package announce import ( "crypto/sha256" + "encoding/binary" "errors" + "log" "sync" "time" - "github.com/Sudo-Ivan/reticulum-go/pkg/identity" "github.com/Sudo-Ivan/reticulum-go/pkg/common" + "github.com/Sudo-Ivan/reticulum-go/pkg/identity" ) const ( + // Packet Types + PACKET_TYPE_DATA = 0x00 + PACKET_TYPE_ANNOUNCE = 0x01 + PACKET_TYPE_LINK = 0x02 + PACKET_TYPE_PROOF = 0x03 + + // Announce Types 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 + + // IFAC Flag + IFAC_NONE = 0x00 + IFAC_AUTH = 0x80 // Most significant bit + MAX_HOPS = 128 PROPAGATION_RATE = 0.02 // 2% of interface bandwidth RETRY_INTERVAL = 300 // 5 minutes @@ -30,14 +57,14 @@ type AnnounceHandler interface { type Announce struct { mutex sync.RWMutex destinationHash []byte - identity *identity.Identity - appData []byte - hops uint8 - timestamp int64 - signature []byte - pathResponse bool - retries int - handlers []AnnounceHandler + identity *identity.Identity + appData []byte + hops uint8 + timestamp int64 + signature []byte + pathResponse bool + retries int + handlers []AnnounceHandler } func New(dest *identity.Identity, appData []byte, pathResponse bool) (*Announce, error) { @@ -64,32 +91,24 @@ func New(dest *identity.Identity, appData []byte, pathResponse bool) (*Announce, } func (a *Announce) Propagate(interfaces []common.NetworkInterface) error { - a.mutex.Lock() - defer a.mutex.Unlock() + packet := a.CreatePacket() - if a.hops >= MAX_HOPS { - return errors.New("maximum hop count reached") - } + log.Printf("Propagating announce:") + log.Printf(" Destination Hash: %x", a.destinationHash) + log.Printf(" Public Key: %x", a.identity.GetPublicKey()) + log.Printf(" App Data: %s", string(a.appData)) + log.Printf(" Packet Size: %d bytes", len(packet)) + log.Printf(" Full Packet: %x", packet) - // Increment hop count - a.hops++ - - // Create announce packet - packet := make([]byte, 0) - packet = append(packet, a.destinationHash...) - packet = append(packet, a.identity.GetPublicKey()...) - packet = append(packet, byte(a.hops)) - - if a.appData != nil { - packet = append(packet, a.appData...) - } - - packet = append(packet, a.signature...) - - // Propagate to all interfaces + // Propagate to interfaces for _, iface := range interfaces { + log.Printf("Propagating on interface %s (%s):", iface.GetName(), iface.GetType()) + log.Printf(" MTU: %d bytes", iface.GetMTU()) + if err := iface.Send(packet, ""); err != nil { - return err + log.Printf(" Failed to propagate: %v", err) + } else { + log.Printf(" Successfully propagated") } } @@ -175,4 +194,56 @@ func (a *Announce) RequestPath(destHash []byte, onInterface common.NetworkInterf } return nil -} \ No newline at end of file +} + +// CreateHeader creates a Reticulum packet header according to spec +func CreateHeader(ifacFlag byte, headerType byte, contextFlag byte, propType byte, destType byte, packetType byte, hops byte) []byte { + header := make([]byte, 2) + + // First byte: [IFAC Flag], [Header Type], [Context Flag], [Propagation Type], [Destination Type] and [Packet Type] + header[0] = ifacFlag | (headerType << 6) | (contextFlag << 5) | + (propType << 4) | (destType << 2) | packetType + + // Second byte: Number of hops + header[1] = hops + + return header +} + +func (a *Announce) CreatePacket() []byte { + packet := make([]byte, 0) + + // Create header for announce packet + header := CreateHeader( + IFAC_NONE, // No interface authentication + 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 + byte(a.hops), // Current hop count + ) + packet = append(packet, header...) + + // Add destination hash (16 bytes) + packet = append(packet, a.destinationHash...) + + // Add context byte + packet = append(packet, ANNOUNCE_IDENTITY) + + // Add public key + packet = append(packet, a.identity.GetPublicKey()...) + + // Add app data with length prefix + if a.appData != nil { + lenBytes := make([]byte, 2) + binary.BigEndian.PutUint16(lenBytes, uint16(len(a.appData))) + packet = append(packet, lenBytes...) + packet = append(packet, a.appData...) + } + + // Add signature + packet = append(packet, a.signature...) + + return packet +} diff --git a/pkg/identity/identity.go b/pkg/identity/identity.go index 1d7ce27..2a32904 100644 --- a/pkg/identity/identity.go +++ b/pkg/identity/identity.go @@ -183,7 +183,8 @@ func (i *Identity) Encrypt(plaintext []byte, ratchet []byte) ([]byte, error) { func (i *Identity) Hash() []byte { h := sha256.New() h.Write(i.GetPublicKey()) - return h.Sum(nil) + fullHash := h.Sum(nil) + return fullHash[:TruncatedHashLen/8] } func TruncatedHash(data []byte) []byte { @@ -200,6 +201,10 @@ func GetRandomHash() []byte { } func Remember(packetHash, destHash []byte, publicKey []byte, appData []byte) { + if len(destHash) > TruncatedHashLen/8 { + destHash = destHash[:TruncatedHashLen/8] + } + knownDestinations[string(destHash)] = []interface{}{ time.Now().Unix(), packetHash, @@ -213,6 +218,10 @@ func ValidateAnnounce(packet []byte, destHash []byte, publicKey []byte, signatur return false } + if len(destHash) > TruncatedHashLen/8 { + destHash = destHash[:TruncatedHashLen/8] + } + announced := &Identity{} announced.publicKey = publicKey[:KeySize/16] announced.verificationKey = publicKey[KeySize/16:]