Programme passerelle dans le cadre du projet Prosecco
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

359 行
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. }