]> source.dussan.org Git - rspamd.git/commitdiff
* Place all protocol logic in separate file
authorcebka@mailsupport.rambler.ru <cebka@mailsupport.rambler.ru>
Sat, 20 Sep 2008 00:13:49 +0000 (04:13 +0400)
committercebka@mailsupport.rambler.ru <cebka@mailsupport.rambler.ru>
Sat, 20 Sep 2008 00:13:49 +0000 (04:13 +0400)
 - simplify protocol parsing logic
 - add compatibility with sa-spamd
 - TODO: add protocol output for all commands

configure
main.h
protocol.c [new file with mode: 0644]
protocol.h [new file with mode: 0644]
worker.c

index a8a5ddd32a52841f62e1acd2e5655ab2cf257b76..8150e03d441a4f651dcd8a32118035c5d284928a 100755 (executable)
--- a/configure
+++ b/configure
@@ -21,7 +21,7 @@ YACC_OUTPUT="cfg_yacc.c"
 LEX_OUTPUT="cfg_lex.c"
 CONFIG="config.h"
 
-SOURCES="upstream.c cfg_utils.c memcached.c main.c util.c worker.c fstring.c url.c perl.c mem_pool.c plugins/surbl.c ${LEX_OUTPUT} ${YACC_OUTPUT}"
+SOURCES="upstream.c cfg_utils.c memcached.c main.c util.c worker.c fstring.c url.c perl.c protocol.c mem_pool.c plugins/surbl.c ${LEX_OUTPUT} ${YACC_OUTPUT}"
 MODULES="surbl"
 
 CFLAGS="$CFLAGS -W -Wpointer-arith -Wno-unused-parameter"
@@ -30,7 +30,7 @@ CFLAGS="$CFLAGS -Wunused-value -ggdb -I${LOCALBASE}/include"
 CFLAGS="$CFLAGS "
 LDFLAGS="$LDFLAGS -L/usr/lib -L${LOCALBASE}/lib"
 OPT_FLAGS="-O -pipe -fno-omit-frame-pointer"
-DEPS="config.h cfg_file.h memcached.h util.h main.h upstream.h fstring.h url.h perl.h mem_pool.h ${LEX_OUTPUT} ${YACC_OUTPUT}"
+DEPS="config.h cfg_file.h memcached.h util.h main.h upstream.h fstring.h url.h perl.h mem_pool.h protocol.h ${LEX_OUTPUT} ${YACC_OUTPUT}"
 EXEC=rspamd
 USER=postfix
 GROUP=postfix
diff --git a/main.h b/main.h
index c7e39c38f0788820ff9146a1a5751b39dd76bc35..e4f7fc600bd9b8dc33a682b3b0468371f0bf6761 100644 (file)
--- a/main.h
+++ b/main.h
@@ -23,6 +23,7 @@
 #include "mem_pool.h"
 #include "url.h"
 #include "memcached.h"
+#include "protocol.h"
 
 #include <glib.h>
 #include <gmime/gmime.h>
@@ -112,6 +113,8 @@ struct worker_task {
                WAIT_FILTER,
        } state;
        size_t content_length;
+       enum rspamd_protocol proto;
+       enum rspamd_command cmd;
        char *helo;
        char *from;
        char *rcpt;
diff --git a/protocol.c b/protocol.c
new file mode 100644 (file)
index 0000000..12fdfcf
--- /dev/null
@@ -0,0 +1,254 @@
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include "main.h"
+
+/*
+ * Just check if the passed message is spam or not and reply as
+ * described below
+ */
+#define MSG_CMD_CHECK "check"
+/* 
+ * Check if message is spam or not, and return score plus list
+ * of symbols hit
+ */
+#define MSG_CMD_SYMBOLS "symbols"
+/*
+ * Check if message is spam or not, and return score plus report
+ */
+#define MSG_CMD_REPORT "report"
+/*
+ * Check if message is spam or not, and return score plus report
+ * if the message is spam
+ */
+#define MSG_CMD_REPORT_IFSPAM "report_ifspam"
+/*
+ * Ignore this message -- client opened connection then changed
+ */
+#define MSG_CMD_SKIP "skip"
+/*
+ * Return a confirmation that spamd is alive
+ */ 
+#define MSG_CMD_PING "ping"
+/*
+ * Process this message as described above and return modified message
+ */
+#define MSG_CMD_PROCESS "process"
+
+/*
+ * spamassassin greeting:
+ */
+#define SPAMC_GREETING "SPAMC"
+/*
+ * rspamd greeting:
+ */
+#define RSPAMC_GREETING "RSPAMC"
+/*
+ * Headers
+ */
+#define CONTENT_LENGTH_HEADER "Content-Length"
+#define HELO_HEADER "Helo"
+#define FROM_HEADER "From"
+#define IP_ADDR_HEADER "IP"
+#define NRCPT_HEADER "Recipient-Number"
+#define RCPT_HEADER "Rcpt"
+
+static int
+parse_command (struct worker_task *task, char *line)
+{
+       char *token;
+
+       token = strsep (&line, " ");
+       if (line == NULL || token == NULL) {
+               return -1;
+       }
+
+       switch (token[0]) {
+               case 'c':
+               case 'C':
+                       /* check */
+                       if (strcasecmp (token + 1, MSG_CMD_CHECK + 1) == 0) {
+                               task->cmd = CMD_CHECK;  
+                       }
+                       else {
+                               msg_debug ("parse_command: bad comand: %s", token);
+                               return -1;
+                       }
+                       break;
+               case 's':
+               case 'S':
+                       /* symbols, skip */
+                       if (strcasecmp (token + 1, MSG_CMD_SYMBOLS + 1) == 0) {
+                               task->cmd = CMD_SYMBOLS;
+                       }
+                       else if (strcasecmp (token + 1, MSG_CMD_SKIP + 1) == 0) {
+                               task->cmd = CMD_SKIP;
+                       }
+                       else {
+                               msg_debug ("parse_command: bad comand: %s", token);
+                               return -1;
+                       }
+                       break;
+               case 'p':
+               case 'P':
+                       /* ping, process */
+                       if (strcasecmp (token + 1, MSG_CMD_PING + 1) == 0) {
+                               task->cmd = CMD_PING;
+                       }
+                       else if (strcasecmp (token + 1, MSG_CMD_PROCESS + 1) == 0) {
+                               task->cmd = CMD_PROCESS;
+                       }
+                       else {
+                               msg_debug ("parse_command: bad comand: %s", token);
+                               return -1;
+                       }
+                       break;
+               case 'r':
+               case 'R':
+                       /* report, report_ifspam */
+                       if (strcasecmp (token + 1, MSG_CMD_REPORT + 1) == 0) {
+                               task->cmd = CMD_REPORT;
+                       }
+                       else if (strcasecmp (token + 1, MSG_CMD_REPORT_IFSPAM + 1) == 0) {
+                               task->cmd = CMD_REPORT_IFSPAM;
+                       }
+                       else {
+                               msg_debug ("parse_command: bad comand: %s", token);
+                               return -1;
+                       }
+                       break;
+               default:
+                       msg_debug ("parse_command: bad comand: %s", token);
+                       return -1;
+       }
+
+       if (strncasecmp (line, RSPAMC_GREETING, sizeof (RSPAMC_GREETING) - 1) == 0) {
+               task->proto = RSPAMC_PROTO;
+       }
+       else if (strncasecmp (line, SPAMC_GREETING, sizeof (SPAMC_GREETING) -1) == 0) {
+               task->proto = SPAMC_PROTO;
+       }
+       else {
+               msg_debug ("parse_command: bad protocol version: %s", line);
+               return -1;
+       }
+       task->state = READ_HEADER;
+       return 0;
+}
+
+static int
+parse_header (struct worker_task *task, char *line)
+{
+       char *headern, *err;
+       headern = strsep (&line, ":");
+
+       /* Check end of headers */
+       if (*line == '\r' && *(line + 1) == '\n') {
+               task->state = READ_MESSAGE;
+               return 0;
+       }
+
+       if (line == NULL || headern == NULL) {
+               return -1;
+       }
+       /* Eat whitespaces */
+       g_strstrip (line);
+       g_strstrip (headern);
+
+       switch (headern[0]) {
+               case 'c':
+               case 'C':
+                       /* content-length */
+                       if (strncasecmp (headern, CONTENT_LENGTH_HEADER, sizeof (CONTENT_LENGTH_HEADER) - 1) == 0) {
+                               task->content_length = strtoul (line, &err, 10);
+                               task->msg = g_malloc (sizeof (f_str_buf_t));
+                               task->msg->buf = fstralloc (task->content_length);
+                               if (task->msg->buf == NULL) {
+                                       msg_err ("read_socket: cannot allocate memory for message buffer");
+                                       return -1;
+                               }
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
+               case 'h':
+               case 'H':
+                       /* helo */
+                       if (strncasecmp (headern, HELO_HEADER, sizeof (HELO_HEADER) - 1) == 0) {
+                               task->helo = g_strdup (line);
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
+               case 'f':
+               case 'F':
+                       /* from */
+                       if (strncasecmp (headern, FROM_HEADER, sizeof (FROM_HEADER) - 1) == 0) {
+                               task->from = g_strdup (line);
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
+               case 'r':
+               case 'R':
+                       /* rcpt */
+                       if (strncasecmp (headern, RCPT_HEADER, sizeof (RCPT_HEADER) - 1) == 0) {
+                               task->rcpt = g_strdup (line);
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
+               case 'n':
+               case 'N':
+                       /* nrcpt */
+                       if (strncasecmp (headern, NRCPT_HEADER, sizeof (NRCPT_HEADER) - 1) == 0) {
+                               task->nrcpt = strtoul (line, &err, 10);
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
+               case 'i':
+               case 'I':
+                       /* ip_addr */
+                       if (strncasecmp (headern, IP_ADDR_HEADER, sizeof (IP_ADDR_HEADER) - 1) == 0) {
+                               if (!inet_aton (line, &task->from_addr)) {
+                                       msg_info ("parse_header: bad ip header: '%s'", line);
+                                       return -1;
+                               }
+                       }
+                       else {
+                               msg_info ("parse_header: wrong header: %s", headern);
+                               return -1;
+                       }
+                       break;
+               default:
+                       msg_info ("parse_header: wrong header: %s", headern);
+                       return -1;
+       }
+
+       return 0;
+}
+
+int
+read_rspamd_input_line (struct worker_task *task, char *line)
+{
+       switch (task->state) {
+               case READ_COMMAND:
+                       return parse_command (task, line);
+                       break;
+               case READ_HEADER:
+                       return parse_header (task, line);
+                       break;
+       }
+}
diff --git a/protocol.h b/protocol.h
new file mode 100644 (file)
index 0000000..17a7a93
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef RSPAMD_PROTOCOL_H
+#define RSPAMD_PROTOCOL_H
+
+#include "config.h"
+
+struct worker_task;
+
+enum rspamd_protocol {
+       SPAMC_PROTO,
+       RSPAMC_PROTO,
+};
+
+enum rspamd_command {
+       CMD_CHECK,
+       CMD_SYMBOLS,
+       CMD_REPORT,
+       CMD_REPORT_IFSPAM,
+       CMD_SKIP,
+       CMD_PING,
+       CMD_PROCESS,
+};
+
+int read_rspamd_input_line (struct worker_task *task, char *line);
+
+#endif
index ea22ffbe271cdf69426277a08bf8afe5c6ffbb84..7c3ce6b95e0fcb5013b227be1ea6010281ac2a71 100644 (file)
--- a/worker.c
+++ b/worker.c
@@ -23,6 +23,7 @@
 
 #include "util.h"
 #include "main.h"
+#include "protocol.h"
 #include "upstream.h"
 #include "cfg_file.h"
 #include "url.h"
@@ -415,108 +416,12 @@ read_socket (struct bufferevent *bev, void *arg)
 
        switch (task->state) {
                case READ_COMMAND:
-                       s = evbuffer_readline (EVBUFFER_INPUT (bev));
-                       if (s != NULL) {
-                               msg_info ("read_socket: got command %s", s);
-                               free (s);
-                               task->state = READ_HEADER;
-                       }
-                       break;
                case READ_HEADER:
                        s = evbuffer_readline (EVBUFFER_INPUT (bev));
-                       if (s != NULL) {
-                               msg_info ("read_socket: got header %s", s);
-                               if (strncasecmp (s, CONTENT_LENGTH_HEADER, sizeof (CONTENT_LENGTH_HEADER) - 1) == 0) {
-                                       task->content_length = atoi (s + sizeof (CONTENT_LENGTH_HEADER) - 1);
-                                       msg_info ("read_socket: parsed content-length: %ld", (long int)task->content_length);
-                                       task->msg = malloc (sizeof (f_str_buf_t));
-                                       if (task->msg == NULL) {
-                                               msg_err ("read_socket: cannot allocate memory");
-                                               bufferevent_disable (bev, EV_READ);
-                                               bufferevent_free (bev);
-                                               free (task);
-                                       }
-                                       task->msg->buf = fstralloc (task->content_length);
-                                       if (task->msg->buf == NULL) {
-                                               msg_err ("read_socket: cannot allocate memory for message buffer");
-                                               bufferevent_disable (bev, EV_READ);
-                                               bufferevent_free (bev);
-                                               free (task->msg);
-                                               free (task);
-                                       }
-                                       task->msg->pos = task->msg->buf->begin;
-                                       update_buf_size (task->msg);
-                               }
-                               else if (strncasecmp (s, HELO_HEADER, sizeof (HELO_HEADER) - 1) == 0) {
-                                       c = rindex (s, '\r');
-                                       if (c != NULL) {
-                                               task->helo = malloc (c - (s + sizeof (HELO_HEADER) - 1));
-                                               if (task->helo) {
-                                                       strlcpy (task->helo, s + sizeof (HELO_HEADER) - 1, (c - (s + sizeof (HELO_HEADER) - 1)));
-                                               }
-                                               else {
-                                                       msg_err ("read_socket: malloc failed for HELO header: %m");
-                                               }
-                                       }
-                                       else {
-                                               msg_err ("read_socket: header " HELO_HEADER " has invalid format, ignored");
-                                       }
-                               }
-                               else if (strncasecmp (s, FROM_HEADER, sizeof (FROM_HEADER) - 1) == 0) {
-                                       c = rindex (s, '\r');
-                                       if (c != NULL) {
-                                               task->from = malloc (c - (s + sizeof (FROM_HEADER) - 1));
-                                               if (task->from) {
-                                                       strlcpy (task->from, s + sizeof (FROM_HEADER) - 1, (c - (s + sizeof (FROM_HEADER) - 1)));
-                                               }
-                                               else {
-                                                       msg_err ("read_socket: malloc failed for FROM header: %m");
-                                               }
-                                       }
-                                       else {
-                                               msg_err ("read_socket: header " FROM_HEADER " has invalid format, ignored");
-                                       }
-                               }
-                               else if (strncasecmp (s, RCPT_HEADER, sizeof (RCPT_HEADER) - 1) == 0) {
-                                       c = rindex (s, '\r');
-                                       if (c != NULL) {
-                                               task->rcpt = malloc (c - (s + sizeof (RCPT_HEADER) - 1));
-                                               if (task->rcpt) {
-                                                       strlcpy (task->rcpt, s + sizeof (RCPT_HEADER) - 1, (c - (s + sizeof (RCPT_HEADER) - 1)));
-                                               }
-                                               else {
-                                                       msg_err ("read_socket: malloc failed for RCPT header: %m");
-                                               }
-                                       }
-                                       else {
-                                               msg_err ("read_socket: header " RCPT_HEADER " has invalid format, ignored");
-                                       }
-                               }
-                               else if (strncasecmp (s, NRCPT_HEADER, sizeof (NRCPT_HEADER) - 1) == 0) {
-                                       task->nrcpt = atoi (s + sizeof (NRCPT_HEADER) - 1);
-                               }
-                               else if (strncasecmp (s, IP_ADDR_HEADER, sizeof (IP_ADDR_HEADER) - 1) == 0) {
-                                       c = rindex (s, '\r');
-                                       if (c != NULL) {
-                                               *c = 0;
-                                               if (!inet_aton (s + sizeof (IP_ADDR_HEADER) - 1, &task->from_addr)) {
-                                                       msg_info ("read_socket: bad ip header: '%s'", s);
-                                               }
-                                       }
-                                       else {
-                                               msg_err ("read_socket: header " IP_ADDR_HEADER " has invalid format, ignored");
-                                       }
-                               }
-                               else if (strlen (s) == 0 || (*s == '\r' && *(s+1) == '\n')) {
-                                       if (task->content_length != 0) {
-                                               task->state = READ_MESSAGE;
-                                       }
-                                       else {
-                                               task->state = WRITE_ERROR;
-                                       }
-                               }
-                               free (s);
+                       if (read_rspamd_input_line (task, s) != 0) {
+                               task->state = WRITE_ERROR;
                        }
+                       free (s);
                        break;
                case READ_MESSAGE:
                        r = bufferevent_read (bev, task->msg->pos, task->msg->free);