xref: /openbsd-src/sbin/unwind/frontend.c (revision a95f0396caacddadc7bfeaf9106dda335057dcd3)
1*a95f0396Skirill /*	$OpenBSD: frontend.c,v 1.90 2024/11/24 11:33:34 kirill Exp $	*/
2018cebfbSflorian 
3018cebfbSflorian /*
4018cebfbSflorian  * Copyright (c) 2018 Florian Obser <florian@openbsd.org>
5018cebfbSflorian  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6018cebfbSflorian  * Copyright (c) 2004 Esben Norby <norby@openbsd.org>
7018cebfbSflorian  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
8018cebfbSflorian  *
9018cebfbSflorian  * Permission to use, copy, modify, and distribute this software for any
10018cebfbSflorian  * purpose with or without fee is hereby granted, provided that the above
11018cebfbSflorian  * copyright notice and this permission notice appear in all copies.
12018cebfbSflorian  *
13018cebfbSflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14018cebfbSflorian  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15018cebfbSflorian  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16018cebfbSflorian  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17018cebfbSflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18018cebfbSflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19018cebfbSflorian  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20018cebfbSflorian  */
21018cebfbSflorian 
22018cebfbSflorian #include <sys/types.h>
23018cebfbSflorian #include <sys/queue.h>
24018cebfbSflorian #include <sys/socket.h>
25018cebfbSflorian #include <sys/syslog.h>
262d988276Sflorian #include <sys/tree.h>
27018cebfbSflorian #include <sys/uio.h>
28018cebfbSflorian 
295ec49af2Sflorian #include <netinet/in.h>
30018cebfbSflorian #include <net/if.h>
31018cebfbSflorian #include <net/route.h>
32018cebfbSflorian 
33018cebfbSflorian #include <errno.h>
34018cebfbSflorian #include <event.h>
355dca88ceSflorian #include <ifaddrs.h>
36018cebfbSflorian #include <imsg.h>
37018cebfbSflorian #include <netdb.h>
38018cebfbSflorian #include <pwd.h>
39018cebfbSflorian #include <signal.h>
405ec49af2Sflorian #include <stdint.h>
41018cebfbSflorian #include <stdio.h>
42018cebfbSflorian #include <stdlib.h>
43018cebfbSflorian #include <string.h>
445ec49af2Sflorian #include <time.h>
45018cebfbSflorian #include <unistd.h>
46018cebfbSflorian 
4771f565e7Sflorian #include "libunbound/config.h"
4871f565e7Sflorian #include "libunbound/sldns/pkthdr.h"
4971f565e7Sflorian #include "libunbound/sldns/sbuffer.h"
50d1b04a40Sflorian #include "libunbound/sldns/str2wire.h"
5171f565e7Sflorian #include "libunbound/sldns/wire2str.h"
52a8ba344bSflorian #include "libunbound/util/alloc.h"
53a8ba344bSflorian #include "libunbound/util/net_help.h"
54a8ba344bSflorian #include "libunbound/util/regional.h"
554340e121Sflorian #include "libunbound/util/data/dname.h"
56a8ba344bSflorian #include "libunbound/util/data/msgencode.h"
574340e121Sflorian #include "libunbound/util/data/msgparse.h"
584340e121Sflorian #include "libunbound/util/data/msgreply.h"
5971f565e7Sflorian 
6058b5b9b8Sflorian #include "log.h"
61018cebfbSflorian #include "unwind.h"
62018cebfbSflorian #include "frontend.h"
63018cebfbSflorian #include "control.h"
6400b0420eSflorian #include "dns64_synth.h"
65018cebfbSflorian 
6669f07918Sbluhm #define	MINIMUM(a, b)		(((a) < (b)) ? (a) : (b))
67018cebfbSflorian #define	ROUTE_SOCKET_BUF_SIZE   16384
68018cebfbSflorian 
698a36e665Sflorian /*
708a36e665Sflorian  * size of a resource record with name a two octed pointer to qname
718a36e665Sflorian  * 2 octets pointer to qname
728a36e665Sflorian  * 2 octets TYPE
738a36e665Sflorian  * 2 octets CLASS
748a36e665Sflorian  * 4 octets TTL
758a36e665Sflorian  * 2 octets RDLENGTH
768a36e665Sflorian  */
778a36e665Sflorian #define COMPRESSED_RR_SIZE	12
78a8ba344bSflorian #define MINIMIZE_ANSWER		1
798a36e665Sflorian 
80297af7e1Sflorian #define FD_RESERVE		5
81297af7e1Sflorian #define TCP_TIMEOUT		15
82297af7e1Sflorian #define DEFAULT_TCP_SIZE	512
83297af7e1Sflorian 
84018cebfbSflorian struct udp_ev {
85018cebfbSflorian 	struct event		 ev;
86018cebfbSflorian 	uint8_t			 query[65536];
87018cebfbSflorian 	struct msghdr		 rcvmhdr;
88018cebfbSflorian 	struct iovec		 rcviov[1];
89018cebfbSflorian 	struct sockaddr_storage	 from;
90018cebfbSflorian } udp4ev, udp6ev;
91018cebfbSflorian 
92297af7e1Sflorian struct tcp_accept_ev {
93297af7e1Sflorian 	struct event		 ev;
94297af7e1Sflorian 	struct event		 pause;
95297af7e1Sflorian } tcp4ev, tcp6ev;
96297af7e1Sflorian 
97018cebfbSflorian struct pending_query {
98018cebfbSflorian 	TAILQ_ENTRY(pending_query)	 entry;
99018cebfbSflorian 	struct sockaddr_storage		 from;
1004340e121Sflorian 	struct sldns_buffer		*qbuf;
101a8ba344bSflorian 	struct sldns_buffer		*abuf;
102a8ba344bSflorian 	struct regional			*region;
103a8ba344bSflorian 	struct query_info		 qinfo;
104a8ba344bSflorian 	struct edns_data		 edns;
105297af7e1Sflorian 	struct event			 ev;		/* for tcp */
106297af7e1Sflorian 	struct event			 resp_ev;	/* for tcp */
107297af7e1Sflorian 	struct event			 tmo_ev;	/* for tcp */
108018cebfbSflorian 	uint64_t			 imsg_id;
109dbf56da7Sflorian 	uint16_t			 id;
110dbf56da7Sflorian 	uint16_t			 flags;
111018cebfbSflorian 	int				 fd;
112297af7e1Sflorian 	int				 tcp;
11300b0420eSflorian 	int				 dns64_synthesize;
114018cebfbSflorian };
115018cebfbSflorian 
116018cebfbSflorian TAILQ_HEAD(, pending_query)	 pending_queries;
117018cebfbSflorian 
1182d988276Sflorian struct bl_node {
1192d988276Sflorian 	RB_ENTRY(bl_node)	 entry;
1202d988276Sflorian 	char			*domain;
121*a95f0396Skirill 	int			 len;
122*a95f0396Skirill 	int			 wildcard;
1232d988276Sflorian };
1242d988276Sflorian 
125018cebfbSflorian __dead void		 frontend_shutdown(void);
126018cebfbSflorian void			 frontend_sig_handler(int, short, void *);
127018cebfbSflorian void			 frontend_startup(void);
128018cebfbSflorian void			 udp_receive(int, short, void *);
129a8ba344bSflorian void			 handle_query(struct pending_query *);
130a8ba344bSflorian void			 free_pending_query(struct pending_query *);
131297af7e1Sflorian void			 tcp_accept(int, short, void *);
132297af7e1Sflorian int			 accept_reserve(int, struct sockaddr *, socklen_t *);
133297af7e1Sflorian void			 accept_paused(int, short, void *);
134297af7e1Sflorian void			 tcp_request(int, short, void *);
135297af7e1Sflorian void			 tcp_response(int, short, void *);
136297af7e1Sflorian void			 tcp_timeout(int, short, void *);
137ad50aed9Sflorian int			 check_query(sldns_buffer*);
138a8ba344bSflorian void			 noerror_answer(struct pending_query *);
13900b0420eSflorian void			 synthesize_dns64_answer(struct pending_query *);
14000b0420eSflorian void			 resend_dns64_query(struct pending_query *);
1418a36e665Sflorian void			 chaos_answer(struct pending_query *);
142a8ba344bSflorian void			 error_answer(struct pending_query *, int rcode);
1431e5d1cd0Sflorian void			 send_answer(struct pending_query *);
144018cebfbSflorian void			 route_receive(int, short, void *);
145018cebfbSflorian void			 handle_route_message(struct rt_msghdr *,
146018cebfbSflorian 			     struct sockaddr **);
147018cebfbSflorian void			 get_rtaddrs(int, struct sockaddr *,
148018cebfbSflorian 			     struct sockaddr **);
149018cebfbSflorian struct pending_query	*find_pending_query(uint64_t);
150296cf316Sflorian void			 parse_trust_anchor(struct trust_anchor_head *, int);
151296cf316Sflorian void			 send_trust_anchors(struct trust_anchor_head *);
152296cf316Sflorian void			 write_trust_anchors(struct trust_anchor_head *, int);
1532d988276Sflorian void			 parse_blocklist(int);
1542d988276Sflorian int			 bl_cmp(struct bl_node *, struct bl_node *);
1552d988276Sflorian void			 free_bl(void);
156b5001ac5Sotto int			 pending_query_cnt(void);
1575dca88ceSflorian void			 check_available_af(void);
158*a95f0396Skirill void			 reverse(char *, char *);
159018cebfbSflorian 
160bb81f7e1Sflorian struct uw_conf		*frontend_conf;
161d81b02e2Sflorian static struct imsgev	*iev_main;
162d81b02e2Sflorian static struct imsgev	*iev_resolver;
163018cebfbSflorian struct event		 ev_route;
1647be68703Sflorian int			 udp4sock = -1, udp6sock = -1;
165297af7e1Sflorian int			 tcp4sock = -1, tcp6sock = -1;
166d1b04a40Sflorian int			 ta_fd = -1;
167018cebfbSflorian 
168296cf316Sflorian static struct trust_anchor_head	 trust_anchors, new_trust_anchors;
169296cf316Sflorian 
1702d988276Sflorian RB_HEAD(bl_tree, bl_node)	 bl_head = RB_INITIALIZER(&bl_head);
1712d988276Sflorian RB_PROTOTYPE(bl_tree, bl_node, entry, bl_cmp)
1722d988276Sflorian RB_GENERATE(bl_tree, bl_node, entry, bl_cmp)
1732d988276Sflorian 
17400b0420eSflorian struct dns64_prefix	*dns64_prefixes;
17500b0420eSflorian int			 dns64_prefix_count;
17600b0420eSflorian 
177018cebfbSflorian void
178018cebfbSflorian frontend_sig_handler(int sig, short event, void *bula)
179018cebfbSflorian {
180018cebfbSflorian 	/*
181018cebfbSflorian 	 * Normal signal handler rules don't apply because libevent
182018cebfbSflorian 	 * decouples for us.
183018cebfbSflorian 	 */
184018cebfbSflorian 
185018cebfbSflorian 	switch (sig) {
186018cebfbSflorian 	case SIGINT:
187018cebfbSflorian 	case SIGTERM:
188018cebfbSflorian 		frontend_shutdown();
189018cebfbSflorian 	default:
190018cebfbSflorian 		fatalx("unexpected signal");
191018cebfbSflorian 	}
192018cebfbSflorian }
193018cebfbSflorian 
194018cebfbSflorian void
195018cebfbSflorian frontend(int debug, int verbose)
196018cebfbSflorian {
197018cebfbSflorian 	struct event	 ev_sigint, ev_sigterm;
198018cebfbSflorian 	struct passwd	*pw;
199018cebfbSflorian 
200018cebfbSflorian 	frontend_conf = config_new_empty();
201018cebfbSflorian 
202018cebfbSflorian 	log_init(debug, LOG_DAEMON);
203018cebfbSflorian 	log_setverbose(verbose);
204018cebfbSflorian 
205018cebfbSflorian 	if ((pw = getpwnam(UNWIND_USER)) == NULL)
206018cebfbSflorian 		fatal("getpwnam");
207018cebfbSflorian 
208018cebfbSflorian 	if (chroot(pw->pw_dir) == -1)
209018cebfbSflorian 		fatal("chroot");
210018cebfbSflorian 	if (chdir("/") == -1)
211018cebfbSflorian 		fatal("chdir(\"/\")");
212018cebfbSflorian 
213d223f0d9Sflorian 	setproctitle("%s", "frontend");
214d223f0d9Sflorian 	log_procinit("frontend");
215018cebfbSflorian 
216018cebfbSflorian 	if (setgroups(1, &pw->pw_gid) ||
217018cebfbSflorian 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
218018cebfbSflorian 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
219018cebfbSflorian 		fatal("can't drop privileges");
220018cebfbSflorian 
2215dca88ceSflorian 	if (pledge("stdio dns unix recvfd", NULL) == -1)
222018cebfbSflorian 		fatal("pledge");
223018cebfbSflorian 
224018cebfbSflorian 	event_init();
225018cebfbSflorian 
226018cebfbSflorian 	/* Setup signal handler. */
227018cebfbSflorian 	signal_set(&ev_sigint, SIGINT, frontend_sig_handler, NULL);
228018cebfbSflorian 	signal_set(&ev_sigterm, SIGTERM, frontend_sig_handler, NULL);
229018cebfbSflorian 	signal_add(&ev_sigint, NULL);
230018cebfbSflorian 	signal_add(&ev_sigterm, NULL);
231018cebfbSflorian 	signal(SIGPIPE, SIG_IGN);
232018cebfbSflorian 	signal(SIGHUP, SIG_IGN);
233018cebfbSflorian 
234018cebfbSflorian 	/* Setup pipe and event handler to the parent process. */
2354595f84cSotto 	if (iev_main != NULL)
2364595f84cSotto 		fatal("iev_main");
237018cebfbSflorian 	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
238018cebfbSflorian 		fatal(NULL);
2390e59d0d1Sclaudio 	if (imsgbuf_init(&iev_main->ibuf, 3) == -1)
2400e59d0d1Sclaudio 		fatal(NULL);
2410e59d0d1Sclaudio 	imsgbuf_allow_fdpass(&iev_main->ibuf);
242018cebfbSflorian 	iev_main->handler = frontend_dispatch_main;
243018cebfbSflorian 	iev_main->events = EV_READ;
244018cebfbSflorian 	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
245018cebfbSflorian 	    iev_main->handler, iev_main);
246018cebfbSflorian 	event_add(&iev_main->ev, NULL);
247018cebfbSflorian 
248018cebfbSflorian 	udp4ev.rcviov[0].iov_base = (caddr_t)udp4ev.query;
249018cebfbSflorian 	udp4ev.rcviov[0].iov_len = sizeof(udp4ev.query);
250018cebfbSflorian 	udp4ev.rcvmhdr.msg_name = (caddr_t)&udp4ev.from;
251018cebfbSflorian 	udp4ev.rcvmhdr.msg_namelen = sizeof(udp4ev.from);
252018cebfbSflorian 	udp4ev.rcvmhdr.msg_iov = udp4ev.rcviov;
253018cebfbSflorian 	udp4ev.rcvmhdr.msg_iovlen = 1;
254018cebfbSflorian 
255018cebfbSflorian 	udp6ev.rcviov[0].iov_base = (caddr_t)udp6ev.query;
256018cebfbSflorian 	udp6ev.rcviov[0].iov_len = sizeof(udp6ev.query);
257018cebfbSflorian 	udp6ev.rcvmhdr.msg_name = (caddr_t)&udp6ev.from;
258018cebfbSflorian 	udp6ev.rcvmhdr.msg_namelen = sizeof(udp6ev.from);
259018cebfbSflorian 	udp6ev.rcvmhdr.msg_iov = udp6ev.rcviov;
260018cebfbSflorian 	udp6ev.rcvmhdr.msg_iovlen = 1;
261018cebfbSflorian 
262018cebfbSflorian 	TAILQ_INIT(&pending_queries);
263018cebfbSflorian 
264296cf316Sflorian 	TAILQ_INIT(&trust_anchors);
265296cf316Sflorian 	TAILQ_INIT(&new_trust_anchors);
266296cf316Sflorian 
267abb04357Sflorian 	add_new_ta(&trust_anchors, KSK2017);
26810427868Sflorian 	add_new_ta(&trust_anchors, KSK2024);
269abb04357Sflorian 
270018cebfbSflorian 	event_dispatch();
271018cebfbSflorian 
272018cebfbSflorian 	frontend_shutdown();
273018cebfbSflorian }
274018cebfbSflorian 
275018cebfbSflorian __dead void
276018cebfbSflorian frontend_shutdown(void)
277018cebfbSflorian {
278018cebfbSflorian 	/* Close pipes. */
279dd7efffeSclaudio 	imsgbuf_write(&iev_resolver->ibuf);
2809cbf9e90Sclaudio 	imsgbuf_clear(&iev_resolver->ibuf);
281018cebfbSflorian 	close(iev_resolver->ibuf.fd);
282dd7efffeSclaudio 	imsgbuf_write(&iev_main->ibuf);
2839cbf9e90Sclaudio 	imsgbuf_clear(&iev_main->ibuf);
284018cebfbSflorian 	close(iev_main->ibuf.fd);
285018cebfbSflorian 
286018cebfbSflorian 	config_clear(frontend_conf);
287018cebfbSflorian 
288018cebfbSflorian 	free(iev_resolver);
289018cebfbSflorian 	free(iev_main);
290018cebfbSflorian 
291018cebfbSflorian 	log_info("frontend exiting");
292018cebfbSflorian 	exit(0);
293018cebfbSflorian }
294018cebfbSflorian 
295018cebfbSflorian int
296018cebfbSflorian frontend_imsg_compose_main(int type, pid_t pid, void *data, uint16_t datalen)
297018cebfbSflorian {
298bb81f7e1Sflorian 	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
299018cebfbSflorian }
300018cebfbSflorian 
301018cebfbSflorian int
302bb81f7e1Sflorian frontend_imsg_compose_resolver(int type, pid_t pid, void *data,
303bb81f7e1Sflorian     uint16_t datalen)
304018cebfbSflorian {
305018cebfbSflorian 	return (imsg_compose_event(iev_resolver, type, 0, pid, -1, data,
306018cebfbSflorian 	    datalen));
307018cebfbSflorian }
308018cebfbSflorian 
309018cebfbSflorian void
310018cebfbSflorian frontend_dispatch_main(int fd, short event, void *bula)
311018cebfbSflorian {
312bb81f7e1Sflorian 	static struct uw_conf	*nconf;
313018cebfbSflorian 	struct imsg		 imsg;
314018cebfbSflorian 	struct imsgev		*iev = bula;
315018cebfbSflorian 	struct imsgbuf		*ibuf = &iev->ibuf;
316018cebfbSflorian 	int			 n, shut = 0;
317018cebfbSflorian 
318018cebfbSflorian 	if (event & EV_READ) {
319668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
320dd7efffeSclaudio 			fatal("imsgbuf_read error");
321018cebfbSflorian 		if (n == 0)	/* Connection closed. */
322018cebfbSflorian 			shut = 1;
323018cebfbSflorian 	}
324018cebfbSflorian 	if (event & EV_WRITE) {
325dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
326e3b6409cSclaudio 			if (errno == EPIPE)	/* Connection closed. */
327018cebfbSflorian 				shut = 1;
328e3b6409cSclaudio 			else
329dd7efffeSclaudio 				fatal("imsgbuf_write");
330e3b6409cSclaudio 		}
331018cebfbSflorian 	}
332018cebfbSflorian 
333018cebfbSflorian 	for (;;) {
334018cebfbSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
335018cebfbSflorian 			fatal("%s: imsg_get error", __func__);
336018cebfbSflorian 		if (n == 0)	/* No more messages. */
337018cebfbSflorian 			break;
338018cebfbSflorian 
339018cebfbSflorian 		switch (imsg.hdr.type) {
340b2501eadSflorian 		case IMSG_SOCKET_IPC_RESOLVER:
341018cebfbSflorian 			/*
342018cebfbSflorian 			 * Setup pipe and event handler to the resolver
343018cebfbSflorian 			 * process.
344018cebfbSflorian 			 */
345018cebfbSflorian 			if (iev_resolver) {
3462b821978Sflorian 				fatalx("%s: received unexpected imsg fd "
347018cebfbSflorian 				    "to frontend", __func__);
348018cebfbSflorian 				break;
349018cebfbSflorian 			}
350eeb36cc3Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1) {
3512b821978Sflorian 				fatalx("%s: expected to receive imsg fd to "
352018cebfbSflorian 				   "frontend but didn't receive any",
353018cebfbSflorian 				   __func__);
354018cebfbSflorian 				break;
355018cebfbSflorian 			}
356018cebfbSflorian 
3574595f84cSotto 			if (iev_resolver != NULL)
3584595f84cSotto 				fatal("iev_resolver");
359018cebfbSflorian 			iev_resolver = malloc(sizeof(struct imsgev));
360018cebfbSflorian 			if (iev_resolver == NULL)
361018cebfbSflorian 				fatal(NULL);
362018cebfbSflorian 
3630e59d0d1Sclaudio 			if (imsgbuf_init(&iev_resolver->ibuf, fd) == -1)
3640e59d0d1Sclaudio 				fatal(NULL);
365018cebfbSflorian 			iev_resolver->handler = frontend_dispatch_resolver;
366018cebfbSflorian 			iev_resolver->events = EV_READ;
367018cebfbSflorian 
368018cebfbSflorian 			event_set(&iev_resolver->ev, iev_resolver->ibuf.fd,
369bb81f7e1Sflorian 			    iev_resolver->events, iev_resolver->handler,
370bb81f7e1Sflorian 			    iev_resolver);
371018cebfbSflorian 			event_add(&iev_resolver->ev, NULL);
372018cebfbSflorian 			break;
373018cebfbSflorian 		case IMSG_RECONF_CONF:
3742d988276Sflorian 		case IMSG_RECONF_BLOCKLIST_FILE:
375018cebfbSflorian 		case IMSG_RECONF_FORWARDER:
3763570995aSflorian 		case IMSG_RECONF_DOT_FORWARDER:
377dd16127bSotto 		case IMSG_RECONF_FORCE:
378679647feSflorian 			imsg_receive_config(&imsg, &nconf);
3793570995aSflorian 			break;
380018cebfbSflorian 		case IMSG_RECONF_END:
381580cede2Sflorian 			if (nconf == NULL)
382580cede2Sflorian 				fatalx("%s: IMSG_RECONF_END without "
383580cede2Sflorian 				    "IMSG_RECONF_CONF", __func__);
384018cebfbSflorian 			merge_config(frontend_conf, nconf);
3852d988276Sflorian 			if (frontend_conf->blocklist_file == NULL)
3862d988276Sflorian 				free_bl();
387018cebfbSflorian 			nconf = NULL;
388018cebfbSflorian 			break;
389018cebfbSflorian 		case IMSG_UDP6SOCK:
3902b821978Sflorian 			if (udp6sock != -1)
3912b821978Sflorian 				fatalx("%s: received unexpected udp6sock",
3922b821978Sflorian 				    __func__);
393eeb36cc3Sclaudio 			if ((udp6sock = imsg_get_fd(&imsg)) == -1)
394018cebfbSflorian 				fatalx("%s: expected to receive imsg "
395bb81f7e1Sflorian 				    "UDP6 fd but didn't receive any", __func__);
396018cebfbSflorian 			event_set(&udp6ev.ev, udp6sock, EV_READ | EV_PERSIST,
397018cebfbSflorian 			    udp_receive, &udp6ev);
398d265a5d3Sflorian 			event_add(&udp6ev.ev, NULL);
399018cebfbSflorian 			break;
400018cebfbSflorian 		case IMSG_UDP4SOCK:
4012b821978Sflorian 			if (udp4sock != -1)
4022b821978Sflorian 				fatalx("%s: received unexpected udp4sock",
4032b821978Sflorian 				    __func__);
404eeb36cc3Sclaudio 			if ((udp4sock = imsg_get_fd(&imsg)) == -1)
405018cebfbSflorian 				fatalx("%s: expected to receive imsg "
406bb81f7e1Sflorian 				    "UDP4 fd but didn't receive any", __func__);
407018cebfbSflorian 			event_set(&udp4ev.ev, udp4sock, EV_READ | EV_PERSIST,
408018cebfbSflorian 			    udp_receive, &udp4ev);
409d265a5d3Sflorian 			event_add(&udp4ev.ev, NULL);
410018cebfbSflorian 			break;
411297af7e1Sflorian 		case IMSG_TCP4SOCK:
412297af7e1Sflorian 			if (tcp4sock != -1)
413297af7e1Sflorian 				fatalx("%s: received unexpected tcp4sock",
414297af7e1Sflorian 				    __func__);
415eeb36cc3Sclaudio 			if ((tcp4sock = imsg_get_fd(&imsg)) == -1)
416297af7e1Sflorian 				fatalx("%s: expected to receive imsg "
417297af7e1Sflorian 				    "TCP4 fd but didn't receive any", __func__);
418297af7e1Sflorian 			event_set(&tcp4ev.ev, tcp4sock, EV_READ | EV_PERSIST,
419297af7e1Sflorian 			    tcp_accept, &tcp4ev);
420297af7e1Sflorian 			event_add(&tcp4ev.ev, NULL);
421297af7e1Sflorian 			evtimer_set(&tcp4ev.pause, accept_paused, &tcp4ev);
422297af7e1Sflorian 			break;
423297af7e1Sflorian 		case IMSG_TCP6SOCK:
424297af7e1Sflorian 			if (tcp6sock != -1)
425297af7e1Sflorian 				fatalx("%s: received unexpected tcp6sock",
426297af7e1Sflorian 				    __func__);
427eeb36cc3Sclaudio 			if ((tcp6sock = imsg_get_fd(&imsg)) == -1)
428297af7e1Sflorian 				fatalx("%s: expected to receive imsg "
429297af7e1Sflorian 				    "TCP6 fd but didn't receive any", __func__);
430297af7e1Sflorian 			event_set(&tcp6ev.ev, tcp6sock, EV_READ | EV_PERSIST,
431297af7e1Sflorian 			    tcp_accept, &tcp6ev);
432297af7e1Sflorian 			event_add(&tcp6ev.ev, NULL);
433297af7e1Sflorian 			evtimer_set(&tcp6ev.pause, accept_paused, &tcp6ev);
434297af7e1Sflorian 			break;
4357be68703Sflorian 		case IMSG_ROUTESOCK: {
4367be68703Sflorian 			static int	 routesock = -1;
4377be68703Sflorian 
4382b821978Sflorian 			if (routesock != -1)
4392b821978Sflorian 				fatalx("%s: received unexpected routesock",
4402b821978Sflorian 				    __func__);
441eeb36cc3Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1)
442018cebfbSflorian 				fatalx("%s: expected to receive imsg "
443018cebfbSflorian 				    "routesocket fd but didn't receive any",
444018cebfbSflorian 				    __func__);
445018cebfbSflorian 			routesock = fd;
446018cebfbSflorian 			event_set(&ev_route, fd, EV_READ | EV_PERSIST,
447018cebfbSflorian 			    route_receive, NULL);
448018cebfbSflorian 			break;
4497be68703Sflorian 		}
450018cebfbSflorian 		case IMSG_STARTUP:
451018cebfbSflorian 			frontend_startup();
452018cebfbSflorian 			break;
453018cebfbSflorian 		case IMSG_CONTROLFD:
454eeb36cc3Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1)
455bb81f7e1Sflorian 				fatalx("%s: expected to receive imsg control "
456bb81f7e1Sflorian 				    "fd but didn't receive any", __func__);
457018cebfbSflorian 			/* Listen on control socket. */
4583538560bSflorian 			control_listen(fd);
459018cebfbSflorian 			break;
460296cf316Sflorian 		case IMSG_TAFD:
461eeb36cc3Sclaudio 			if ((ta_fd = imsg_get_fd(&imsg)) != -1)
462d1b04a40Sflorian 				parse_trust_anchor(&trust_anchors, ta_fd);
463296cf316Sflorian 			if (!TAILQ_EMPTY(&trust_anchors))
464296cf316Sflorian 				send_trust_anchors(&trust_anchors);
465296cf316Sflorian 			break;
4662d988276Sflorian 		case IMSG_BLFD:
467eeb36cc3Sclaudio 			if ((fd = imsg_get_fd(&imsg)) == -1)
4682d988276Sflorian 				fatalx("%s: expected to receive imsg block "
4692d988276Sflorian 				   "list fd but didn't receive any", __func__);
4702d988276Sflorian 			parse_blocklist(fd);
4712d988276Sflorian 			break;
472018cebfbSflorian 		default:
473018cebfbSflorian 			log_debug("%s: error handling imsg %d", __func__,
474018cebfbSflorian 			    imsg.hdr.type);
475018cebfbSflorian 			break;
476018cebfbSflorian 		}
477018cebfbSflorian 		imsg_free(&imsg);
478018cebfbSflorian 	}
479018cebfbSflorian 	if (!shut)
480018cebfbSflorian 		imsg_event_add(iev);
481018cebfbSflorian 	else {
482018cebfbSflorian 		/* This pipe is dead. Remove its event handler. */
483018cebfbSflorian 		event_del(&iev->ev);
484018cebfbSflorian 		event_loopexit(NULL);
485018cebfbSflorian 	}
486018cebfbSflorian }
487018cebfbSflorian 
488018cebfbSflorian void
489018cebfbSflorian frontend_dispatch_resolver(int fd, short event, void *bula)
490018cebfbSflorian {
49100b0420eSflorian 	static struct dns64_prefix	*new_dns64_prefixes = NULL;
49200b0420eSflorian 	static int			 new_dns64_prefix_count = 0;
49300b0420eSflorian 	static int			 new_dns64_prefix_pos = 0;
49415c83d0cSflorian 	struct pending_query		*pq;
495018cebfbSflorian 	struct imsgev			*iev = bula;
496018cebfbSflorian 	struct imsgbuf			*ibuf = &iev->ibuf;
497018cebfbSflorian 	struct imsg			 imsg;
498296cf316Sflorian 	int				 n, shut = 0, chg;
499018cebfbSflorian 
500018cebfbSflorian 	if (event & EV_READ) {
501668e5ba9Sclaudio 		if ((n = imsgbuf_read(ibuf)) == -1)
502dd7efffeSclaudio 			fatal("imsgbuf_read error");
503018cebfbSflorian 		if (n == 0)	/* Connection closed. */
504018cebfbSflorian 			shut = 1;
505018cebfbSflorian 	}
506018cebfbSflorian 	if (event & EV_WRITE) {
507dd7efffeSclaudio 		if (imsgbuf_write(ibuf) == -1) {
508e3b6409cSclaudio 			if (errno == EPIPE)	/* Connection closed. */
509018cebfbSflorian 				shut = 1;
510e3b6409cSclaudio 			else
511dd7efffeSclaudio 				fatal("imsgbuf_write");
512e3b6409cSclaudio 		}
513018cebfbSflorian 	}
514018cebfbSflorian 
515018cebfbSflorian 	for (;;) {
516018cebfbSflorian 		if ((n = imsg_get(ibuf, &imsg)) == -1)
517018cebfbSflorian 			fatal("%s: imsg_get error", __func__);
518018cebfbSflorian 		if (n == 0)	/* No more messages. */
519018cebfbSflorian 			break;
520018cebfbSflorian 
521018cebfbSflorian 		switch (imsg.hdr.type) {
5221548e3a9Sflorian 		case IMSG_ANSWER: {
5231548e3a9Sflorian 			struct answer_header	*answer_header;
5241548e3a9Sflorian 			int			 data_len;
5251548e3a9Sflorian 			uint8_t			*data;
5261548e3a9Sflorian 
5271548e3a9Sflorian 			if (IMSG_DATA_SIZE(imsg) < sizeof(*answer_header))
52815c83d0cSflorian 				fatalx("%s: IMSG_ANSWER wrong length: "
52915c83d0cSflorian 				    "%lu", __func__, IMSG_DATA_SIZE(imsg));
5301548e3a9Sflorian 			answer_header = (struct answer_header *)imsg.data;
5311548e3a9Sflorian 			data = (uint8_t *)imsg.data + sizeof(*answer_header);
5324753c8fdSflorian 			if (answer_header->answer_len > UINT16_MAX)
5331548e3a9Sflorian 				fatalx("%s: IMSG_ANSWER answer too big: %d",
5341548e3a9Sflorian 				    __func__, answer_header->answer_len);
5351548e3a9Sflorian 			data_len = IMSG_DATA_SIZE(imsg) -
5361548e3a9Sflorian 			    sizeof(*answer_header);
5371548e3a9Sflorian 
5381548e3a9Sflorian 			if ((pq = find_pending_query(answer_header->id)) ==
5391e5d1cd0Sflorian 			    NULL) {
5401548e3a9Sflorian 				log_warnx("%s: cannot find pending query %llu",
5411548e3a9Sflorian 				    __func__, answer_header->id);
54215c83d0cSflorian 				break;
54315c83d0cSflorian 			}
54415c83d0cSflorian 
5451548e3a9Sflorian 			if (answer_header->srvfail) {
546a8ba344bSflorian 				error_answer(pq, LDNS_RCODE_SERVFAIL);
5471e5d1cd0Sflorian 				send_answer(pq);
54815c83d0cSflorian 				break;
54915c83d0cSflorian 			}
5501548e3a9Sflorian 
551dbf56da7Sflorian 			if (answer_header->bogus && !(pq->flags & BIT_CD)) {
552a8ba344bSflorian 				error_answer(pq, LDNS_RCODE_SERVFAIL);
55315c83d0cSflorian 				send_answer(pq);
554018cebfbSflorian 				break;
5551548e3a9Sflorian 			}
556a8ba344bSflorian 
557a8ba344bSflorian 			if (sldns_buffer_position(pq->abuf) == 0 &&
558a8ba344bSflorian 			    !sldns_buffer_set_capacity(pq->abuf,
559a8ba344bSflorian 			    answer_header->answer_len)) {
560a8ba344bSflorian 				error_answer(pq, LDNS_RCODE_SERVFAIL);
561a8ba344bSflorian 				send_answer(pq);
562a8ba344bSflorian 				break;
5631548e3a9Sflorian 			}
5641548e3a9Sflorian 
565a8ba344bSflorian 			if (sldns_buffer_position(pq->abuf) + data_len >
566a8ba344bSflorian 			    sldns_buffer_capacity(pq->abuf))
5671548e3a9Sflorian 				fatalx("%s: IMSG_ANSWER answer too big: %d",
5681548e3a9Sflorian 				    __func__, data_len);
569a8ba344bSflorian 			sldns_buffer_write(pq->abuf, data, data_len);
5701548e3a9Sflorian 
571a8ba344bSflorian 			if (sldns_buffer_position(pq->abuf) ==
572a8ba344bSflorian 			    sldns_buffer_capacity(pq->abuf)) {
573a8ba344bSflorian 				sldns_buffer_flip(pq->abuf);
57400b0420eSflorian 				if (pq->dns64_synthesize) {
57500b0420eSflorian 					synthesize_dns64_answer(pq);
5761548e3a9Sflorian 					send_answer(pq);
57700b0420eSflorian 				} else {
57800b0420eSflorian 					noerror_answer(pq);
57900b0420eSflorian 					if (pq->dns64_synthesize)
58000b0420eSflorian 						/* we did not find a answer */
58100b0420eSflorian 						resend_dns64_query(pq);
58200b0420eSflorian 					else
58300b0420eSflorian 						send_answer(pq);
58400b0420eSflorian 				}
585a8ba344bSflorian 			}
5861548e3a9Sflorian 			break;
5871548e3a9Sflorian 		}
588018cebfbSflorian 		case IMSG_CTL_RESOLVER_INFO:
589ecfbee2cSflorian 		case IMSG_CTL_AUTOCONF_RESOLVER_INFO:
590c071f090Sflorian 		case IMSG_CTL_MEM_INFO:
591018cebfbSflorian 		case IMSG_CTL_END:
592018cebfbSflorian 			control_imsg_relay(&imsg);
593018cebfbSflorian 			break;
594296cf316Sflorian 		case IMSG_NEW_TA:
595296cf316Sflorian 			/* make sure this is a string */
596a9155f32Sflorian 			((char *)imsg.data)[IMSG_DATA_SIZE(imsg) - 1] = '\0';
597a9155f32Sflorian 			add_new_ta(&new_trust_anchors, imsg.data);
598296cf316Sflorian 			break;
599296cf316Sflorian 		case IMSG_NEW_TAS_ABORT:
600296cf316Sflorian 			free_tas(&new_trust_anchors);
601296cf316Sflorian 			break;
602296cf316Sflorian 		case IMSG_NEW_TAS_DONE:
603296cf316Sflorian 			chg = merge_tas(&new_trust_anchors, &trust_anchors);
60407b5b07bSflorian 			if (chg)
605296cf316Sflorian 				send_trust_anchors(&trust_anchors);
60607b5b07bSflorian 
607296cf316Sflorian 			/*
608296cf316Sflorian 			 * always write trust anchors, the modify date on
609296cf316Sflorian 			 * the file is an indication when we made progress
610296cf316Sflorian 			 */
611d1b04a40Sflorian 			if (ta_fd != -1)
612d1b04a40Sflorian 				write_trust_anchors(&trust_anchors, ta_fd);
613296cf316Sflorian 			break;
61400b0420eSflorian 		case IMSG_NEW_DNS64_PREFIXES_START:
61500b0420eSflorian 			if (IMSG_DATA_SIZE(imsg) !=
61600b0420eSflorian 			    sizeof(new_dns64_prefix_count))
61700b0420eSflorian 				fatalx("%s: IMSG_NEW_DNS64_PREFIXES_START "
61800b0420eSflorian 				    "wrong length: %lu", __func__,
61900b0420eSflorian 				    IMSG_DATA_SIZE(imsg));
62000b0420eSflorian 			memcpy(&new_dns64_prefix_count, imsg.data,
62100b0420eSflorian 			    sizeof(new_dns64_prefix_count));
62200b0420eSflorian 			free(new_dns64_prefixes);
62300b0420eSflorian 			new_dns64_prefixes = NULL;
62400b0420eSflorian 			if (new_dns64_prefix_count > 0)
62500b0420eSflorian 				new_dns64_prefixes =
62600b0420eSflorian 				    calloc(new_dns64_prefix_count,
62700b0420eSflorian 				    sizeof(struct dns64_prefix));
62800b0420eSflorian 			new_dns64_prefix_pos = 0;
62900b0420eSflorian 			break;
63000b0420eSflorian 		case IMSG_NEW_DNS64_PREFIX: {
63100b0420eSflorian 			if (IMSG_DATA_SIZE(imsg) != sizeof(struct dns64_prefix))
63200b0420eSflorian 				fatalx("%s: IMSG_NEW_DNS64_PREFIX wrong "
63300b0420eSflorian 				    "length: %lu", __func__,
63400b0420eSflorian 				    IMSG_DATA_SIZE(imsg));
63500b0420eSflorian 			if (new_dns64_prefixes == NULL)
63600b0420eSflorian 				break;
63700b0420eSflorian 			if (new_dns64_prefix_pos >= new_dns64_prefix_count)
63800b0420eSflorian 				fatalx("%s: IMSG_NEW_DNS64_PREFIX: too many "
63900b0420eSflorian 				    "prefixes", __func__);
64000b0420eSflorian 			memcpy(&new_dns64_prefixes[new_dns64_prefix_pos++],
64100b0420eSflorian 			    imsg.data, sizeof(struct dns64_prefix));
64200b0420eSflorian 			break;
64300b0420eSflorian 		}
64400b0420eSflorian 		case IMSG_NEW_DNS64_PREFIXES_DONE:
64500b0420eSflorian 			free(dns64_prefixes);
64600b0420eSflorian 			dns64_prefixes = new_dns64_prefixes;
64700b0420eSflorian 			dns64_prefix_count = new_dns64_prefix_count;
64800b0420eSflorian 			new_dns64_prefixes = NULL;
64900b0420eSflorian 			break;
650018cebfbSflorian 		default:
651018cebfbSflorian 			log_debug("%s: error handling imsg %d", __func__,
652018cebfbSflorian 			    imsg.hdr.type);
653018cebfbSflorian 			break;
654018cebfbSflorian 		}
655018cebfbSflorian 		imsg_free(&imsg);
656018cebfbSflorian 	}
657018cebfbSflorian 	if (!shut)
658018cebfbSflorian 		imsg_event_add(iev);
659018cebfbSflorian 	else {
660018cebfbSflorian 		/* This pipe is dead. Remove its event handler. */
661018cebfbSflorian 		event_del(&iev->ev);
662018cebfbSflorian 		event_loopexit(NULL);
663018cebfbSflorian 	}
664018cebfbSflorian }
665018cebfbSflorian 
666018cebfbSflorian void
667018cebfbSflorian frontend_startup(void)
668018cebfbSflorian {
669018cebfbSflorian 	if (!event_initialized(&ev_route))
670018cebfbSflorian 		fatalx("%s: did not receive a route socket from the main "
671018cebfbSflorian 		    "process", __func__);
672018cebfbSflorian 
673018cebfbSflorian 	event_add(&ev_route, NULL);
674018cebfbSflorian 
675018cebfbSflorian 	frontend_imsg_compose_main(IMSG_STARTUP_DONE, 0, NULL, 0);
6765dca88ceSflorian 	check_available_af();
677018cebfbSflorian }
678018cebfbSflorian 
679018cebfbSflorian void
680a8ba344bSflorian free_pending_query(struct pending_query *pq)
681a8ba344bSflorian {
682a8ba344bSflorian 	if (!pq)
683a8ba344bSflorian 		return;
684a8ba344bSflorian 
685a8ba344bSflorian 	TAILQ_REMOVE(&pending_queries, pq, entry);
686a8ba344bSflorian 	regional_destroy(pq->region);
687a8ba344bSflorian 	sldns_buffer_free(pq->qbuf);
688a8ba344bSflorian 	sldns_buffer_free(pq->abuf);
689297af7e1Sflorian 	if (pq->tcp) {
690297af7e1Sflorian 		if (event_initialized(&pq->ev))
691297af7e1Sflorian 			event_del(&pq->ev);
692297af7e1Sflorian 		if (event_initialized(&pq->resp_ev))
693297af7e1Sflorian 			event_del(&pq->resp_ev);
694297af7e1Sflorian 		if (event_initialized(&pq->tmo_ev))
695297af7e1Sflorian 			event_del(&pq->tmo_ev);
696297af7e1Sflorian 		if (pq->fd != -1)
697297af7e1Sflorian 			close(pq->fd);
698297af7e1Sflorian 	}
699a8ba344bSflorian 	free(pq);
700a8ba344bSflorian }
701a8ba344bSflorian 
702a8ba344bSflorian void
703018cebfbSflorian udp_receive(int fd, short events, void *arg)
704018cebfbSflorian {
705018cebfbSflorian 	struct udp_ev		*udpev = (struct udp_ev *)arg;
706a8ba344bSflorian 	struct pending_query	*pq = NULL;
707a8ba344bSflorian 	ssize_t			 len;
708018cebfbSflorian 
709df69c215Sderaadt 	if ((len = recvmsg(fd, &udpev->rcvmhdr, 0)) == -1) {
710018cebfbSflorian 		log_warn("recvmsg");
711018cebfbSflorian 		return;
712018cebfbSflorian 	}
713018cebfbSflorian 
71410dfa598Sflorian 	if ((pq = calloc(1, sizeof(*pq))) == NULL) {
715018cebfbSflorian 		log_warn(NULL);
716018cebfbSflorian 		return;
717018cebfbSflorian 	}
718018cebfbSflorian 
719018cebfbSflorian 	do {
720018cebfbSflorian 		arc4random_buf(&pq->imsg_id, sizeof(pq->imsg_id));
721018cebfbSflorian 	} while(find_pending_query(pq->imsg_id) != NULL);
722018cebfbSflorian 
723a8ba344bSflorian 	TAILQ_INSERT_TAIL(&pending_queries, pq, entry);
724a8ba344bSflorian 
725a8ba344bSflorian 	pq->from = udpev->from;
726a8ba344bSflorian 	pq->fd = fd;
727a8ba344bSflorian 	pq->qbuf = sldns_buffer_new(len);
728a8ba344bSflorian 	pq->abuf = sldns_buffer_new(len); /* make sure we can send errors */
729a8ba344bSflorian 	pq->region = regional_create();
730a8ba344bSflorian 
731dbf56da7Sflorian 	if (!pq->qbuf || !pq->abuf || !pq->region) {
732a8ba344bSflorian 		log_warnx("out of memory");
733a8ba344bSflorian 		free_pending_query(pq);
734a8ba344bSflorian 		return;
7354340e121Sflorian 	}
736a8ba344bSflorian 
7374340e121Sflorian 	sldns_buffer_write(pq->qbuf, udpev->query, len);
7384340e121Sflorian 	sldns_buffer_flip(pq->qbuf);
739a8ba344bSflorian 	handle_query(pq);
740a8ba344bSflorian }
741a8ba344bSflorian 
742a8ba344bSflorian void
743a8ba344bSflorian handle_query(struct pending_query *pq)
744a8ba344bSflorian {
745a8ba344bSflorian 	struct query_imsg	 query_imsg;
746a8ba344bSflorian 	struct bl_node		 find;
747*a95f0396Skirill 	int			 rcode, matched;
748a8ba344bSflorian 	char			*str;
749a8ba344bSflorian 	char			 dname[LDNS_MAX_DOMAINLEN + 1];
750a8ba344bSflorian 	char			 qclass_buf[16];
751a8ba344bSflorian 	char			 qtype_buf[16];
752018cebfbSflorian 
7536282c991Sflorian 	if (log_getverbose() & OPT_VERBOSE2 && (str =
754a8ba344bSflorian 	    sldns_wire2str_pkt(sldns_buffer_begin(pq->qbuf),
755a8ba344bSflorian 	    sldns_buffer_limit(pq->qbuf))) != NULL) {
7566282c991Sflorian 		log_debug("from: %s\n%s", ip_port((struct sockaddr *)
757a8ba344bSflorian 		    &pq->from), str);
7584340e121Sflorian 		free(str);
7594340e121Sflorian 	}
7604340e121Sflorian 
761dbf56da7Sflorian 	if (sldns_buffer_remaining(pq->qbuf) < LDNS_HEADER_SIZE) {
762dbf56da7Sflorian 		log_warnx("bad query: too short, dropped");
763ad50aed9Sflorian 		goto drop;
764a8ba344bSflorian 	}
765a8ba344bSflorian 
766dbf56da7Sflorian 	pq->id = sldns_buffer_read_u16_at(pq->qbuf, 0);
767dbf56da7Sflorian 	pq->flags = sldns_buffer_read_u16_at(pq->qbuf, 2);
768a8ba344bSflorian 
769dbf56da7Sflorian 	if (!query_info_parse(&pq->qinfo, pq->qbuf)) {
770dbf56da7Sflorian 		log_warnx("query_info_parse failed");
771a8ba344bSflorian 		goto drop;
772a8ba344bSflorian 	}
773a8ba344bSflorian 
774a8ba344bSflorian 	rcode = check_query(pq->qbuf);
775a8ba344bSflorian 	switch (rcode) {
776a8ba344bSflorian 	case LDNS_RCODE_NOERROR:
777a8ba344bSflorian 		break;
778a8ba344bSflorian 	case -1:
779a8ba344bSflorian 		goto drop;
780a8ba344bSflorian 	default:
781a8ba344bSflorian 		error_answer(pq, rcode);
782ad50aed9Sflorian 		goto send_answer;
783ad50aed9Sflorian 	}
784ad50aed9Sflorian 
785a1a7ba80Sflorian 	rcode = parse_edns_from_query_pkt(pq->qbuf, &pq->edns, NULL, NULL,
7867037e34cSflorian 	    NULL, 0, pq->region, NULL);
787a8ba344bSflorian 	if (rcode != LDNS_RCODE_NOERROR) {
788a8ba344bSflorian 		error_answer(pq, rcode);
789ad50aed9Sflorian 		goto send_answer;
790ad50aed9Sflorian 	}
791ad50aed9Sflorian 
792a8ba344bSflorian 	if (!dname_valid(pq->qinfo.qname, pq->qinfo.qname_len)) {
793a8ba344bSflorian 		error_answer(pq, LDNS_RCODE_FORMERR);
794ad50aed9Sflorian 		goto send_answer;
795ad50aed9Sflorian 	}
796a8ba344bSflorian 	dname_str(pq->qinfo.qname, dname);
797ad50aed9Sflorian 
798a8ba344bSflorian 	sldns_wire2str_class_buf(pq->qinfo.qclass, qclass_buf,
799a8ba344bSflorian 	    sizeof(qclass_buf));
800a8ba344bSflorian 	sldns_wire2str_type_buf(pq->qinfo.qtype, qtype_buf, sizeof(qtype_buf));
801a8ba344bSflorian 	log_debug("%s: %s %s %s ?", ip_port((struct sockaddr *)&pq->from),
8024595f84cSotto 	    dname, qclass_buf, qtype_buf);
803ad50aed9Sflorian 
804*a95f0396Skirill 	if (!RB_EMPTY(&bl_head)) {
805*a95f0396Skirill 		find.len = strlen(dname);
806*a95f0396Skirill 		find.wildcard = 0;
807*a95f0396Skirill 		reverse(dname, dname + find.len);
8084340e121Sflorian 		find.domain = dname;
809*a95f0396Skirill 		matched = (RB_FIND(bl_tree, &bl_head, &find) != NULL);
810*a95f0396Skirill 		reverse(dname, dname + find.len);
811*a95f0396Skirill 		if (matched) {
812ac71ec8eSflorian 			if (frontend_conf->blocklist_log)
813ac71ec8eSflorian 				log_info("blocking %s", dname);
814a8ba344bSflorian 			error_answer(pq, LDNS_RCODE_REFUSED);
815ad50aed9Sflorian 			goto send_answer;
816ad50aed9Sflorian 		}
817*a95f0396Skirill 	}
818ad50aed9Sflorian 
819a8ba344bSflorian 	if (pq->qinfo.qtype == LDNS_RR_TYPE_AXFR || pq->qinfo.qtype ==
820ad50aed9Sflorian 	    LDNS_RR_TYPE_IXFR) {
821a8ba344bSflorian 		error_answer(pq, LDNS_RCODE_REFUSED);
822ad50aed9Sflorian 		goto send_answer;
823ad50aed9Sflorian 	}
824ad50aed9Sflorian 
825a8ba344bSflorian 	if(pq->qinfo.qtype == LDNS_RR_TYPE_OPT ||
826a8ba344bSflorian 	    pq->qinfo.qtype == LDNS_RR_TYPE_TSIG ||
827a8ba344bSflorian 	    pq->qinfo.qtype == LDNS_RR_TYPE_TKEY ||
828a8ba344bSflorian 	    pq->qinfo.qtype == LDNS_RR_TYPE_MAILA ||
829a8ba344bSflorian 	    pq->qinfo.qtype == LDNS_RR_TYPE_MAILB ||
830a8ba344bSflorian 	    (pq->qinfo.qtype >= 128 && pq->qinfo.qtype <= 248)) {
831a8ba344bSflorian 		error_answer(pq, LDNS_RCODE_FORMERR);
832ad50aed9Sflorian 		goto send_answer;
833ad50aed9Sflorian 	}
834ad50aed9Sflorian 
835a8ba344bSflorian 	if (pq->qinfo.qclass == LDNS_RR_CLASS_CH) {
8368a36e665Sflorian 		if (strcasecmp(dname, "version.server.") == 0 ||
8378a36e665Sflorian 		    strcasecmp(dname, "version.bind.") == 0) {
8388a36e665Sflorian 			chaos_answer(pq);
8398a36e665Sflorian 		} else
840a8ba344bSflorian 			error_answer(pq, LDNS_RCODE_REFUSED);
841ad50aed9Sflorian 		goto send_answer;
8422d988276Sflorian 	}
8432d988276Sflorian 
844e650aea3Sotto 	if (strlcpy(query_imsg.qname, dname, sizeof(query_imsg.qname)) >=
845e650aea3Sotto 	    sizeof(query_imsg.qname)) {
84671f565e7Sflorian 		log_warnx("qname too long");
847a8ba344bSflorian 		error_answer(pq, LDNS_RCODE_FORMERR);
848ad50aed9Sflorian 		goto send_answer;
84971f565e7Sflorian 	}
850e650aea3Sotto 	query_imsg.id = pq->imsg_id;
851a8ba344bSflorian 	query_imsg.t = pq->qinfo.qtype;
852a8ba344bSflorian 	query_imsg.c = pq->qinfo.qclass;
853018cebfbSflorian 
854e650aea3Sotto 	if (frontend_imsg_compose_resolver(IMSG_QUERY, 0, &query_imsg,
855a8ba344bSflorian 	    sizeof(query_imsg)) == -1) {
856a8ba344bSflorian 		error_answer(pq, LDNS_RCODE_SERVFAIL);
857ad50aed9Sflorian 		goto send_answer;
858018cebfbSflorian 	}
859ad50aed9Sflorian 	return;
860ad50aed9Sflorian 
861ad50aed9Sflorian  send_answer:
8621e5d1cd0Sflorian 	send_answer(pq);
863a8ba344bSflorian 	return;
864a8ba344bSflorian 
865ad50aed9Sflorian  drop:
866a8ba344bSflorian 	free_pending_query(pq);
867a8ba344bSflorian }
868a8ba344bSflorian 
869a8ba344bSflorian void
870a8ba344bSflorian noerror_answer(struct pending_query *pq)
871a8ba344bSflorian {
872a8ba344bSflorian 	struct query_info		 skip, qinfo;
873a8ba344bSflorian 	struct reply_info		*rinfo = NULL;
874a8ba344bSflorian 	struct alloc_cache		 alloc;
875a8ba344bSflorian 	struct edns_data		 edns;
87600b0420eSflorian 	struct ub_packed_rrset_key	*an_rrset = NULL;
87700b0420eSflorian 	struct packed_rrset_data	*an_rrset_data = NULL;
878a8ba344bSflorian 
879a8ba344bSflorian 	alloc_init(&alloc, NULL, 0);
880a8ba344bSflorian 	memset(&qinfo, 0, sizeof(qinfo));
881a8ba344bSflorian 	/* read past query section, no memory is allocated */
882a8ba344bSflorian 	if (!query_info_parse(&skip, pq->abuf))
883a8ba344bSflorian 		goto srvfail;
884a8ba344bSflorian 
885a8ba344bSflorian 	if (reply_info_parse(pq->abuf, &alloc, &qinfo, &rinfo, pq->region,
886a8ba344bSflorian 	    &edns) != 0)
887a8ba344bSflorian 		goto srvfail;
88800b0420eSflorian 
88900b0420eSflorian 	if ((an_rrset = reply_find_answer_rrset(&qinfo, rinfo)) != NULL)
89000b0420eSflorian 		an_rrset_data = (struct packed_rrset_data*)an_rrset->entry.data;
89100b0420eSflorian 
892a8ba344bSflorian 	/* reply_info_parse() allocates memory */
893a8ba344bSflorian 	query_info_clear(&qinfo);
894a8ba344bSflorian 
89500b0420eSflorian 	/* XXX check that there a no AAAA records in answer section? */
89600b0420eSflorian 	if ((an_rrset_data == NULL || an_rrset_data->count == 0) &&
89700b0420eSflorian 	    !pq->dns64_synthesize && pq->qinfo.qtype == LDNS_RR_TYPE_AAAA &&
89800b0420eSflorian 	    pq->qinfo.qclass == LDNS_RR_CLASS_IN && dns64_prefix_count > 0) {
89900b0420eSflorian 		pq->dns64_synthesize = 1;
90000b0420eSflorian 		return;
90100b0420eSflorian 	}
90200b0420eSflorian 
903a8ba344bSflorian 	sldns_buffer_clear(pq->abuf);
904dbf56da7Sflorian 	if (reply_info_encode(&pq->qinfo, rinfo, htons(pq->id), rinfo->flags,
905297af7e1Sflorian 	    pq->abuf, 0, pq->region, pq->tcp ? UINT16_MAX : pq->edns.udp_size,
906a8ba344bSflorian 	    pq->edns.bits & EDNS_DO, MINIMIZE_ANSWER) == 0)
907a8ba344bSflorian 		goto srvfail;
908a8ba344bSflorian 
909a8ba344bSflorian 	reply_info_parsedelete(rinfo, &alloc);
910a8ba344bSflorian 	alloc_clear(&alloc);
911a8ba344bSflorian 	return;
912a8ba344bSflorian 
913a8ba344bSflorian  srvfail:
914a8ba344bSflorian 	reply_info_parsedelete(rinfo, &alloc);
915a8ba344bSflorian 	alloc_clear(&alloc);
916a8ba344bSflorian 	error_answer(pq, LDNS_RCODE_SERVFAIL);
917ad50aed9Sflorian }
918ad50aed9Sflorian 
9198a36e665Sflorian void
92000b0420eSflorian synthesize_dns64_answer(struct pending_query *pq)
92100b0420eSflorian {
92200b0420eSflorian 	struct query_info		 skip, qinfo;
92300b0420eSflorian 	struct reply_info		*rinfo = NULL, *synth_rinfo = NULL;
92400b0420eSflorian 	struct alloc_cache		 alloc;
92500b0420eSflorian 	struct edns_data		 edns;
92600b0420eSflorian 	size_t				 i;
92700b0420eSflorian 
92800b0420eSflorian 	pq->dns64_synthesize = 0;
92900b0420eSflorian 
93000b0420eSflorian 	alloc_init(&alloc, NULL, 0);
93100b0420eSflorian 	memset(&qinfo, 0, sizeof(qinfo));
93200b0420eSflorian 	/* read past query section, no memory is allocated */
93300b0420eSflorian 	if (!query_info_parse(&skip, pq->abuf))
93400b0420eSflorian 		goto srvfail;
93500b0420eSflorian 
93600b0420eSflorian 	if (reply_info_parse(pq->abuf, &alloc, &qinfo, &rinfo, pq->region,
93700b0420eSflorian 	    &edns) != 0)
93800b0420eSflorian 		goto srvfail;
93900b0420eSflorian 
94000b0420eSflorian 	/* reply_info_parse() allocates memory */
94100b0420eSflorian 	query_info_clear(&qinfo);
94200b0420eSflorian 
94300b0420eSflorian 	synth_rinfo = construct_reply_info_base(pq->region, rinfo->flags,
94400b0420eSflorian 	    rinfo->qdcount, rinfo->ttl, rinfo->prefetch_ttl,
94500b0420eSflorian 	    rinfo->serve_expired_ttl, rinfo->an_numrrsets,
94600b0420eSflorian 	    rinfo->ns_numrrsets, rinfo->ar_numrrsets, rinfo->rrset_count,
9476ced2d15Sflorian 	    rinfo->security, rinfo->reason_bogus);
94800b0420eSflorian 
94900b0420eSflorian 	if (!synth_rinfo)
95000b0420eSflorian 		goto srvfail;
95100b0420eSflorian 
95200b0420eSflorian 	if(!reply_info_alloc_rrset_keys(synth_rinfo, NULL, pq->region))
95300b0420eSflorian 		goto srvfail;
95400b0420eSflorian 
95500b0420eSflorian 	for (i = 0; i < synth_rinfo->rrset_count; i++) {
95600b0420eSflorian 		struct ub_packed_rrset_key	*src_rrset_key, *dst_rrset_key;
95700b0420eSflorian 		struct packed_rrset_data	*src_rrset_data;
95800b0420eSflorian 		struct packed_rrset_data	*dst_rrset_data;
95900b0420eSflorian 
96000b0420eSflorian 		src_rrset_key = rinfo->rrsets[i];
96100b0420eSflorian 		src_rrset_data =
96200b0420eSflorian 		    (struct packed_rrset_data *)src_rrset_key->entry.data;
96300b0420eSflorian 		dst_rrset_key = synth_rinfo->rrsets[i];
96400b0420eSflorian 
96500b0420eSflorian 		dst_rrset_key->id = src_rrset_key->id;
96600b0420eSflorian 		dst_rrset_key->rk = src_rrset_key->rk;
96700b0420eSflorian 
96800b0420eSflorian 		if (i < rinfo->an_numrrsets && src_rrset_key->rk.type ==
96900b0420eSflorian 		    htons(LDNS_RR_TYPE_A)) {
97000b0420eSflorian 			dns64_synth_aaaa_data(src_rrset_key, src_rrset_data,
97100b0420eSflorian 			    dst_rrset_key, &dst_rrset_data, pq->region);
97200b0420eSflorian 			if (dst_rrset_data == NULL)
97300b0420eSflorian 				goto srvfail;
97400b0420eSflorian 		} else {
97500b0420eSflorian 			dst_rrset_key->entry.hash = src_rrset_key->entry.hash;
97600b0420eSflorian 			dst_rrset_key->rk.dname = regional_alloc_init(
97700b0420eSflorian 			    pq->region, src_rrset_key->rk.dname,
97800b0420eSflorian 			    src_rrset_key->rk.dname_len);
97900b0420eSflorian 			if (dst_rrset_key->rk.dname == NULL)
98000b0420eSflorian 				goto srvfail;
98100b0420eSflorian 
98200b0420eSflorian 			dst_rrset_data = regional_alloc_init(pq->region,
98300b0420eSflorian 			    src_rrset_data,
98400b0420eSflorian 			    packed_rrset_sizeof(src_rrset_data));
98500b0420eSflorian 			if (dst_rrset_data == NULL)
98600b0420eSflorian 				goto srvfail;
98700b0420eSflorian 		}
98800b0420eSflorian 
98900b0420eSflorian 		packed_rrset_ptr_fixup(dst_rrset_data);
99000b0420eSflorian 		dst_rrset_key->entry.data = dst_rrset_data;
99100b0420eSflorian 	}
99200b0420eSflorian 
99300b0420eSflorian 	if (!sldns_buffer_set_capacity(pq->abuf, pq->tcp ? UINT16_MAX :
99400b0420eSflorian 	    pq->edns.udp_size))
99500b0420eSflorian 		goto srvfail;
99600b0420eSflorian 
99700b0420eSflorian 	sldns_buffer_clear(pq->abuf);
99800b0420eSflorian 
999dbf56da7Sflorian 	if (reply_info_encode(&pq->qinfo, synth_rinfo, htons(pq->id),
100000b0420eSflorian 	    synth_rinfo->flags, pq->abuf, 0, pq->region,
100100b0420eSflorian 	    pq->tcp ? UINT16_MAX : pq->edns.udp_size,
100200b0420eSflorian 	    pq->edns.bits & EDNS_DO, MINIMIZE_ANSWER) == 0)
100300b0420eSflorian 		goto srvfail;
100400b0420eSflorian 
100500b0420eSflorian 	reply_info_parsedelete(rinfo, &alloc);
100600b0420eSflorian 	alloc_clear(&alloc);
100700b0420eSflorian 	return;
100800b0420eSflorian 
100900b0420eSflorian  srvfail:
101000b0420eSflorian 	reply_info_parsedelete(rinfo, &alloc);
101100b0420eSflorian 	alloc_clear(&alloc);
101200b0420eSflorian 	error_answer(pq, LDNS_RCODE_SERVFAIL);
101300b0420eSflorian }
101400b0420eSflorian 
101500b0420eSflorian void
10162de410b6Stb resend_dns64_query(struct pending_query *opq)
10172de410b6Stb {
101800b0420eSflorian 	struct pending_query	*pq;
101900b0420eSflorian 	struct query_imsg	 query_imsg;
102000b0420eSflorian 	int			 rcode;
102100b0420eSflorian 	char			 dname[LDNS_MAX_DOMAINLEN + 1];
102200b0420eSflorian 
102300b0420eSflorian 	if ((pq = calloc(1, sizeof(*pq))) == NULL) {
102400b0420eSflorian 		log_warn(NULL);
102500b0420eSflorian 		return;
102600b0420eSflorian 	}
102700b0420eSflorian 
102800b0420eSflorian 	do {
102900b0420eSflorian 		arc4random_buf(&pq->imsg_id, sizeof(pq->imsg_id));
103000b0420eSflorian 	} while(find_pending_query(pq->imsg_id) != NULL);
103100b0420eSflorian 
103200b0420eSflorian 	TAILQ_INSERT_TAIL(&pending_queries, pq, entry);
103300b0420eSflorian 
103400b0420eSflorian 	pq->from = opq->from;
103500b0420eSflorian 	pq->fd = opq->fd;
103600b0420eSflorian 	opq->fd = -1;
103700b0420eSflorian 	pq->tcp = opq->tcp;
103800b0420eSflorian 	pq->qbuf = sldns_buffer_new(sldns_buffer_capacity(opq->qbuf));
103900b0420eSflorian 	pq->abuf = sldns_buffer_new(sldns_buffer_capacity(opq->abuf));
104000b0420eSflorian 	pq->region = regional_create();
104100b0420eSflorian 
1042dbf56da7Sflorian 	if (!pq->qbuf || !pq->abuf || !pq->region) {
104300b0420eSflorian 		log_warnx("out of memory");
104400b0420eSflorian 		free_pending_query(pq);
104500b0420eSflorian 		free_pending_query(opq);
104600b0420eSflorian 		return;
104700b0420eSflorian 	}
104800b0420eSflorian 
104900b0420eSflorian 	sldns_buffer_rewind(opq->qbuf);
105000b0420eSflorian 	sldns_buffer_write(pq->qbuf, sldns_buffer_current(opq->qbuf),
105100b0420eSflorian 	    sldns_buffer_remaining(opq->qbuf));
105200b0420eSflorian 	sldns_buffer_flip(pq->qbuf);
105300b0420eSflorian 
105400b0420eSflorian 	if (pq->tcp) {
105500b0420eSflorian 		struct timeval	 timeout = {TCP_TIMEOUT, 0};
105600b0420eSflorian 
105700b0420eSflorian 		event_set(&pq->ev, pq->fd, EV_READ | EV_PERSIST, tcp_request,
105800b0420eSflorian 		    pq);
105900b0420eSflorian 		event_set(&pq->resp_ev, pq->fd, EV_WRITE | EV_PERSIST,
106000b0420eSflorian 		    tcp_response, pq);
106100b0420eSflorian 		evtimer_set(&pq->tmo_ev, tcp_timeout, pq);
106200b0420eSflorian 		evtimer_add(&pq->tmo_ev, &timeout);
106300b0420eSflorian 	}
106400b0420eSflorian 
1065dbf56da7Sflorian 	if (sldns_buffer_remaining(pq->qbuf) < LDNS_HEADER_SIZE) {
1066dbf56da7Sflorian 		log_warnx("bad query: too short, dropped");
1067dbf56da7Sflorian 		goto drop;
1068dbf56da7Sflorian 	}
1069dbf56da7Sflorian 
1070dbf56da7Sflorian 	pq->id = sldns_buffer_read_u16_at(pq->qbuf, 0);
1071dbf56da7Sflorian 	pq->flags = sldns_buffer_read_u16_at(pq->qbuf, 2);
1072dbf56da7Sflorian 
107300b0420eSflorian 	if (!query_info_parse(&pq->qinfo, pq->qbuf)) {
107400b0420eSflorian 		log_warnx("query_info_parse failed");
107500b0420eSflorian 		goto drop;
107600b0420eSflorian 	}
107700b0420eSflorian 
1078a1a7ba80Sflorian 	rcode = parse_edns_from_query_pkt(pq->qbuf, &pq->edns, NULL, NULL,
10797037e34cSflorian 	    NULL, 0, pq->region, NULL);
108000b0420eSflorian 	if (rcode != LDNS_RCODE_NOERROR) {
108100b0420eSflorian 		error_answer(pq, rcode);
108200b0420eSflorian 		goto send_answer;
108300b0420eSflorian 	}
108400b0420eSflorian 
108500b0420eSflorian 	dname_str(pq->qinfo.qname, dname);
108600b0420eSflorian 	strlcpy(query_imsg.qname, dname, sizeof(query_imsg.qname));
108700b0420eSflorian 	query_imsg.id = pq->imsg_id;
108800b0420eSflorian 	query_imsg.t = LDNS_RR_TYPE_A;
108900b0420eSflorian 	query_imsg.c = pq->qinfo.qclass;
109000b0420eSflorian 
109100b0420eSflorian 	pq->dns64_synthesize = 1;
109200b0420eSflorian 
109300b0420eSflorian 	if (frontend_imsg_compose_resolver(IMSG_QUERY, 0, &query_imsg,
109400b0420eSflorian 	    sizeof(query_imsg)) == -1) {
109500b0420eSflorian 		error_answer(pq, LDNS_RCODE_SERVFAIL);
109600b0420eSflorian 		goto send_answer;
109700b0420eSflorian 	}
109800b0420eSflorian 
109900b0420eSflorian 	free_pending_query(opq);
110000b0420eSflorian 	return;
110100b0420eSflorian 
110200b0420eSflorian  send_answer:
110300b0420eSflorian 	free_pending_query(opq);
110400b0420eSflorian 	send_answer(pq);
110500b0420eSflorian 	return;
110600b0420eSflorian 
110700b0420eSflorian  drop:
110800b0420eSflorian 	free_pending_query(opq);
110900b0420eSflorian 	free_pending_query(pq);
111000b0420eSflorian }
111100b0420eSflorian 
111200b0420eSflorian void
11138a36e665Sflorian chaos_answer(struct pending_query *pq)
11148a36e665Sflorian {
1115a8ba344bSflorian 	size_t		 len;
1116a8ba344bSflorian 	const char	*name = "unwind";
11178a36e665Sflorian 
11188a36e665Sflorian 	len = strlen(name);
1119a8ba344bSflorian 	if (!sldns_buffer_set_capacity(pq->abuf,
1120a8ba344bSflorian 	    sldns_buffer_capacity(pq->qbuf) + COMPRESSED_RR_SIZE + 1 + len)) {
1121a8ba344bSflorian 		error_answer(pq, LDNS_RCODE_SERVFAIL);
11228a36e665Sflorian 		return;
1123a8ba344bSflorian 	}
11248a36e665Sflorian 
1125a8ba344bSflorian 	sldns_buffer_copy(pq->abuf, pq->qbuf);
11268a36e665Sflorian 
1127a8ba344bSflorian 	sldns_buffer_clear(pq->abuf);
1128a8ba344bSflorian 
1129a8ba344bSflorian 	sldns_buffer_skip(pq->abuf, sizeof(uint16_t));	/* skip id */
1130a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 0);		/* clear flags */
1131a8ba344bSflorian 	LDNS_QR_SET(sldns_buffer_begin(pq->abuf));
1132a8ba344bSflorian 	LDNS_RA_SET(sldns_buffer_begin(pq->abuf));
11338a36e665Sflorian 	if (LDNS_RD_WIRE(sldns_buffer_begin(pq->qbuf)))
1134a8ba344bSflorian 		LDNS_RD_SET(sldns_buffer_begin(pq->abuf));
11358a36e665Sflorian 	if (LDNS_CD_WIRE(sldns_buffer_begin(pq->qbuf)))
1136a8ba344bSflorian 		LDNS_CD_SET(sldns_buffer_begin(pq->abuf));
1137a8ba344bSflorian 	LDNS_RCODE_SET(sldns_buffer_begin(pq->abuf), LDNS_RCODE_NOERROR);
1138a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 1);		/* qdcount */
1139a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 1);		/* ancount */
1140a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 0);		/* nscount */
1141a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 0);		/* arcount */
1142a8ba344bSflorian 	(void)query_dname_len(pq->abuf);		/* skip qname */
1143a8ba344bSflorian 	sldns_buffer_skip(pq->abuf, sizeof(uint16_t));	/* skip qtype */
1144a8ba344bSflorian 	sldns_buffer_skip(pq->abuf, sizeof(uint16_t));	/* skip qclass */
11458a36e665Sflorian 
1146a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 0xc00c);	/* ptr to query */
1147a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, LDNS_RR_TYPE_TXT);
1148a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, LDNS_RR_CLASS_CH);
1149a8ba344bSflorian 	sldns_buffer_write_u32(pq->abuf, 0);		/* TTL */
1150a8ba344bSflorian 	sldns_buffer_write_u16(pq->abuf, 1 + len);	/* RDLENGTH */
1151a8ba344bSflorian 	sldns_buffer_write_u8(pq->abuf, len);		/* length octed */
1152a8ba344bSflorian 	sldns_buffer_write(pq->abuf, name, len);
1153a8ba344bSflorian 	sldns_buffer_flip(pq->abuf);
1154a8ba344bSflorian }
1155a8ba344bSflorian 
1156a8ba344bSflorian void
1157a8ba344bSflorian error_answer(struct pending_query *pq, int rcode)
1158a8ba344bSflorian {
1159a8ba344bSflorian 	sldns_buffer_clear(pq->abuf);
1160dbf56da7Sflorian 	error_encode(pq->abuf, rcode, &pq->qinfo, htons(pq->id), pq->flags,
1161dbf56da7Sflorian 	    pq->edns.edns_present ? &pq->edns : NULL);
11628a36e665Sflorian }
11638a36e665Sflorian 
1164ad50aed9Sflorian int
1165ad50aed9Sflorian check_query(sldns_buffer* pkt)
1166ad50aed9Sflorian {
1167ad50aed9Sflorian 	if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
1168ad50aed9Sflorian 		log_warnx("bad query: too short, dropped");
1169ad50aed9Sflorian 		return -1;
1170ad50aed9Sflorian 	}
1171ad50aed9Sflorian 	if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
1172ad50aed9Sflorian 		log_warnx("bad query: QR set, dropped");
1173ad50aed9Sflorian 		return -1;
1174ad50aed9Sflorian 	}
1175ad50aed9Sflorian 	if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
1176ad50aed9Sflorian 		LDNS_TC_CLR(sldns_buffer_begin(pkt));
1177ad50aed9Sflorian 		log_warnx("bad query: TC set");
1178ad50aed9Sflorian 		return (LDNS_RCODE_FORMERR);
1179ad50aed9Sflorian 	}
1180ad50aed9Sflorian 	if(!(LDNS_RD_WIRE(sldns_buffer_begin(pkt)))) {
1181ad50aed9Sflorian 		log_warnx("bad query: RD not set");
1182ad50aed9Sflorian 		return (LDNS_RCODE_REFUSED);
1183ad50aed9Sflorian 	}
1184ad50aed9Sflorian 	if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
1185ad50aed9Sflorian 		log_warnx("bad query: unknown opcode %d",
1186ad50aed9Sflorian 		    LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
1187ad50aed9Sflorian 		return (LDNS_RCODE_NOTIMPL);
1188ad50aed9Sflorian 	}
1189ad50aed9Sflorian 
1190ad50aed9Sflorian 	if (LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1 &&
1191ad50aed9Sflorian 	    LDNS_ANCOUNT(sldns_buffer_begin(pkt))!= 0 &&
1192ad50aed9Sflorian 	    LDNS_NSCOUNT(sldns_buffer_begin(pkt))!= 0 &&
1193ad50aed9Sflorian 	    LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
1194ad50aed9Sflorian 		log_warnx("bad query: qdcount: %d, ancount: %d "
1195ad50aed9Sflorian 		    "nscount: %d, arcount: %d",
1196ad50aed9Sflorian 		    LDNS_QDCOUNT(sldns_buffer_begin(pkt)),
1197ad50aed9Sflorian 		    LDNS_ANCOUNT(sldns_buffer_begin(pkt)),
1198ad50aed9Sflorian 		    LDNS_NSCOUNT(sldns_buffer_begin(pkt)),
1199ad50aed9Sflorian 		    LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
1200ad50aed9Sflorian 		return (LDNS_RCODE_FORMERR);
1201ad50aed9Sflorian 	}
12021e80ba60Sflorian 	return (LDNS_RCODE_NOERROR);
1203018cebfbSflorian }
1204018cebfbSflorian 
1205018cebfbSflorian void
12061e5d1cd0Sflorian send_answer(struct pending_query *pq)
1207018cebfbSflorian {
12086282c991Sflorian 	char	*str;
1209018cebfbSflorian 
12106282c991Sflorian 	if (log_getverbose() & OPT_VERBOSE2 && (str =
1211a8ba344bSflorian 	    sldns_wire2str_pkt(sldns_buffer_begin(pq->abuf),
1212a8ba344bSflorian 	    sldns_buffer_limit(pq->abuf))) != NULL) {
1213a8ba344bSflorian 		log_debug("from: %s\n%s", ip_port((struct sockaddr *)
1214a8ba344bSflorian 		    &pq->from), str);
12156282c991Sflorian 		free(str);
12166282c991Sflorian 	}
12176282c991Sflorian 
1218297af7e1Sflorian 	if (!pq->tcp) {
1219a8ba344bSflorian 		if(sendto(pq->fd, sldns_buffer_current(pq->abuf),
1220a8ba344bSflorian 		    sldns_buffer_remaining(pq->abuf), 0,
1221a8ba344bSflorian 		    (struct sockaddr *)&pq->from, pq->from.ss_len) == -1)
1222018cebfbSflorian 			log_warn("sendto");
1223a8ba344bSflorian 		free_pending_query(pq);
1224297af7e1Sflorian 	} else {
1225297af7e1Sflorian 		struct sldns_buffer	*tmp;
1226297af7e1Sflorian 
1227297af7e1Sflorian 		tmp = sldns_buffer_new(sldns_buffer_limit(pq->abuf) + 2);
1228297af7e1Sflorian 
1229297af7e1Sflorian 		if (!tmp) {
1230297af7e1Sflorian 			free_pending_query(pq);
1231297af7e1Sflorian 			return;
1232297af7e1Sflorian 		}
1233297af7e1Sflorian 
1234297af7e1Sflorian 		sldns_buffer_write_u16(tmp, sldns_buffer_limit(pq->abuf));
1235297af7e1Sflorian 		sldns_buffer_write(tmp, sldns_buffer_current(pq->abuf),
1236297af7e1Sflorian 		    sldns_buffer_remaining(pq->abuf));
1237297af7e1Sflorian 		sldns_buffer_flip(tmp);
1238297af7e1Sflorian 		sldns_buffer_free(pq->abuf);
1239297af7e1Sflorian 		pq->abuf = tmp;
1240297af7e1Sflorian 		event_add(&pq->resp_ev, NULL);
1241297af7e1Sflorian 	}
1242018cebfbSflorian }
1243018cebfbSflorian 
1244018cebfbSflorian char*
1245018cebfbSflorian ip_port(struct sockaddr *sa)
1246018cebfbSflorian {
1247018cebfbSflorian 	static char	 hbuf[NI_MAXHOST], buf[NI_MAXHOST];
1248018cebfbSflorian 
1249018cebfbSflorian 	if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
1250018cebfbSflorian 	    NI_NUMERICHOST) != 0) {
1251018cebfbSflorian 		snprintf(buf, sizeof(buf), "%s", "(unknown)");
1252018cebfbSflorian 		return buf;
1253018cebfbSflorian 	}
1254018cebfbSflorian 
1255018cebfbSflorian 	if (sa->sa_family == AF_INET6)
12569c8ccd70Sflorian 		snprintf(buf, sizeof(buf), "[%s]:%d", hbuf, ntohs(
12579c8ccd70Sflorian 		    ((struct sockaddr_in6 *)sa)->sin6_port));
1258018cebfbSflorian 	if (sa->sa_family == AF_INET)
12599c8ccd70Sflorian 		snprintf(buf, sizeof(buf), "[%s]:%d", hbuf, ntohs(
12609c8ccd70Sflorian 		    ((struct sockaddr_in *)sa)->sin_port));
1261018cebfbSflorian 
1262018cebfbSflorian 	return buf;
1263018cebfbSflorian }
1264018cebfbSflorian 
1265018cebfbSflorian struct pending_query*
1266018cebfbSflorian find_pending_query(uint64_t id)
1267018cebfbSflorian {
1268018cebfbSflorian 	struct pending_query	*pq;
1269018cebfbSflorian 
1270018cebfbSflorian 	TAILQ_FOREACH(pq, &pending_queries, entry)
1271018cebfbSflorian 		if (pq->imsg_id == id)
1272018cebfbSflorian 			return pq;
1273018cebfbSflorian 	return NULL;
1274018cebfbSflorian }
1275018cebfbSflorian 
1276018cebfbSflorian void
1277018cebfbSflorian route_receive(int fd, short events, void *arg)
1278018cebfbSflorian {
1279018cebfbSflorian 	static uint8_t		*buf;
1280018cebfbSflorian 
1281018cebfbSflorian 	struct rt_msghdr	*rtm;
1282018cebfbSflorian 	struct sockaddr		*sa, *rti_info[RTAX_MAX];
1283018cebfbSflorian 	ssize_t			 n;
1284018cebfbSflorian 
1285018cebfbSflorian 	if (buf == NULL) {
1286018cebfbSflorian 		buf = malloc(ROUTE_SOCKET_BUF_SIZE);
1287018cebfbSflorian 		if (buf == NULL)
1288018cebfbSflorian 			fatal("malloc");
1289018cebfbSflorian 	}
1290018cebfbSflorian 	rtm = (struct rt_msghdr *)buf;
1291018cebfbSflorian 	if ((n = read(fd, buf, ROUTE_SOCKET_BUF_SIZE)) == -1) {
1292018cebfbSflorian 		if (errno == EAGAIN || errno == EINTR)
1293018cebfbSflorian 			return;
1294018cebfbSflorian 		log_warn("dispatch_rtmsg: read error");
1295018cebfbSflorian 		return;
1296018cebfbSflorian 	}
1297018cebfbSflorian 
1298018cebfbSflorian 	if (n == 0)
1299018cebfbSflorian 		fatal("routing socket closed");
1300018cebfbSflorian 
1301018cebfbSflorian 	if (n < (ssize_t)sizeof(rtm->rtm_msglen) || n < rtm->rtm_msglen) {
1302018cebfbSflorian 		log_warnx("partial rtm of %zd in buffer", n);
1303018cebfbSflorian 		return;
1304018cebfbSflorian 	}
1305018cebfbSflorian 
1306018cebfbSflorian 	if (rtm->rtm_version != RTM_VERSION)
1307018cebfbSflorian 		return;
1308018cebfbSflorian 
1309018cebfbSflorian 	sa = (struct sockaddr *)(buf + rtm->rtm_hdrlen);
1310018cebfbSflorian 	get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
1311018cebfbSflorian 
1312018cebfbSflorian 	handle_route_message(rtm, rti_info);
1313018cebfbSflorian }
1314018cebfbSflorian 
1315018cebfbSflorian #define ROUNDUP(a) \
1316018cebfbSflorian 	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
1317018cebfbSflorian 
1318018cebfbSflorian void
1319018cebfbSflorian get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
1320018cebfbSflorian {
1321018cebfbSflorian 	int	i;
1322018cebfbSflorian 
1323018cebfbSflorian 	for (i = 0; i < RTAX_MAX; i++) {
1324018cebfbSflorian 		if (addrs & (1 << i)) {
1325018cebfbSflorian 			rti_info[i] = sa;
1326018cebfbSflorian 			sa = (struct sockaddr *)((char *)(sa) +
1327018cebfbSflorian 			    ROUNDUP(sa->sa_len));
1328018cebfbSflorian 		} else
1329018cebfbSflorian 			rti_info[i] = NULL;
1330018cebfbSflorian 	}
1331018cebfbSflorian }
1332018cebfbSflorian 
1333018cebfbSflorian void
1334018cebfbSflorian handle_route_message(struct rt_msghdr *rtm, struct sockaddr **rti_info)
1335018cebfbSflorian {
133628ba4729Sflorian 	struct imsg_rdns_proposal	 rdns_proposal;
133728ba4729Sflorian 	struct sockaddr_rtdns		*rtdns;
133885384332Sflorian 	struct if_announcemsghdr	*ifan;
1339018cebfbSflorian 
1340018cebfbSflorian 	switch (rtm->rtm_type) {
134185384332Sflorian 	case RTM_IFANNOUNCE:
134285384332Sflorian 		ifan = (struct if_announcemsghdr *)rtm;
134385384332Sflorian 		if (ifan->ifan_what == IFAN_ARRIVAL)
134485384332Sflorian 			break;
134585384332Sflorian 		rdns_proposal.if_index = ifan->ifan_index;
134685384332Sflorian 		rdns_proposal.src = 0;
134785384332Sflorian 		rdns_proposal.rtdns.sr_family = AF_INET;
134885384332Sflorian 		rdns_proposal.rtdns.sr_len = offsetof(struct sockaddr_rtdns,
134985384332Sflorian 		    sr_dns);
135085384332Sflorian 		frontend_imsg_compose_resolver(IMSG_REPLACE_DNS, 0,
135185384332Sflorian 		    &rdns_proposal, sizeof(rdns_proposal));
135285384332Sflorian 		break;
13537e9ae0c5Sflorian 	case RTM_IFINFO:
1354dcacc294Sflorian 		frontend_imsg_compose_resolver(IMSG_NETWORK_CHANGED, 0, NULL,
13557e9ae0c5Sflorian 		    0);
13567e9ae0c5Sflorian 		break;
135728ba4729Sflorian 	case RTM_PROPOSAL:
135828ba4729Sflorian 		if (!(rtm->rtm_addrs & RTA_DNS))
135928ba4729Sflorian 			break;
136028ba4729Sflorian 
136128ba4729Sflorian 		rtdns = (struct sockaddr_rtdns*)rti_info[RTAX_DNS];
136228ba4729Sflorian 		rdns_proposal.if_index = rtm->rtm_index;
136312811ba0Sflorian 		rdns_proposal.src = rtm->rtm_priority;
136428ba4729Sflorian 		memcpy(&rdns_proposal.rtdns, rtdns, sizeof(rdns_proposal.rtdns));
1365906bb1caSflorian 		frontend_imsg_compose_resolver(IMSG_REPLACE_DNS, 0,
136628ba4729Sflorian 		    &rdns_proposal, sizeof(rdns_proposal));
136728ba4729Sflorian 		break;
13685dca88ceSflorian 	case RTM_NEWADDR:
13695dca88ceSflorian 	case RTM_DELADDR:
13705dca88ceSflorian 	case RTM_DESYNC:
13715dca88ceSflorian 		check_available_af();
13725dca88ceSflorian 		break;
1373018cebfbSflorian 	default:
1374018cebfbSflorian 		break;
1375018cebfbSflorian 	}
1376018cebfbSflorian }
1377018cebfbSflorian 
1378018cebfbSflorian void
1379296cf316Sflorian add_new_ta(struct trust_anchor_head *tah, char *val)
1380296cf316Sflorian {
1381296cf316Sflorian 	struct trust_anchor	*ta, *i;
1382296cf316Sflorian 	int			 cmp;
1383296cf316Sflorian 
1384296cf316Sflorian 	if ((ta = malloc(sizeof(*ta))) == NULL)
1385296cf316Sflorian 		fatal("%s", __func__);
1386296cf316Sflorian 	if ((ta->ta = strdup(val)) == NULL)
1387296cf316Sflorian 		fatal("%s", __func__);
1388296cf316Sflorian 
1389296cf316Sflorian 	/* keep the list sorted to prevent churn if the order changes in DNS */
1390296cf316Sflorian 	TAILQ_FOREACH(i, tah, entry) {
1391296cf316Sflorian 		cmp = strcmp(i->ta, ta->ta);
1392296cf316Sflorian 		if ( cmp == 0) {
1393296cf316Sflorian 			/* duplicate */
1394296cf316Sflorian 			free(ta->ta);
1395296cf316Sflorian 			free(ta);
1396296cf316Sflorian 			return;
1397296cf316Sflorian 		} else if (cmp > 0) {
1398296cf316Sflorian 			TAILQ_INSERT_BEFORE(i, ta, entry);
1399296cf316Sflorian 			return;
1400296cf316Sflorian 		}
1401296cf316Sflorian 	}
1402296cf316Sflorian 	TAILQ_INSERT_TAIL(tah, ta, entry);
1403296cf316Sflorian }
1404296cf316Sflorian 
1405296cf316Sflorian void
1406296cf316Sflorian free_tas(struct trust_anchor_head *tah)
1407296cf316Sflorian {
1408296cf316Sflorian 	struct trust_anchor	*ta;
1409296cf316Sflorian 
1410296cf316Sflorian 	while ((ta = TAILQ_FIRST(tah))) {
1411296cf316Sflorian 		TAILQ_REMOVE(tah, ta, entry);
1412296cf316Sflorian 		free(ta->ta);
1413296cf316Sflorian 		free(ta);
1414296cf316Sflorian 	}
1415296cf316Sflorian }
1416296cf316Sflorian 
1417296cf316Sflorian int
1418296cf316Sflorian merge_tas(struct trust_anchor_head *newh, struct trust_anchor_head *oldh)
1419296cf316Sflorian {
1420296cf316Sflorian 	struct trust_anchor	*i, *j;
1421296cf316Sflorian 	int			 chg = 0;
1422296cf316Sflorian 
1423296cf316Sflorian 	j = TAILQ_FIRST(oldh);
1424296cf316Sflorian 
1425296cf316Sflorian 	TAILQ_FOREACH(i, newh, entry) {
1426296cf316Sflorian 		if (j == NULL || strcmp(i->ta, j->ta) != 0) {
1427296cf316Sflorian 			chg = 1;
1428296cf316Sflorian 			break;
1429296cf316Sflorian 		}
1430296cf316Sflorian 		j = TAILQ_NEXT(j, entry);
1431296cf316Sflorian 	}
1432296cf316Sflorian 	if (j != NULL)
1433296cf316Sflorian 		chg = 1;
1434296cf316Sflorian 
1435296cf316Sflorian 	if (chg) {
1436296cf316Sflorian 		free_tas(oldh);
143794a469e3Sbket 		TAILQ_CONCAT(oldh, newh, entry);
1438296cf316Sflorian 	} else {
1439296cf316Sflorian 		free_tas(newh);
1440296cf316Sflorian 	}
1441296cf316Sflorian 	return (chg);
1442296cf316Sflorian }
1443296cf316Sflorian 
1444296cf316Sflorian void
1445296cf316Sflorian parse_trust_anchor(struct trust_anchor_head *tah, int fd)
1446296cf316Sflorian {
1447d1b04a40Sflorian 	size_t	 len, dname_len;
1448d1b04a40Sflorian 	ssize_t	 n, sz;
1449d1b04a40Sflorian 	uint8_t	 rr[LDNS_RR_BUF_SIZE];
1450d1b04a40Sflorian 	char	*str, *p, buf[512], *line;
1451296cf316Sflorian 
1452d1b04a40Sflorian 	sz = 0;
1453d1b04a40Sflorian 	str = NULL;
1454d1b04a40Sflorian 
1455d1b04a40Sflorian 	while ((n = read(fd, buf, sizeof(buf))) > 0) {
1456d1b04a40Sflorian 		p = recallocarray(str, sz, sz + n, 1);
1457d1b04a40Sflorian 		if (p == NULL) {
1458d1b04a40Sflorian 			log_warn("%s", __func__);
1459d1b04a40Sflorian 			goto out;
1460d1b04a40Sflorian 		}
1461d1b04a40Sflorian 		str = p;
1462d1b04a40Sflorian 		memcpy(str + sz, buf, n);
1463d1b04a40Sflorian 		sz += n;
1464296cf316Sflorian 	}
1465296cf316Sflorian 
1466d1b04a40Sflorian 	if (n == -1) {
1467d1b04a40Sflorian 		log_warn("%s", __func__);
1468d1b04a40Sflorian 		goto out;
1469d1b04a40Sflorian 	}
1470d1b04a40Sflorian 
1471d1b04a40Sflorian 	/* make it a string */
1472d1b04a40Sflorian 	p = recallocarray(str, sz, sz + 1, 1);
1473d1b04a40Sflorian 	if (p == NULL) {
1474d1b04a40Sflorian 		log_warn("%s", __func__);
1475d1b04a40Sflorian 		goto out;
1476d1b04a40Sflorian 	}
1477d1b04a40Sflorian 	str = p;
1478d1b04a40Sflorian 	sz++;
1479d1b04a40Sflorian 
1480d1b04a40Sflorian 	len = sizeof(rr);
1481d1b04a40Sflorian 
1482f8e69f6bSotto 	while ((line = strsep(&p, "\n")) != NULL) {
1483d1b04a40Sflorian 		if (sldns_str2wire_rr_buf(line, rr, &len, &dname_len,
14846cee0ce8Sflorian 		    ROOT_DNSKEY_TTL, NULL, 0, NULL, 0) != 0)
1485296cf316Sflorian 			continue;
1486d1b04a40Sflorian 		if (sldns_wirerr_get_type(rr, len, dname_len) ==
1487d1b04a40Sflorian 		    LDNS_RR_TYPE_DNSKEY)
1488296cf316Sflorian 			add_new_ta(tah, line);
1489296cf316Sflorian 	}
1490d1b04a40Sflorian 
1491d1b04a40Sflorian out:
1492d1b04a40Sflorian 	free(str);
1493d1b04a40Sflorian 	return;
1494296cf316Sflorian }
1495296cf316Sflorian 
1496296cf316Sflorian void
1497296cf316Sflorian send_trust_anchors(struct trust_anchor_head *tah)
1498296cf316Sflorian {
1499296cf316Sflorian 	struct trust_anchor	*ta;
1500296cf316Sflorian 
1501296cf316Sflorian 	TAILQ_FOREACH(ta, tah, entry)
1502296cf316Sflorian 		frontend_imsg_compose_resolver(IMSG_NEW_TA, 0, ta->ta,
1503296cf316Sflorian 		    strlen(ta->ta) + 1);
1504296cf316Sflorian 	frontend_imsg_compose_resolver(IMSG_NEW_TAS_DONE, 0, NULL, 0);
1505296cf316Sflorian }
1506296cf316Sflorian 
1507296cf316Sflorian void
1508296cf316Sflorian write_trust_anchors(struct trust_anchor_head *tah, int fd)
1509296cf316Sflorian {
1510296cf316Sflorian 	struct trust_anchor	*ta;
1511d1b04a40Sflorian 	size_t			 len = 0;
1512d1b04a40Sflorian 	ssize_t			 n;
1513d1b04a40Sflorian 	char			*str;
1514296cf316Sflorian 
1515d1b04a40Sflorian 	if (lseek(fd, 0, SEEK_SET) == -1) {
1516296cf316Sflorian 		log_warn("%s", __func__);
1517d1b04a40Sflorian 		goto out;
1518296cf316Sflorian 	}
1519296cf316Sflorian 
1520d1b04a40Sflorian 	TAILQ_FOREACH(ta, tah, entry) {
1521d1b04a40Sflorian 		if ((n = asprintf(&str, "%s\n", ta->ta)) == -1) {
1522d1b04a40Sflorian 			log_warn("%s", __func__);
1523d1b04a40Sflorian 			len = 0;
1524d1b04a40Sflorian 			goto out;
1525d1b04a40Sflorian 		}
1526d1b04a40Sflorian 		len += n;
1527d1b04a40Sflorian 		if (write(fd, str, n) != n) {
1528d1b04a40Sflorian 			log_warn("%s", __func__);
1529d1b04a40Sflorian 			free(str);
1530d1b04a40Sflorian 			len = 0;
1531d1b04a40Sflorian 			goto out;
1532d1b04a40Sflorian 		}
1533d1b04a40Sflorian 		free(str);
1534d1b04a40Sflorian 	}
1535d1b04a40Sflorian out:
1536d1b04a40Sflorian 	ftruncate(fd, len);
1537d1b04a40Sflorian 	fsync(fd);
1538296cf316Sflorian }
15392d988276Sflorian 
15402d988276Sflorian void
15412d988276Sflorian parse_blocklist(int fd)
15422d988276Sflorian {
15432d988276Sflorian 	FILE		 *f;
15442d988276Sflorian 	struct bl_node	*bl_node;
15452d988276Sflorian 	char		 *line = NULL;
15462d988276Sflorian 	size_t		  linesize = 0;
15472d988276Sflorian 	ssize_t		  linelen;
15482d988276Sflorian 
15492d988276Sflorian 	if((f = fdopen(fd, "r")) == NULL) {
15502d988276Sflorian 		log_warn("cannot read block list");
15512d988276Sflorian 		close(fd);
15522d988276Sflorian 		return;
15532d988276Sflorian 	}
15542d988276Sflorian 
15552d988276Sflorian 	free_bl();
15562d988276Sflorian 
15572d988276Sflorian 	while ((linelen = getline(&line, &linesize, f)) != -1) {
15582d988276Sflorian 		if (line[linelen - 1] == '\n') {
15592d988276Sflorian 			if (linelen >= 2 && line[linelen - 2] != '.')
15602d988276Sflorian 				line[linelen - 1] = '.';
15612d988276Sflorian 			else
1562*a95f0396Skirill 				line[linelen-- - 1] = '\0';
15632d988276Sflorian 		}
15642d988276Sflorian 
1565*a95f0396Skirill 		if (line[0] == '#')
1566*a95f0396Skirill 		    continue;
1567*a95f0396Skirill 
15682d988276Sflorian 		bl_node = malloc(sizeof *bl_node);
15692d988276Sflorian 		if (bl_node == NULL)
15702d988276Sflorian 			fatal("%s: malloc", __func__);
15712d988276Sflorian 		if ((bl_node->domain = strdup(line)) == NULL)
15722d988276Sflorian 			fatal("%s: strdup", __func__);
1573*a95f0396Skirill 		reverse(bl_node->domain, bl_node->domain + linelen);
1574*a95f0396Skirill 		bl_node->len = linelen;
1575*a95f0396Skirill 		bl_node->wildcard = line[0] == '.';
1576dbebd753Stb 		if (RB_INSERT(bl_tree, &bl_head, bl_node) != NULL) {
1577dbebd753Stb 			log_warnx("duplicate blocked domain \"%s\"", line);
1578dbebd753Stb 			free(bl_node->domain);
1579dbebd753Stb 			free(bl_node);
1580dbebd753Stb 		}
15812d988276Sflorian 	}
15822d988276Sflorian 	free(line);
15832d988276Sflorian 	if (ferror(f))
15842d988276Sflorian 		log_warn("getline");
15852d988276Sflorian 	fclose(f);
15862d988276Sflorian }
15872d988276Sflorian 
15882d988276Sflorian int
15892d988276Sflorian bl_cmp(struct bl_node *e1, struct bl_node *e2) {
1590*a95f0396Skirill 	if (e1->wildcard == e2->wildcard)
15912d988276Sflorian 		return (strcasecmp(e1->domain, e2->domain));
1592*a95f0396Skirill 	else if (e1->wildcard)
1593*a95f0396Skirill 		return (strncasecmp(e1->domain, e2->domain, e1->len));
1594*a95f0396Skirill 	else /* e2->wildcard */
1595*a95f0396Skirill 		return (strncasecmp(e1->domain, e2->domain, e2->len));
15962d988276Sflorian }
15972d988276Sflorian 
15982d988276Sflorian void
15992d988276Sflorian free_bl(void)
16002d988276Sflorian {
16012d988276Sflorian 	struct bl_node	*n, *nxt;
16022d988276Sflorian 
16033bcff273Stb 	RB_FOREACH_SAFE(n, bl_tree, &bl_head, nxt) {
16042d988276Sflorian 		RB_REMOVE(bl_tree, &bl_head, n);
1605cb873a5fStb 		free(n->domain);
16062d988276Sflorian 		free(n);
16072d988276Sflorian 	}
16082d988276Sflorian }
1609b5001ac5Sotto 
1610b5001ac5Sotto int
1611b5001ac5Sotto pending_query_cnt(void)
1612b5001ac5Sotto {
1613b5001ac5Sotto 	struct pending_query	*e;
1614b5001ac5Sotto 	int			 cnt = 0;
1615b5001ac5Sotto 
1616b5001ac5Sotto 	TAILQ_FOREACH(e, &pending_queries, entry)
1617b5001ac5Sotto 		cnt++;
1618b5001ac5Sotto 	return cnt;
1619b5001ac5Sotto }
1620297af7e1Sflorian 
1621297af7e1Sflorian void
1622297af7e1Sflorian accept_paused(int fd, short events, void *arg)
1623297af7e1Sflorian {
1624297af7e1Sflorian 	struct tcp_accept_ev	*tcpev = arg;
1625297af7e1Sflorian 	event_add(&tcpev->ev, NULL);
1626297af7e1Sflorian }
1627297af7e1Sflorian 
1628297af7e1Sflorian int
1629297af7e1Sflorian accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
1630297af7e1Sflorian {
1631297af7e1Sflorian 	if (getdtablecount() + FD_RESERVE >= getdtablesize()) {
1632297af7e1Sflorian 		log_debug("%s: inflight fds exceeded", __func__);
1633297af7e1Sflorian 		errno = EMFILE;
1634297af7e1Sflorian 		return -1;
1635297af7e1Sflorian 	}
1636297af7e1Sflorian 	return accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
1637297af7e1Sflorian }
1638297af7e1Sflorian 
1639297af7e1Sflorian void
1640297af7e1Sflorian tcp_accept(int fd, short events, void *arg)
1641297af7e1Sflorian {
1642297af7e1Sflorian 	static struct timeval	 timeout = {TCP_TIMEOUT, 0};
1643297af7e1Sflorian 	static struct timeval	 backoff = {1, 0};
1644297af7e1Sflorian 	struct pending_query	*pq;
1645297af7e1Sflorian 	struct tcp_accept_ev	*tcpev;
1646297af7e1Sflorian 	struct sockaddr_storage	 ss;
1647297af7e1Sflorian 	socklen_t		 len;
1648297af7e1Sflorian 	int			 s;
1649297af7e1Sflorian 
1650297af7e1Sflorian 	tcpev = arg;
1651297af7e1Sflorian 	len = sizeof(ss);
1652297af7e1Sflorian 
1653297af7e1Sflorian 	if ((s = accept_reserve(fd, (struct sockaddr *)&ss, &len)) == -1) {
1654297af7e1Sflorian 		switch (errno) {
1655297af7e1Sflorian 		case EINTR:
1656297af7e1Sflorian 		case EWOULDBLOCK:
1657297af7e1Sflorian 		case ECONNABORTED:
1658297af7e1Sflorian 			return;
1659297af7e1Sflorian 		case EMFILE:
1660297af7e1Sflorian 		case ENFILE:
1661297af7e1Sflorian 			event_del(&tcpev->ev);
1662297af7e1Sflorian 			evtimer_add(&tcpev->pause, &backoff);
1663297af7e1Sflorian 			return;
1664297af7e1Sflorian 		default:
1665297af7e1Sflorian 			fatal("accept");
1666297af7e1Sflorian 		}
1667297af7e1Sflorian 	}
1668297af7e1Sflorian 
1669297af7e1Sflorian 	if ((pq = calloc(1, sizeof(*pq))) == NULL) {
1670297af7e1Sflorian 		log_warn(NULL);
1671297af7e1Sflorian 		close(s);
1672297af7e1Sflorian 		return;
1673297af7e1Sflorian 	}
1674297af7e1Sflorian 
1675297af7e1Sflorian 	do {
1676297af7e1Sflorian 		arc4random_buf(&pq->imsg_id, sizeof(pq->imsg_id));
1677297af7e1Sflorian 	} while(find_pending_query(pq->imsg_id) != NULL);
1678297af7e1Sflorian 
1679297af7e1Sflorian 	TAILQ_INSERT_TAIL(&pending_queries, pq, entry);
1680297af7e1Sflorian 
1681297af7e1Sflorian 	pq->from = ss;
1682297af7e1Sflorian 	pq->fd = s;
1683297af7e1Sflorian 	pq->tcp = 1;
1684297af7e1Sflorian 	pq->qbuf = sldns_buffer_new(DEFAULT_TCP_SIZE);
1685297af7e1Sflorian 	pq->region = regional_create();
1686297af7e1Sflorian 
1687dbf56da7Sflorian 	if (!pq->qbuf || !pq->region) {
1688297af7e1Sflorian 		free_pending_query(pq);
1689297af7e1Sflorian 		return;
1690297af7e1Sflorian 	}
1691297af7e1Sflorian 
1692297af7e1Sflorian 	event_set(&pq->ev, s, EV_READ | EV_PERSIST, tcp_request, pq);
1693297af7e1Sflorian 	event_add(&pq->ev, NULL);
1694297af7e1Sflorian 	event_set(&pq->resp_ev, s, EV_WRITE | EV_PERSIST, tcp_response, pq);
1695297af7e1Sflorian 
1696297af7e1Sflorian 	evtimer_set(&pq->tmo_ev, tcp_timeout, pq);
1697297af7e1Sflorian 	evtimer_add(&pq->tmo_ev, &timeout);
1698297af7e1Sflorian }
1699297af7e1Sflorian 
1700297af7e1Sflorian void
1701297af7e1Sflorian tcp_request(int fd, short events, void *arg)
1702297af7e1Sflorian {
1703297af7e1Sflorian 	struct pending_query	*pq;
1704297af7e1Sflorian 	ssize_t			 n;
1705297af7e1Sflorian 
1706297af7e1Sflorian 	pq = arg;
1707297af7e1Sflorian 
1708297af7e1Sflorian 	n = read(fd, sldns_buffer_current(pq->qbuf),
1709297af7e1Sflorian 	    sldns_buffer_remaining(pq->qbuf));
1710297af7e1Sflorian 
1711297af7e1Sflorian 	switch (n) {
1712297af7e1Sflorian 	case -1:
1713297af7e1Sflorian 		switch (errno) {
1714297af7e1Sflorian 		case EINTR:
1715297af7e1Sflorian 		case EAGAIN:
1716297af7e1Sflorian 			return;
1717297af7e1Sflorian 		default:
1718297af7e1Sflorian 			goto fail;
1719297af7e1Sflorian 		}
1720297af7e1Sflorian 		break;
1721297af7e1Sflorian 	case 0:
1722297af7e1Sflorian 		log_debug("closed connection");
1723297af7e1Sflorian 		goto fail;
1724297af7e1Sflorian 	default:
1725297af7e1Sflorian 		break;
1726297af7e1Sflorian 	}
1727297af7e1Sflorian 
1728297af7e1Sflorian 	sldns_buffer_skip(pq->qbuf, n);
1729297af7e1Sflorian 
1730297af7e1Sflorian 	if (sldns_buffer_position(pq->qbuf) >= 2 && !pq->abuf) {
1731297af7e1Sflorian 		struct sldns_buffer	*tmp;
173269f07918Sbluhm 		size_t			 rem;
1733297af7e1Sflorian 		uint16_t		 len;
1734297af7e1Sflorian 
1735297af7e1Sflorian 		sldns_buffer_flip(pq->qbuf);
1736297af7e1Sflorian 		len = sldns_buffer_read_u16(pq->qbuf);
1737297af7e1Sflorian 		tmp = sldns_buffer_new(len);
1738b9be5719Stb 		if (tmp == NULL)
1739297af7e1Sflorian 			goto fail;
1740b9be5719Stb 		pq->abuf = sldns_buffer_new(len);
1741b9be5719Stb 		if (pq->abuf == NULL) {
1742b9be5719Stb 			sldns_buffer_free(tmp);
1743b9be5719Stb 			goto fail;
1744b9be5719Stb 		}
1745297af7e1Sflorian 
174669f07918Sbluhm 		rem = sldns_buffer_remaining(pq->qbuf);
1747297af7e1Sflorian 		sldns_buffer_write(tmp, sldns_buffer_current(pq->qbuf),
174869f07918Sbluhm 		    MINIMUM(len, rem));
1749297af7e1Sflorian 		sldns_buffer_free(pq->qbuf);
1750297af7e1Sflorian 		pq->qbuf = tmp;
1751297af7e1Sflorian 	}
1752297af7e1Sflorian 	if (sldns_buffer_remaining(pq->qbuf) == 0) {
1753297af7e1Sflorian 		sldns_buffer_flip(pq->qbuf);
1754297af7e1Sflorian 		shutdown(fd, SHUT_RD);
1755297af7e1Sflorian 		event_del(&pq->ev);
1756297af7e1Sflorian 		handle_query(pq);
1757297af7e1Sflorian 	}
1758297af7e1Sflorian 	return;
1759297af7e1Sflorian fail:
1760297af7e1Sflorian 	free_pending_query(pq);
1761297af7e1Sflorian }
1762297af7e1Sflorian 
1763297af7e1Sflorian void
1764297af7e1Sflorian tcp_response(int fd, short events, void *arg)
1765297af7e1Sflorian {
1766297af7e1Sflorian 	struct pending_query	*pq;
1767297af7e1Sflorian 	ssize_t			 n;
1768297af7e1Sflorian 
1769297af7e1Sflorian 	pq = arg;
1770297af7e1Sflorian 
1771297af7e1Sflorian 	n = write(fd, sldns_buffer_current(pq->abuf),
1772297af7e1Sflorian 	    sldns_buffer_remaining(pq->abuf));
1773297af7e1Sflorian 
1774297af7e1Sflorian 	if (n == -1) {
1775297af7e1Sflorian 		if (errno == EAGAIN || errno == EINTR)
1776297af7e1Sflorian 			return;
1777297af7e1Sflorian 		free_pending_query(pq);
1778cc695705Sjsg 		return;
1779297af7e1Sflorian 	}
1780297af7e1Sflorian 	sldns_buffer_skip(pq->abuf, n);
1781297af7e1Sflorian 	if (sldns_buffer_remaining(pq->abuf) == 0)
1782297af7e1Sflorian 		free_pending_query(pq);
1783297af7e1Sflorian }
1784297af7e1Sflorian 
1785297af7e1Sflorian void
1786297af7e1Sflorian tcp_timeout(int fd, short events, void *arg)
1787297af7e1Sflorian {
1788297af7e1Sflorian 	free_pending_query(arg);
1789297af7e1Sflorian }
17905dca88ceSflorian 
17915dca88ceSflorian void
1792c16f5ec7Stb check_available_af(void)
17935dca88ceSflorian {
17945dca88ceSflorian 	static int		 available_af = HAVE_IPV4 | HAVE_IPV6;
17955dca88ceSflorian 	static int		 rtable = -1;
17965dca88ceSflorian 	struct ifaddrs		*ifap, *ifa;
17975dca88ceSflorian 	struct if_data		*ifa_data;
17985dca88ceSflorian 	struct sockaddr_in	*sin4;
17995dca88ceSflorian 	struct sockaddr_in6	*sin6;
18005dca88ceSflorian 	int			 new_available_af = 0, ifa_rtable = -1;
18015dca88ceSflorian 
18025dca88ceSflorian 	if (rtable == -1)
18035dca88ceSflorian 		rtable = getrtable();
18045dca88ceSflorian 
18055dca88ceSflorian 	if (getifaddrs(&ifap) != 0) {
18065dca88ceSflorian 		log_warn("getifaddrs");
18075dca88ceSflorian 		return;
18085dca88ceSflorian 	}
18095dca88ceSflorian 
18105dca88ceSflorian 	for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
18115dca88ceSflorian 		if (ifa->ifa_addr == NULL)
18125dca88ceSflorian 			continue;
18135dca88ceSflorian 		switch(ifa->ifa_addr->sa_family) {
18145dca88ceSflorian 		case AF_LINK:
18155dca88ceSflorian 			/* AF_LINK comes before inet / inet6 on an interface */
18165dca88ceSflorian 			ifa_data = (struct if_data *)ifa->ifa_data;
18175dca88ceSflorian 			ifa_rtable = ifa_data->ifi_rdomain;
18185dca88ceSflorian 			break;
18195dca88ceSflorian 		case AF_INET:
18205dca88ceSflorian 			if (ifa_rtable != rtable)
18215dca88ceSflorian 				continue;
18225dca88ceSflorian 
18235dca88ceSflorian 			sin4 = (struct sockaddr_in *)ifa->ifa_addr;
18245dca88ceSflorian 			if ((ntohl(sin4->sin_addr.s_addr) >> 24) ==
18255dca88ceSflorian 			    IN_LOOPBACKNET)
18265dca88ceSflorian 				continue;
18275dca88ceSflorian 			new_available_af |= HAVE_IPV4;
18285dca88ceSflorian 			break;
18295dca88ceSflorian 		case AF_INET6:
18305dca88ceSflorian 			if (ifa_rtable != rtable)
18315dca88ceSflorian 				continue;
18325dca88ceSflorian 
18335dca88ceSflorian 			sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
18345dca88ceSflorian 			if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr) ||
18355dca88ceSflorian 			    IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
18365dca88ceSflorian 			    IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr) ||
18375dca88ceSflorian 			    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr))
18385dca88ceSflorian 				continue;
18395dca88ceSflorian 			new_available_af |= HAVE_IPV6;
18405dca88ceSflorian 			break;
18415dca88ceSflorian 		default:
18425dca88ceSflorian 			break;
18435dca88ceSflorian 		}
18445dca88ceSflorian 		if (new_available_af == (HAVE_IPV4 | HAVE_IPV6))
18455dca88ceSflorian 			break;
18465dca88ceSflorian 	}
18475dca88ceSflorian 	freeifaddrs(ifap);
18485dca88ceSflorian 	if (new_available_af != available_af) {
18495dca88ceSflorian 		available_af = new_available_af;
18505dca88ceSflorian 		frontend_imsg_compose_resolver(IMSG_CHANGE_AFS, 0,
18515dca88ceSflorian 		    &available_af, sizeof(available_af));
18525dca88ceSflorian 	}
18535dca88ceSflorian }
1854*a95f0396Skirill 
1855*a95f0396Skirill void
1856*a95f0396Skirill reverse(char *begin, char *end)
1857*a95f0396Skirill {
1858*a95f0396Skirill 	char	t;
1859*a95f0396Skirill 
1860*a95f0396Skirill 	while (begin < --end) {
1861*a95f0396Skirill 		t = *begin;
1862*a95f0396Skirill 		*begin = *end;
1863*a95f0396Skirill 		*end = t;
1864*a95f0396Skirill 		++begin;
1865*a95f0396Skirill 	}
1866*a95f0396Skirill }
1867