This commit is contained in:
Sudo-Ivan
2024-12-30 04:00:52 -06:00
parent decbd8f29a
commit 139926be05
4 changed files with 196 additions and 60 deletions

57
To-Do
View File

@@ -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
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

View File

@@ -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")
}
}
}

View File

@@ -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
}
}
// 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
}

View File

@@ -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:]