diff --git a/include/dns.h b/include/dns.h index b0be628c..f5655e16 100644 --- a/include/dns.h +++ b/include/dns.h @@ -29,6 +29,8 @@ #include "stdinc.h" #include "authd.h" +extern rb_dlink_list nameservers; + typedef void (*DNSCB)(const char *res, int status, int aftype, void *data); typedef void (*DNSLISTCB)(int resc, const char *resv[], int status, void *data); @@ -37,6 +39,7 @@ uint16_t lookup_ip(const char *hostname, int aftype, DNSCB callback, void *data) void cancel_lookup(uint16_t xid); void dns_results_callback(const char *callid, const char *status, const char *aftype, const char *results); void dns_stats_results_callback(const char *callid, const char *status, int resc, const char *resv[]); -void report_dns_servers(struct Client *, char); +void report_dns_servers(struct Client *); +void init_nameserver_cache(void); #endif diff --git a/ircd/dns.c b/ircd/dns.c index 416b9c49..a9fc6539 100644 --- a/ircd/dns.c +++ b/ircd/dns.c @@ -60,14 +60,10 @@ struct dnsstatreq void *data; }; -struct dnsstatreq_data -{ - char uid[IDLEN]; - char statchar; -}; - static struct dnsreq querytable[DNS_IDTABLE_SIZE]; static struct dnsstatreq stattable[DNS_STATTABLE_SIZE]; +rb_dlink_list nameservers; + static uint16_t assign_dns_id(void) @@ -133,9 +129,6 @@ handle_dns_stat_failure(uint8_t xid) req->callback(1, err, 2, req->data); - /* NOTE - this assumes req->data is on the heap */ - rb_free(req->data); - req->callback = NULL; req->data = NULL; } @@ -150,9 +143,6 @@ cancel_lookup(uint16_t xid) void cancel_dns_stats(uint16_t xid) { - /* NOTE - this assumes data is on the heap */ - rb_free(stattable[xid].data); - stattable[xid].callback = NULL; stattable[xid].data = NULL; } @@ -277,8 +267,6 @@ dns_stats_results_callback(const char *callid, const char *status, int resc, con if(req->callback == NULL) { - /* NOTE - this assumes req->data is strdup'd or such */ - rb_free(req->data); req->data = NULL; return; } @@ -300,45 +288,49 @@ dns_stats_results_callback(const char *callid, const char *status, int resc, con /* Query complete */ req->callback(resc, resv, st, stattable[nid].data); - rb_free(req->data); req->data = NULL; req->callback = NULL; } static void -report_dns_servers_cb(int resc, const char *resv[], int status, void *data) +get_nameservers_cb(int resc, const char *resv[], int status, void *data) { - struct Client *source_p; - struct dnsstatreq_data *c_data = data; - - if(!(source_p = find_id(c_data->uid))) - /* Client's gone, oh well. */ - return; - 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++) - sendto_one_numeric(source_p, RPL_STATSDEBUG, "A %s", resv[i]); + rb_dlinkAddAlloc(rb_strdup(resv[i]), &nameservers); } else { - if(resc && resv[resc][0]) - /* XXX is this the right reply? */ - sendto_one_numeric(source_p, RPL_STATSDEBUG, "A Error: %s", resv[resc]); + const char *error = resc ? resv[resc] : "Unknown error"; + iwarn(L_MAIN, "Error getting DNS servers: %s", error); } - - sendto_one_numeric(source_p, RPL_ENDOFSTATS, form_str(RPL_ENDOFSTATS), c_data->statchar); } void -report_dns_servers(struct Client *source_p, char statchar) +report_dns_servers(struct Client *source_p) { - /* Use the UID to avoid a race where source_p goes away */ - struct dnsstatreq_data *data = rb_malloc(sizeof(struct dnsstatreq_data)); - rb_strlcpy(data->uid, source_p->id, IDLEN); - data->statchar = statchar; + rb_dlink_node *n; - get_nameservers(report_dns_servers_cb, data); + RB_DLINK_FOREACH(n, nameservers.head) + { + sendto_one_numeric(source_p, RPL_STATSDEBUG, "A %s", (char *)n->data); + } +} + +void +init_nameserver_cache(void) +{ + (void)get_nameservers(get_nameservers_cb, NULL); } static void diff --git a/ircd/ircd.c b/ircd/ircd.c index 109c5f05..d5726d05 100644 --- a/ircd/ircd.c +++ b/ircd/ircd.c @@ -663,6 +663,8 @@ charybdis_main(int argc, char *argv[]) init_auth(); /* Initialise the auth code */ init_authd(); /* Start up authd. */ + init_nameserver_cache(); /* Get our nameserver cache for STATS a/A */ + privilegeset_set_new("default", "", 0); if (testing_conf) diff --git a/modules/m_stats.c b/modules/m_stats.c index cedd60ed..a2cf3ceb 100644 --- a/modules/m_stats.c +++ b/modules/m_stats.c @@ -89,7 +89,7 @@ struct StatsStruct int need_admin; }; -static void stats_dns_servers(struct Client *, char); +static void stats_dns_servers(struct Client *); static void stats_delay(struct Client *); static void stats_hash(struct Client *); static void stats_connect(struct Client *); @@ -132,8 +132,8 @@ static void stats_capability(struct Client *); */ static struct StatsStruct stats_cmd_table[] = { /* letter function need_oper need_admin */ - {'a', NULL /* special */, 1, 1, }, - {'A', NULL /* special */, 1, 1, }, + {'a', stats_dns_servers, 1, 1, }, + {'A', stats_dns_servers, 1, 1, }, {'b', stats_delay, 1, 1, }, {'B', stats_hash, 1, 1, }, {'c', stats_connect, 0, 0, }, @@ -219,7 +219,7 @@ m_stats(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ if(hunt_server (client_p, source_p, ":%s STATS %s :%s", 2, parc, parv) != HUNTED_ISME) return 0; - if((statchar != 'L') && (statchar != 'l') && (statchar != 'A') && (statchar != 'a')) + if((statchar != 'L') && (statchar != 'l')) did_stats = stats_spy(source_p, statchar, NULL); /* if did_stats is true, a module grabbed this STATS request */ @@ -247,17 +247,9 @@ m_stats(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_ break; } + /* Blah, stats L needs the parameters, none of the others do.. */ if(statchar == 'L' || statchar == 'l') - { - /* Blah, stats L needs the parameters, none of the others do.. */ stats_ltrace (source_p, parc, parv); - } - else if(statchar == 'a' || statchar == 'A') - { - /* Need to suppress RPL_ENDOFSTATS since this is an async call */ - stats_dns_servers(source_p, statchar); - return 0; - } else stats_cmd_table[i].handler (source_p); } @@ -272,9 +264,9 @@ stats_out: } static void -stats_dns_servers (struct Client *source_p, char statchar) +stats_dns_servers (struct Client *source_p) { - report_dns_servers (source_p, statchar); + report_dns_servers (source_p); } static void