PSR SE2a4 2022/2023 G2 : Différence entre versions
(→A faire (concernant les serveurs SMTP)) |
(→A faire (concernant les serveurs SMTP)) |
||
Ligne 1 : | Ligne 1 : | ||
− | == A faire | + | == A faire == |
*un système doit être réalisé permettant au serveur SMTP sortant de mettre en file d’attente les messages non remis à destination pour cause d’erreur transitoire du serveur SMTP cible;<br> | *un système doit être réalisé permettant au serveur SMTP sortant de mettre en file d’attente les messages non remis à destination pour cause d’erreur transitoire du serveur SMTP cible;<br> | ||
*les communications peuvent ne pas être chiffrées, les communications non chiffrés sont reçues sur le port 25 ;<br> | *les communications peuvent ne pas être chiffrées, les communications non chiffrés sont reçues sur le port 25 ;<br> | ||
*les communications peuvent être chiffrées par TLS, les communication chiffrées peuvent être négociées directement sur le port 465 ;<br> | *les communications peuvent être chiffrées par TLS, les communication chiffrées peuvent être négociées directement sur le port 465 ;<br> | ||
*il doit être possible de basculer sur une communication chiffrée à partir du port 25 en utilisant les commandes EHLO et STARTTLS ;<br> | *il doit être possible de basculer sur une communication chiffrée à partir du port 25 en utilisant les commandes EHLO et STARTTLS ;<br> | ||
+ | |||
+ | *ne doivent être stockés que les courriels à destination d’un utilisateur local ;<br> | ||
+ | *le processus de remise stocke le message dans le sous-répertoire Maildir/tmp puis le déplace dans le sous-répertoire Maildir/new, déplacement doit être fait par la primitive rename ;<br> | ||
+ | *pour assurer un nom unique aux fichiers de stockage, utilisez la date en seconde (fonction time), le PID et un compteur commun à tous les flux d’exécution (utilisation de sémaphores indispensable).<br> | ||
== A faire (concernant le stockage des courriels) == | == A faire (concernant le stockage des courriels) == |
Version du 7 avril 2023 à 09:49
Sommaire
A faire
- un système doit être réalisé permettant au serveur SMTP sortant de mettre en file d’attente les messages non remis à destination pour cause d’erreur transitoire du serveur SMTP cible;
- les communications peuvent ne pas être chiffrées, les communications non chiffrés sont reçues sur le port 25 ;
- les communications peuvent être chiffrées par TLS, les communication chiffrées peuvent être négociées directement sur le port 465 ;
- il doit être possible de basculer sur une communication chiffrée à partir du port 25 en utilisant les commandes EHLO et STARTTLS ;
- ne doivent être stockés que les courriels à destination d’un utilisateur local ;
- le processus de remise stocke le message dans le sous-répertoire Maildir/tmp puis le déplace dans le sous-répertoire Maildir/new, déplacement doit être fait par la primitive rename ;
- pour assurer un nom unique aux fichiers de stockage, utilisez la date en seconde (fonction time), le PID et un compteur commun à tous les flux d’exécution (utilisation de sémaphores indispensable).
A faire (concernant le stockage des courriels)
- ne doivent être stockés que les courriels à destination d’un utilisateur local ;
- le processus de remise stocke le message dans le sous-répertoire Maildir/tmp puis le déplace dans le sous-répertoire Maildir/new, déplacement doit être fait par la primitive rename ;
- pour assurer un nom unique aux fichiers de stockage, utilisez la date en seconde (fonction time), le PID et un compteur commun à tous les flux d’exécution (utilisation de sémaphores indispensable).
Test sur la VM
- Se connecter au serveur : "ssh root@capbreton.plil.info"
- Se connecter à la VM : "ssh root@193.48.57.164" (password : "glopglopglop")
- Copier le programme dans la VM (à la racine) : "scp - r LisaJerome/ root@193.48.57.164:/
- Ouvrir le terminal en mode root : "su -" et vérifier si le port 25 est déjà occupé : "ss -tpln"
- Arrêter le processus exim4 (qui utilise le port 25) : "service exim4 stop"
- Compiler le programme : "make clean" + "make debug" (à la racine du prog)
- Exécuter le serveur d'envoi de mail sur l'interface loopback: ./SMTPin -l -j <logfile.txt>
- Exécuter le serveur de réception de mail sur l'interface Eth0 : ./SMTPout -i Eth0 -j <logfile.txt>
- Se connecter à un des serveurs : nc localhost 25"
Debug SMTPin
- Dans SMTPin ==> "mx.c" ne sert à rien (il est vide d'ailleurs), la fonction "**chercherMX" est implémentée dans "libs/Reseau/mx.c", on peut donc le supprimer.
- Dans SMTPin ==> "in.c" -> fonction "gestionCourriel", une fois les enregistrements DNS de type MX (serveurs courriel) trouvés, on envoie le courriel au MX qui a la priorité la plus basse, si l'envoi échoue on retente avec le MX de priorité suivante jusqu'à ce que l'envoi soit un succès. Pourtant si l'envoi est un succès, on continue d'envoyer le mail aux autres MX, il faut donc rajouter l'instruction else{break;} dans le code lorsque l'envoi est un succès.
while(*p!=NULL){ #ifdef DEVERMINE printf("Serveur : %s\n",*p); #endif int ss=connexionServeur(*p,SMTP_PORT_DEFAULT); FILE *dialogue=fdopen(ss,"a+"); if(dialogue==NULL){ perror("gestionCourriel.fdopen"); exit(EXIT_FAILURE); } char erreur[MAX_ERREUR]; int resultat=SMTP_dialogue(dialogue,donnees,erreur,MAX_ERREUR); fclose(dialogue); if(resultat<0) ecritureJournal(JOURNIV_DEVERMINE,JOURNAL_MXHS,*p); // Logguer l'erreur else{break;} p++; }
Modifications SMTPout
- On stocke les courriels dans la structure de répertoire MAILDIR, composée de 3 sous-répertoires : tmp, new et cur. Le processus qui récupère les courriels place les courriels dans le répertoire tmp, le nom du fichier est généré automatiquement de manière à être unique. Une fois le message complètement reçu par le serveur de courriel (MTA), il est déplacé, par un système de link/unlink dans le répertoire new. Au passage du client de messagerie qui parcourt le répertoire new, il est à nouveau déplacé et est mis dans le répertoire cur. Le message n'a toujours pas été lu.
- Dans "outc.c" -> fonction "gestionCourriel", on déplace le sous-répertoire Maildir/tmp dans le sous-repertoire Maildir/new en utilisant la primitive rename
char fichier[MAX_CHEMIN]; sprintf(fichier,"%s/%s/%s/%ld_%010d_%010ld",dossier,id,MAILDIR_TMP,time(NULL),pid,messages); FILE *f=fopen(fichier,"w"); if(f==NULL){ ecritureJournal(JOURNIV_ERREUR,JOURNAL_OUVERTURE,fichier); return; } int nb=fwrite(donnees->corps,donnees->taille,1,f); if(nb!=1){ ecritureJournal(JOURNIV_ERREUR,JOURNAL_ECRITURE,fichier); return; } fclose(f); char fichier_new[MAX_CHEMIN]; sprintf(fichier_new,"%s/%s/%s/%ld_%010d_%010ld",dossier,id,MAILDIR_NEW,time(NULL),pid,messages); rename(fichier, fichier_new);
Exécuter les 2 serveurs sur une interface différente du port réseau 25
Après avoir créé la VM (routable sur internet) sur le serveur capbreton.plil.info et y avoir copié le prog, on s'aperçoit qu'il n'est pas possible de lancer les 2 serveurs SMTPin et SMTPout en même temps car les 2 s'exécutent sur la même interface du port 25. Il faut donc lancer les serveurs sur des interfaces diff (SMTPout : eth0, SMTPin : loopback).
- SMPTout(args.h) => ajout d'une variable "interface" à la structure "stmp_config
struct smtp_config { char journal[CONFIG_MAX_JOURNAL]; int niveau; char port[CONFIG_MAX_PORT]; char dossier[CONFIG_MAX_CHEMIN]; char carte[CONFIG_MAX_CHEMIN]; unsigned char local; char interface[CONFIG_MAX_INTERFACE]; };
- SMPTout (args.c) => ajout d'un case i "interface" dans le switch
static struct option long_options[] = { {"local",no_argument,0,'l'}, {"interfaces", required_argument,0, 'i'}, {"port",required_argument,0,'p'}, {"journal",required_argument,0,'j'}, {"niveau",required_argument,0,'n'}, {"dossier",required_argument,0,'d'}, {"utilisateurs",required_argument,0,'u'}, {0,0,0,0} };
while(1){ int c=getopt_long(argc,argv,"lp:j:n:d:u:i:",long_options,NULL); if(c<0) break; switch(c){ case 'l': config->local=1; break; case 'i': strncpy(config->interface,optarg,sizeof(config->interface)-1); break; case 'p': strncpy(config->port,optarg,sizeof(config->port)-1); break; case 'j': strncpy(config->journal,optarg,sizeof(config->journal)-1); break; case 'd': strncpy(config->dossier,optarg,sizeof(config->dossier)-1); break; case 'u': strncpy(config->carte,optarg,sizeof(config->carte)-1); break; case 'n': config->niveau=atoi(optarg); break; default: afficheSyntaxe(argv[0]); break; } }
- SMPTout (out.c) ==> main function => récupérer l'interface passée en paramètre
char *interface=NULL; struct smtp_config config; analyseArguments(argc,argv,&config); if(config.journal[0]!='\0') creationJournal(config.journal); niveauJournal(config.niveau); ecritureJournal(JOURNIV_INFO,JOURNAL_DEBUT); if(config.port[0]=='\0') strcpy(config.port,SMTP_PORT_DEFAULT); if(config.local==1) interface=SMTP_LOCAL_INTERFACE; if(config.interface!=NULL) interface=config.interface;
Debug SMTPin -> envoi mails
- libs/SMTP/smtp.c -> ajout DEBUG :
static int retour_generique(FILE *dialogue,int succes,char *erreur,int taille){ char ligne[MAX_LIGNE]; #ifdef DEVERMINE printf("SMTP -> retour generique\n"); #endif if(fgets(ligne,MAX_LIGNE,dialogue)==NULL) return -1; ligne[MAX_LIGNE-1]='\0'; int code; int statut=sscanf(ligne,"%d",&code); #ifdef DEVERMINE printf("statut =%d\n", statut); printf("succes =%d\n", succes); printf("code =%d\n", code); #endif if(statut==1 && code!=succes){ strncpy(erreur,ligne,taille-1); #ifdef DEVERMINE printf("retour_generique ERROR\n"); #endif } return (statut==1 && code==succes)?0:-1; }
- Ce qui nous donne :
- 0 [50/woody.escaut.net]
Serveur : woody.escaut.net SMTP -> dialogue_connexion
SMTP -> retour generique statut =1 succes =250 code =220
SMTP -> dialogue_HELO
SMTP -> retour generique statut =1 succes =250 code =250 SMTP -> dialogue_MAIL SMTP -> retour generique statut =1 succes =250 code =250
SMTP -> dialogue_RCPT
SMTP -> retour generique statut =1 succes =250 code =250
SMTP -> dialogue_DATA
SMTP -> retour generique statut =1 succes =250 code =354
SMTP -> dialogue_QUIT
SMTP -> retour_generique statut =1 succes =221 code =250
On remarque donc que la fonction "dialogue_connexion" attend un code de succès 220 au lieu de 250, "dialogue_DATA" 354 au lieu de 250 et "dialogue_QUIT" 250 au lieu de 221.
- On modifie alors smtp.c à l'aide des variables globales définies dans "smtp_private.h":
On remarque que la fonction dialogue_connexion attend un code de succès 250 au lieu de 220, on vient donc le remplacer dans smtp.private.h.
???
Voir debug DATA
Après test, on remarque que le serveur SMTPin n'envoie pas nos mails même s'il a trouvé le nom de domaine et le MX de destination.
Debug "DEVERMINE" -> modif ACCUEIL CODE à 220 au lieu de 250. pour le ./SMTPin, commande strace -f ./SMTPin -l + modifier fgets dans libs/SMTP.c, gérer la gestion d'une commande à deux lignes : si présence d'un tiret dans la quatrième colonne, il faut prendre en compte la commande complète.
Erreur code 354 pour l'envoi de RCPT TO. à voir.