X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/fe037171d6c2b5e9d28ac10a015a13ca5e011cee..8e1bdeda92e1414e312406e7169caf40ad48308b:/ircd/dns.c diff --git a/ircd/dns.c b/ircd/dns.c index ed6cd57e..92cca073 100644 --- a/ircd/dns.c +++ b/ircd/dns.c @@ -22,28 +22,29 @@ * USA */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DNS_IDTABLE_SIZE 0x2000 +#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(uint16_t id, char type, const char *addr); +static void submit_dns(uint32_t uid, char type, const char *addr); +static void submit_dns_stat(uint32_t uid); struct dnsreq { @@ -51,34 +52,38 @@ struct dnsreq void *data; }; -static struct dnsreq querytable[DNS_IDTABLE_SIZE]; +struct dnsstatreq +{ + DNSLISTCB callback; + void *data; +}; + +/* 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 uint16_t -assign_dns_id(void) +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 void -handle_dns_failure(uint16_t xid) +handle_dns_failure(uint32_t xid) { - struct dnsreq *req; + struct dnsreq *req = rb_dictionary_retrieve(query_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); @@ -86,81 +91,130 @@ handle_dns_failure(uint16_t xid) req->data = NULL; } +static void +handle_dns_stat_failure(uint32_t xid) +{ + struct dnsstatreq *req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(xid)); + s_assert(req); + + if(req == NULL || req->callback == NULL) + return; + + req->callback(1, NULL, 2, req->data); + req->callback = NULL; + req->data = NULL; +} + + +void +cancel_lookup(uint32_t xid) +{ + 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; +} + void -cancel_lookup(uint16_t xid) +cancel_dns_stats(uint32_t xid) { - querytable[xid].callback = NULL; - querytable[xid].data = NULL; + 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; } -uint16_t + +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(nid, aft == 4 ? DNS_HOST_IPV4 : DNS_HOST_IPV6, 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(nid, aft == 4 ? DNS_REVERSE_IPV4 : DNS_REVERSE_IPV6, addr); - return (nid); + submit_dns(rid, aft == 4 ? DNS_REVERSE_IPV4 : DNS_REVERSE_IPV6, addr); + return (rid); } +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 = *status == 'O'; + + 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) { @@ -168,32 +222,106 @@ dns_results_callback(const char *callid, const char *status, const char *type, c 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)); } void -report_dns_servers(struct Client *source_p) +dns_stats_results_callback(const char *callid, const char *status, int resc, const char *resv[]) +{ + struct dnsstatreq *req; + uint32_t qid; + int st; + long lqid = strtol(callid, NULL, 16); + + if(lqid > UINT32_MAX) + return; + + qid = (uint32_t)lqid; + req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(qid)); + + s_assert(req); + if (req == NULL) + return; + + if(req->callback == NULL) + { + req->data = NULL; + return; + } + + switch(*status) + { + case 'Y': + st = 0; + break; + case 'X': + /* Error */ + st = 1; + break; + default: + /* Shouldn't happen... */ + return; + } + + /* Query complete */ + req->callback(resc, resv, st, req->data); + + rb_free(req); + rb_dictionary_delete(stat_dict, RB_UINT_TO_POINTER(qid)); +} + +static void +stats_results_callback(int resc, const char *resv[], int status, void *data) { -#if 0 - rb_dlink_node *ptr; - RB_DLINK_FOREACH(ptr, nameservers.head) + if(status == 0) + { + rb_dlink_node *n, *tn; + + RB_DLINK_FOREACH_SAFE(n, tn, nameservers.head) + { + /* Clean up old nameservers */ + rb_free(n->data); + rb_dlinkDestroy(n, &nameservers); + } + + for(int i = 0; i < resc; i++) + rb_dlinkAddAlloc(rb_strdup(resv[i]), &nameservers); + } + else { - sendto_one_numeric(source_p, RPL_STATSDEBUG, "A %s", (char *)ptr->data); + const char *error = resc ? resv[resc - 1] : "Unknown error"; + iwarn("Error getting DNS servers: %s", error); } -#endif } + +void +init_dns(void) +{ + 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 +reload_nameservers(void) +{ + check_authd(); + rb_helper_write(authd_helper, "R D"); + (void)get_nameservers(stats_results_callback, NULL); +} + + static void -submit_dns(uint16_t nid, char type, const char *addr) +submit_dns(uint32_t nid, char type, const char *addr) { if(authd_helper == NULL) { @@ -202,3 +330,14 @@ submit_dns(uint16_t nid, char type, const char *addr) } rb_helper_write(authd_helper, "D %x %c %s", nid, type, addr); } + +static void +submit_dns_stat(uint32_t nid) +{ + if(authd_helper == NULL) + { + handle_dns_stat_failure(nid); + return; + } + rb_helper_write(authd_helper, "S %x D", nid); +}