#include "server.h" void DROP_SERVER(const char* serverHost, char** givenPort, int* listenSocket){ if( DEBUGMOD&HDR ) printf("====== DROP_SERVER(%s, %s, %d) ======\n\n", serverHost, *givenPort, *listenSocket); // FONCTIONNEMENT struct addrinfo hints; // contiendra le filtre/format struct addrinfo* addrinfo; // contiendra les infos du serveur int SOCKET, BIND, LISTEN; // file_desc(s) // INFOS struct sockaddr_storage serverInfo; // contiendra les informations du server socklen_t sockaddr_len = sizeof(struct sockaddr_storage); char infoHost[maxHostLen]; // contiendra l'adresse du server char infoPort[maxPortLen]; // contiendra le port du server /* [1] On définit le filtre/format =======================================================*/ memset(&hints, 0, sizeof(struct addrinfo)); // on vide le filtre hints.ai_family = AF_UNSPEC; // Allow IPv4 ou IPv6 hints.ai_socktype = SOCK_STREAM; // TCP (SOCK_DGRAM = UDP) hints.ai_flags = AI_PASSIVE; // mode SERVER hints.ai_protocol = 0; // non spécifié if( DEBUGMOD&SCK ) printf("============HINTS===========\n"); if( DEBUGMOD&SCK ) printf( "AI_FLAGS = %d\n", hints.ai_flags ); // int if( DEBUGMOD&SCK ) printf( "AI_FAMILY = %d\n", hints.ai_family ); // int if( DEBUGMOD&SCK ) printf( "AI_SOCKTYPE = %d\n", hints.ai_socktype ); // int if( DEBUGMOD&SCK ) printf( "AI_PROTOCOL = %d\n", hints.ai_protocol ); // int if( DEBUGMOD&SCK ) printf( "AI_ADDRLEN = %d\n", hints.ai_addrlen ); // int if( DEBUGMOD&SCK ) printf("\n"); /* [2] On récupère les infos =======================================================*/ if( strlen(*givenPort) == 0 ) // si pas défini, port dynamique getaddrinfo(serverHost, 0, &hints, &addrinfo); else // sinon manuel getaddrinfo(serverHost, *givenPort, &hints, &addrinfo); // Remarque: port=0 donc va être défini dynamiquement if( DEBUGMOD&SCK ) printf("=============RES============\n"); if( DEBUGMOD&SCK ) printf( "AI_FLAGS = %d\n", addrinfo->ai_flags ); // int if( DEBUGMOD&SCK ) printf( "AI_FAMILY = %d\n", addrinfo->ai_family ); // int if( DEBUGMOD&SCK ) printf( "AI_SOCKTYPE = %d\n", addrinfo->ai_socktype ); // int if( DEBUGMOD&SCK ) printf( "AI_PROTOCOL = %d\n", addrinfo->ai_protocol ); // int if( DEBUGMOD&SCK ) printf( "AI_ADDRLEN = %d\n", addrinfo->ai_addrlen ); // int if( DEBUGMOD&SCK ) printf("\n"); /* [3] Création de la socket =======================================================*/ SOCKET = socket(addrinfo->ai_family, addrinfo->ai_socktype, 0); if( DEBUGMOD&SCK ) printf("SOCKET = %d\n", SOCKET); // si erreur if( SOCKET == -1 ) return; /* [4] On publie la SOCKET =======================================================*/ BIND = bind( SOCKET, addrinfo->ai_addr, addrinfo->ai_addrlen ); if( DEBUGMOD&SCK ) printf("BIND = %d\n", BIND); // si erreur if( BIND == -1 ) return; /* [5] On récupère les informations du serveur (host/port) =======================================================*/ int getInfo = getsockname(SOCKET, (struct sockaddr *) &serverInfo, &sockaddr_len); if( getInfo == -1 ) return; getInfo = getnameinfo( // on récupère le host et le port (struct sockaddr *) &serverInfo, sizeof(serverInfo), infoHost, maxHostLen, infoPort, maxPortLen, NI_NUMERICHOST | NI_NUMERICSERV ); if( getInfo == -1 ) return; if( DEBUGMOD&SCK ) printf("Server host: %s\n", infoHost); if( DEBUGMOD&SCK ) printf("Server port: %s\n", infoPort); // on a plus besoin des infos de l'adresse freeaddrinfo(addrinfo); /* [6] On met la socket sur écoute =======================================================*/ LISTEN = listen(SOCKET, maxListLen); if( DEBUGMOD&SCK ) printf("LISTEN = %d\n", LISTEN); // si erreur if( LISTEN == -1 ) return; /* [7] On envoie les données par référence =======================================================*/ // port *givenPort = malloc( maxPortLen ); strcpy(*givenPort, infoPort); // socket d'écoute *listenSocket = SOCKET; } int MANAGE_REQUEST(char* pRequest, int* USER_SOCKET, int* FTP_SOCKET, int* DUSER_SOCKET, int* DFTP_SOCKET){ if( DEBUGMOD&HDR ) printf("====== MANAGE_REQUEST(%s, %d, %d, %d, %d) ======\n\n", pRequest, *USER_SOCKET, *FTP_SOCKET, *DUSER_SOCKET, *DFTP_SOCKET); char response[maxBuffLen]; // contiendra la réponse (2*taille buffer pour strcat(BUFLEN, BUFLEN)) int nbSend; // contiendra le nombre de données envoyées char rCommand[5]; // contiendra les commandes (1ère partie) char rContent[maxBuffLen]; // contiendra le contenu associé à la commande (2ème partie) // on vide les buffers memset(&rCommand, '\0', sizeof(rCommand)); memset(&rContent, '\0', sizeof(rContent)); memset(&response, '\0', sizeof(response)); /* [1] On découpe la requête en 2 parties ================================================*/ splitFtpRequest(pRequest, rCommand, rContent); /* [2] Selection en fonction de @rCommand ================================================*/ /* (1) USER username@serveur => connection FTP (commande) --------------------------------------------*/ if( strcmp(rCommand, "USER") == 0 && indexOf(rContent, '@') >= 0 ){ char userName[100] = {0}; char hostName[maxHostLen] = {0}; // pour l'envoi de la séquence d'initialisation char* ftp_response; ftp_response = malloc(maxBuffLen); memset(ftp_response, 0, maxBuffLen); /* 1. On extrait @username et @hostname */ sscanf(rContent, "%[^@]@%s\r\n", userName, hostName); if( DEBUGMOD&BUF ) printf("USERNAME [[%s]]\n", userName); if( DEBUGMOD&BUF ) printf("HOSTNAME [[%s]]\n", hostName); /* 2. On se connecte au serveur FTP (commandes) */ int error = CONNECT_CLIENT(hostName, FTP_PORT, FTP_SOCKET); if( error == -1 || *FTP_SOCKET == -1 ){ // si erreur printf("Impossible de se connecter au serveur (%s:%s)\n", hostName, FTP_PORT); strcpy(pRequest, "421 ERREUR: impossible de se connecter au serveur!!\r\n"); return -1; } if( DEBUGMOD&SCK ) printf("FTP SOCKET CONNECTED AT %s:%s\n", hostName, FTP_PORT); /* 3. On envoie la séquence d'initialisation */ CLIENT_SEND(FTP_SOCKET, "", &ftp_response); if( DEBUGMOD&CMD ) xPrint("P->F: %s\n\n", "\r\n"); if( DEBUGMOD&CMD ) xPrint("F->P: %s\n", ftp_response); /* 4. On envoie la requête USER au serveur FTP auquel on vient de se connecter */ char newRequest[maxBuffLen]; strcat(newRequest, "USER "); strcat(newRequest, userName); strcat(newRequest, "\r\n"); strcpy(response, "USER xdrm\r\n"); } else if( strcmp(rCommand, "USER") == 0 ) // si oubli serveur strcpy(response, "421 'username@FTPserver' attendu\n"); /* (2) PORT a1,a2,a3,a4,p1,p2 => utilisateur (actif) --------------------------------------------*/ else if( strcmp(rCommand, "PORT") == 0 ){ int a1, a2, a3, a4 = 0; int p1, p2 = 0; char serverHost[maxHostLen] = {0}; char serverPort[maxPortLen] = {0}; char BUFFER[maxBuffLen] = {0}; /* 1. On récupère l'ip et le port de la réponse */ sscanf(pRequest, "PORT %d,%d,%d,%d,%d,%d", &a1, &a2, &a3, &a4, &p1, &p2); // on récupère l'adresse en sprintf(serverHost, "%d.%d.%d.%d", a1, a2, a3, a4); // on récupère le port en sprintf(serverPort, "%d", p1*256+p2); /* 2. On se connecte au client */ if( DEBUGMOD&SCK ) printf("CONNECTING TO CLIENT %s:%s\n", serverHost, serverPort); CONNECT_CLIENT(serverHost, serverPort, DUSER_SOCKET); if( DEBUGMOD&SCK ) printf("CONNECTED TO CLIENT %s:%s\n", serverHost, serverPort); /* 3. Envoi de "PASV" car on veut être en mode passif entre le proxy et le serveur FTP */ strcpy(response, "PASV\r\n"); } /* (n) Si aucun traitement on recopie la requête telquel --------------------------------------------*/ else strcpy(response, pRequest); /* [3] Retour de la réponse ================================================*/ strcpy(pRequest, response); printf("RESP: %s\n", pRequest); return 0; } void MANAGE_RESPONSE(char* pAnswer, int* USER_SOCKET, int* FTP_SOCKET, int* DUSER_SOCKET, int* DFTP_SOCKET){ if( DEBUGMOD&HDR ) printf("====== MANAGE_RESPONSE(%s, %d, %d, %d, %d) ======\n\n", pAnswer, *USER_SOCKET, *FTP_SOCKET, *DUSER_SOCKET, *DFTP_SOCKET); char response[maxBuffLen]; // contiendra la réponse char ftpCodeStr[4]; // contiendra le code FTP (1ère partie) char ftpText[maxBuffLen]; // contiendra le texte associé à la commande (2ème partie) int ftpCode; // contiendra le code FTP en numérique // on vide les buffers memset(&ftpCodeStr, '\0', sizeof(ftpCode)); memset(&ftpText, '\0', sizeof(ftpText)); memset(&response, '\0', sizeof(response)); /* [1] On découpe la requête en 2 parties ================================================*/ splitFtpResponse(pAnswer, ftpCodeStr, ftpText); // on met le code FTP en ftpCode = atoi( ftpCodeStr ); // mise à disposition de variables temporaires int tmp[6] = {0}; char serverHost[maxHostLen]; char serverPort[maxPortLen]; char BUFFER[maxBuffLen] = {0}; /* [2] Selection en fonction de @ftpCode ================================================*/ switch(ftpCode){ /* (1) Demande d'username --------------------------------------------*/ case 220: strcpy(response, WLCM_MSG); break; /* (2) username OK -> demande MDP --------------------------------------------*/ case 331: strcpy(response, USER_MSG); break; /* (3) Bon mdp -> connection --------------------------------------------*/ case 230: strcpy(response, PASS_BON_MSG); break; /* (4) Mauvais mdp -> message erreur --------------------------------------------*/ case 530: strcpy(response, PASS_BAD_MSG); break; /* (5) Info SYST --------------------------------------------*/ // case 215: // strcpy(response, "bla\n"); // break; /* (6) LOGOUT => EXIT --------------------------------------------*/ case 221: strcpy(response, EXIT_MSG); break; /* (7) Mode passif => On lance les SOCKETS du BUS DE DONNEES --------------------------------------------*/ case 227: // on lance la SOCKET FTP du BUS DE DONNEES /* 1. On récupère l'ip et le port de la réponse */ sscanf(pAnswer, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]); // on récupère l'adresse en sprintf(serverHost, "%d.%d.%d.%d", tmp[0], tmp[1], tmp[2], tmp[3]); // on récupère le port en sprintf(serverPort, "%d", tmp[4]*256+tmp[5]); /* 2. Connexion au serveur FTP */ if( DEBUGMOD&SCK ) printf("CONNECTING TO FTP %s:%s\n", serverHost, serverPort); CONNECT_CLIENT(serverHost, serverPort, DFTP_SOCKET); if( DEBUGMOD&SCK ) printf("CONNECTED TO FTP %s:%s\n", serverHost, serverPort); /* 3. Envoi du message de code 200 */ strcpy(response, LIST_DAT_MSG); break; /* (8) On lit la SOCKET FTP du BUS DE DONNEES --------------------------------------------*/ case 150: /* 1. Envoi au client de l'écoute de la réponse (associée) du BUS DE DONNEES */ // sread(FTP_SOCKET, BUFFER); // if( DEBUGMOD&CMD ) xPrint("F->P: %s\n", BUFFER); swrite(USER_SOCKET, READ_CON_MSG); if( DEBUGMOD&CMD ) xPrint("P->C: %s\n", READ_CON_MSG); /* 2. On lit la SOCKET FTP (BUS DE DONNEES) */ tmp[0] = WAIT_SOCKET_UPDATE(DFTP_SOCKET, BUFFER); if( DEBUGMOD&DAT && tmp[0] == -1 ) printf("ERROR\n"); else if( DEBUGMOD&DAT ) xPrint("[BUS_IN]: %s\n", BUFFER); /* 3. On redirige sur la SOCKET utilisateur (BUS DE DONNEES) */ tmp[1] = swrite(DUSER_SOCKET, BUFFER); if( DEBUGMOD&DAT && tmp[1] == -1 ) printf("ERROR\n"); else if( DEBUGMOD&DAT ) xPrint("[BUS_OUT]: %s\n", BUFFER); if( DEBUGMOD&DAT ) xPrint("BUS_FTP->BUS_CLIENT: %s\n", BUFFER); /* 4. On ferme les SOCKETS du BUS DE DONNEES */ close(*DFTP_SOCKET); if( DEBUGMOD&CMD ) printf("BUS_FTP fermé (%d)\n", *DFTP_SOCKET); close(*DUSER_SOCKET); if( DEBUGMOD&CMD ) printf("BUS_USER fermé (%d)\n", *DUSER_SOCKET); // on vide les SOCKET FTP des 2 BUS // WAIT_SOCKET_UPDATE(FTP_SOCKET, BUFFER); // command // WAIT_SOCKET_UPDATE(DFTP_SOCKET, BUFFER); // données // printf("") /* 5. On vide le BUS DE COMMANDE du serveur FTP */ /* A. On définit un TIMEOUT (1 sec) */ setSocketTimeout(FTP_SOCKET, 0, 50); /* B. On attends une réponse */ tmp[2] = sread(FTP_SOCKET, BUFFER); /* C. On enlève le TIMEOUT (default) */ setSocketTimeout(FTP_SOCKET, SOCKET_TIMEOUT); /* 6. On transmet le message de fin de la transaction (226) */ strcpy(response, STOP_DAT_MSG); break; /* (9) Fin de transfert de données (fermeture SOCKETS du BUS DE DONNEES) --------------------------------------------*/ case 226: strcpy(response, "226 Fin de la transaction!\r\n"); close(*DUSER_SOCKET); close(*DFTP_SOCKET); break; /* (n) Commande inconnue --------------------------------------------*/ default: strcpy(response, pAnswer); break; } /* [3] Retour de la réponse ================================================*/ strcpy(pAnswer, response); } int WAIT_SOCKET_UPDATE(int* pSocket, char* pBuffer){ memset(pBuffer, 0, maxBuffLen); // on vide le buffer int nbRead = 0; do{ nbRead = sread(pSocket, pBuffer); // si on est déconnecté, on renvoie une erreur if( nbRead == -1 ){ printf("Client déconnecté!\n"); return -1; } }while( pBuffer[nbRead-1] != '\n' && pBuffer[nbRead-2] != '\r' ); // on retourne -1 si erreur, SINON 0 return nbRead; }