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