2 * dns.c: An interface to the resolver module in authd
3 * (based somewhat on ircd-ratbox dns.c)
5 * Copyright (C) 2005 Aaron Sethman <androsyn@ratbox.org>
6 * Copyright (C) 2005-2012 ircd-ratbox development team
7 * Copyright (C) 2016 William Pitcock <nenolod@dereferenced.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
28 #include "ircd_defs.h"
41 #define DNS_HOST_IPV4 ((char)'4')
42 #define DNS_HOST_IPV6 ((char)'6')
43 #define DNS_REVERSE_IPV4 ((char)'R')
44 #define DNS_REVERSE_IPV6 ((char)'S')
46 static void submit_dns(uint32_t uid
, char type
, const char *addr
);
47 static void submit_dns_stat(uint32_t uid
);
61 /* These serve as a form of sparse array */
62 static rb_dictionary
*query_dict
;
63 static rb_dictionary
*stat_dict
;
65 rb_dlink_list nameservers
;
67 static uint32_t query_id
= 0;
68 static uint32_t stat_id
= 0;
71 static inline uint32_t
72 assign_id(uint32_t *id
)
81 handle_dns_failure(uint32_t xid
)
83 struct dnsreq
*req
= rb_dictionary_retrieve(query_dict
, RB_UINT_TO_POINTER(xid
));
86 if(req
== NULL
|| req
->callback
== NULL
)
89 req
->callback("FAILED", 0, 0, req
->data
);
95 handle_dns_stat_failure(uint32_t xid
)
97 struct dnsstatreq
*req
= rb_dictionary_retrieve(stat_dict
, RB_UINT_TO_POINTER(xid
));
100 if(req
== NULL
|| req
->callback
== NULL
)
103 req
->callback(1, NULL
, 2, req
->data
);
104 req
->callback
= NULL
;
110 cancel_lookup(uint32_t xid
)
112 struct dnsreq
*req
= rb_dictionary_retrieve(query_dict
, RB_UINT_TO_POINTER(xid
));
118 req
->callback
= NULL
;
123 cancel_dns_stats(uint32_t xid
)
125 struct dnsstatreq
*req
= rb_dictionary_retrieve(stat_dict
, RB_UINT_TO_POINTER(xid
));
131 req
->callback
= NULL
;
137 lookup_hostname(const char *hostname
, int aftype
, DNSCB callback
, void *data
)
139 struct dnsreq
*req
= rb_malloc(sizeof(struct dnsreq
));
141 uint32_t rid
= assign_id(&query_id
);
145 rb_dictionary_add(query_dict
, RB_UINT_TO_POINTER(rid
), req
);
147 req
->callback
= callback
;
151 if(aftype
== AF_INET6
)
157 submit_dns(rid
, aft
== 4 ? DNS_HOST_IPV4
: DNS_HOST_IPV6
, hostname
);
162 lookup_ip(const char *addr
, int aftype
, DNSCB callback
, void *data
)
164 struct dnsreq
*req
= rb_malloc(sizeof(struct dnsreq
));
166 uint32_t rid
= assign_id(&query_id
);
170 rb_dictionary_add(query_dict
, RB_UINT_TO_POINTER(rid
), req
);
172 req
->callback
= callback
;
176 if(aftype
== AF_INET6
)
182 submit_dns(rid
, aft
== 4 ? DNS_REVERSE_IPV4
: DNS_REVERSE_IPV6
, addr
);
187 get_nameservers(DNSLISTCB callback
, void *data
)
189 struct dnsstatreq
*req
= rb_malloc(sizeof(struct dnsstatreq
));
190 uint32_t qid
= assign_id(&stat_id
);
194 rb_dictionary_add(stat_dict
, RB_UINT_TO_POINTER(qid
), req
);
196 req
->callback
= callback
;
199 submit_dns_stat(qid
);
205 dns_results_callback(const char *callid
, const char *status
, const char *type
, const char *results
)
211 long lrid
= strtol(callid
, NULL
, 16);
213 if(lrid
> UINT32_MAX
)
216 rid
= (uint32_t)lrid
;
217 req
= rb_dictionary_retrieve(query_dict
, RB_UINT_TO_POINTER(rid
));
221 st
= (*status
== 'O');
222 aft
= *type
== '6' || *type
== 'S' ? 6 : 4;
223 if(req
->callback
== NULL
)
225 /* got cancelled..oh well */
236 req
->callback(results
, st
, aft
, req
->data
);
239 rb_dictionary_delete(query_dict
, RB_UINT_TO_POINTER(rid
));
243 dns_stats_results_callback(const char *callid
, const char *status
, int resc
, const char *resv
[])
245 struct dnsstatreq
*req
;
248 long lqid
= strtol(callid
, NULL
, 16);
250 if(lqid
> UINT32_MAX
)
253 qid
= (uint32_t)lqid
;
254 req
= rb_dictionary_retrieve(stat_dict
, RB_UINT_TO_POINTER(qid
));
260 if(req
->callback
== NULL
)
276 /* Shouldn't happen... */
281 req
->callback(resc
, resv
, st
, req
->data
);
284 rb_dictionary_delete(stat_dict
, RB_UINT_TO_POINTER(qid
));
288 stats_results_callback(int resc
, const char *resv
[], int status
, void *data
)
292 rb_dlink_node
*n
, *tn
;
294 RB_DLINK_FOREACH_SAFE(n
, tn
, nameservers
.head
)
296 /* Clean up old nameservers */
298 rb_dlinkDestroy(n
, &nameservers
);
301 for(int i
= 0; i
< resc
; i
++)
302 rb_dlinkAddAlloc(rb_strdup(resv
[i
]), &nameservers
);
306 const char *error
= resc
? resv
[resc
- 1] : "Unknown error";
307 iwarn("Error getting DNS servers: %s", error
);
315 query_dict
= rb_dictionary_create("dns queries", rb_uint32cmp
);
316 stat_dict
= rb_dictionary_create("dns stat queries", rb_uint32cmp
);
317 (void)get_nameservers(stats_results_callback
, NULL
);
321 reload_nameservers(void)
324 rb_helper_write(authd_helper
, "R D");
325 (void)get_nameservers(stats_results_callback
, NULL
);
330 submit_dns(uint32_t nid
, char type
, const char *addr
)
332 if(authd_helper
== NULL
)
334 handle_dns_failure(nid
);
337 rb_helper_write(authd_helper
, "D %x %c %s", nid
, type
, addr
);
341 submit_dns_stat(uint32_t nid
)
343 if(authd_helper
== NULL
)
345 handle_dns_stat_failure(nid
);
348 rb_helper_write(authd_helper
, "S %x D", nid
);