Programme passerelle dans le cadre du projet Prosecco
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

359 lignes
9.6 KiB

  1. /* Notre passerrelle TCP IPv4 */
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <strings.h>
  6. #include <stdint.h>
  7. #include <unistd.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #include <sys/socket.h>
  12. #include <arpa/inet.h>
  13. #include <netdb.h>
  14. #include <signal.h>
  15. #include <sys/wait.h>
  16. #include <pthread.h>
  17. #include "chiffre.h"
  18. #include "pass.h"
  19. /* Variables globales */
  20. static int RUN = 1; // booléen pour la boucle d'acceptation
  21. static int Chiff = 0; // valeur pour l'option de chiffrement, -1 pour local, 1 pour distant, 0 pour rien
  22. static in_port_t PORTL, PORTD; // ports distant et local au format du réseau !
  23. static uint32_t ADDRD; // adresse distante au format réseau
  24. static int SidLoc, SidDist; // variables globales des deux taches de transfert
  25. /* Fonction qui agit en tant que handler pour signal() */
  26. void interrupt(int S)
  27. {
  28. switch (S) {
  29. case SIGCHLD:
  30. while (waitpid(-1, NULL, WNOHANG) != -1);
  31. break;
  32. case SIGINT:
  33. RUN = 0;
  34. exit(EXIT_FAILURE);
  35. break;
  36. case SIGTERM:
  37. fprintf(stderr, "Arret de la passerelle !\n");
  38. exit(0);
  39. break;
  40. default:
  41. fprintf(stderr, "Reçu signal %d !?!\n", S);
  42. break;
  43. }
  44. }
  45. /* Fonction qui traduit une adresse IPv4 en chaîne de caractères xxx.xxx.xxx.xxx */
  46. char *adip(uint32_t A)
  47. {
  48. // 255.255.255.255 par exemple = 15 char + '\0' = 16
  49. static char buffer[16];
  50. sprintf(buffer, "%d.%d.%d.%d",
  51. (int) ((A>>24) & 0xFF),
  52. (int) ((A>>16) & 0xFF),
  53. (int) ((A>>8) & 0xFF),
  54. (int) (A & 0xFF)
  55. );
  56. return buffer;
  57. }
  58. /* Fontion qui fabrique un IPv4 au format réseau */
  59. uint32_t makeip4(int a, int b, int c, int d)
  60. {
  61. // exemple : makeip4(127,0,0,1);
  62. uint32_t addresse;
  63. char *p;
  64. p = (char *) &addresse;
  65. *p++ = (unsigned char) a;
  66. *p++ = (unsigned char) b;
  67. *p++ = (unsigned char) c;
  68. *p = (unsigned char) d;
  69. return addresse;
  70. }
  71. /* Fonction qui lit taille octets à la fois */
  72. int readNbc(int fd, char *buffer, int taille)
  73. {
  74. char *debut;
  75. int n, T = taille;
  76. #ifdef TRACE_SP
  77. printf("readNbc %d octets !\n", taille);
  78. #endif
  79. debut = buffer;
  80. while (T > 0) {
  81. if ((n = read(fd, debut, T)) == -1) return -1;
  82. debut += n;
  83. T -= n;
  84. }
  85. return 0;
  86. }
  87. /* Fonction du thread qui lit le port local et écrit vers le port distant */
  88. void *fct_th(void *p)
  89. {
  90. int n;
  91. uint16_t lb;
  92. char buf[LBUF];
  93. /* On s'occupe du transfert local -> distant */
  94. while (1) {
  95. /* Lecture côté local */
  96. if (Chiff == -1) { // chiffrement côté local
  97. if (read(SidLoc, &lb, sizeof(lb)) != sizeof(lb)) n = -1;
  98. else {
  99. n = (int) ntohs(lb);
  100. if (readNbc(SidLoc, buf, n) == -1) n = -1;
  101. #ifdef XOR_SIMPLE
  102. chiffre_xor_simple(buf, n);
  103. #endif
  104. #ifdef XOR_FICHIER
  105. chiffre_xor_fichier(buf, n);
  106. #endif
  107. #ifdef PLAYFAIR
  108. chiffre_playfair(buf, n);
  109. #endif
  110. }
  111. } else n = read(SidLoc, buf, LBUF);
  112. if (n > 0) {
  113. /* Ecriture côté distant */
  114. if (Chiff == 1) {
  115. #ifdef TRACE_SP
  116. printf("writeNbc %d octets !\n", n);
  117. #endif
  118. #ifdef XOR_SIMPLE
  119. chiffre_xor_simple(buf, n);
  120. #endif
  121. #ifdef XOR_FICHIER
  122. chiffre_xor_fichier(buf, n);
  123. #endif
  124. #ifdef PLAYFAIR
  125. dechiffre_playfair(buf, n);
  126. #endif
  127. lb = htons((uint16_t) n);
  128. write(SidDist, &lb, sizeof(lb)); // On envoie le nombre d'octets du paquet
  129. }
  130. write(SidDist, buf, n);
  131. }
  132. if (n == -1) break;
  133. }
  134. return NULL;
  135. }
  136. /* Création de la passerelle pour le client */
  137. int liaison(int fd)
  138. {
  139. int sid, n;
  140. uint16_t lb;
  141. struct sockaddr_in Sin;
  142. pthread_t thid;
  143. char buf[LBUF];
  144. /* On est dans le cas du client qui veut se connecter au serveur */
  145. /* Fabrication de l'interface réseau en IPv4 */
  146. SidLoc = fd; // pour que le thread l'utilise
  147. if ((sid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  148. perror("socket");
  149. return 1;
  150. }
  151. Sin.sin_family = AF_INET;
  152. Sin.sin_port = PORTD;
  153. Sin.sin_addr.s_addr = ADDRD;
  154. /* On fait la connexion */
  155. if (connect(sid, (struct sockaddr *) &Sin, sizeof(Sin)) == -1) {
  156. perror("connect");
  157. return 2;
  158. }
  159. /* On masque le signal SIGPIPE */
  160. signal(SIGPIPE, SIG_IGN);
  161. /* La connexion est faite ! */
  162. SidDist = sid; // pour que le thread l'utilise
  163. /* Création du thread qui va se charger du transfert local vers distant */
  164. if (pthread_create(&thid, NULL, fct_th, NULL) != 0) {
  165. fprintf(stderr, "Erreur création thread !\n");
  166. close(fd);
  167. close(sid);
  168. return 3;
  169. }
  170. /* On s'occupe du transfert distant -> local */
  171. while (1) {
  172. if (Chiff == 1) { // chiffrement côté distant
  173. if (read(sid, &lb, sizeof(lb)) != sizeof(lb)) n = -1;
  174. else {
  175. n = (int) ntohs(lb);
  176. if (readNbc(sid, buf, n) == -1) n = -1;
  177. #ifdef XOR_SIMPLE
  178. chiffre_xor_simple(buf, n);
  179. #endif
  180. #ifdef XOR_FICHIER
  181. chiffre_xor_fichier(buf, n);
  182. #endif
  183. #ifdef PLAYFAIR
  184. dechiffre_playfair(buf, n);
  185. #endif
  186. }
  187. } else n = read(sid, buf, LBUF);
  188. if (n > 0) {
  189. if (Chiff == -1) {
  190. #ifdef TRACE_SP
  191. printf("writeNbc %d octets !\n", n);
  192. #endif
  193. #ifdef XOR_SIMPLE
  194. chiffre_xor_simple(buf, n);
  195. #endif
  196. #ifdef XOR_FICHIER
  197. chiffre_xor_fichier(buf, n);
  198. #endif
  199. #ifdef PLAYFAIR
  200. chiffre_playfair(buf, n);
  201. #endif
  202. lb = htons((uint16_t) n);
  203. write(fd, &lb, sizeof(lb));
  204. }
  205. write(fd, buf, n);
  206. }
  207. if (n == -1) break;
  208. }
  209. close(fd);
  210. return 0;
  211. }
  212. /* Message d'aide pour l'utilisateur */
  213. void finerr(char *N, int err)
  214. {
  215. fprintf(stderr, "%s : version %s\n", N, Version);
  216. fprintf(stderr, "Utilisation : %s -d|-l|-s port_local nom_ou_ip_serveur port_distant\n", N);
  217. exit(err);
  218. }
  219. int main(int N, char *P[])
  220. {
  221. int sid, new_sid, err; // socket id = file descriptor
  222. struct sockaddr_in Sin, Srec;
  223. struct hostent *host;
  224. pid_t pid;
  225. long lg;
  226. /* Récupération des éventuels signaux qu'on pourrait recevoir, et appel de la fonction interrupt() */
  227. signal(SIGCHLD, interrupt);
  228. signal(SIGINT, interrupt);
  229. signal(SIGTERM, interrupt);
  230. #ifdef XOR_FICHIER
  231. if (init_cle_xor_fichier()) {
  232. fprintf(stderr, "Erreur lecture fichier clé : '%s' !\n", NFCLE);
  233. return 1;
  234. }
  235. #endif
  236. #ifdef PLAYFAIR
  237. init_table_chiffre(CLE_PLAYFAIR);
  238. #endif
  239. /* Vérification que l'on a bien 4 paramètres et seulement 4 */
  240. if (N != 5) finerr(P[0], 1);
  241. /* Vérification du 1er paramètre */
  242. if (P[1][0] != '-') finerr(P[0], 1);
  243. if (strlen(P[1]) != 2) finerr(P[0], 2);
  244. switch (P[1][1]) {
  245. case 'l':
  246. Chiff = -1;
  247. break;
  248. case 'd':
  249. Chiff = 1;
  250. break;
  251. case 's':
  252. Chiff = 0;
  253. break;
  254. default:
  255. finerr(P[0], 2);
  256. break;
  257. }
  258. PORTL = htons(atoi(P[2]));
  259. PORTD = htons(atoi(P[4]));
  260. /* Récuperation de l'adresse */
  261. if ((host = gethostbyname(P[3])) == NULL) {
  262. fprintf(stderr, "Erreur gethostbyname no %d !\n", h_errno);
  263. return 2;
  264. }
  265. bcopy((void*) (host->h_addr), (void*) (&ADDRD), host->h_length);
  266. /* Fabrication de l'interface réseau en IPv4 */
  267. if ((sid = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
  268. perror("socket");
  269. return 5;
  270. }
  271. Sin.sin_family = AF_INET;
  272. Sin.sin_port = PORTL;
  273. Sin.sin_addr.s_addr = makeip4(0, 0, 0, 0);
  274. // Sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  275. /* Puis faire un bind() pour s'attacher à ce port */
  276. /* La fonction bind est une fonction unique, aveugle à la structure qui va envoyer les données. Elle ne se soucie
  277. * pas de savoir si on va communiquer en IPv4 ou IPv6 par exemple.
  278. * La fonction bind prend donc en fait une structure générique, sockaddr. Dans cette structure elle lit sa_family,
  279. * qui lui indique qu'il s'agit d'IPv4. */
  280. /* Pour faire la conversion des struct on fait un cast. */
  281. if (bind(sid, (struct sockaddr *) &Sin, sizeof(Sin)) == -1) {
  282. perror("bind");
  283. return 3;
  284. }
  285. /* On définit le nombre d'écoutes simultanées */
  286. if (listen(sid, NBCLI) == -1) {
  287. perror("listen");
  288. return 4;
  289. }
  290. /* On laisse le serveur accepter des connexions
  291. * A chaque connexion établie, le serveur crée un fils pour gérer celle-ci. */
  292. while (RUN) { // on attend les clients locaux pour transmettre les données
  293. lg = sizeof(Sin);
  294. if ((new_sid = accept(sid, (struct sockaddr *) &Srec, (socklen_t *) &lg)) < 0) {
  295. perror("accept");
  296. } else {
  297. #ifdef TRACE_1
  298. printf("Connexion de %s !\n", adip(ntohl(Srec.sin_addr.s_addr)));
  299. #endif
  300. /* Création d'un processus dédié au client */
  301. if ((pid = fork()) == -1) {
  302. perror("fork");
  303. write(new_sid, "Erreur passerelle !\n", 21);
  304. } else {
  305. if (pid == 0) { // code du fils
  306. err = liaison(new_sid); // Création de la passerelle privée pour le client
  307. if (err) fprintf(stderr, "Erreur liaison %d !\n", err);
  308. return err;
  309. }
  310. }
  311. close(new_sid); // On ferme le file descriptor qu'on vient de créer puisque c'est le fils qui s'en occupe
  312. }
  313. }
  314. return 0;
  315. }