|
@@ -0,0 +1,323 @@ |
|
|
|
|
|
/* 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" |
|
|
|
|
|
|
|
|
|
|
|
/* 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 */ |
|
|
|
|
|
|
|
|
|
|
|
/* 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) |
|
|
|
|
|
{ |
|
|
|
|
|
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; |
|
|
|
|
|
fchiffre2(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 |
|
|
|
|
|
fchiffre2(buf,n,0); |
|
|
|
|
|
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; |
|
|
|
|
|
fchiffre2(buf,n,0); |
|
|
|
|
|
} |
|
|
|
|
|
} else n=read(sid,buf,LBUF); |
|
|
|
|
|
if (n > 0) { |
|
|
|
|
|
if (Chiff==-1) { |
|
|
|
|
|
#ifdef TRACESP |
|
|
|
|
|
printf(" writeNbc %d octets !\n",n); |
|
|
|
|
|
#endif |
|
|
|
|
|
fchiffre2(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 */ |
|
|
|
|
|
} |
|
|
|
|
|
|