Résumé

  • UDP ASSOCIATE créait, sur une connexion TCP ayant négocié une méthode, un contexte de relais qui cessait dès la fermeture de cette connexion ; le flux fixait la durée de l’état sans transporter les données UDP.
  • L’adresse liée par le serveur, l’IP source attendue, la destination inscrite dans chaque datagramme, la méthode de sécurité et la file de fragments restaient des preuves distinctes, jamais un reçu global.

Une association n’était pas un tunnel permanent

Le mot « association » peut suggérer une chose solide. Dans SOCKS5, il nommait plutôt une permission d’exécution bornée. Le client ouvrait d’abord TCP vers le serveur SOCKS, proposait des méthodes d’authentification, achevait la sous-négociation choisie, puis demandait UDP ASSOCIATE.

RFC 1928, publié en mars 1996, ne laissait aucun doute sur la fin : l’association UDP se termine lorsque se termine la connexion TCP sur laquelle la demande est arrivée. Le dernier datagramme ne votait pas pour une prolongation. Un délai d’inactivité ne devenait pas l’unique juge. Une nouvelle session exigeait une nouvelle décision.

Le protocole ne faisait pourtant pas passer les charges UDP dans TCP. Les datagrammes conservaient leurs propres pertes, duplications, retards et ordres d’arrivée. TCP portait le contexte : choix de méthode, création du relais, continuité observable de la relation de contrôle. Sa fermeture révoquait un état local ; elle ne disait rien de définitif sur ce qu’un datagramme déjà transmis avait accompli au loin.

Ce compromis était mince. Il donnait à un service sans connexion un début et une fin vérifiables sans lui prêter les garanties d’un flux.

Trois adresses racontaient trois décisions

La demande UDP ASSOCIATE pouvait indiquer l’adresse et le port dont le client comptait émettre ses datagrammes. Le serveur était autorisé à employer cette information pour restreindre l’accès. Si le client ne la connaissait pas encore, il devait mettre adresse et port à zéro.

Zéro ne signifiait pas « ouvert à tous ». Il signalait une information absente dans la demande. Le serveur devait encore déterminer la source utilisable selon la connexion présente, l’adresse observée et sa politique locale.

La réponse réussie fournissait BND.ADDR et BND.PORT. Dans cette commande, ces champs désignaient le point d’entrée UDP auquel envoyer les messages à relayer. Un serveur multirésident pouvait donner une adresse différente de celle atteinte par TCP.

La destination finale se trouvait ailleurs : dans l’en-tête de chaque datagramme. Ainsi, l’adresse TCP du serveur, le point d’entrée UDP choisi par le relais et la destination distante n’étaient ni interchangeables ni nécessairement égaux. Un inventaire qui n’enregistre qu’une « adresse de proxy » rend les incidents presque impossibles à reconstruire.

Le destinataire changeait d’un datagramme à l’autre

Chaque envoi du client vers le relais portait deux octets réservés, FRAG, un type d’adresse, l’adresse de destination, son port et la charge. L’association n’imposait donc pas une destination unique. Elle donnait au relais une grammaire pour interpréter chaque intention séparément.

Lorsqu’une réponse venait d’un hôte distant, le relais l’enveloppait dans le même format. Le client pouvait alors attribuer le datagramme reçu à une adresse et un port déclarés par le relais. Cela produisait une trace utile, non une identité absolue : l’adresse distante pouvait être partagée, traduite ou usurpée ailleurs, et le relais témoignait de ce qu’il avait reçu.

De même, accepter un en-tête valide ne prouvait pas la livraison. Le relais pouvait autoriser et émettre ; la route pouvait perdre le datagramme ; l’application distante pouvait le rejeter, le traiter ou ne jamais répondre. Le succès local n’absorbait pas les décisions suivantes.

Quand TCP se fermait, l’ancien BND.ADDR restait peut-être mémorisé par le client. Il ne devenait pas pour autant un jeton durable. Une adresse correcte ne recréait pas l’association qui l’avait rendue utilisable.

Filtrer la source ne nommait pas l’utilisateur

Le relais UDP devait obtenir du serveur SOCKS l’adresse IP client attendue et abandonner silencieusement tout datagramme venant d’une autre IP pour cette association. La règle empêchait un tiers situé à une autre adresse d’emprunter facilement le contexte existant.

Elle ne réalisait pas une identification humaine. Une IP peut couvrir plusieurs machines derrière une traduction d’adresses, plusieurs processus ou plusieurs comptes. La mobilité peut la remplacer. Le contrôle prouve seulement qu’au bord du relais le paquet portait la source enregistrée.

L’authentification avait son propre résultat, issu de la méthode négociée sur TCP. RFC 1929 définissait un échange nom d’utilisateur/mot de passe dont les identifiants circulaient en clair et déconseillait son usage lorsque l’écoute était possible. RFC 1961 définissait une méthode GSS-API pouvant négocier authentification, intégrité par message et confidentialité facultative.

Deux déploiements « SOCKS5 » pouvaient ainsi exposer la même commande tout en produisant des garanties très différentes. Le journal devait conserver la méthode effectivement sélectionnée, le niveau de protection et l’étendue des données couvertes. Le nom du protocole ne remplissait pas ces cases.

FRAG ajoutait une mémoire révocable

Dans l’enveloppe UDP de SOCKS5, FRAG=0 signifiait que le datagramme était autonome. Les valeurs de 1 à 127 indiquaient la position d’un fragment, et le bit de poids fort marquait la fin de la séquence. Cette fragmentation appartenait au relais SOCKS ; elle n’était pas le champ Fragment Offset d’IP.

Sa mise en œuvre restait facultative. Un récepteur qui ne savait pas réassembler devait jeter tout FRAG non nul. Celui qui l’acceptait maintenait une file et un minuteur. L’expiration supprimait les fragments. L’arrivée d’un numéro inférieur au plus grand déjà traité réinitialisait également la file. Le minuteur devait durer au moins cinq secondes, tandis que la norme recommandait d’éviter la fragmentation.

Ce mécanisme ne rendait pas UDP fiable. Il n’ajoutait ni accusé de réception, ni retransmission, ni conservation indéfinie. La mémoire pouvait aider à reconstruire une charge ; elle ne certifiait ni son expédition ultérieure ni son traitement.

Pour l’exploitation, la différence est essentielle. Une absence peut provenir d’une mauvaise source, d’une fonction FRAG non prise en charge, d’un délai expiré, d’un ordre revenu en arrière, d’une perte après le relais ou d’un silence applicatif. Un seul compteur « échec UDP » efface ces causalités.

La fermeture empêchait l’autorité orpheline

On pourrait conserver le relais tant que des datagrammes arrivent. Ce serait économique pour une application mobile, mais dangereux pour la provenance. Le trafic récent montre qu’un émetteur connaît l’adresse du relais. Il ne montre pas que la partie authentifiée qui avait ouvert TCP contrôle toujours ce trafic.

Un simple délai d’inactivité souffre du problème inverse. Le silence peut être une application calme, un chemin retour rompu ou un client mort. Le minuteur tranche seulement une durée locale ; il ne révèle pas l’histoire.

La connexion de contrôle offrait un fait plus net. Tant qu’elle vivait, le serveur pouvait rattacher méthode, politique et entrée UDP à un dialogue actif. À sa disparition, la révocation plaçait le coût de l’incertitude sur la reconnexion plutôt que sur un relais orphelin.

Cette décision pouvait interrompre un flux UDP sain lors d’une panne TCP brève. Elle exigeait de conserver un socket et compliquait les changements d’adresse. Mais la règle était visible, testable et réversible : le client pouvait créer une nouvelle association. Une permission prolongée par des paquets impossibles à attribuer l’aurait été beaucoup moins.

La passerelle entre IPv4 et IPv6 conserva la couche

RFC 3089, document Informational de 2001, décrivit une passerelle SOCKS entre IPv4 et IPv6. Elle terminait des connexions des deux côtés à la couche application, pouvait déléguer la résolution de noms à un nœud double pile et héritait de CONNECT, BIND et UDP ASSOCIATE.

Cette extension d’usage ne transforma pas SOCKS en routage IP. Elle montra qu’un intermédiaire pouvait résoudre une incompatibilité d’adresses en conservant les objets distincts : nom demandé, résultat de résolution, association de contrôle et données relayées. L’interopérabilité venait d’un petit contrat exécutable, non d’une autorité universelle accordée à la passerelle.

Sources