void rspamd_stat_close (void) { struct rspamd_classifier *cl; struct rspamd_statfile *st; struct rspamd_stat_ctx *st_ctx; struct rspamd_stat_async_elt *aelt; GList *cur; guint i, j; gint id; st_ctx = rspamd_stat_get_ctx (); g_assert (st_ctx != NULL); for (i = 0; i < st_ctx->classifiers->len; i ++) { cl = g_ptr_array_index (st_ctx->classifiers, i); for (j = 0; j < cl->statfiles_ids->len; j ++) { id = g_array_index (cl->statfiles_ids, gint, j); st = g_ptr_array_index (st_ctx->statfiles, id); st->backend->close (st->bkcf); g_slice_free1 (sizeof (*st), st); } if (cl->cache && cl->cachecf) { cl->cache->close (cl->cachecf); } g_array_free (cl->statfiles_ids, TRUE); g_slice_free1 (sizeof (*cl), cl); } cur = st_ctx->async_elts->head; while (cur) { aelt = cur->data; REF_RELEASE (aelt); cur = g_list_next (cur); } g_queue_free (stat_ctx->async_elts); g_ptr_array_free (st_ctx->statfiles, TRUE); g_ptr_array_free (st_ctx->classifiers, TRUE); REF_RELEASE (stat_ctx->cfg); g_slice_free1 (sizeof (*st_ctx), st_ctx); /* Set global var to NULL */ stat_ctx = NULL; }
static void rspamd_symbols_cache_order_unref (gpointer p) { struct symbols_cache_order *ord = p; REF_RELEASE (ord); }
static int http_map_read (struct rspamd_http_connection *conn, struct rspamd_http_message *msg, const gchar *chunk, gsize len) { struct http_callback_data *cbd = conn->ud; rspamd_mempool_t *pool; if (msg->code != 200 || len == 0) { /* Ignore not full replies */ return 0; } pool = cbd->map->pool; if (write (cbd->out_fd, chunk, len) == -1) { msg_err_pool ("cannot write to %s: %s", cbd->tmpfile, strerror (errno)); REF_RELEASE (cbd); return -1; } return 0; }
static void rspamd_fuzzy_redis_session_dtor (struct rspamd_fuzzy_redis_session *session) { redisAsyncContext *ac; guint i; if (session->ctx) { ac = session->ctx; session->ctx = NULL; rspamd_redis_pool_release_connection (session->backend->pool, ac, FALSE); } if (event_get_base (&session->timeout)) { event_del (&session->timeout); } if (session->argv) { for (i = 0; i < session->nargs; i ++) { g_free (session->argv[i]); } g_free (session->argv); } REF_RELEASE (session->backend); g_slice_free1 (sizeof (*session), session); }
void rspamd_re_cache_unref (struct rspamd_re_cache *cache) { if (cache) { REF_RELEASE (cache); } }
void rspamd_fuzzy_backend_close_redis (struct rspamd_fuzzy_backend *bk, void *subr_ud) { struct rspamd_fuzzy_backend_redis *backend = subr_ud; g_assert (backend != NULL); REF_RELEASE (backend); }
void rspamd_re_cache_runtime_destroy (struct rspamd_re_runtime *rt) { g_assert (rt != NULL); g_slice_free1 (NBYTES (rt->cache->nre), rt->checked); g_slice_free1 (rt->cache->nre, rt->results); REF_RELEASE (rt->cache); g_slice_free1 (sizeof (*rt), rt); }
void rspamd_symbols_cache_destroy (struct symbols_cache *cache) { GList *cur; struct delayed_cache_dependency *ddep; struct delayed_cache_condition *dcond; if (cache != NULL) { if (cache->cfg->cache_filename) { /* Try to sync values to the disk */ if (!rspamd_symbols_cache_save_items (cache, cache->cfg->cache_filename)) { msg_err_cache ("cannot save cache data to %s", cache->cfg->cache_filename); } } if (cache->delayed_deps) { cur = cache->delayed_deps; while (cur) { ddep = cur->data; g_free (ddep->from); g_free (ddep->to); g_slice_free1 (sizeof (*ddep), ddep); cur = g_list_next (cur); } g_list_free (cache->delayed_deps); } if (cache->delayed_conditions) { cur = cache->delayed_conditions; while (cur) { dcond = cur->data; g_free (dcond->sym); g_slice_free1 (sizeof (*dcond), dcond); cur = g_list_next (cur); } g_list_free (cache->delayed_conditions); } g_hash_table_destroy (cache->items_by_symbol); rspamd_mempool_delete (cache->static_pool); g_ptr_array_free (cache->items_by_id, TRUE); REF_RELEASE (cache->items_by_order); g_slice_free1 (sizeof (*cache), cache); } }
/* * HTTP callbacks */ static void http_map_error (struct rspamd_http_connection *conn, GError *err) { struct http_callback_data *cbd = conn->ud; rspamd_mempool_t *pool; pool = cbd->map->pool; msg_err_pool ("connection with http server terminated incorrectly: %s", err->message); REF_RELEASE (cbd); }
static void rspamd_map_dns_callback (struct rdns_reply *reply, void *arg) { struct http_callback_data *cbd = arg; rspamd_mempool_t *pool; pool = cbd->map->pool; if (reply->code == RDNS_RC_NOERROR) { /* * We just get the first address hoping that a resolver performs * round-robin rotation well */ if (cbd->addr == NULL) { cbd->addr = rspamd_inet_address_from_rnds (reply->entries); if (cbd->addr != NULL) { rspamd_inet_address_set_port (cbd->addr, cbd->data->port); /* Try to open a socket */ cbd->fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE); if (cbd->fd != -1) { cbd->stage = map_load_file; cbd->conn = rspamd_http_connection_new (http_map_read, http_map_error, http_map_finish, RSPAMD_HTTP_BODY_PARTIAL|RSPAMD_HTTP_CLIENT_SIMPLE, RSPAMD_HTTP_CLIENT, NULL); write_http_request (cbd); } else { rspamd_inet_address_destroy (cbd->addr); cbd->addr = NULL; } } } } else if (cbd->stage < map_load_file) { if (cbd->stage == map_resolve_host2) { /* We have still one request pending */ cbd->stage = map_resolve_host1; } else { /* We could not resolve host, so cowardly fail here */ msg_err_pool ("cannot resolve %s", cbd->data->host); } } REF_RELEASE (cbd); }
void rmilter_session_close (struct rmilter_session *s) { msg_debug_session ("closing session: %p", s); if (s->m->cb->close) { s->m->cb->close (s, s->ud); } s->m->async->del_read (s->read_ev, s->m->async->data); s->m->async->del_timer (s->timeout_ev, s->m->async->data); /* Release reference that is handled by milter itself */ REF_RELEASE (s); }
static void rspamd_symbols_cache_resort (struct symbols_cache *cache) { struct symbols_cache_order *ord; guint i; gpointer p; ord = rspamd_symbols_cache_order_new (cache->used_items); for (i = 0; i < cache->used_items; i ++) { p = g_ptr_array_index (cache->items_by_id, i); g_ptr_array_add (ord->d, p); } g_ptr_array_sort_with_data (ord->d, cache_logic_cmp, cache); if (cache->items_by_order) { REF_RELEASE (cache->items_by_order); } cache->items_by_order = ord; }
int main (int argc, char **argv) { gint i, start = 1, mode = MODE_NORMAL; struct rspamd_config *cfg; rspamd_logger_t *logger = NULL; if (argc > 2 && *argv[1] == '-') { start = 2; if (argv[1][1] == 'g') { mode = MODE_GMIME; } } cfg = rspamd_config_new (); cfg->libs_ctx = rspamd_init_libs (); cfg->log_type = RSPAMD_LOG_CONSOLE; rspamd_set_logger (cfg, g_quark_from_static_string ("mime"), &logger, NULL); (void) rspamd_log_open (logger); g_log_set_default_handler (rspamd_glib_log_function, logger); g_set_printerr_handler (rspamd_glib_printerr_function); rspamd_config_post_load (cfg, RSPAMD_CONFIG_INIT_LIBS|RSPAMD_CONFIG_INIT_URL|RSPAMD_CONFIG_INIT_NO_TLD); for (i = start; i < argc; i ++) { if (argv[i]) { rspamd_process_file (cfg, argv[i], mode); } } rspamd_printf ("Total time parsing: %.4f seconds\n", total_time); rspamd_log_close (logger); REF_RELEASE (cfg); return 0; }
static int http_map_finish (struct rspamd_http_connection *conn, struct rspamd_http_message *msg) { struct http_callback_data *cbd = conn->ud; struct rspamd_map *map; rspamd_mempool_t *pool; char fpath[PATH_MAX]; guchar *aux_data, *in = NULL; gsize inlen = 0; struct stat st; map = cbd->map; pool = cbd->map->pool; if (msg->code == 200) { if (cbd->stage == map_load_file) { if (msg->last_modified) { cbd->data->last_checked = msg->last_modified; } else { cbd->data->last_checked = msg->date; } /* Maybe we need to check signature ? */ if (map->is_signed) { close (cbd->out_fd); if (map->trusted_pubkey) { /* No need to load key */ cbd->stage = map_load_signature; cbd->pk = rspamd_pubkey_ref (map->trusted_pubkey); rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile); } else { rspamd_snprintf (fpath, sizeof (fpath), "%s.pub", cbd->tmpfile); cbd->stage = map_load_pubkey; } cbd->out_fd = rspamd_file_xopen (fpath, O_RDWR|O_CREAT, 00644); if (cbd->out_fd == -1) { msg_err_pool ("cannot open pubkey file %s for writing: %s", fpath, strerror (errno)); goto end; } rspamd_http_connection_reset (cbd->conn); write_http_request (cbd); goto end; } else { /* Unsinged version - just open file */ in = rspamd_file_xmap (cbd->tmpfile, PROT_READ, &inlen); if (in == NULL) { msg_err_pool ("cannot read tempfile %s: %s", cbd->tmpfile, strerror (errno)); goto end; } } } else if (cbd->stage == map_load_pubkey) { /* We now can load pubkey */ (void)lseek (cbd->out_fd, 0, SEEK_SET); if (fstat (cbd->out_fd, &st) == -1) { msg_err_pool ("cannot stat pubkey file %s: %s", fpath, strerror (errno)); goto end; } aux_data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, cbd->out_fd, 0); close (cbd->out_fd); cbd->out_fd = -1; if (aux_data == MAP_FAILED) { msg_err_pool ("cannot map pubkey file %s: %s", fpath, strerror (errno)); goto end; } cbd->pk = rspamd_pubkey_from_base32 (aux_data, st.st_size, RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519); munmap (aux_data, st.st_size); if (cbd->pk == NULL) { msg_err_pool ("cannot load pubkey file %s: bad pubkey", fpath); goto end; } rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile); cbd->out_fd = rspamd_file_xopen (fpath, O_RDWR|O_CREAT, 00644); if (cbd->out_fd == -1) { msg_err_pool ("cannot open signature file %s for writing: %s", fpath, strerror (errno)); goto end; } cbd->stage = map_load_signature; rspamd_http_connection_reset (cbd->conn); write_http_request (cbd); goto end; } else if (cbd->stage == map_load_signature) { /* We can now check signature */ close (cbd->out_fd); cbd->out_fd = -1; in = rspamd_file_xmap (cbd->tmpfile, PROT_READ, &inlen); if (in == NULL) { msg_err_pool ("cannot read tempfile %s: %s", cbd->tmpfile, strerror (errno)); goto end; } if (!rspamd_map_check_sig_pk (cbd->tmpfile, map, in, inlen, cbd->pk)) { goto end; } } g_assert (in != NULL); map->read_callback (map->pool, in, inlen, &cbd->cbdata, TRUE); map->fin_callback (map->pool, &cbd->cbdata); *map->user_data = cbd->cbdata.cur_data; msg_info_pool ("read map data from %s", cbd->data->host); } else if (msg->code == 304 && cbd->stage == map_load_file) { msg_debug_pool ("data is not modified for server %s", cbd->data->host); if (msg->last_modified) { cbd->data->last_checked = msg->last_modified; } else { cbd->data->last_checked = msg->date; } } else { msg_info_pool ("cannot load map %s from %s: HTTP error %d", map->uri, cbd->data->host, msg->code); } end: REF_RELEASE (cbd); return 0; }
void rspamd_regexp_unref (rspamd_regexp_t *re) { REF_RELEASE (re); }
gint main (gint argc, gchar **argv, gchar **env) { GError *error = NULL; GOptionContext *context; GOptionGroup *og; struct rspamd_config *cfg; GQuark process_quark; gchar **nargv, **targv; const gchar *cmd_name; const struct rspamadm_command *cmd; gint i, nargc, targc; ucl_vars = g_hash_table_new_full (rspamd_strcase_hash, rspamd_strcase_equal, g_free, g_free); process_quark = g_quark_from_static_string ("rspamadm"); cfg = rspamd_config_new (); cfg->libs_ctx = rspamd_init_libs (); rspamd_main = g_malloc0 (sizeof (*rspamd_main)); rspamd_main->cfg = cfg; rspamd_main->pid = getpid (); rspamd_main->type = process_quark; rspamd_main->server_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "rspamadm"); cfg->log_level = G_LOG_LEVEL_WARNING; cfg->log_type = RSPAMD_LOG_CONSOLE; rspamd_set_logger (cfg, process_quark, rspamd_main); (void) rspamd_log_open (rspamd_main->logger); g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger); g_set_printerr_handler (rspamd_glib_printerr_function); rspamd_config_post_load (cfg, FALSE); /* Setup logger */ if (verbose) { cfg->log_level = G_LOG_LEVEL_DEBUG; } else { cfg->log_level = G_LOG_LEVEL_INFO; } gperf_profiler_init (cfg, "rspamadm"); setproctitle ("rspamdadm"); /* Now read options and store everything till the first non-dash argument */ nargv = g_malloc0 (sizeof (gchar *) * (argc + 1)); nargv[0] = g_strdup (argv[0]); for (i = 1, nargc = 1; i < argc; i ++) { if (argv[i] && argv[i][0] == '-') { /* Copy to nargv */ nargv[nargc] = g_strdup (argv[i]); nargc ++; } else { break; } } context = g_option_context_new ("command - rspamd administration utility"); og = g_option_group_new ("global", "global options", "global options", NULL, NULL); g_option_context_set_help_enabled (context, FALSE); g_option_group_add_entries (og, entries); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_set_main_group (context, og); targv = nargv; targc = nargc; if (!g_option_context_parse (context, &targc, &targv, &error)) { fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } g_strfreev (nargv); if (show_version) { rspamadm_version (); exit (EXIT_SUCCESS); } if (show_help) { rspamadm_usage (context); exit (EXIT_SUCCESS); } if (list_commands) { rspamadm_commands (); exit (EXIT_SUCCESS); } cmd_name = argv[nargc]; if (cmd_name == NULL) { cmd_name = "help"; } cmd = rspamadm_search_command (cmd_name); if (cmd == NULL) { fprintf (stderr, "Invalid command name: %s\n", cmd_name); exit (EXIT_FAILURE); } if (nargc < argc) { nargv = g_malloc0 (sizeof (gchar *) * (argc - nargc + 1)); nargv[0] = g_strdup_printf ("%s %s", argv[0], cmd_name); for (i = 1; i < argc - nargc; i ++) { nargv[i] = g_strdup (argv[i + nargc]); } targc = argc - nargc; targv = nargv; cmd->run (targc, targv); g_strfreev (nargv); } else { cmd->run (0, NULL); } rspamd_log_close (rspamd_main->logger); REF_RELEASE (rspamd_main->cfg); g_free (rspamd_main); return 0; }
void rspamd_upstream_test_func (void) { struct upstream_list *ls, *nls; struct upstream *up, *upn; struct event_base *ev_base = event_init (); struct rspamd_dns_resolver *resolver; struct rspamd_config *cfg; gint i, success = 0; const gint assumptions = 100500; gdouble p; struct event ev; struct timeval tv; rspamd_inet_addr_t *addr, *next_addr, *paddr; cfg = rspamd_config_new (); cfg->dns_retransmits = 2; cfg->dns_timeout = 0.5; cfg->upstream_max_errors = 1; cfg->upstream_revive_time = 0.5; cfg->upstream_error_time = 2; resolver = dns_resolver_init (NULL, ev_base, cfg); rspamd_upstreams_library_config (cfg, cfg->ups_ctx, ev_base, resolver->r); /* * Test v4/v6 priorities */ nls = rspamd_upstreams_create (cfg->ups_ctx); g_assert (rspamd_upstreams_add_upstream (nls, "127.0.0.1", 0, NULL)); up = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_RANDOM, NULL, 0); rspamd_parse_inet_address (&paddr, "127.0.0.2", 0); g_assert (rspamd_upstream_add_addr (up, paddr)); rspamd_parse_inet_address (&paddr, "::1", 0); g_assert (rspamd_upstream_add_addr (up, paddr)); /* Rewind to start */ addr = rspamd_upstream_addr (up); addr = rspamd_upstream_addr (up); /* cur should be zero here */ addr = rspamd_upstream_addr (up); next_addr = rspamd_upstream_addr (up); g_assert (rspamd_inet_address_get_af (addr) == AF_INET); g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET); next_addr = rspamd_upstream_addr (up); g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET6); next_addr = rspamd_upstream_addr (up); g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET); next_addr = rspamd_upstream_addr (up); g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET); next_addr = rspamd_upstream_addr (up); g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET6); /* Test errors with IPv6 */ rspamd_upstream_fail (up); /* Now we should have merely IPv4 addresses in rotation */ addr = rspamd_upstream_addr (up); for (i = 0; i < 256; i++) { next_addr = rspamd_upstream_addr (up); g_assert (rspamd_inet_address_get_af (addr) == AF_INET); g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET); g_assert (rspamd_inet_address_compare (addr, next_addr) != 0); addr = next_addr; } rspamd_upstreams_destroy (nls); ls = rspamd_upstreams_create (cfg->ups_ctx); g_assert (rspamd_upstreams_parse_line (ls, test_upstream_list, 443, NULL)); g_assert (rspamd_upstreams_count (ls) == 3); /* Test master-slave rotation */ rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, "kernel.org"); rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, "kernel.org"); /* Test round-robin rotation */ rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org"); rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org"); rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com"); rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org"); rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com"); rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "microsoft.com"); /* Test stable hashing */ nls = rspamd_upstreams_create (cfg->ups_ctx); g_assert (rspamd_upstreams_parse_line (nls, test_upstream_list, 443, NULL)); g_assert (rspamd_upstreams_parse_line (nls, new_upstream_list, 443, NULL)); for (i = 0; i < assumptions; i ++) { ottery_rand_bytes (test_key, sizeof (test_key)); up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_HASHED, test_key, sizeof (test_key)); upn = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_HASHED, test_key, sizeof (test_key)); if (strcmp (rspamd_upstream_name (up), rspamd_upstream_name (upn)) == 0) { success ++; } } p = 1.0 - fabs (3.0 / 4.0 - (gdouble)success / (gdouble)assumptions); /* * P value is calculated as following: * when we add/remove M upstreams from the list, the probability of hash * miss should be close to the relation N / (N + M), where N is the size of * the previous upstreams list. */ msg_debug ("p value for hash consistency: %.6f", p); g_assert (p > 0.9); rspamd_upstreams_destroy (nls); /* Upstream fail test */ evtimer_set (&ev, rspamd_upstream_timeout_handler, resolver); event_base_set (ev_base, &ev); up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, NULL, 0); for (i = 0; i < 100; i ++) { rspamd_upstream_fail (up); } g_assert (rspamd_upstreams_alive (ls) == 2); tv.tv_sec = 2; tv.tv_usec = 0; event_add (&ev, &tv); event_base_loop (ev_base, 0); g_assert (rspamd_upstreams_alive (ls) == 3); rspamd_upstreams_destroy (ls); REF_RELEASE (cfg); }
/** * Async HTTP callback */ static void http_callback (gint fd, short what, void *ud) { struct rspamd_map *map = ud; struct http_map_data *data; struct http_callback_data *cbd; rspamd_mempool_t *pool; gchar tmpbuf[PATH_MAX]; data = map->map_data; pool = map->pool; if (!g_atomic_int_compare_and_exchange (map->locked, 0, 1)) { msg_debug_pool ( "don't try to reread map as it is locked by other process, will reread it later"); jitter_timeout_event (map, TRUE, FALSE, FALSE); return; } /* Plan event */ cbd = g_slice_alloc0 (sizeof (struct http_callback_data)); rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "%s" G_DIR_SEPARATOR_S "rspamd_map%d-XXXXXX", map->cfg->temp_dir, map->id); cbd->out_fd = mkstemp (tmpbuf); if (cbd->out_fd == -1) { g_slice_free1 (sizeof (*cbd), cbd); msg_err_pool ("cannot create tempfile: %s", strerror (errno)); jitter_timeout_event (map, FALSE, FALSE, TRUE); g_atomic_int_set (map->locked, 0); return; } cbd->tmpfile = g_strdup (tmpbuf); cbd->ev_base = map->ev_base; cbd->map = map; cbd->data = data; cbd->fd = -1; cbd->cbdata.state = 0; cbd->cbdata.prev_data = *cbd->map->user_data; cbd->cbdata.cur_data = NULL; cbd->cbdata.map = cbd->map; cbd->stage = map_resolve_host2; double_to_tv (map->cfg->map_timeout, &cbd->tv); REF_INIT_RETAIN (cbd, free_http_cbdata); msg_debug_pool ("reading map data from %s", data->host); /* Send both A and AAAA requests */ if (map->r->r) { if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, data->host, RDNS_REQUEST_A)) { REF_RETAIN (cbd); } if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, data->host, RDNS_REQUEST_AAAA)) { REF_RETAIN (cbd); } jitter_timeout_event (map, FALSE, FALSE, FALSE); map->dtor = free_http_cbdata_dtor; map->dtor_data = cbd; } else { msg_warn_pool ("cannot load map: DNS resolver is not initialized"); jitter_timeout_event (map, FALSE, FALSE, TRUE); } /* We don't need own ref as it is now refcounted by DNS requests */ REF_RELEASE (cbd); }
void rspamd_email_address_unref (struct rspamd_email_address *addr) { REF_RELEASE (addr); }