]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/unbound/services/listen_dnsport.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 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  */
65 static void
66 verbose_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
91 int
92 create_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
388 int
389 create_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  */
495 static int
496 make_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 */
541 static int
542 make_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  */
577 static int
578 port_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 */
592 static int
593 set_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  */
661 static int
662 ports_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  */
747 static int
748 listen_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
760 struct listen_dnsport* 
761 listen_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
815 void
816 listen_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
827 void 
828 listen_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
837 struct listen_port* 
838 listening_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
918 void 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
935 size_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
948 void 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
961 void 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