Licence d'Informatique - Projet tutoré
MUXFTP : un serveur FTP virtuel
Résumé :
Le protocole FTP est couramment utilisé pour effectuer des transferts
de fichiers dans des réseaux IP (Internet ou LAN). Son mode de fonctionnement
est tel que chaque transfert de fichier utilise une connexion TCP différente
; ce qui permet d'effectuer un transfert d'un serveur à un autre
sans passer par le client. Le serveur FTP virtuel est une variante sur
ce thème ; le but est d'implanter un serveur FTP qui servira de
proxy pour un ou plusieurs serveurs FTP normaux. L'originalité
du proxy sera de permettre des "montages" ou "liens symboliques"
à travers l'arborescence virtuelle ; par exemple, sur le serveur
virtuel, le répertoire /pub pourrait être redirigé
vers le serveur helios dans son répertoire /pub
; le répertoire /debian pourrait être redirigé
vers le répertoire du même nom sur le serveur naibed
; et le répertoire /incoming sur le serveur porky
dans le répertoire /new. Le second intérêt
du serveur virtuel est de permettre des connexions directes entre le client
et le véritable serveur, sans que les données n'aient à
transiter par le proxy. Bien sûr, outre l'écriture
du serveur (impliquant la compréhension du protocole FTP et l'utilisation
de sockets en C ou dans un autre langage adapté), le projet
comporte la rédaction d'une documentation permettant de faire fonctionner
le serveur et éventuellement d'y apporter des modifications, ainsi
que la réalisation d'un package Debian afin de permettre
une installation facile.
Mots clefs :
FTP - SERVEUR - DEBIAN - DPKG - LINUX - RETR - PASV - PORT - SOCKET - TCP
- API - DEMON - PROXY - PYTHON
Connaissances requises :
-
Notions de base de réseaux IP (être familier avec ping,
telnet et éventuellement netcat ; avoir déjà
utilisé un client FTP, et éventuellement avoir déjà
installé ou configuré un serveur FTP)
-
Anglais lu et écrit couramment (toutes les docs à lire, ainsi
qu'à rédiger, sont en anglais)
-
Langage de programmation - plusieurs choix possibles : C/C++ (très
proche du système, attention à la propreté du code),
Java ou Python (gestion "propre" du réseau, des threads,
des exceptions)
-
Bonne méthodologie au niveau des tests du programme (on ne débogue
pas un programme en environnement client/serveur à coups de printf)
-
Système de packaging Linux quelconque (dpkg ou rpm
par exemple)
Intérêt
La manipulation de sockets constitue à la fois une difficulté
et un intérêt importants. Les concepts réseau
ne sont pas très difficiles à appréhender, et pour
quelqu'un qui dispose déjà de quelques notions, ce projet
est l'occasion de les conforter concrètement. Le protocole FTP est
original ; à la fois simple (format des commandes, données
transférées sans en-têtes particulières...)
et compliqué (utilisation de deux connexions séparées
pour les commandes et les données). Sa complexité nous permet
justement les transferts serveur/serveur ou serveur/client par l'intermédiaire
d'un proxy, sans charger le client ou le proxy. En résumé,
ce projet permet d'aborder la programmation réseau, en utilisant
des protocoles très courants ; de plus, l'utilité du proxy
FTP est bien réelle, car il permettrait de créer un serveur
FTP "virtuel" de très grande taille, constitué en réalité
de plusieurs serveurs "normaux" et d'un proxy.
Description détaillée :
Le protocole FTP est assez ancien (il fait partie des premiers protocoles
définis sur TCP/IP, et fêtera donc bientôt ses 30 ans),
et il est encore utilisé tous les jours dans de nombreuses applications
(téléchargement de programmes, de sources ; accès
non crypté à des données personnelles ; mise à
jour de sites Web...). Son principe est assez simple : le client établit
une connexion dite de commande avec le serveur. Après une
éventuelle phase d'authentification très simple, le client
peut se promener dans les répertoires du serveur, comme on le ferait
avec la commande shell cd. Lorsque le client souhaite lister le
contenu d'un répertoire, ou bien transférer un fichier du
serveur vers chez lui ou inversement, il établit une seconde connexion,
dite de données. Chaque répertoire listé, ou
chaque fichier transféré, nécessite une nouvelle connexion.
Cette connexion supplémentaire peut sembler lourde et inutile,
mais elle constitue toute la force du protocole. En effet, le côté
qui établit cette deuxième connexion demande son adresse
à l'autre partie ; c'est-à-dire que si c'est le serveur qui
établit la deuxième connexion (mode par défaut, dit
actif), il demande au client sur quelle adresse IP et quel
port TCP le contacter ; si c'est le client qui établit la connexion
(mode passif, utilisé pour passer certains firewalls),
le serveur lui dit sur quelle adresse IP et port TCP le contacter. Ce
qui veut dire que lorsque le client annonce "me contacter sur telle adresse,
tel port", le serveur FTP virtuel (le proxy) va contacter un "vrai"
serveur FTP pour lui relayer cette information, afin que ce soit le vrai
serveur qui se connecte directement au client ; inversement, lorsque c'est
au serveur d'annoncer où se connecter, le proxy demande l'adresse
et le port au vrai serveur et annonce ces informations au client.
Un petit schéma pour rendre tout ceci encore plus incompréhensible
:
DATA pour LIST
/--------------------------------------------------------\
|
|
v CWD /pub, LIST, cwd /debian
CWD /pub, LIST v
[client]<----------------------\ /--------->[serveur
1]
^ cd /new, STOR
| /
|
v / CWD /debian
|
[proxy]*------------>[serveur 2]
|
\
\
\ CWD /new, STOR
\
\--------->[serveur 3]
\
^
\ DATA pour
STOR
|
\--------------------------------------------------/
Heureusement, il est très facile d'utiliser un outil comme netcat
pour simuler le comportement d'un serveur ou d'un client FTP, afin de mieux
comprendre le principe de fonctionnement et de réaliser des tests.
Il doit exister un moyen de définir les "montages" ou "liens"
dans l'arborescence du serveur. Plusieurs solutions sont possibles
; voici 3 exemples :
-
fichier de configuration, spécifiant des associations chemin "virtuel"
-> (serveur,chemin)
-
arborescence "normale", chaque fichier étant interprété
comme un répertoire virtuel ; chaque fichier doit être un
fichier texte, contenant le nom du serveur et le répertoire réels
-
arborescence constituée de liens symboliques, pointant vers des
fichiers inexistants, le nom du fichier cible indiquand le serveur et le
chemin réels
-
...
A priori, l'écriture du proxy nécessite de gérer
la plupart des commandes du protocole FTP, mais toutes les commandes manipulant
l'état du serveur (changement de répertoire courant, principalement)
doivent être exécutées sur un serveur distant. Il faut
donc éventuellement conserver plusieurs connexions ouvertes, et
maintenir un état ; il va sans dire qu'il est fortement recommandé
de réfléchir longuement sur papier avant de pondre un code
qui ferait n'importe quoi.
Le projet peut être développé en C ou C++, mais
ce n'est pas obligatoire. L'inconvénient de ces langages est qu'il
n'y a pas de bibliothèque standard bien adaptée à
la manipulation de threads et de sockets ; il faut utiliser
des appels système d'assez bas niveau, gérer correctement
les erreurs et les signaux... En Java ou en Python, le développement
est beaucoup plus facile. Le Python n'est pas enseigné à
Marne-La-Vallée (pour l'instant), mais si des élèves
souhaitent utiliser ce langage (qui présente de nombreux avantages
sur le Java, surtout pour un projet "léger"), il est relativement
simple à prendre en main.
Travail à effectuer :
-
se familiariser avec le protocole FTP (réaliser un transfert en
utilisant nc, par exemple)
-
comprendre les nuances mode actif/passif ; réaliser un transfert
serveur/serveur, et simuler le fonctionnement du proxy (toujours
avec nc, à la main)
-
étudier brièvement le fonctionnement des sockets et
des threads dans les différents langages proposés,
afin de faire un choix
-
écrire le pseudo-code des différentes parties du proxy
-
choisir la méthode de configuration (association entre chemins virtuels
et serveur+chemin réels)
-
implanter le proxy
-
faire de nombreux tests
-
réaliser un package Debian
Des améliorations pourront être proposées ; par exemple
afin de faire du load-balancing sur plusieurs serveurs offrant les
mêmes contenus, ou bien pour calculer à partir de l'adresse
IP du client le miroir le plus proche de lui. Ces améliorations
sont tout à fait facultatives ; il est bien plus important d'avoir
un projet qui marche avec les fonctionalités de base, qu'un projet
qui ne marche pas avec des fonctionalités étendues...