|
- /* notre passerelle TCP IPv4 */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.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 <signal.h>
- #include <sys/wait.h>
- #include <netdb.h>
- #include <pthread.h>
-
- #include "pass.h"
- #include "chiffrePF.h"
-
- /* les variables globales */
- int RUN=1; /* Indice qui permet de stopper en le mettant a zero */
- int Chiff=0; /* =0 rien; =1 chiff. distant =-1 chiff. local */
- in_port_t PORTL, PORTD; /* au format du reseau !! */
- uint32_t ADDRD; /* adressse distante au format du reseau */
- long long CLE = 0xABCD1276FA8745EC;
-
-
- void interrupt(int S)
- {
- switch(S) {
- case SIGCHLD :
- while (waitpid(-1,NULL,WNOHANG) != -1);
- break;
- case SIGINT:
- case SIGTERM:
- fprintf(stderr,"Arret de la passerelle !\n");
- exit(0);
- default:
- fprintf(stderr,"Recu signal %d !?!?\n",S);
- }
- return;
- }
-
-
- /* la structure sockaddr_in */
- struct sockaddr_in Sin = { AF_INET }; /* Le reste de egal à 0 !! */
-
- /* fct qui fabrique un IP v4 au format reseau
- exemple : makip4(127,0,0,1); */
- uint32_t makip4(int a, int b, int c, int d)
- {
- uint32_t A;
- char *p;
- p = (char *)&A;
- *p++ = (unsigned char)a;
- *p++ = (unsigned char)b;
- *p++ = (unsigned char)c;
- *p = (unsigned char)d;
- //return htonl(A);
- return A;
- }
-
- /* fct qui traduit une adresse IP V4 en chaine de caractere xxx.xxx.xxx.xxx */
- char * adip(uint32_t A)
- {
- static char b[16];
- sprintf(b,"%d.%d.%d.%d", (int)((A>>24)& 0xFF), (int)((A>>16)& 0xFF), (int)((A>>8)& 0xFF), (int)(A & 0xFF));
- return b;
- }
-
- int readNbc(int fd, char*b, int t)
- {
- char * d;
- int n, T=t;
- #ifdef TRACESP
- printf(" readNbc %d octets !\n",t);
- #endif
- d=b;
- while(T>0) {
- if ((n=read(fd,d,T)) == -1) return -1;
- d+=n;
- T-=n;
- }
- return 0;
- }
-
- int SidLoc, SidDist; /* variables globales des 2 taches de transfert */
-
- /* gestion des cles a partir d'un fichier externe */
- char *NFCLE="/tmp/clepass";
- /* ATTENTION choisir LCLE tel que = 8*n !!! */
- #define LCLE 8192 /* 8 ko => cle de 65536 bits !! */
- char BCLE[LCLE]; /* buffer contenant la cle */
-
- /* fchiffre3 utilise les fonction PF */
- void fchiffre3(char * b, int l, int ori)
- {
- if (ori) PF_chiffreD(b,l);
- else PF_dechiffreD(b,l);
- }
-
- /* on suppose dans tout le code que la fct de chiffrement est telle que
- fchiffre(fchiffre(buf)) = buf !! autrement dit qu'elle est involutive ! */
- void fchiffre2(char * b, int l, int ori) /* travaille avec BCLE */
- {
- long long *d, *f, *c, *fc;
- d=(long long*)b;
- f=(long long*)(b+l);
- c=(long long *)BCLE;
- fc=(long long *)(BCLE+LCLE);
- /* le chiffrement avec xor */
- while (d<f) {
- *d++ ^= *c++; /* equiv. *d ^= *c; d++; c++; */
- if (c==fc) c=(long long *)BCLE;
- }
- return; /* pour l'instant ne fait rien !! */
- }
-
- int initCle(void)
- {
- PF_init("Salut");
- /* si on utilise fchiffre2() !!
- int fd;
- if ((fd = open(NFCLE,O_RDONLY)) == -1) return -1;
- if (read(fd,BCLE, LCLE) != LCLE) return -1;
- close(fd);
- *******************/
- return 0;
- }
-
- void fchiffre(char * b, int l, int ori) /* travaille avec CLE de 64 bits */
- {
- long long *d, *f;
- d=(long long*)b;
- f=(long long*)(b+l);
- /* le chiffrement avec xor */
- while (d<f) *d++ ^= CLE;
- #ifdef TRACECH
- if (ori==0) { /* le thread L -> D */
- if (Chiff==1) printf("Chiffrement l=%d vers %d !\n",l,ntohs(PORTD));
- else printf("Dechiffrement l=%d depuis %d !\n",l,ntohs(PORTL));
- } else { /* le fils D -> L */
- if (Chiff==1) printf("Dechiffrement l=%d depuis %d !\n",l,ntohs(PORTD));
- else printf("Chiffrement l=%d vers %d !\n",l,ntohs(PORTL));
- }
- #endif
- return; /* pour l'instant ne fait rien !! */
- }
-
- /* la fonction du thread qui lit le port local et ecrit vers le port distant */
- void * fct_th(void * p)
- {
- int n;
- uint16_t lb;
- char buf[LBUF];
- /* on s'occupe du transfert L -> D */
- while (1) {
- /* lecture cote LOCAL */
- if (Chiff == -1) { /* chiffrement cote local */
- if (read(SidLoc,&lb,2)!=2) n=-1;
- else {
- n = (int)ntohs(lb);
- if (readNbc(SidLoc,buf,n) == -1) n=-1;
- /* on pourrait faire varier le chiffrement dans le code en faisant :
- #ifdef CHIF_V1
- fchiffre(buf,n,0);
- #endif
- #ifdef CHIF_V2
- fchiffre2(buf,n,0);
- #endif
- etc .... *************************************************/
- /* on dechiffre */
- fchiffre3(buf,n,0);
- }
- } else
- n=read(SidLoc,buf,LBUF);
- if (n > 0) {
- /* ecriture cote DISTANT */
- if (Chiff == 1) {
- #ifdef TRACESP
- printf(" writeNbc %d octets !\n",n);
- #endif
- /* on chiffre */
- fchiffre3(buf,n,1);
- lb = htons((uint16_t)n);
- write(SidDist,&lb,2); /* on envoie le nb d'octets du paquet */
- }
- write(SidDist,buf,n);
- }
- if (n==-1) break;
- }
- return NULL;
- }
-
-
- int liaison(int fd) /* il faut creer la passerelle pour le client */
- {
- int sid,n ;
- uint16_t lb;
- struct sockaddr_in Sin = { AF_INET };
- pthread_t thid;
- char buf[LBUF];
- /* on est dans le cas du client qui veut se connecter au serveur */
- /* fabrication de l'interface reseau en IP V4 */
- SidLoc = fd; /* pour que le thread l'utilise */
- if ((sid = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
- perror("socket"); return 1;
- }
- Sin.sin_port = PORTD;
- Sin.sin_addr.s_addr = ADDRD;
- /* on fait la connexion */
- if (connect(sid, (struct sockaddr*)&Sin, sizeof(Sin)) < 0) {
- 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 */
- /* creation du thread qui va se charger du transfert L -> D */
- if (pthread_create(&thid,NULL,fct_th,NULL) !=0) {
- fprintf(stderr,"Erreur creation thread !\n");
- close(fd);
- close(sid);
- return 3;
- }
- /* on s'occupe du transfert D -> L */
- while (1) {
- if (Chiff == 1) { /* chiffrement cote distant */
- if (read(sid,&lb,2)!=2) n=-1;
- else {
- n = (int)ntohs(lb);
- if (readNbc(sid,buf,n) == -1) n=-1;
- /* on dechiffre */
- fchiffre3(buf,n,0);
- }
- } else n=read(sid,buf,LBUF);
- if (n > 0) {
- if (Chiff==-1) {
- #ifdef TRACESP
- printf(" writeNbc %d octets !\n",n);
- #endif
- /* on chiffre */
- fchiffre3(buf,n,1);
- lb = htons((uint16_t)n);
- write(fd,&lb,2); /* on envoie le nb d'octets du paquet */
- }
- write(fd,buf,n);
- }
- if (n==-1) break;
- }
- close(fd);
- return 0;
- }
-
- 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, newsid, err; /* socket id = file descriptor */
- struct sockaddr_in Srec;
- struct hostent *h;
- pid_t pid;
- long lg;
-
- signal(SIGCHLD,interrupt);
- signal(SIGINT,interrupt);
- signal(SIGTERM,interrupt);
- if (initCle()) {
- fprintf(stderr,"Erreur lecture ficher cle %s !!\n", NFCLE);
- return 1;
- }
- /* verification que l'on a bien 4 parametres et seult 4 ! */
- if (N != 5) finerr(P[0],1);
- /* verification du 1er parametres */
- if (P[1][0] != '-') finerr(P[0],2);
- 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);
- }
- PORTL = htons(atoi(P[2]));
- PORTD = htons(atoi(P[4]));
- if ((h=gethostbyname(P[3])) == NULL) {
- fprintf(stderr,"Erreur gethostbyname no %d !\n",h_errno);
- return 2;
- }
- bcopy((void*)(h->h_addr),(void*)(&ADDRD),h->h_length);
-
- /* fabrication de l'interface reseau en IP V4 */
- if ((sid = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
- perror("socket"); return 5;
- }
- /* initialiser la structure sockaddr_in pour dire quel port on veut */
- Sin.sin_port = PORTL;
- /* Sin.sin_addr.s_addr = makip4(127,0,0,1); */
- Sin.sin_addr.s_addr = makip4(0,0,0,0);
- /* puis faire un bind() pour s'attacher a ce port */
- if (bind(sid,(struct sockaddr *)&Sin,sizeof(Sin)) == -1) {
- perror("bind"); return 3;
- }
-
- /* on definit le nombre d'ecoutes simultannees */
- if (listen(sid, NBCLI) == -1) {
- perror("listen"); return 4;
- }
- while(RUN) { /* on attend le clients locaux pour transmettre les donnees */
- lg = sizeof(Sin);
- if ((newsid=accept(sid,(struct sockaddr *)&Srec, (socklen_t*)&lg))<0){
- perror("accept");
- } else {
- /* message pour informer qui se connecte */
- #ifdef TRACE_1
- printf("Connexion de %s !\n",adip(ntohl(Srec.sin_addr.s_addr)));
- #endif
- /* creation du processus dedie au client */
- if ((pid = fork()) == -1) {
- perror("fork");
- write(newsid,"Erreur passerelle !\n",18);
- } else {
- if (pid==0) { /* code du fils */
- err=liaison(newsid);/* creation passerelle privee pour client */
- if (err) printf("Erreur liaison %d !\n",err);
- return err;
- }
- /* suite du pere : ie passerelle principale */
- }
- close(newsid);
- }
- }
- return 0; /* fin OK */
- }
|