From b4fbb32b3dcd21f1fc90c419aa3992ecb6f7924a Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Tue, 15 Mar 2016 14:58:43 +0000 Subject: [PATCH] [Feature] Rework rspamd DNS to use the ordinary upstreams rotation Issue: #552 Reported by: @Freeaqingme --- src/libserver/dns.c | 177 +++++++++++++++++++++++++++++++++----------- src/libserver/dns.h | 5 ++ 2 files changed, 137 insertions(+), 45 deletions(-) diff --git a/src/libserver/dns.c b/src/libserver/dns.c index 3c67411a0..eb0e4e9a2 100644 --- a/src/libserver/dns.c +++ b/src/libserver/dns.c @@ -21,6 +21,24 @@ #include "uthash.h" #include "rdns_event.h" +static struct rdns_upstream_elt* rspamd_dns_select_upstream (const char *name, + size_t len, void *ups_data); +static struct rdns_upstream_elt* rspamd_dns_select_upstream_retransmit ( + const char *name, + size_t len, void *ups_data); +static void rspamd_dns_upstream_ok (struct rdns_upstream_elt *elt, + void *ups_data); +static void rspamd_dns_upstream_fail (struct rdns_upstream_elt *elt, + void *ups_data); + +static struct rdns_upstream_context rspamd_ups_ctx = { + .select = rspamd_dns_select_upstream, + .select_retransmit = rspamd_dns_select_upstream_retransmit, + .ok = rspamd_dns_upstream_ok, + .fail = rspamd_dns_upstream_fail, + .data = NULL +}; + struct rspamd_dns_request_ud { struct rspamd_async_session *session; dns_callback_type cb; @@ -176,78 +194,147 @@ static void rspamd_rnds_log_bridge ( function, format, args); } +static void +rspamd_dns_server_init (struct upstream *up, gpointer ud) +{ + struct rspamd_dns_resolver *r = ud; + rspamd_inet_addr_t *addr; + void *serv; + struct rdns_upstream_elt *elt; + + addr = rspamd_upstream_addr (up); + + if (r->cfg) { + serv = rdns_resolver_add_server (r->r, rspamd_inet_address_to_string (addr), + rspamd_inet_address_get_port (addr), 0, r->cfg->dns_io_per_server); + } + else { + serv = rdns_resolver_add_server (r->r, rspamd_inet_address_to_string (addr), + rspamd_inet_address_get_port (addr), 0, 8); + } + + elt = g_slice_alloc0 (sizeof (*elt)); + elt->server = serv; + elt->lib_data = up; + + rspamd_upstream_set_data (up, elt); +} + struct rspamd_dns_resolver * dns_resolver_init (rspamd_logger_t *logger, struct event_base *ev_base, struct rspamd_config *cfg) { - GList *cur; - struct rspamd_dns_resolver *new; - gchar *begin, *p, *err; - gint priority; + struct rspamd_dns_resolver *dns_resolver; - new = g_slice_alloc0 (sizeof (struct rspamd_dns_resolver)); - new->ev_base = ev_base; + dns_resolver = g_slice_alloc0 (sizeof (struct rspamd_dns_resolver)); + dns_resolver->ev_base = ev_base; if (cfg != NULL) { - new->request_timeout = cfg->dns_timeout; - new->max_retransmits = cfg->dns_retransmits; + dns_resolver->request_timeout = cfg->dns_timeout; + dns_resolver->max_retransmits = cfg->dns_retransmits; } else { - new->request_timeout = 1; - new->max_retransmits = 2; + dns_resolver->request_timeout = 1; + dns_resolver->max_retransmits = 2; } - new->r = rdns_resolver_new (); - rdns_bind_libevent (new->r, new->ev_base); + dns_resolver->r = rdns_resolver_new (); + rdns_bind_libevent (dns_resolver->r, dns_resolver->ev_base); if (cfg != NULL) { - rdns_resolver_set_log_level (new->r, cfg->log_level); + rdns_resolver_set_log_level (dns_resolver->r, cfg->log_level); + dns_resolver->cfg = cfg; } - rdns_resolver_set_logger (new->r, rspamd_rnds_log_bridge, logger); + rdns_resolver_set_logger (dns_resolver->r, rspamd_rnds_log_bridge, logger); if (cfg == NULL || cfg->nameservers == NULL) { /* Parse resolv.conf */ - if (!rdns_resolver_parse_resolv_conf (new->r, "/etc/resolv.conf")) { + if (!rdns_resolver_parse_resolv_conf (dns_resolver->r, "/etc/resolv.conf")) { msg_err_config ( "cannot parse resolv.conf and no nameservers defined, so no ways to resolve addresses"); - rdns_resolver_release (new->r); - new->r = NULL; + rdns_resolver_release (dns_resolver->r); + dns_resolver->r = NULL; - return new; + return dns_resolver; } } else { - cur = cfg->nameservers; - while (cur) { - begin = cur->data; - p = strchr (begin, ':'); - if (p != NULL) { - *p = '\0'; - p++; - priority = strtoul (p, &err, 10); - if (err != NULL && *err != '\0') { - msg_info_config ( - "bad character '%xc', must be 'm' or 's' or a numeric priority", - *err); - } - } - else { - priority = 0; - } - if (!rdns_resolver_add_server (new->r, begin, 53, priority, - cfg->dns_io_per_server)) { - msg_warn_config ("cannot parse ip address of nameserver: %s", begin); - cur = g_list_next (cur); - continue; - } - - cur = g_list_next (cur); + dns_resolver->ups = rspamd_upstreams_create (cfg->ups_ctx); + + if (!rspamd_upstreams_from_ucl (dns_resolver->ups, cfg->nameservers, + 53, dns_resolver)) { + msg_err_config ("cannot parse DNS nameservers definitions"); + rdns_resolver_release (dns_resolver->r); + dns_resolver->r = NULL; + + return dns_resolver; } + rspamd_upstreams_foreach (dns_resolver->ups, rspamd_dns_server_init, + dns_resolver); + rspamd_upstreams_set_flags (dns_resolver->ups, RSPAMD_UPSTREAM_FLAG_NORESOLVE); + rdns_resolver_set_upstream_lib (dns_resolver->r, &rspamd_ups_ctx, + dns_resolver->ups); + } + + rdns_resolver_init (dns_resolver->r); + + return dns_resolver; +} + + +static struct rdns_upstream_elt* +rspamd_dns_select_upstream (const char *name, + size_t len, void *ups_data) +{ + struct upstream_list *ups = ups_data; + struct upstream *up; + + up = rspamd_upstream_get (ups, RSPAMD_UPSTREAM_ROUND_ROBIN, name, len); + + if (up) { + msg_debug ("select %s", rspamd_upstream_name (up)); + + return rspamd_upstream_get_data (up); } - rdns_resolver_init (new->r); + return NULL; +} + +static struct rdns_upstream_elt* +rspamd_dns_select_upstream_retransmit ( + const char *name, + size_t len, void *ups_data) +{ + struct upstream_list *ups = ups_data; + struct upstream *up; + + up = rspamd_upstream_get_forced (ups, RSPAMD_UPSTREAM_RANDOM, name, len); + + if (up) { + msg_debug ("select forced %s", rspamd_upstream_name (up)); + + return rspamd_upstream_get_data (up); + } + + return NULL; +} + +static void +rspamd_dns_upstream_ok (struct rdns_upstream_elt *elt, + void *ups_data) +{ + struct upstream *up = elt->lib_data; + + rspamd_upstream_ok (up); +} + +static void +rspamd_dns_upstream_fail (struct rdns_upstream_elt *elt, + void *ups_data) +{ + struct upstream *up = elt->lib_data; - return new; + rspamd_upstream_fail (up); } diff --git a/src/libserver/dns.h b/src/libserver/dns.h index e465de82d..52325af91 100644 --- a/src/libserver/dns.h +++ b/src/libserver/dns.h @@ -22,10 +22,15 @@ #include "events.h" #include "logger.h" #include "rdns.h" +#include "upstream.h" + +struct rspamd_config; struct rspamd_dns_resolver { struct rdns_resolver *r; struct event_base *ev_base; + struct upstream_list *ups; + struct rspamd_config *cfg; gdouble request_timeout; guint max_retransmits; }; -- 2.39.5