authd: allow querying the list of DNS servers.
This was an asston of pain, and it still feels "dirty" as it introduces an async call where there normally wouldn't be one. Better implementation more than welcome.
This commit is contained in:
parent
cdf5ed6cc8
commit
394b8dde17
9 changed files with 298 additions and 42 deletions
|
@ -23,11 +23,33 @@
|
|||
|
||||
#define MAXPARA 10
|
||||
|
||||
static void handle_stat(int parc, char *parv[]);
|
||||
|
||||
rb_helper *authd_helper = NULL;
|
||||
authd_cmd_handler authd_cmd_handlers[255] = {
|
||||
['D'] = resolve_dns,
|
||||
['S'] = handle_stat,
|
||||
};
|
||||
|
||||
authd_stat_handler authd_stat_handlers[255] = {
|
||||
['D'] = enumerate_nameservers,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_stat(int parc, char *parv[])
|
||||
{
|
||||
authd_stat_handler handler;
|
||||
|
||||
if(parc < 3)
|
||||
/* XXX Should log this somehow */
|
||||
return;
|
||||
|
||||
if (!(handler = authd_stat_handlers[parv[2][0]]))
|
||||
return;
|
||||
|
||||
handler(parv[1], parv[2][0]);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_request(rb_helper *helper)
|
||||
{
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
extern rb_helper *authd_helper;
|
||||
|
||||
typedef void (*authd_cmd_handler)(int parc, char *parv[]);
|
||||
typedef void (*authd_stat_handler)(const char *rid, const char letter);
|
||||
extern authd_cmd_handler authd_cmd_handlers[255];
|
||||
extern authd_stat_handler authd_stat_handlers[255];
|
||||
|
||||
#endif
|
||||
|
|
38
authd/dns.c
38
authd/dns.c
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "authd.h"
|
||||
#include "dns.h"
|
||||
#include "res.h"
|
||||
|
||||
static void
|
||||
submit_dns_answer(void *userdata, struct DNSReply *reply)
|
||||
|
@ -136,3 +137,40 @@ resolve_dns(int parc, char *parv[])
|
|||
else
|
||||
gethost_byaddr(&req->addr, &req->query);
|
||||
}
|
||||
|
||||
void
|
||||
enumerate_nameservers(const char *rid, const char letter)
|
||||
{
|
||||
char buf[40 * IRCD_MAXNS]; /* Plenty */
|
||||
char *c = buf;
|
||||
int i;
|
||||
|
||||
if (!irc_nscount)
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
rb_helper_write(authd_helper, "X %s %c NONAMESERVERS", rid, letter);
|
||||
return;
|
||||
}
|
||||
|
||||
for(i = 0; i < irc_nscount; i++)
|
||||
{
|
||||
char addr[40];
|
||||
int ret;
|
||||
|
||||
rb_inet_ntop_sock((struct sockaddr *)&irc_nsaddr_list[i], addr, sizeof(addr));
|
||||
|
||||
if (!addr[0])
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
rb_helper_write(authd_helper, "X %s %c INVALIDNAMESERVER", rid, letter);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = snprintf(c, 40, "%s ", addr);
|
||||
c += (size_t)ret;
|
||||
}
|
||||
|
||||
*(--c) = '\0';
|
||||
|
||||
rb_helper_write(authd_helper, "Y %s %c %s", rid, letter, buf);
|
||||
}
|
||||
|
|
|
@ -35,5 +35,6 @@ struct dns_request
|
|||
};
|
||||
|
||||
extern void resolve_dns(int parc, char *parv[]);
|
||||
extern void enumerate_nameservers(const char *rid, const char letter);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1111,9 +1111,9 @@ irc_dn_find(const unsigned char *domain, const unsigned char *msg,
|
|||
}
|
||||
|
||||
/*
|
||||
* * Thinking in noninternationalized USASCII (per the DNS spec),
|
||||
* * convert this character to lower case if it's upper case.
|
||||
* */
|
||||
* Thinking in noninternationalized USASCII (per the DNS spec),
|
||||
* convert this character to lower case if it's upper case.
|
||||
*/
|
||||
static int
|
||||
mklower(int ch)
|
||||
{
|
||||
|
|
|
@ -26,19 +26,17 @@
|
|||
#ifndef CHARYBDIS_DNS_H
|
||||
#define CHARYBDIS_DNS_H
|
||||
|
||||
#include "stdinc.h"
|
||||
#include "authd.h"
|
||||
|
||||
typedef void (*DNSCB)(const char *res, int status, int aftype, void *data);
|
||||
|
||||
extern rb_helper *authd_helper;
|
||||
|
||||
void init_authd(void);
|
||||
void restart_authd(void);
|
||||
void rehash_authd(void);
|
||||
void check_authd(void);
|
||||
typedef void (*DNSLISTCB)(int resc, const char *resv[], int status, void *data);
|
||||
|
||||
uint16_t lookup_hostname(const char *hostname, int aftype, DNSCB callback, void *data);
|
||||
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 report_dns_servers(struct Client *);
|
||||
void dns_stats_results_callback(const char *callid, const char *status, int resc, const char *resv[]);
|
||||
void report_dns_servers(struct Client *, char);
|
||||
|
||||
#endif
|
||||
|
|
31
ircd/authd.c
31
ircd/authd.c
|
@ -97,11 +97,11 @@ parse_authd_reply(rb_helper * helper)
|
|||
ssize_t len;
|
||||
int parc;
|
||||
char dnsBuf[READBUF_SIZE];
|
||||
|
||||
char *parv[MAXPARA + 1];
|
||||
|
||||
while((len = rb_helper_read(helper, dnsBuf, sizeof(dnsBuf))) > 0)
|
||||
{
|
||||
parc = rb_string_to_array(dnsBuf, parv, MAXPARA+1);
|
||||
parc = rb_string_to_array(dnsBuf, parv, MAXPARA+1);
|
||||
|
||||
switch (*parv[0])
|
||||
{
|
||||
|
@ -114,6 +114,33 @@ parse_authd_reply(rb_helper * helper)
|
|||
}
|
||||
dns_results_callback(parv[1], parv[2], parv[3], parv[4]);
|
||||
break;
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
if(parc < 3)
|
||||
{
|
||||
ilog(L_MAIN, "authd sent a result with wrong number of arguments: got %d", parc);
|
||||
restart_authd();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Select by type */
|
||||
switch(*parv[2])
|
||||
{
|
||||
case 'D':
|
||||
/* parv[0] conveys status */
|
||||
if(parc < 4)
|
||||
{
|
||||
ilog(L_MAIN, "authd sent a result with wrong number of arguments: got %d", parc);
|
||||
restart_authd();
|
||||
return;
|
||||
}
|
||||
dns_stats_results_callback(parv[1], parv[0], parc - 3, (const char **)&parv[3]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
204
ircd/dns.c
204
ircd/dns.c
|
@ -22,28 +22,31 @@
|
|||
* USA
|
||||
*/
|
||||
|
||||
#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 "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"
|
||||
|
||||
#define DNS_IDTABLE_SIZE 0x2000
|
||||
#define DNS_STATTABLE_SIZE 0x10
|
||||
|
||||
#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(uint16_t uid, char type, const char *addr);
|
||||
static void submit_dns_stat(uint16_t uid);
|
||||
|
||||
struct dnsreq
|
||||
{
|
||||
|
@ -51,7 +54,20 @@ struct dnsreq
|
|||
void *data;
|
||||
};
|
||||
|
||||
struct dnsstatreq
|
||||
{
|
||||
DNSLISTCB callback;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct dnsstatreq_data
|
||||
{
|
||||
char uid[IDLEN];
|
||||
char statchar;
|
||||
};
|
||||
|
||||
static struct dnsreq querytable[DNS_IDTABLE_SIZE];
|
||||
static struct dnsstatreq stattable[DNS_STATTABLE_SIZE];
|
||||
|
||||
static uint16_t
|
||||
assign_dns_id(void)
|
||||
|
@ -72,6 +88,25 @@ assign_dns_id(void)
|
|||
return (id);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
assign_dns_stat_id(void)
|
||||
{
|
||||
static uint8_t id = 1;
|
||||
int loopcnt = 0;
|
||||
while(1)
|
||||
{
|
||||
if(++loopcnt > DNS_STATTABLE_SIZE)
|
||||
return 0;
|
||||
if(id < DNS_STATTABLE_SIZE - 1 || id == 0)
|
||||
id++;
|
||||
else
|
||||
id = 1;
|
||||
if(stattable[id].callback == NULL)
|
||||
break;
|
||||
}
|
||||
return (id);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dns_failure(uint16_t xid)
|
||||
{
|
||||
|
@ -86,6 +121,25 @@ handle_dns_failure(uint16_t xid)
|
|||
req->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_dns_stat_failure(uint8_t xid)
|
||||
{
|
||||
struct dnsstatreq *req;
|
||||
const char *err[] = { "Unknown failure" };
|
||||
|
||||
req = &stattable[xid];
|
||||
if(req->callback == NULL)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
cancel_lookup(uint16_t xid)
|
||||
{
|
||||
|
@ -93,6 +147,16 @@ cancel_lookup(uint16_t xid)
|
|||
querytable[xid].data = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
lookup_hostname(const char *hostname, int aftype, DNSCB callback, void *data)
|
||||
{
|
||||
|
@ -130,7 +194,7 @@ lookup_ip(const char *addr, int aftype, DNSCB callback, void *data)
|
|||
|
||||
if((nid = assign_dns_id()) == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
req = &querytable[nid];
|
||||
|
||||
req->callback = callback;
|
||||
|
@ -147,6 +211,24 @@ lookup_ip(const char *addr, int aftype, DNSCB callback, void *data)
|
|||
return (nid);
|
||||
}
|
||||
|
||||
uint8_t
|
||||
get_nameservers(DNSLISTCB callback, void *data)
|
||||
{
|
||||
struct dnsstatreq *req;
|
||||
uint8_t nid;
|
||||
check_authd();
|
||||
|
||||
if((nid = assign_dns_stat_id()) == 0)
|
||||
return 0;
|
||||
|
||||
req = &stattable[nid];
|
||||
req->callback = callback;
|
||||
req->data = data;
|
||||
|
||||
submit_dns_stat(nid);
|
||||
return (nid);
|
||||
}
|
||||
|
||||
void
|
||||
dns_results_callback(const char *callid, const char *status, const char *type, const char *results)
|
||||
{
|
||||
|
@ -160,7 +242,7 @@ dns_results_callback(const char *callid, const char *status, const char *type, c
|
|||
return;
|
||||
nid = (uint16_t)lnid;
|
||||
req = &querytable[nid];
|
||||
st = *status == 'O';
|
||||
st = (*status == 'O');
|
||||
aft = *type == '6' || *type == 'S' ? 6 : 4;
|
||||
if(req->callback == NULL)
|
||||
{
|
||||
|
@ -181,15 +263,82 @@ dns_results_callback(const char *callid, const char *status, const char *type, c
|
|||
}
|
||||
|
||||
void
|
||||
report_dns_servers(struct Client *source_p)
|
||||
dns_stats_results_callback(const char *callid, const char *status, int resc, const char *resv[])
|
||||
{
|
||||
#if 0
|
||||
rb_dlink_node *ptr;
|
||||
RB_DLINK_FOREACH(ptr, nameservers.head)
|
||||
struct dnsstatreq *req;
|
||||
uint8_t nid;
|
||||
int st, i;
|
||||
long lnid = strtol(callid, NULL, 16);
|
||||
|
||||
if(lnid > DNS_STATTABLE_SIZE || lnid == 0)
|
||||
return;
|
||||
nid = (uint8_t)lnid;
|
||||
req = &stattable[nid];
|
||||
|
||||
if(req->callback == NULL)
|
||||
{
|
||||
sendto_one_numeric(source_p, RPL_STATSDEBUG, "A %s", (char *)ptr->data);
|
||||
/* NOTE - this assumes req->data is strdup'd or such */
|
||||
rb_free(req->data);
|
||||
req->data = NULL;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
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, 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
for(int i = 0; i < resc; i++)
|
||||
sendto_one_numeric(source_p, RPL_STATSDEBUG, "A %s", resv[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(resc && resv[resc][0])
|
||||
/* XXX is this the right reply? */
|
||||
sendto_one_numeric(source_p, RPL_STATSDEBUG, "A Error: %s", resv[resc]);
|
||||
}
|
||||
|
||||
sendto_one_numeric(source_p, RPL_ENDOFSTATS, form_str(RPL_ENDOFSTATS), c_data->statchar);
|
||||
}
|
||||
|
||||
void
|
||||
report_dns_servers(struct Client *source_p, char statchar)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
get_nameservers(report_dns_servers_cb, data);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -202,3 +351,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(uint16_t nid)
|
||||
{
|
||||
if(authd_helper == NULL)
|
||||
{
|
||||
handle_dns_stat_failure(nid);
|
||||
return;
|
||||
}
|
||||
rb_helper_write(authd_helper, "S %x D", nid);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ struct StatsStruct
|
|||
int need_admin;
|
||||
};
|
||||
|
||||
static void stats_dns_servers(struct Client *);
|
||||
static void stats_dns_servers(struct Client *, char);
|
||||
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', stats_dns_servers, 1, 1, },
|
||||
{'A', stats_dns_servers, 1, 1, },
|
||||
{'a', NULL /* special */, 1, 1, },
|
||||
{'A', NULL /* special */, 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'))
|
||||
if((statchar != 'L') && (statchar != 'l') && (statchar != 'A') && (statchar != 'a'))
|
||||
did_stats = stats_spy(source_p, statchar, NULL);
|
||||
|
||||
/* if did_stats is true, a module grabbed this STATS request */
|
||||
|
@ -247,9 +247,17 @@ 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);
|
||||
}
|
||||
|
@ -264,9 +272,9 @@ stats_out:
|
|||
}
|
||||
|
||||
static void
|
||||
stats_dns_servers (struct Client *source_p)
|
||||
stats_dns_servers (struct Client *source_p, char statchar)
|
||||
{
|
||||
report_dns_servers (source_p);
|
||||
report_dns_servers (source_p, statchar);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in a new issue