]> jfr.im git - solanum.git/blob - ircd/dns.c
Correct order of chunking and encoding steps.
[solanum.git] / ircd / dns.c
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 Ariadne Conill <ariadne@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
46 static void submit_dns(uint32_t uid, char type, const char *addr);
47 static void submit_dns_stat(uint32_t uid);
48
49 struct dnsreq
50 {
51 DNSCB callback;
52 void *data;
53 };
54
55 struct dnsstatreq
56 {
57 DNSLISTCB callback;
58 void *data;
59 };
60
61 /* These serve as a form of sparse array */
62 static rb_dictionary *query_dict;
63 static rb_dictionary *stat_dict;
64
65 rb_dlink_list nameservers;
66
67 static uint32_t query_id = 0;
68 static uint32_t stat_id = 0;
69
70
71 static inline uint32_t
72 assign_id(uint32_t *id)
73 {
74 if(++(*id) == 0)
75 *id = 1;
76
77 return *id;
78 }
79
80 static void
81 handle_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
94 static void
95 handle_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
109 void
110 cancel_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
122 void
123 cancel_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
136 uint32_t
137 lookup_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
159 uint32_t
160 lookup_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
182 static uint32_t
183 get_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
200 void
201 dns_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
236 void
237 dns_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
281 static void
282 stats_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
306 void
307 init_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
314 void
315 reload_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
323 static void
324 submit_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
334 static void
335 submit_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 }