aboutsummaryrefslogtreecommitdiffstats
path: root/src/libutil/upstream.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2014-11-07 13:33:45 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2014-11-07 13:33:45 +0000
commitcd5656abb755d5070651b1594bc4b2f8acd345df (patch)
tree8856926125af323e2722f67ba15f1c53037078fb /src/libutil/upstream.c
parent9691ba214d38cda7042ba902acd3c6e7231aa6b7 (diff)
downloadrspamd-cd5656abb755d5070651b1594bc4b2f8acd345df.tar.gz
rspamd-cd5656abb755d5070651b1594bc4b2f8acd345df.zip
Rework IP addresses in upstreams.
- Select ipv4/unix addresses if they exist and use ipv6 for ipv6 only upstreams (since the support of ipv6 is poor in many OSes and environments). - Free IP list on upstream destruction. - Add test cases for addresses selection. - Allow adding of free form IP addresses to upstreams.
Diffstat (limited to 'src/libutil/upstream.c')
-rw-r--r--src/libutil/upstream.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/src/libutil/upstream.c b/src/libutil/upstream.c
index 7bec3729a..b5f1ed35e 100644
--- a/src/libutil/upstream.c
+++ b/src/libutil/upstream.c
@@ -105,6 +105,42 @@ rspamd_upstreams_library_init (struct rdns_resolver *resolver,
ev_base = base;
}
+static gint
+rspamd_upstream_af_to_weight (const rspamd_inet_addr_t *addr)
+{
+ int ret;
+
+ switch (addr->af) {
+ case AF_UNIX:
+ ret = 2;
+ break;
+ case AF_INET:
+ ret = 1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Select IPv4 addresses before IPv6
+ */
+static gint
+rspamd_upstream_addr_sort_func (gconstpointer a, gconstpointer b)
+{
+ const rspamd_inet_addr_t *ip1 = (const rspamd_inet_addr_t *)a,
+ *ip2 = (const rspamd_inet_addr_t *)b;
+ gint w1, w2;
+
+ w1 = rspamd_upstream_af_to_weight (ip1);
+ w2 = rspamd_upstream_af_to_weight (ip2);
+
+ return w2 - w1;
+}
+
static void
rspamd_upstream_set_active (struct upstream_list *ls, struct upstream *up)
{
@@ -186,6 +222,8 @@ rspamd_upstream_update_addrs (struct upstream *up)
up->addrs.cur = 0;
up->addrs.count = addr_cnt;
up->addrs.addr = new_addrs;
+ qsort (up->addrs.addr, up->addrs.count, sizeof (up->addrs.addr[0]),
+ rspamd_upstream_addr_sort_func);
g_free (old);
}
@@ -340,13 +378,36 @@ rspamd_upstream_dtor (struct upstream *up)
rspamd_mutex_free (up->lock);
g_free (up->name);
+ g_free (up->addrs.addr);
g_slice_free1 (sizeof (*up), up);
}
rspamd_inet_addr_t*
rspamd_upstream_addr (struct upstream *up)
{
- return &up->addrs.addr[up->addrs.cur++ % up->addrs.count];
+ gint idx, next_idx, w1, w2;
+ /*
+ * We know that addresses are sorted in the way that ipv4 addresses come
+ * first. Therefore, we select only ipv4 addresses if they exist, since
+ * many systems now has poorly supported ipv6
+ */
+ idx = up->addrs.cur;
+ next_idx = (idx + 1) % up->addrs.count;
+ w1 = rspamd_upstream_af_to_weight (&up->addrs.addr[idx]);
+ w2 = rspamd_upstream_af_to_weight (&up->addrs.addr[next_idx]);
+
+ /*
+ * We don't care about the exact priorities, but we prefer ipv4/unix
+ * addresses before any ipv6 addresses
+ */
+ if (!w1 || w2) {
+ up->addrs.cur = next_idx;
+ }
+ else {
+ up->addrs.cur = 0;
+ }
+
+ return &up->addrs.addr[up->addrs.cur];
}
const gchar*
@@ -377,6 +438,8 @@ rspamd_upstreams_add_upstream (struct upstream_list *ups,
up->ls = ups;
REF_INIT_RETAIN (up, rspamd_upstream_dtor);
up->lock = rspamd_mutex_new ();
+ qsort (up->addrs.addr, up->addrs.count, sizeof (up->addrs.addr[0]),
+ rspamd_upstream_addr_sort_func);
rspamd_upstream_set_active (ups, up);
@@ -384,6 +447,24 @@ rspamd_upstreams_add_upstream (struct upstream_list *ups,
}
gboolean
+rspamd_upstream_add_addr (struct upstream *up, const rspamd_inet_addr_t *addr)
+{
+ gint nsz;
+
+ /*
+ * XXX: slow and inefficient
+ */
+ nsz = ++up->addrs.count;
+ up->addrs.addr = g_realloc (up->addrs.addr,
+ nsz * sizeof (up->addrs.addr[0]));
+ memcpy (&up->addrs.addr[nsz - 1], addr, sizeof (*addr));
+ qsort (up->addrs.addr, up->addrs.count, sizeof (up->addrs.addr[0]),
+ rspamd_upstream_addr_sort_func);
+
+ return TRUE;
+}
+
+gboolean
rspamd_upstreams_parse_line (struct upstream_list *ups,
const gchar *str, guint16 def_port, void *data)
{