summaryrefslogtreecommitdiff
path: root/src/rexmpp_dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rexmpp_dns.c')
-rw-r--r--src/rexmpp_dns.c291
1 files changed, 279 insertions, 12 deletions
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
}