Périmètre : établissement client-client et négociation des capacités. Les pistes ci-dessous sont des sujets de mesure ou de robustesse, pas des fonctions produit annoncées.
1. Sources auditées
BaseClient.cpp
UpdownClient.h
ClientList.cpp
ClientUDPSocket.cpp
Packets.cpp
Opcodes.h
edonkey-protocol.txt
2. Handshake historique
Le wire eDonkey contient déjà :
OP_HELLO 0x01
OP_HELLOANSWER 0x4C
Le document historique associe ce handshake à un Client info puis à l’adresse serveur.
3. Construction du Hello actuel
SendHelloPacket() écrit :
uint8 = 16
SendHelloTypePacket()
opcode = OP_HELLO
Le 16 correspond historiquement à la taille du UserHash qui ouvre le corps du Hello.
4. HelloAnswer
SendHelloAnswer() appelle le même :
SendHelloTypePacket()
puis utilise OP_HELLOANSWER.
Le contenu principal est donc symétrique.
5. Tronc commun du payload
SendHelloTypePacket() écrit notamment :
UserHash 16
eD2K ID uint32
TCP port uint16
TagCount
Tags...
Server IP
Server port
Les extensions modernes vivent surtout dans les tags.
6. CT_NAME
Valeur :
pseudonyme utilisateur
Classe de confiance :
DISPLAY_CLAIM
Ne jamais utiliser ce champ comme identité forte.
7. CT_VERSION
Valeur de base :
EDONKEYVERSION = 0x3C
Ce champ historique n’est pas la version logicielle complète eMule.
8. CT_EMULE_UDPPORTS
Packing actuel :
bits 31..16 = Kad UDP port
bits 15..0 = eMule UDP port
Le Kad port annoncé peut être le port externe vérifié ou le port interne configuré selon l’état du firewall tester.
9. Buddy tags
Si :
Buddy présent
ET
client firewalled
la branche ajoute :
CT_EMULE_BUDDYIP
CT_EMULE_BUDDYUDP
Ces champs influencent le chemin de callback.
10. CT_EMULE_MISCOPTIONS1
Packing observé :
AICH version << 29
Unicode << 28
UDP version << 24
Data compression << 20
SecureIdent << 16
SX1 version << 12
Extended Requests << 8
Comments << 4
PeerCache << 3
NoViewSharedFiles << 2
MultiPacket << 1
Preview << 0
Plusieurs champs occupent plusieurs bits.
11. Valeurs MISC1 actuelles
Branche étudiée :
AICH = 1
Unicode = 1
UDPVer = 4
Compression = 1
SecureIdent = 3 si crypto disponible
SX1 = 4
ExtendedRequests = 2
Comments = 1
MultiPacket = 1
Preview selon réglage
PeerCache = 0
Le commentaire SX1 rappelle un héritage de compatibilité.
12. CT_EMULE_MISCOPTIONS2
Il regroupe notamment :
Kad version
LargeFiles
ExtMultiPacket
reserved/mod bit
SupportsCryptLayer
RequestsCryptLayer
RequiresCryptLayer
SupportsSourceEx2
SupportsCaptcha
DirectUDPCallback
Avant toute documentation octet-par-octet définitive, le packing exact doit être recoupé avec le parser, aMule et des captures.
13. Connect Options condensées
SetConnectOptions(uint8) interprète :
bit 0 = crypt support
bit 1 = crypt request
bit 2 = crypt require
bit 3 = direct UDP callback
Cette forme compacte réapparaît dans des réponses de sources et callbacks.
14. États contradictoires possibles
Paquets théoriquement incohérents :
RequiresCrypt = 1
SupportsCrypt = 0
ou :
DirectCallback = 1
sans port exploitable
Le parser doit rester robuste et la machine d’état choisir un comportement conservateur.
15. Ancien OP_EMULEINFO
SendMuleInfoPacket() écrit :
eMule short version
EMULE_PROTOCOL
7 tags
Tags actuels :
compression
UDP version
UDP port
SourceExchange
Comments
ExtendedRequests
Features
16. ET_FEATURES
Le champ legacy combine notamment SecureIdent et Preview. Il existe donc une duplication historique entre plusieurs mécanismes d’annonce.
17. ProcessMuleInfoPacket()
Le parser conserve des déductions implicites pour d’anciennes versions :
UDP v1
SX1 v1
comments
shared directories
Commentaire clé du code :
in the future do not use version to guess about new features
18. Principe d’extension
Toute future fonction qui exigerait une interop devrait préférer :
capability explicite
à :
if software version >= X
Mais aucun nouveau bit n’est justifié tant qu’un besoin wire réel n’existe pas.
19. Classification du logiciel
InitClientSoftwareVersion() distingue entre autres :
cDonkey
xMule
aMule
Shareaza
lphant
MLdonkey
eDonkeyHybrid
eMule-compatible
Utilité :
UI
debug
compatibilité
Pas :
preuve de confiance
20. Mod string / version string
Un pair peut falsifier une chaîne logicielle. Toute logique anti-leecher fondée uniquement sur ce nom serait fragile.
Le D05 reste la référence pour une confiance fondée sur des observations.
21. Connexion obfusquée
CUpDownClient::Connect() active la couche d’obfuscation si :
UserHash valide
remote SupportsCrypt
local Crypt enabled
ET
(remote RequestsCrypt OU local Preferred)
Sinon, elle reste en clair si la politique le permet.
22. Required Crypt
Les incompatibilités sont également filtrées lors de l’admission des sources.
Si une extrémité exige un mode que l’autre ne peut satisfaire :
source/connexion inutilisable
Cette interaction doit être étudiée avec D13.
23. Large Files
La capability gouverne l’usage de variantes telles que :
OP_COMPRESSEDPART_I64
OP_SENDINGPART_I64
OP_REQUESTPARTS_I64
Tester explicitement les frontières de taille.
24. MultiPacket
Le protocole conserve plusieurs générations :
OP_MULTIPACKET deprecated
OP_MULTIPACKET_EXT deprecated
OP_MULTIPACKET_EXT2 moderne
Les anciennes branches sont des chemins de compatibilité susceptibles d’être peu testés aujourd’hui.
25. Hashset v2 / FileIdentifier
Les opcodes :
OP_HASHSETREQUEST2
OP_HASHSETANSWER2
utilisent un FileIdentifier plus riche et peuvent demander des données MD4/AICH selon options.
À relier au D07 et au D14.
26. Direct UDP Callback
Le bit local n’est activé que si :
Kad actif
TCP firewalled
UDP non-firewalled
UDP verified
Il s’agit donc déjà d’une capability calculée à partir d’observations.
32. Evidence de capacités
Structure conceptuelle locale :
PeerCapabilities {
announced
negotiated
successfully_used
failed
}
Sans score unique.
33. Claimed vs observed
Exemples :
annonce SX2
→ requête SX2
→ réponse valide ?
annonce AICH
→ répond à AICH ?
Cela peut aider au diagnostic de clients atypiques.
34. Ne pas pénaliser immédiatement
Une incohérence peut venir d’un vieux client, d’un bug, d’un Mod expérimental, d’un paquet partiel ou d’une mauvaise interprétation de notre parser.
Première phase :
observer
journaliser
rejouer
pas bannir.
35. Dette de compatibilité
Inventorier toutes les zones où :
version logicielle
→ capacité supposée
et les classer :
legacy indispensable
legacy encore active
supposition remplaçable par flag
36. Machine d’état
Tester aussi l’ordre des messages :
HelloAnswer sans Hello
double Hello
MuleInfo prématuré
File Request avant fin du handshake
La robustesse dépend autant de l’ordre que des champs.
37. Identité
Trois niveaux doivent rester séparés :
UserHash déclaré
clé publique SecureIdent connue
signature SecureIdent vérifiée
Ne jamais convertir le premier en troisième dans une métrique.
38. Vie privée / fingerprinting
Le Hello révèle déjà :
nickname
capabilities
versions
ports
server
Buddy éventuel
Chaque nouvelle capability publique augmente un peu le fingerprinting. Toute extension future doit donc avoir un besoin d’interop réel.
39. Compatibilité passive d’abord
Pour une expérimentation locale, préférer :
instrumentation
logs
compteurs
à un nouveau tag/opcode.
40. Lien D12 → D13
D12 répond :
« comment savons-nous que le pair comprend l'obfuscation ? »
D13 répondra :
« que fait réellement cette obfuscation au flux ? »
Ne pas confondre négociation de capability et sécurité cryptographique.
41. Conclusion
Le handshake eMule est une couche de négociation riche construite autour d’un cœur eDonkey très ancien.
Les risques techniques intéressants aujourd’hui sont surtout :
legacy inference
tags malformés
flags incohérents
chemins peu testés
claims pris à tort pour des preuves
La meilleure première étape est la couverture de tests et l’observabilité, pas l’ajout de nouvelles capacités.
================================================================================================