]> jfr.im git - solanum.git/blame_incremental - ircd/dns.c
Resolve shfit/reduce conflict in timespec production (#54)
[solanum.git] / ircd / dns.c
... / ...
CommitLineData
1/*
2 * dns.c: An interface to the resolver module in authd
3 * (based somewhat on ircd-ratbox dns.c)
4 *
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>
8 *
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.
13 *
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.
18 *
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
22 * USA
23 */
24
25#include "stdinc.h"
26#include "rb_lib.h"
27#include "client.h"
28#include "ircd_defs.h"
29#include "parse.h"
30#include "dns.h"
31#include "match.h"
32#include "logger.h"
33#include "s_conf.h"
34#include "client.h"
35#include "send.h"
36#include "numeric.h"
37#include "msg.h"
38#include "hash.h"
39#include "s_assert.h"
40
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')
45
46static void submit_dns(uint32_t uid, char type, const char *addr);
47static void submit_dns_stat(uint32_t uid);
48
49struct dnsreq
50{
51 DNSCB callback;
52 void *data;
53};
54
55struct dnsstatreq
56{
57 DNSLISTCB callback;
58 void *data;
59};
60
61/* These serve as a form of sparse array */
62static rb_dictionary *query_dict;
63static rb_dictionary *stat_dict;
64
65rb_dlink_list nameservers;
66
67static uint32_t query_id = 0;
68static uint32_t stat_id = 0;
69
70
71static inline uint32_t
72assign_id(uint32_t *id)
73{
74 if(++(*id) == 0)
75 *id = 1;
76
77 return *id;
78}
79
80static void
81handle_dns_failure(uint32_t xid)
82{
83 struct dnsreq *req = rb_dictionary_retrieve(query_dict, RB_UINT_TO_POINTER(xid));
84 s_assert(req);
85
86 if(req == NULL || req->callback == NULL)
87 return;
88
89 req->callback("FAILED", 0, 0, req->data);
90 req->callback = NULL;
91 req->data = NULL;
92}
93
94static void
95handle_dns_stat_failure(uint32_t xid)
96{
97 struct dnsstatreq *req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(xid));
98 s_assert(req);
99
100 if(req == NULL || req->callback == NULL)
101 return;
102
103 req->callback(1, NULL, 2, req->data);
104 req->callback = NULL;
105 req->data = NULL;
106}
107
108
109void
110cancel_lookup(uint32_t xid)
111{
112 struct dnsreq *req = rb_dictionary_retrieve(query_dict, RB_UINT_TO_POINTER(xid));
113 s_assert(req);
114
115 if (req == NULL)
116 return;
117
118 req->callback = NULL;
119 req->data = NULL;
120}
121
122void
123cancel_dns_stats(uint32_t xid)
124{
125 struct dnsstatreq *req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(xid));
126 s_assert(req);
127
128 if (req == NULL)
129 return;
130
131 req->callback = NULL;
132 req->data = NULL;
133}
134
135
136uint32_t
137lookup_hostname(const char *hostname, int aftype, DNSCB callback, void *data)
138{
139 struct dnsreq *req = rb_malloc(sizeof(struct dnsreq));
140 int aft;
141 uint32_t rid = assign_id(&query_id);
142
143 check_authd();
144
145 rb_dictionary_add(query_dict, RB_UINT_TO_POINTER(rid), req);
146
147 req->callback = callback;
148 req->data = data;
149
150 if(aftype == AF_INET6)
151 aft = 6;
152 else
153 aft = 4;
154
155 submit_dns(rid, aft == 4 ? DNS_HOST_IPV4 : DNS_HOST_IPV6, hostname);
156 return (rid);
157}
158
159uint32_t
160lookup_ip(const char *addr, int aftype, DNSCB callback, void *data)
161{
162 struct dnsreq *req = rb_malloc(sizeof(struct dnsreq));
163 int aft;
164 uint32_t rid = assign_id(&query_id);
165
166 check_authd();
167
168 rb_dictionary_add(query_dict, RB_UINT_TO_POINTER(rid), req);
169
170 req->callback = callback;
171 req->data = data;
172
173 if(aftype == AF_INET6)
174 aft = 6;
175 else
176 aft = 4;
177
178 submit_dns(rid, aft == 4 ? DNS_REVERSE_IPV4 : DNS_REVERSE_IPV6, addr);
179 return (rid);
180}
181
182static uint32_t
183get_nameservers(DNSLISTCB callback, void *data)
184{
185 struct dnsstatreq *req = rb_malloc(sizeof(struct dnsstatreq));
186 uint32_t qid = assign_id(&stat_id);
187
188 check_authd();
189
190 rb_dictionary_add(stat_dict, RB_UINT_TO_POINTER(qid), req);
191
192 req->callback = callback;
193 req->data = data;
194
195 submit_dns_stat(qid);
196 return (qid);
197}
198
199
200void
201dns_results_callback(const char *callid, const char *status, const char *type, const char *results)
202{
203 struct dnsreq *req;
204 uint32_t rid;
205 int st;
206 int aft;
207 long lrid = strtol(callid, NULL, 16);
208
209 if(lrid > UINT32_MAX)
210 return;
211
212 rid = (uint32_t)lrid;
213 req = rb_dictionary_retrieve(query_dict, RB_UINT_TO_POINTER(rid));
214 if(req == NULL)
215 return;
216
217 st = (*status == 'O');
218 aft = *type == '6' || *type == 'S' ? 6 : 4;
219 if(req->callback == NULL)
220 {
221 /* got cancelled..oh well */
222 req->data = NULL;
223 return;
224 }
225 if(aft == 6)
226 aft = AF_INET6;
227 else
228 aft = AF_INET;
229
230 req->callback(results, st, aft, req->data);
231
232 rb_free(req);
233 rb_dictionary_delete(query_dict, RB_UINT_TO_POINTER(rid));
234}
235
236void
237dns_stats_results_callback(const char *callid, const char *status, int resc, const char *resv[])
238{
239 struct dnsstatreq *req;
240 uint32_t qid;
241 int st;
242 long lqid = strtol(callid, NULL, 16);
243
244 if(lqid > UINT32_MAX)
245 return;
246
247 qid = (uint32_t)lqid;
248 req = rb_dictionary_retrieve(stat_dict, RB_UINT_TO_POINTER(qid));
249
250 s_assert(req);
251 if (req == NULL)
252 return;
253
254 if(req->callback == NULL)
255 {
256 req->data = NULL;
257 return;
258 }
259
260 switch(*status)
261 {
262 case 'Y':
263 st = 0;
264 break;
265 case 'X':
266 /* Error */
267 st = 1;
268 break;
269 default:
270 /* Shouldn't happen... */
271 return;
272 }
273
274 /* Query complete */
275 req->callback(resc, resv, st, req->data);
276
277 rb_free(req);
278 rb_dictionary_delete(stat_dict, RB_UINT_TO_POINTER(qid));
279}
280
281static void
282stats_results_callback(int resc, const char *resv[], int status, void *data)
283{
284 if(status == 0)
285 {
286 rb_dlink_node *n, *tn;
287
288 RB_DLINK_FOREACH_SAFE(n, tn, nameservers.head)
289 {
290 /* Clean up old nameservers */
291 rb_free(n->data);
292 rb_dlinkDestroy(n, &nameservers);
293 }
294
295 for(int i = 0; i < resc; i++)
296 rb_dlinkAddAlloc(rb_strdup(resv[i]), &nameservers);
297 }
298 else
299 {
300 const char *error = resc ? resv[resc - 1] : "Unknown error";
301 iwarn("Error getting DNS servers: %s", error);
302 }
303}
304
305
306void
307init_dns(void)
308{
309 query_dict = rb_dictionary_create("dns queries", rb_uint32cmp);
310 stat_dict = rb_dictionary_create("dns stat queries", rb_uint32cmp);
311 (void)get_nameservers(stats_results_callback, NULL);
312}
313
314void
315reload_nameservers(void)
316{
317 check_authd();
318 rb_helper_write(authd_helper, "R D");
319 (void)get_nameservers(stats_results_callback, NULL);
320}
321
322
323static void
324submit_dns(uint32_t nid, char type, const char *addr)
325{
326 if(authd_helper == NULL)
327 {
328 handle_dns_failure(nid);
329 return;
330 }
331 rb_helper_write(authd_helper, "D %x %c %s", nid, type, addr);
332}
333
334static void
335submit_dns_stat(uint32_t nid)
336{
337 if(authd_helper == NULL)
338 {
339 handle_dns_stat_failure(nid);
340 return;
341 }
342 rb_helper_write(authd_helper, "S %x D", nid);
343}