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.

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