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