|
- /* Notre passerrelle TCP IPv4 */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <signal.h>
- #include <sys/wait.h>
- #include <pthread.h>
-
- #include "chiffre.h"
- #include "pass.h"
-
- /* Variables globales */
-
- static int RUN = 1; // booléen pour la boucle d'acceptation
- static int Chiff = 0; // valeur pour l'option de chiffrement, -1 pour local, 1 pour distant, 0 pour rien
- static in_port_t PORTL, PORTD; // ports distant et local au format du réseau !
- static uint32_t ADDRD; // adresse distante au format réseau
- static int SidLoc, SidDist; // variables globales des deux taches de transfert
-
-
- /* Fonction qui agit en tant que handler pour signal() */
- void interrupt(int S)
- {
- switch (S) {
- case SIGCHLD:
- while (waitpid(-1, NULL, WNOHANG) != -1);
- break;
- case SIGINT:
- RUN = 0;
- exit(EXIT_FAILURE);
- break;
- case SIGTERM:
- fprintf(stderr, "Arret de la passerelle !\n");
- exit(0);
- break;
- default:
- fprintf(stderr, "Reçu signal %d !?!\n", S);
- break;
- }
- }
-
- /* Fonction qui traduit une adresse IPv4 en chaîne de caractères xxx.xxx.xxx.xxx */
- char *adip(uint32_t A)
- {
- // 255.255.255.255 par exemple = 15 char + '\0' = 16
- static char buffer[16];
-
- sprintf(buffer, "%d.%d.%d.%d",
- (int) ((A>>24) & 0xFF),
- (int) ((A>>16) & 0xFF),
- (int) ((A>>8) & 0xFF),
- (int) (A & 0xFF)
- );
-
- return buffer;
- }
-
- /* Fontion qui fabrique un IPv4 au format réseau */
- uint32_t makeip4(int a, int b, int c, int d)
- {
- // exemple : makeip4(127,0,0,1);
- uint32_t addresse;
- char *p;
- p = (char *) &addresse;
- *p++ = (unsigned char) a;
- *p++ = (unsigned char) b;
- *p++ = (unsigned char) c;
- *p = (unsigned char) d;
-
- return addresse;
- }
-
- /* Fonction qui lit taille octets à la fois */
- int readNbc(int fd, char *buffer, int taille)
- {
- char *debut;
- int n, T = taille;
-
- #ifdef TRACE_SP
- printf("readNbc %d octets !\n", taille);
- #endif
-
- debut = buffer;
- while (T > 0) {
- if ((n = read(fd, debut, T)) == -1) return -1;
- debut += n;
- T -= n;
- }
- return 0;
- }
-
- /* Fonction du thread qui lit le port local et écrit vers le port distant */
- void *fct_th(void *p)
- {
- int n;
- uint16_t lb;
- char buf[LBUF];
-
- /* On s'occupe du transfert local -> distant */
- while (1) {
- /* Lecture côté local */
- if (Chiff == -1) { // chiffrement côté local
- if (read(SidLoc, &lb, sizeof(lb)) != sizeof(lb)) n = -1;
- else {
- n = (int) ntohs(lb);
- if (readNbc(SidLoc, buf, n) == -1) n = -1;
- #ifdef XOR_SIMPLE
- chiffre_xor_simple(buf, n);
- #endif
- #ifdef XOR_FICHIER
- chiffre_xor_fichier(buf, n);
- #endif
- #ifdef PLAYFAIR
- chiffre_playfair(buf, n);
- #endif
- }
- } else n = read(SidLoc, buf, LBUF);
- if (n > 0) {
- /* Ecriture côté distant */
- if (Chiff == 1) {
- #ifdef TRACE_SP
- printf("writeNbc %d octets !\n", n);
- #endif
- #ifdef XOR_SIMPLE
- chiffre_xor_simple(buf, n);
- #endif
- #ifdef XOR_FICHIER
- chiffre_xor_fichier(buf, n);
- #endif
- #ifdef PLAYFAIR
- dechiffre_playfair(buf, n);
- #endif
- lb = htons((uint16_t) n);
- write(SidDist, &lb, sizeof(lb)); // On envoie le nombre d'octets du paquet
- }
- write(SidDist, buf, n);
- }
- if (n == -1) break;
- }
-
- return NULL;
- }
-
- /* Création de la passerelle pour le client */
- int liaison(int fd)
- {
- int sid, n;
- uint16_t lb;
- struct sockaddr_in Sin;
- pthread_t thid;
- char buf[LBUF];
-
- /* On est dans le cas du client qui veut se connecter au serveur */
-
- /* Fabrication de l'interface réseau en IPv4 */
- SidLoc = fd; // pour que le thread l'utilise
- if ((sid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
- perror("socket");
- return 1;
- }
-
- Sin.sin_family = AF_INET;
- Sin.sin_port = PORTD;
- Sin.sin_addr.s_addr = ADDRD;
-
- /* On fait la connexion */
- if (connect(sid, (struct sockaddr *) &Sin, sizeof(Sin)) == -1) {
- perror("connect");
- return 2;
- }
-
- /* On masque le signal SIGPIPE */
- signal(SIGPIPE, SIG_IGN);
-
- /* La connexion est faite ! */
- SidDist = sid; // pour que le thread l'utilise
-
- /* Création du thread qui va se charger du transfert local vers distant */
- if (pthread_create(&thid, NULL, fct_th, NULL) != 0) {
- fprintf(stderr, "Erreur création thread !\n");
- close(fd);
- close(sid);
- return 3;
- }
-
- /* On s'occupe du transfert distant -> local */
- while (1) {
- if (Chiff == 1) { // chiffrement côté distant
- if (read(sid, &lb, sizeof(lb)) != sizeof(lb)) n = -1;
- else {
- n = (int) ntohs(lb);
- if (readNbc(sid, buf, n) == -1) n = -1;
- #ifdef XOR_SIMPLE
- chiffre_xor_simple(buf, n);
- #endif
- #ifdef XOR_FICHIER
- chiffre_xor_fichier(buf, n);
- #endif
- #ifdef PLAYFAIR
- dechiffre_playfair(buf, n);
- #endif
- }
- } else n = read(sid, buf, LBUF);
- if (n > 0) {
- if (Chiff == -1) {
- #ifdef TRACE_SP
- printf("writeNbc %d octets !\n", n);
- #endif
- #ifdef XOR_SIMPLE
- chiffre_xor_simple(buf, n);
- #endif
- #ifdef XOR_FICHIER
- chiffre_xor_fichier(buf, n);
- #endif
- #ifdef PLAYFAIR
- chiffre_playfair(buf, n);
- #endif
- lb = htons((uint16_t) n);
- write(fd, &lb, sizeof(lb));
- }
- write(fd, buf, n);
- }
- if (n == -1) break;
- }
-
- close(fd);
-
- return 0;
- }
-
- /* Message d'aide pour l'utilisateur */
- void finerr(char *N, int err)
- {
- fprintf(stderr, "%s : version %s\n", N, Version);
- fprintf(stderr, "Utilisation : %s -d|-l|-s port_local nom_ou_ip_serveur port_distant\n", N);
- exit(err);
- }
-
- int main(int N, char *P[])
- {
- int sid, new_sid, err; // socket id = file descriptor
- struct sockaddr_in Sin, Srec;
- struct hostent *host;
- pid_t pid;
- long lg;
-
- /* Récupération des éventuels signaux qu'on pourrait recevoir, et appel de la fonction interrupt() */
- signal(SIGCHLD, interrupt);
- signal(SIGINT, interrupt);
- signal(SIGTERM, interrupt);
-
- #ifdef XOR_FICHIER
- if (init_cle_xor_fichier()) {
- fprintf(stderr, "Erreur lecture fichier clé : '%s' !\n", NFCLE);
- return 1;
- }
- #endif
- #ifdef PLAYFAIR
- init_table_chiffre(CLE_PLAYFAIR);
- #endif
-
- /* Vérification que l'on a bien 4 paramètres et seulement 4 */
- if (N != 5) finerr(P[0], 1);
-
- /* Vérification du 1er paramètre */
- if (P[1][0] != '-') finerr(P[0], 1);
- if (strlen(P[1]) != 2) finerr(P[0], 2);
- switch (P[1][1]) {
- case 'l':
- Chiff = -1;
- break;
- case 'd':
- Chiff = 1;
- break;
- case 's':
- Chiff = 0;
- break;
- default:
- finerr(P[0], 2);
- break;
- }
-
- PORTL = htons(atoi(P[2]));
- PORTD = htons(atoi(P[4]));
-
- /* Récuperation de l'adresse */
- if ((host = gethostbyname(P[3])) == NULL) {
- fprintf(stderr, "Erreur gethostbyname no %d !\n", h_errno);
- return 2;
- }
- bcopy((void*) (host->h_addr), (void*) (&ADDRD), host->h_length);
-
- /* Fabrication de l'interface réseau en IPv4 */
- if ((sid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
- perror("socket");
- return 5;
- }
-
- Sin.sin_family = AF_INET;
- Sin.sin_port = PORTL;
- Sin.sin_addr.s_addr = makeip4(0, 0, 0, 0);
- // Sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- /* Puis faire un bind() pour s'attacher à ce port */
- /* La fonction bind est une fonction unique, aveugle à la structure qui va envoyer les données. Elle ne se soucie
- * pas de savoir si on va communiquer en IPv4 ou IPv6 par exemple.
- * La fonction bind prend donc en fait une structure générique, sockaddr. Dans cette structure elle lit sa_family,
- * qui lui indique qu'il s'agit d'IPv4. */
- /* Pour faire la conversion des struct on fait un cast. */
- if (bind(sid, (struct sockaddr *) &Sin, sizeof(Sin)) == -1) {
- perror("bind");
- return 3;
- }
-
- /* On définit le nombre d'écoutes simultanées */
- if (listen(sid, NBCLI) == -1) {
- perror("listen");
- return 4;
- }
-
- /* On laisse le serveur accepter des connexions
- * A chaque connexion établie, le serveur crée un fils pour gérer celle-ci. */
- while (RUN) { // on attend les clients locaux pour transmettre les données
- lg = sizeof(Sin);
- if ((new_sid = accept(sid, (struct sockaddr *) &Srec, (socklen_t *) &lg)) < 0) {
- perror("accept");
- } else {
- #ifdef TRACE_1
- printf("Connexion de %s !\n", adip(ntohl(Srec.sin_addr.s_addr)));
- #endif
-
- /* Création d'un processus dédié au client */
- if ((pid = fork()) == -1) {
- perror("fork");
- write(new_sid, "Erreur passerelle !\n", 21);
- } else {
- if (pid == 0) { // code du fils
- err = liaison(new_sid); // Création de la passerelle privée pour le client
- if (err) fprintf(stderr, "Erreur liaison %d !\n", err);
- return err;
- }
- }
- close(new_sid); // On ferme le file descriptor qu'on vient de créer puisque c'est le fils qui s'en occupe
- }
- }
-
- return 0;
- }
|