PSR SE2a4 2022/2023 G5
Sommaire
TP SMTP 2022 - Spécifications techniques
Farid LAZOUACHE / William BECUE
GITHUB
https://github.com/FaridLazouache/SMTP
Paramètres du TP
Groupe | Domaine | Nom VM | IPv4 virtuelle | IPv4 routée | VLAN privé | Réseau local IPv4 | Cisco 6509-E | Cisco 9200 | ISR4331 | IPv6 |
---|---|---|---|---|---|---|---|---|---|---|
Groupe 5 | miserable.site | VMalex2 | 10.24.0.250 | 193.48.57.167/28 | 24 | 10.24.0.0/16 | 10.24.0.251 | 10.24.0.252 | 10.24.0.253 | 2001:660:4401:60A0:216:3eff:fe92:8ec5 |
Machine virtuelle
- Connexion au serveur Capbreton :
ssh root@capbreton.plil.info
→ Dossier de stockage des données de la VM : /usr/local/xen/domains/VMalex2
→ Fichier de configuration de la VM : /etc/xen/VMalex2.cfg
- Connexion à la VM :
ssh root@193.48.57.167
Journal de bord
Séance 1
Découverte du projet, de la strucuture des serveurs, des sockets, etc.
Nous avons édité le Wiki afin de choisir notre machine virtuelle.
Nous avons testé la machine virtuelle avec la commande suivante : ssh root@193.48.57.167
Séance 2
Nous avons découvert le projet, le contenu et la structure des programmes. Nous avons, notamment, examiné la gestion des SMTPs rentrants et sortants, nous avons commencé notre analyse du fichier in.c.
La fonction qui gère la gestion des clients SMTP (les clients qui souhaitent se connecter de l'extérieur) puis la gestion des courriels (des demandes venants de l'extèrieur) qui permet de récupérer les noms de domaines et les MX. Ensuite, la fonction gestionCourriel()
permet à partir d'une boucle de gérer la connexion au serveur stocké dans ss (socket). Le contenu des messages va être stocké dans un fichier, celui-ci va être envoyé vers le serveur SMTP qui, lui, va envoyer le message sur internet ou bien sur le disque si c'est un utilisateur local.
Nous, nous sommes rendu compte, que le message de base envoyait une réponse à tous les MX. Cependant, il suffit d'un MX qui réponde à notre demande. De fait nous avons ajouté un else break ligne 66 dans le cas où nous avions déjà eu un retour, pour stopper la boucle.
Nous avons compris que gestion SMTP rempli struct courriel qui appel gestion courriel une fois remplie.
Ce qui a été fait
- les serveurs SMTP doivent gérer les enregistrements MX permettant d’associer un nom de domaine à un serveur de messagerie, le recours aux enregistrements AAAA et A est à utiliser en cas d’absence de MX
- pour prévenir les failles, les deux serveurs SMTP seront écrits à partir de zéro en respectant la RFC 5321 mais avec des simplifications
- les serveurs doivent être codés en langage C en utilisant la bibliothèque des sockets
- les commandes VRFY et EXPN qui permettent au client de vérifier si une messagerie est disponible pour la transmission, ne seront pas implémentées
- le routage des messages ne doit pas être implémenté
- les communications peuvent ne pas être chiffrées, les communications non chiffrés sont reçues sur le port 25
- chaque connexion doit être gérée via un processus léger (Thread) et chaque commande par une fonction à laquelle est passée une structure représentant l’état du dialogue entre le client et le serveur
- les serveurs SMTP doivent être contactables en IPv4 et en IPv6, ils doivent aussi prendre en charge IPv4 et IPv6 pour la transmission vers les serveurs SMTP cibles ; => connexion et inittialisation serveur
- les deux serveurs ne diffèrent que par la méthode de distribution finale (stockage dans un système de fichiers ou envoi à un serveur SMTP cible)
- le serveur SMTP sortant ne doit être lié qu’à l’interface réseau loopback
- ne doivent être stockés que les courriels à destination d’un utilisateur local
- le format de stockage doit être le format maildir qui est une structure de répertoires particulière utilisée pour sauvegarder des courriers électroniques (le format maildir est très bien décrit sur Wikipédia)
- chaque message entrant doit être ajouté au dossier de réception Maildir propre à l’utilisateur de destination
- 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). => time
- Free mutexes =>
ajout via libs/Flux/mutex.c dans la fonction, ajout
int mutex_fin(void){
free(mutexes)}
à la fin de la fonction, ainsi le thread est libérer mais pas l'allocation mémoire - via src/SMTPout/out.c dans la fonction void gestionCourriel, ajout
char newfile[MAX_CHEMIN];
sprintf(newfile,"%s/%s/%s/%ld_%010d_%010ld",dossier,id,MAILDIR_NEW,time(NULL),pid,messages);
rename(fichier, newfile);
Dans le but de gérer MAILDIR_NEW avec le rename - Nous nous sommes rendu compte via src/SMTPin/in.c dans la fonction
void gestionCourriel
qu'il y avait une continuité d'envoi de mail aux autres MX, même si l'envoi était un succès. De fait, nous avons ajoutéfclose(dialogue);
à la fin de la fonction
Reste à 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 ; => data gestion_dialog erreur temporaire mais pas definitive => courriel file d'attente et le renvoyer comme un script
- les communications peuvent être chiffrées par TLS, les communication chiffrées peuvent être négociées directement sur le port 465 ; => serveur deux ports différents, un en claire et un directement chiffré
- il doit être possible de basculer sur une communication chiffrée à partir du port 25 en utilisant les commandes EHLO et STARTTLS ; => 4 caractères
- Faire une communication chiffré
- pour la transmission vers les serveurs SMTP cibles, une communication chiffrée doit être préférée ; => envoyer un helo à la place => lancer la commande starTTLS => ehlo a partir de cette commande reponse plusieur lignes, si connait starttls reponse 250
Séance 3
Dans le cadre de la troisième séance nous avons essayé d'établir une communication avec le serveur. Pour ce faire nous avons envoyé à la machine virtuel (notre serveur) le fichier de gestion de serveur- Nous nous sommes rendus compte que SMTPin et SMTPout écouter sur les mêmes interfaces.
- Nous avons instancié une nouvelle interface. Tout d'abord, via src/SMTPout/args.h, nous avons définis la taille de l'interface
#define CONFIG_MAX_INTERFACE 1024
, et nous avons ajouté une variable interface dans la structurestruct smtp_config
,char interface[CONFIG_MAX_INTERFACE]
- Dans la fonction analyseArguments, de SMTPout/args.c : Structure long_options modifiée pour prendre en compte le paramètre d'interface
i
Ajout dans la fonction - Dans la fonction analyseArguments, de SMTPout/args.c : Paramètres de la fonction getotp_long modifiés pour inclure i et un argument supplémentaire Ensuite ajout de l'argument
- Gestion des erreurs
- Dans SMTPout/out.c ajouter gestion config.interface (à ajouter dans la structure config)
- Ajout d'interfaces au niveau du SMTPout, nous avons complété le fichier SMTPout/out.c pour gérer l'argument i. En effet, dans la fonction principale nous avons ajouté
- Gestion d'erreurs : notification de la part du serveur de l'erreur 502, en cas de EHLO mal orthographié.
- Test serveur mail avec le site mxtoolbox.com.
- Test serveur mail avec telnet.
- DEBUGGER le SMTPin
- Analyse de boucleServeur dans reseau.c, appelé par SMTPin et SMTPout. Puis nous avons ajouté des
#ifdef DEVERMINE
dans les fonctions appelées. - SMTP Dialogue ne fonctionnait pas, commande
strace -f ./SMTPin -l
Nous avons modifié via libs/SMTP/smtp_private.h la valeur de : - 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.
- On a réalisé différents test sur le serveur de mail. Cependant, en se connectant nous avons bien les mx, mais on en fait rien. C'est à dire on se retrouve dans une boucle while qui est dans boucleServeur, de in.c.
- On a modifié connexionServeur dans reseau.c à l'aide du programme envoyé par le professeur.
- Réussir à sortir de la boucle while dans boucleserveur de in.c Problème on devrait sortir de la boucle while, on y arrive avec gmail, mais la fac le bloque Trouver comment faire avec un IPV4
- Suite à nos tentatives d'envoi de mail via le test de SMTPin, nous nous sommes rendu compte que nous avions un problème dans connexionServeur. Nous avons ajouté
if(connect(s,p->ai_addr,p->ai_addrlen)==0) break;
if(p->ai_family==AF_INET6) ipv6=1;
if(p->ai_family==AF_INET) ipv4=1;
p=p->ai_next;
}
- Problème rencontré : notre serveur résolution de nom n'était pas opérationnelle, nous l'avions kill, la semaine précédente, nous ne l'avions pas restart.
- Nous arrivons a envoyé des mails.
Nous avons définistext.txt
vi text.txt
Puis on utilise
EHLO
MAIL FROM: root@miserable.site
RCPT TO: william.becue@polyetch-lille.fr
DATA : CECI EST UN TEST
SUBJECT: test
.
QUITnc -C -q0 -i1 localhost 25 < text.txt
- Maintenant on doit faire en sorte, que l'on attende que le serveur nous réponde. Pour ce faire, nous avons modifié via /libs/SMTP/smtp.c la fonction
static int dialogue_DATA
static int dialogue_DATA(FILE *dialogue,char *corps,char *erreur,int taille)
{
int code;
// FAIRE APPEL A DIALOGUE_GENERIQUE POUR ENVOYER DATA AVANT D'ENVOYER LE CORPS ET LE POINT
code = dialogue_generique(dialogue, "DATA", "", CONTINUE_DATA_CODE, erreur, taille);
#ifdef DEVERMINE
printf("\nCODE = %d\n", code);
#endif
if(!code)
{ if(fprintf(dialogue,corps)<0) return -1;
if(fprintf(dialogue,".\r\n")<0) return -1;
//dialogue_generique(dialogue, NULL, NULL, NULL, erreur, taille);
return retour_generique(dialogue,SUCCES_DATA_CODE,erreur,taille);
}
else
return -1;
}
À faire la prochaine fois
- Essayer de rendre SMTPout fonctionnel.
- On créé une map à la racine de notre VM, map.txt
- on a du créer manuellement l'arborescence des fichiers et des utilisateurs. En effet, le serveur ne créé pas de strcuture MAILDIR, composé de ses 3 sous répertoires (tmp,cur et new) :
mkdir /tmp/root
Puis,
mkdir /tmp/root/tmp
mkdir /tmp/root/newmkdir /tmp/flazouac
Et,
mkdir /tmp/flazouac/tmp
mkdir /tmp/flazouac/newmkdir /tmp/wbecue
mkdir /tmp/wbecue/tmp
mkdir /tmp/wbecue/new - On a lancé sur un terminal strace ./SMTPout -i eth0 -u map.txt et on teste "de l'extérieur" depuis notre session
nc 193.48.57.167 25
mais nous ne recevions rien, via différent#ifdef DEVERMINE{}#endif
. - De fait, nous avons modifé via src/SMTPout/ou.c la fonction adresseVersUtilisateur(). Nous avons modifié
for(i=0;i<strlen(adresse);i++){
parfor(i=0;i<strlen(destinataire);i++){
- Ensuite, via src/SMTPout/ou.c la fonction scanCarteUtilisateur(). Nous avons modifié
if(strcasecmp(adresses[i].adresse,courriel)) return adresses[i].id;
parif(strcasecmp(adresses[i].adresse,courriel)== 0) return adresses[i].id;
- On a créé sur notre machine un
testout.txt
que l'on va tester vianc -C -i1 -q0 193.48.57.167 25 < testout.txt
- On a définit un exécutable shell
testcharge.sh
- Dans le but de pouvoir envoyer des mails depuis une adresse de l'extérieur et de le recevoir sur le serveur. On modifié via src/smtp.c la fonction
gestion_MAIL
. On avait un problème de gestion d'espace via la commande MAIL FROM:
Alors nous avons modifier SMTPout de sorte à ce qu'il n'écrive que sur eth0
Fait cette séance
void afficheSyntaxe(char *executable)
fprintf(stderr," -i|--interface # lier à l'interface eth0\n");
Puis dans la fonction
int analyseArguments
{"interface", required_argument, 0, 'i'},
i
=> int c=getopt_long(argc,argv,"lp:j:n:d:u:i:",long_options,NULL);
Afin d'ajouter un
case i
dans le switch c
,case 'i': strncpy(config->interface, optarg, sizeof(config->interface)-1);
À faire la prochaine fois
Séance 4
Fait cette séance
else interface = config.interface;
À faire la prochaine fois
Séance 5
Fait cette séance
Nous avons ajouté via /libs/SMTP/smtp.c dans la fonction static int retour_generique
static int retour_generique(FILE *dialogue,int succes,char *erreur,int taille)
{
char ligne[MAX_LIGNE];
//while(fgets(ligne, MAX_LIGNE, dialogue) != '-') // changed fgets to consider hyphen
//{
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("code = %d\n", code);
printf("statut = %d\n", statut);
printf("succes = %d\n", succes);
#endif
if(statut==1 && code!=succes) strncpy(erreur,ligne,taille-1);
return (statut==1 && code==succes)?0:-1;
//}
}
#define ACCUEIL_CODE 220
#define SUCCES_QUIT_CODE 250
Pour correspondre à ce que nous renvoyer la commande strace dans le but d'envoyer des mails
À faire la prochaine fois
Séance 6
Fait cette séance
À faire la prochaine fois
Séance 7
Fait cette séance
Séance 8
Fait cette séance
On déclare des utilisateurs :
root : root@miserable.site
wbecue : wbecue@miserable.site
flazouac : flazouac@miserable.site
for i in {1..10}
do
nc -C -i1 -q0 193.48.57.167 25 < testout.txt &
echo $i
done
static int gestion_MAIL(char *ligne,FILE *client,struct courriel *donnees){
char cmd[MAX_LIGNE];
char tag[MAX_LIGNE];
char arg[MAX_LIGNE];
char suite[MAX_LIGNE];
char format[MAX_LIGNE];
int statut=sscanf(ligne,"%4s %s %s %s",cmd,tag,arg,suite);
#ifdef DEVERMINE
printf("\nstatut = %d\n", statut);
#endif
if(statut!=3 || strcasecmp(tag,MAIL_TAG)!=0){
sprintf(format,"%%4s %s%%s %%s", MAIL_TAG);
#ifdef DEVERMINE
printf("\nformat = %s\n", format);
#endif
int statut2=sscanf(ligne,format,cmd,arg,suite);
#ifdef DEVERMINE
printf("\nstatut2 = %d\n", statut2);
#endif
if(statut2 !=2){
if(fprintf(client,"%03d %s\r\n",ERREUR_MAIL_CODE,ERREUR_MAIL_TEXTE)<0) return GESTION_STOP;
#ifdef DEVERMINE
printf("\nclient = %s\n", client);
#endif
return GESTION_ERREUR;}
}
FARID EVAL
Pour être évalué, il me fallait enlever le fait que le programme SMTPout imprime autant de lignes de "..." qu'il n'y a de lignes dans le fichier, pour cela il fallait modifier smtp.c Dans la fonction afficheCourriel de smtp.c
int end = 0; while(donnees->corps[c]!='\0'){ if(cpt2<AFFICHE_COURRIEL_DEBUT || cpt2>cpt-AFFICHE_COURRIEL_FIN) fwrite(donnees->c orps+c,sizeof(char),1,sortie); if(cpt2==AFFICHE_COURRIEL_DEBUT && cpt2<=cpt-AFFICHE_COURRIEL_FIN && !end) { fprintf(sortie,"...\n"); end = 1; }if(donnees->corps[c]=='\n') cpt2++;