diff options
author | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2008-11-01 18:01:05 +0300 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@rambler-co.ru> | 2008-11-01 18:01:05 +0300 |
commit | 2aa9c74f1c449da92f6faf870f8cc801a83bb08b (patch) | |
tree | 33f0f941f08583fd0c4c3653cadde8d6ce8426c2 /src/cfg_utils.c | |
parent | cc5343692b448c27485a24ea7f1b24d714bb82f6 (diff) | |
download | rspamd-2aa9c74f1c449da92f6faf870f8cc801a83bb08b.tar.gz rspamd-2aa9c74f1c449da92f6faf870f8cc801a83bb08b.zip |
* Reorganize structure of source files
* Adopt build system for new structure
--HG--
rename : cfg_file.h => src/cfg_file.h
rename : cfg_file.l => src/cfg_file.l
rename : cfg_file.y => src/cfg_file.y
rename : cfg_utils.c => src/cfg_utils.c
rename : controller.c => src/controller.c
rename : filter.c => src/filter.c
rename : filter.h => src/filter.h
rename : fstring.c => src/fstring.c
rename : fstring.h => src/fstring.h
rename : main.c => src/main.c
rename : main.h => src/main.h
rename : mem_pool.c => src/mem_pool.c
rename : mem_pool.h => src/mem_pool.h
rename : memcached-test.c => src/memcached-test.c
rename : memcached.c => src/memcached.c
rename : memcached.h => src/memcached.h
rename : perl.c => src/perl.c
rename : perl.h => src/perl.h
rename : plugins/regexp.c => src/plugins/regexp.c
rename : plugins/surbl.c => src/plugins/surbl.c
rename : protocol.c => src/protocol.c
rename : protocol.h => src/protocol.h
rename : upstream.c => src/upstream.c
rename : upstream.h => src/upstream.h
rename : url.c => src/url.c
rename : url.h => src/url.h
rename : util.c => src/util.c
rename : util.h => src/util.h
rename : worker.c => src/worker.c
Diffstat (limited to 'src/cfg_utils.c')
-rw-r--r-- | src/cfg_utils.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/src/cfg_utils.c b/src/cfg_utils.c new file mode 100644 index 000000000..9fa7aac47 --- /dev/null +++ b/src/cfg_utils.c @@ -0,0 +1,563 @@ +#include <sys/types.h> +#include <sys/socket.h> +#include <ctype.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <syslog.h> +#include <netdb.h> +#include <math.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "config.h" +#include "cfg_file.h" +#include "main.h" +#ifndef HAVE_OWN_QUEUE_H +#include <sys/queue.h> +#else +#include "queue.h" +#endif + +extern int yylineno; +extern char *yytext; + +int +add_memcached_server (struct config_file *cf, char *str) +{ + char *cur_tok, *err_str; + struct memcached_server *mc; + struct hostent *hent; + uint16_t port; + + if (str == NULL) return 0; + + cur_tok = strsep (&str, ":"); + + if (cur_tok == NULL || *cur_tok == '\0') return 0; + + if(cf->memcached_servers_num == MAX_MEMCACHED_SERVERS) { + yywarn ("yyparse: maximum number of memcached servers is reached %d", MAX_MEMCACHED_SERVERS); + } + + mc = &cf->memcached_servers[cf->memcached_servers_num]; + if (mc == NULL) return 0; + /* cur_tok - server name, str - server port */ + if (str == NULL) { + port = DEFAULT_MEMCACHED_PORT; + } + else { + port = (uint16_t)strtoul (str, &err_str, 10); + if (*err_str != '\0') { + return 0; + } + } + + if (!inet_aton (cur_tok, &mc->addr)) { + /* Try to call gethostbyname */ + hent = gethostbyname (cur_tok); + if (hent == NULL) { + return 0; + } + else { + memcpy((char *)&mc->addr, hent->h_addr, sizeof(struct in_addr)); + } + } + mc->port = port; + cf->memcached_servers_num++; + return 1; +} + +int +parse_bind_line (struct config_file *cf, char *str, char is_control) +{ + char *cur_tok, *err_str; + struct hostent *hent; + size_t s; + + if (str == NULL) return 0; + cur_tok = strsep (&str, ":"); + + if (cur_tok[0] == '/' || cur_tok[0] == '.') { + if (is_control) { + cf->control_host = memory_pool_strdup (cf->cfg_pool, cur_tok); + cf->control_family = AF_UNIX; + } + else { + cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok); + cf->bind_family = AF_UNIX; + } + return 1; + + } else { + if (str == '\0') { + if (is_control) { + cf->control_port = DEFAULT_CONTROL_PORT; + } + else { + cf->bind_port = DEFAULT_BIND_PORT; + } + } + else { + if (is_control) { + cf->control_port = (uint16_t)strtoul (str, &err_str, 10); + } + else { + cf->bind_port = (uint16_t)strtoul (str, &err_str, 10); + } + if (*err_str != '\0') { + return 0; + } + } + + if (is_control) { + if (!inet_aton (cur_tok, &cf->control_addr)) { + /* Try to call gethostbyname */ + hent = gethostbyname (cur_tok); + if (hent == NULL) { + return 0; + } + else { + cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok); + memcpy((char *)&cf->control_addr, hent->h_addr, sizeof(struct in_addr)); + s = strlen (cur_tok) + 1; + } + } + + cf->control_family = AF_INET; + } + else { + if (!inet_aton (cur_tok, &cf->bind_addr)) { + /* Try to call gethostbyname */ + hent = gethostbyname (cur_tok); + if (hent == NULL) { + return 0; + } + else { + cf->bind_host = memory_pool_strdup (cf->cfg_pool, cur_tok); + memcpy((char *)&cf->bind_addr, hent->h_addr, sizeof(struct in_addr)); + s = strlen (cur_tok) + 1; + } + } + + cf->bind_family = AF_INET; + } + + return 1; + } + + return 0; +} + +void +init_defaults (struct config_file *cfg) +{ + cfg->memcached_error_time = DEFAULT_UPSTREAM_ERROR_TIME; + cfg->memcached_dead_time = DEFAULT_UPSTREAM_DEAD_TIME; + cfg->memcached_maxerrors = DEFAULT_UPSTREAM_MAXERRORS; + cfg->memcached_protocol = TCP_TEXT; + + cfg->workers_number = DEFAULT_WORKERS_NUM; + cfg->modules_opts = g_hash_table_new (g_str_hash, g_str_equal); + cfg->variables = g_hash_table_new (g_str_hash, g_str_equal); + cfg->metrics = g_hash_table_new (g_str_hash, g_str_equal); + cfg->factors = g_hash_table_new (g_str_hash, g_str_equal); + cfg->c_modules = g_hash_table_new (g_str_hash, g_str_equal); + cfg->composite_symbols = g_hash_table_new (g_str_hash, g_str_equal); + + LIST_INIT (&cfg->perl_modules); +} + +void +free_config (struct config_file *cfg) +{ + g_hash_table_remove_all (cfg->modules_opts); + g_hash_table_unref (cfg->modules_opts); + g_hash_table_remove_all (cfg->variables); + g_hash_table_unref (cfg->variables); + g_hash_table_remove_all (cfg->metrics); + g_hash_table_unref (cfg->metrics); + g_hash_table_remove_all (cfg->factors); + g_hash_table_unref (cfg->factors); + g_hash_table_remove_all (cfg->c_modules); + g_hash_table_unref (cfg->c_modules); + g_hash_table_remove_all (cfg->composite_symbols); + g_hash_table_unref (cfg->composite_symbols); + memory_pool_delete (cfg->cfg_pool); +} + +char* +get_module_opt (struct config_file *cfg, char *module_name, char *opt_name) +{ + LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = NULL; + struct module_opt *cur; + + cur_module_opt = g_hash_table_lookup (cfg->modules_opts, module_name); + if (cur_module_opt == NULL) { + return NULL; + } + + LIST_FOREACH (cur, cur_module_opt, next) { + if (strcmp (cur->param, opt_name) == 0) { + return cur->value; + } + } + + return NULL; +} + +size_t +parse_limit (const char *limit) +{ + size_t result = 0; + char *err_str; + + if (!limit || *limit == '\0') return 0; + + result = strtoul (limit, &err_str, 10); + + if (*err_str != '\0') { + /* Megabytes */ + if (*err_str == 'm' || *err_str == 'M') { + result *= 1048576L; + } + /* Kilobytes */ + else if (*err_str == 'k' || *err_str == 'K') { + result *= 1024; + } + /* Gigabytes */ + else if (*err_str == 'g' || *err_str == 'G') { + result *= 1073741824L; + } + } + + return result; +} + +unsigned int +parse_seconds (const char *t) +{ + unsigned int result = 0; + char *err_str; + + if (!t || *t == '\0') return 0; + + result = strtoul (t, &err_str, 10); + + if (*err_str != '\0') { + /* Seconds */ + if (*err_str == 's' || *err_str == 'S') { + result *= 1000; + } + } + + return result; +} + +char +parse_flag (const char *str) +{ + if (!str || !*str) return -1; + + if ((*str == 'Y' || *str == 'y') && *(str + 1) == '\0') { + return 1; + } + + if ((*str == 'Y' || *str == 'y') && + (*(str + 1) == 'E' || *(str + 1) == 'e') && + (*(str + 2) == 'S' || *(str + 2) == 's') && + *(str + 3) == '\0') { + return 1; + } + + if ((*str == 'N' || *str == 'n') && *(str + 1) == '\0') { + return 0; + } + + if ((*str == 'N' || *str == 'n') && + (*(str + 1) == 'O' || *(str + 1) == 'o') && + *(str + 2) == '\0') { + return 0; + } + + return -1; +} + +/* + * Try to substitute all variables in given string + * Return: newly allocated string with substituted variables (original string may be freed if variables are found) + */ +char * +substitute_variable (struct config_file *cfg, char *str, u_char recursive) +{ + char *var, *new, *v_begin, *v_end; + size_t len; + + while ((v_begin = strstr (str, "${")) != NULL) { + len = strlen (str); + *v_begin = '\0'; + v_begin += 2; + if ((v_end = strstr (v_begin, "}")) == NULL) { + /* Not a variable, skip */ + continue; + } + *v_end = '\0'; + var = g_hash_table_lookup (cfg->variables, v_begin); + if (var == NULL) { + yywarn ("substitute_variable: variable %s is not defined", v_begin); + /* Substitute unknown variables with empty string */ + var = ""; + } + else if (recursive) { + var = substitute_variable (cfg, var, recursive); + } + /* Allocate new string */ + new = memory_pool_alloc (cfg->cfg_pool, len - strlen (v_begin) + strlen (var) + 1); + + snprintf (new, len - strlen (v_begin) + strlen (var) + 1, "%s%s%s", + str, var, v_end + 1); + str = new; + } + + return str; +} + +static void +substitute_module_variables (gpointer key, gpointer value, gpointer data) +{ + struct config_file *cfg = (struct config_file *)data; + LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = (struct moduleoptq *)value; + struct module_opt *cur, *tmp; + + LIST_FOREACH_SAFE (cur, cur_module_opt, next, tmp) { + if (cur->value) { + cur->value = substitute_variable (cfg, cur->value, 0); + } + } +} + +static void +substitute_all_variables (gpointer key, gpointer value, gpointer data) +{ + struct config_file *cfg = (struct config_file *)data; + char *var; + + var = value; + /* Do recursive substitution */ + var = substitute_variable (cfg, var, 1); +} + +static void +parse_filters_str (struct config_file *cfg, const char *str, enum script_type type) +{ + gchar **strvec, **p; + struct filter *cur; + int i; + + if (str == NULL) { + return; + } + + strvec = g_strsplit (str, ",", 0); + if (strvec == NULL) { + return; + } + + p = strvec; + while (*p++) { + cur = NULL; + /* Search modules from known C modules */ + for (i = 0; i < MODULES_NUM; i++) { + if (strcasecmp (modules[i].name, *p) == 0) { + cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter)); + cur->type = C_FILTER; + switch (type) { + case SCRIPT_HEADER: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->header_filters, cur, next); + break; + case SCRIPT_MIME: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->mime_filters, cur, next); + break; + case SCRIPT_MESSAGE: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->message_filters, cur, next); + break; + case SCRIPT_URL: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->url_filters, cur, next); + break; + } + break; + } + } + if (cur != NULL) { + /* Go to next iteration */ + continue; + } + cur = memory_pool_alloc (cfg->cfg_pool, sizeof (struct filter)); + cur->type = PERL_FILTER; + switch (type) { + case SCRIPT_HEADER: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->header_filters, cur, next); + break; + case SCRIPT_MIME: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->mime_filters, cur, next); + break; + case SCRIPT_MESSAGE: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->message_filters, cur, next); + break; + case SCRIPT_URL: + cur->func_name = memory_pool_strdup (cfg->cfg_pool, *p); + LIST_INSERT_HEAD (&cfg->url_filters, cur, next); + break; + } + } + + g_strfreev (strvec); +} + +/* + * Substitute all variables in strings + */ +void +post_load_config (struct config_file *cfg) +{ + g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg); + g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg); + parse_filters_str (cfg, cfg->header_filters_str, SCRIPT_HEADER); + parse_filters_str (cfg, cfg->mime_filters_str, SCRIPT_MIME); + parse_filters_str (cfg, cfg->message_filters_str, SCRIPT_MESSAGE); + parse_filters_str (cfg, cfg->url_filters_str, SCRIPT_URL); +} + +/* + * Rspamd regexp utility functions + */ +struct rspamd_regexp* +parse_regexp (memory_pool_t *pool, char *line) +{ + char *begin, *end, *p; + struct rspamd_regexp *result; + int regexp_flags = 0; + enum rspamd_regexp_type type = REGEXP_NONE; + GError *err = NULL; + + result = memory_pool_alloc0 (pool, sizeof (struct rspamd_regexp)); + /* First try to find header name */ + begin = strchr (line, '='); + if (begin != NULL) { + *begin = '\0'; + result->header = memory_pool_strdup (pool, line); + result->type = REGEXP_HEADER; + *begin = '='; + line = begin; + } + /* Find begin of regexp */ + while (*line != '/') { + line ++; + } + if (*line != '\0') { + begin = line + 1; + } + else if (result->header == NULL) { + /* Assume that line without // is just a header name */ + result->header = memory_pool_strdup (pool, line); + result->type = REGEXP_HEADER; + return result; + } + else { + /* We got header name earlier but have not found // expression, so it is invalid regexp */ + return NULL; + } + /* Find end */ + end = begin; + while (*end && (*end != '/' || *(end - 1) == '\\')) { + end ++; + } + if (end == begin || *end != '/') { + return NULL; + } + /* Parse flags */ + p = end + 1; + while (p != NULL) { + switch (*p) { + case 'i': + regexp_flags |= G_REGEX_CASELESS; + p ++; + break; + case 'm': + regexp_flags |= G_REGEX_MULTILINE; + p ++; + break; + case 's': + regexp_flags |= G_REGEX_DOTALL; + p ++; + break; + case 'x': + regexp_flags |= G_REGEX_EXTENDED; + p ++; + break; + case 'u': + regexp_flags |= G_REGEX_UNGREEDY; + p ++; + break; + case 'o': + regexp_flags |= G_REGEX_OPTIMIZE; + p ++; + break; + /* Type flags */ + case 'H': + if (type != REGEXP_NONE) { + type = REGEXP_HEADER; + } + p ++; + break; + case 'M': + if (type != REGEXP_NONE) { + type = REGEXP_MESSAGE; + } + p ++; + break; + case 'P': + if (type != REGEXP_NONE) { + type = REGEXP_MIME; + } + p ++; + break; + case 'U': + if (type != REGEXP_NONE) { + type = REGEXP_URL; + } + p ++; + break; + /* Stop flags parsing */ + default: + p = NULL; + break; + } + } + + result = memory_pool_alloc (pool, sizeof (struct rspamd_regexp)); + result->type = type; + *end = '\0'; + result->regexp = g_regex_new (begin, regexp_flags, 0, &err); + result->regexp_text = memory_pool_strdup (pool, begin); + memory_pool_add_destructor (pool, (pool_destruct_func)g_regex_unref, (void *)result->regexp); + *end = '/'; + + return result; +} + +/* + * vi:ts=4 + */ |