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