]> jfr.im git - solanum.git/blobdiff - ircd/dns.c
Mailmap and copyright update for Ariadne
[solanum.git] / ircd / dns.c
index 2162e0c05acc65c970459e341a01f52efc87a174..20ce14800e5d94850aaaef0a53a812aabef08518 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  Copyright (C) 2005 Aaron Sethman <androsyn@ratbox.org>
  *  Copyright (C) 2005-2012 ircd-ratbox development team
- *  Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
+ *  Copyright (C) 2016 Ariadne Conill <ariadne@dereferenced.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  USA
  */
 
-#include <stdinc.h>
-#include <ratbox_lib.h>
-#include <struct.h>
-#include <ircd_defs.h>
-#include <parse.h>
-#include <dns.h>
-#include <match.h>
-#include <logger.h>
-#include <s_conf.h>
-#include <client.h>
-#include <send.h>
-#include <numeric.h>
-#include <msg.h>
-
-#define DNS_IDTABLE_SIZE 0x2000
-
-#define DNS_HOST       ((char)'H')
-#define DNS_REVERSE    ((char)'I')
-
-static void submit_dns(const char, uint16_t id, int aftype, const char *addr);
-
-static int start_authd(void);
-static void parse_authd_reply(rb_helper * helper);
-static void restart_authd_cb(rb_helper * helper);
-
-static rb_helper *authd_helper;
+#include "stdinc.h"
+#include "rb_lib.h"
+#include "client.h"
+#include "ircd_defs.h"
+#include "parse.h"
+#include "dns.h"
+#include "match.h"
+#include "logger.h"
+#include "s_conf.h"
+#include "client.h"
+#include "send.h"
+#include "numeric.h"
+#include "msg.h"
+#include "hash.h"
+#include "s_assert.h"
+
+#define DNS_HOST_IPV4          ((char)'4')
+#define DNS_HOST_IPV6          ((char)'6')
+#define DNS_REVERSE_IPV4       ((char)'R')
+#define DNS_REVERSE_IPV6       ((char)'S')
+
+static void submit_dns(uint32_t uid, char type, const char *addr);
+static void submit_dns_stat(uint32_t uid);
 
 struct dnsreq
 {
@@ -55,274 +52,292 @@ struct dnsreq
        void *data;
 };
 
-static struct dnsreq querytable[DNS_IDTABLE_SIZE];
+struct dnsstatreq
+{
+       DNSLISTCB callback;
+       void *data;
+};
 
-static uint16_t
-assign_dns_id(void)
+/* These serve as a form of sparse array */
+static rb_dictionary *query_dict;
+static rb_dictionary *stat_dict;
+
+rb_dlink_list nameservers;
+
+static uint32_t query_id = 0;
+static uint32_t stat_id = 0;
+
+
+static inline uint32_t
+assign_id(uint32_t *id)
 {
-       static uint16_t id = 1;
-       int loopcnt = 0;
-       while(1)
-       {
-               if(++loopcnt > DNS_IDTABLE_SIZE)
-                       return 0;
-               if(id < DNS_IDTABLE_SIZE - 1 || id == 0)
-                       id++;
-               else
-                       id = 1;
-               if(querytable[id].callback == NULL)
-                       break;
-       }
-       return (id);
+       if(++(*id) == 0)
+               *id = 1;
+
+       return *id;
 }
 
-static inline void
-check_authd(void)
+static void
+handle_dns_failure(uint32_t xid)
 {
-       if(authd_helper == NULL)
-               restart_authd();
+       struct dnsreq *req = rb_dictionary_retrieve(query_dict, RB_UINT_TO_POINTER(xid));
+       s_assert(req);
+
+       if(req == NULL || req->callback == NULL)
+               return;
+
+       req->callback("FAILED", 0, 0, req->data);
+       req->callback = NULL;
+       req->data = NULL;
 }
 
 static void
-handle_dns_failure(uint16_t xid)
+handle_dns_stat_failure(uint32_t xid)
 {
-       struct dnsreq *req;
+       struct dnsstatreq *req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(xid));
+       s_assert(req);
 
-       req = &querytable[xid];
-       if(req->callback == NULL)
+       if(req == NULL || req->callback == NULL)
                return;
 
-       req->callback("FAILED", 0, 0, req->data);
+       req->callback(1, NULL, 2, req->data);
        req->callback = NULL;
        req->data = NULL;
 }
 
+
 void
-cancel_lookup(uint16_t xid)
+cancel_lookup(uint32_t xid)
 {
-       querytable[xid].callback = NULL;
-       querytable[xid].data = NULL;
+       struct dnsreq *req = rb_dictionary_retrieve(query_dict, RB_UINT_TO_POINTER(xid));
+       s_assert(req);
+
+       if (req == NULL)
+               return;
+
+       req->callback = NULL;
+       req->data = NULL;
 }
 
-uint16_t
+void
+cancel_dns_stats(uint32_t xid)
+{
+       struct dnsstatreq *req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(xid));
+       s_assert(req);
+
+       if (req == NULL)
+               return;
+
+       req->callback = NULL;
+       req->data = NULL;
+}
+
+
+uint32_t
 lookup_hostname(const char *hostname, int aftype, DNSCB callback, void *data)
 {
-       struct dnsreq *req;
+       struct dnsreq *req = rb_malloc(sizeof(struct dnsreq));
        int aft;
-       uint16_t nid;
+       uint32_t rid = assign_id(&query_id);
+
        check_authd();
-       nid = assign_dns_id();
-       if((nid = assign_dns_id()) == 0)
-               return 0;
 
-       req = &querytable[nid];
+       rb_dictionary_add(query_dict, RB_UINT_TO_POINTER(rid), req);
 
        req->callback = callback;
        req->data = data;
 
-#ifdef RB_IPV6
        if(aftype == AF_INET6)
                aft = 6;
        else
-#endif
                aft = 4;
 
-       submit_dns(DNS_HOST, nid, aft, hostname);
-       return (nid);
+       submit_dns(rid, aft == 4 ? DNS_HOST_IPV4 : DNS_HOST_IPV6, hostname);
+       return (rid);
 }
 
-uint16_t
+uint32_t
 lookup_ip(const char *addr, int aftype, DNSCB callback, void *data)
 {
-       struct dnsreq *req;
+       struct dnsreq *req = rb_malloc(sizeof(struct dnsreq));
        int aft;
-       uint16_t nid;
+       uint32_t rid = assign_id(&query_id);
+
        check_authd();
 
-       if((nid = assign_dns_id()) == 0)
-               return 0;
-               
-       req = &querytable[nid];
+       rb_dictionary_add(query_dict, RB_UINT_TO_POINTER(rid), req);
 
        req->callback = callback;
        req->data = data;
 
-#ifdef RB_IPV6
        if(aftype == AF_INET6)
                aft = 6;
        else
-#endif
                aft = 4;
 
-       submit_dns(DNS_REVERSE, nid, aft, addr);
-       return (nid);
+       submit_dns(rid, aft == 4 ? DNS_REVERSE_IPV4 : DNS_REVERSE_IPV6, addr);
+       return (rid);
 }
 
-static void
-results_callback(const char *callid, const char *status, const char *aftype, const char *results)
+static uint32_t
+get_nameservers(DNSLISTCB callback, void *data)
+{
+       struct dnsstatreq *req = rb_malloc(sizeof(struct dnsstatreq));
+       uint32_t qid = assign_id(&stat_id);
+
+       check_authd();
+
+       rb_dictionary_add(stat_dict, RB_UINT_TO_POINTER(qid), req);
+
+       req->callback = callback;
+       req->data = data;
+
+       submit_dns_stat(qid);
+       return (qid);
+}
+
+
+void
+dns_results_callback(const char *callid, const char *status, const char *type, const char *results)
 {
        struct dnsreq *req;
-       uint16_t nid;
+       uint32_t rid;
        int st;
        int aft;
-       long lnid = strtol(callid, NULL, 16);
+       long lrid = strtol(callid, NULL, 16);
 
-       if(lnid > DNS_IDTABLE_SIZE || lnid == 0)
+       if(lrid > UINT32_MAX)
                return;
-       nid = (uint16_t)lnid;
-       req = &querytable[nid];
-       st = atoi(status);
-       aft = atoi(aftype);
+
+       rid = (uint32_t)lrid;
+       req = rb_dictionary_retrieve(query_dict, RB_UINT_TO_POINTER(rid));
+       if(req == NULL)
+               return;
+
+       st = (*status == 'O');
+       aft = *type == '6' || *type == 'S' ? 6 : 4;
        if(req->callback == NULL)
        {
                /* got cancelled..oh well */
                req->data = NULL;
                return;
        }
-#ifdef RB_IPV6
        if(aft == 6)
                aft = AF_INET6;
        else
-#endif
                aft = AF_INET;
 
        req->callback(results, st, aft, req->data);
-       req->callback = NULL;
-       req->data = NULL;
-}
 
+       rb_free(req);
+       rb_dictionary_delete(query_dict, RB_UINT_TO_POINTER(rid));
+}
 
-static char *resolver_path;
-
-static int
-start_authd(void)
+void
+dns_stats_results_callback(const char *callid, const char *status, int resc, const char *resv[])
 {
-       char fullpath[PATH_MAX + 1];
-#ifdef _WIN32
-       const char *suffix = ".exe";
-#else
-       const char *suffix = "";
-#endif
-       if(resolver_path == NULL)
-       {
-               snprintf(fullpath, sizeof(fullpath), "%s/authd%s", PKGLIBEXECDIR, suffix);
+       struct dnsstatreq *req;
+       uint32_t qid;
+       int st;
+       long lqid = strtol(callid, NULL, 16);
 
-               if(access(fullpath, X_OK) == -1)
-               {
-                       snprintf(fullpath, sizeof(fullpath), "%s/libexec/charybdis/authd%s",
-                                ConfigFileEntry.dpath, suffix);
-                       if(access(fullpath, X_OK) == -1)
-                       {
-                               ilog(L_MAIN,
-                                    "Unable to execute authd in %s or %s/libexec/charybdis",
-                                    PKGLIBEXECDIR, ConfigFileEntry.dpath);
-                               sendto_realops_snomask(SNO_GENERAL, L_ALL,
-                                                      "Unable to execute resolver in %s or %s/libexec/charybdis",
-                                                      PKGLIBEXECDIR, ConfigFileEntry.dpath);
-                               return 1;
-                       }
+       if(lqid > UINT32_MAX)
+               return;
 
-               }
+       qid = (uint32_t)lqid;
+       req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(qid));
 
-               resolver_path = rb_strdup(fullpath);
-       }
-
-       authd_helper = rb_helper_start("authd", resolver_path, parse_authd_reply, restart_authd_cb);
+       s_assert(req);
+       if (req == NULL)
+               return;
 
-       if(authd_helper == NULL)
+       if(req->callback == NULL)
        {
-               ilog(L_MAIN, "Unable to start authd helper: %s", strerror(errno));
-               sendto_realops_snomask(SNO_GENERAL, L_ALL, "Unable to start authd helper: %s", strerror(errno));
-               return 1;
+               req->data = NULL;
+               return;
        }
-       ilog(L_MAIN, "resolver helper started");
-       sendto_realops_snomask(SNO_GENERAL, L_ALL, "resolver helper started");
-       rb_helper_run(authd_helper);
-       return 0;
-}
 
-void
-report_dns_servers(struct Client *source_p)
-{
-#if 0
-       rb_dlink_node *ptr;
-       RB_DLINK_FOREACH(ptr, nameservers.head)
+       switch(*status)
        {
-               sendto_one_numeric(source_p, RPL_STATSDEBUG, "A %s", (char *)ptr->data);
+       case 'Y':
+               st = 0;
+               break;
+       case 'X':
+               /* Error */
+               st = 1;
+               break;
+       default:
+               /* Shouldn't happen... */
+               return;
        }
-#endif
+
+       /* Query complete */
+       req->callback(resc, resv, st, req->data);
+
+       rb_free(req);
+       rb_dictionary_delete(stat_dict, RB_UINT_TO_POINTER(qid));
 }
 
 static void
-parse_authd_reply(rb_helper * helper)
+stats_results_callback(int resc, const char *resv[], int status, void *data)
 {
-       ssize_t len;
-       int parc;
-       char dnsBuf[READBUF_SIZE];
-
-       char *parv[MAXPARA + 1];
-       while((len = rb_helper_read(helper, dnsBuf, sizeof(dnsBuf))) > 0)
+       if(status == 0)
        {
-               parc = rb_string_to_array(dnsBuf, parv, MAXPARA+1); 
+               rb_dlink_node *n, *tn;
 
-               if(*parv[0] == 'R')
+               RB_DLINK_FOREACH_SAFE(n, tn, nameservers.head)
                {
-                       if(parc != 5)
-                       {
-                               ilog(L_MAIN, "authd sent a result with wrong number of arguments: got %d", parc);
-                               restart_authd();
-                               return;
-                       }
-                       results_callback(parv[1], parv[2], parv[3], parv[4]);
+                       /* Clean up old nameservers */
+                       rb_free(n->data);
+                       rb_dlinkDestroy(n, &nameservers);
                }
-               else
-                       return;
+
+               for(int i = 0; i < resc; i++)
+                       rb_dlinkAddAlloc(rb_strdup(resv[i]), &nameservers);
+       }
+       else
+       {
+               const char *error = resc ? resv[resc - 1] : "Unknown error";
+               iwarn("Error getting DNS servers: %s", error);
        }
 }
 
-static void
-submit_dns(char type, uint16_t nid, int aftype, const char *addr)
+
+void
+init_dns(void)
 {
-       if(authd_helper == NULL)
-       {
-               handle_dns_failure(nid);
-               return;
-       }
-       rb_helper_write(authd_helper, "%c %x %d %s", type, nid, aftype, addr);
+       query_dict = rb_dictionary_create("dns queries", rb_uint32cmp);
+       stat_dict = rb_dictionary_create("dns stat queries", rb_uint32cmp);
+       (void)get_nameservers(stats_results_callback, NULL);
 }
 
 void
-init_authd(void)
+reload_nameservers(void)
 {
-       if(start_authd())
-       {
-               ilog(L_MAIN, "Unable to start authd helper: %s", strerror(errno));
-               exit(0);
-       }
+       check_authd();
+       rb_helper_write(authd_helper, "R D");
+       (void)get_nameservers(stats_results_callback, NULL);
 }
 
+
 static void
-restart_authd_cb(rb_helper * helper)
+submit_dns(uint32_t nid, char type, const char *addr)
 {
-       ilog(L_MAIN, "authd: restart_authd_cb called, authd died?");
-       sendto_realops_snomask(SNO_GENERAL, L_ALL, "authd - restart_authd_cb called, authd died?");
-       if(helper != NULL)
+       if(authd_helper == NULL)
        {
-               rb_helper_close(helper);
-               authd_helper = NULL;
+               handle_dns_failure(nid);
+               return;
        }
-       start_authd();
-}
-
-void
-restart_authd(void)
-{
-       restart_authd_cb(authd_helper);
+       rb_helper_write(authd_helper, "D %x %c %s", nid, type, addr);
 }
 
-void
-rehash_resolver(void)
+static void
+submit_dns_stat(uint32_t nid)
 {
-       rb_helper_write(authd_helper, "R");
+       if(authd_helper == NULL)
+       {
+               handle_dns_stat_failure(nid);
+               return;
+       }
+       rb_helper_write(authd_helper, "S %x D", nid);
 }
-