1238106Sdes/*
2238106Sdes * services/listen_dnsport.c - listen on port 53 for incoming DNS queries.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file has functions to get queries from clients.
40238106Sdes */
41238106Sdes#include "config.h"
42238106Sdes#ifdef HAVE_SYS_TYPES_H
43238106Sdes#  include <sys/types.h>
44238106Sdes#endif
45238106Sdes#include <sys/time.h>
46238106Sdes#include "services/listen_dnsport.h"
47238106Sdes#include "services/outside_network.h"
48238106Sdes#include "util/netevent.h"
49238106Sdes#include "util/log.h"
50238106Sdes#include "util/config_file.h"
51238106Sdes#include "util/net_help.h"
52291767Sdes#include "sldns/sbuffer.h"
53238106Sdes
54238106Sdes#ifdef HAVE_NETDB_H
55238106Sdes#include <netdb.h>
56238106Sdes#endif
57238106Sdes#include <fcntl.h>
58238106Sdes
59285206Sdes#ifdef HAVE_SYS_UN_H
60285206Sdes#include <sys/un.h>
61285206Sdes#endif
62285206Sdes
63238106Sdes/** number of queued TCP connections for listen() */
64285206Sdes#define TCP_BACKLOG 256
65238106Sdes
66238106Sdes/**
67238106Sdes * Debug print of the getaddrinfo returned address.
68238106Sdes * @param addr: the address returned.
69238106Sdes */
70238106Sdesstatic void
71238106Sdesverbose_print_addr(struct addrinfo *addr)
72238106Sdes{
73238106Sdes	if(verbosity >= VERB_ALGO) {
74238106Sdes		char buf[100];
75238106Sdes		void* sinaddr = &((struct sockaddr_in*)addr->ai_addr)->sin_addr;
76238106Sdes#ifdef INET6
77238106Sdes		if(addr->ai_family == AF_INET6)
78238106Sdes			sinaddr = &((struct sockaddr_in6*)addr->ai_addr)->
79238106Sdes				sin6_addr;
80238106Sdes#endif /* INET6 */
81238106Sdes		if(inet_ntop(addr->ai_family, sinaddr, buf,
82238106Sdes			(socklen_t)sizeof(buf)) == 0) {
83269257Sdes			(void)strlcpy(buf, "(null)", sizeof(buf));
84238106Sdes		}
85238106Sdes		buf[sizeof(buf)-1] = 0;
86238106Sdes		verbose(VERB_ALGO, "creating %s%s socket %s %d",
87238106Sdes			addr->ai_socktype==SOCK_DGRAM?"udp":
88238106Sdes			addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto",
89238106Sdes			addr->ai_family==AF_INET?"4":
90238106Sdes			addr->ai_family==AF_INET6?"6":
91238106Sdes			"_otherfam", buf,
92238106Sdes			ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port));
93238106Sdes	}
94238106Sdes}
95238106Sdes
96238106Sdesint
97238106Sdescreate_udp_sock(int family, int socktype, struct sockaddr* addr,
98238106Sdes        socklen_t addrlen, int v6only, int* inuse, int* noproto,
99291767Sdes	int rcv, int snd, int listen, int* reuseport, int transparent)
100238106Sdes{
101238106Sdes	int s;
102291767Sdes#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU)  || defined(IP_TRANSPARENT)
103238106Sdes	int on=1;
104238106Sdes#endif
105238106Sdes#ifdef IPV6_MTU
106238106Sdes	int mtu = IPV6_MIN_MTU;
107238106Sdes#endif
108238106Sdes#if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF)
109238106Sdes	(void)rcv;
110238106Sdes#endif
111238106Sdes#if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF)
112238106Sdes	(void)snd;
113238106Sdes#endif
114238106Sdes#ifndef IPV6_V6ONLY
115238106Sdes	(void)v6only;
116238106Sdes#endif
117291767Sdes#ifndef IP_TRANSPARENT
118291767Sdes	(void)transparent;
119291767Sdes#endif
120238106Sdes	if((s = socket(family, socktype, 0)) == -1) {
121238106Sdes		*inuse = 0;
122238106Sdes#ifndef USE_WINSOCK
123238106Sdes		if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
124238106Sdes			*noproto = 1;
125238106Sdes			return -1;
126238106Sdes		}
127238106Sdes		log_err("can't create socket: %s", strerror(errno));
128238106Sdes#else
129238106Sdes		if(WSAGetLastError() == WSAEAFNOSUPPORT ||
130238106Sdes			WSAGetLastError() == WSAEPROTONOSUPPORT) {
131238106Sdes			*noproto = 1;
132238106Sdes			return -1;
133238106Sdes		}
134238106Sdes		log_err("can't create socket: %s",
135238106Sdes			wsa_strerror(WSAGetLastError()));
136238106Sdes#endif
137238106Sdes		*noproto = 0;
138238106Sdes		return -1;
139238106Sdes	}
140269257Sdes	if(listen) {
141269257Sdes#ifdef SO_REUSEADDR
142269257Sdes		if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
143269257Sdes			(socklen_t)sizeof(on)) < 0) {
144269257Sdes#ifndef USE_WINSOCK
145269257Sdes			log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
146269257Sdes				strerror(errno));
147269257Sdes			if(errno != ENOSYS) {
148269257Sdes				close(s);
149269257Sdes				*noproto = 0;
150269257Sdes				*inuse = 0;
151269257Sdes				return -1;
152269257Sdes			}
153269257Sdes#else
154269257Sdes			log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
155269257Sdes				wsa_strerror(WSAGetLastError()));
156269257Sdes			closesocket(s);
157269257Sdes			*noproto = 0;
158269257Sdes			*inuse = 0;
159269257Sdes			return -1;
160269257Sdes#endif
161269257Sdes		}
162269257Sdes#endif /* SO_REUSEADDR */
163285206Sdes#ifdef SO_REUSEPORT
164285206Sdes		/* try to set SO_REUSEPORT so that incoming
165269257Sdes		 * queries are distributed evenly among the receiving threads.
166269257Sdes		 * Each thread must have its own socket bound to the same port,
167269257Sdes		 * with SO_REUSEPORT set on each socket.
168269257Sdes		 */
169269257Sdes		if (reuseport && *reuseport &&
170269257Sdes		    setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
171269257Sdes			(socklen_t)sizeof(on)) < 0) {
172269257Sdes#ifdef ENOPROTOOPT
173269257Sdes			if(errno != ENOPROTOOPT || verbosity >= 3)
174269257Sdes				log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
175269257Sdes					strerror(errno));
176269257Sdes#endif
177269257Sdes			/* this option is not essential, we can continue */
178269257Sdes			*reuseport = 0;
179269257Sdes		}
180269257Sdes#else
181269257Sdes		(void)reuseport;
182285206Sdes#endif /* defined(SO_REUSEPORT) */
183291767Sdes#ifdef IP_TRANSPARENT
184291767Sdes		if (transparent &&
185291767Sdes		    setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
186291767Sdes		    (socklen_t)sizeof(on)) < 0) {
187291767Sdes			log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s",
188291767Sdes			strerror(errno));
189291767Sdes		}
190291767Sdes#endif /* IP_TRANSPARENT */
191269257Sdes	}
192238106Sdes	if(rcv) {
193238106Sdes#ifdef SO_RCVBUF
194238106Sdes		int got;
195238106Sdes		socklen_t slen = (socklen_t)sizeof(got);
196238106Sdes#  ifdef SO_RCVBUFFORCE
197238106Sdes		/* Linux specific: try to use root permission to override
198238106Sdes		 * system limits on rcvbuf. The limit is stored in
199238106Sdes		 * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */
200238106Sdes		if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv,
201238106Sdes			(socklen_t)sizeof(rcv)) < 0) {
202238106Sdes			if(errno != EPERM) {
203238106Sdes#    ifndef USE_WINSOCK
204238106Sdes				log_err("setsockopt(..., SO_RCVBUFFORCE, "
205238106Sdes					"...) failed: %s", strerror(errno));
206238106Sdes				close(s);
207238106Sdes#    else
208238106Sdes				log_err("setsockopt(..., SO_RCVBUFFORCE, "
209238106Sdes					"...) failed: %s",
210238106Sdes					wsa_strerror(WSAGetLastError()));
211238106Sdes				closesocket(s);
212238106Sdes#    endif
213238106Sdes				*noproto = 0;
214238106Sdes				*inuse = 0;
215238106Sdes				return -1;
216238106Sdes			}
217238106Sdes#  endif /* SO_RCVBUFFORCE */
218238106Sdes			if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv,
219238106Sdes				(socklen_t)sizeof(rcv)) < 0) {
220238106Sdes#  ifndef USE_WINSOCK
221238106Sdes				log_err("setsockopt(..., SO_RCVBUF, "
222238106Sdes					"...) failed: %s", strerror(errno));
223238106Sdes				close(s);
224238106Sdes#  else
225238106Sdes				log_err("setsockopt(..., SO_RCVBUF, "
226238106Sdes					"...) failed: %s",
227238106Sdes					wsa_strerror(WSAGetLastError()));
228238106Sdes				closesocket(s);
229238106Sdes#  endif
230238106Sdes				*noproto = 0;
231238106Sdes				*inuse = 0;
232238106Sdes				return -1;
233238106Sdes			}
234238106Sdes			/* check if we got the right thing or if system
235238106Sdes			 * reduced to some system max.  Warn if so */
236238106Sdes			if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got,
237238106Sdes				&slen) >= 0 && got < rcv/2) {
238238106Sdes				log_warn("so-rcvbuf %u was not granted. "
239238106Sdes					"Got %u. To fix: start with "
240238106Sdes					"root permissions(linux) or sysctl "
241238106Sdes					"bigger net.core.rmem_max(linux) or "
242238106Sdes					"kern.ipc.maxsockbuf(bsd) values.",
243238106Sdes					(unsigned)rcv, (unsigned)got);
244238106Sdes			}
245238106Sdes#  ifdef SO_RCVBUFFORCE
246238106Sdes		}
247238106Sdes#  endif
248238106Sdes#endif /* SO_RCVBUF */
249238106Sdes	}
250238106Sdes	/* first do RCVBUF as the receive buffer is more important */
251238106Sdes	if(snd) {
252238106Sdes#ifdef SO_SNDBUF
253238106Sdes		int got;
254238106Sdes		socklen_t slen = (socklen_t)sizeof(got);
255238106Sdes#  ifdef SO_SNDBUFFORCE
256238106Sdes		/* Linux specific: try to use root permission to override
257238106Sdes		 * system limits on sndbuf. The limit is stored in
258238106Sdes		 * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */
259238106Sdes		if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd,
260238106Sdes			(socklen_t)sizeof(snd)) < 0) {
261238106Sdes			if(errno != EPERM) {
262238106Sdes#    ifndef USE_WINSOCK
263238106Sdes				log_err("setsockopt(..., SO_SNDBUFFORCE, "
264238106Sdes					"...) failed: %s", strerror(errno));
265238106Sdes				close(s);
266238106Sdes#    else
267238106Sdes				log_err("setsockopt(..., SO_SNDBUFFORCE, "
268238106Sdes					"...) failed: %s",
269238106Sdes					wsa_strerror(WSAGetLastError()));
270238106Sdes				closesocket(s);
271238106Sdes#    endif
272238106Sdes				*noproto = 0;
273238106Sdes				*inuse = 0;
274238106Sdes				return -1;
275238106Sdes			}
276238106Sdes#  endif /* SO_SNDBUFFORCE */
277238106Sdes			if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd,
278238106Sdes				(socklen_t)sizeof(snd)) < 0) {
279238106Sdes#  ifndef USE_WINSOCK
280238106Sdes				log_err("setsockopt(..., SO_SNDBUF, "
281238106Sdes					"...) failed: %s", strerror(errno));
282238106Sdes				close(s);
283238106Sdes#  else
284238106Sdes				log_err("setsockopt(..., SO_SNDBUF, "
285238106Sdes					"...) failed: %s",
286238106Sdes					wsa_strerror(WSAGetLastError()));
287238106Sdes				closesocket(s);
288238106Sdes#  endif
289238106Sdes				*noproto = 0;
290238106Sdes				*inuse = 0;
291238106Sdes				return -1;
292238106Sdes			}
293238106Sdes			/* check if we got the right thing or if system
294238106Sdes			 * reduced to some system max.  Warn if so */
295238106Sdes			if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got,
296238106Sdes				&slen) >= 0 && got < snd/2) {
297238106Sdes				log_warn("so-sndbuf %u was not granted. "
298238106Sdes					"Got %u. To fix: start with "
299238106Sdes					"root permissions(linux) or sysctl "
300238106Sdes					"bigger net.core.wmem_max(linux) or "
301238106Sdes					"kern.ipc.maxsockbuf(bsd) values.",
302238106Sdes					(unsigned)snd, (unsigned)got);
303238106Sdes			}
304238106Sdes#  ifdef SO_SNDBUFFORCE
305238106Sdes		}
306238106Sdes#  endif
307238106Sdes#endif /* SO_SNDBUF */
308238106Sdes	}
309238106Sdes	if(family == AF_INET6) {
310238106Sdes# if defined(IPV6_V6ONLY)
311238106Sdes		if(v6only) {
312238106Sdes			int val=(v6only==2)?0:1;
313238106Sdes			if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
314238106Sdes				(void*)&val, (socklen_t)sizeof(val)) < 0) {
315238106Sdes#ifndef USE_WINSOCK
316238106Sdes				log_err("setsockopt(..., IPV6_V6ONLY"
317238106Sdes					", ...) failed: %s", strerror(errno));
318238106Sdes				close(s);
319238106Sdes#else
320238106Sdes				log_err("setsockopt(..., IPV6_V6ONLY"
321238106Sdes					", ...) failed: %s",
322238106Sdes					wsa_strerror(WSAGetLastError()));
323238106Sdes				closesocket(s);
324238106Sdes#endif
325238106Sdes				*noproto = 0;
326238106Sdes				*inuse = 0;
327238106Sdes				return -1;
328238106Sdes			}
329238106Sdes		}
330238106Sdes# endif
331238106Sdes# if defined(IPV6_USE_MIN_MTU)
332238106Sdes		/*
333238106Sdes		 * There is no fragmentation of IPv6 datagrams
334238106Sdes		 * during forwarding in the network. Therefore
335238106Sdes		 * we do not send UDP datagrams larger than
336238106Sdes		 * the minimum IPv6 MTU of 1280 octets. The
337238106Sdes		 * EDNS0 message length can be larger if the
338238106Sdes		 * network stack supports IPV6_USE_MIN_MTU.
339238106Sdes		 */
340238106Sdes		if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
341238106Sdes			(void*)&on, (socklen_t)sizeof(on)) < 0) {
342238106Sdes#  ifndef USE_WINSOCK
343238106Sdes			log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
344238106Sdes				"...) failed: %s", strerror(errno));
345238106Sdes			close(s);
346238106Sdes#  else
347238106Sdes			log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
348238106Sdes				"...) failed: %s",
349238106Sdes				wsa_strerror(WSAGetLastError()));
350238106Sdes			closesocket(s);
351238106Sdes#  endif
352238106Sdes			*noproto = 0;
353238106Sdes			*inuse = 0;
354238106Sdes			return -1;
355238106Sdes		}
356238106Sdes# elif defined(IPV6_MTU)
357238106Sdes		/*
358238106Sdes		 * On Linux, to send no larger than 1280, the PMTUD is
359238106Sdes		 * disabled by default for datagrams anyway, so we set
360238106Sdes		 * the MTU to use.
361238106Sdes		 */
362238106Sdes		if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU,
363238106Sdes			(void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
364238106Sdes#  ifndef USE_WINSOCK
365238106Sdes			log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
366238106Sdes				strerror(errno));
367238106Sdes			close(s);
368238106Sdes#  else
369238106Sdes			log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
370238106Sdes				wsa_strerror(WSAGetLastError()));
371238106Sdes			closesocket(s);
372238106Sdes#  endif
373238106Sdes			*noproto = 0;
374238106Sdes			*inuse = 0;
375238106Sdes			return -1;
376238106Sdes		}
377238106Sdes# endif /* IPv6 MTU */
378238106Sdes	} else if(family == AF_INET) {
379238106Sdes#  if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
380285206Sdes/* linux 3.15 has IP_PMTUDISC_OMIT, Hannes Frederic Sowa made it so that
381285206Sdes * PMTU information is not accepted, but fragmentation is allowed
382285206Sdes * if and only if the packet size exceeds the outgoing interface MTU
383285206Sdes * (and also uses the interface mtu to determine the size of the packets).
384285206Sdes * So there won't be any EMSGSIZE error.  Against DNS fragmentation attacks.
385285206Sdes * FreeBSD already has same semantics without setting the option. */
386285206Sdes		int omit_set = 0;
387285206Sdes		int action;
388285206Sdes#   if defined(IP_PMTUDISC_OMIT)
389285206Sdes		action = IP_PMTUDISC_OMIT;
390238106Sdes		if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
391238106Sdes			&action, (socklen_t)sizeof(action)) < 0) {
392285206Sdes
393285206Sdes			if (errno != EINVAL) {
394285206Sdes				log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_OMIT...) failed: %s",
395285206Sdes					strerror(errno));
396285206Sdes
397249141Sdes#    ifndef USE_WINSOCK
398285206Sdes				close(s);
399249141Sdes#    else
400285206Sdes				closesocket(s);
401249141Sdes#    endif
402285206Sdes				*noproto = 0;
403285206Sdes				*inuse = 0;
404285206Sdes				return -1;
405285206Sdes			}
406238106Sdes		}
407285206Sdes		else
408285206Sdes		{
409285206Sdes		    omit_set = 1;
410285206Sdes		}
411285206Sdes#   endif
412285206Sdes		if (omit_set == 0) {
413285206Sdes   			action = IP_PMTUDISC_DONT;
414285206Sdes			if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
415285206Sdes				&action, (socklen_t)sizeof(action)) < 0) {
416285206Sdes				log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_DONT...) failed: %s",
417285206Sdes					strerror(errno));
418285206Sdes#    ifndef USE_WINSOCK
419285206Sdes				close(s);
420285206Sdes#    else
421285206Sdes				closesocket(s);
422285206Sdes#    endif
423285206Sdes				*noproto = 0;
424285206Sdes				*inuse = 0;
425285206Sdes				return -1;
426285206Sdes			}
427285206Sdes		}
428238106Sdes#  elif defined(IP_DONTFRAG)
429238106Sdes		int off = 0;
430238106Sdes		if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
431238106Sdes			&off, (socklen_t)sizeof(off)) < 0) {
432238106Sdes			log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s",
433238106Sdes				strerror(errno));
434249141Sdes#    ifndef USE_WINSOCK
435249141Sdes			close(s);
436249141Sdes#    else
437249141Sdes			closesocket(s);
438249141Sdes#    endif
439269257Sdes			*noproto = 0;
440269257Sdes			*inuse = 0;
441238106Sdes			return -1;
442238106Sdes		}
443238106Sdes#  endif /* IPv4 MTU */
444238106Sdes	}
445238106Sdes	if(bind(s, (struct sockaddr*)addr, addrlen) != 0) {
446238106Sdes		*noproto = 0;
447269257Sdes		*inuse = 0;
448238106Sdes#ifndef USE_WINSOCK
449238106Sdes#ifdef EADDRINUSE
450238106Sdes		*inuse = (errno == EADDRINUSE);
451238106Sdes		/* detect freebsd jail with no ipv6 permission */
452238106Sdes		if(family==AF_INET6 && errno==EINVAL)
453238106Sdes			*noproto = 1;
454238106Sdes		else if(errno != EADDRINUSE) {
455285206Sdes			log_err_addr("can't bind socket", strerror(errno),
456238106Sdes				(struct sockaddr_storage*)addr, addrlen);
457238106Sdes		}
458238106Sdes#endif /* EADDRINUSE */
459238106Sdes		close(s);
460238106Sdes#else /* USE_WINSOCK */
461238106Sdes		if(WSAGetLastError() != WSAEADDRINUSE &&
462238106Sdes			WSAGetLastError() != WSAEADDRNOTAVAIL) {
463285206Sdes			log_err_addr("can't bind socket",
464285206Sdes				wsa_strerror(WSAGetLastError()),
465238106Sdes				(struct sockaddr_storage*)addr, addrlen);
466238106Sdes		}
467238106Sdes		closesocket(s);
468238106Sdes#endif
469238106Sdes		return -1;
470238106Sdes	}
471238106Sdes	if(!fd_set_nonblock(s)) {
472238106Sdes		*noproto = 0;
473238106Sdes		*inuse = 0;
474238106Sdes#ifndef USE_WINSOCK
475238106Sdes		close(s);
476238106Sdes#else
477238106Sdes		closesocket(s);
478238106Sdes#endif
479238106Sdes		return -1;
480238106Sdes	}
481238106Sdes	return s;
482238106Sdes}
483238106Sdes
484238106Sdesint
485269257Sdescreate_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
486291767Sdes	int* reuseport, int transparent)
487238106Sdes{
488238106Sdes	int s;
489291767Sdes#if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT)
490238106Sdes	int on = 1;
491291767Sdes#endif
492291767Sdes#ifndef IP_TRANSPARENT
493291767Sdes	(void)transparent;
494291767Sdes#endif
495238106Sdes	verbose_print_addr(addr);
496238106Sdes	*noproto = 0;
497238106Sdes	if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
498238106Sdes#ifndef USE_WINSOCK
499238106Sdes		if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
500238106Sdes			*noproto = 1;
501238106Sdes			return -1;
502238106Sdes		}
503238106Sdes		log_err("can't create socket: %s", strerror(errno));
504238106Sdes#else
505238106Sdes		if(WSAGetLastError() == WSAEAFNOSUPPORT ||
506238106Sdes			WSAGetLastError() == WSAEPROTONOSUPPORT) {
507238106Sdes			*noproto = 1;
508238106Sdes			return -1;
509238106Sdes		}
510238106Sdes		log_err("can't create socket: %s",
511238106Sdes			wsa_strerror(WSAGetLastError()));
512238106Sdes#endif
513238106Sdes		return -1;
514238106Sdes	}
515238106Sdes#ifdef SO_REUSEADDR
516238106Sdes	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
517238106Sdes		(socklen_t)sizeof(on)) < 0) {
518238106Sdes#ifndef USE_WINSOCK
519238106Sdes		log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
520238106Sdes			strerror(errno));
521249141Sdes		close(s);
522238106Sdes#else
523238106Sdes		log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
524238106Sdes			wsa_strerror(WSAGetLastError()));
525249141Sdes		closesocket(s);
526238106Sdes#endif
527238106Sdes		return -1;
528238106Sdes	}
529238106Sdes#endif /* SO_REUSEADDR */
530285206Sdes#ifdef SO_REUSEPORT
531285206Sdes	/* try to set SO_REUSEPORT so that incoming
532269257Sdes	 * connections are distributed evenly among the receiving threads.
533269257Sdes	 * Each thread must have its own socket bound to the same port,
534269257Sdes	 * with SO_REUSEPORT set on each socket.
535269257Sdes	 */
536269257Sdes	if (reuseport && *reuseport &&
537269257Sdes		setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
538269257Sdes		(socklen_t)sizeof(on)) < 0) {
539269257Sdes#ifdef ENOPROTOOPT
540269257Sdes		if(errno != ENOPROTOOPT || verbosity >= 3)
541269257Sdes			log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
542269257Sdes				strerror(errno));
543269257Sdes#endif
544269257Sdes		/* this option is not essential, we can continue */
545269257Sdes		*reuseport = 0;
546269257Sdes	}
547269257Sdes#else
548269257Sdes	(void)reuseport;
549285206Sdes#endif /* defined(SO_REUSEPORT) */
550238106Sdes#if defined(IPV6_V6ONLY)
551238106Sdes	if(addr->ai_family == AF_INET6 && v6only) {
552238106Sdes		if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
553238106Sdes			(void*)&on, (socklen_t)sizeof(on)) < 0) {
554238106Sdes#ifndef USE_WINSOCK
555238106Sdes			log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
556238106Sdes				strerror(errno));
557249141Sdes			close(s);
558238106Sdes#else
559238106Sdes			log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
560238106Sdes				wsa_strerror(WSAGetLastError()));
561249141Sdes			closesocket(s);
562238106Sdes#endif
563238106Sdes			return -1;
564238106Sdes		}
565238106Sdes	}
566238106Sdes#else
567238106Sdes	(void)v6only;
568238106Sdes#endif /* IPV6_V6ONLY */
569291767Sdes#ifdef IP_TRANSPARENT
570291767Sdes	if (transparent &&
571291767Sdes	    setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
572291767Sdes	    (socklen_t)sizeof(on)) < 0) {
573291767Sdes		log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s",
574291767Sdes			strerror(errno));
575291767Sdes	}
576291767Sdes#endif /* IP_TRANSPARENT */
577238106Sdes	if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) {
578238106Sdes#ifndef USE_WINSOCK
579238106Sdes		/* detect freebsd jail with no ipv6 permission */
580238106Sdes		if(addr->ai_family==AF_INET6 && errno==EINVAL)
581238106Sdes			*noproto = 1;
582238106Sdes		else {
583285206Sdes			log_err_addr("can't bind socket", strerror(errno),
584238106Sdes				(struct sockaddr_storage*)addr->ai_addr,
585238106Sdes				addr->ai_addrlen);
586238106Sdes		}
587249141Sdes		close(s);
588238106Sdes#else
589285206Sdes		log_err_addr("can't bind socket",
590285206Sdes			wsa_strerror(WSAGetLastError()),
591238106Sdes			(struct sockaddr_storage*)addr->ai_addr,
592238106Sdes			addr->ai_addrlen);
593249141Sdes		closesocket(s);
594238106Sdes#endif
595238106Sdes		return -1;
596238106Sdes	}
597238106Sdes	if(!fd_set_nonblock(s)) {
598249141Sdes#ifndef USE_WINSOCK
599249141Sdes		close(s);
600249141Sdes#else
601249141Sdes		closesocket(s);
602249141Sdes#endif
603238106Sdes		return -1;
604238106Sdes	}
605238106Sdes	if(listen(s, TCP_BACKLOG) == -1) {
606238106Sdes#ifndef USE_WINSOCK
607238106Sdes		log_err("can't listen: %s", strerror(errno));
608249141Sdes		close(s);
609238106Sdes#else
610238106Sdes		log_err("can't listen: %s", wsa_strerror(WSAGetLastError()));
611249141Sdes		closesocket(s);
612238106Sdes#endif
613238106Sdes		return -1;
614238106Sdes	}
615238106Sdes	return s;
616238106Sdes}
617238106Sdes
618285206Sdesint
619285206Sdescreate_local_accept_sock(const char *path, int* noproto)
620285206Sdes{
621285206Sdes#ifdef HAVE_SYS_UN_H
622285206Sdes	int s;
623285206Sdes	struct sockaddr_un usock;
624285206Sdes
625285206Sdes	verbose(VERB_ALGO, "creating unix socket %s", path);
626285206Sdes#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
627285206Sdes	/* this member exists on BSDs, not Linux */
628285206Sdes	usock.sun_len = (socklen_t)sizeof(usock);
629285206Sdes#endif
630285206Sdes	usock.sun_family = AF_LOCAL;
631285206Sdes	/* length is 92-108, 104 on FreeBSD */
632285206Sdes	(void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path));
633285206Sdes
634285206Sdes	if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
635285206Sdes		log_err("Cannot create local socket %s (%s)",
636285206Sdes			path, strerror(errno));
637285206Sdes		return -1;
638285206Sdes	}
639285206Sdes
640285206Sdes	if (unlink(path) && errno != ENOENT) {
641285206Sdes		/* The socket already exists and cannot be removed */
642285206Sdes		log_err("Cannot remove old local socket %s (%s)",
643285206Sdes			path, strerror(errno));
644285206Sdes		return -1;
645285206Sdes	}
646285206Sdes
647285206Sdes	if (bind(s, (struct sockaddr *)&usock,
648285206Sdes		(socklen_t)sizeof(struct sockaddr_un)) == -1) {
649285206Sdes		log_err("Cannot bind local socket %s (%s)",
650285206Sdes			path, strerror(errno));
651285206Sdes		return -1;
652285206Sdes	}
653285206Sdes
654285206Sdes	if (!fd_set_nonblock(s)) {
655285206Sdes		log_err("Cannot set non-blocking mode");
656285206Sdes		return -1;
657285206Sdes	}
658285206Sdes
659285206Sdes	if (listen(s, TCP_BACKLOG) == -1) {
660285206Sdes		log_err("can't listen: %s", strerror(errno));
661285206Sdes		return -1;
662285206Sdes	}
663285206Sdes
664285206Sdes	(void)noproto; /*unused*/
665285206Sdes	return s;
666285206Sdes#else
667285206Sdes	(void)path;
668285206Sdes	log_err("Local sockets are not supported");
669285206Sdes	*noproto = 1;
670285206Sdes	return -1;
671285206Sdes#endif
672285206Sdes}
673285206Sdes
674285206Sdes
675238106Sdes/**
676238106Sdes * Create socket from getaddrinfo results
677238106Sdes */
678238106Sdesstatic int
679238106Sdesmake_sock(int stype, const char* ifname, const char* port,
680269257Sdes	struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
681291767Sdes	int* reuseport, int transparent)
682238106Sdes{
683238106Sdes	struct addrinfo *res = NULL;
684238106Sdes	int r, s, inuse, noproto;
685238106Sdes	hints->ai_socktype = stype;
686238106Sdes	*noip6 = 0;
687238106Sdes	if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) {
688238106Sdes#ifdef USE_WINSOCK
689238106Sdes		if(r == EAI_NONAME && hints->ai_family == AF_INET6){
690238106Sdes			*noip6 = 1; /* 'Host not found' for IP6 on winXP */
691238106Sdes			return -1;
692238106Sdes		}
693238106Sdes#endif
694238106Sdes		log_err("node %s:%s getaddrinfo: %s %s",
695238106Sdes			ifname?ifname:"default", port, gai_strerror(r),
696238106Sdes#ifdef EAI_SYSTEM
697238106Sdes			r==EAI_SYSTEM?(char*)strerror(errno):""
698238106Sdes#else
699238106Sdes			""
700238106Sdes#endif
701238106Sdes		);
702238106Sdes		return -1;
703238106Sdes	}
704238106Sdes	if(stype == SOCK_DGRAM) {
705238106Sdes		verbose_print_addr(res);
706238106Sdes		s = create_udp_sock(res->ai_family, res->ai_socktype,
707238106Sdes			(struct sockaddr*)res->ai_addr, res->ai_addrlen,
708269257Sdes			v6only, &inuse, &noproto, (int)rcv, (int)snd, 1,
709291767Sdes			reuseport, transparent);
710238106Sdes		if(s == -1 && inuse) {
711238106Sdes			log_err("bind: address already in use");
712238106Sdes		} else if(s == -1 && noproto && hints->ai_family == AF_INET6){
713238106Sdes			*noip6 = 1;
714238106Sdes		}
715238106Sdes	} else	{
716291767Sdes		s = create_tcp_accept_sock(res, v6only, &noproto, reuseport,
717291767Sdes			transparent);
718238106Sdes		if(s == -1 && noproto && hints->ai_family == AF_INET6){
719238106Sdes			*noip6 = 1;
720238106Sdes		}
721238106Sdes	}
722238106Sdes	freeaddrinfo(res);
723238106Sdes	return s;
724238106Sdes}
725238106Sdes
726238106Sdes/** make socket and first see if ifname contains port override info */
727238106Sdesstatic int
728238106Sdesmake_sock_port(int stype, const char* ifname, const char* port,
729269257Sdes	struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
730291767Sdes	int* reuseport, int transparent)
731238106Sdes{
732238106Sdes	char* s = strchr(ifname, '@');
733238106Sdes	if(s) {
734238106Sdes		/* override port with ifspec@port */
735238106Sdes		char p[16];
736238106Sdes		char newif[128];
737238106Sdes		if((size_t)(s-ifname) >= sizeof(newif)) {
738238106Sdes			log_err("ifname too long: %s", ifname);
739238106Sdes			*noip6 = 0;
740238106Sdes			return -1;
741238106Sdes		}
742238106Sdes		if(strlen(s+1) >= sizeof(p)) {
743238106Sdes			log_err("portnumber too long: %s", ifname);
744238106Sdes			*noip6 = 0;
745238106Sdes			return -1;
746238106Sdes		}
747269257Sdes		(void)strlcpy(newif, ifname, sizeof(newif));
748238106Sdes		newif[s-ifname] = 0;
749269257Sdes		(void)strlcpy(p, s+1, sizeof(p));
750238106Sdes		p[strlen(s+1)]=0;
751238106Sdes		return make_sock(stype, newif, p, hints, v6only, noip6,
752291767Sdes			rcv, snd, reuseport, transparent);
753238106Sdes	}
754269257Sdes	return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd,
755291767Sdes		reuseport, transparent);
756238106Sdes}
757238106Sdes
758238106Sdes/**
759238106Sdes * Add port to open ports list.
760238106Sdes * @param list: list head. changed.
761238106Sdes * @param s: fd.
762238106Sdes * @param ftype: if fd is UDP.
763238106Sdes * @return false on failure. list in unchanged then.
764238106Sdes */
765238106Sdesstatic int
766238106Sdesport_insert(struct listen_port** list, int s, enum listen_type ftype)
767238106Sdes{
768238106Sdes	struct listen_port* item = (struct listen_port*)malloc(
769238106Sdes		sizeof(struct listen_port));
770238106Sdes	if(!item)
771238106Sdes		return 0;
772238106Sdes	item->next = *list;
773238106Sdes	item->fd = s;
774238106Sdes	item->ftype = ftype;
775238106Sdes	*list = item;
776238106Sdes	return 1;
777238106Sdes}
778238106Sdes
779238106Sdes/** set fd to receive source address packet info */
780238106Sdesstatic int
781238106Sdesset_recvpktinfo(int s, int family)
782238106Sdes{
783238106Sdes#if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)) || defined(IP_PKTINFO)
784238106Sdes	int on = 1;
785238106Sdes#else
786238106Sdes	(void)s;
787238106Sdes#endif
788238106Sdes	if(family == AF_INET6) {
789238106Sdes#           ifdef IPV6_RECVPKTINFO
790238106Sdes		if(setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
791238106Sdes			(void*)&on, (socklen_t)sizeof(on)) < 0) {
792238106Sdes			log_err("setsockopt(..., IPV6_RECVPKTINFO, ...) failed: %s",
793238106Sdes				strerror(errno));
794238106Sdes			return 0;
795238106Sdes		}
796238106Sdes#           elif defined(IPV6_PKTINFO)
797238106Sdes		if(setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO,
798238106Sdes			(void*)&on, (socklen_t)sizeof(on)) < 0) {
799238106Sdes			log_err("setsockopt(..., IPV6_PKTINFO, ...) failed: %s",
800238106Sdes				strerror(errno));
801238106Sdes			return 0;
802238106Sdes		}
803238106Sdes#           else
804238106Sdes		log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please "
805238106Sdes			"disable interface-automatic in config");
806238106Sdes		return 0;
807238106Sdes#           endif /* defined IPV6_RECVPKTINFO */
808238106Sdes
809238106Sdes	} else if(family == AF_INET) {
810238106Sdes#           ifdef IP_PKTINFO
811238106Sdes		if(setsockopt(s, IPPROTO_IP, IP_PKTINFO,
812238106Sdes			(void*)&on, (socklen_t)sizeof(on)) < 0) {
813238106Sdes			log_err("setsockopt(..., IP_PKTINFO, ...) failed: %s",
814238106Sdes				strerror(errno));
815238106Sdes			return 0;
816238106Sdes		}
817238106Sdes#           elif defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)
818238106Sdes		if(setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
819238106Sdes			(void*)&on, (socklen_t)sizeof(on)) < 0) {
820238106Sdes			log_err("setsockopt(..., IP_RECVDSTADDR, ...) failed: %s",
821238106Sdes				strerror(errno));
822238106Sdes			return 0;
823238106Sdes		}
824238106Sdes#           else
825238106Sdes		log_err("no IP_SENDSRCADDR or IP_PKTINFO option, please disable "
826238106Sdes			"interface-automatic in config");
827238106Sdes		return 0;
828238106Sdes#           endif /* IP_PKTINFO */
829238106Sdes
830238106Sdes	}
831238106Sdes	return 1;
832238106Sdes}
833238106Sdes
834238106Sdes/**
835238106Sdes * Helper for ports_open. Creates one interface (or NULL for default).
836238106Sdes * @param ifname: The interface ip address.
837238106Sdes * @param do_auto: use automatic interface detection.
838238106Sdes * 	If enabled, then ifname must be the wildcard name.
839238106Sdes * @param do_udp: if udp should be used.
840238106Sdes * @param do_tcp: if udp should be used.
841238106Sdes * @param hints: for getaddrinfo. family and flags have to be set by caller.
842238106Sdes * @param port: Port number to use (as string).
843238106Sdes * @param list: list of open ports, appended to, changed to point to list head.
844238106Sdes * @param rcv: receive buffer size for UDP
845238106Sdes * @param snd: send buffer size for UDP
846238106Sdes * @param ssl_port: ssl service port number
847269257Sdes * @param reuseport: try to set SO_REUSEPORT if nonNULL and true.
848269257Sdes * 	set to false on exit if reuseport failed due to no kernel support.
849291767Sdes * @param transparent: set IP_TRANSPARENT socket option.
850238106Sdes * @return: returns false on error.
851238106Sdes */
852238106Sdesstatic int
853238106Sdesports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
854238106Sdes	struct addrinfo *hints, const char* port, struct listen_port** list,
855291767Sdes	size_t rcv, size_t snd, int ssl_port, int* reuseport, int transparent)
856238106Sdes{
857238106Sdes	int s, noip6=0;
858238106Sdes	if(!do_udp && !do_tcp)
859238106Sdes		return 0;
860238106Sdes	if(do_auto) {
861238106Sdes		if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
862291767Sdes			&noip6, rcv, snd, reuseport, transparent)) == -1) {
863238106Sdes			if(noip6) {
864238106Sdes				log_warn("IPv6 protocol not available");
865238106Sdes				return 1;
866238106Sdes			}
867238106Sdes			return 0;
868238106Sdes		}
869238106Sdes		/* getting source addr packet info is highly non-portable */
870249141Sdes		if(!set_recvpktinfo(s, hints->ai_family)) {
871249141Sdes#ifndef USE_WINSOCK
872249141Sdes			close(s);
873249141Sdes#else
874249141Sdes			closesocket(s);
875249141Sdes#endif
876238106Sdes			return 0;
877249141Sdes		}
878238106Sdes		if(!port_insert(list, s, listen_type_udpancil)) {
879238106Sdes#ifndef USE_WINSOCK
880238106Sdes			close(s);
881238106Sdes#else
882238106Sdes			closesocket(s);
883238106Sdes#endif
884238106Sdes			return 0;
885238106Sdes		}
886238106Sdes	} else if(do_udp) {
887238106Sdes		/* regular udp socket */
888238106Sdes		if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
889291767Sdes			&noip6, rcv, snd, reuseport, transparent)) == -1) {
890238106Sdes			if(noip6) {
891238106Sdes				log_warn("IPv6 protocol not available");
892238106Sdes				return 1;
893238106Sdes			}
894238106Sdes			return 0;
895238106Sdes		}
896238106Sdes		if(!port_insert(list, s, listen_type_udp)) {
897238106Sdes#ifndef USE_WINSOCK
898238106Sdes			close(s);
899238106Sdes#else
900238106Sdes			closesocket(s);
901238106Sdes#endif
902238106Sdes			return 0;
903238106Sdes		}
904238106Sdes	}
905238106Sdes	if(do_tcp) {
906238106Sdes		int is_ssl = ((strchr(ifname, '@') &&
907238106Sdes			atoi(strchr(ifname, '@')+1) == ssl_port) ||
908238106Sdes			(!strchr(ifname, '@') && atoi(port) == ssl_port));
909238106Sdes		if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
910291767Sdes			&noip6, 0, 0, reuseport, transparent)) == -1) {
911238106Sdes			if(noip6) {
912238106Sdes				/*log_warn("IPv6 protocol not available");*/
913238106Sdes				return 1;
914238106Sdes			}
915238106Sdes			return 0;
916238106Sdes		}
917238106Sdes		if(is_ssl)
918238106Sdes			verbose(VERB_ALGO, "setup TCP for SSL service");
919238106Sdes		if(!port_insert(list, s, is_ssl?listen_type_ssl:
920238106Sdes			listen_type_tcp)) {
921238106Sdes#ifndef USE_WINSOCK
922238106Sdes			close(s);
923238106Sdes#else
924238106Sdes			closesocket(s);
925238106Sdes#endif
926238106Sdes			return 0;
927238106Sdes		}
928238106Sdes	}
929238106Sdes	return 1;
930238106Sdes}
931238106Sdes
932238106Sdes/**
933238106Sdes * Add items to commpoint list in front.
934238106Sdes * @param c: commpoint to add.
935238106Sdes * @param front: listen struct.
936238106Sdes * @return: false on failure.
937238106Sdes */
938238106Sdesstatic int
939238106Sdeslisten_cp_insert(struct comm_point* c, struct listen_dnsport* front)
940238106Sdes{
941238106Sdes	struct listen_list* item = (struct listen_list*)malloc(
942238106Sdes		sizeof(struct listen_list));
943238106Sdes	if(!item)
944238106Sdes		return 0;
945238106Sdes	item->com = c;
946238106Sdes	item->next = front->cps;
947238106Sdes	front->cps = item;
948238106Sdes	return 1;
949238106Sdes}
950238106Sdes
951238106Sdesstruct listen_dnsport*
952238106Sdeslisten_create(struct comm_base* base, struct listen_port* ports,
953238106Sdes	size_t bufsize, int tcp_accept_count, void* sslctx,
954285206Sdes	struct dt_env* dtenv, comm_point_callback_t* cb, void *cb_arg)
955238106Sdes{
956238106Sdes	struct listen_dnsport* front = (struct listen_dnsport*)
957238106Sdes		malloc(sizeof(struct listen_dnsport));
958238106Sdes	if(!front)
959238106Sdes		return NULL;
960238106Sdes	front->cps = NULL;
961269257Sdes	front->udp_buff = sldns_buffer_new(bufsize);
962238106Sdes	if(!front->udp_buff) {
963238106Sdes		free(front);
964238106Sdes		return NULL;
965238106Sdes	}
966238106Sdes
967238106Sdes	/* create comm points as needed */
968238106Sdes	while(ports) {
969238106Sdes		struct comm_point* cp = NULL;
970238106Sdes		if(ports->ftype == listen_type_udp)
971238106Sdes			cp = comm_point_create_udp(base, ports->fd,
972238106Sdes				front->udp_buff, cb, cb_arg);
973238106Sdes		else if(ports->ftype == listen_type_tcp)
974238106Sdes			cp = comm_point_create_tcp(base, ports->fd,
975238106Sdes				tcp_accept_count, bufsize, cb, cb_arg);
976238106Sdes		else if(ports->ftype == listen_type_ssl) {
977238106Sdes			cp = comm_point_create_tcp(base, ports->fd,
978238106Sdes				tcp_accept_count, bufsize, cb, cb_arg);
979238106Sdes			cp->ssl = sslctx;
980238106Sdes		} else if(ports->ftype == listen_type_udpancil)
981238106Sdes			cp = comm_point_create_udp_ancil(base, ports->fd,
982238106Sdes				front->udp_buff, cb, cb_arg);
983238106Sdes		if(!cp) {
984238106Sdes			log_err("can't create commpoint");
985238106Sdes			listen_delete(front);
986238106Sdes			return NULL;
987238106Sdes		}
988285206Sdes		cp->dtenv = dtenv;
989238106Sdes		cp->do_not_close = 1;
990238106Sdes		if(!listen_cp_insert(cp, front)) {
991238106Sdes			log_err("malloc failed");
992238106Sdes			comm_point_delete(cp);
993238106Sdes			listen_delete(front);
994238106Sdes			return NULL;
995238106Sdes		}
996238106Sdes		ports = ports->next;
997238106Sdes	}
998238106Sdes	if(!front->cps) {
999238106Sdes		log_err("Could not open sockets to accept queries.");
1000238106Sdes		listen_delete(front);
1001238106Sdes		return NULL;
1002238106Sdes	}
1003238106Sdes
1004238106Sdes	return front;
1005238106Sdes}
1006238106Sdes
1007238106Sdesvoid
1008238106Sdeslisten_list_delete(struct listen_list* list)
1009238106Sdes{
1010238106Sdes	struct listen_list *p = list, *pn;
1011238106Sdes	while(p) {
1012238106Sdes		pn = p->next;
1013238106Sdes		comm_point_delete(p->com);
1014238106Sdes		free(p);
1015238106Sdes		p = pn;
1016238106Sdes	}
1017238106Sdes}
1018238106Sdes
1019238106Sdesvoid
1020238106Sdeslisten_delete(struct listen_dnsport* front)
1021238106Sdes{
1022238106Sdes	if(!front)
1023238106Sdes		return;
1024238106Sdes	listen_list_delete(front->cps);
1025269257Sdes	sldns_buffer_free(front->udp_buff);
1026238106Sdes	free(front);
1027238106Sdes}
1028238106Sdes
1029238106Sdesstruct listen_port*
1030269257Sdeslistening_ports_open(struct config_file* cfg, int* reuseport)
1031238106Sdes{
1032238106Sdes	struct listen_port* list = NULL;
1033238106Sdes	struct addrinfo hints;
1034238106Sdes	int i, do_ip4, do_ip6;
1035238106Sdes	int do_tcp, do_auto;
1036238106Sdes	char portbuf[32];
1037238106Sdes	snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
1038238106Sdes	do_ip4 = cfg->do_ip4;
1039238106Sdes	do_ip6 = cfg->do_ip6;
1040238106Sdes	do_tcp = cfg->do_tcp;
1041238106Sdes	do_auto = cfg->if_automatic && cfg->do_udp;
1042238106Sdes	if(cfg->incoming_num_tcp == 0)
1043238106Sdes		do_tcp = 0;
1044238106Sdes
1045238106Sdes	/* getaddrinfo */
1046238106Sdes	memset(&hints, 0, sizeof(hints));
1047238106Sdes	hints.ai_flags = AI_PASSIVE;
1048238106Sdes	/* no name lookups on our listening ports */
1049238106Sdes	if(cfg->num_ifs > 0)
1050238106Sdes		hints.ai_flags |= AI_NUMERICHOST;
1051238106Sdes	hints.ai_family = AF_UNSPEC;
1052238106Sdes#ifndef INET6
1053238106Sdes	do_ip6 = 0;
1054238106Sdes#endif
1055238106Sdes	if(!do_ip4 && !do_ip6) {
1056238106Sdes		return NULL;
1057238106Sdes	}
1058238106Sdes	/* create ip4 and ip6 ports so that return addresses are nice. */
1059238106Sdes	if(do_auto || cfg->num_ifs == 0) {
1060238106Sdes		if(do_ip6) {
1061238106Sdes			hints.ai_family = AF_INET6;
1062238106Sdes			if(!ports_create_if(do_auto?"::0":"::1",
1063238106Sdes				do_auto, cfg->do_udp, do_tcp,
1064238106Sdes				&hints, portbuf, &list,
1065238106Sdes				cfg->so_rcvbuf, cfg->so_sndbuf,
1066291767Sdes				cfg->ssl_port, reuseport,
1067291767Sdes				cfg->ip_transparent)) {
1068238106Sdes				listening_ports_free(list);
1069238106Sdes				return NULL;
1070238106Sdes			}
1071238106Sdes		}
1072238106Sdes		if(do_ip4) {
1073238106Sdes			hints.ai_family = AF_INET;
1074238106Sdes			if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
1075238106Sdes				do_auto, cfg->do_udp, do_tcp,
1076238106Sdes				&hints, portbuf, &list,
1077238106Sdes				cfg->so_rcvbuf, cfg->so_sndbuf,
1078291767Sdes				cfg->ssl_port, reuseport,
1079291767Sdes				cfg->ip_transparent)) {
1080238106Sdes				listening_ports_free(list);
1081238106Sdes				return NULL;
1082238106Sdes			}
1083238106Sdes		}
1084238106Sdes	} else for(i = 0; i<cfg->num_ifs; i++) {
1085238106Sdes		if(str_is_ip6(cfg->ifs[i])) {
1086238106Sdes			if(!do_ip6)
1087238106Sdes				continue;
1088238106Sdes			hints.ai_family = AF_INET6;
1089238106Sdes			if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
1090238106Sdes				do_tcp, &hints, portbuf, &list,
1091238106Sdes				cfg->so_rcvbuf, cfg->so_sndbuf,
1092291767Sdes				cfg->ssl_port, reuseport,
1093291767Sdes				cfg->ip_transparent)) {
1094238106Sdes				listening_ports_free(list);
1095238106Sdes				return NULL;
1096238106Sdes			}
1097238106Sdes		} else {
1098238106Sdes			if(!do_ip4)
1099238106Sdes				continue;
1100238106Sdes			hints.ai_family = AF_INET;
1101238106Sdes			if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
1102238106Sdes				do_tcp, &hints, portbuf, &list,
1103238106Sdes				cfg->so_rcvbuf, cfg->so_sndbuf,
1104291767Sdes				cfg->ssl_port, reuseport,
1105291767Sdes				cfg->ip_transparent)) {
1106238106Sdes				listening_ports_free(list);
1107238106Sdes				return NULL;
1108238106Sdes			}
1109238106Sdes		}
1110238106Sdes	}
1111238106Sdes	return list;
1112238106Sdes}
1113238106Sdes
1114238106Sdesvoid listening_ports_free(struct listen_port* list)
1115238106Sdes{
1116238106Sdes	struct listen_port* nx;
1117238106Sdes	while(list) {
1118238106Sdes		nx = list->next;
1119238106Sdes		if(list->fd != -1) {
1120238106Sdes#ifndef USE_WINSOCK
1121238106Sdes			close(list->fd);
1122238106Sdes#else
1123238106Sdes			closesocket(list->fd);
1124238106Sdes#endif
1125238106Sdes		}
1126238106Sdes		free(list);
1127238106Sdes		list = nx;
1128238106Sdes	}
1129238106Sdes}
1130238106Sdes
1131238106Sdessize_t listen_get_mem(struct listen_dnsport* listen)
1132238106Sdes{
1133238106Sdes	size_t s = sizeof(*listen) + sizeof(*listen->base) +
1134238106Sdes		sizeof(*listen->udp_buff) +
1135269257Sdes		sldns_buffer_capacity(listen->udp_buff);
1136238106Sdes	struct listen_list* p;
1137238106Sdes	for(p = listen->cps; p; p = p->next) {
1138238106Sdes		s += sizeof(*p);
1139238106Sdes		s += comm_point_get_mem(p->com);
1140238106Sdes	}
1141238106Sdes	return s;
1142238106Sdes}
1143238106Sdes
1144238106Sdesvoid listen_stop_accept(struct listen_dnsport* listen)
1145238106Sdes{
1146238106Sdes	/* do not stop the ones that have no tcp_free list
1147238106Sdes	 * (they have already stopped listening) */
1148238106Sdes	struct listen_list* p;
1149238106Sdes	for(p=listen->cps; p; p=p->next) {
1150238106Sdes		if(p->com->type == comm_tcp_accept &&
1151238106Sdes			p->com->tcp_free != NULL) {
1152238106Sdes			comm_point_stop_listening(p->com);
1153238106Sdes		}
1154238106Sdes	}
1155238106Sdes}
1156238106Sdes
1157238106Sdesvoid listen_start_accept(struct listen_dnsport* listen)
1158238106Sdes{
1159238106Sdes	/* do not start the ones that have no tcp_free list, it is no
1160238106Sdes	 * use to listen to them because they have no free tcp handlers */
1161238106Sdes	struct listen_list* p;
1162238106Sdes	for(p=listen->cps; p; p=p->next) {
1163238106Sdes		if(p->com->type == comm_tcp_accept &&
1164238106Sdes			p->com->tcp_free != NULL) {
1165238106Sdes			comm_point_start_listening(p->com, -1, -1);
1166238106Sdes		}
1167238106Sdes	}
1168238106Sdes}
1169238106Sdes
1170