Client FTP en mode passif [Résolu]

Signaler
Messages postés
34
Date d'inscription
dimanche 23 novembre 2003
Statut
Membre
Dernière intervention
6 juillet 2008
-
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
-
Bonjour,
je tente de créer un "client FTP" pour l'instant tres simpliste qui permet juste de se connecter à un serveur FTP et de lister le contenu du serveur uniquement et ceci dans le but de me familiariser avec la programmation des sockets.
J'utilise un serveur FTP tres simples nommée Typsoft.

Dans un premier temps, j'arrive bien à me connecter au serveur FTP en mode passif et a récuperer les reponses aux commandes mais pas les données .
Je recupère donc les résultat suivants:
reponse à ma fonction connect ():
220 **** FTP Server 1.10 ready...
réponse à ma commande USER body\r\n

331 Password required for body.
réponse à la commande PASS ****\r\n:

230 User body logged in.
réponse à la commande SYST\r\n:

215 UNIX Type: L8
réponse à la commande PASS\r\n

227 Entering Passive Mode (10,10,1,,1,231).

Mais maintenant je pense avoir un problème de comprehension du mode passif.
Si j'en crois apres mes recherches, mise a part que le mode passif permet d'éviter que notre firewall bloque la tentative de connexion du serveur  pour la transmission des données, il permet au client d'etre l'initiateur de la connexion au canal de données.
Si c'est bien cela, je dois donc créer un autre socket ayant pour destination l'adresse du serveur et le port qui sont indiqué dans la réponse
227 Entering Passive Mode (10,10,1,,1,231)??

Je pose la question parceque quand j'utilise le shell pour me connecter au serveur FTP en mode passif et que je lance wireshark(sniffeur) je ne vois pas que le client tente de se connecter au port désigné dans la réponse à la commande PASS\r\n.

Une derniere question à chaque réponse du serveur, le client envoit des paquets d'acquittements, mais ca m'a l'air compliqué à implementé, puisqu'il nous faut les numéros de séquence, hors les sockets en tout cas ceux que j'utilise ne semble pas permettre d'avoir accès à cette information???

Merci, d'avance pour l'aide fournit.

7 réponses

Messages postés
5
Date d'inscription
lundi 28 février 2005
Statut
Membre
Dernière intervention
6 juillet 2008

mmhh dans ton code il y a un bleme...
si la reponse au PASV est (192,168,1,42,13,21), l'adresse IP du socket est bien 192.168.1.42, mais le port n'est pas 1321, c'est 13*256 + 21 soit 3328
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
2
Salut,

Aucun problème, c'est bien comme ça qu'il faut calculer le port (13*256 + 21).
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
2
Salut,

En effet, l'adresse sur laquelle tu dois connecter ton deuxieme socket
est bien le (10,10,1,,1,231). Par contre il semble y avoir un petit
probleme de formatage, ou ptet que quand on ne met pas de chiffre ça
signifie 0, à verifier dans la rfc.

Pour ce qui est des acquittements, il existe plusieurs modes de
transferts mais en général c'est le plus simple qui est utilisé, les
données brutes sont envoyées, sans méchanisme d'accusé de reception
(qui peut sembler inutile vu qu'il est déjà implementé au niveau tcp).
Messages postés
34
Date d'inscription
dimanche 23 novembre 2003
Statut
Membre
Dernière intervention
6 juillet 2008

La je peine un peu parce que quand j'initialise la connection vers l'autre port pour la data ca ne marche pas.Errno me renvoit l'erreur: connect: Connection refused.

Je poste donc mon code tres simple, car c'est juste pour me familiariser avec les sockets.
#include <sys/socket.h>
#include <errno.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>

#define PORTS 21

int indice_port(char tab[100],int nbre)
{
    int nbre_virgule=0;
    int i=0;
    while(1)
    {
        if(i>99){/*printf("\non sort 99\n");*/break;}
        else
        {
                
            if(tab[i]==',')nbre_virgule++;

            if(nbre_virgule==nbre)break;
            /*on sort si on est a la fin de la reponse*/            
            if(tab[i]=='.'){/*printf("\non sort a cause de .\n");*/break;}                
            i++;
            
            
        }
    
    }
    return i+1;

}
int Quelport(char tab[100])
{
    int nbre_virgule=0;
    int taille_port=0;
    char tmp[8];    
    char tmp2[8];    
    int i=0;
    int indice;
    indice=indice_port(tab,4);//pour arriver à la partie port de la reponse
    
    while(1)
    {
        if(i>8)break;
        if(tab[indice]==')')break;        
        tmp[i]=tab[indice];
        i++;
        indice++;
    }
    tmp[i]='\0';
    //ainsi on ne recupere pas la derniere parenthese
    
    /*il faut supprimer la virgule*/
    indice=0;
    i=0;
    while(1)
    {
        if(i>6)break;
        if(tmp[indice]==')')break;        
        if(tmp[indice]!=',')        
        {
            tmp2[i]=tmp[indice];
            i++;       
         }
        indice++;
        
    }
        
    //printf("\nle port dans la fonction vaut %s\n",tmp2);
    return atoi(tmp2);

}
int main(void)
{
    /*les variables*/
    int sock,sock_data;//sock pour le flux commande et sock_data pour le flux data
    int i;
    int taille;//taille des reponses récuperer
    char resp[100];//tableau pour les réponses aux commandes
    char buf[1000];        
    int port; //pour le mode passif
    struct hostent *h;
    struct sockaddr_in dest,dest_data;//dest pour les commande dest_data pour la data
   
    /*Creation d'un socket pour la communication via un flux réseau*/
    if((sock=socket(AF_INET,SOCK_STREAM,0))<0)
    {
        perror("sock");//renvoi du code d'erreur
        return 1;
    }     

    dest.sin_family = AF_INET;//Pour préciser que c'est une communication réseau
    dest.sin_port = htons(PORTS); //Préciser le numéro de port soit le 21 pour les commandes
    h=gethostbyname("ServFTP");//Recuperer l'adresse IP du serveur FTP dans le fichier /etc/hosts
    bcopy(h->h_addr,(struct sockaddr *)&amp;dest.sin_addr,h->h_length);//mettre l'adresse de destination dans la struct sockaddr_in
       
    /*test de connection au serveur*/
    if(connect(sock,(struct sockaddr *)&amp;dest, sizeof(struct sockaddr))<0)
    {
    printf("\nerreur flux commande");
        perror("connect");//renvoi du code d'erreur
        return 2;
    }
    /*transmission du login*/
    write(sock,"USER body\r\n",11);
    taille=read(sock,resp,sizeof(resp));
    for(i=0;i<taille;i++)
    printf("%c",resp[i]);

    /*transmission du mot de passe*/
    write(sock,"PASS passwd\r\n",13);
    taille=read(sock,resp,sizeof(resp));
    for(i=0;i<taille;i++)
    printf("%c",resp[i]);
   
    /*transmettre le type de systeme du client*/
    write(sock,"SYST\r\n",6);
    taille=read(sock,resp,sizeof(resp));
    for(i=0;i<taille;i++)
    printf("%c",resp[i]);
   
    /*Passage en mode passif*/
    write(sock,"PASV\r\n",6);
    taille=read(sock,resp,sizeof(resp));
    for(i=0;i<taille;i++)
    printf("%c",resp[i]);

    taille=read(sock,resp,sizeof(resp));
    for(i=0;i<taille;i++)
    printf("%c",resp[i]);

    /*fonction simple qui permet de recuperer dans la reponse à PASV le numero de port*/
    port=Quelport(resp);
    printf("\nle numero de port apres la fonction est: %d",port);

    
    if((sock_data=socket(AF_INET,SOCK_STREAM,0))<0)//ouverture socket pour la data
    {
        perror("sock");//renvoi du code d'erreur
        return 1;
    }     
  
    dest_data.sin_family = AF_INET;//Pour préciser que c'est une communication réseau
    dest_data.sin_port = htons(port); //Préciser le numéro de port soit le 21 pour envoyer des commandes
    bcopy(h->h_addr,(struct sockaddr *)&amp;dest_data.sin_addr,h->h_length);//mettre l'adresse de destination dans la struct sockaddr_in

 
    if(connect(sock_data,(struct sockaddr *)&amp;dest_data, sizeof(struct sockaddr))<0)//connection au serveur pour la data
    {
    printf("\nerreur flux données");
        perror("connect");//renvoi du code d'erreur
        return 2;
    }
      
    write(sock,"LIST\r\n",6);
    taille=read(sock,resp,sizeof(resp));
    for(i=0;i<taille;i++)
    printf("%c",resp[i]);
    write(sock_data,buf,sizeof(buf));
    printf("\n%s",buf);
}

Donc moi je recupere comme résultat
[root@localhost socket]# ./main
220 TYPSoft FTP Server 1.10 ready...
331 Password required for anek.
230 User anek logged in.
215 UNIX Type: L8
227 Entering Passive Mode (192,168,1,42,13,21).

le numero de port apres la fonction est: 1321
connect: Connection refused


Et sur mon serveur FTP, j'ai coupé le firewall le temps de mes tests.
Parcontre un autre truc bizzare avant que je mette les deux printf("erreur flux ..."), au dessus des perrors j'avais le numéro de port qui s'affichait dans mon printf apres l'erreur renvoyée par errno.
Cependant dans mon code, je lui dit bien d'afficher le numéro de port avant de me donner l'erreur.
En tout cas merci pour le début d'aide je sens que j'avance.
Messages postés
34
Date d'inscription
dimanche 23 novembre 2003
Statut
Membre
Dernière intervention
6 juillet 2008

erf c koi les balises pour le code??
dsl
Messages postés
34
Date d'inscription
dimanche 23 novembre 2003
Statut
Membre
Dernière intervention
6 juillet 2008

Ok merci ca marche nikel.
Juste une autre question quelqu'un sait pourquoi c'est comme ca qu'il faut calculer le numéro de port c'est dans la rfc ou ailleurs?
Encore un grand merci pour l'aide.
Messages postés
1905
Date d'inscription
mercredi 22 janvier 2003
Statut
Membre
Dernière intervention
17 septembre 2012
2
Salut,

C'est dans la RFC oui.