/* notre passerelle TCP IPv4 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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 */ }