Преглед изворни кода

* Add dkim check plugin.

tags/0.5.0
Vsevolod Stakhov пре 12 година
родитељ
комит
61b06ca037
1 измењених фајлова са 247 додато и 0 уклоњено
  1. 247
    0
      src/plugins/dkim_check.c

+ 247
- 0
src/plugins/dkim_check.c Прегледај датотеку

@@ -0,0 +1,247 @@
/* Copyright (c) 2010-2011, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


/***MODULE:spf
* rspamd module that checks spf records of incoming email
*
* Allowed options:
* - symbol_allow (string): symbol to insert (default: 'R_SPF_ALLOW')
* - symbol_fail (string): symbol to insert (default: 'R_SPF_FAIL')
* - symbol_softfail (string): symbol to insert (default: 'R_SPF_SOFTFAIL')
* - whitelist (map): map of whitelisted networks
*/

#include "config.h"
#include "main.h"
#include "message.h"
#include "cfg_file.h"
#include "expressions.h"
#include "util.h"
#include "view.h"
#include "map.h"
#include "dkim.h"
#include "cfg_xml.h"
#include "hash.h"

#define DEFAULT_SYMBOL_REJECT "R_DKIM_REJECT"
#define DEFAULT_SYMBOL_TEMPFAIL "R_DKIM_TEMPFAIL"
#define DEFAULT_SYMBOL_ALLOW "R_DKIM_ALLOW"
#define DEFAULT_CACHE_SIZE 2048
#define DEFAULT_CACHE_MAXAGE 86400

struct dkim_ctx {
gint (*filter) (struct worker_task * task);
gchar *symbol_reject;
gchar *symbol_tempfail;
gchar *symbol_allow;

memory_pool_t *dkim_pool;
radix_tree_t *whitelist_ip;
GHashTable *dkim_domains;
rspamd_lru_hash_t *dkim_hash;
};

static struct dkim_ctx *dkim_module_ctx = NULL;

static void dkim_symbol_callback (struct worker_task *task, void *unused);

/* Initialization */
gint dkim_module_init (struct config_file *cfg, struct module_ctx **ctx);
gint dkim_module_config (struct config_file *cfg);
gint dkim_module_reconfig (struct config_file *cfg);

module_t dkim_module = {
"dkim",
dkim_module_init,
dkim_module_config,
dkim_module_reconfig
};

gint
dkim_module_init (struct config_file *cfg, struct module_ctx **ctx)
{
dkim_module_ctx = g_malloc0 (sizeof (struct dkim_ctx));

dkim_module_ctx->dkim_pool = memory_pool_new (memory_pool_get_size ());

*ctx = (struct module_ctx *)dkim_module_ctx;
register_module_opt ("dkim", "symbol_reject", MODULE_OPT_TYPE_STRING);
register_module_opt ("dkim", "symbol_tempfail", MODULE_OPT_TYPE_STRING);
register_module_opt ("dkim", "symbol_allow", MODULE_OPT_TYPE_STRING);
register_module_opt ("dkim", "dkim_cache_size", MODULE_OPT_TYPE_UINT);
register_module_opt ("dkim", "dkim_cache_expire", MODULE_OPT_TYPE_TIME);
register_module_opt ("dkim", "whitelist", MODULE_OPT_TYPE_MAP);
register_module_opt ("dkim", "domains", MODULE_OPT_TYPE_MAP);

return 0;
}

gint
dkim_module_config (struct config_file *cfg)
{
gchar *value;
gint res = TRUE;
guint cache_size, cache_expire;

dkim_module_ctx->whitelist_ip = radix_tree_create ();

if ((value = get_module_opt (cfg, "dkim", "symbol_reject")) != NULL) {
dkim_module_ctx->symbol_reject = memory_pool_strdup (dkim_module_ctx->dkim_pool, value);
}
else {
dkim_module_ctx->symbol_reject = DEFAULT_SYMBOL_REJECT;
}
if ((value = get_module_opt (cfg, "dkim", "symbol_tempfail")) != NULL) {
dkim_module_ctx->symbol_tempfail = memory_pool_strdup (dkim_module_ctx->dkim_pool, value);
}
else {
dkim_module_ctx->symbol_tempfail = DEFAULT_SYMBOL_TEMPFAIL;
}
if ((value = get_module_opt (cfg, "dkim", "symbol_allow")) != NULL) {
dkim_module_ctx->symbol_allow = memory_pool_strdup (dkim_module_ctx->dkim_pool, value);
}
else {
dkim_module_ctx->symbol_allow = DEFAULT_SYMBOL_ALLOW;
}
if ((value = get_module_opt (cfg, "dkim", "dkim_cache_size")) != NULL) {
cache_size = strtoul (value, NULL, 10);
}
else {
cache_size = DEFAULT_CACHE_SIZE;
}
if ((value = get_module_opt (cfg, "dkim", "dkim_cache_expire")) != NULL) {
cache_expire = cfg_parse_time (value, TIME_SECONDS) / 1000;
}
else {
cache_expire = DEFAULT_CACHE_MAXAGE;
}
if ((value = get_module_opt (cfg, "dkim", "whitelist")) != NULL) {
if (! add_map (value, read_radix_list, fin_radix_list, (void **)&dkim_module_ctx->whitelist_ip)) {
msg_warn ("cannot load whitelist from %s", value);
}
}
if ((value = get_module_opt (cfg, "dkim", "domains")) != NULL) {
if (! add_map (value, read_host_list, fin_host_list, (void **)&dkim_module_ctx->dkim_domains)) {
msg_warn ("cannot load domains list from %s", value);
}
}

register_symbol (&cfg->cache, dkim_module_ctx->symbol_reject, 1, dkim_symbol_callback, NULL);
register_virtual_symbol (&cfg->cache, dkim_module_ctx->symbol_tempfail, 1);
register_virtual_symbol (&cfg->cache, dkim_module_ctx->symbol_allow, 1);

dkim_module_ctx->dkim_hash = rspamd_lru_hash_new (rspamd_strcase_hash, rspamd_strcase_equal,
cache_size, cache_expire, g_free, (GDestroyNotify)rspamd_dkim_key_free);

return res;
}

gint
dkim_module_reconfig (struct config_file *cfg)
{
memory_pool_delete (dkim_module_ctx->dkim_pool);
radix_tree_free (dkim_module_ctx->whitelist_ip);
if (dkim_module_ctx->dkim_domains) {
g_hash_table_destroy (dkim_module_ctx->dkim_domains);
}
dkim_module_ctx->dkim_pool = memory_pool_new (memory_pool_get_size ());

return dkim_module_config (cfg);
}

static void
dkim_module_check (struct worker_task *task, rspamd_dkim_context_t *ctx, rspamd_dkim_key_t *key)
{
gint res;

msg_debug ("check dkim signature for %s domain", ctx->dns_key);
res = rspamd_dkim_check (ctx, key, task);

if (res == DKIM_REJECT) {
insert_result (task, dkim_module_ctx->symbol_reject, 1, NULL);
}
else if (res == DKIM_TRYAGAIN) {
insert_result (task, dkim_module_ctx->symbol_tempfail, 1, NULL);
}
else if (res == DKIM_CONTINUE) {
insert_result (task, dkim_module_ctx->symbol_allow, 1, NULL);
}
}

static void
dkim_module_key_handler (rspamd_dkim_key_t *key, gsize keylen, rspamd_dkim_context_t *ctx, gpointer ud, GError *err)
{
struct worker_task *task = ud;


if (key != NULL) {
/* Add new key to the lru cache */
rspamd_lru_hash_insert (dkim_module_ctx->dkim_hash, g_strdup (ctx->dns_key), key, task->tv.tv_sec);
dkim_module_check (task, ctx, key);
}
else {
/* Insert tempfail symbol */
insert_result (task, dkim_module_ctx->symbol_tempfail, 1, NULL);
}
}

static void
dkim_symbol_callback (struct worker_task *task, void *unused)
{
GList *hlist;
rspamd_dkim_context_t *ctx;
rspamd_dkim_key_t *key;
GError *err = NULL;
/* First check if a message has its signature */

hlist = message_get_header (task->task_pool, task->message, DKIM_SIGNHEADER, FALSE);
if (hlist != NULL) {
/* Check whitelist */
msg_debug ("dkim signature found");
#ifdef HAVE_INET_PTON
if (!task->from_addr.has_addr ||
radix32tree_find (dkim_module_ctx->whitelist_ip, ntohl (task->from_addr.d.in4.s_addr)) == RADIX_NO_VALUE) {
#else
if (radix32tree_find (dkim_module_ctx->whitelist_ip, ntohl (task->from_addr.s_addr)) == RADIX_NO_VALUE) {
#endif
/* Parse signature */
msg_debug ("create dkim signature");
ctx = rspamd_create_dkim_context (hlist->data, task->task_pool, &err);
if (ctx == NULL) {
msg_info ("cannot parse DKIM context: %s", err->message);
g_error_free (err);
}
else {
/* Get key */
key = rspamd_lru_hash_lookup (dkim_module_ctx->dkim_hash, ctx->dns_key, task->tv.tv_sec);
if (key != NULL) {
dkim_module_check (task, ctx, key);
}
else {
rspamd_get_dkim_key (ctx, task->resolver, task->s, dkim_module_key_handler, task);
}
}
}
}
}

Loading…
Откажи
Сачувај