1 /*
2 * resolver.c: dns resolving daemon for ircd-ratbox
3 * Based on many things ripped from ratbox-services
4 * and ircd-ratbox itself and who knows what else
5 *
6 * Copyright (C) 2003-2005 Lee Hardy <leeh@leeh.co.uk>
7 * Copyright (C) 2003-2012 ircd-ratbox development team
8 * Copyright (C) 2005-2008 Aaron Sethman <androsyn@ratbox.org>
9 *
10 * $Id: resolver.c 29265 2015-12-20 04:35:39Z androsyn $
11 */
12
13 #define READBUF_SIZE 16384
14
15 #include "setup.h"
16 #include <ratbox_lib.h>
17 #include "res.h"
18 #include "reslib.h"
19
20 #define MAXPARA 10
21 #define REQIDLEN 10
22
23 #define REQREV 0
24 #define REQFWD 1
25
26 #define REVIPV4 0
27 #define REVIPV6 1
28 #define REVIPV6INT 2
29 #define FWDHOST 4
30
31 #define EmptyString(x) (!(x) || (*(x) == '\0'))
32
33 static int do_rehash;
34 static rb_helper *res_helper;
35
36 static char readBuf[READBUF_SIZE];
37 static void resolve_ip(char **parv);
38 static void resolve_host(char **parv);
39 static void report_nameservers(void);
40
41 #ifdef RB_IPV6
42 struct in6_addr ipv6_addr;
43 #endif
44 struct in_addr ipv4_addr;
45
46
47 struct dns_request
48 {
49 struct DNSQuery query;
50 char reqid[REQIDLEN];
51 struct rb_sockaddr_storage addr;
52 int reqtype;
53 int revfwd;
54 };
55
56
57 #ifndef WINDOWS
58 static void
dummy_handler(int sig)59 dummy_handler(int sig)
60 {
61 return;
62 }
63
64 static void
rehash(int sig)65 rehash(int sig)
66 {
67 do_rehash = 1;
68 }
69 #endif
70
71 static void
setup_signals()72 setup_signals()
73 {
74 #ifndef WINDOWS
75 struct sigaction act;
76
77 act.sa_flags = 0;
78 act.sa_handler = SIG_IGN;
79 sigemptyset(&act.sa_mask);
80 sigaddset(&act.sa_mask, SIGPIPE);
81 sigaction(SIGPIPE, &act, 0);
82 sigaddset(&act.sa_mask, SIGALRM);
83 sigaction(SIGALRM, &act, 0);
84 sigaddset(&act.sa_mask, SIGINT);
85 sigaction(SIGINT, &act, 0);
86 #ifdef SIGTRAP
87 sigaddset(&act.sa_mask, SIGTRAP);
88 sigaction(SIGTRAP, &act, 0);
89 #endif
90
91 #ifdef SIGWINCH
92 sigaddset(&act.sa_mask, SIGWINCH);
93 sigaction(SIGWINCH, &act, 0);
94 #endif
95 sigaction(SIGPIPE, &act, 0);
96 #ifdef SIGTRAP
97 sigaction(SIGTRAP, &act, 0);
98 #endif
99
100 act.sa_handler = dummy_handler;
101 sigaddset(&act.sa_mask, SIGALRM);
102 sigaction(SIGALRM, &act, 0);
103 act.sa_handler = rehash;
104 sigaddset(&act.sa_mask, SIGHUP);
105 sigaction(SIGHUP, &act, 0);
106 #endif
107 }
108
109 static void
error_cb(rb_helper * helper)110 error_cb(rb_helper *helper)
111 {
112 exit(1);
113 }
114
115
116 static void
send_answer(void * vptr,struct DNSReply * reply)117 send_answer(void *vptr, struct DNSReply *reply)
118 {
119 struct dns_request *req = (struct dns_request *)vptr;
120 char response[64];
121 int result = 0;
122 int aftype = 0;
123 strcpy(response, "FAILED");
124 if(reply != NULL)
125 {
126 switch (req->revfwd)
127 {
128 case REQREV:
129 {
130 if(req->reqtype == REVIPV4)
131 {
132 struct sockaddr_in *ip, *ip_fwd;
133 ip = (struct sockaddr_in *)&req->addr;
134 ip_fwd = (struct sockaddr_in *)&reply->addr;
135 aftype = 4;
136 if(ip->sin_addr.s_addr != ip_fwd->sin_addr.s_addr)
137 {
138 result = 0;
139 break;
140 }
141 }
142 #ifdef RB_IPV6
143 else if(req->reqtype == REVIPV6)
144 {
145 struct sockaddr_in6 *ip, *ip_fwd;
146 ip = (struct sockaddr_in6 *)&req->addr;
147 ip_fwd = (struct sockaddr_in6 *)&reply->addr;
148 aftype = 6;
149 if(memcmp
150 (&ip->sin6_addr, &ip_fwd->sin6_addr,
151 sizeof(struct in6_addr)) != 0)
152 {
153 result = 0;
154 break;
155 }
156 }
157 #endif
158 else
159 {
160 /* uhh wut? */
161 result = 0;
162 break;
163 }
164
165 if(strlen(reply->h_name) < 63)
166 {
167 strcpy(response, reply->h_name);
168 result = 1;
169 }
170 else
171 {
172 strcpy(response, "HOSTTOOLONG");
173 result = 0;
174 }
175 break;
176 }
177
178 case REQFWD:
179 {
180 #ifdef RB_IPV6
181 if(GET_SS_FAMILY(&reply->addr) == AF_INET6)
182 {
183 char tmpres[65];
184 rb_inet_ntop_sock((struct sockaddr *)&reply->addr,
185 tmpres, sizeof(tmpres) - 1);
186 aftype = 6;
187 if(*tmpres == ':')
188 {
189 strcpy(response, "0");
190 strcat(response, tmpres);
191 }
192 else
193 strcpy(response, tmpres);
194 result = 1;
195 break;
196 }
197 else
198 #endif
199 if(GET_SS_FAMILY(&reply->addr) == AF_INET)
200 {
201 result = 1;
202 aftype = 4;
203 rb_inet_ntop_sock((struct sockaddr *)&reply->addr,
204 response, sizeof(response));
205 break;
206 }
207 else
208 break;
209 }
210 default:
211 {
212 exit(1);
213 }
214 }
215
216 }
217
218 rb_helper_write(res_helper, "R %s %d %d %s\n", req->reqid, result, aftype, response);
219 rb_free(req);
220 }
221
222 static void
set_bind(char ** parv)223 set_bind(char **parv)
224 {
225 char *ipv4 = parv[2];
226 #ifdef RB_IPV6
227 char *ipv6 = parv[3];
228 #endif
229 if(!strcmp(ipv4, "0"))
230 ipv4_addr.s_addr = INADDR_ANY;
231 else
232 rb_inet_pton(AF_INET, ipv4, &ipv4_addr);
233 #ifdef RB_IPV6
234 if(!strcmp(ipv6, "0"))
235 memcpy(&ipv6_addr, &in6addr_any, sizeof(ipv6_addr));
236 else
237 rb_inet_pton(AF_INET6, ipv6, &ipv6_addr);
238 #endif
239 }
240
241
242
243 /*
244 request protocol:
245
246 INPUTS:
247
248 IPTYPE: 4, 5, 6, ipv4, ipv6.int/arpa, ipv6 respectively
249 requestid: identifier of the request
250
251
252 RESIP requestid IPTYPE IP
253 RESHST requestid IPTYPE hostname
254
255 OUTPUTS:
256 ERR error string = daemon failed and is going to shutdown
257 otherwise
258
259 FWD requestid PASS/FAIL hostname or reason for failure
260 REV requestid PASS/FAIL IP or reason
261
262 */
263
264
265 static void
parse_request(rb_helper * helper)266 parse_request(rb_helper *helper)
267 {
268 int len;
269 static char *parv[MAXPARA + 1];
270 int parc;
271 while((len = rb_helper_read(helper, readBuf, sizeof(readBuf))) > 0)
272 {
273 parc = rb_string_to_array(readBuf, parv, MAXPARA);
274 switch (*parv[0])
275 {
276 case 'I':
277 if(parc != 4)
278 abort();
279 resolve_ip(parv);
280 break;
281 case 'H':
282 if(parc != 4)
283 abort();
284 resolve_host(parv);
285 break;
286 case 'B':
287 if(parc != 4)
288 abort();
289 set_bind(parv);
290 break;
291 case 'R':
292 restart_resolver();
293 report_nameservers();
294 break;
295 default:
296 break;
297 }
298 }
299 }
300
301
302 static void
resolve_host(char ** parv)303 resolve_host(char **parv)
304 {
305 struct dns_request *req;
306 char *requestid = parv[1];
307 char *iptype = parv[2];
308 char *rec = parv[3];
309 int flags;
310
311 req = rb_malloc(sizeof(struct dns_request));
312 strcpy(req->reqid, requestid);
313
314 req->revfwd = REQFWD;
315 req->reqtype = FWDHOST;
316
317 switch (*iptype)
318 {
319 case 6:
320 flags = T_AAAA;
321 break;
322 default:
323 flags = T_A;
324 break;
325 }
326
327 req->query.ptr = req;
328 req->query.callback = send_answer;
329 gethost_byname_type(rec, &req->query, flags);
330 }
331
332 static void
resolve_ip(char ** parv)333 resolve_ip(char **parv)
334 {
335 char *requestid = parv[1];
336 char *iptype = parv[2];
337 char *rec = parv[3];
338 int aftype;
339 struct dns_request *req;
340 if(strlen(requestid) >= REQIDLEN)
341 exit(3);
342
343 req = rb_malloc(sizeof(struct dns_request));
344 req->revfwd = REQREV;
345 strcpy(req->reqid, requestid);
346
347 if(!rb_inet_pton_sock(rec, (struct sockaddr *)&req->addr))
348 exit(6);
349
350 aftype = GET_SS_FAMILY(&req->addr);
351 switch (*iptype)
352 {
353 case '4':
354 req->reqtype = REVIPV4;
355 if(aftype != AF_INET)
356 exit(6);
357 break;
358 case '6':
359 req->reqtype = REVIPV6;
360 if(aftype != AF_INET6)
361 exit(6);
362 break;
363 default:
364 exit(7);
365 }
366 req->query.ptr = req;
367 req->query.callback = send_answer;
368 gethost_byaddr(&req->addr, &req->query);
369 }
370
371 extern int irc_nscount;
372 extern struct rb_sockaddr_storage irc_nsaddr_list[];
373
374 static void
report_nameservers(void)375 report_nameservers(void)
376 {
377 int i;
378 char ipaddr[HOSTIPLEN + 1];
379 char buf[512];
380 buf[0] = '\0';
381 for(i = 0; i < irc_nscount; i++)
382 {
383 if(!rb_inet_ntop_sock
384 ((struct sockaddr *)&(irc_nsaddr_list[i]), ipaddr, sizeof(ipaddr)))
385 {
386 rb_strlcpy(ipaddr, "?", sizeof(ipaddr));
387 }
388 rb_snprintf_append(buf, sizeof(buf), "%s ", ipaddr);
389 }
390 rb_helper_write(res_helper, "A %s", buf);
391
392 }
393
394 static void
check_rehash(void * unused)395 check_rehash(void *unused)
396 {
397 if(do_rehash)
398 {
399 restart_resolver();
400 do_rehash = 0;
401 report_nameservers();
402 }
403 }
404
405
406 int
main(int argc,char ** argv)407 main(int argc, char **argv)
408 {
409 res_helper = rb_helper_child(parse_request, error_cb, NULL, NULL, NULL, 256, 1024, 256, 256); /* XXX fix me */
410
411 if(res_helper == NULL)
412 {
413 fprintf(stderr,
414 "This is ircd-ratbox resolver. You know you aren't supposed to run me directly?\n");
415 fprintf(stderr,
416 "You get an Id tag for this: $Id: resolver.c 29265 2015-12-20 04:35:39Z androsyn $\n");
417 fprintf(stderr, "Have a nice life\n");
418 exit(1);
419 }
420 rb_set_time();
421 setup_signals();
422 init_resolver();
423 rb_init_prng(NULL, RB_PRNG_DEFAULT);
424 rb_event_add("check_rehash", check_rehash, NULL, 5);
425 report_nameservers();
426 rb_helper_loop(res_helper, 0);
427 return 1;
428 }
429