Browse Source

* Implement ability to add conditional rules to rspamd.xml

tags/0.3.7
Vsevolod Stakhov 13 years ago
parent
commit
0bb8eff9b5
7 changed files with 170 additions and 46 deletions
  1. 1
    0
      CMakeLists.txt
  2. 2
    1
      config.h.in
  3. 6
    0
      src/cfg_utils.c
  4. 83
    39
      src/cfg_xml.c
  5. 11
    6
      src/cfg_xml.h
  6. 66
    0
      src/lua/lua_cfg_file.c
  7. 1
    0
      src/lua/lua_common.h

+ 1
- 0
CMakeLists.txt View File

@@ -354,6 +354,7 @@ CHECK_INCLUDE_FILES(sys/wait.h HAVE_SYS_WAIT_H)
CHECK_INCLUDE_FILES(sys/param.h HAVE_SYS_PARAM_H)
CHECK_INCLUDE_FILES(sys/cdefs.h HAVE_SYS_CDEFS_H)
CHECK_INCLUDE_FILES(sys/file.h HAVE_SYS_FILE_H)
CHECK_INCLUDE_FILES(sys/utsname.h HAVE_SYS_UTSNAME_H)
CHECK_INCLUDE_FILES(sys/resource.h HAVE_SYS_RESOURCE_H)
CHECK_INCLUDE_FILES(netinet/in.h HAVE_NETINET_IN_H)
CHECK_INCLUDE_FILES(arpa/inet.h HAVE_ARPA_INET_H)

+ 2
- 1
config.h.in View File

@@ -67,7 +67,8 @@
#cmakedefine HAVE_SYS_PARAM_H 1
#cmakedefine HAVE_SYS_FILE_H 1
#cmakedefine HAVE_SYS_RESOURCE_H 1
#cmakedefine HAVE_SYS_TIMEB_H 1
#cmakedefine HAVE_SYS_TIMEB_H 1
#cmakedefine HAVE_SYS_UTSNAME_H 1

#cmakedefine HAVE_PIDFILE 1


+ 6
- 0
src/cfg_utils.c View File

@@ -930,10 +930,16 @@ read_xml_config (struct config_file *cfg, const gchar *filename)
/* Prepare xml parser */
ud.cfg = cfg;
ud.state = XML_READ_START;
ud.if_stack = g_queue_new ();

ctx = g_markup_parse_context_new (&xml_parser, G_MARKUP_TREAT_CDATA_AS_TEXT | G_MARKUP_PREFIX_ERROR_POSITION, &ud, NULL);
res = g_markup_parse_context_parse (ctx, data, st.st_size, &err);

if (g_queue_get_length (ud.if_stack) != 0) {
msg_err ("unexpected nesting for if arguments");
res = FALSE;
}

munmap (data, st.st_size);

return res;

+ 83
- 39
src/cfg_xml.c View File

@@ -449,6 +449,42 @@ xml_error_quark (void)
return g_quark_from_static_string ("xml-error-quark");
}

static inline const gchar *
xml_state_to_string (struct rspamd_xml_userdata *ud)
{
switch (ud->state) {
case XML_READ_START:
return "read start tag";
case XML_READ_PARAM:
return "read param";
case XML_READ_MODULE:
return "read module section";
case XML_READ_MODULES:
return "read modules section";
case XML_READ_CLASSIFIER:
return "read classifier section";
case XML_READ_STATFILE:
return "read statfile section";
case XML_READ_METRIC:
return "read metric section";
case XML_READ_WORKER:
return "read worker section";
case XML_READ_VIEW:
return "read view section";
case XML_READ_LOGGING:
return "read logging section";
case XML_READ_VALUE:
return "read value";
case XML_SKIP_ELEMENTS:
return "skip if block";
case XML_ERROR:
return "error occured";
case XML_END:
return "read final tag";
}
/* Unreached */
return "unknown state";
}

static inline gboolean
extract_attr (const gchar *attr, const gchar **attribute_names, const gchar **attribute_values, gchar **res)
@@ -1333,8 +1369,23 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
{
struct rspamd_xml_userdata *ud = user_data;
struct classifier_config *ccf;
gchar *res;

gchar *res, *condition;

if (g_ascii_strcasecmp (element_name, "if") == 0) {
/* Push current state to queue */
g_queue_push_head (ud->if_stack, GSIZE_TO_POINTER ((gsize)ud->state));
/* Now get attributes */
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values);
if ((condition = g_hash_table_lookup (ud->cur_attrs, "condition")) == NULL) {
msg_err ("unknown condition attribute for if tag");
*error = g_error_new (xml_error_quark (), XML_PARAM_MISSING, "param 'condition' is required for tag 'if'");
ud->state = XML_ERROR;
}
if (! lua_check_condition (ud->cfg, condition)) {
ud->state = XML_SKIP_ELEMENTS;
}
return;
}
switch (ud->state) {
case XML_READ_START:
if (g_ascii_strcasecmp (element_name, "rspamd") != 0) {
@@ -1432,6 +1483,9 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values);
}
break;
case XML_SKIP_ELEMENTS:
/* Do nothing */
return;
case XML_READ_MODULE:
case XML_READ_METRIC:
case XML_READ_MODULES:
@@ -1444,7 +1498,10 @@ rspamd_xml_start_element (GMarkupParseContext *context, const gchar *element_nam
ud->cur_attrs = process_attrs (ud->cfg, attribute_names, attribute_values);
break;
default:
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is unexpected in this state", element_name);
if (*error == NULL) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is unexpected in this state %s",
element_name, xml_state_to_string (ud));
}
break;
}
}
@@ -1471,8 +1528,25 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name,
struct metric *m;
struct classifier_config *ccf;
struct statfile *st;
gboolean res;
gboolean res;
gpointer tptr;
if (g_ascii_strcasecmp (element_name, "if") == 0) {
tptr = g_queue_pop_head (ud->if_stack);

if (tptr == NULL) {
*error = g_error_new (xml_error_quark (), XML_EXTRA_ELEMENT, "element %s is umatched", element_name);
ud->state = XML_ERROR;
}
/* Restore state */
if (ud->state == XML_SKIP_ELEMENTS) {
ud->state = GPOINTER_TO_SIZE (tptr);
}
/* Skip processing */

return;
}

switch (ud->state) {
case XML_READ_MODULE:
CHECK_TAG ("module", FALSE);
@@ -1562,6 +1636,8 @@ rspamd_xml_end_element (GMarkupParseContext *context, const gchar *element_name,
ud->state = XML_ERROR;
}
break;
case XML_SKIP_ELEMENTS:
return;
default:
ud->state = XML_ERROR;
break;
@@ -1643,6 +1719,9 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len
ud->state = XML_ERROR;
}
break;
case XML_SKIP_ELEMENTS:
/* Do nothing */
return;
default:
ud->state = XML_ERROR;
break;
@@ -1650,41 +1729,6 @@ rspamd_xml_text (GMarkupParseContext *context, const gchar *text, gsize text_len

}

static inline const gchar *
xml_state_to_string (struct rspamd_xml_userdata *ud)
{
switch (ud->state) {
case XML_READ_START:
return "read start tag";
case XML_READ_PARAM:
return "read param";
case XML_READ_MODULE:
return "read module section";
case XML_READ_MODULES:
return "read modules section";
case XML_READ_CLASSIFIER:
return "read classifier section";
case XML_READ_STATFILE:
return "read statfile section";
case XML_READ_METRIC:
return "read metric section";
case XML_READ_WORKER:
return "read worker section";
case XML_READ_VIEW:
return "read view section";
case XML_READ_LOGGING:
return "read logging section";
case XML_READ_VALUE:
return "read value";
case XML_ERROR:
return "error occured";
case XML_END:
return "read final tag";
}
/* Unreached */
return "unknown state";
}

void
rspamd_xml_error (GMarkupParseContext *context, GError *error, gpointer user_data)
{

+ 11
- 6
src/cfg_xml.h View File

@@ -24,6 +24,7 @@ enum xml_read_state {
XML_READ_VIEW,
XML_READ_LOGGING,
XML_READ_VALUE,
XML_SKIP_ELEMENTS,
XML_ERROR,
XML_END
};
@@ -39,13 +40,17 @@ enum module_opt_type {
MODULE_OPT_TYPE_ANY
};

/**
* Structure that is used for semantic resolution of configuration
*/
struct rspamd_xml_userdata {
enum xml_read_state state;
struct config_file *cfg;
gchar section_name[MAX_NAME];
gpointer section_pointer;
gpointer parent_pointer;
GHashTable *cur_attrs;
enum xml_read_state state; /*< state of parser */
struct config_file *cfg; /*< configuration object */
gchar section_name[MAX_NAME]; /*< current section */
gpointer section_pointer; /*< pointer to object related with section */
gpointer parent_pointer; /*< parent's section object */
GHashTable *cur_attrs; /*< attributes of current tag */
GQueue *if_stack; /*< stack of if elements */
};

/* Text is NULL terminated here */

+ 66
- 0
src/lua/lua_cfg_file.c View File

@@ -23,6 +23,9 @@
*/

#include "lua_common.h"
#ifdef HAVE_SYS_UTSNAME_H
#include <sys/utsname.h>
#endif

/*
* This is implementation of lua routines to handle config file params
@@ -295,3 +298,66 @@ lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname, enum l
*res = NULL;
return FALSE;
}

#define FAKE_RES_VAR "rspamd_res"
gboolean
lua_check_condition (struct config_file *cfg, const gchar *condition)
{
lua_State *L = cfg->lua_state;
gchar *hostbuf, *condbuf;
gsize hostlen;
gboolean res;
#ifdef HAVE_SYS_UTSNAME_H
struct utsname uts;
#endif

/* Set some globals for condition */
/* XXX: think what other variables can be useful */
hostlen = sysconf (_SC_HOST_NAME_MAX) + 1;
hostbuf = alloca (hostlen);
gethostname (hostbuf, hostlen);
hostbuf[hostlen - 1] = '\0';

/* Hostname */
lua_pushstring (L, hostbuf);
lua_setglobal (L, "hostname");
/* Config file name */
lua_pushstring (L, cfg->cfg_name);
lua_setglobal (L, "cfg_name");
/* Check for uname */
#ifdef HAVE_SYS_UTSNAME_H
uname (&uts);
lua_pushstring (L, uts.sysname);
lua_setglobal (L, "osname");
lua_pushstring (L, uts.release);
lua_setglobal (L, "osrelease");
#else
lua_pushstring (L, "unknown");
lua_setglobal (L, "osname");
lua_pushstring (L, "");
lua_setglobal (L, "osrelease");
#endif
/* Make fake string */
hostlen = sizeof (FAKE_RES_VAR "=") + strlen (condition);
condbuf = g_malloc (hostlen);
rspamd_strlcpy (condbuf, FAKE_RES_VAR "=", sizeof (FAKE_RES_VAR "="));
g_strlcat (condbuf, condition, hostlen);
/* Evaluate condition */
if (luaL_dostring (L, condbuf) != 0) {
msg_err ("eval of '%s' failed: '%s'", condition, lua_tostring (L, -1));
g_free (condbuf);
return FALSE;
}
/* Get global variable res to get result */
lua_getglobal (L, FAKE_RES_VAR);
if (! lua_isboolean (L, -1)) {
msg_err ("bad string evaluated: %s, type: %s", condbuf, lua_typename (L, lua_type (L, -1)));
g_free (condbuf);
return FALSE;
}

res = lua_toboolean (L, -1);
g_free (condbuf);

return res;
}

+ 1
- 0
src/lua/lua_common.h View File

@@ -55,6 +55,7 @@ void lua_post_load_config (struct config_file *cfg);
void lua_process_element (struct config_file *cfg, const gchar *name, struct module_opt *opt, gint idx);
gboolean lua_handle_param (struct worker_task *task, gchar *mname, gchar *optname,
enum lua_var_type expected_type, gpointer *res);
gboolean lua_check_condition (struct config_file *cfg, const gchar *condition);


#endif /* WITH_LUA */

Loading…
Cancel
Save