1/*
2 * services/listen_dnsport.c - listen on port 53 for incoming DNS queries.
3 *
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5 *
6 * This software is open source.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/**
37 * \file
38 *
39 * This file has functions to get queries from clients.
40 */
41#include "config.h"
42#ifdef HAVE_SYS_TYPES_H
43#  include <sys/types.h>
44#endif
45#include <sys/time.h>
46#include "services/listen_dnsport.h"
47#include "services/outside_network.h"
48#include "util/netevent.h"
49#include "util/log.h"
50#include "util/config_file.h"
51#include "util/net_help.h"
52
53#ifdef HAVE_NETDB_H
54#include <netdb.h>
55#endif
56#include <fcntl.h>
57
58/** number of queued TCP connections for listen() */
59#define TCP_BACKLOG 5
60
61/**
62 * Debug print of the getaddrinfo returned address.
63 * @param addr: the address returned.
64 */
65static void
66verbose_print_addr(struct addrinfo *addr)
67{
68	if(verbosity >= VERB_ALGO) {
69		char buf[100];
70		void* sinaddr = &((struct sockaddr_in*)addr->ai_addr)->sin_addr;
71#ifdef INET6
72		if(addr->ai_family == AF_INET6)
73			sinaddr = &((struct sockaddr_in6*)addr->ai_addr)->
74				sin6_addr;
75#endif /* INET6 */
76		if(inet_ntop(addr->ai_family, sinaddr, buf,
77			(socklen_t)sizeof(buf)) == 0) {
78			strncpy(buf, "(null)", sizeof(buf));
79		}
80		buf[sizeof(buf)-1] = 0;
81		verbose(VERB_ALGO, "creating %s%s socket %s %d",
82			addr->ai_socktype==SOCK_DGRAM?"udp":
83			addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto",
84			addr->ai_family==AF_INET?"4":
85			addr->ai_family==AF_INET6?"6":
86			"_otherfam", buf,
87			ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port));
88	}
89}
90
91int
92create_udp_sock(int family, int socktype, struct sockaddr* addr,
93        socklen_t addrlen, int v6only, int* inuse, int* noproto,
94	int rcv, int snd)
95{
96	int s;
97#if defined(IPV6_USE_MIN_MTU)
98	int on=1;
99#endif
100#ifdef IPV6_MTU
101	int mtu = IPV6_MIN_MTU;
102#endif
103#if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF)
104	(void)rcv;
105#endif
106#if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF)
107	(void)snd;
108#endif
109#ifndef IPV6_V6ONLY
110	(void)v6only;
111#endif
112	if((s = socket(family, socktype, 0)) == -1) {
113		*inuse = 0;
114#ifndef USE_WINSOCK
115		if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
116			*noproto = 1;
117			return -1;
118		}
119		log_err("can't create socket: %s", strerror(errno));
120#else
121		if(WSAGetLastError() == WSAEAFNOSUPPORT ||
122			WSAGetLastError() == WSAEPROTONOSUPPORT) {
123			*noproto = 1;
124			return -1;
125		}
126		log_err("can't create socket: %s",
127			wsa_strerror(WSAGetLastError()));
128#endif
129		*noproto = 0;
130		return -1;
131	}
132	if(rcv) {
133#ifdef SO_RCVBUF
134		int got;
135		socklen_t slen = (socklen_t)sizeof(got);
136#  ifdef SO_RCVBUFFORCE
137		/* Linux specific: try to use root permission to override
138		 * system limits on rcvbuf. The limit is stored in
139		 * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */
140		if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv,
141			(socklen_t)sizeof(rcv)) < 0) {
142			if(errno != EPERM) {
143#    ifndef USE_WINSOCK
144				log_err("setsockopt(..., SO_RCVBUFFORCE, "
145					"...) failed: %s", strerror(errno));
146				close(s);
147#    else
148				log_err("setsockopt(..., SO_RCVBUFFORCE, "
149					"...) failed: %s",
150					wsa_strerror(WSAGetLastError()));
151				closesocket(s);
152#    endif
153				*noproto = 0;
154				*inuse = 0;
155				return -1;
156			}
157#  endif /* SO_RCVBUFFORCE */
158			if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv,
159				(socklen_t)sizeof(rcv)) < 0) {
160#  ifndef USE_WINSOCK
161				log_err("setsockopt(..., SO_RCVBUF, "
162					"...) failed: %s", strerror(errno));
163				close(s);
164#  else
165				log_err("setsockopt(..., SO_RCVBUF, "
166					"...) failed: %s",
167					wsa_strerror(WSAGetLastError()));
168				closesocket(s);
169#  endif
170				*noproto = 0;
171				*inuse = 0;
172				return -1;
173			}
174			/* check if we got the right thing or if system
175			 * reduced to some system max.  Warn if so */
176			if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got,
177				&slen) >= 0 && got < rcv/2) {
178				log_warn("so-rcvbuf %u was not granted. "
179					"Got %u. To fix: start with "
180					"root permissions(linux) or sysctl "
181					"bigger net.core.rmem_max(linux) or "
182					"kern.ipc.maxsockbuf(bsd) values.",
183					(unsigned)rcv, (unsigned)got);
184			}
185#  ifdef SO_RCVBUFFORCE
186		}
187#  endif
188#endif /* SO_RCVBUF */
189	}
190	/* first do RCVBUF as the receive buffer is more important */
191	if(snd) {
192#ifdef SO_SNDBUF
193		int got;
194		socklen_t slen = (socklen_t)sizeof(got);
195#  ifdef SO_SNDBUFFORCE
196		/* Linux specific: try to use root permission to override
197		 * system limits on sndbuf. The limit is stored in
198		 * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */
199		if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd,
200			(socklen_t)sizeof(snd)) < 0) {
201			if(errno != EPERM) {
202#    ifndef USE_WINSOCK
203				log_err("setsockopt(..., SO_SNDBUFFORCE, "
204					"...) failed: %s", strerror(errno));
205				close(s);
206#    else
207				log_err("setsockopt(..., SO_SNDBUFFORCE, "
208					"...) failed: %s",
209					wsa_strerror(WSAGetLastError()));
210				closesocket(s);
211#    endif
212				*noproto = 0;
213				*inuse = 0;
214				return -1;
215			}
216#  endif /* SO_SNDBUFFORCE */
217			if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd,
218				(socklen_t)sizeof(snd)) < 0) {
219#  ifndef USE_WINSOCK
220				log_err("setsockopt(..., SO_SNDBUF, "
221					"...) failed: %s", strerror(errno));
222				close(s);
223#  else
224				log_err("setsockopt(..., SO_SNDBUF, "
225					"...) failed: %s",
226					wsa_strerror(WSAGetLastError()));
227				closesocket(s);
228#  endif
229				*noproto = 0;
230				*inuse = 0;
231				return -1;
232			}
233			/* check if we got the right thing or if system
234			 * reduced to some system max.  Warn if so */
235			if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got,
236				&slen) >= 0 && got < snd/2) {
237				log_warn("so-sndbuf %u was not granted. "
238					"Got %u. To fix: start with "
239					"root permissions(linux) or sysctl "
240					"bigger net.core.wmem_max(linux) or "
241					"kern.ipc.maxsockbuf(bsd) values.",
242					(unsigned)snd, (unsigned)got);
243			}
244#  ifdef SO_SNDBUFFORCE
245		}
246#  endif
247#endif /* SO_SNDBUF */
248	}
249	if(family == AF_INET6) {
250# if defined(IPV6_V6ONLY)
251		if(v6only) {
252			int val=(v6only==2)?0:1;
253			if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
254				(void*)&val, (socklen_t)sizeof(val)) < 0) {
255#ifndef USE_WINSOCK
256				log_err("setsockopt(..., IPV6_V6ONLY"
257					", ...) failed: %s", strerror(errno));
258				close(s);
259#else
260				log_err("setsockopt(..., IPV6_V6ONLY"
261					", ...) failed: %s",
262					wsa_strerror(WSAGetLastError()));
263				closesocket(s);
264#endif
265				*noproto = 0;
266				*inuse = 0;
267				return -1;
268			}
269		}
270# endif
271# if defined(IPV6_USE_MIN_MTU)
272		/*
273		 * There is no fragmentation of IPv6 datagrams
274		 * during forwarding in the network. Therefore
275		 * we do not send UDP datagrams larger than
276		 * the minimum IPv6 MTU of 1280 octets. The
277		 * EDNS0 message length can be larger if the
278		 * network stack supports IPV6_USE_MIN_MTU.
279		 */
280		if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
281			(void*)&on, (socklen_t)sizeof(on)) < 0) {
282#  ifndef USE_WINSOCK
283			log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
284				"...) failed: %s", strerror(errno));
285			close(s);
286#  else
287			log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
288				"...) failed: %s",
289				wsa_strerror(WSAGetLastError()));
290			closesocket(s);
291#  endif
292			*noproto = 0;
293			*inuse = 0;
294			return -1;
295		}
296# elif defined(IPV6_MTU)
297		/*
298		 * On Linux, to send no larger than 1280, the PMTUD is
299		 * disabled by default for datagrams anyway, so we set
300		 * the MTU to use.
301		 */
302		if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU,
303			(void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
304#  ifndef USE_WINSOCK
305			log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
306				strerror(errno));
307			close(s);
308#  else
309			log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
310				wsa_strerror(WSAGetLastError()));
311			closesocket(s);
312#  endif
313			*noproto = 0;
314			*inuse = 0;
315			return -1;
316		}
317# endif /* IPv6 MTU */
318	} else if(family == AF_INET) {
319#  if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
320		int action = IP_PMTUDISC_DONT;
321		if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
322			&action, (socklen_t)sizeof(action)) < 0) {
323			log_err("setsockopt(..., IP_MTU_DISCOVER, "
324				"IP_PMTUDISC_DONT...) failed: %s",
325				strerror(errno));
326#    ifndef USE_WINSOCK
327			close(s);
328#    else
329			closesocket(s);
330#    endif
331			return -1;
332		}
333#  elif defined(IP_DONTFRAG)
334		int off = 0;
335		if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
336			&off, (socklen_t)sizeof(off)) < 0) {
337			log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s",
338				strerror(errno));
339#    ifndef USE_WINSOCK
340			close(s);
341#    else
342			closesocket(s);
343#    endif
344			return -1;
345		}
346#  endif /* IPv4 MTU */
347	}
348	if(bind(s, (struct sockaddr*)addr, addrlen) != 0) {
349		*noproto = 0;
350#ifndef USE_WINSOCK
351#ifdef EADDRINUSE
352		*inuse = (errno == EADDRINUSE);
353		/* detect freebsd jail with no ipv6 permission */
354		if(family==AF_INET6 && errno==EINVAL)
355			*noproto = 1;
356		else if(errno != EADDRINUSE) {
357			log_err("can't bind socket: %s", strerror(errno));
358			log_addr(0, "failed address",
359				(struct sockaddr_storage*)addr, addrlen);
360		}
361#endif /* EADDRINUSE */
362		close(s);
363#else /* USE_WINSOCK */
364		if(WSAGetLastError() != WSAEADDRINUSE &&
365			WSAGetLastError() != WSAEADDRNOTAVAIL) {
366			log_err("can't bind socket: %s",
367				wsa_strerror(WSAGetLastError()));
368			log_addr(0, "failed address",
369				(struct sockaddr_storage*)addr, addrlen);
370		}
371		closesocket(s);
372#endif
373		return -1;
374	}
375	if(!fd_set_nonblock(s)) {
376		*noproto = 0;
377		*inuse = 0;
378#ifndef USE_WINSOCK
379		close(s);
380#else
381		closesocket(s);
382#endif
383		return -1;
384	}
385	return s;
386}
387
388int
389create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto)
390{
391	int s;
392#if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
393	int on = 1;
394#endif /* SO_REUSEADDR || IPV6_V6ONLY */
395	verbose_print_addr(addr);
396	*noproto = 0;
397	if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
398#ifndef USE_WINSOCK
399		if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
400			*noproto = 1;
401			return -1;
402		}
403		log_err("can't create socket: %s", strerror(errno));
404#else
405		if(WSAGetLastError() == WSAEAFNOSUPPORT ||
406			WSAGetLastError() == WSAEPROTONOSUPPORT) {
407			*noproto = 1;
408			return -1;
409		}
410		log_err("can't create socket: %s",
411			wsa_strerror(WSAGetLastError()));
412#endif
413		return -1;
414	}
415#ifdef SO_REUSEADDR
416	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
417		(socklen_t)sizeof(on)) < 0) {
418#ifndef USE_WINSOCK
419		log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
420			strerror(errno));
421		close(s);
422#else
423		log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
424			wsa_strerror(WSAGetLastError()));
425		closesocket(s);
426#endif
427		return -1;
428	}
429#endif /* SO_REUSEADDR */
430#if defined(IPV6_V6ONLY)
431	if(addr->ai_family == AF_INET6 && v6only) {
432		if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
433			(void*)&on, (socklen_t)sizeof(on)) < 0) {
434#ifndef USE_WINSOCK
435			log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
436				strerror(errno));
437			close(s);
438#else
439			log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
440				wsa_strerror(WSAGetLastError()));
441			closesocket(s);
442#endif
443			return -1;
444		}
445	}
446#else
447	(void)v6only;
448#endif /* IPV6_V6ONLY */
449	if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) {
450#ifndef USE_WINSOCK
451		/* detect freebsd jail with no ipv6 permission */
452		if(addr->ai_family==AF_INET6 && errno==EINVAL)
453			*noproto = 1;
454		else {
455			log_err("can't bind socket: %s", strerror(errno));
456			log_addr(0, "failed address",
457				(struct sockaddr_storage*)addr->ai_addr,
458				addr->ai_addrlen);
459		}
460		close(s);
461#else
462		log_err("can't bind socket: %s",
463			wsa_strerror(WSAGetLastError()));
464		log_addr(0, "failed address",
465			(struct sockaddr_storage*)addr->ai_addr,
466			addr->ai_addrlen);
467		closesocket(s);
468#endif
469		return -1;
470	}
471	if(!fd_set_nonblock(s)) {
472#ifndef USE_WINSOCK
473		close(s);
474#else
475		closesocket(s);
476#endif
477		return -1;
478	}
479	if(listen(s, TCP_BACKLOG) == -1) {
480#ifndef USE_WINSOCK
481		log_err("can't listen: %s", strerror(errno));
482		close(s);
483#else
484		log_err("can't listen: %s", wsa_strerror(WSAGetLastError()));
485		closesocket(s);
486#endif
487		return -1;
488	}
489	return s;
490}
491
492/**
493 * Create socket from getaddrinfo results
494 */
495static int
496make_sock(int stype, const char* ifname, const char* port,
497	struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd)
498{
499	struct addrinfo *res = NULL;
500	int r, s, inuse, noproto;
501	hints->ai_socktype = stype;
502	*noip6 = 0;
503	if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) {
504#ifdef USE_WINSOCK
505		if(r == EAI_NONAME && hints->ai_family == AF_INET6){
506			*noip6 = 1; /* 'Host not found' for IP6 on winXP */
507			return -1;
508		}
509#endif
510		log_err("node %s:%s getaddrinfo: %s %s",
511			ifname?ifname:"default", port, gai_strerror(r),
512#ifdef EAI_SYSTEM
513			r==EAI_SYSTEM?(char*)strerror(errno):""
514#else
515			""
516#endif
517		);
518		return -1;
519	}
520	if(stype == SOCK_DGRAM) {
521		verbose_print_addr(res);
522		s = create_udp_sock(res->ai_family, res->ai_socktype,
523			(struct sockaddr*)res->ai_addr, res->ai_addrlen,
524			v6only, &inuse, &noproto, (int)rcv, (int)snd);
525		if(s == -1 && inuse) {
526			log_err("bind: address already in use");
527		} else if(s == -1 && noproto && hints->ai_family == AF_INET6){
528			*noip6 = 1;
529		}
530	} else	{
531		s = create_tcp_accept_sock(res, v6only, &noproto);
532		if(s == -1 && noproto && hints->ai_family == AF_INET6){
533			*noip6 = 1;
534		}
535	}
536	freeaddrinfo(res);
537	return s;
538}
539
540/** make socket and first see if ifname contains port override info */
541static int
542make_sock_port(int stype, const char* ifname, const char* port,
543	struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd)
544{
545	char* s = strchr(ifname, '@');
546	if(s) {
547		/* override port with ifspec@port */
548		char p[16];
549		char newif[128];
550		if((size_t)(s-ifname) >= sizeof(newif)) {
551			log_err("ifname too long: %s", ifname);
552			*noip6 = 0;
553			return -1;
554		}
555		if(strlen(s+1) >= sizeof(p)) {
556			log_err("portnumber too long: %s", ifname);
557			*noip6 = 0;
558			return -1;
559		}
560		strncpy(newif, ifname, sizeof(newif));
561		newif[s-ifname] = 0;
562		strncpy(p, s+1, sizeof(p));
563		p[strlen(s+1)]=0;
564		return make_sock(stype, newif, p, hints, v6only, noip6,
565			rcv, snd);
566	}
567	return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd);
568}
569
570/**
571 * Add port to open ports list.
572 * @param list: list head. changed.
573 * @param s: fd.
574 * @param ftype: if fd is UDP.
575 * @return false on failure. list in unchanged then.
576 */
577static int
578port_insert(struct listen_port** list, int s, enum listen_type ftype)
579{
580	struct listen_port* item = (struct listen_port*)malloc(
581		sizeof(struct listen_port));
582	if(!item)
583		return 0;
584	item->next = *list;
585	item->fd = s;
586	item->ftype = ftype;
587	*list = item;
588	return 1;
589}
590
591/** set fd to receive source address packet info */
592static int
593set_recvpktinfo(int s, int family)
594{
595#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)) || defined(IP_PKTINFO)
596	int on = 1;
597#else
598	(void)s;
599#endif
600	if(family == AF_INET6) {
601#           ifdef IPV6_RECVPKTINFO
602		if(setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
603			(void*)&on, (socklen_t)sizeof(on)) < 0) {
604			log_err("setsockopt(..., IPV6_RECVPKTINFO, ...) failed: %s",
605				strerror(errno));
606			return 0;
607		}
608#           elif defined(IPV6_PKTINFO)
609		if(setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO,
610			(void*)&on, (socklen_t)sizeof(on)) < 0) {
611			log_err("setsockopt(..., IPV6_PKTINFO, ...) failed: %s",
612				strerror(errno));
613			return 0;
614		}
615#           else
616		log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please "
617			"disable interface-automatic in config");
618		return 0;
619#           endif /* defined IPV6_RECVPKTINFO */
620
621	} else if(family == AF_INET) {
622#           ifdef IP_PKTINFO
623		if(setsockopt(s, IPPROTO_IP, IP_PKTINFO,
624			(void*)&on, (socklen_t)sizeof(on)) < 0) {
625			log_err("setsockopt(..., IP_PKTINFO, ...) failed: %s",
626				strerror(errno));
627			return 0;
628		}
629#           elif defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)
630		if(setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
631			(void*)&on, (socklen_t)sizeof(on)) < 0) {
632			log_err("setsockopt(..., IP_RECVDSTADDR, ...) failed: %s",
633				strerror(errno));
634			return 0;
635		}
636#           else
637		log_err("no IP_SENDSRCADDR or IP_PKTINFO option, please disable "
638			"interface-automatic in config");
639		return 0;
640#           endif /* IP_PKTINFO */
641
642	}
643	return 1;
644}
645
646/**
647 * Helper for ports_open. Creates one interface (or NULL for default).
648 * @param ifname: The interface ip address.
649 * @param do_auto: use automatic interface detection.
650 * 	If enabled, then ifname must be the wildcard name.
651 * @param do_udp: if udp should be used.
652 * @param do_tcp: if udp should be used.
653 * @param hints: for getaddrinfo. family and flags have to be set by caller.
654 * @param port: Port number to use (as string).
655 * @param list: list of open ports, appended to, changed to point to list head.
656 * @param rcv: receive buffer size for UDP
657 * @param snd: send buffer size for UDP
658 * @param ssl_port: ssl service port number
659 * @return: returns false on error.
660 */
661static int
662ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
663	struct addrinfo *hints, const char* port, struct listen_port** list,
664	size_t rcv, size_t snd, int ssl_port)
665{
666	int s, noip6=0;
667	if(!do_udp && !do_tcp)
668		return 0;
669	if(do_auto) {
670		if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
671			&noip6, rcv, snd)) == -1) {
672			if(noip6) {
673				log_warn("IPv6 protocol not available");
674				return 1;
675			}
676			return 0;
677		}
678		/* getting source addr packet info is highly non-portable */
679		if(!set_recvpktinfo(s, hints->ai_family)) {
680#ifndef USE_WINSOCK
681			close(s);
682#else
683			closesocket(s);
684#endif
685			return 0;
686		}
687		if(!port_insert(list, s, listen_type_udpancil)) {
688#ifndef USE_WINSOCK
689			close(s);
690#else
691			closesocket(s);
692#endif
693			return 0;
694		}
695	} else if(do_udp) {
696		/* regular udp socket */
697		if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
698			&noip6, rcv, snd)) == -1) {
699			if(noip6) {
700				log_warn("IPv6 protocol not available");
701				return 1;
702			}
703			return 0;
704		}
705		if(!port_insert(list, s, listen_type_udp)) {
706#ifndef USE_WINSOCK
707			close(s);
708#else
709			closesocket(s);
710#endif
711			return 0;
712		}
713	}
714	if(do_tcp) {
715		int is_ssl = ((strchr(ifname, '@') &&
716			atoi(strchr(ifname, '@')+1) == ssl_port) ||
717			(!strchr(ifname, '@') && atoi(port) == ssl_port));
718		if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
719			&noip6, 0, 0)) == -1) {
720			if(noip6) {
721				/*log_warn("IPv6 protocol not available");*/
722				return 1;
723			}
724			return 0;
725		}
726		if(is_ssl)
727			verbose(VERB_ALGO, "setup TCP for SSL service");
728		if(!port_insert(list, s, is_ssl?listen_type_ssl:
729			listen_type_tcp)) {
730#ifndef USE_WINSOCK
731			close(s);
732#else
733			closesocket(s);
734#endif
735			return 0;
736		}
737	}
738	return 1;
739}
740
741/**
742 * Add items to commpoint list in front.
743 * @param c: commpoint to add.
744 * @param front: listen struct.
745 * @return: false on failure.
746 */
747static int
748listen_cp_insert(struct comm_point* c, struct listen_dnsport* front)
749{
750	struct listen_list* item = (struct listen_list*)malloc(
751		sizeof(struct listen_list));
752	if(!item)
753		return 0;
754	item->com = c;
755	item->next = front->cps;
756	front->cps = item;
757	return 1;
758}
759
760struct listen_dnsport*
761listen_create(struct comm_base* base, struct listen_port* ports,
762	size_t bufsize, int tcp_accept_count, void* sslctx,
763	comm_point_callback_t* cb, void *cb_arg)
764{
765	struct listen_dnsport* front = (struct listen_dnsport*)
766		malloc(sizeof(struct listen_dnsport));
767	if(!front)
768		return NULL;
769	front->cps = NULL;
770	front->udp_buff = ldns_buffer_new(bufsize);
771	if(!front->udp_buff) {
772		free(front);
773		return NULL;
774	}
775
776	/* create comm points as needed */
777	while(ports) {
778		struct comm_point* cp = NULL;
779		if(ports->ftype == listen_type_udp)
780			cp = comm_point_create_udp(base, ports->fd,
781				front->udp_buff, cb, cb_arg);
782		else if(ports->ftype == listen_type_tcp)
783			cp = comm_point_create_tcp(base, ports->fd,
784				tcp_accept_count, bufsize, cb, cb_arg);
785		else if(ports->ftype == listen_type_ssl) {
786			cp = comm_point_create_tcp(base, ports->fd,
787				tcp_accept_count, bufsize, cb, cb_arg);
788			cp->ssl = sslctx;
789		} else if(ports->ftype == listen_type_udpancil)
790			cp = comm_point_create_udp_ancil(base, ports->fd,
791				front->udp_buff, cb, cb_arg);
792		if(!cp) {
793			log_err("can't create commpoint");
794			listen_delete(front);
795			return NULL;
796		}
797		cp->do_not_close = 1;
798		if(!listen_cp_insert(cp, front)) {
799			log_err("malloc failed");
800			comm_point_delete(cp);
801			listen_delete(front);
802			return NULL;
803		}
804		ports = ports->next;
805	}
806	if(!front->cps) {
807		log_err("Could not open sockets to accept queries.");
808		listen_delete(front);
809		return NULL;
810	}
811
812	return front;
813}
814
815void
816listen_list_delete(struct listen_list* list)
817{
818	struct listen_list *p = list, *pn;
819	while(p) {
820		pn = p->next;
821		comm_point_delete(p->com);
822		free(p);
823		p = pn;
824	}
825}
826
827void
828listen_delete(struct listen_dnsport* front)
829{
830	if(!front)
831		return;
832	listen_list_delete(front->cps);
833	ldns_buffer_free(front->udp_buff);
834	free(front);
835}
836
837struct listen_port*
838listening_ports_open(struct config_file* cfg)
839{
840	struct listen_port* list = NULL;
841	struct addrinfo hints;
842	int i, do_ip4, do_ip6;
843	int do_tcp, do_auto;
844	char portbuf[32];
845	snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
846	do_ip4 = cfg->do_ip4;
847	do_ip6 = cfg->do_ip6;
848	do_tcp = cfg->do_tcp;
849	do_auto = cfg->if_automatic && cfg->do_udp;
850	if(cfg->incoming_num_tcp == 0)
851		do_tcp = 0;
852
853	/* getaddrinfo */
854	memset(&hints, 0, sizeof(hints));
855	hints.ai_flags = AI_PASSIVE;
856	/* no name lookups on our listening ports */
857	if(cfg->num_ifs > 0)
858		hints.ai_flags |= AI_NUMERICHOST;
859	hints.ai_family = AF_UNSPEC;
860#ifndef INET6
861	do_ip6 = 0;
862#endif
863	if(!do_ip4 && !do_ip6) {
864		return NULL;
865	}
866	/* create ip4 and ip6 ports so that return addresses are nice. */
867	if(do_auto || cfg->num_ifs == 0) {
868		if(do_ip6) {
869			hints.ai_family = AF_INET6;
870			if(!ports_create_if(do_auto?"::0":"::1",
871				do_auto, cfg->do_udp, do_tcp,
872				&hints, portbuf, &list,
873				cfg->so_rcvbuf, cfg->so_sndbuf,
874				cfg->ssl_port)) {
875				listening_ports_free(list);
876				return NULL;
877			}
878		}
879		if(do_ip4) {
880			hints.ai_family = AF_INET;
881			if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
882				do_auto, cfg->do_udp, do_tcp,
883				&hints, portbuf, &list,
884				cfg->so_rcvbuf, cfg->so_sndbuf,
885				cfg->ssl_port)) {
886				listening_ports_free(list);
887				return NULL;
888			}
889		}
890	} else for(i = 0; i<cfg->num_ifs; i++) {
891		if(str_is_ip6(cfg->ifs[i])) {
892			if(!do_ip6)
893				continue;
894			hints.ai_family = AF_INET6;
895			if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
896				do_tcp, &hints, portbuf, &list,
897				cfg->so_rcvbuf, cfg->so_sndbuf,
898				cfg->ssl_port)) {
899				listening_ports_free(list);
900				return NULL;
901			}
902		} else {
903			if(!do_ip4)
904				continue;
905			hints.ai_family = AF_INET;
906			if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
907				do_tcp, &hints, portbuf, &list,
908				cfg->so_rcvbuf, cfg->so_sndbuf,
909				cfg->ssl_port)) {
910				listening_ports_free(list);
911				return NULL;
912			}
913		}
914	}
915	return list;
916}
917
918void listening_ports_free(struct listen_port* list)
919{
920	struct listen_port* nx;
921	while(list) {
922		nx = list->next;
923		if(list->fd != -1) {
924#ifndef USE_WINSOCK
925			close(list->fd);
926#else
927			closesocket(list->fd);
928#endif
929		}
930		free(list);
931		list = nx;
932	}
933}
934
935size_t listen_get_mem(struct listen_dnsport* listen)
936{
937	size_t s = sizeof(*listen) + sizeof(*listen->base) +
938		sizeof(*listen->udp_buff) +
939		ldns_buffer_capacity(listen->udp_buff);
940	struct listen_list* p;
941	for(p = listen->cps; p; p = p->next) {
942		s += sizeof(*p);
943		s += comm_point_get_mem(p->com);
944	}
945	return s;
946}
947
948void listen_stop_accept(struct listen_dnsport* listen)
949{
950	/* do not stop the ones that have no tcp_free list
951	 * (they have already stopped listening) */
952	struct listen_list* p;
953	for(p=listen->cps; p; p=p->next) {
954		if(p->com->type == comm_tcp_accept &&
955			p->com->tcp_free != NULL) {
956			comm_point_stop_listening(p->com);
957		}
958	}
959}
960
961void listen_start_accept(struct listen_dnsport* listen)
962{
963	/* do not start the ones that have no tcp_free list, it is no
964	 * use to listen to them because they have no free tcp handlers */
965	struct listen_list* p;
966	for(p=listen->cps; p; p=p->next) {
967		if(p->com->type == comm_tcp_accept &&
968			p->com->tcp_free != NULL) {
969			comm_point_start_listening(p->com, -1, -1);
970		}
971	}
972}
973
974