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