Programme passerelle dans le cadre du projet Prosecco
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

347 lines
9.4 KiB

  1. /* notre passerelle TCP IPv4 */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdint.h>
  6. #include <unistd.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <fcntl.h>
  10. #include <sys/socket.h>
  11. #include <arpa/inet.h>
  12. #include <signal.h>
  13. #include <sys/wait.h>
  14. #include <netdb.h>
  15. #include <pthread.h>
  16. #include "pass.h"
  17. #include "chiffrePF.h"
  18. /* les variables globales */
  19. int RUN=1; /* Indice qui permet de stopper en le mettant a zero */
  20. int Chiff=0; /* =0 rien; =1 chiff. distant =-1 chiff. local */
  21. in_port_t PORTL, PORTD; /* au format du reseau !! */
  22. uint32_t ADDRD; /* adressse distante au format du reseau */
  23. long long CLE = 0xABCD1276FA8745EC;
  24. void interrupt(int S)
  25. {
  26. switch(S) {
  27. case SIGCHLD :
  28. while (waitpid(-1,NULL,WNOHANG) != -1);
  29. break;
  30. case SIGINT:
  31. case SIGTERM:
  32. fprintf(stderr,"Arret de la passerelle !\n");
  33. exit(0);
  34. default:
  35. fprintf(stderr,"Recu signal %d !?!?\n",S);
  36. }
  37. return;
  38. }
  39. /* la structure sockaddr_in */
  40. struct sockaddr_in Sin = { AF_INET }; /* Le reste de egal à 0 !! */
  41. /* fct qui fabrique un IP v4 au format reseau
  42. exemple : makip4(127,0,0,1); */
  43. uint32_t makip4(int a, int b, int c, int d)
  44. {
  45. uint32_t A;
  46. char *p;
  47. p = (char *)&A;
  48. *p++ = (unsigned char)a;
  49. *p++ = (unsigned char)b;
  50. *p++ = (unsigned char)c;
  51. *p = (unsigned char)d;
  52. //return htonl(A);
  53. return A;
  54. }
  55. /* fct qui traduit une adresse IP V4 en chaine de caractere xxx.xxx.xxx.xxx */
  56. char * adip(uint32_t A)
  57. {
  58. static char b[16];
  59. sprintf(b,"%d.%d.%d.%d", (int)((A>>24)& 0xFF), (int)((A>>16)& 0xFF), (int)((A>>8)& 0xFF), (int)(A & 0xFF));
  60. return b;
  61. }
  62. int readNbc(int fd, char*b, int t)
  63. {
  64. char * d;
  65. int n, T=t;
  66. #ifdef TRACESP
  67. printf(" readNbc %d octets !\n",t);
  68. #endif
  69. d=b;
  70. while(T>0) {
  71. if ((n=read(fd,d,T)) == -1) return -1;
  72. d+=n;
  73. T-=n;
  74. }
  75. return 0;
  76. }
  77. int SidLoc, SidDist; /* variables globales des 2 taches de transfert */
  78. /* gestion des cles a partir d'un fichier externe */
  79. char *NFCLE="/tmp/clepass";
  80. /* ATTENTION choisir LCLE tel que = 8*n !!! */
  81. #define LCLE 8192 /* 8 ko => cle de 65536 bits !! */
  82. char BCLE[LCLE]; /* buffer contenant la cle */
  83. /* fchiffre3 utilise les fonction PF */
  84. void fchiffre3(char * b, int l, int ori)
  85. {
  86. if (ori) PF_chiffreD(b,l);
  87. else PF_dechiffreD(b,l);
  88. }
  89. /* on suppose dans tout le code que la fct de chiffrement est telle que
  90. fchiffre(fchiffre(buf)) = buf !! autrement dit qu'elle est involutive ! */
  91. void fchiffre2(char * b, int l, int ori) /* travaille avec BCLE */
  92. {
  93. long long *d, *f, *c, *fc;
  94. d=(long long*)b;
  95. f=(long long*)(b+l);
  96. c=(long long *)BCLE;
  97. fc=(long long *)(BCLE+LCLE);
  98. /* le chiffrement avec xor */
  99. while (d<f) {
  100. *d++ ^= *c++; /* equiv. *d ^= *c; d++; c++; */
  101. if (c==fc) c=(long long *)BCLE;
  102. }
  103. return; /* pour l'instant ne fait rien !! */
  104. }
  105. int initCle(void)
  106. {
  107. PF_init("Salut");
  108. /* si on utilise fchiffre2() !!
  109. int fd;
  110. if ((fd = open(NFCLE,O_RDONLY)) == -1) return -1;
  111. if (read(fd,BCLE, LCLE) != LCLE) return -1;
  112. close(fd);
  113. *******************/
  114. return 0;
  115. }
  116. void fchiffre(char * b, int l, int ori) /* travaille avec CLE de 64 bits */
  117. {
  118. long long *d, *f;
  119. d=(long long*)b;
  120. f=(long long*)(b+l);
  121. /* le chiffrement avec xor */
  122. while (d<f) *d++ ^= CLE;
  123. #ifdef TRACECH
  124. if (ori==0) { /* le thread L -> D */
  125. if (Chiff==1) printf("Chiffrement l=%d vers %d !\n",l,ntohs(PORTD));
  126. else printf("Dechiffrement l=%d depuis %d !\n",l,ntohs(PORTL));
  127. } else { /* le fils D -> L */
  128. if (Chiff==1) printf("Dechiffrement l=%d depuis %d !\n",l,ntohs(PORTD));
  129. else printf("Chiffrement l=%d vers %d !\n",l,ntohs(PORTL));
  130. }
  131. #endif
  132. return; /* pour l'instant ne fait rien !! */
  133. }
  134. /* la fonction du thread qui lit le port local et ecrit vers le port distant */
  135. void * fct_th(void * p)
  136. {
  137. int n;
  138. uint16_t lb;
  139. char buf[LBUF];
  140. /* on s'occupe du transfert L -> D */
  141. while (1) {
  142. /* lecture cote LOCAL */
  143. if (Chiff == -1) { /* chiffrement cote local */
  144. if (read(SidLoc,&lb,2)!=2) n=-1;
  145. else {
  146. n = (int)ntohs(lb);
  147. if (readNbc(SidLoc,buf,n) == -1) n=-1;
  148. /* on pourrait faire varier le chiffrement dans le code en faisant :
  149. #ifdef CHIF_V1
  150. fchiffre(buf,n,0);
  151. #endif
  152. #ifdef CHIF_V2
  153. fchiffre2(buf,n,0);
  154. #endif
  155. etc .... *************************************************/
  156. /* on dechiffre */
  157. fchiffre3(buf,n,0);
  158. }
  159. } else
  160. n=read(SidLoc,buf,LBUF);
  161. if (n > 0) {
  162. /* ecriture cote DISTANT */
  163. if (Chiff == 1) {
  164. #ifdef TRACESP
  165. printf(" writeNbc %d octets !\n",n);
  166. #endif
  167. /* on chiffre */
  168. fchiffre3(buf,n,1);
  169. lb = htons((uint16_t)n);
  170. write(SidDist,&lb,2); /* on envoie le nb d'octets du paquet */
  171. }
  172. write(SidDist,buf,n);
  173. }
  174. if (n==-1) break;
  175. }
  176. return NULL;
  177. }
  178. int liaison(int fd) /* il faut creer la passerelle pour le client */
  179. {
  180. int sid,n ;
  181. uint16_t lb;
  182. struct sockaddr_in Sin = { AF_INET };
  183. pthread_t thid;
  184. char buf[LBUF];
  185. /* on est dans le cas du client qui veut se connecter au serveur */
  186. /* fabrication de l'interface reseau en IP V4 */
  187. SidLoc = fd; /* pour que le thread l'utilise */
  188. if ((sid = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
  189. perror("socket"); return 1;
  190. }
  191. Sin.sin_port = PORTD;
  192. Sin.sin_addr.s_addr = ADDRD;
  193. /* on fait la connexion */
  194. if (connect(sid, (struct sockaddr*)&Sin, sizeof(Sin)) < 0) {
  195. perror("connect"); return 2;
  196. }
  197. /* on masque le signal SIGPIPE */
  198. signal(SIGPIPE,SIG_IGN);
  199. /* la connexion est faite ! */
  200. SidDist = sid; /* pour que le thread l'utilise */
  201. /* creation du thread qui va se charger du transfert L -> D */
  202. if (pthread_create(&thid,NULL,fct_th,NULL) !=0) {
  203. fprintf(stderr,"Erreur creation thread !\n");
  204. close(fd);
  205. close(sid);
  206. return 3;
  207. }
  208. /* on s'occupe du transfert D -> L */
  209. while (1) {
  210. if (Chiff == 1) { /* chiffrement cote distant */
  211. if (read(sid,&lb,2)!=2) n=-1;
  212. else {
  213. n = (int)ntohs(lb);
  214. if (readNbc(sid,buf,n) == -1) n=-1;
  215. /* on dechiffre */
  216. fchiffre3(buf,n,0);
  217. }
  218. } else n=read(sid,buf,LBUF);
  219. if (n > 0) {
  220. if (Chiff==-1) {
  221. #ifdef TRACESP
  222. printf(" writeNbc %d octets !\n",n);
  223. #endif
  224. /* on chiffre */
  225. fchiffre3(buf,n,1);
  226. lb = htons((uint16_t)n);
  227. write(fd,&lb,2); /* on envoie le nb d'octets du paquet */
  228. }
  229. write(fd,buf,n);
  230. }
  231. if (n==-1) break;
  232. }
  233. close(fd);
  234. return 0;
  235. }
  236. void finerr(char * N, int err)
  237. {
  238. fprintf(stderr,"%s : version %s\n",N,Version);
  239. fprintf(stderr,"Utilisation : %s -d|-l|-s port_local nom_ou_ip_serveur port_distant !\n",N);
  240. exit(err);
  241. }
  242. int main(int N, char *P[])
  243. {
  244. int sid, newsid, err; /* socket id = file descriptor */
  245. struct sockaddr_in Srec;
  246. struct hostent *h;
  247. pid_t pid;
  248. long lg;
  249. signal(SIGCHLD,interrupt);
  250. signal(SIGINT,interrupt);
  251. signal(SIGTERM,interrupt);
  252. if (initCle()) {
  253. fprintf(stderr,"Erreur lecture ficher cle %s !!\n", NFCLE);
  254. return 1;
  255. }
  256. /* verification que l'on a bien 4 parametres et seult 4 ! */
  257. if (N != 5) finerr(P[0],1);
  258. /* verification du 1er parametres */
  259. if (P[1][0] != '-') finerr(P[0],2);
  260. if (strlen(P[1]) != 2) finerr(P[0],2);
  261. switch(P[1][1]) {
  262. case 'l':
  263. Chiff = -1;
  264. break;
  265. case 'd':
  266. Chiff = 1;
  267. break;
  268. case 's':
  269. Chiff = 0;
  270. break;
  271. default :
  272. finerr(P[0],2);
  273. }
  274. PORTL = htons(atoi(P[2]));
  275. PORTD = htons(atoi(P[4]));
  276. if ((h=gethostbyname(P[3])) == NULL) {
  277. fprintf(stderr,"Erreur gethostbyname no %d !\n",h_errno);
  278. return 2;
  279. }
  280. bcopy((void*)(h->h_addr),(void*)(&ADDRD),h->h_length);
  281. /* fabrication de l'interface reseau en IP V4 */
  282. if ((sid = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
  283. perror("socket"); return 5;
  284. }
  285. /* initialiser la structure sockaddr_in pour dire quel port on veut */
  286. Sin.sin_port = PORTL;
  287. /* Sin.sin_addr.s_addr = makip4(127,0,0,1); */
  288. Sin.sin_addr.s_addr = makip4(0,0,0,0);
  289. /* puis faire un bind() pour s'attacher a ce port */
  290. if (bind(sid,(struct sockaddr *)&Sin,sizeof(Sin)) == -1) {
  291. perror("bind"); return 3;
  292. }
  293. /* on definit le nombre d'ecoutes simultannees */
  294. if (listen(sid, NBCLI) == -1) {
  295. perror("listen"); return 4;
  296. }
  297. while(RUN) { /* on attend le clients locaux pour transmettre les donnees */
  298. lg = sizeof(Sin);
  299. if ((newsid=accept(sid,(struct sockaddr *)&Srec, (socklen_t*)&lg))<0){
  300. perror("accept");
  301. } else {
  302. /* message pour informer qui se connecte */
  303. #ifdef TRACE_1
  304. printf("Connexion de %s !\n",adip(ntohl(Srec.sin_addr.s_addr)));
  305. #endif
  306. /* creation du processus dedie au client */
  307. if ((pid = fork()) == -1) {
  308. perror("fork");
  309. write(newsid,"Erreur passerelle !\n",18);
  310. } else {
  311. if (pid==0) { /* code du fils */
  312. err=liaison(newsid);/* creation passerelle privee pour client */
  313. if (err) printf("Erreur liaison %d !\n",err);
  314. return err;
  315. }
  316. /* suite du pere : ie passerelle principale */
  317. }
  318. close(newsid);
  319. }
  320. }
  321. return 0; /* fin OK */
  322. }