]> source.dussan.org Git - rspamd.git/commitdiff
Add parsing logic for log_format
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 5 Nov 2015 13:49:25 +0000 (16:49 +0300)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 5 Nov 2015 13:49:25 +0000 (16:49 +0300)
src/libserver/cfg_utils.c

index bad00db8a91e349959e54c709d9be9ec22210690..fe72370807f04a50eef30a195009a225e954d861 100644 (file)
@@ -280,42 +280,263 @@ rspamd_config_parse_flag (const gchar *str, guint len)
        return -1;
 }
 
-gboolean
-rspamd_config_calculate_checksum (struct rspamd_config *cfg)
+static gboolean
+rspamd_config_process_var (struct rspamd_config *cfg, const rspamd_ftok_t *var,
+               const rspamd_ftok_t *content)
 {
-       gint fd;
-       void *map;
-       struct stat st;
-
-       /* Compute checksum for config file that should be used by xml dumper */
-       if ((fd = open (cfg->cfg_name, O_RDONLY)) == -1) {
-               msg_err_config (
-                       "config file %s is no longer available, cannot calculate checksum");
-               return FALSE;
+       guint flags = RSPAMD_LOG_FLAG_DEFAULT;
+       struct rspamd_log_format *lf;
+       enum rspamd_log_format_type type;
+       rspamd_ftok_t tok;
+       gint id;
+
+       g_assert (var != NULL);
+
+       if (var->len > 3 && rspamd_lc_cmp (var->begin, "if_", 3) == 0) {
+               flags |= RSPAMD_LOG_FLAG_CONDITION;
+               tok.begin = var->begin + 3;
+               tok.len = var->len - 3;
+       }
+       else {
+               tok.begin = var->begin;
+               tok.len = var->len;
+       }
+
+       /* Now compare variable and check what we have */
+       /*
+       RSPAMD_LOG_MID,
+                       RSPAMD_LOG_QID,
+                       RSPAMD_LOG_USER,
+                       RSPAMD_LOG_ISSPAM,
+                       RSPAMD_LOG_ACTION,
+                       RSPAMD_LOG_SCORES,
+                       RSPAMD_LOG_SYMBOLS,
+                       RSPAMD_LOG_IP,
+                       RSPAMD_LOG_DNS_REQ,
+                       RSPAMD_LOG_SMTP_FROM,
+                       RSPAMD_LOG_MIME_FROM,
+                       RSPAMD_LOG_TIME_REAL,
+                       RSPAMD_LOG_TIME_VIRTUAL,
+                       RSPAMD_LOG_LUA
+       */
+       if (rspamd_ftok_cstr_equal (&tok, "mid", TRUE)) {
+               type = RSPAMD_LOG_MID;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "qid", TRUE)) {
+               type = RSPAMD_LOG_QID;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "user", TRUE)) {
+               type = RSPAMD_LOG_USER;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "isspam", TRUE)) {
+               type = RSPAMD_LOG_ISSPAM;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "action", TRUE)) {
+               type = RSPAMD_LOG_ACTION;
        }
-       if (stat (cfg->cfg_name, &st) == -1) {
-               msg_err_config ("cannot stat %s: %s", cfg->cfg_name, strerror (errno));
-               close (fd);
+       else if (rspamd_ftok_cstr_equal (&tok, "scores", TRUE)) {
+               type = RSPAMD_LOG_SCORES;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "symbols", TRUE)) {
+               type = RSPAMD_LOG_SYMBOLS;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "ip", TRUE)) {
+               type = RSPAMD_LOG_IP;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "dns_req", TRUE)) {
+               type = RSPAMD_LOG_DNS_REQ;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "smtp_from", TRUE)) {
+               type = RSPAMD_LOG_SMTP_FROM;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "mime_from", TRUE)) {
+               type = RSPAMD_LOG_MIME_FROM;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "time_real", TRUE)) {
+               type = RSPAMD_LOG_TIME_REAL;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "time_virtual", TRUE)) {
+               type = RSPAMD_LOG_TIME_VIRTUAL;
+       }
+       else if (rspamd_ftok_cstr_equal (&tok, "lua", TRUE)) {
+               type = RSPAMD_LOG_LUA;
+       }
+       else {
+               msg_err_config ("unknown log variable: %T", &tok);
                return FALSE;
        }
 
-       /* Now mmap this file to simplify reading process */
-       if ((map =
-               mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
-               msg_err_config ("cannot mmap %s: %s", cfg->cfg_name, strerror (errno));
-               close (fd);
+       lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
+       lf->type = type;
+       lf->flags = flags;
+
+       if (type != RSPAMD_LOG_LUA) {
+               if (content && content->len > 0) {
+                       lf->data = rspamd_mempool_alloc0 (cfg->cfg_pool,
+                                       sizeof (rspamd_ftok_t));
+                       memcpy (lf->data, &tok, sizeof (tok));
+               }
+       }
+       else {
+               /* Load lua code and ensure that we have function ref returned */
+               if (!content || content->len == 0) {
+                       msg_err_config ("lua variable needs content: %T", &tok);
+                       return FALSE;
+               }
+
+               if (luaL_loadbuffer (cfg->lua_state, content->begin, content->len,
+                               "lua log variable") != 0) {
+                       msg_err_config ("error loading lua code: '%T': %s", content,
+                                       lua_tostring (cfg->lua_state, -1));
+                       return FALSE;
+               }
+               if (lua_pcall (cfg->lua_state, 0, 1, 0) != 0) {
+                       msg_err_config ("error executing lua code: '%T': %s", content,
+                                       lua_tostring (cfg->lua_state, -1));
+                       return FALSE;
+               }
+
+               if (lua_type (cfg->lua_state, -1) != LUA_TFUNCTION) {
+                       msg_err_config ("lua variable should return function: %T", content);
+                       lua_pop (cfg->lua_state, 1);
+                       return FALSE;
+               }
+
+               id = luaL_ref (cfg->lua_state, LUA_REGISTRYINDEX);
+               lf->data = GINT_TO_POINTER (id);
+       }
+
+       DL_APPEND (cfg->log_format, lf);
+
+       return TRUE;
+}
+
+static gboolean
+rspamd_config_parse_log_format (struct rspamd_config *cfg)
+{
+       const gchar *p, *c, *end;
+       struct rspamd_log_format *lf = NULL;
+       rspamd_ftok_t var, var_content;
+       enum {
+               parse_str,
+               parse_dollar,
+               parse_var_name,
+               parse_var_content,
+       } state = parse_str;
+
+       g_assert (cfg != NULL);
+       c = cfg->log_format_str;
+
+       if (c == NULL) {
                return FALSE;
        }
-       close (fd);
 
-       /* Get checksum for a file */
-       cfg->checksum = g_compute_checksum_for_string (G_CHECKSUM_MD5,
-                       map,
-                       st.st_size);
-       munmap (map, st.st_size);
+       p = c;
+       end = p + strlen (p);
+
+       while (p < end) {
+               switch (state) {
+               case parse_str:
+                       if (*p == '$') {
+                               state = parse_dollar;
+                       }
+                       else {
+                               p ++;
+                       }
+                       break;
+               case parse_dollar:
+                       if (p > c) {
+                               /* We have string element that we need to store */
+                               lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
+                               lf->type = RSPAMD_LOG_STRING;
+                               lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
+                               rspamd_strlcpy (lf->data, c, p - c + 1);
+                               DL_APPEND (cfg->log_format, lf);
+                               lf = NULL;
+                       }
+                       p++;
+                       c = p;
+                       state = parse_var_name;
+                       break;
+               case parse_var_name:
+                       if (*p == '{') {
+                               var.begin = c;
+                               var.len = p - c;
+                               p ++;
+                               c = p;
+                               state = parse_var_content;
+                       }
+                       else if (g_ascii_isspace (*p)) {
+                               /* Variable with no content */
+                               var.begin = c;
+                               var.len = p - c;
+                               p++;
+                               c = p;
+
+                               if (!rspamd_config_process_var (cfg, &var, NULL)) {
+                                       return FALSE;
+                               }
+
+                               state = parse_str;
+                       }
+                       else {
+                               p++;
+                       }
+                       break;
+               case parse_var_content:
+                       if (*p == '}') {
+                               var_content.begin = c;
+                               var_content.len = p - c;
+                               p ++;
+                               c = p;
+
+                               if (!rspamd_config_process_var (cfg, &var, &var_content)) {
+                                       return FALSE;
+                               }
+
+                               state = parse_str;
+                       }
+                       else {
+                               p++;
+                       }
+                       break;
+               }
+       }
+
+       /* Last state */
+       switch (state) {
+       case parse_str:
+               if (p > c) {
+                       /* We have string element that we need to store */
+                       lf = rspamd_mempool_alloc0 (cfg->cfg_pool, sizeof (*lf));
+                       lf->type = RSPAMD_LOG_STRING;
+                       lf->data = rspamd_mempool_alloc (cfg->cfg_pool, p - c + 1);
+                       rspamd_strlcpy (lf->data, c, p - c + 1);
+                       DL_APPEND (cfg->log_format, lf);
+                       lf = NULL;
+               }
+               break;
+
+       case parse_var_name:
+               var.begin = c;
+               var.len = p - c;
+
+               if (!rspamd_config_process_var (cfg, &var, NULL)) {
+                       return FALSE;
+               }
+               break;
+       case parse_dollar:
+       case parse_var_content:
+               msg_err_config ("cannot parse log format %s: incomplete string",
+                       cfg->log_format_str);
+               return FALSE;
+               break;
+       }
 
        return TRUE;
 }
+
+
 /*
  * Perform post load actions
  */
@@ -385,6 +606,11 @@ rspamd_config_post_load (struct rspamd_config *cfg)
 
        /* Insert classifiers symbols */
        (void)rspamd_config_insert_classify_symbols (cfg);
+
+       /* Parse format string that we have */
+       if (!rspamd_config_parse_log_format (cfg)) {
+               msg_err_config ("cannot parse log format, task logging will not be available");
+       }
 }
 
 #if 0