summaryrefslogtreecommitdiff
path: root/decoders/mail/mail.c
diff options
context:
space:
mode:
Diffstat (limited to 'decoders/mail/mail.c')
-rw-r--r--decoders/mail/mail.c514
1 files changed, 514 insertions, 0 deletions
diff --git a/decoders/mail/mail.c b/decoders/mail/mail.c
new file mode 100644
index 0000000..7516548
--- /dev/null
+++ b/decoders/mail/mail.c
@@ -0,0 +1,514 @@
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#include "stellar/packet.h"
+#include "stellar/utils.h"
+#include "stellar/mq.h"
+#include "stellar/session.h"
+#include "stellar/mail.h"
+
+#include "mail_internal.h"
+#include "mail_parser.h"
+
+#define PORT_SMTP 25
+#define PORT_POP3 110
+#define PORT_IMAP 143
+
+static int is_current_packet_c2s(struct session *sess)
+{
+ const struct layer *first_pkt_layer, *curr_pkt_layer;
+
+ const struct packet *first_pkt, *curr_pkt;
+
+ first_pkt = session_get_first_packet(sess, FLOW_TYPE_C2S);
+ curr_pkt = session_get_current_packet(sess);
+
+ int i = 0;
+ int layer_count = packet_get_layer_count(first_pkt);
+
+ for (i = 0; i < 2 /* l3/l4 */; i++) {
+ first_pkt_layer = packet_get_layer_by_idx(first_pkt, layer_count - 1 -i);
+ curr_pkt_layer = packet_get_layer_by_idx(curr_pkt, layer_count - 1 -i);
+
+ if (first_pkt_layer->proto != curr_pkt_layer->proto) {
+ return 0;
+ }
+ switch (first_pkt_layer->proto) {
+ case LAYER_PROTO_TCP:
+ if (0 != memcmp(first_pkt_layer->hdr.tcp, curr_pkt_layer->hdr.tcp, sizeof(struct tcphdr))) {
+ return 0;
+ }
+ break;
+ case LAYER_PROTO_UDP:
+ if (0 != memcmp(first_pkt_layer->hdr.udp, curr_pkt_layer->hdr.udp, sizeof(struct udphdr))) {
+ return 0;
+ }
+ break;
+ case LAYER_PROTO_IPV4:
+ if (0 != memcmp(first_pkt_layer->hdr.ip4, curr_pkt_layer->hdr.ip4, sizeof(struct ip))) {
+ return 0;
+ }
+ break;
+ case LAYER_PROTO_IPV6:
+ if (0 != memcmp(first_pkt_layer->hdr.ip6, curr_pkt_layer->hdr.ip6, sizeof(struct ip6_hdr))) {
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ }
+
+ return 1;
+}
+
+static int mail_subscribe_command(struct mail_env *mail_env, mail_command_callback_func *cb, void *arg)
+{
+ int topic;
+ struct mq_schema *schema;
+
+ schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref);
+ if (schema == NULL) {
+ return -1;
+ }
+
+ topic = mq_schema_get_topic_id(schema, MAIL_COMMAND_TOPIC_NAME);
+ if (topic < 0) {
+ return -1;
+ }
+
+ return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg);
+}
+
+static int mail_subscribe_header(struct mail_env *mail_env, mail_header_callback_func *cb, void *arg)
+{
+ int topic;
+ struct mq_schema *schema;
+
+ schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref);
+ if (schema == NULL) {
+ return -1;
+ }
+
+ topic = mq_schema_get_topic_id(schema, MAIL_HEADER_TOPIC_NAME);
+ if (topic < 0) {
+ return -1;
+ }
+
+ return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg);
+}
+
+static int mail_subscribe_body(struct mail_env *mail_env, mail_body_callback_func *cb, void *arg)
+{
+ int topic;
+ struct mq_schema *schema;
+
+ schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref);
+ if (schema == NULL) {
+ return -1;
+ }
+
+ topic = mq_schema_get_topic_id(schema, MAIL_BODY_TOPIC_NAME);
+ if (topic < 0) {
+ return -1;
+ }
+
+ return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg);
+}
+
+static int mail_subscribe_attachment(struct mail_env *mail_env, mail_attachment_callback_func *cb, void *arg)
+{
+ int topic;
+ struct mq_schema *schema;
+
+ schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref);
+ if (schema == NULL) {
+ return -1;
+ }
+
+ topic = mq_schema_get_topic_id(schema, MAIL_ATTACHMENT_TOPIC_NAME);
+ if (topic < 0) {
+ return -1;
+ }
+
+ return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg);
+}
+
+static int mail_subscribe_eml(struct mail_env *mail_env, mail_eml_callback_func *cb, void *arg)
+{
+ int topic;
+ struct mq_schema *schema;
+
+ schema = module_manager_get_mq_schema(mail_env->mod_mgr_ref);
+ if (schema == NULL) {
+ return -1;
+ }
+
+ topic = mq_schema_get_topic_id(schema, MAIL_EML_TOPIC_NAME);
+ if (topic < 0) {
+ return -1;
+ }
+
+ return mq_schema_subscribe(schema, topic, (on_msg_cb_func *)(void *)cb, arg);
+}
+
+static void mail_dispatch(int topic, void *msg, on_msg_cb_func *msg_cb, void *arg, void *dispatch_arg)
+{
+ struct mail_message *mail_msg;
+ struct mail_env *mail_env;
+
+ mail_msg = (struct mail_message *)msg;
+ mail_env = (struct mail_env *)dispatch_arg;
+
+ if (topic == mail_env->command_topic_id) {
+ mail_command_callback_func *command_cb = (mail_command_callback_func *)(void *)msg_cb;
+ command_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq,
+ mail_msg->command, mail_msg->command_param, mail_msg->command_param_len,
+ mail_msg->command_line, mail_msg->command_line_len,
+ arg);
+ return;
+ }
+
+ if (topic == mail_env->header_topic_id) {
+ mail_header_callback_func *header_cb = (mail_header_callback_func *)(void *)msg_cb;
+ header_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq, &mail_msg->header, arg);
+ return;
+ }
+
+ if (topic == mail_env->body_topic_id) {
+ mail_body_callback_func *body_cb = (mail_body_callback_func *)(void *)msg_cb;
+ body_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq,
+ mail_msg->body, mail_msg->body_len,
+ mail_msg->body_offset, mail_msg->is_body_finished,
+ arg);
+ return;
+ }
+
+ if (topic == mail_env->attachment_topic_id) {
+ mail_attachment_callback_func *attachment_cb = (mail_attachment_callback_func *)(void *)msg_cb;
+ attachment_cb(mail_msg->sess_ref, mail_msg->mail_protocol, mail_msg->mail_seq,
+ mail_msg->attachment_name, mail_msg->attachment_name_len,
+ mail_msg->attachment, mail_msg->attachment_len,
+ mail_msg->attachment_offset, mail_msg->is_attachment_finished,
+ arg);
+ return;
+ }
+
+ if (topic == mail_env->eml_topic_id) {
+ mail_eml_callback_func *eml_cb = (mail_eml_callback_func *)(void *)msg_cb;
+ eml_cb(mail_msg->sess_ref, mail_msg->mail_protocol,
+ mail_msg->eml, mail_msg->eml_len,
+ mail_msg->eml_offset, mail_msg->is_eml_finished,
+ arg);
+ return;
+ }
+}
+
+int mail_subscribe(struct mail_env *mail_env,
+ mail_command_callback_func command_cb,
+ mail_header_callback_func *header_cb,
+ mail_body_callback_func *body_cb,
+ mail_attachment_callback_func *attachment_cb,
+ mail_eml_callback_func *eml_cb,
+ void *arg)
+{
+ int ret;
+
+ ret = mail_subscribe_command(mail_env, command_cb, arg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = mail_subscribe_header(mail_env, header_cb, arg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = mail_subscribe_body(mail_env, body_cb, arg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = mail_subscribe_attachment(mail_env, attachment_cb, arg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = mail_subscribe_eml(mail_env, eml_cb, arg);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mail_session_ctx_free(struct mail_session_ctx *session_ctx)
+{
+ switch (session_ctx->protocol) {
+ case MAIL_PROTOCOL_SMTP:
+ if (session_ctx->smtp_parser) {
+ smtp_parser_free(session_ctx->smtp_parser);
+ }
+ break;
+ case MAIL_PROTOCOL_POP3:
+ break;
+ case MAIL_PROTOCOL_IMAP:
+ break;
+ default:
+ break;
+ }
+ free(session_ctx);
+}
+
+static struct mail_session_ctx *mail_session_ctx_new(void)
+{
+ struct mail_session_ctx *session_ctx;
+ session_ctx = (struct mail_session_ctx *)calloc(1, sizeof(struct mail_session_ctx));
+ return session_ctx;
+}
+
+static int mail_info_process(struct mail_env *mail_env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s)
+{
+ int ret;
+
+ ret = smtp_parser_get_command(session_ctx->smtp_parser);
+ if (ret == 0) {
+ mail_publish_command(mail_env, sess, mail_protocol, mail_seq, cmd, cmd_param, cmd_param_len, cmd_line, cmd_line_len);
+ }
+
+ struct mail_info *mail;
+ mail = smtp_parser_get_mailinfo(session_ctx->smtp_parser);
+ if (mail) {
+ mail_info_get_header();
+ mail_info_get_body();
+ mail_info_get_attachment();
+ }
+}
+
+static int mail_imap_process(struct mail_env *mail_env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s)
+{
+ int ret;
+
+ ret = smtp_parser_process(session_ctx->smtp_parser, payload, payload_len , is_c2s);
+ if (ret != 0) {
+ return;
+ }
+
+ ret = smtp_parser_get_command(session_ctx->smtp_parser);
+ if (ret == 0) {
+ mail_publish_command(mail_env, sess, mail_protocol, mail_seq, cmd, cmd_param, cmd_param_len, cmd_line, cmd_line_len);
+ }
+
+ struct mail_info *mail;
+ mail = smtp_parser_get_mailinfo(session_ctx->smtp_parser);
+ if (mail) {
+ mail_info_get_header();
+ mail_info_get_body();
+ mail_info_get_attachment();
+ }
+}
+
+static int mail_pop3_process(struct mail_env *mail_env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s)
+{
+ int ret;
+
+ ret = smtp_parser_process(session_ctx->smtp_parser, payload, payload_len , is_c2s);
+ if (ret != 0) {
+ return;
+ }
+
+ ret = smtp_parser_get_command(session_ctx->smtp_parser);
+ if (ret == 0) {
+ mail_publish_command(mail_env, sess, mail_protocol, mail_seq, cmd, cmd_param, cmd_param_len, cmd_line, cmd_line_len);
+ }
+
+ struct mail_info *mail;
+ mail = smtp_parser_get_mailinfo(session_ctx->smtp_parser);
+ if (mail) {
+ mail_info_get_header();
+ mail_info_get_body();
+ mail_info_get_attachment();
+ }
+}
+
+static int mail_smtp_process(struct mail_env *mail_env, struct mail_session_ctx *session_ctx, const char *payload, size_t payload_len, int is_c2s)
+{
+ int ret;
+
+ if (session_ctx->smtp_parser == NULL) {
+ session_ctx->smtp_parser = smtp_parser_new(mail_env);
+ }
+
+ ret = smtp_parser_process(session_ctx->smtp_parser, payload, payload_len , is_c2s);
+ if (ret != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mail_on_tcp_payload(struct session *sess, enum session_state state, const char *payload, uint32_t payload_len, void *arg)
+{
+ (void)state;
+ int ret;
+ int is_packet_c2s;
+ struct mail_session_ctx *session_ctx;
+ struct mail_env *mail_env = (struct mail_env *)arg;
+
+ if (payload == NULL || payload_len == 0) {
+ return;
+ }
+
+ session_ctx = (struct mail_session_ctx *)session_get_exdata(sess, mail_env->exdata_id);
+ if (session_ctx == NULL) {
+ session_ctx = mail_session_ctx_new();
+ session_ctx->mail_env_ref = mail_env;
+ session_ctx->sess_ref = sess;
+ session_ctx->protocol = MAIL_PROTOCOL_MAX;
+ session_ctx->is_mail_protocol = 1;
+ session_set_exdata(sess, mail_env->exdata_id, session_ctx);
+
+ if (smtp_identify(payload, payload_len, is_packet_c2s)) {
+ session_ctx->protocol = MAIL_PROTOCOL_SMTP;
+ }
+ //if (pop3_identify((char *)payload, payload_len, is_packet_c2s)) {
+ // session_ctx->protocol = MAIL_PROTOCOL_POP3;
+ //}
+
+ //if (imap_identify((char *)payload, payload_len, is_packet_c2s)) {
+ // session_ctx->protocol = MAIL_PROTOCOL_IMAP;
+ //}
+ }
+
+ is_packet_c2s = is_current_packet_c2s(sess);
+
+ switch (session_ctx->protocol) {
+ case MAIL_PROTOCOL_SMTP:
+ mail_smtp_process(mail_env, session_ctx, payload, payload_len, is_packet_c2s);
+ break;
+ case MAIL_PROTOCOL_POP3:
+ //ret = pop3_parser_process(session_ctx->smtp, payload, payload_len , is_packet_c2s);
+ //if (ret != 0) {
+ // return;
+ //}
+ break;
+ case MAIL_PROTOCOL_IMAP:
+ //ret = imap_parser_process(session_ctx->smtp, payload, payload_len , is_packet_c2s);
+ //if (ret != 0) {
+ // return;
+ //}
+ break;
+ default:
+ break;
+ }
+}
+
+void mail_on_exdata_free(int idx, void *ex_ptr, void *arg)
+{
+ (void)(idx);
+ (void)(arg);
+ struct mail_session_ctx *session_ctx = (struct mail_session_ctx *)ex_ptr;
+
+ if (session_ctx) {
+ mail_session_ctx_free(session_ctx);
+ }
+}
+
+static void mail_on_message_free(void *msg, void *arg)
+{
+ (void)(arg);
+ struct mail_message *mail_msg;
+
+ mail_msg = (struct mail_message *)msg;
+ if (mail_msg) {
+ free(mail_msg);
+ }
+}
+
+void mail_exit(struct module_manager *mod_mgr, struct module *mod)
+{
+ (void)(mod_mgr);
+ struct mail_env *mail_env;
+ struct mq_schema *schema;
+
+ if (mod) {
+ mail_env = (struct mail_env *)module_get_ctx(mod);
+ if (mail_env) {
+ schema = module_manager_get_mq_schema(mod_mgr);
+ mq_schema_destroy_topic(schema, mail_env->command_topic_id);
+ mq_schema_destroy_topic(schema, mail_env->header_topic_id);
+ mq_schema_destroy_topic(schema, mail_env->body_topic_id);
+ mq_schema_destroy_topic(schema, mail_env->attachment_topic_id);
+ mq_schema_destroy_topic(schema, mail_env->eml_topic_id);
+ free(mail_env);
+ }
+
+ module_free(mod);
+ }
+}
+
+struct module* mail_init(struct module_manager *mod_mgr)
+{
+ int ret;
+ struct module *mod;
+ struct mq_schema *schema;
+ struct session_manager *sess_mgr;
+ struct mail_env *mail_env;
+
+ mail_env = (struct mail_env *)calloc(1, sizeof(struct mail_env));
+ mail_env->mod_mgr_ref = mod_mgr;
+ mod = module_new(MAIL_MODULE_NAME, mail_env);
+ sess_mgr = module_to_session_manager(module_manager_get_module(mod_mgr, SESSION_MANAGER_MODULE_NAME));
+ schema = module_manager_get_mq_schema(mod_mgr);
+
+ if (sess_mgr == NULL || schema == NULL) {
+ goto exit;
+ }
+
+ ret = session_manager_subscribe_tcp_stream(sess_mgr, mail_on_tcp_payload, mail_env);
+ if (ret < 0) {
+ goto exit;
+ }
+
+ mail_env->exdata_id = session_manager_new_session_exdata_index(sess_mgr, MAIL_EXDATA_NAME, mail_on_exdata_free, NULL);
+ if (mail_env->exdata_id < 0) {
+ goto exit;
+ }
+
+ mail_env->command_topic_id = mq_schema_create_topic(schema, MAIL_COMMAND_TOPIC_NAME, mail_dispatch, mail_env, mail_on_message_free, NULL);
+ if (mail_env->command_topic_id < 0) {
+ goto exit;
+ }
+ mail_env->header_topic_id = mq_schema_create_topic(schema, MAIL_HEADER_TOPIC_NAME, mail_dispatch, mail_env, mail_on_message_free, NULL);
+ if (mail_env->header_topic_id < 0) {
+ goto exit;
+ }
+ mail_env->body_topic_id = mq_schema_create_topic(schema, MAIL_BODY_TOPIC_NAME, mail_dispatch, mail_env, mail_on_message_free, NULL);
+ if (mail_env->body_topic_id < 0) {
+ goto exit;
+ }
+ mail_env->attachment_topic_id = mq_schema_create_topic(schema, MAIL_ATTACHMENT_TOPIC_NAME, mail_dispatch, mail_env, mail_on_message_free, NULL);
+ if (mail_env->attachment_topic_id < 0) {
+ goto exit;
+ }
+ mail_env->eml_topic_id = mq_schema_create_topic(schema, MAIL_EML_TOPIC_NAME, mail_dispatch, mail_env, mail_on_message_free, NULL);
+ if (mail_env->eml_topic_id < 0) {
+ goto exit;
+ }
+
+ return mod;
+exit:
+ mail_exit(mod_mgr, mod);
+ return NULL;
+}
+
+struct mail_env *module_to_mail_env(struct module *mod)
+{
+ assert(mod);
+ assert(strcmp(module_get_name(mod), MAIL_MODULE_NAME) == 0);
+ return module_get_ctx(mod);
+}