Geek++ · Dossier 10 / 25

Serveurs eD2K : audit technique

Étude technique publique · 2,173 mots · ≈ 10 min de lecture attentive

Étude intégraleSans réflexion CODEXSources & constantes conservées
Serveur eD2K
SERVER
LOGINSEARCHGETSOURCESCALLBACKOFFERFILES

0. Règle éditoriale pour la suite du projet

À partir de ce dossier, nous séparons strictement deux choses.

Couche publique

Les pages pédagogiques expliquent :

ce qu'est eMule
comment fonctionne eD2K
comment fonctionne Kad
les choix historiques
les limites observées dans le protocole et les implémentations

Elles ne présentent pas une amélioration future comme si elle appartenait déjà au client.

Couche interne

Les rapports de travail peuvent contenir :

hypothèses
pistes
expériences
instrumentation
correctifs candidats
comparaisons avec les Mods

Ces éléments restent internes jusqu’à :

implémentation
test
validation
absence de régression

Publication ultérieure

La logique éditoriale retenue est :

« Après ces études, voici le fruit de notre travail. »

Une future version du logiciel sera donc présentée après validation comme résultat du travail, et non introduite par anticipation dans chaque fiche historique.

Les dossiers publics 01–09 pourront être harmonisés selon cette règle lors d’une passe éditoriale ultérieure.


1. Corpus de référence

Historique

edonkey-protocol.txt, v0.6, 2002.

Valeur :

surface protocolaire ancienne
opcodes
formats client↔serveur
UDP
server.met

Limite :

document communautaire / reverse-engineered
pas une spécification normative officielle exhaustive

Client

eMule Community 0.72a :

tag eMule_v0.72a-community
SHA ac3d52eafd88e9f6d9e0c2204c6dbead18db750b

Fichiers majeurs :

ServerConnect.cpp
ServerSocket.cpp
ServerList.cpp
UDPSocket.cpp
SharedFileList.cpp
DownloadQueue.cpp
Opcodes.h

Serveur indépendant

eNode, petermrg/eNode.

Utilité :

observer le côté serveur
rejouer en laboratoire
corroborer Login / OfferFiles / Search / GetSources / Callback

Ne pas prendre eNode comme norme de tous les serveurs historiques.


2. Surface protocolaire historique

Client → serveur :

0x01 Login
0x14 Get Server List
0x15 Offer Files
0x16 Search
0x19 Get Sources
0x1C Callback Request
0x21 More Results

Serveur → client :

0x32 Server List
0x33 Search Result
0x34 Server Status
0x35 Callback Requested
0x36 Callback Failed
0x38 Server Message
0x40 ID Change
0x41 Server Ident
0x42 Found Sources

UDP historique :

0x96 Status Request
0x97 Status Result
0x98 Search
0x99 Search Result
0x9A Get Sources
0x9B Found Sources
0x9C Callback
0x9E Callback Fail
0xA1 Server List
0xA2 Server Desc Request
0xA3 Server Desc

3. Control plane / data plane

Le serveur appartient principalement au :

CONTROL PLANE

Il aide à :

identifier
indexer
rechercher
découvrir
rendre joignable

Le contenu reste dans le :

DATA PLANE
client ↔ client

Cette distinction sera utile pour tous les dossiers suivants.


4. Modèle de connexion serveur

Le client possède un connectedsocket courant.

Plusieurs essais peuvent exister pendant la connexion, mais une fois l’un d’eux établi :

un seul serveur TCP principal

reste actif.

En parallèle :

plusieurs serveurs UDP

peuvent être consultés.


5. Login moderne

CServerConnect::ConnectionEstablished() construit :

UserHash
ClientID
TCP port
TagCount = 4

Tags :

CT_NAME
CT_VERSION
CT_SERVER_FLAGS
CT_EMULE_VERSION

Puis :

OP_LOGINREQUEST

6. Capabilities du client

CT_SERVER_FLAGS annonce :

ZLIB
NEWTAGS
LARGEFILES
UNICODE
SUPPORTCRYPT
REQUESTCRYPT
REQUIRECRYPT

Le login est donc également une négociation de capacités.


7. IDCHANGE

ServerSocket.cpp traite OP_IDCHANGE.

Le paquet moderne peut contenir :

ClientID
server TCP flags
public IP rapportée

Le client :

enregistre l'ID
déduit l'IP depuis le HighID
ou conserve l'IP rapportée si LowID

8. Confirmation indépendante par eNode

eNode :

loginRequest
→ isFirewalled
→ LowID si firewalled
→ IPv4 comme ID si joignable

Le modèle est cohérent avec la lecture côté client.

Les détails précis du test de firewall ne doivent pas être généralisés à tous les serveurs sans source supplémentaire.


9. Après connexion : remise à zéro de la publication

Une fois connecté :

ClearED2KPublishInfo();
SendListToServer();

Une nouvelle session serveur repart donc avec un nouvel état de publication.


10. SendListToServer()

La fonction sélectionne les fichiers :

non encore publiés
et
compatibles avec les capacités du serveur

Puis les trie selon la priorité d’upload.


11. Limite de publication

Le client calcule :

limit = SoftFiles

puis force :

si 0 ou > 200
→ 200

Il faut rester prudent sur la sémantique serveur exacte de SoftFiles.

Le fait solide est :

le client l'utilise pour borner son lot

12. Publication progressive

Les fichiers envoyés deviennent :

PublishedED2K = true

Les suivants attendent un autre cycle.

Constante :

ED2KREPUBLISHTIME = 1 minute

13. Compression

Si le serveur annonce :

SRV_TCPFLG_COMPRESSION

OP_OFFERFILES peut être compressé.

Le code essaie la compression et garde le paquet compressé seulement si elle est avantageuse.


14. KeepAlive

KeepConnectionAlive() envoie :

OP_OFFERFILES
count = 0

comme paquet de maintien de connexion.

C’est une curiosité historique documentable.


15. Publication côté serveur

eNode :

offerFiles()
→ db.files.addSource(file, client.info)

Le modèle serveur est donc :

FileHash / FileMetadata
↔
Client source

et non stockage du contenu.


16. Recherche serveur

Historique :

OP_SEARCHREQUEST
→ OP_SEARCHRESULT

eNode :

db.files.find(query)

La recherche porte sur l’index serveur.


17. Limite de la recherche

L’index d’un serveur n’est pas :

l'intégralité du réseau eD2K

Les recherches UDP globales et Kad complètent cette vue.


18. GetSources TCP

Historique :

OP_GETSOURCES
→ OP_FOUNDSOURCES

La requête moderne du client ajoute la taille du fichier.

Grand fichier :

Hash
0 marker
uint64 size

Fichier classique :

Hash
uint32 size

19. Variante obfuscation

Si possible :

OP_GETSOURCES_OBFU
→ OP_FOUNDSOURCES_OBFU

La réponse enrichie peut fournir des données de connexion supplémentaires, dont un UserHash selon les options.


20. Réception FoundSources

Le client fait :

FileHash
→ CPartFile
→ AddSources()

Le serveur alimente donc le même pipeline de source admission que les autres canaux.


21. Queue locale des demandes serveur

m_localServerReqQueue

La sélection tient compte de :

LastSearchTime
DownloadPriority

afin de choisir quels fichiers interroger en premier.


22. Batch TCP

Valeur actuelle :

iMaxFilesPerTcpFrame = 15

Le client concatène jusqu’à 15 requêtes dans une même frame.


23. Cadence du batch TCP

Après le frame :

15 * (16 + 4) seconds

soit environ :

300 s = 5 min

avant le batch suivant.

Ce timer est distinct de la constante historique :

SERVERREASKTIME = 15 min

Ne pas les confondre dans la documentation.


24. UDP GetSources multi-serveurs

Le client peut interroger successivement les serveurs de server.met.

Il saute :

serveur TCP courant
serveurs trop défaillants

et vérifie :

source limit
LargeFiles support
UDP flags

25. Cadence UDP

Constante :

UDPSERVERREASKTIME = 30 min

Le mécanisme n’est donc pas permanent.


26. Limites de la requête UDP

Constantes/logique :

MAX_UDP_PACKET_DATA = 510
MAX_REQUESTS_PER_SERVER = 35

Plusieurs hashes peuvent être groupés.

La taille de la requête varie avec :

GetSources1
GetSources2
LargeFiles

28. ServerStats

Le client sonde périodiquement les serveurs.

Cadence nominale :

≈ 4,5 h

avec randomisation historique et minimum de 20 min pour certains repings.


29. Challenge UDP

Requête :

challenge uint32

Réponse attendue :

même challenge

Si différent :

ignore

Niveau de confiance :

corrélation

pas authentification forte.


30. Informations apprises par UDP

Selon taille/version :

users
files
max users
soft files
hard files
UDP flags
LowID users
UDP obfuscation port
TCP obfuscation port
server UDP key

31. Capacités UDP

Bits connus dans la branche :

ExtGetSources
ExtGetSources2
ExtGetFiles
NewTags
Unicode
LargeFiles
UDP obfuscation
TCP obfuscation

32. Server Description

Ancien format :

name
description

Nouveau format :

challenge
tag list

Le client rejette une nouvelle réponse au challenge inattendu.


33. Callback serveur

Historique :

OP_CALLBACKREQUEST <LowID>
→ serveur
→ OP_CALLBACKREQUESTED vers LowID
→ LowID connecte le demandeur

eNode possède exactement ce modèle dans son code.


34. Échec callback

Si le LowID ciblé n’est plus dans la table du serveur :

CALLBACKFAILED

Le serveur ne peut pas joindre un client qu’il n’a plus en session.


35. Extension callback moderne

OP_CALLBACKREQUESTED peut contenir :

IP
port
crypt options
UserHash

Si le UserHash reçu contredit celui déjà associé au client :

le client ne fait pas confiance aux options crypt

Bonne pratique historique à retenir dans le Trust Model.


36. server.met historique

Document 2002 :

0x0E
DWORD count
IP
port
Meta list

Le document mentionne même l’existence possible de données de queue/tail non interprétées.


37. server.met moderne

Lecture :

0xE0 ou 0x0E

Écriture :

0xE0

38. Métadonnées modernes conservées

Le writer peut stocker :

name
dynIP
description
fail count
preference
users
files
ping
last ping
max users
soft files
hard files
version
UDP flags
LowID users
UDP key
UDP key IP
TCP/UDP obfuscation ports

39. Sauvegarde transactionnelle simple

Séquence :

écrire server.met.new
ancien server.met → server_met.old
server.met.new → server.met

C’est une protection utile contre une écriture directe détruisant le fichier courant.


40. Sauvegarde périodique

CServerList::Process() :

≈ 17 min

pour persister les informations apprises.


41. AutoUpdate

Sources possibles :

URL configurée
server.met local
server_met.download
staticservers.dat

Lors d’un update, une ancienne liste est conservée en backup.


43. Server list fournie par un serveur

OP_SERVERLIST

Les nouvelles entrées sont créées :

SRV_PR_LOW

Une liste reçue d’un serveur n’est donc pas promue directement.


44. Admission d’un serveur

AddServer() vérifie :

GoodIP
IPFilter
duplicate address:port
duplicate IP/TCP
DynIP

45. Trust boundary serveur

Mesuré localement

TCP connect
UDP response
ping
callback abouti
source connectée
fichier confirmé

Déclaré par serveur

name
description
version
users
files
LowID users
source list
search results
capability flags

Corrélé

UDP challenge response
description challenge

Ne pas confondre les trois niveaux.


46. Fake content vs corruption

Un fichier peut être :

parfaitement cohérent avec son ED2K hash

tout en étant :

mal nommé ou trompeur

AICH protège :

l'intégrité du contenu associé au hash

pas :

la vérité du nom affiché

47. Première campagne interne : rendement des canaux de sources

Pour un ensemble de FileHash :

server TCP
server UDP
Kad
SX

Tracer :

announced
new
duplicate
filtered
connected
file-confirmed
payload
hash-valid

Aucune décision automatique dans la première phase.


48. Impact du réglage Crypt Required

Comparer sur périodes/fichiers comparables :

Crypt Required OFF
Crypt Required ON

Mesures :

UDP server sources
time-to-first-source
time-to-first-transfer
sources utiles totales

But :

comprendre l’impact réel du chemin désactivé.

Pas recommander un réglage avant résultats.


49. Evidence par serveur

Structure conceptuelle :

ServerEvidence

Reachability
SourceYield
SearchYield
CallbackReliability
CapabilityConsistency

Ne pas créer un score unique 0–100.


50. Callback evidence

Tracer séparément :

server TCP callback
server UDP callback
Kad Buddy callback
Direct UDP callback

Mesures :

attempt
instruction received
connection
fail
latency

51. Publication coverage

Pour une grosse bibliothèque :

local file count
published flag count
server SoftFiles
OfferFiles packet count
time since connect

Question à tester :

temps réel pour publier l'ensemble

Le client montre ce qu’il envoie ; seul un test côté serveur peut confirmer ce qui est conservé.


52. eNode comme serveur laboratoire

Intérêt majeur :

contrôler les deux extrémités

Tests possibles :

HighID
LowID
OfferFiles
GetSources
Search
Callback
UDP

Permet captures et assertions précises sans dépendre d’un serveur public.


53. Limite eNode

Le projet contient encore des TODO et ne couvre pas nécessairement toutes les extensions modernes.

Règle :

absence dans eNode
≠
absence dans le protocole

54. Wireshark comme troisième témoin

Pour les futurs layouts binaires :

eMule writer
eMule reader
eNode/aMule
Wireshark
capture réelle

Trianguler avant de publier une spécification octet-par-octet.


55. server.met provenance

Le format ne porte pas une signature d’auteur.

Première instrumentation potentielle :

origin URL/manual/server
imported count
filtered count
duplicates
DNS success
UDP response
TCP success

Pas de nouveau format nécessaire pour mesurer.


56. Fuzzing local server.met

Cibles :

AddServerMetToList
AddTagFromFile

Cas :

version invalide
count énorme
troncature
tag inconnu
string length excessive
DynIP malformé

Objectif :

pas de crash
pas d'allocation aberrante
pas d'état partiellement créé

57. Fuzzing TCP serveur

Cibles :

OP_IDCHANGE
OP_SERVERSTATUS
OP_SERVERIDENT
OP_SERVERLIST
OP_FOUNDSOURCES
OP_CALLBACKREQUESTED
OP_SEARCHRESULT

58. Fuzzing UDP serveur

Cibles :

GLOBSEARCHRES
GLOBFOUNDSOURCES
GLOBSERVSTATRES
SERVER_DESC_RES

Les challenges/taille doivent être testés aux frontières.


59. Performance : ne pas optimiser le CPU au mauvais endroit

Sur une machine moderne, parser quelques dizaines de records serveur coûte peu.

Le coût pratique peut plutôt venir de :

mauvaises connexions déclenchées
pollution de listes
timeouts
recherches inutiles
callbacks ratés

Les métriques doivent donc mesurer le résultat réseau, pas seulement les microsecondes CPU.


60. Ne pas classer les serveurs uniquement par taille

Un gros serveur peut fournir :

beaucoup de résultats

simplement parce qu’il indexe davantage de clients.

Un plus petit peut apporter :

des hashes uniques
des sources différentes

Mesurer aussi :

diversité
nouveauté
utilité

61. Search diversity

Comparer :

hashes uniques par serveur
duplications
temps de réponse
résultats recoupés avec Kad

Une divergence entre index n’est pas automatiquement frauduleuse.

Les populations indexées sont différentes.


62. Source diversity

Même principe :

10 nouvelles sources

peuvent être plus utiles que :

100 doublons

Le rendement doit distinguer quantité et information réellement nouvelle.


63. Failed count

Les serveurs accumulent un compteur d’échecs.

Ils peuvent être retirés après le seuil configuré.

À tester sur :

DNS dynamique
coupure temporaire
VPN
réseau mobile

avant toute modification de politique.


64. Challenge pseudo-aléatoire

Les challenges serveur utilisent encore des générateurs historiques.

Ce n’est pas équivalent au problème SecureIdent.

Ici le challenge sert essentiellement à :

corréler requête/réponse

et non à protéger une identité cryptographique.

Priorité de modernisation faible.


67. Conclusion

Le serveur eD2K assure principalement :

session / Client ID
indexation
recherche
discovery de sources
callback LowID

La branche moderne ajoute :

multi-server UDP
capability flags
compression
LargeFiles
obfuscation
server health
server.met enrichi

L’étude ne justifie pas de « refaire » le protocole serveur.

Le travail interne pertinent est plutôt de mesurer, sur le réseau actuel, la valeur réelle de chaque fonction et de chaque canal.

Les conclusions applicables au futur client devront être publiées seulement après expérimentation et validation.



Dossier 10 terminé

Serveurs eD2K : audit technique

← Dossier 09Dossier 11 →