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