summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordefanor <defanor@uberspace.net>2021-09-21 21:39:52 +0300
committerdefanor <defanor@uberspace.net>2021-09-21 21:39:52 +0300
commit18f1f8f8d12131402ca13b53488870f2ab21d3d1 (patch)
tree33b885ef6495d3745265d17e598fdf21268a2553
parentbec43cf7a9d33cd0ad393c86ffdd005c45f0f419 (diff)
Make libunbound optional
Just use gethostbyname when it's disabled. Possibly will add c-ares, getaddrinfo_a, and other options in the future.
-rw-r--r--README7
-rw-r--r--configure.ac9
-rw-r--r--src/Makefile.am2
-rw-r--r--src/rexmpp.c118
-rw-r--r--src/rexmpp.h12
-rw-r--r--src/rexmpp_dns.c291
-rw-r--r--src/rexmpp_dns.h48
-rw-r--r--src/rexmpp_tcp.c62
-rw-r--r--src/rexmpp_tcp.h31
9 files changed, 431 insertions, 149 deletions
diff --git a/README b/README
index 5f1eb06..a881e11 100644
--- a/README
+++ b/README
@@ -14,7 +14,7 @@ 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: libunbound, libxml2, gsasl, nettle. Optionally
+Current dependencies: libxml2, gsasl, nettle. Optionally libunbound,
gnutls with gnutls-dane or openssl, icu-i18n, gpgme.
@@ -37,12 +37,13 @@ A rough roadmap:
- Better connectivity:
[+] "Happy Eyeballs" (RFC 8305).
-[+] XEP-0368 v1.1: SRV records for XMPP over TLS.
+[+] XEP-0368 v1.1: SRV records for XMPP over TLS (when built with
+ libunbound).
[+] SOCKS5 (RFC 1928) support. Implemented, though no authentication.
[+] XEP-0199 v2.0: XMPP Ping.
[.] Certificate verification using DANE (experimental, only when built
with GnuTLS).
-[+] DNSSEC checks.
+[+] DNSSEC checks (when built with libunbound).
- Library refinement:
diff --git a/configure.ac b/configure.ac
index d9453ed..9e8e080 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,7 +24,7 @@ PKG_CHECK_MODULES([GSASL], [libgsasl])
PKG_CHECK_MODULES([NETTLE], [nettle])
-# DNS: libunbound
+# DNS: libunbound, optional
AC_ARG_VAR([DNSSEC_TRUST_ANCHOR_FILE],
[A DNSSEC trust anchor, containing DNSKEY in zone file format])
@@ -34,7 +34,12 @@ AC_DEFINE_UNQUOTED([DNSSEC_TRUST_ANCHOR_FILE],
"$DNSSEC_TRUST_ANCHOR_FILE",
[A DNSSEC trust anchor, containing DNSKEY in zone file format])
-PKG_CHECK_MODULES([UNBOUND], [libunbound])
+AC_ARG_WITH([unbound],
+ AS_HELP_STRING([--without-unbound], [don't use libunbound]))
+
+AS_IF([test "x$with_unbound" != "xno"],
+ [PKG_CHECK_MODULES([UNBOUND], [libunbound],
+ [AC_DEFINE([USE_UNBOUND], [1], [Use libunbound])])])
# GPGME, optional
diff --git a/src/Makefile.am b/src/Makefile.am
index deb3ac6..51a5da7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -32,7 +32,7 @@ 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) $(GPGME_CFLAGS) \
$(ICU_I18N_CFLAGS) $(NETTLE_CFLAGS)
librexmpp_la_LIBADD = $(LIBXML_LIBS) \
$(GNUTLS_LIBS) $(LIBDANE_LIBS) $(OPENSSL_LIBS) \
diff --git a/src/rexmpp.c b/src/rexmpp.c
index 8998ea9..b35e40a 100644
--- a/src/rexmpp.c
+++ b/src/rexmpp.c
@@ -400,7 +400,6 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
s->tls_policy = REXMPP_TLS_REQUIRE;
s->send_buffer = NULL;
s->send_queue = NULL;
- s->resolver_ctx = NULL;
s->server_srv = NULL;
s->server_srv_cur = -1;
s->server_srv_tls = NULL;
@@ -458,30 +457,13 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
return REXMPP_E_XML;
}
- s->resolver_ctx = ub_ctx_create();
- if (s->resolver_ctx == NULL) {
- rexmpp_log(s, LOG_CRIT, "Failed to create resolver context");
+ if (rexmpp_dns_ctx_init(s)) {
xmlFreeParserCtxt(s->xml_parser);
return REXMPP_E_DNS;
}
- err = ub_ctx_resolvconf(s->resolver_ctx, NULL);
- if (err != 0) {
- rexmpp_log(s, LOG_WARNING, "Failed to read resolv.conf: %s",
- ub_strerror(err));
- }
- err = ub_ctx_hosts(s->resolver_ctx, NULL);
- if (err != 0) {
- rexmpp_log(s, LOG_WARNING, "Failed to read hosts file: %s",
- ub_strerror(err));
- }
- /* todo: better to make this path configurable, not to hardcode it */
- err = ub_ctx_add_ta_file(s->resolver_ctx, DNSSEC_TRUST_ANCHOR_FILE);
- if (err != 0) {
- rexmpp_log(s, LOG_WARNING, "Failed to set root key file for DNSSEC: %s",
- ub_strerror(err));
- }
if (rexmpp_tls_init(s)) {
+ rexmpp_dns_ctx_deinit(s);
xmlFreeParserCtxt(s->xml_parser);
return REXMPP_E_TLS;
}
@@ -491,6 +473,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
rexmpp_log(s, LOG_CRIT, "gsasl initialisation error: %s",
gsasl_strerror(err));
rexmpp_tls_deinit(s);
+ rexmpp_dns_ctx_deinit(s);
xmlFreeParserCtxt(s->xml_parser);
return REXMPP_E_SASL;
}
@@ -505,6 +488,7 @@ rexmpp_err_t rexmpp_init (rexmpp_t *s,
gpgme_strerror(err));
gsasl_done(s->sasl_ctx);
rexmpp_tls_deinit(s);
+ rexmpp_dns_ctx_deinit(s);
xmlFreeParserCtxt(s->xml_parser);
return REXMPP_E_PGP;
}
@@ -559,12 +543,12 @@ void rexmpp_cleanup (rexmpp_t *s) {
s->input_queue_last = NULL;
}
if (s->server_srv != NULL) {
- ub_resolve_free(s->server_srv);
+ rexmpp_dns_result_free(s->server_srv);
s->server_srv = NULL;
s->server_srv_cur = -1;
}
if (s->server_srv_tls != NULL) {
- ub_resolve_free(s->server_srv_tls);
+ rexmpp_dns_result_free(s->server_srv_tls);
s->server_srv_tls = NULL;
s->server_srv_tls_cur = -1;
}
@@ -580,10 +564,7 @@ void rexmpp_done (rexmpp_t *s) {
#endif
gsasl_done(s->sasl_ctx);
rexmpp_tls_deinit(s);
- if (s->resolver_ctx != NULL) {
- ub_ctx_delete(s->resolver_ctx);
- s->resolver_ctx = NULL;
- }
+ rexmpp_dns_ctx_deinit(s);
xmlFreeParserCtxt(s->xml_parser);
if (s->stream_id != NULL) {
free(s->stream_id);
@@ -1148,8 +1129,8 @@ rexmpp_err_t rexmpp_start_connecting (rexmpp_t *s) {
s->server_host, s->server_port);
return
rexmpp_process_conn_err(s,
- rexmpp_tcp_conn_init(&s->server_connection,
- s->resolver_ctx,
+ rexmpp_tcp_conn_init(s,
+ &s->server_connection,
s->server_host,
s->server_port));
} else {
@@ -1157,15 +1138,15 @@ rexmpp_err_t rexmpp_start_connecting (rexmpp_t *s) {
s->server_host, s->server_port,
s->socks_host, s->socks_port);
return rexmpp_process_conn_err(s,
- rexmpp_tcp_conn_init(&s->server_connection,
- s->resolver_ctx,
+ rexmpp_tcp_conn_init(s,
+ &s->server_connection,
s->socks_host,
s->socks_port));
}
}
rexmpp_err_t rexmpp_try_next_host (rexmpp_t *s) {
- struct ub_result *cur_result;
+ rexmpp_dns_result_t *cur_result;
int cur_number;
/* todo: check priorities and weights */
s->tls_state = REXMPP_TLS_INACTIVE;
@@ -1301,34 +1282,22 @@ rexmpp_process_conn_err (rexmpp_t *s,
return REXMPP_E_AGAIN;
}
-void rexmpp_srv_cb (void *s_ptr,
- int err,
- struct ub_result *result)
+void rexmpp_srv_cb (rexmpp_t *s,
+ void *ptr,
+ rexmpp_dns_result_t *result)
{
- rexmpp_t *s = s_ptr;
- if (err == 0) {
- if (result->bogus) {
- rexmpp_log(s, LOG_WARNING,
- "Received a bogus SRV resolution result for %s",
- result->qname);
- } else if (result->havedata) {
- 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) {
- s->server_srv = result;
- } else {
- s->server_srv_tls = result;
- }
+ (void)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) {
+ s->server_srv = result;
} else {
- rexmpp_log(s, LOG_DEBUG, "No data in the %s SRV result", result->qname);
+ s->server_srv_tls = result;
}
- } else {
- rexmpp_log(s, LOG_WARNING, "Failed to query %s SRV records: %s",
- result->qname, ub_strerror(err));
}
-
if (s->resolver_state == REXMPP_RESOLVER_SRV) {
s->resolver_state = REXMPP_RESOLVER_SRV_2;
} else if (s->resolver_state == REXMPP_RESOLVER_SRV_2) {
@@ -2257,24 +2226,15 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
if (srv_query == NULL) {
return REXMPP_E_MALLOC;
}
+ s->resolver_state = REXMPP_RESOLVER_SRV;
snprintf(srv_query, srv_query_buf_len,
"_xmpps-client._tcp.%s.", s->initial_jid.domain);
- int err;
- err = ub_resolve_async(s->resolver_ctx, srv_query, 33, 1,
- s, rexmpp_srv_cb, NULL);
- if (err) {
- rexmpp_log(s, LOG_ERR, "Failed to query %s SRV record: %s",
- srv_query, ub_strerror(err));
- }
+ rexmpp_dns_resolve(s, srv_query, 33, 1,
+ NULL, rexmpp_srv_cb);
snprintf(srv_query, srv_query_buf_len,
"_xmpp-client._tcp.%s.", s->initial_jid.domain);
- err = ub_resolve_async(s->resolver_ctx, srv_query, 33, 1,
- s, rexmpp_srv_cb, NULL);
- if (err) {
- rexmpp_log(s, LOG_ERR, "Failed to query %s SRV record: %s",
- srv_query, ub_strerror(err));
- }
- s->resolver_state = REXMPP_RESOLVER_SRV;
+ rexmpp_dns_resolve(s, srv_query, 33, 1,
+ NULL, rexmpp_srv_cb);
free(srv_query);
} else {
/* A host is configured manually, connect there. */
@@ -2303,13 +2263,8 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
rexmpp_srv_cb. */
if (s->resolver_state != REXMPP_RESOLVER_NONE &&
s->resolver_state != REXMPP_RESOLVER_READY) {
- if (ub_poll(s->resolver_ctx)) {
- int err = ub_process(s->resolver_ctx);
- if (err != 0) {
- rexmpp_log(s, LOG_ERR, "DNS query processing error: %s",
- ub_strerror(err));
- return REXMPP_E_DNS;
- }
+ if (rexmpp_dns_process(s, read_fds, write_fds)) {
+ return REXMPP_E_DNS;
}
}
@@ -2332,7 +2287,7 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
if (s->tcp_state == REXMPP_TCP_CONNECTING) {
rexmpp_err_t err =
rexmpp_process_conn_err(s,
- rexmpp_tcp_conn_proceed(&s->server_connection,
+ rexmpp_tcp_conn_proceed(s, &s->server_connection,
read_fds, write_fds));
if (err > REXMPP_E_AGAIN) {
return err;
@@ -2449,14 +2404,11 @@ int rexmpp_fds(rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
if (s->resolver_state != REXMPP_RESOLVER_NONE &&
s->resolver_state != REXMPP_RESOLVER_READY) {
- max_fd = ub_fd(s->resolver_ctx) + 1;
- if (max_fd != 0) {
- FD_SET(max_fd - 1, read_fds);
- }
+ max_fd = rexmpp_dns_fds(s, read_fds, write_fds);
}
if (s->tcp_state == REXMPP_TCP_CONNECTING) {
- conn_fd = rexmpp_tcp_conn_fds(&s->server_connection, read_fds, write_fds);
+ conn_fd = rexmpp_tcp_conn_fds(s, &s->server_connection, read_fds, write_fds);
if (conn_fd > max_fd) {
max_fd = conn_fd;
}
@@ -2503,7 +2455,7 @@ struct timeval *rexmpp_timeout (rexmpp_t *s,
s->resolver_state != REXMPP_RESOLVER_READY) {
} else if (s->tcp_state == REXMPP_TCP_CONNECTING) {
- ret = rexmpp_tcp_conn_timeout(&s->server_connection, max_tv, tv);
+ ret = rexmpp_tcp_conn_timeout(s, &s->server_connection, max_tv, tv);
}
struct timeval now;
gettimeofday(&now, NULL);
diff --git a/src/rexmpp.h b/src/rexmpp.h
index a7b376a..d8d5e86 100644
--- a/src/rexmpp.h
+++ b/src/rexmpp.h
@@ -13,7 +13,6 @@
#include "config.h"
-#include <unbound.h>
#include <gsasl.h>
#include <libxml/tree.h>
#ifdef HAVE_GPGME
@@ -311,10 +310,15 @@ struct rexmpp
time_t last_network_activity;
/* DNS-related structures. */
- struct ub_ctx *resolver_ctx;
- struct ub_result *server_srv;
+ /* struct ub_ctx *resolver_ctx; */
+ /* struct ub_result *server_srv; */
+ /* int server_srv_cur; */
+ /* struct ub_result *server_srv_tls; */
+ /* int server_srv_tls_cur; */
+ rexmpp_dns_ctx_t resolver;
+ rexmpp_dns_result_t *server_srv;
int server_srv_cur;
- struct ub_result *server_srv_tls;
+ rexmpp_dns_result_t *server_srv_tls;
int server_srv_tls_cur;
struct rexmpp_dns_srv server_active_srv;
diff --git a/src/rexmpp_dns.c b/src/rexmpp_dns.c
index 6a8e743..5b3fd9e 100644
--- a/src/rexmpp_dns.c
+++ b/src/rexmpp_dns.c
@@ -6,31 +6,298 @@
@copyright MIT license.
*/
-#include "rexmpp_dns.h"
#include <memory.h>
+#include <syslog.h>
+
+#include "config.h"
+
+#if defined(USE_UNBOUND)
+#include <unbound.h>
+#else
+#include <netdb.h>
+#endif
+
+#include "rexmpp.h"
+#include "rexmpp_dns.h"
+
+
+struct rexmpp_dns_query_cb_data {
+ rexmpp_t *s;
+ dns_query_cb_t cb;
+ void *ptr;
+};
+
+
/* https://tools.ietf.org/html/rfc1035#section-3.1 */
+
+int rexmpp_dns_parse_qname (char *in, int in_len, char *out, int out_len) {
+ int i = 0;
+ while (i < in_len && in[i]) {
+ if (i + in[i] < in_len && i + in[i] < out_len) {
+ memcpy(out + i, in + i + 1, in[i]);
+ i += in[i];
+ out[i] = '.';
+ i++;
+ out[i] = '\0';
+ } else {
+ return -1;
+ }
+ }
+ return i;
+}
+
int rexmpp_parse_srv (char *in, int in_len, struct rexmpp_dns_srv *out) {
- int i;
- char *name;
if (in_len < 7 || in_len > 255 + 6) {
return -1;
}
out->priority = in[0] * 0x100 + in[1];
out->weight = in[2] * 0x100 + in[3];
out->port = in[4] * 0x100 + in[5];
- name = in + 6;
- i = 0;
- while (name[i]) {
- if (i + name[i] < 255) {
- memcpy(out->target + i, name + i + 1, name[i]);
- i += name[i];
- out->target[i] = '.';
- i++;
- out->target[i] = '\0';
+ if (rexmpp_dns_parse_qname(in + 6, in_len - 6, out->target, 255) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+
+void rexmpp_dns_result_free (rexmpp_dns_result_t *result) {
+ if (result->data != NULL) {
+ int i;
+ for (i = 0; result->data[i] != NULL; i++) {
+ free(result->data[i]);
+ }
+ free(result->data);
+ result->data = NULL;
+ }
+ if (result->len != NULL) {
+ free(result->len);
+ result->len = NULL;
+ }
+ if (result->qname != NULL) {
+ free(result->qname);
+ result->qname = NULL;
+ }
+ free(result);
+}
+
+
+int rexmpp_dns_ctx_init (rexmpp_t *s) {
+#if defined(USE_UNBOUND)
+ int err;
+ s->resolver.ctx = ub_ctx_create();
+ if (s->resolver.ctx == NULL) {
+ rexmpp_log(s, LOG_CRIT, "Failed to create resolver context");
+ return 1;
+ }
+ err = ub_ctx_resolvconf(s->resolver.ctx, NULL);
+ if (err != 0) {
+ rexmpp_log(s, LOG_WARNING, "Failed to read resolv.conf: %s",
+ ub_strerror(err));
+ }
+ err = ub_ctx_hosts(s->resolver.ctx, NULL);
+ if (err != 0) {
+ rexmpp_log(s, LOG_WARNING, "Failed to read hosts file: %s",
+ ub_strerror(err));
+ }
+ err = ub_ctx_add_ta_file(s->resolver.ctx, DNSSEC_TRUST_ANCHOR_FILE);
+ if (err != 0) {
+ rexmpp_log(s, LOG_WARNING, "Failed to set root key file for DNSSEC: %s",
+ ub_strerror(err));
+ }
+ return 0;
+#else
+ (void)s;
+ return 0;
+#endif
+}
+
+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) {
+#if defined(USE_UNBOUND)
+ if (s->resolver.ctx != NULL) {
+ ub_ctx_delete(s->resolver.ctx);
+ s->resolver.ctx = NULL;
+ }
+#else
+ (void)s;
+#endif
+}
+
+int rexmpp_dns_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
+#if defined(USE_UNBOUND)
+ (void)write_fds;
+ int max_fd = ub_fd(s->resolver.ctx) + 1;
+ if (max_fd != 0) {
+ FD_SET(max_fd - 1, read_fds);
+ }
+ return max_fd;
+#else
+ (void)s;
+ (void)read_fds;
+ (void)write_fds;
+ return 0;
+#endif
+}
+
+struct timeval * rexmpp_dns_timeout (rexmpp_t *s,
+ struct timeval *max_tv,
+ struct timeval *tv)
+{
+#if defined(USE_UNBOUND)
+ (void)s;
+ (void)tv;
+ return max_tv;
+#else
+ (void)s;
+ (void)max_tv;
+ (void)tv;
+ return max_tv;
+#endif
+}
+
+#if defined(USE_UNBOUND)
+void rexmpp_dns_cb (void *ptr,
+ int err,
+ struct ub_result *result)
+{
+ struct rexmpp_dns_query_cb_data *d = ptr;
+ rexmpp_t *s = d->s;
+
+ if (err != 0) {
+ rexmpp_log(s, LOG_WARNING, "%s DNS query failure: %s",
+ result->qname, ub_strerror(err));
+ ub_resolve_free(result);
+ d->cb(s, d->ptr, NULL);
+ return;
+ }
+
+ if (result->bogus) {
+ rexmpp_log(s, LOG_WARNING,
+ "Received a bogus DNS resolution result for %s",
+ result->qname);
+ 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);
+ ub_resolve_free(result);
+ d->cb(s, d->ptr, NULL);
+ return;
+ }
+
+ int i, size = 0;
+ while (result->data[size] != NULL) {
+ size++;
+ }
+ rexmpp_dns_result_t *res = malloc(sizeof(rexmpp_dns_result_t));
+ res->data = malloc(sizeof(char *) * (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]);
+ }
+ 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);
+}
+#endif
+
+
+int rexmpp_dns_resolve (rexmpp_t *s,
+ const char *query,
+ int rrtype,
+ int rrclass,
+ void* ptr,
+ dns_query_cb_t callback)
+{
+#if defined(USE_UNBOUND)
+ struct rexmpp_dns_query_cb_data *d =
+ malloc(sizeof(struct rexmpp_dns_query_cb_data));
+ d->s = s;
+ d->cb = callback;
+ d->ptr = ptr;
+ int err = ub_resolve_async(s->resolver.ctx, query, rrtype, rrclass,
+ d, rexmpp_dns_cb, NULL);
+ if (err) {
+ rexmpp_log(s, LOG_ERR, "Failed to query %s: %s",
+ query, ub_strerror(err));
+ return 1;
+ }
+#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);
+ if (hostinfo == NULL) {
+ 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;
+ callback(s, ptr, r);
+ }
+ } else if (rrtype == 33) {
+ rexmpp_log(s, LOG_WARNING, "rexmpp is built without SRV lookup support");
+ callback(s, ptr, NULL);
} else {
+ rexmpp_log(s, LOG_ERR, "A DNS lookup of unrecognized type is requested");
+ callback(s, ptr, NULL);
return -1;
}
+ } else {
+ rexmpp_log(s, LOG_ERR, "A DNS lookup of unrecognized class is requested");
+ callback(s, ptr, NULL);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int rexmpp_dns_process (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) {
+#if defined(USE_UNBOUND)
+ (void)read_fds;
+ (void)write_fds;
+ if (ub_poll(s->resolver.ctx)) {
+ int err = ub_process(s->resolver.ctx);
+ if (err != 0) {
+ rexmpp_log(s, LOG_ERR, "DNS query processing error: %s",
+ ub_strerror(err));
+ return 1;
+ }
}
return 0;
+#else
+ (void)s;
+ (void)read_fds;
+ (void)write_fds;
+ return 0;
+#endif
}
diff --git a/src/rexmpp_dns.h b/src/rexmpp_dns.h
index 9d9f271..3c94e90 100644
--- a/src/rexmpp_dns.h
+++ b/src/rexmpp_dns.h
@@ -11,6 +11,22 @@
#define REXMPP_DNS_H
#include <stdint.h>
+#include "config.h"
+
+#include "rexmpp.h"
+
+#if defined(USE_UNBOUND)
+#include <unbound.h>
+struct rexmpp_dns_ctx {
+ struct ub_ctx *ctx;
+};
+#else
+struct rexmpp_dns_ctx {
+ int dummy;
+};
+#endif
+
+typedef struct rexmpp_dns_ctx rexmpp_dns_ctx_t;
struct rexmpp_dns_srv {
uint16_t priority;
@@ -19,6 +35,13 @@ struct rexmpp_dns_srv {
char target[256];
};
+struct rexmpp_dns_result {
+ char **data;
+ int *len;
+ char *qname;
+ int secure;
+};
+
/**
@brief Parses an SRV DNS RR's RDATA.
@param[in] in SRV record's RDATA.
@@ -29,4 +52,29 @@ struct rexmpp_dns_srv {
int
rexmpp_parse_srv (char *in, int in_len, struct rexmpp_dns_srv *out);
+typedef struct rexmpp_dns_result rexmpp_dns_result_t;
+
+/* struct rexmpp_dns_result *rexmpp_dns_result_init (int len); */
+void rexmpp_dns_result_free (rexmpp_dns_result_t *result);
+
+int rexmpp_dns_ctx_init (rexmpp_t *s);
+void rexmpp_dns_ctx_cleanup (rexmpp_t *s);
+void rexmpp_dns_ctx_deinit (rexmpp_t *s);
+int rexmpp_dns_fds (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
+struct timeval * rexmpp_dns_timeout (rexmpp_t *s,
+ struct timeval *max_tv,
+ struct timeval *tv);
+
+typedef void (*dns_query_cb_t) (rexmpp_t *s, void *ptr, rexmpp_dns_result_t *result);
+
+int rexmpp_dns_resolve (rexmpp_t *s,
+ const char *query,
+ int rrtype,
+ int rrclass,
+ void* ptr,
+ dns_query_cb_t callback);
+
+int rexmpp_dns_process (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds);
+
+
#endif
diff --git a/src/rexmpp_tcp.c b/src/rexmpp_tcp.c
index 27c3ba4..a4d5018 100644
--- a/src/rexmpp_tcp.c
+++ b/src/rexmpp_tcp.c
@@ -6,7 +6,6 @@
@copyright MIT license.
*/
-#include <unbound.h>
#include <netdb.h>
#include <arpa/nameser.h>
#include <sys/socket.h>
@@ -19,17 +18,19 @@
#include <arpa/inet.h>
#include <fcntl.h>
+#include "rexmpp.h"
#include "rexmpp_tcp.h"
+#include "rexmpp_dns.h"
-void rexmpp_dns_aaaa_cb (void *ptr,
- int status,
- struct ub_result *result)
+void rexmpp_tcp_dns_aaaa_cb (rexmpp_t *s,
+ void *ptr,
+ rexmpp_dns_result_t *result)
{
+ (void)s;
rexmpp_tcp_conn_t *conn = ptr;
- conn->resolver_status_v6 = status;
conn->resolved_v6 = result;
- if (status == 0 && ! result->bogus && result->havedata) {
+ if (result != NULL) {
conn->resolution_v6 = REXMPP_CONN_RESOLUTION_SUCCESS;
conn->addr_cur_v6 = -1;
} else {
@@ -37,14 +38,14 @@ void rexmpp_dns_aaaa_cb (void *ptr,
}
}
-void rexmpp_dns_a_cb (void *ptr,
- int status,
- struct ub_result *result)
+void rexmpp_tcp_dns_a_cb (rexmpp_t *s,
+ void *ptr,
+ rexmpp_dns_result_t *result)
{
+ (void)s;
rexmpp_tcp_conn_t *conn = ptr;
- conn->resolver_status_v4 = status;
conn->resolved_v4 = result;
- if (status == 0 && ! result->bogus && result->havedata) {
+ if (result != NULL) {
conn->resolution_v4 = REXMPP_CONN_RESOLUTION_SUCCESS;
conn->addr_cur_v4 = -1;
if (conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) {
@@ -74,11 +75,11 @@ void rexmpp_tcp_cleanup (rexmpp_tcp_conn_t *conn) {
conn->resolution_v6 = REXMPP_CONN_RESOLUTION_INACTIVE;
}
if (conn->resolved_v4 != NULL) {
- ub_resolve_free(conn->resolved_v4);
+ rexmpp_dns_result_free(conn->resolved_v4);
conn->resolved_v4 = NULL;
}
if (conn->resolved_v6 != NULL) {
- ub_resolve_free(conn->resolved_v6);
+ rexmpp_dns_result_free(conn->resolved_v6);
conn->resolved_v6 = NULL;
}
}
@@ -99,8 +100,8 @@ rexmpp_tcp_connected (rexmpp_tcp_conn_t *conn, int fd) {
}
rexmpp_tcp_conn_error_t
-rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn,
- struct ub_ctx *resolver_ctx,
+rexmpp_tcp_conn_init (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
const char *host,
uint16_t port)
{
@@ -165,12 +166,11 @@ rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn,
}
conn->resolution_v4 = REXMPP_CONN_RESOLUTION_WAITING;
conn->resolution_v6 = REXMPP_CONN_RESOLUTION_WAITING;
- conn->resolver_ctx = resolver_ctx;
- ub_resolve_async(conn->resolver_ctx, host, 28, 1,
- conn, rexmpp_dns_aaaa_cb, NULL);
- ub_resolve_async(conn->resolver_ctx, host, 1, 1,
- conn, rexmpp_dns_a_cb, NULL);
+ rexmpp_dns_resolve(s, host, 28, 1,
+ conn, rexmpp_tcp_dns_aaaa_cb);
+ rexmpp_dns_resolve(s, host, 1, 1,
+ conn, rexmpp_tcp_dns_a_cb);
return REXMPP_CONN_IN_PROGRESS;
}
@@ -193,7 +193,8 @@ int rexmpp_tcp_conn_ipv6_available(rexmpp_tcp_conn_t *conn) {
}
rexmpp_tcp_conn_error_t
-rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn,
+rexmpp_tcp_conn_proceed (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
fd_set *read_fds,
fd_set *write_fds)
{
@@ -222,9 +223,7 @@ rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn,
/* Name resolution. */
if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING ||
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) {
- if (ub_poll(conn->resolver_ctx)) {
- ub_process(conn->resolver_ctx);
- }
+ rexmpp_dns_process(s, read_fds, write_fds);
}
if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_FAILURE &&
@@ -344,17 +343,15 @@ rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn,
}
}
-int rexmpp_tcp_conn_fds (rexmpp_tcp_conn_t *conn,
+int rexmpp_tcp_conn_fds (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
fd_set *read_fds,
fd_set *write_fds)
{
int max_fd = 0, i;
if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING ||
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) {
- max_fd = ub_fd(conn->resolver_ctx) + 1;
- if (max_fd != 0) {
- FD_SET(max_fd - 1, read_fds);
- }
+ max_fd = rexmpp_dns_fds(s, read_fds, write_fds);
}
for (i = 0; i < REXMPP_TCP_MAX_CONNECTION_ATTEMPTS; i++) {
if (conn->sockets[i] != -1) {
@@ -367,12 +364,17 @@ int rexmpp_tcp_conn_fds (rexmpp_tcp_conn_t *conn,
return max_fd;
}
-struct timeval *rexmpp_tcp_conn_timeout (rexmpp_tcp_conn_t *conn,
+struct timeval *rexmpp_tcp_conn_timeout (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
struct timeval *max_tv,
struct timeval *tv)
{
struct timeval now;
struct timeval *ret = max_tv;
+ if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_WAITING ||
+ conn->resolution_v6 == REXMPP_CONN_RESOLUTION_WAITING) {
+ ret = rexmpp_dns_timeout(s, max_tv, tv);
+ }
if (conn->resolution_v4 == REXMPP_CONN_RESOLUTION_SUCCESS ||
conn->resolution_v6 == REXMPP_CONN_RESOLUTION_SUCCESS ||
(conn->resolution_v4 == REXMPP_CONN_RESOLUTION_INACTIVE &&
diff --git a/src/rexmpp_tcp.h b/src/rexmpp_tcp.h
index 1e13ca3..5a296cc 100644
--- a/src/rexmpp_tcp.h
+++ b/src/rexmpp_tcp.h
@@ -21,6 +21,9 @@
#include <sys/time.h>
+#include "rexmpp.h"
+#include "rexmpp_dns.h"
+
#define REXMPP_TCP_MAX_CONNECTION_ATTEMPTS 20
#define REXMPP_TCP_IPV6_DELAY_MS 50
#define REXMPP_TCP_CONN_DELAY_MS 250
@@ -70,19 +73,13 @@ struct rexmpp_tcp_connection {
/** @brief A port we are connecting to. */
uint16_t port;
- /** @brief Resolver context. */
- struct ub_ctx *resolver_ctx;
- /** @brief Resolver error is stored here when
- ::REXMPP_CONN_RESOLVER_ERROR is returned. */
- int resolver_error;
-
/** @brief State of A record resolution. */
enum rexmpp_tcp_conn_resolution_status resolution_v4;
/** @brief Status of A record resolution, as returned by the
resolver. */
int resolver_status_v4;
/** @brief Resolved A records. */
- struct ub_result *resolved_v4;
+ rexmpp_dns_result_t *resolved_v4;
/** @brief The AF_INET address number we are currently at. */
int addr_cur_v4;
@@ -92,7 +89,7 @@ struct rexmpp_tcp_connection {
resolver. */
int resolver_status_v6;
/** @brief Resolved AAAA records. */
- struct ub_result *resolved_v6;
+ rexmpp_dns_result_t *resolved_v6;
/** @brief The AF_INET6 address number we are currently at. */
int addr_cur_v6;
@@ -112,28 +109,30 @@ struct rexmpp_tcp_connection {
/**
@brief Initiates a connection.
+ @param[in] s ::rexmpp
@param[out] conn An allocated connection structure.
- @param[in] resolver_ctx Resolver context to use.
@param[in] host A host to connect to. This could be a domain name,
or a textual representation of an IPv4 or an IPv6 address.
@param[in] port A port to connect to.
@returns A ::rexmpp_tcp_conn_error state.
*/
rexmpp_tcp_conn_error_t
-rexmpp_tcp_conn_init (rexmpp_tcp_conn_t *conn,
- struct ub_ctx *resolver_ctx,
+rexmpp_tcp_conn_init (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
const char *host,
uint16_t port);
/**
@brief Continues a connection process.
+ @param[in] s ::rexmpp
@param[in,out] conn An active connection structure.
@param[in] read_fds File descriptors available for reading from.
@param[in] write_fds File descriptors available for writing to.
@returns A ::rexmpp_tcp_conn_error state.
*/
rexmpp_tcp_conn_error_t
-rexmpp_tcp_conn_proceed (rexmpp_tcp_conn_t *conn,
+rexmpp_tcp_conn_proceed (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
fd_set *read_fds,
fd_set *write_fds);
@@ -158,6 +157,7 @@ int rexmpp_tcp_conn_finish (rexmpp_tcp_conn_t *conn);
File descriptors are only added to an @c fd_set, so the ones it
already contains will not be lost.
+ @param[in] s ::rexmpp
@param[in] conn An active connection structure.
@param[out] read_fds File descriptors a connection process is
interested in reading from.
@@ -165,19 +165,22 @@ int rexmpp_tcp_conn_finish (rexmpp_tcp_conn_t *conn);
interested in writing to.
@returns Maximum file descriptor number, plus 1.
*/
-int rexmpp_tcp_conn_fds (rexmpp_tcp_conn_t *conn,
+int rexmpp_tcp_conn_fds (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
fd_set *read_fds,
fd_set *write_fds);
/**
@brief Reports timeouts.
+ @param[in] s ::rexmpp
@param[in] conn An active connection structure.
@param[in] max_tv An existing maximum timeout.
@param[out] tv A timeval structure to store a new timeout in.
@returns A pointer to either max_tv or tv, depending on which one
is smaller.
*/
-struct timeval *rexmpp_tcp_conn_timeout (rexmpp_tcp_conn_t *conn,
+struct timeval *rexmpp_tcp_conn_timeout (rexmpp_t *s,
+ rexmpp_tcp_conn_t *conn,
struct timeval *max_tv,
struct timeval *tv);