2 Contrôleur, routeur et proxy http

  Le but de cette section va être de pouvoir parler à un serveur en faisant passer les paquet par l’intermédiaire de plusieurs routeurs. Pour cela, il est nécessaire d’avoir à sa disposition un contrôleur qui va choisir un chemin, puis encapsuler les données du client vers le premier routeur. Le rôle du routeur se contentant pour l’instant de jouer le rôle d’intermédiaire.

  Une attention toute particulière devra être apportée aux logs de vos serveurs. Il faut qu’ils soient de la meilleure qualité possible pour pouvoir débugger facilement. De plus un système devra exister qui permette de récupérer les logs de vos serveurs.

  Dans tout le projet, les paquets que vous allez traiter auront tous le format suivant :

format des paquets

Nous considèrerons que la version sera 0.

2.1 Routeur

  Pour les utilisateurs de Python, l’utilisation de la librairie asyncore est autorisée et conseillée. Dans les autres langages, la methode par select devrait être la plus efficace mais souvent plus difficile à programmer. Quelquefois, selon le système d’exploitation, l’utilisation de fork() peut se révéler plus efficace que l’utilisation de threads. A vous de justifier votre choix de programmation.

Celui-ci offre plusieurs services :

2.1.1 Services proposés par le routeur

Les services que proposent le routeur sont accessibles par les clients avec les requêtes : SUIV, CONN FLUX, FERM et BKDR.

Si le sucesseur d’un routeur ferme la connexion alors, le routeur envoie à son client utilisant ce successeur la commande CLOS (CLOSed). Si la connexion a été obtenue avec CONN plutôt que SUIV alors le paquet contiendra aussi le n de session dans la partie données.

2.1.2 Contrôleur

  Le contrôleur sera un serveur qui devra dans le cas général être lancé sur le même poste que le client en tant que démon. Il va se comporter soit comme le serveur cible soit comme un proxy http . Le contrôleur joue un rôle similaire à celui des routeurs, mais en plus il contrôle la création des chemins et les encapsulation des données. C’est le contôleur qui va créer un tunnel de routeur. C’est au contrôleur de décider quelle sera la longueur des chemins et qui gèrera les numéros de session. Le contrôleur décidera aussi par la suite les clés à utiliser pour le chiffrement.

Le contrôleur doit pouvoir fonctionner selon deux modes : un mode simulation de serveur et un mode proxy http .

Le routeur doit posséder les fonction internes suivantes :

De plus, pour le début du projet, nous considérons que le contrôleur possède la liste des routeurs accessibles ; soit dans une structure de données remplie manuellement, soit dans un fichier qui sera chargé à chaque démarrage du contrôleur. Ajouter un système de publication des routeur fera partie des dernières étapes du projet.

La conception du contrôleur sera très proche de celle des routeurs. Voici les requêtes que peuvent formuler les clients au contrôleur et les services qui leur sont alors fournis :

2.2 Résumé et exemple

Pour résumer voici la table qui résume l’ensemble des requêtes pour les routeurs et les contrôleurs :

Pour le routeur :




Requête Données Retour requête



SUIV "adresse:port" "COOK" ou "ERRC"



CONN nsession"adresse:port""COOK" ou "ERRC"



FLUX données brutes -



FERM - "CLOS"



BKDR - logs



Pour le contrôleur :




Requête Données Retour requête



CONN nsession"adresse:port""COOK" ou "ERRC"



FLUX données brutes -



BKDR - logs



Requête proxy - -



Pour fixer les idées nous donnons un exemple des paquets passant sur le réseaux. Le réseau concerné est le suivant :

représentation du réseau

Sont écrit entre parenthèse les commande qui ne nécessitent pas d’entrée ou de sortie sur les sockets comme les connexions et les "close". Les paquets sont écrit selon la notation suivante : v."req".l."data" avec :

Voir la figure 1 page §.


Illustration de la connexion echo


Fig. 1: Illustration de la connexion echo

--- Creation du tunnel avant la connexion du client ---  
C  -> R1 : (connect)  
R1 -> C  : (accept)  
C  -> R1 : 0."SUIV".19."147.94.66.131:34500"  
R1 -> R2 : (connect)  
R2 -> R1 : (accept)  
R1 -> C : 0."COOK".0.  
--- Creation de la connexion ---  
A  -> C  : (connect)  
C  -> A  : (accept)  
C  -> R1 : 0."FLUX".30.[0."CONN".23.2345"serverecho:2000"]  
R1 -> R2 : 0."CONN".23.2345"serverecho:2000"  
R2 -> B  : (connect)  
B  -> R2 : (accept)  
R2 -> R1 : 0."COOK".4.2345  
R1 -> C  : 0."DATA".11.[0."COOK".4.2345]  
--- Envoi des données vers le serveur ---  
A  -> C  : 0."FLUX".6."coucou"  
C  -> R1 : 0."FLUX".17.[0."FLUX".10.2345"coucou"]  
R1 -> R2 : 0."FLUX".10.2345"coucou"  
R2 -> B  : "coucou"  
B  -> R2 : "coucou"  
R2 -> R1 : 0."DATA".10.2345"coucou"  
R1 -> C  : 0."DATA".17.[0.DATA.10.2345"coucou"]  
C  -> A  : "coucou"  
--- Fermeture de la session ---  
A  -> C  : (close)  
C  -> R1 : 0."FLUX".11.[0."FERM".4.2345]  
R1 -> R2 : 0."FERM".4.2345  
R2 -> B  : (close)

2.1.  Écrivez le même type de conversation en utilisant le même réseaux mais en ajoutant un deuxième client echo D qui se connecte en même temps à un autre serveur echo E.

(a)  Pourraient-ont se passer des numéros de session ? Si oui, quelles fonctionnalités du réseau anonyme perdraient-on ? Si non, expliquez en quoi ces numéros de sessions sont absolument nécessaires à la bonne utilisation du réseau anonyme.

Voici un autre exemple de dialogue possible entre un client http A et un serveur http B qui se parlent par l’intermédiaire d’un contrôlleur C et de deux routeurs R1 et R2. L’adresse IP de R2 est 147.94.66.131 l’adresse de B est servhttp.com et écoute sur le port 80.

C  -> R1 : 0."SUIV".19."147.94.66.131:34500"  
R1 -> R2 : (connect)  
R2 -> R1 : (accept)  
R1 -> C  : 0."COOK".0  
A  -> C  : GET http://servhttp.com HTTP/1.0\r\n  
C  -> R1 : 0."FLUX".26.[0."CONN".19.456"servhttp.com:80"]  
R1 -> R2 : 0."CONN".19.456"servhttp.com:80"  
R2 -> B  : (connect)  
B  -> R2 : (accept)  
R2 -> R1 : 0."COOK".4.456  
R1 -> C  : 0."DATA".11.[0."COOK".4.456]  
C  -> R1 : 0."FLUX".49.[0."FLUX".42.456"GET http://servhttp.com HTTP/1.0\r\n"]  
R1 -> R2 : 0."FLUX".42.456"GET http://servhttp.com HTTP/1.0\r\n"  
R2 -> B  : "GET http://servhttp.com HTTP/1.0\r\n"  
B  -> R2 : HTTP/1.0 200 OK ...  
R2 -> R1 : 0."DATA".231.456"HTTP/1.0 200 OK ... "  
R1 -> C  : 0."DATA".238.[0."DATA".231.456"HTTP/1.0 200 OK ... "]  
C  -> A  : "HTTP/1.0 200 OK ... "  
B  -> R2 : (close)  
R2 -> R1 : 0.CLOS.4.456  
R1 -> C  : 0."DATA".11.[0."CLOS".4.456]  
C  -> A  : (close)

Remarquez que la connexion entre R1 et R2 n’a pas été fermée.

2.2. Dans un premier temps programmez un routeur sans gérer la requête CONN.

(a) En utilisant telnet, vérifiez que vous pouvez vous connecter à travers plusieurs routeurs. Pour cela utilisez comme destination un serveur echo.

2.3. Programmez un contrôleur qui ne gére pas CONN et vérifiez que tout fonctionne. En particulier vérifiez, en utilisant ethereal, que les message sont bien ceux attendus. Essayez l’ensemble des cas suivants :

(a) contrôleur en mode simulation vers un serveur echo en utilisant un, deux et trois routeurs.

2.4. Ajoutez le service CONN au routeur et au contrôleur. Vérifiez que tout fonctionne correctement :

(a) Soit le tunnel suivant : un contrôleur sur 127.0.0.1:9090, le routeur sur 127.0.0.1:9091, un serveur echo sur 127.0.0.1:3000. En utilisant ethernet donnez les trames qui correspondent à la connexion de deux clients echo qui se connectent au serveur echo via le tunnel.

(b) Recommencez en ajoutant un second routeur, puis un troisième (toujours sur l’ordinateur local).

(c) Vérifiez que les connexions fonctionnent toujours même lorsque les ordinateurs sont différents.

2.5. Ajoutez la fonctionnalité mode proxy http au contrôleur.

(a) Vérifiez en vous connectant via le contrôleur vers votre site personnel ou sur n’importe quel site hébergé par daumier. N’oubliez pas de vérifier avec ethereal que les paquets sont bien envoyés via le contrôleur.