Spécification (non officielle) du protocole Netsoul Par Patrick MARIE Dernière modification: 20031029 /* * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 42): * wrote this file. As long as you retain this notice * you can do whatever you want with this stuff. If we meet some day, and you * think this stuff is worth it, you can buy me a beer in return. Patrick MARIE * ---------------------------------------------------------------------------- */ Ce papier est munie d'une structure qui me semble la meilleure pour la rédaction de celle ci (lire: j'écris cela comme je le sens). Il décrit ce que j'ai pu apprendre en lisant les différentes sources des clients, et en reproduisant différentes parties du protocole. Pour ceux qui ne le savent pas, Epita/Epitech sont deux écoles d'informatique en France, situe au Kremlin bicetre (sud ouest de Paris). (liens: http://www.epita.fr/ ; http://www.epitech.net/) Je ne suis pour ma part aucunement affilié de près ou de loin à ces écoles, rédigeant cette documentation pour informer les utilisateurs. I. Sommaire * I. Sommaire * II. Présentation * III. Phase d'authentification * IV. Commandes * V. Messages serveur * VI. Annexes II. Présentation Les informations présentes dans ce papier feront sûrement l'objet de modifications indépendantes de ma volonté. Sera indépendante de ma volonté également la mise à jour de ce texte, car je ne serai certainement pas motivé pour continuer de chercher ce que les mainteneurs principaux de Netsoul-Epita (voir ci dessous) feront comme modifications dans le futur. Les informations sont actuelles à la date de dernière mise à jour de ce texte. Au moment ou j'écris ces lignes, le seul serveur Netsoul-Epita (Netsoul-Epita nommant le nom du protocole netsoul dans Epita) se situe sur le port TCP 4242 et à l'adresse "ns-server.epita.fr" (163.5.255.80) (et en interne dans Epita, 10.42.1.59) Les commandes envoyées et reçues sont toujours terminées par '\n'. Certaines commandes envoyées par le client peuvent recevoir des "accusés de réception", d'autres non. Tout cela sera notifié au bon moment. Notations: Les messages reçus et envoyés étant au format texte ascii, il est facile de représenter dans ce texte plusieurs exemples. Les lignes envoyées seront dans ce document précédées d'un 'client: '; Les lignes reçues seront précédées d'un 'server: '. Bien entendu, ces 'client: ' et 'server: ' ne font pas partis de la communication sur le réseau. Par exemple: -- capture 1 -- client: test -- fin capture 1 -- correspondra en C à: ... #define TEST_MESSAGE "test\n" ... write(sock, TEST_MESSAGE, strlen(TEST_MESSAGE)); ... Pour les exemples "longs", on rajoutera des balises '-- capture X --' et '-- fin capture X --' pour délimiter ces exemples. III. Phase d'authentification 1/ Premier cas: utilisateur externe au PIE. -- capture 1 -- client: telnet ns-server.epita.fr 4242 client: Connected to 163.5.255.80. client: Escape character is '^]'. server: salut 27 2fb93c1e8020c71ccf99f6555f70e56f 195.220.50.8 45686 1036068977 -- fin capture 1 -- Le premier message d'authentification est de ce format: salut Le numéro de socket est invariablement un unsigned int; la chaîne md5 un unsigned char d'une longueur de 32 octets ('\0' final non compris); l'host client est une ip lisible, donc au maximum d'une longueur de 15 octets; ('\0' final non compris); le port client est un unsigned short; le timestamp est un time_t. Le hash md5 aléatoire, l'host client et le port client vont servir à construire la chaîne d'authentification à envoyer par le client. Avant cela, le client doit demander l'autorisation de s'authentifier, et en donner la méthode. client: auth_ag ext_user none none server: rep 002 -- cmd end A partir de ce moment, le client doit envoyer la commande 'ext_user_log', de ce format la: client: ext_user_log mycroft b2177622c14612a9b0e725b9c317026f none location server: rep 002 -- cmd end Les paramètres sont de ce format: ext_user_log Le login user n'est que le login utilisateur, sur le PIE; La chaîne md5 de réponse est telle que: MD5("-/") Exemple: ... /* Les arguments sont récupérées des commandes précédentes */ sprintf(buffer, "%s-%s/%i%s", hashauth, client_host, client_port, password); /* Primitive MD5 issue de la libcrypto (openssl) */ MD5(buffer, strlen(buffer), pass); /* MD5 renvoie des données sous format binaires, on rend la chaîne 'lisible' */ str = malloc(sizeof(char) * (MD5_DIGEST_LENGTH * 2 + 1)); memset(str, 0, (MD5_DIGEST_LENGTH * 2 + 1)); for (i = 0; i < MD5_DIGEST_LENGTH; i ++) sprintf(str + (2 * i), "%02x", pass[i]); ... Le champs 'user data' et 'user location' permettent de définir deux valeurs, en général le client utilise et la version, et la location du client (dans le PIE, la salle, le rang et le numéro de station) Ces deux champs doivent être dans le format des urls, c'est à dire pour faire passer "toto tutu lala" il faudra envoyer "toto%20tutu%20%lala" Ces deux champs sont de longueur maximum de 64 caractères. Exemple: client: ext_user_log mycroft c5b38c5022d9e1af23cfb89630010f03 paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20 nsc%20roulez server: rep 002 -- cmd end Au moment où l'ext_user_log est envoyé et confirmé, l'utilisateur est loggué dans le réseau netsoul et peut envoyer des commandes. On associera deux commandes à la phase de connexion pour un utilisateur externe au PIE: "attach" et le changement de status. 'attach' permet aux utilisateurs externes de libérer l'accès à d'autres daemons interne à epita tels que les news. client: attach server: rep 002 -- cmd end En final, à la connexion, le status utilisateur est 'connexion'. Le client doit changer ce status. (voir plus loin.) client: state actif:1067437282 Le serveur ne renvoie rien suite à la commande 'state'. 2/ Second cas: utilisateur interne au PIE. Un utilisateur du PIE, c'est à dire l'ensemble des machines dans le parc informatique d'epita n'a pas à subir cette phase d'authentification, comme elle a été établie par la connexion de l'utilisateur sur le réseau. Afin de récupérer la connexion, l'utilisateur doit récupérer les variables d'environnement $NS_USER_LINK afin de connaitre le numéro de la socket unix, qui sera: ... int sock; struct sockaddr_un sua; sock = socket (PF_LOCAL, SOCK_STREAM, 0); sprintf(path, "%s/.ns/%s", getenv("HOME"), getenv("NS_USER_LINK")); strcpy(sua.sun_path, path); connect (sock, (struct sockaddr *)&sua, sizeof(sua)); ... IV. Commandes Ces commandes existent pour les clients internes et externes au PIE. D'une manière générale, les commandes utilisateurs doivent être précédée d'un 'user_cmd' quand on est à l'extérieur du PIE, et d'un 'cmd' quand on est à l'intérieur du PIE. Exemple: Si l'on veut envoyer un message à 'rn' (voir section IV. 2/ ), on utilisera: - de l'extérieur: client: user_cmd msg_user rn msg test - de l'intérieur (sur la socket unix): client: cmd msg_user rn msg test 1/ state Les clients (utilisateur) netsoul se voient attribués d'un status de la connexion. Bien que n'importe quel status semble être accepté par le serveur, il est préférable d'en utiliser qu'un de ceux ci: * actif -> Vous êtes sur votre station de travail, près à être joint si nécessaire; * away -> Vous n'êtes pas sur votre station de travail; * connection -> Vous n'avez pas changé le status par défaut suivant la connexion; * idle -> Vous êtes sur votre station, mais n'avez pas montré signe de vie; * lock -> Vous avez locké votre station; * server -> Le client est sur un serveur d'applications; * none -> Vous ne désirez pas utiliser le status. Avec cela, il faut envoyer le timestamp de changement d'état, sous ce format: state : Exemples d'utilisation: client: state actif:1036142854 state away:1036142860 D'une manière générale, les commandes utilisateur A l'externe du PIE, cette commande peut aussi etre envoyée de cette forme: client: user_cmd state Exemples d'utilisation: client: user_cmd state none client: user_cmd state actif Voir également la section "Messages serveur". 2/ msg Comme jabber ou yahoo, il est possible de faire de "l'instant messaging" avec Netsoul. On peut envoyer des messages à toutes les personnes loggués à netsoul. L'envoie de message à des personnes non loggués est autorisée, mais les messages ne sont pas conservés par le serveur (donc perdus). Exemple, pour un utilisateur externe puis interne: client: user_cmd msg_user rn msg bonjours client: cmd msg_user rn msg bonjours Format: (cmd|user_cmd) msg_user msg login / liste login contient soit un login (Exemple: 'rn'); soit une liste de login (Exemple: '{rn,jumpy,:42}'), ou, entre accolades et sépares par des ',', on peut mettre soit des login soit des numéros de sockets (prefixees alors de ':'). Cette notion de liste de login est également utilisée pour d'autre commandes. message: le message doit être du même format que "user data" et "location", en 'url encoded'. Exemple: client: user_cmd msg_user {mycroft,:1049} msg Salut%2C%20ca%20vas%20%3F Voir également la section "Messages serveur". 3/ list_users list_users permet de récupérer la liste des clients loggues sur netsoul. Il peut viser un login en particulier ou plusieurs via une liste de login (décrit dans la section IV. 2/) Format: list_users Exemple: -- capture 1 -- client: list_users rn server: 1419 rn 163.5.42.42 1067515354 1067516102 1 3 NetBsd_wse bocal_r1p1 wheel actif:1067516103 - server: rep 002 -- cmd end -- fin capture 1 -- -- capture 2 -- client: list_users dontexist server: rep 002 -- cmd end -- fin capture 2 -- -- capture 3 -- client: list_users {:1419,benoit_e} server: 184 benoit_e 10.252.42.53 1067515906 1067516521 3 1 ~ kernel ept_2002 serveur:1067515855 bnsd-0.1 server: 1419 rn 163.5.42.42 1067515354 1067516718 1 3 NetBsd_wse bocal_r1p1 wheel actif:1067516719 - server: rep 002 -- cmd end -- fin capture 3 -- Voir la section IV. 2/ pour la description de 'login / liste login'. Voir également la section "Messages serveur". 4/ watch_log_user watch_log_user permet de mettre en place, sur le serveur, une liste de login/connexion pour lesquelles on veut etre avertis des login/logout/ changements de status... (comme icq, aim, ...) Format: (cmd|user_cmd) watch_log_user Exemple: client: user_cmd watch_log_user {rn,benoit_e} Voir la section IV. 2/ pour la description de 'login / liste login'. Voir également la section "Messages serveur". 5/ who who permet d'avoir des informations sur un/des utilisateur(s) loggues (moyen de substitution à list_users). Format: (cmd|user_cmd) who Exemple: -- capture -- client: raw user_cmd who {rn,mycroft} server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | who 525 mycroft 195.220.50.8 106751826 5 1067518791 3 1 ~ paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20 ext actif:1067518387 nsc%20roulez server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | who 1419 rn 163.5.42.42 1067515354 1067518532 1 3 NetBsd_wse bocal_r1p1 wheel actif:1067518039 - server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | who 118 mycroft 212.129.36.164 1067500202 1067518681 3 1 ~ appart%40madrid ext actif:1067500221 bns%2D0%2E9%2E2%20%5B%20bNetSoul%20rocks%20%5D server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | who rep 002 -- cmd end -- fin capture -- Voir la section IV. 2/ pour la description de 'login / liste login'. Voir également la section "Messages serveur". 6/ exit Un client peut envoyer à tout moment la commande 'exit' afin de se delogguer du serveur. V. Messages serveur 1/ Changement de status d'un utilisateur Le client netsoul recevra tout les messages login, logout et state d'un utilisateur qu'il aura mis dans sa "watch_log" list. Exemple: client: user_cmd watch_log_user {mycroft} [...] server: user_cmd 91:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | login server: user_cmd 91:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | state actif:1067518230 server: user_cmd 91:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | state away:1067518242 server: user_cmd 91:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | logout [...] Voici le format d'une notification: user_cmd :user::@::: | socket: unsigned int, représentant le numéro de la socket du client qui vient d'envoyer le message; trust level: 1/3 hors du PIE (en externe, donc), 3/1 en interne; login: login de l'utilisateur du client qui envoie le message; user host: adresse ip du client; workstation type: type de la machine (seulement pour le PIE, ex: NetBsd_wse); location: champs location de l'utilisateur (en url encoded); command: soit login (pour indiquer que l'utilisateur vient de se logguer), logout (l'utilisateur vient de se delogguer), state (l'utilisateur vient de changer de status). 2/ Réception d'un message La réception d'un message est similaire au changement d'un status (V. 1/); Est juste différent la commande, qui sera 'msg': Exemple: client: user_cmd msg_user {mycroft} msg test server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | msg test Le message est url-encoded, et ne peut contenir plus de 256 caractères (après encodage.) De plus, on pourra recevoir les notifications pour les mails: server: user_cmd 0:mail:9/9:_deamon:: | new_mail -f mycroft@virgaria.org %28test%20email%29 La commande est 'new_mail'; Cette commande est suivie de -f, puis de l'email source du message et finalement du titre du mail en url-encoded. 3/ Réception d'une réponse à la commande list_users client: list_users franco_l server: 1043 franco_l 213.142.23.186 1067500237 1067520661 3 1 ~ rhs%2Ese epita_2003 actif:1067500198 42 server: rep 002 -- cmd end Le format du message reçu est de la forme: socket: unsigned int, représentant le numéro de la socket du client qui vient d'envoyer le message; user host: adresse ip du client; login timestamp: heure de connexion du client sur netsoul last status change timestamp: heure du dernier changement d'etat; trust level low/high: correspondent au 1/3 et 3/1 pour les machines dans le PIE et hors du PIE; workstation type: type de la machine; location: champs location de l'utilisateur (en url encoded); group: groupe de l'utilisateur; status: status de l'utilisateur; user date: champs userdata de l'utilisateur (en url encoded). 4/ Réception d'une réponse à la commande who Suite à la commande who, le client reçoit au moins une ligne comprenant, sous la forme d'un message de changement de status (V. 1/), mais ayant comme commande 'who' le message 'rep 002 -- cmd end'. client: user_cmd who {rn} server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | who 1419 rn 163.5.42.42 1067515354 1067522535 1 3 NetBsd_wse bocal_r1p1 wheel idle:1067522086 - server: user_cmd 525:user:1/3:mycroft@195.220.50.8:~:paul%2Dsud%2Easso%2Eups%2Dtlse%2Efr%20:ext | who rep 002 -- cmd end Le format de la partie avant le '|' est décrit dans la section V. I/ Le format de la partie après le '|' est le suivant: | who Le message reçu après le 'who' étant du même format que celui renvoyé par la commande 'list_users', le format n'en sera pas re décrit ici. cf section V. 3/ 5/ Réception d'un 'ping' Le serveur netsoul envoit régulierement des 'ping' afin de voir si le client est encore connecté. Il associe cela à un nombre qui correspond au nombre de seconde que le serveur attend après un message du client avant de le déconnecter. Le client peut répondre, par exemple, la même ligne envoyée. Exemple: server: ping 600 client: ping 600 VI. Annexes 1/ A faire * tenter une connexion ext à l'intérieur du PIE; il me semble que le 'protocole' d'auth etait une fois de plus différent. (cf méthode csecret) * voir les différentes gestions des "cmd", "user_cmd", ... à l'intérieur du PIE. * extensions des clients: 06:33 !!! Not yet handled: [user_cmd 95:user:1/3:asega_a@10.253.4.11:~:%5co_:ept3 | dotnetSoul_UserCancelledTyping null ] 06:33 !!! Not yet handled: [user_cmd 95:user:1/3:asega_a@10.253.4.11:~:%5co_:ept3 | dotnetSoul_UserTyping null ] 06:33 !!! Not yet handled: [user_cmd 95:user:1/3:asega_a@10.253.4.11:~:%5co_:ept3 | dotnetSoul_UserCancelledTyping null ] * récupérer les clients en commande, et voir les fonctions. 2/ Exemple de connexion 'complet' 3/ Change Log