RFC IRC : Implémentations actuelles


La seule implémentation actuelle de ce protocole est le serveur IRC version 2.8. Les versions précédentes peuvent implémenter certaines ou toutes les commandes décrites dans ce document en utilisant les messages NOTICE à la place des réponses numériques. Malheureusement, à causes des problèmes de compatibilité ascensionnelle, les implémentations de certaines parties de ce document diffèrent de ce qui est spécifié. Une différence notable est :
     * La présence de tout LF ou CR dans n'importe ou dans le message marque sa fin (au lieu de la séquence préconisée CR-LF) ;

Le reste de cette section traite d'issues qui sont pour la plupart intéressantes pour ceux qui veulent implémenter un serveur, mais certaines s'appliquent aussi directement aux clients.

8.1 Protocole Réseau: TCP - Pourquoi il est le plus approprié.

IRC a été implémenté sur TCP car TCP fourni un protocole réseau fiable qui est approprié à cette échelle de discussions. L'utilisation d'IP multicast est une alternative, mais n'est pas très répandue à l'heure actuelle.

8.1.1 Support des sockets Unix

Etant donné que les domaines de sockets Unix permettent les opérations listen/connect, les implémentations actuelles peuvent être configurées pour écouter et accepter aussi bien les clients que les serveurs sur un domaine de socket Unix. On reconnaît les sockets à un nom d'hôte commençant par un '/'.

Lors de la communication des informations au sujet d'un domaine de socket Unix, le serveur doit remplacer le nom de chemin par le vrai nom d'hôte, à moins que le nom socket soit demandé.

8.2 Traitement des commandes

Afin de fournir des E/S réseaux 'non-tamponnées' utiles aux clients et aux serveurs, à chaque connection est associée son propre 'tampon d'entrée' dans lequel les résultats de lectures et traitements les plus récents sont conservés. Une taille de tampon de 512 octets et utilisée afin de contenir un message complet, bien qu'il en contienne habituellement plusieurs. Le tampon privé est traité après toute opération de lecture à la recherche de messages valides. Lors du traitement de messages multiples en provenance d'un client, on doit prendre soin au cas où un des messages causerait le départ du client.

8.3 Distribution de message

Il est courant de trouver des liens réseaux saturés ou des hôtes à qui vous envoyer des données et qui sont incapables d'en faire autant. Bien qu'Unix gère typiquement cela à travers la fenêtre TCP et ses tampons internes, le serveur a généralement de grandes quantités de données à envoyer (spécialement lorsqu'une nouvelle connection serveur/serveur est crée) et les petits tampons fournis dans le noyau ne sont pas suffisant à la queue de sortie. Pour alléger ce problème, une "queue d'envoi" est utilisée comme une queue FIFO pour les données à envoyer. Une "queue d'envoi" typique peut croître jusqu'à 200ko sur un gros réseau IRC, avec des connections réseau lentes quand un nouveau serveur se connecte.

Lorsqu'il traite ses connections, un serveur doit d'abord lire et traiter toutes les données entrantes, en mémorisant les données qui seront émises. Quand toutes les entrées disponibles sont traitées, la queue d'envoi est expédiée. Cela réduit le nombre d'appels systèmes write() et aide TCP à faire des paquets plus gros.

8.4 La vie d'une connection

Pour détecter quand une connection est morte ou ne répond plus, le serveur doit envoyer un PING à toute les connections dont il n'a pas eu de réponse depuis un temps donné.

Si une connection ne répond pas à temps, elle est fermée en utilisant les procédures appropriées. Une connection est également lâchée si son sendq grossi au-delà du maximum autorisé, car il vaut mieux fermer une connection lente que d'avoir le processus serveur bloqué.

8.5 Etablissement d'une connection serveur à client

Lors de la connection à un serveur IRC, on envoie au client le MOTD (s'il est présent) ainsi que le nombre actuel d'utilisateur et de serveurs (comme pour la commande LUSER). Le serveur doit également envoyer un message non équivoque au client, qui stipule son nom, sa version, ainsi que tout autre message d'introduction qui lui semble approprié.

Après cela, le serveur doit envoyer le pseudo du nouvel utilisateur, et toute autre information aussi bien fournies par le client (commande USER) que celles trouvées par le serveur (serveurs DNS et IDENT). Le serveur doit envoyer ces informations à la première commande NICK suivi de USER.

8.6 Etablissement d'une connection serveur/serveur

Le processus d'établissement d'une connection serveur à serveur est plein de dangers, car il y a de nombreux domaines où un problème peut survenir { - the least of which are race conditions.}

Après avoir reçu une connection suivi d'une paire PASS/SERVER qui a été reconnue valide, le serveur doit répondre avec ses propres informations PASS/SERVER pour cette connection, ainsi que toutes les informations d'état qu'il connais comme décrit ci-dessous.

Quand le serveur initiant reçoit la paire PASS/SERVER, lui aussi vérifie que le serveur répondant est authentifié correctement avant d'accepter la connection comme étant ce serveur.

8.6.1 Echange des informations d'état des serveurs à la connection

L'ordre des informations d'état échangées entre les serveurs est essentiel. L'ordre requis est le suivant :
  • tous les autres serveurs connus ;
  • toutes les informations utilisateurs connues ;
  • toutes les informations de canaux connues.
Les informations concernant les serveurs sont envoyées avec des messages SERVER supplémentaires, les informations utilisateurs avec des messages NICK/USER/MODE/JOIN et celles des canaux avec des messages MODE.

NOTE : Les sujets des canaux ne sont PAS échangés ici, car la commande TOPIC écrase toute information de sujet précédente, si bien que, au mieux, les deux côtés de la connection échangeraient les sujets.

En passant les informations d'état concernant les serveurs en premier, toutes les collisions avec des serveurs qui existeraient déjà ont lieu avant les collisions de pseudo dues à un second serveur introduisant un pseudonyme particulier. En raison de l'obligation de réseau IRC à n'exister que sur un graphe acyclique, il est possible que le réseau se soit déjà reconnecté ailleurs, et l'endroit où la collision a lieu indique ou le réseau doit être divisé.

8.7 Terminaison des connection serveur/client.

Lorsqu'une connection client se ferme, un message QUIT est généré de la part du client par le serveur sur lequel le client était connecté. Aucun autre message ne doit être généré ou utilisé.

8.8 Terminaison des connections serveur/serveur.

Si une connection serveur/serveur est fermée, soit par un SQUIT généré à distance, soit par une cause 'naturelle', le reste du réseau IRC doit le prendre en compte, et c'est au serveur qui détecte la fermeture de faire circuler l'information. Le serveur envoie une liste de SQUIT (un par serveur au-delà de la connection coupée) et une liste de QUIT (un par client au-delà de la connection coupée).

8.9 Suivi des changements de pseudonymes

Tous les serveurs IRC doivent garder un historique des changements récents de pseudonymes. Cela est nécessaire pour offrir au serveur la possibilité de garder le contact quand une commande concerne un utilisateur changeant de pseudo. Les commandes qui doivent vérifier un changement de pseudo sont :
  • KILL (le pseudo se faisant tuer)
  • MODE (+/- o,v)
  • KICK (le pseudo se faisant exclure)
Aucune autre commande ne doit vérifier un changement de pseudo.

Dans les cas ci-dessus, le serveur doit tout d'abord vérifier l'existence du pseudonyme, puis vérifier l'historique pour voir à qui appartient ce pseudo. Cela réduit les chances de problèmes, mais ne les empêche pas complètement, ce qui peu résulter au final de l'affectation du mauvais client. Lors du traçage des changements de pseudonymes pour une des commandes ci-dessus, il est recommandé qu'un intervalle de temps soit donné, et que les entrées trop vielles soient ignorées.

Pour un historique parfait, un serveur devrait être capable de garder les pseudonymes de tous les clients qui ont décidé d'un changement. La taille est limitée par d'autres facteurs (tels que la mémoire, ...)

8.10 Contrôle d'inondation des clients

Dans un gros réseau de serveurs IRC interconnectés, il est assez facile, pour un simple client connecté, d'émettre un flux continu de messages qui résultent non seulement en l'inondation du réseau, mais aussi en la dégradation de la qualité de service fournie aux autres clients. Au lieu de demander à chaque 'victime' de gérer sa propre protection, la protection contre les inondations est incluse dans le serveur et est appliquée à tous les clients, à l'exception des services. L'algorithme actuel est le suivant :
  • vérifier si les 'messages de temps' des clients est inférieur au temps courant (et le mettre à l'heure courante le temps échéant) ;
  • lire toute donnée présentée par le client ;
  • tant que le compteur est inférieur à dix secondes par rapport à l'heure actuelle, traiter tout message actuel et pénaliser le client de deux secondes par message ;
Ce qui, en essence, signifie qu'un client ne peut envoyer plus d'un message toutes les deux secondes sans être affecté.

8.11 Boucles non bloquantes

Dans un environnement temps réel, il est essentiel qu'un processus serveur attende aussi peu que possible, de manière à ce que tous les clients soient servis justement. Evidement, cela nécessite des ES non bloquantes sur toutes les opérations de lecture/écriture du réseau. Pour les connections de serveur normales, ce n'est pas compliqué, mais il y a des opérations gérées qui peuvent causer un blocage du serveur (telles que les lectures disque). Quand c'est possible, de telles activités doivent être exécutée avec un délai d'attente maximal court.

8.11.1 Recherche du nom d'hôte (DNS)

L'utilisation des librairies de résolution standards de Berkeley et autres entraîne de gros délais, dans les cas où les réponses n'arrivent pas. Afin d'éviter cela, un jeu de routines DNS indépendantes ont été écrites, où les opérations DNS ont été écrites avec des E/S non bloquantes et testées depuis la boucle d'E/S principale du serveur.

8.11.2 Recherche du nom d'utilisateur (IDENT)

Bien qu'il y ait de nombreuses libraires IDENT à utiliser et inclure dans d'autres programmes, elles posent des problèmes puisqu'elles opèrent de façon synchrone, et résultent en de nombreuses attentes. Encore une fois, la solution a été d'écrire un jeu de routines qui coopèrent avec le reste du serveur, et utilisent des E/S non bloquantes.

8.12 Fichier de configuration

Afin de fournir une façon flexible de configurer et de lancer le serveur, il est recommandé qu'un fichier de configuration soit utilisé, qu'il contienne les instructions du serveur suivantes :
  • de quels hôtes accepter une connection en tant que client;
  • de quels hôtes accepter une connection en tant que serveur;
  • à quels hôtes se connecter (aussi bien activement que passivement) ;
  • informations sur l'emplacement du serveur (université, ville/état, entreprise par exemple) ;
  • quels sont les responsables du serveur, avec une adresse email où ils peuvent être contactés ;
  • noms d'hôtes et mots de passe pour les clients qui souhaitent obtenir l'accès restreint aux commandes d'opérateur.
Lors de la spécification des noms d'hôtes, les noms de domaines et la notation 'point' (127.0.0.1) doivent être tous les deux gérées. Il doit être possible de préciser un mot de passe à utiliser/accepter pour toutes les connections entrantes et sortantes (bien que les connections sortantes soient toutes à destination de serveurs).

La liste ci-dessus est le minimum obligatoire pour tout serveur qui souhaite se connecter à un autre serveur. Parmi les autres éléments utiles, on trouve :

  • spécification de quels serveurs un serveur peut introduire ;
  • jusqu'à quelle longueur une branche de serveur peut aller ;
  • heures durant lesquelles un client peut se connecter

8.12.1 Autorisation des connections de clients

Un serveur doit utiliser une sorte de 'liste de contrôle d'accès' (soit dans le fichier de configuration ou ailleurs) qu'il lit au démarrage et utilise pour décider quels hôtes les clients peuvent utiliser pour se connecter.

'Accepter' et 'interdire' doivent tout les deux être implémentés pour fournir le niveau de flexibilité requis par le contrôle d'accès des hôtes.

8.12.2 Opérateurs

En raison des pouvoirs qui leur sont accordés , le don des privilèges d'opérateurs à une personne turbulente peut avoir des conséquences désastreuses sur le bien-être du réseau IRC en général. C'est pourquoi l'acquisition de ces pouvoirs ne doit pas être facile. La configuration actuelle nécessite deux mots de passes, bien que l'un d'entre eux soit généralement facile à trouver. L'enregistrement des mots de passe d'opérateur dans le fichier de configuration est préférable à leur codage en dur, et ils doivent être sauvegardé dans un format codé (par exemple en utilisant crypt(3) d'Unix) afin de rendre les vols plus difficiles.

8.12.3 Autorisation des connections de serveurs

L'interconnexion de serveurs n'est pas une chose triviale : une mauvaise connection peut avoir un gros impact sur l'utilité d'IRC. C'est pourquoi chaque serveur doit avoir une liste des serveurs sur lesquels il peut se connecter, et de ceux qui peuvent se connecter à lui. En aucune manière un serveur ne doit accepter arbitrairement une connection d'hôte en tant en serveur. En plus de la liste des serveurs qui peuvent et qui ne peuvent pas se connecter, le fichier de configuration doit aussi contenir le mot de passe et les autres caractéristiques de ce lien.

8.12.4 Admin

Pour fournir des réponses valides et précises à la commande ADMIN (voir section 4.3.7), le serveur doit trouver tous les détails appropriés dans le fichier de configuration.

8.13 Appartenance à un canal.

Le serveur actuel autorise tout utilisateur enregistré localement à accéder jusqu'à 10 canaux différents. Il n'y a pas de limites imposées aux utilisateurs non-locaux, si bien que le serveur reste (raisonnablement) cohérent avec les autres serveurs pour ce qui est de l'appartenance à un canal.