17 mai 2010

Protocoale pentru posta electronica

Anatomia mesajelor e-mail

Un mesaj e-mail a fost întotdeauna transmis in format plain-text. Chiar si prin adăugarea attachmenturilor, mesajele de e-mail sunt trimise tot ca mesaje plain-text, prin folosirea unor mecanisme de codificare (uuencode/uudecode, MIME/BASE64). Un mesaj este format dintr-o secţiune de headere, urmata de o secţiune cu conţinutul mesajului. Structura headerelor este descrisa in RFC 822, RFC 1521 si RFC 1806, ele având in general următoarea structura:
- Unul sau mai multe headere Received: , care indica ce cale a fost urmata de mesaj de la sursa pana la destinaţie
- Mime-Version: versiunea mime folosita, 1.0 in general
- Content-Type: text/plain pentru mesaje text, multipart/mixed pentru mesaje cu ataşamente
- Subject: - subject-ul mesajului
- Date: - data si ora când a fost trimis mesajul
- Message ID: - un ID pentru mesaj, folosit pentru identificarea in mod unic a unui mesaj
- From: - numele si adresa de mail a expeditorului
- To: - numele si adresa de mail a destinatarului
- Cc: - carbon copy - alţi destinatari

Mesajele cu ataşamente pot folosi una din următoarele tehnici pentru codificarea acestora:
  • uuencode - la începuturile e-mail-ului, fişierele care se doreau trimise prin email trebuiau convertite in format text si invers prin folosirea utilitarelor numite uuencode/uudecode. Si in zilele de azi, unii clienţi de mail adaugă ataşamentele la sfârşitul mesajelor, codificându-le cu algoritmul folosit de uuencode.
  • MIME / Base64 - aceasta tehnologie este cea recomandata pentru trimiterea de mesaje cu ataşamente.
In terminologia folosita de sistemele de e-mail, exista 3 actori in cadrul sistemului de e-mail. Aceştia pot fi situaţi pe 3 maşini diferite sau pot co-exista pe acelaşi computer:
  • Mail User Agent (MUA), sau client de e-mail - aceasta este aplicaţia folosita de utilizator pentru a citi si trimite mesaje email. El nu primeşte direct mesaje, acesta fiind rolul Mailbox Server-ului.
  • Mailbox Server, sau server de e-mail - acesta este calculatorul/serverul care primeşte si stochează mesajele.
  • Mail Transfer Agent (MTA), sau "router" de e-mail - aceasta este aplicaţia care primeşte si retrimite mesajele spre un alt MTA sau spre un Mailbox Server.
Protocolul SMTP este folosit si de către clienţii de mail când se trimit mesaje e-mail. Astfel, pentru a trimite un mesaj clienţii de mail (MUA) se conectează la serverele SMTP (MTA) si comunica prin protocolul SMTP. In schimb, la transferul mesajelor recepţionate intre Mailbox Server si clientul de mail
se folosesc alte protocoale, cele mai cunoscute fiind POP3 (POP versiunea 3) si IMAP.

Protocolul POP (Post Office Protocol) este destinat folosirii in mod "offline" si este cel mai vechi dintre cele doua protocoale. In paradigma POP, mesajele sunt stocate pe un server, iar un client de mail interoghează periodic serverul, aducând mesajele noi pe calculatorul utilizatorului. După ce un mesaj este descărcat, este şters de pe server. In continuare, toate procesările asupra mesajelor sunt făcute pe calculatorul utilizatorului.

Protocolul IMAP (Internet Message Access Protocol) poate face si procesare offline, dar este in general folosit pentru accesul "online" la mail. In modul online, mesajele sunt stocate tot pe un server, dar clientul nu copiază pur si simplu mesajele pe calculatorul utilizatorului. Se foloseşte un mod de comunicaţie interactiv, in care clientul poate cere doar headere de mesaje, doar anumite mesaje, sau poate căuta mesaje care respecta anumite criterii. Mesajele pot fi marcate ca "deleted" sau "answered" si acest marcaj este făcut pe server. Pe scurt, protocolul IMAP permite manipularea mesajelor de la distanta ca si cum ar fi stocate local.

Urmatorul program implementeaza un client simplu de smtp folosind socketsi tcp. Se apeleaza folosind ca parametru adresa serverului care accepta sa gazduiasca clientul (accepta telnet). In continuare, trimite la adresa de e-mail specificata mesaje de la un "expeditor" oarecare...


#include "sys/socket.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "unistd.h"
#include "sys/types.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "errno.h"

#define SMTP_PORT 25
#define MAXLEN 500

/**
* Citeste maxim maxlen octeti din socket-ul sockfd. Intoarce
* numarul de octeti cititi.
*/
ssize_t Readline (int sockd, void *vptr, size_t maxlen) {
ssize_t n, rc;
char c, *buffer;

buffer = vptr;

for ( n = 1; n<=maxlen-1; n++ ) {
if ( (rc = read(sockd, &c, 1)) == 1 ) {
*buffer++ = c;
if ( c == '\n' )
break;
}
else if ( rc == 0 ) {
if ( n == 1 )
return 0;
else
break;
}
else {
if ( errno == EINTR )
continue;
return -1;
}
}

*buffer = 0;
return n;
}

/**
* Trimite o comanda SMTP si asteapta raspuns de la server.
* Comanda trebuie sa fie in buffer-ul sendbuf.
* Sirul expected contine inceputul raspunsului pe care
* trebuie sa-l trimita serverul in caz de succes (de ex. codul
* 250). Daca raspunsul semnaleaza o eroare se iese din program.
*/
void send_command(int sockfd, char sendbuf[], char *expected) {
char recvbuf[MAXLEN];
int nbytes;
char CRLF[3];

CRLF[0] = 13; CRLF[1] = 10; CRLF[2] = 0;
strcat(sendbuf, CRLF);
printf("Trimit: %s", sendbuf);
write(sockfd, sendbuf, strlen(sendbuf));
nbytes = Readline(sockfd, recvbuf, MAXLEN - 1);
recvbuf[nbytes] = 0;
printf("Am primit: %s", recvbuf);
if (strstr(recvbuf, expected) != recvbuf) {
printf("Am primit mesaj de eroare de la server!\n");
exit(-1);
}
}

int main(int argc, char **argv) {
int sockfd;
int port = SMTP_PORT;
struct sockaddr_in servaddr;
char server_ip[15];
char sendbuf[MAXLEN];
char recvbuf[MAXLEN];

if (argc != 2) {
printf("Utilizare: ./send_msg adresa_server");
exit(-1);
}
strcpy(server_ip, argv[1]);

if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0))<0>
printf("Eroare la creare socket.\n");
exit(-1);
}

/* formarea adresei serverului */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);

if (inet_aton(server_ip, &servaddr.sin_addr)<=0) {
printf("Adresa IP invalida.\n");
exit(-1);
}

/* conectare la server */
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))<0>
printf("Eroare la conectare\n");
exit(-1);
}

Readline(sockfd, recvbuf, MAXLEN -1);
printf("Am primit: %s\n", recvbuf);

sprintf(sendbuf, "HELO `adresa_ip_aici`");
send_command(sockfd, sendbuf, "250");

sprintf(sendbuf, "mail from: Anonymous@yahoo.com");
send_command(sockfd, sendbuf, "250");

sprintf(sendbuf, "rcpt to: yourSecretLover@yahoo.com");
send_command(sockfd, sendbuf, "250");

sprintf(sendbuf, "data");
send_command(sockfd, sendbuf, "354");

sprintf(sendbuf, "secret message from a secret person\n.");
send_command(sockfd, sendbuf, "250");

sprintf(sendbuf, "quit");
send_command(sockfd, sendbuf, "221");

close(sockfd);
}

Niciun comentariu: