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