Geek++ · Dossier 16 / 25

Audit du moteur de recherche eD2K/Kad et du filtre anti-spam

Étude technique publique · 1,859 mots · ≈ 9 min de lecture attentive

Étude intégraleSans réflexion CODEXSources & constantes conservées
Recherche
requête
⌄
ServeurKad
résultats + métadonnées

Périmètre : construction des requêtes, choix du canal, recherche globale UDP, recherche Kad, agrégation des résultats et filtre anti-spam. Le MultiServer n’est pas un objectif de recherche ici : ce dossier étudie le protocole et la qualité des résultats.

1. Sources auditées

SearchResultsWnd.cpp
SearchList.cpp
SearchList.h
SearchFile.cpp
SearchParams.h
SearchParamsWnd.cpp
SearchExpr.*
Scanner.*
ServerSocket.cpp
UDPSocket.cpp
ServerList.cpp
kademlia/kademlia/Search.cpp
SearchManager.cpp
Opcodes.h

Référence historique :

edonkey-protocol.txt

2. Types de recherche exposés

StartSearch() distingue :

SearchTypeAutomatic
SearchTypeEd2kServer
SearchTypeEd2kGlobal
SearchTypeKademlia
SearchTypeContentDB

ContentDB sort du protocole P2P et ouvre une requête web historique.

3. Sélection Automatic

Si un seul réseau est disponible :

server only → ED2K Server
Kad only    → Kad

Si les deux sont connectés, la branche applique une heuristique historique.

4. Heuristique Automatic actuelle

Le serveur est choisi si le serveur courant est statique ou s’il vérifie notamment :

users > 40 000
users < 2 000 000
files > 5 000 000
server list < 40

Sinon Kad.

Le commentaire dit explicitement que cette logique pourrait être optimisée.

5. Interprétation

Ces seuils ne sont pas des propriétés du protocole.

Ils représentent une heuristique codée dans une certaine époque du réseau.

Avant toute modification :

mesurer le réseau actuel

6. Construction d’une recherche eD2K

DoNewEd2kSearch() :

vérifie connexion serveur
détermine support 64-bit/LargeFiles
GetSearchPacket()
annule ancienne recherche ED2K
crée SearchID
enregistre nouvelle SearchList
envoie OP_SEARCHREQUEST

7. SearchID

La fenêtre attribue un identifiant local de recherche afin de rattacher résultats, onglet et état.

Important pour :

réponses tardives
plusieurs recherches successives
annulation
UDP global

8. Search packet

GetSearchPacket() transforme l’expression et les filtres en une représentation binaire de recherche.

Le protocole possède un arbre d’expressions, pas une simple chaîne libre.

9. Nœuds booléens

Types historiques :

AND
OR
AND NOT

Le parser/serializer construit un arbre récursif.

Cas de fuzzing naturel :

profondeur excessive
arbre tronqué
nombre énorme de nœuds

10. Termes texte

Une recherche peut écrire un paramètre texte simple.

Pour Kad, un mot-clé principal est extrait séparément afin de construire la cible de routage.

11. Métadonnées chaîne

Le builder prend notamment en charge :

FT_FILETYPE
FT_FILEFORMAT
FT_MEDIA_CODEC
FT_MEDIA_TITLE
FT_MEDIA_ALBUM
FT_MEDIA_ARTIST
FT_FILENAME

Le détail exact de compatibilité varie entre vieux/nouveaux tags.

12. Comparaisons numériques

La syntaxe supporte des opérateurs de comparaison pour les attributs numériques.

Exemples :

FileSize
Sources
Bitrate
Length
CompleteSources

à confirmer attribut par attribut dans SearchExpr/builder.

13. 32-bit / 64-bit

Le builder peut produire une requête nécessitant 64 bits.

La branche mémorise :

m_b64BitSearchPacket

pour éviter d’envoyer cette requête à un serveur UDP incapable de LargeFiles.

14. Envoi local TCP

Paquet :

OP_SEARCHREQUEST

vers le serveur connecté.

En mode Global, une copie du payload est conservée pour le parcours UDP.

15. Timeout serveur local

En Global :

TimerServerTimeout = 50 s

Si le serveur courant tarde trop, la recherche globale UDP peut démarrer.

Il ne s’agit pas d’un timeout de téléchargement.

16. Timer global

Une fois le global actif :

intervalle ≈ 750 ms

La liste des serveurs est parcourue progressivement.

17. Serveurs morts

Le parcours saute les serveurs dont le failed-count a atteint le seuil DeadServerRetries.

Donc la qualité de server.met influence directement le coût d’une recherche globale.

18. Recherche UDP v1

Serveur ancien :

OP_GLOBSEARCHREQ

si la requête est compatible.

19. Recherche UDP v2

Si :

SRV_UDPFLG_EXT_GETFILES

le client utilise :

OP_GLOBSEARCHREQ2

20. Recherche UDP v3

Si le serveur supporte les extensions adéquates et LargeFiles :

OP_GLOBSEARCHREQ3

avec un tag de flags :

CT_SERVER_UDPSEARCH_FLAGS
SRVCAP_UDP_NEWTAGS_LARGEFILES

21. Skip LargeFiles

Une recherche nécessitant 64 bits est ignorée pour un serveur UDP qui ne supporte pas cette capacité.

Cela évite d’envoyer une requête qu’il interpréterait incorrectement.

22. Notification d’origine

Après un envoi UDP :

SentUDPRequestNotification(searchID, serverIP)

La SearchList peut ainsi associer certaines réponses à leur serveur d’origine.

Cette provenance est importante pour l’anti-spam.

23. Réception UDP

UDPSocket.cpp transmet les résultats à :

ProcessUDPSearchAnswer()

avec :

server IP
server port

Les résultats de plusieurs serveurs sont donc agrégeables avec provenance.

24. More Results

SearchMore() envoie :

OP_QUERY_MORE_RESULT

au serveur TCP courant.

Constante historique :

MAX_MORE_SEARCH_REQ = 5

Le commentaire indique une limite totale dépendant du nombre de réponses par page serveur.

DoNewKadSearch() :

extrait premier mot-clé
gère quotes
Trim
construit les contraintes
vérifie chars interdits
PrepareFindKeywords()

Le SearchID vient alors de l’objet CSearch Kad.

26. Keyword principal

Le premier token n’est pas nécessairement toute l’expression booléenne.

Il sert à choisir la clé distribuée.

Les autres conditions accompagnent la recherche pour filtrer les entrées.

27. Requête Kad et recherche serveur

Une partie de la logique de construction des contraintes est partagée.

Mais le transport et le mécanisme de découverte sont complètement différents.

28. Agrégation

SearchList reçoit des résultats de :

server TCP
server UDP
Kad
client shared-files selon contexte

Elle doit regrouper les variantes et conserver les origines.

29. Identité de regroupement

Le FileHash est la base naturelle de regroupement.

Les variantes de nom doivent être conservées comme observations, pas transformées en fichiers distincts lorsque le hash est identique.

30. Métadonnées contradictoires

Cas :

même hash
taille différente

devrait être considéré comme incohérent car taille+hash font partie de l’identité opérationnelle.

Cas :

même hash
noms différents

est possible.

Tester les décisions actuelles de SearchList.

31. Anti-spam : architecture

CSearchList::DoSpamRating() combine :

heuristiques générales
et
apprentissage à partir des choix utilisateur

Le commentaire du code reconnaît la fiabilité limitée des seules heuristiques.

32. Hash connu spam

Un FileHash déjà marqué spam peut produire un score décisif.

Un hash marqué explicitement non-spam peut au contraire devenir une forte preuve négative.

33. Noms

Le filtre compare :

nom exact
nom similaire
nom après suppression des mots de recherche et séparateurs

Il prend aussi en compte les variantes parent/enfant d’un même résultat groupé.

34. Tailles similaires

Une taille connue spam peut influencer un résultat si elle est proche :

< 5 Mio d'écart
ET
< 5 %

Ce signal a un poids relativement faible seul.

35. Serveur UDP d’origine

Le filtre conserve des IP de serveurs associés à du spam.

Le score dépend du contexte :

seul serveur à avoir donné le résultat
plusieurs serveurs
nombre de serveurs déjà marqués

36. Ratio spam d’un serveur

m_mUDPServerRecords conserve pour chaque serveur :

results
spam results

Un ratio est calculé.

Seuil historique visible :

UDP_SPAMRATIO_THRESHOLD = 50

37. Sources initiales

Le filtre peut également apprendre des sources clientes associées à des résultats spam.

Cela montre que l’ancien système avait déjà une notion de corrélation multi-signal.

38. Heuristiques générales

Le commentaire source cite notamment :

forte disponibilité sur un serveur UDP mais pas les autres
archive/program entre ~0,1 et 10 MB
100 % complete sources + forte disponibilité

Ces règles visaient des campagnes historiques de faux résultats.

39. Poids visibles

Exemples de constantes :

similar name ~40–60
similar size 10
UDP server 10–21
only spam servers 30
source hit 39
heuristic base 39
heuristic max 60

Et :

SEARCH_SPAM_THRESHOLD = 60

Ces valeurs doivent être traitées comme heuristiques historiques, pas comme probabilités.

40. Problème du score additif

Additionner plusieurs signaux corrélés peut surpondérer un même phénomène.

Exemple :

même campagne de spam
→ nom similaire
→ taille similaire
→ même serveur
→ mêmes sources

Ces signaux ne sont pas statistiquement indépendants.

41. Risque de dérive temporelle

Les heuristiques « petit .exe/.zip très disponible » correspondaient à des campagnes anciennes.

En 2026, le profil du spam peut avoir changé.

Question centrale :

quelle précision ont encore ces règles ?

42. Dataset de validation

Créer un corpus offline avec résultats réels/synthétiques étiquetés :

spam
non-spam
incertain

Éviter de prétendre mesurer précision/recall sans labels humains.

49. Ce que « utile » doit signifier

Pas seulement :

beaucoup de lignes

Mais :

hashs uniques
résultat choisi par utilisateur
sources ensuite trouvées
fichier finalement transférable

50. Pas de « meilleur réseau » global

Kad peut mieux fonctionner sur une requête rare.

Un gros serveur peut être meilleur sur une autre.

Le but n’est pas de déclarer :

Kad > serveur

mais de comprendre les conditions.

51. MultiServer

Le projet possède déjà sa propre réflexion/maîtrise du MultiServer.

D16 ne doit donc pas repartir sur une conception « Smart MultiServer ».

Ici nous étudions seulement :

la recherche UDP globale du protocole
la provenance des résultats
leur qualité

52. Query parser fuzzing

Cibles :

arbre profond
nœud incomplet
opérateur invalide
string énorme
tag inconnu
uint64 frontière
expressions imbriquées

53. Result parser fuzzing

Cibles :

count énorme
tag count énorme
troncature
FileHash absent
taille 0
taille > max
Unicode malformé
duplicate tags

54. UDP correlation

Une réponse UDP doit être associée à une recherche active et à une origine attendue.

Vérifier le comportement sur :

réponse tardive
serveur jamais interrogé
ancienne SearchID
onglet fermé

55. Kad late results

Même question pour Kad :

search stopping
15 s grace
late answer
deleted GUI search

Le moteur prévoit déjà une phase de stop avant destruction.

56. Privacy audit

Journaliser une recherche peut révéler les termes de l’utilisateur.

Toute télémétrie expérimentale doit privilégier :

SearchID local
hash du terme si nécessaire
compteurs

et éviter la conservation longue des requêtes textuelles.

57. Search evidence local-only

Structure conceptuelle :

SearchEvidence {
  search_id
  channel
  origin
  result_hash
  first_seen
  duplicate
  metadata_conflict
  spam_reasons
}

Sans upload externe par défaut.

58. UI et filtre

Un filtre anti-spam amélioré ne doit pas supprimer silencieusement des résultats légitimes sans possibilité de diagnostic.

Pour les tests :

score
reasons
hidden/visible

doivent être observables.

59. Noms alternatifs

Un même FileHash ayant plusieurs noms peut fournir une information utile contre certains fakes.

Mais le « nom majoritaire » n’est pas automatiquement vrai.

Mesurer seulement.

60. Sources complètes

Le nombre de complete sources est une métadonnée utile mais déclarative.

Ne pas confondre :

complete sources annoncées

avec :

sources réellement vérifiées

61. Recherche par hash

Lorsqu’on possède déjà un lien ED2K, la recherche textuelle devient secondaire.

Le téléchargement peut directement utiliser le FileHash et lancer la découverte de sources.

D14 et D16 doivent donc rester clairement séparés.

62. Robustesse sur 64-bit

Tests frontières :

OLD_MAX_EMULE_FILE_SIZE - 1
OLD_MAX_EMULE_FILE_SIZE
OLD_MAX_EMULE_FILE_SIZE + 1
MAX_EMULE_FILE_SIZE
MAX + 1

sur :

builder
server local
global UDP capability filtering
Kad

63. Performance locale

Les listes de résultats peuvent être nombreuses.

Profiling à faire sur :

grouping
spam recalculation
sorting
UI refresh
string normalization

Sur PC moderne, l’UI peut être plus coûteuse que le parsing réseau.

64. Pas d’optimisation par suppression de vérifications

Si un profil montre du coût dans le spam filter ou le regroupement, ne pas supprimer d’abord les contrôles de cohérence.

Séparer :

algorithme
allocations
rafraîchissement GUI

65. Recherche liée à Trust Model

Les résultats de recherche sont des :

remote claims

Leur confiance peut se renforcer par :

observations indépendantes
cohérence de métadonnées
succès du téléchargement

mais aucune de ces dimensions ne doit devenir une « vérité » avant validation.

66. Conclusion

Le moteur de recherche eMule est déjà une architecture multi-canal sophistiquée :

query tree
server TCP
global UDP
Kad
result grouping
spam heuristics
user feedback

Les zones qui méritent le plus d’étude sont :

pertinence actuelle du mode Automatic
rendement de chaque canal
qualité des métadonnées
validité du filtre anti-spam historique
robustesse des parsers

La prochaine étape n’est pas de changer ces règles immédiatement, mais de construire le corpus de test et les métriques permettant de savoir lesquelles fonctionnent encore réellement.

================================================================================================


Dossier 16 terminé

Audit du moteur de recherche eD2K/Kad et du filtre anti-spam

← Dossier 15Dossier 17 →