summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2021-09-22 18:44:25 +0300
committerdefanor <defanor@uberspace.net>2021-09-22 18:44:25 +0300
commit498e517c2f2fc22b40550f5d87596b5926b73f45 (patch)
treebab0d3f9c0a8382060f5e83ed4bba5f73a246c09
parent18f1f8f8d12131402ca13b53488870f2ab21d3d1 (diff)
Reintroduce c-ares as an option for DNS lookups
-rw-r--r--README6
-rw-r--r--configure.ac7
-rw-r--r--src/Makefile.am4
-rw-r--r--src/rexmpp.c27
-rw-r--r--src/rexmpp.h2
-rw-r--r--src/rexmpp_dns.c164
-rw-r--r--src/rexmpp_dns.h10
7 files changed, 159 insertions, 61 deletions
diff --git a/README b/README
index a881e11..28ee230 100644
--- a/README
+++ b/README
@@ -14,8 +14,8 @@ rely on any particular UI, should be flexible and not stay in the way
of implementing additional XEPs on top of it, and should try to make
it easy to implement a decent client application using it.
-Current dependencies: libxml2, gsasl, nettle. Optionally libunbound,
-gnutls with gnutls-dane or openssl, icu-i18n, gpgme.
+Current dependencies: libxml2, gsasl, nettle. Optionally libunbound or
+c-ares, gnutls with gnutls-dane or openssl, icu-i18n, gpgme.
A rough roadmap:
@@ -38,7 +38,7 @@ A rough roadmap:
[+] "Happy Eyeballs" (RFC 8305).
[+] XEP-0368 v1.1: SRV records for XMPP over TLS (when built with
- libunbound).
+ libunbound or c-ares).
[+] SOCKS5 (RFC 1928) support. Implemented, though no authentication.
[+] XEP-0199 v2.0: XMPP Ping.
[.] Certificate verification using DANE (experimental, only when built
diff --git a/configure.ac b/configure.ac
index 9e8e080..e318940 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,7 +24,7 @@ PKG_CHECK_MODULES([GSASL], [libgsasl])
PKG_CHECK_MODULES([NETTLE], [nettle])
-# DNS: libunbound, optional
+# DNS: libunbound or c-ares, optional
AC_ARG_VAR([DNSSEC_TRUST_ANCHOR_FILE],
[A DNSSEC trust anchor, containing DNSKEY in zone file format])
@@ -36,10 +36,15 @@ AC_DEFINE_UNQUOTED([DNSSEC_TRUST_ANCHOR_FILE],
AC_ARG_WITH([unbound],
AS_HELP_STRING([--without-unbound], [don't use libunbound]))
+AC_ARG_WITH([cares],
+ AS_HELP_STRING([--with-cares], [use c-ares]))
AS_IF([test "x$with_unbound" != "xno"],
[PKG_CHECK_MODULES([UNBOUND], [libunbound],
[AC_DEFINE([USE_UNBOUND], [1], [Use libunbound])])])
+AS_IF([test "x$with_cares" == "xyes"],
+ [PKG_CHECK_MODULES([CARES], [libcares],
+ [AC_DEFINE([USE_CARES], [1], [Use c-ares])])])
# GPGME, optional
diff --git a/src/Makefile.am b/src/Makefile.am
index 51a5da7..0ccdf5b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,9 +32,9 @@ include_HEADERS = config.h rexmpp_roster.h rexmpp_tcp.h rexmpp_socks.h rexmpp.h
rexmpp_pubsub.h
librexmpp_la_CFLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) \
$(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \
- $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(GPGME_CFLAGS) \
+ $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \
$(ICU_I18N_CFLAGS) $(NETTLE_CFLAGS)
librexmpp_la_LIBADD = $(LIBXML_LIBS) \
$(GNUTLS_LIBS) $(LIBDANE_LIBS) $(OPENSSL_LIBS) \
- $(GSASL_LIBS) $(UNBOUND_LIBS) $(GPGME_LIBS) $(ICU_I18N_LIBS) \
+ $(GSASL_LIBS) $(UNBOUND_LIBS) $(CARES_LIBS) $(GPGME_LIBS) $(ICU_I18N_LIBS) \
$(NETTLE_LIBS)
diff --git a/src/rexmpp.c b/src/rexmpp.c
index b35e40a..acb4473 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -1184,17 +1184,10 @@ rexmpp_err_t rexmpp_try_next_host (rexmpp_t *s) {
return REXMPP_E_AGAIN;
}
- int err = rexmpp_parse_srv(cur_result->data[cur_number],
- cur_result->len[cur_number],
- &(s->server_active_srv));
- if (err) {
- rexmpp_log(s, LOG_ERR, "Failed to parse an SRV record");
- rexmpp_cleanup(s);
- rexmpp_schedule_reconnect(s);
- return REXMPP_E_DNS;
- }
- s->server_host = s->server_active_srv.target;
- s->server_port = s->server_active_srv.port;
+ s->server_active_srv = (rexmpp_dns_srv_t *)cur_result->data[cur_number];
+
+ s->server_host = s->server_active_srv->target;
+ s->server_port = s->server_active_srv->port;
return rexmpp_start_connecting(s);
}
@@ -1286,13 +1279,13 @@ void rexmpp_srv_cb (rexmpp_t *s,
void *ptr,
rexmpp_dns_result_t *result)
{
- (void)ptr;
+ char *type = ptr;
if (result != NULL) {
rexmpp_log(s,
result->secure ? LOG_DEBUG : LOG_WARNING,
- "Resolved %s SRV record (%s)",
- result->qname, result->secure ? "secure" : "not secure");
- if (strncmp("_xmpp-", result->qname, 6) == 0) {
+ "Resolved a %s SRV record (%s)",
+ type, result->secure ? "secure" : "not secure");
+ if (strncmp("xmpp", type, 5) == 0) {
s->server_srv = result;
} else {
s->server_srv_tls = result;
@@ -2230,11 +2223,11 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
snprintf(srv_query, srv_query_buf_len,
"_xmpps-client._tcp.%s.", s->initial_jid.domain);
rexmpp_dns_resolve(s, srv_query, 33, 1,
- NULL, rexmpp_srv_cb);
+ "xmpps", rexmpp_srv_cb);
snprintf(srv_query, srv_query_buf_len,
"_xmpp-client._tcp.%s.", s->initial_jid.domain);
rexmpp_dns_resolve(s, srv_query, 33, 1,
- NULL, rexmpp_srv_cb);
+ "xmpp", rexmpp_srv_cb);
free(srv_query);
} else {
/* A host is configured manually, connect there. */
diff --git a/src/rexmpp.h b/src/rexmpp.h
index d8d5e86..1fdfc28 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -320,7 +320,7 @@ struct rexmpp
int server_srv_cur;
rexmpp_dns_result_t *server_srv_tls;
int server_srv_tls_cur;
- struct rexmpp_dns_srv server_active_srv;
+ struct rexmpp_dns_srv *server_active_srv;
/* The XMPP server we are connecting to. */
const char *server_host;
diff --git a/src/rexmpp_dns.c b/src/rexmpp_dns.c
index 5b3fd9e..00c9074 100644
--- a/src/rexmpp_dns.c
+++ b/src/rexmpp_dns.c
@@ -13,9 +13,12 @@
#if defined(USE_UNBOUND)
#include <unbound.h>
+#elif defined(USE_CARES)
+#include <ares.h>
#else
-#include <netdb.h>
#endif
+#include <netdb.h>
+
#include "rexmpp.h"
#include "rexmpp_dns.h"
@@ -74,13 +77,27 @@ void rexmpp_dns_result_free (rexmpp_dns_result_t *result) {
free(result->len);
result->len = NULL;
}
- if (result->qname != NULL) {
- free(result->qname);
- result->qname = NULL;
- }
free(result);
}
+rexmpp_dns_result_t *result_from_hostent (struct hostent *hostinfo) {
+ rexmpp_dns_result_t *r = malloc(sizeof(rexmpp_dns_result_t));
+ r->secure = 0;
+ int i, size = 0;
+ while (hostinfo->h_addr_list[size] != NULL) {
+ size++;
+ }
+ r->data = malloc(sizeof(void *) * (size + 1));
+ r->len = malloc(sizeof(int) * size);
+ for (i = 0; i < size; i++) {
+ r->len[i] = hostinfo->h_length;
+ r->data[i] = malloc(r->len[i]);
+ memcpy(r->data[i], hostinfo->h_addr_list[i], hostinfo->h_length);
+ }
+ r->data[size] = NULL;
+ return r;
+}
+
int rexmpp_dns_ctx_init (rexmpp_t *s) {
#if defined(USE_UNBOUND)
@@ -106,6 +123,21 @@ int rexmpp_dns_ctx_init (rexmpp_t *s) {
ub_strerror(err));
}
return 0;
+#elif defined(USE_CARES)
+ int err = ares_library_init(ARES_LIB_INIT_ALL);
+ if (err != 0) {
+ rexmpp_log(s, LOG_CRIT, "ares library initialisation error: %s",
+ ares_strerror(err));
+ return 1;
+ }
+ err = ares_init(&(s->resolver.channel));
+ if (err) {
+ rexmpp_log(s, LOG_CRIT, "ares channel initialisation error: %s",
+ ares_strerror(err));
+ ares_library_cleanup();
+ return 1;
+ }
+ return 0;
#else
(void)s;
return 0;
@@ -113,13 +145,8 @@ int rexmpp_dns_ctx_init (rexmpp_t *s) {
}
void rexmpp_dns_ctx_cleanup (rexmpp_t *s) {
-#if defined(USE_UNBOUND)
(void)s;
return;
-#else
- (void)s;
- return;
-#endif
}
void rexmpp_dns_ctx_deinit (rexmpp_t *s) {
@@ -128,6 +155,9 @@ void rexmpp_dns_ctx_deinit (rexmpp_t *s) {
ub_ctx_delete(s->resolver.ctx);
s->resolver.ctx = NULL;
}
+#elif defined(USE_CARES)
+ ares_destroy(s->resolver.channel);
+ ares_library_cleanup();
#else
(void)s;
#endif
@@ -141,6 +171,8 @@ int rexmpp_dns_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
FD_SET(max_fd - 1, read_fds);
}
return max_fd;
+#elif defined(USE_CARES)
+ return ares_fds(s->resolver.channel, read_fds, write_fds);
#else
(void)s;
(void)read_fds;
@@ -157,6 +189,8 @@ struct timeval * rexmpp_dns_timeout (rexmpp_t *s,
(void)s;
(void)tv;
return max_tv;
+#elif defined(USE_CARES)
+ return ares_timeout(s->resolver.channel, max_tv, tv);
#else
(void)s;
(void)max_tv;
@@ -174,8 +208,8 @@ void rexmpp_dns_cb (void *ptr,
rexmpp_t *s = d->s;
if (err != 0) {
- rexmpp_log(s, LOG_WARNING, "%s DNS query failure: %s",
- result->qname, ub_strerror(err));
+ rexmpp_log(s, LOG_WARNING, "DNS query failure: %s",
+ ub_strerror(err));
ub_resolve_free(result);
d->cb(s, d->ptr, NULL);
return;
@@ -183,15 +217,14 @@ void rexmpp_dns_cb (void *ptr,
if (result->bogus) {
rexmpp_log(s, LOG_WARNING,
- "Received a bogus DNS resolution result for %s",
- result->qname);
+ "Received a bogus DNS resolution result");
ub_resolve_free(result);
d->cb(s, d->ptr, NULL);
return;
}
if (! result->havedata) {
- rexmpp_log(s, LOG_DEBUG, "No data in the %s query result", result->qname);
+ rexmpp_log(s, LOG_DEBUG, "No data in the query result");
ub_resolve_free(result);
d->cb(s, d->ptr, NULL);
return;
@@ -202,20 +235,85 @@ void rexmpp_dns_cb (void *ptr,
size++;
}
rexmpp_dns_result_t *res = malloc(sizeof(rexmpp_dns_result_t));
- res->data = malloc(sizeof(char *) * (size + 1));
+ res->data = malloc(sizeof(void *) * (size + 1));
res->len = malloc(sizeof(int) * size);
for (i = 0; i < size; i++) {
- res->len[i] = result->len[i];
- res->data[i] = malloc(res->len[i]);
- memcpy(res->data[i], result->data[i], res->len[i]);
+ if (result->qtype == 33) {
+ /* SRV */
+ res->len[i] = sizeof(rexmpp_dns_srv_t);
+ res->data[i] = malloc(res->len[i]);
+ int err = rexmpp_parse_srv(result->data[i], result->len[i],
+ (rexmpp_dns_srv_t*)res->data[i]);
+ if (err) {
+ rexmpp_log(s, LOG_WARNING, "Failed to parse an SRV record");
+ res->data[i + 1] = NULL;
+ rexmpp_dns_result_free(res);
+ d->cb(s, d->ptr, NULL);
+ return;
+ }
+ } else {
+ /* Non-SRV, for now that's just A or AAAA */
+ res->len[i] = result->len[i];
+ res->data[i] = malloc(res->len[i]);
+ memcpy(res->data[i], result->data[i], res->len[i]);
+ }
}
res->data[size] = NULL;
res->secure = result->secure;
- res->qname = strdup(result->qname);
ub_resolve_free(result);
d->cb(s, d->ptr, res);
free(d);
}
+#elif defined(USE_CARES)
+void rexmpp_dns_cb (void *ptr,
+ int err,
+ int timeouts,
+ unsigned char *abuf,
+ int alen)
+{
+ (void)timeouts;
+ struct rexmpp_dns_query_cb_data *d = ptr;
+ rexmpp_t *s = d->s;
+ if (err != ARES_SUCCESS) {
+ rexmpp_log(s, LOG_WARNING, "A DNS query failure: %s",
+ ares_strerror(err));
+ d->cb(s, d->ptr, NULL);
+ return;
+ }
+ /* c-ares won't just tell us the type, but it does check for it in
+ the parsing functions, so we just try them out. */
+ struct hostent *hostinfo;
+ struct ares_srv_reply *srv, *cur_srv;
+ if (ares_parse_a_reply(abuf, alen, &hostinfo, NULL, NULL) == ARES_SUCCESS ||
+ ares_parse_aaaa_reply(abuf, alen, &hostinfo, NULL, NULL) == ARES_SUCCESS) {
+ rexmpp_dns_result_t *r = result_from_hostent(hostinfo);
+ ares_free_hostent(hostinfo);
+ d->cb(s, d->ptr, r);
+ } else if (ares_parse_srv_reply(abuf, alen, &srv) == ARES_SUCCESS) {
+ int i, size;
+ for (size = 0, cur_srv = srv; cur_srv != NULL; size++, cur_srv = cur_srv->next);
+ rexmpp_dns_result_t *r = malloc(sizeof(rexmpp_dns_result_t));
+ r->secure = 0;
+ r->data = malloc(sizeof(void*) * (size + 1));
+ r->len = malloc(sizeof(int) * size);
+ for (cur_srv = srv, i = 0; i < size; i++, cur_srv = cur_srv->next) {
+ r->len[i] = sizeof(rexmpp_dns_srv_t);
+ rexmpp_dns_srv_t *r_srv = malloc(sizeof(rexmpp_dns_srv_t));
+ r_srv->priority = cur_srv->priority;
+ r_srv->weight = cur_srv->weight;
+ r_srv->port = cur_srv->port;
+ strncpy(r_srv->target, cur_srv->host, 255);
+ r_srv->target[255] = '\0';
+ r->data[i] = r_srv;
+ }
+ r->data[size] = NULL;
+ ares_free_data(srv);
+ d->cb(s, d->ptr, r);
+ }else {
+ rexmpp_log(s, LOG_ERR, "Failed to parse a query");
+ d->cb(s, d->ptr, NULL);
+ }
+}
#endif
@@ -239,8 +337,14 @@ int rexmpp_dns_resolve (rexmpp_t *s,
query, ub_strerror(err));
return 1;
}
+#elif defined(USE_CARES)
+ struct rexmpp_dns_query_cb_data *d =
+ malloc(sizeof(struct rexmpp_dns_query_cb_data));
+ d->s = s;
+ d->cb = callback;
+ d->ptr = ptr;
+ ares_query(s->resolver.channel, query, rrclass, rrtype, rexmpp_dns_cb, d);
#else
- rexmpp_dns_result_t *r = malloc(sizeof(rexmpp_dns_result_t));;
if (rrclass == 1) {
if (rrtype == 1 || rrtype == 28) {
struct hostent *hostinfo = gethostbyname(query);
@@ -248,20 +352,7 @@ int rexmpp_dns_resolve (rexmpp_t *s,
rexmpp_log(s, LOG_ERR, "Failed to lookup %s", query);
callback(s, ptr, NULL);
} else {
- r->qname = strdup(query);
- r->secure = 0;
- int i, size = 0;
- while (hostinfo->h_addr_list[size] != NULL) {
- size++;
- }
- r->data = malloc(sizeof(char *) * (size + 1));
- r->len = malloc(sizeof(int) * size);
- for (i = 0; i < size; i++) {
- r->len[i] = hostinfo->h_length;
- r->data[i] = malloc(r->len[i]);
- memcpy(r->data[i], hostinfo->h_addr_list[i], hostinfo->h_length);
- }
- r->data[size] = NULL;
+ rexmpp_dns_result_t *r = result_from_hostent(hostinfo);
callback(s, ptr, r);
}
} else if (rrtype == 33) {
@@ -294,6 +385,9 @@ int rexmpp_dns_process (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
}
}
return 0;
+#elif defined(USE_CARES)
+ ares_process(s->resolver.channel, read_fds, write_fds);
+ return 0;
#else
(void)s;
(void)read_fds;
diff --git a/src/rexmpp_dns.h b/src/rexmpp_dns.h
index 3c94e90..704cafb 100644
--- a/src/rexmpp_dns.h
+++ b/src/rexmpp_dns.h
@@ -20,6 +20,11 @@
struct rexmpp_dns_ctx {
struct ub_ctx *ctx;
};
+#elif defined(USE_CARES)
+#include <ares.h>
+struct rexmpp_dns_ctx {
+ ares_channel channel;
+};
#else
struct rexmpp_dns_ctx {
int dummy;
@@ -35,10 +40,11 @@ struct rexmpp_dns_srv {
char target[256];
};
+typedef struct rexmpp_dns_srv rexmpp_dns_srv_t;
+
struct rexmpp_dns_result {
- char **data;
+ void **data;
int *len;
- char *qname;
int secure;
};