# Découverte des Nœuds et Ajout de Nœuds Externes ## Comment les relais découvrent-ils initialement les autres nœuds ? ### 1. Découverte automatique (actuelle) Actuellement, les relais utilisent une **découverte statique** basée sur les noms de conteneurs Docker : ```rust // Dans sync.rs - discover_relays() let relay_hosts = vec![ "sdk_relay_1", "sdk_relay_2", "sdk_relay_3", ]; ``` **Mécanisme :** 1. Chaque relais a une liste prédéfinie des autres relais 2. Au démarrage, il tente de se connecter à chaque relais de la liste 3. Il ignore son propre nom (`relay_id`) 4. Il ajoute les relais découverts à sa liste `known_relays` ### 2. Configuration par relay_id Chaque relais a un `relay_id` unique dans sa configuration : ```toml # .conf.docker.relay1 relay_id=relay-1 # .conf.docker.relay2 relay_id=relay-2 # .conf.docker.relay3 relay_id=relay-3 ``` ### 3. Partage de la liste des relais Une fois connectés, les relais partagent leur liste de relais connus via des messages `RelaySync` : ```rust // Création d'un message RelaySync pub fn create_relay_sync(&self) -> Result { let known_relays = self.known_relays.lock().unwrap(); let relays: Vec = known_relays.values().cloned().collect(); let payload = SyncPayload::RelayData { relays, network_topology, }; Ok(SyncMessage::new(SyncType::RelaySync, self.relay_id.clone(), payload)) } ``` ## Comment ajouter un nœud externe ? ### Option 1: Modification de la liste statique **Pour ajouter un nœud externe, il faut modifier le code source :** ```rust // Dans sync.rs - discover_relays() let relay_hosts = vec![ "sdk_relay_1", "sdk_relay_2", "sdk_relay_3", "external-relay-1", // ← Nouveau nœud externe "external-relay-2", // ← Autre nœud externe ]; ``` **Avantages :** - Simple à implémenter - Contrôle total sur les nœuds autorisés **Inconvénients :** - Nécessite une recompilation - Pas flexible pour l'ajout dynamique - Centralisé ### Option 2: Configuration externe (recommandée) **Créer un fichier de configuration pour les nœuds externes :** ```toml # external_nodes.conf [relays] external-relay-1 = "external-relay-1.example.com:8090" external-relay-2 = "external-relay-2.example.com:8090" external-relay-3 = "192.168.1.100:8090" [discovery] auto_discover = true bootstrap_nodes = [ "bootstrap-1.4nk.net:8090", "bootstrap-2.4nk.net:8090" ] ``` **Modification du code pour supporter la configuration :** ```rust pub struct DiscoveryConfig { pub external_relays: HashMap, pub auto_discover: bool, pub bootstrap_nodes: Vec, } impl SyncManager { pub fn load_discovery_config(&self) -> Result { // Charger depuis external_nodes.conf } pub async fn discover_relays(&self) -> Result<()> { let config = self.load_discovery_config()?; // Découverte locale (Docker) for host in &["sdk_relay_1", "sdk_relay_2", "sdk_relay_3"] { // ... logique existante } // Découverte externe for (relay_id, address) in &config.external_relays { let relay_info = RelayInfo { relay_id: relay_id.clone(), address: address.clone(), // ... autres champs }; self.add_relay(relay_info)?; } // Découverte via bootstrap nodes if config.auto_discover { for bootstrap in &config.bootstrap_nodes { self.discover_via_bootstrap(bootstrap).await?; } } Ok(()) } } ``` ### Option 3: Découverte via DNS **Utiliser des enregistrements DNS pour la découverte :** ```rust pub async fn discover_via_dns(&self, domain: &str) -> Result<()> { // Résoudre les enregistrements SRV ou A let addresses = dns_lookup::get_host_addresses(domain)?; for addr in addresses { let relay_info = RelayInfo { relay_id: format!("relay-{}", addr), address: format!("{}:8090", addr), // ... autres champs }; self.add_relay(relay_info)?; } Ok(()) } ``` ### Option 4: Découverte via API REST **Créer une API pour l'enregistrement des nœuds :** ```rust // Endpoint pour enregistrer un nouveau nœud POST /api/relays/register { "relay_id": "external-relay-1", "address": "external-relay-1.example.com:8090", "capabilities": ["sync", "mesh"], "version": "1.0.0" } // Endpoint pour récupérer la liste des nœuds GET /api/relays/list ``` ## Implémentation recommandée ### 1. Créer un fichier de configuration externe ```bash # Créer le fichier de configuration cat > 4NK/4NK_node/sdk_relay/external_nodes.conf << EOF [relays] # Nœuds externes connus external-relay-1 = "external-relay-1.example.com:8090" external-relay-2 = "192.168.1.100:8090" [discovery] auto_discover = true bootstrap_nodes = [ "bootstrap-1.4nk.net:8090" ] [security] allowed_domains = [ "*.4nk.net", "*.example.com" ] EOF ``` ### 2. Modifier le code pour supporter la configuration ```rust // Dans sync.rs use std::fs; use toml; #[derive(Debug, Deserialize)] struct ExternalConfig { relays: HashMap, discovery: DiscoverySettings, security: SecuritySettings, } #[derive(Debug, Deserialize)] struct DiscoverySettings { auto_discover: bool, bootstrap_nodes: Vec, } #[derive(Debug, Deserialize)] struct SecuritySettings { allowed_domains: Vec, } impl SyncManager { pub fn load_external_config(&self) -> Result { let config_content = fs::read_to_string("external_nodes.conf")?; let config: ExternalConfig = toml::from_str(&config_content)?; Ok(config) } pub async fn discover_relays(&self) -> Result<()> { // Découverte locale (existante) let local_hosts = vec!["sdk_relay_1", "sdk_relay_2", "sdk_relay_3"]; for host in local_hosts { // ... logique existante } // Découverte externe (nouvelle) if let Ok(config) = self.load_external_config() { for (relay_id, address) in &config.relays { let relay_info = RelayInfo { relay_id: relay_id.clone(), address: address.clone(), sp_address: "".to_string(), version: "1.0.0".to_string(), uptime: 0, last_seen: SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(), capabilities: vec!["sync".to_string(), "mesh".to_string()], health_status: HealthStatus::Healthy, }; self.add_relay(relay_info)?; } } Ok(()) } } ``` ### 3. Script pour ajouter un nœud externe ```bash #!/bin/bash # add_external_node.sh RELAY_ID=$1 ADDRESS=$2 CONFIG_FILE="4NK/4NK_node/sdk_relay/external_nodes.conf" if [ -z "$RELAY_ID" ] || [ -z "$ADDRESS" ]; then echo "Usage: $0 " echo "Example: $0 external-relay-1 external-relay-1.example.com:8090" exit 1 fi # Ajouter le nœud à la configuration echo "Adding external node: $RELAY_ID -> $ADDRESS" # Vérifier si le fichier existe if [ ! -f "$CONFIG_FILE" ]; then cat > "$CONFIG_FILE" << EOF [relays] [discovery] auto_discover = true bootstrap_nodes = [] [security] allowed_domains = ["*.4nk.net"] EOF fi # Ajouter le nœud sed -i "/^\[relays\]$/a $RELAY_ID = \"$ADDRESS\"" "$CONFIG_FILE" echo "✅ External node added successfully!" echo "🔄 Restart relays to apply changes:" echo " docker-compose restart sdk_relay_1 sdk_relay_2 sdk_relay_3" ``` ## Sécurité et validation ### Validation des nœuds externes ```rust impl SyncManager { pub fn validate_external_relay(&self, relay_info: &RelayInfo) -> Result { // Vérifier le format de l'adresse if !self.is_valid_address(&relay_info.address) { return Ok(false); } // Vérifier le domaine autorisé if !self.is_allowed_domain(&relay_info.address) { return Ok(false); } // Vérifier la connectivité if !self.can_connect_to_relay(&relay_info.address).await? { return Ok(false); } Ok(true) } pub async fn can_connect_to_relay(&self, address: &str) -> Result { // Test de connectivité WebSocket // ... logique de test } } ``` ### Gestion des nœuds malveillants ```rust impl SyncManager { pub fn blacklist_relay(&self, relay_id: &str, reason: &str) { // Ajouter à la liste noire // Arrêter les connexions // Notifier les autres relais } pub fn rate_limit_relay(&self, relay_id: &str) { // Limiter le nombre de messages // Surveiller les comportements suspects } } ``` ## Conclusion **Recommandation :** Utiliser l'**Option 2 (Configuration externe)** car elle offre : 1. **Flexibilité** : Ajout de nœuds sans recompilation 2. **Sécurité** : Contrôle des domaines autorisés 3. **Évolutivité** : Support pour la découverte automatique 4. **Simplicité** : Configuration par fichier **Prochaines étapes :** 1. Implémenter le support de `external_nodes.conf` 2. Créer le script `add_external_node.sh` 3. Ajouter la validation et la sécurité 4. Tester avec des nœuds externes