2 * services/listen_dnsport.c - listen on port 53 for incoming DNS queries.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
39 * This file has functions to get queries from clients.
42 #ifdef HAVE_SYS_TYPES_H
43 # include <sys/types.h>
46 #include "services/listen_dnsport.h"
47 #include "services/outside_network.h"
48 #include "util/netevent.h"
50 #include "util/config_file.h"
51 #include "util/net_help.h"
52 #include "sldns/sbuffer.h"
63 /** number of queued TCP connections for listen() */
64 #define TCP_BACKLOG 256
67 * Debug print of the getaddrinfo returned address.
68 * @param addr: the address returned.
71 verbose_print_addr(struct addrinfo *addr)
73 if(verbosity >= VERB_ALGO) {
75 void* sinaddr = &((struct sockaddr_in*)addr->ai_addr)->sin_addr;
77 if(addr->ai_family == AF_INET6)
78 sinaddr = &((struct sockaddr_in6*)addr->ai_addr)->
81 if(inet_ntop(addr->ai_family, sinaddr, buf,
82 (socklen_t)sizeof(buf)) == 0) {
83 (void)strlcpy(buf, "(null)", sizeof(buf));
85 buf[sizeof(buf)-1] = 0;
86 verbose(VERB_ALGO, "creating %s%s socket %s %d",
87 addr->ai_socktype==SOCK_DGRAM?"udp":
88 addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto",
89 addr->ai_family==AF_INET?"4":
90 addr->ai_family==AF_INET6?"6":
92 ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port));
97 create_udp_sock(int family, int socktype, struct sockaddr* addr,
98 socklen_t addrlen, int v6only, int* inuse, int* noproto,
99 int rcv, int snd, int listen, int* reuseport, int transparent)
102 #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) || defined(IP_TRANSPARENT)
106 int mtu = IPV6_MIN_MTU;
108 #if !defined(SO_RCVBUFFORCE) && !defined(SO_RCVBUF)
111 #if !defined(SO_SNDBUFFORCE) && !defined(SO_SNDBUF)
117 #ifndef IP_TRANSPARENT
120 if((s = socket(family, socktype, 0)) == -1) {
123 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
127 log_err("can't create socket: %s", strerror(errno));
129 if(WSAGetLastError() == WSAEAFNOSUPPORT ||
130 WSAGetLastError() == WSAEPROTONOSUPPORT) {
134 log_err("can't create socket: %s",
135 wsa_strerror(WSAGetLastError()));
142 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
143 (socklen_t)sizeof(on)) < 0) {
145 log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
147 if(errno != ENOSYS) {
154 log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
155 wsa_strerror(WSAGetLastError()));
162 #endif /* SO_REUSEADDR */
164 /* try to set SO_REUSEPORT so that incoming
165 * queries are distributed evenly among the receiving threads.
166 * Each thread must have its own socket bound to the same port,
167 * with SO_REUSEPORT set on each socket.
169 if (reuseport && *reuseport &&
170 setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
171 (socklen_t)sizeof(on)) < 0) {
173 if(errno != ENOPROTOOPT || verbosity >= 3)
174 log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
177 /* this option is not essential, we can continue */
182 #endif /* defined(SO_REUSEPORT) */
183 #ifdef IP_TRANSPARENT
185 setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
186 (socklen_t)sizeof(on)) < 0) {
187 log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s",
190 #endif /* IP_TRANSPARENT */
195 socklen_t slen = (socklen_t)sizeof(got);
196 # ifdef SO_RCVBUFFORCE
197 /* Linux specific: try to use root permission to override
198 * system limits on rcvbuf. The limit is stored in
199 * /proc/sys/net/core/rmem_max or sysctl net.core.rmem_max */
200 if(setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, (void*)&rcv,
201 (socklen_t)sizeof(rcv)) < 0) {
204 log_err("setsockopt(..., SO_RCVBUFFORCE, "
205 "...) failed: %s", strerror(errno));
208 log_err("setsockopt(..., SO_RCVBUFFORCE, "
210 wsa_strerror(WSAGetLastError()));
217 # endif /* SO_RCVBUFFORCE */
218 if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&rcv,
219 (socklen_t)sizeof(rcv)) < 0) {
221 log_err("setsockopt(..., SO_RCVBUF, "
222 "...) failed: %s", strerror(errno));
225 log_err("setsockopt(..., SO_RCVBUF, "
227 wsa_strerror(WSAGetLastError()));
234 /* check if we got the right thing or if system
235 * reduced to some system max. Warn if so */
236 if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, (void*)&got,
237 &slen) >= 0 && got < rcv/2) {
238 log_warn("so-rcvbuf %u was not granted. "
239 "Got %u. To fix: start with "
240 "root permissions(linux) or sysctl "
241 "bigger net.core.rmem_max(linux) or "
242 "kern.ipc.maxsockbuf(bsd) values.",
243 (unsigned)rcv, (unsigned)got);
245 # ifdef SO_RCVBUFFORCE
248 #endif /* SO_RCVBUF */
250 /* first do RCVBUF as the receive buffer is more important */
254 socklen_t slen = (socklen_t)sizeof(got);
255 # ifdef SO_SNDBUFFORCE
256 /* Linux specific: try to use root permission to override
257 * system limits on sndbuf. The limit is stored in
258 * /proc/sys/net/core/wmem_max or sysctl net.core.wmem_max */
259 if(setsockopt(s, SOL_SOCKET, SO_SNDBUFFORCE, (void*)&snd,
260 (socklen_t)sizeof(snd)) < 0) {
263 log_err("setsockopt(..., SO_SNDBUFFORCE, "
264 "...) failed: %s", strerror(errno));
267 log_err("setsockopt(..., SO_SNDBUFFORCE, "
269 wsa_strerror(WSAGetLastError()));
276 # endif /* SO_SNDBUFFORCE */
277 if(setsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&snd,
278 (socklen_t)sizeof(snd)) < 0) {
280 log_err("setsockopt(..., SO_SNDBUF, "
281 "...) failed: %s", strerror(errno));
284 log_err("setsockopt(..., SO_SNDBUF, "
286 wsa_strerror(WSAGetLastError()));
293 /* check if we got the right thing or if system
294 * reduced to some system max. Warn if so */
295 if(getsockopt(s, SOL_SOCKET, SO_SNDBUF, (void*)&got,
296 &slen) >= 0 && got < snd/2) {
297 log_warn("so-sndbuf %u was not granted. "
298 "Got %u. To fix: start with "
299 "root permissions(linux) or sysctl "
300 "bigger net.core.wmem_max(linux) or "
301 "kern.ipc.maxsockbuf(bsd) values.",
302 (unsigned)snd, (unsigned)got);
304 # ifdef SO_SNDBUFFORCE
307 #endif /* SO_SNDBUF */
309 if(family == AF_INET6) {
310 # if defined(IPV6_V6ONLY)
312 int val=(v6only==2)?0:1;
313 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
314 (void*)&val, (socklen_t)sizeof(val)) < 0) {
316 log_err("setsockopt(..., IPV6_V6ONLY"
317 ", ...) failed: %s", strerror(errno));
320 log_err("setsockopt(..., IPV6_V6ONLY"
322 wsa_strerror(WSAGetLastError()));
331 # if defined(IPV6_USE_MIN_MTU)
333 * There is no fragmentation of IPv6 datagrams
334 * during forwarding in the network. Therefore
335 * we do not send UDP datagrams larger than
336 * the minimum IPv6 MTU of 1280 octets. The
337 * EDNS0 message length can be larger if the
338 * network stack supports IPV6_USE_MIN_MTU.
340 if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
341 (void*)&on, (socklen_t)sizeof(on)) < 0) {
343 log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
344 "...) failed: %s", strerror(errno));
347 log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
349 wsa_strerror(WSAGetLastError()));
356 # elif defined(IPV6_MTU)
358 * On Linux, to send no larger than 1280, the PMTUD is
359 * disabled by default for datagrams anyway, so we set
362 if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU,
363 (void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
365 log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
369 log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
370 wsa_strerror(WSAGetLastError()));
377 # endif /* IPv6 MTU */
378 } else if(family == AF_INET) {
379 # if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
380 /* linux 3.15 has IP_PMTUDISC_OMIT, Hannes Frederic Sowa made it so that
381 * PMTU information is not accepted, but fragmentation is allowed
382 * if and only if the packet size exceeds the outgoing interface MTU
383 * (and also uses the interface mtu to determine the size of the packets).
384 * So there won't be any EMSGSIZE error. Against DNS fragmentation attacks.
385 * FreeBSD already has same semantics without setting the option. */
388 # if defined(IP_PMTUDISC_OMIT)
389 action = IP_PMTUDISC_OMIT;
390 if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
391 &action, (socklen_t)sizeof(action)) < 0) {
393 if (errno != EINVAL) {
394 log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_OMIT...) failed: %s",
413 action = IP_PMTUDISC_DONT;
414 if (setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER,
415 &action, (socklen_t)sizeof(action)) < 0) {
416 log_err("setsockopt(..., IP_MTU_DISCOVER, IP_PMTUDISC_DONT...) failed: %s",
428 # elif defined(IP_DONTFRAG)
430 if (setsockopt(s, IPPROTO_IP, IP_DONTFRAG,
431 &off, (socklen_t)sizeof(off)) < 0) {
432 log_err("setsockopt(..., IP_DONTFRAG, ...) failed: %s",
443 # endif /* IPv4 MTU */
445 if(bind(s, (struct sockaddr*)addr, addrlen) != 0) {
450 *inuse = (errno == EADDRINUSE);
451 /* detect freebsd jail with no ipv6 permission */
452 if(family==AF_INET6 && errno==EINVAL)
454 else if(errno != EADDRINUSE) {
455 log_err_addr("can't bind socket", strerror(errno),
456 (struct sockaddr_storage*)addr, addrlen);
458 #endif /* EADDRINUSE */
460 #else /* USE_WINSOCK */
461 if(WSAGetLastError() != WSAEADDRINUSE &&
462 WSAGetLastError() != WSAEADDRNOTAVAIL) {
463 log_err_addr("can't bind socket",
464 wsa_strerror(WSAGetLastError()),
465 (struct sockaddr_storage*)addr, addrlen);
471 if(!fd_set_nonblock(s)) {
485 create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
486 int* reuseport, int transparent)
489 #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT)
492 #ifndef IP_TRANSPARENT
495 verbose_print_addr(addr);
497 if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
499 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
503 log_err("can't create socket: %s", strerror(errno));
505 if(WSAGetLastError() == WSAEAFNOSUPPORT ||
506 WSAGetLastError() == WSAEPROTONOSUPPORT) {
510 log_err("can't create socket: %s",
511 wsa_strerror(WSAGetLastError()));
516 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*)&on,
517 (socklen_t)sizeof(on)) < 0) {
519 log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
523 log_err("setsockopt(.. SO_REUSEADDR ..) failed: %s",
524 wsa_strerror(WSAGetLastError()));
529 #endif /* SO_REUSEADDR */
531 /* try to set SO_REUSEPORT so that incoming
532 * connections are distributed evenly among the receiving threads.
533 * Each thread must have its own socket bound to the same port,
534 * with SO_REUSEPORT set on each socket.
536 if (reuseport && *reuseport &&
537 setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void*)&on,
538 (socklen_t)sizeof(on)) < 0) {
540 if(errno != ENOPROTOOPT || verbosity >= 3)
541 log_warn("setsockopt(.. SO_REUSEPORT ..) failed: %s",
544 /* this option is not essential, we can continue */
549 #endif /* defined(SO_REUSEPORT) */
550 #if defined(IPV6_V6ONLY)
551 if(addr->ai_family == AF_INET6 && v6only) {
552 if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
553 (void*)&on, (socklen_t)sizeof(on)) < 0) {
555 log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
559 log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
560 wsa_strerror(WSAGetLastError()));
568 #endif /* IPV6_V6ONLY */
569 #ifdef IP_TRANSPARENT
571 setsockopt(s, IPPROTO_IP, IP_TRANSPARENT, (void*)&on,
572 (socklen_t)sizeof(on)) < 0) {
573 log_warn("setsockopt(.. IP_TRANSPARENT ..) failed: %s",
576 #endif /* IP_TRANSPARENT */
577 if(bind(s, addr->ai_addr, addr->ai_addrlen) != 0) {
579 /* detect freebsd jail with no ipv6 permission */
580 if(addr->ai_family==AF_INET6 && errno==EINVAL)
583 log_err_addr("can't bind socket", strerror(errno),
584 (struct sockaddr_storage*)addr->ai_addr,
589 log_err_addr("can't bind socket",
590 wsa_strerror(WSAGetLastError()),
591 (struct sockaddr_storage*)addr->ai_addr,
597 if(!fd_set_nonblock(s)) {
605 if(listen(s, TCP_BACKLOG) == -1) {
607 log_err("can't listen: %s", strerror(errno));
610 log_err("can't listen: %s", wsa_strerror(WSAGetLastError()));
619 create_local_accept_sock(const char *path, int* noproto)
623 struct sockaddr_un usock;
625 verbose(VERB_ALGO, "creating unix socket %s", path);
626 #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
627 /* this member exists on BSDs, not Linux */
628 usock.sun_len = (socklen_t)sizeof(usock);
630 usock.sun_family = AF_LOCAL;
631 /* length is 92-108, 104 on FreeBSD */
632 (void)strlcpy(usock.sun_path, path, sizeof(usock.sun_path));
634 if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) {
635 log_err("Cannot create local socket %s (%s)",
636 path, strerror(errno));
640 if (unlink(path) && errno != ENOENT) {
641 /* The socket already exists and cannot be removed */
642 log_err("Cannot remove old local socket %s (%s)",
643 path, strerror(errno));
647 if (bind(s, (struct sockaddr *)&usock,
648 (socklen_t)sizeof(struct sockaddr_un)) == -1) {
649 log_err("Cannot bind local socket %s (%s)",
650 path, strerror(errno));
654 if (!fd_set_nonblock(s)) {
655 log_err("Cannot set non-blocking mode");
659 if (listen(s, TCP_BACKLOG) == -1) {
660 log_err("can't listen: %s", strerror(errno));
664 (void)noproto; /*unused*/
668 log_err("Local sockets are not supported");
676 * Create socket from getaddrinfo results
679 make_sock(int stype, const char* ifname, const char* port,
680 struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
681 int* reuseport, int transparent)
683 struct addrinfo *res = NULL;
684 int r, s, inuse, noproto;
685 hints->ai_socktype = stype;
687 if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) {
689 if(r == EAI_NONAME && hints->ai_family == AF_INET6){
690 *noip6 = 1; /* 'Host not found' for IP6 on winXP */
694 log_err("node %s:%s getaddrinfo: %s %s",
695 ifname?ifname:"default", port, gai_strerror(r),
697 r==EAI_SYSTEM?(char*)strerror(errno):""
704 if(stype == SOCK_DGRAM) {
705 verbose_print_addr(res);
706 s = create_udp_sock(res->ai_family, res->ai_socktype,
707 (struct sockaddr*)res->ai_addr, res->ai_addrlen,
708 v6only, &inuse, &noproto, (int)rcv, (int)snd, 1,
709 reuseport, transparent);
710 if(s == -1 && inuse) {
711 log_err("bind: address already in use");
712 } else if(s == -1 && noproto && hints->ai_family == AF_INET6){
716 s = create_tcp_accept_sock(res, v6only, &noproto, reuseport,
718 if(s == -1 && noproto && hints->ai_family == AF_INET6){
726 /** make socket and first see if ifname contains port override info */
728 make_sock_port(int stype, const char* ifname, const char* port,
729 struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd,
730 int* reuseport, int transparent)
732 char* s = strchr(ifname, '@');
734 /* override port with ifspec@port */
737 if((size_t)(s-ifname) >= sizeof(newif)) {
738 log_err("ifname too long: %s", ifname);
742 if(strlen(s+1) >= sizeof(p)) {
743 log_err("portnumber too long: %s", ifname);
747 (void)strlcpy(newif, ifname, sizeof(newif));
749 (void)strlcpy(p, s+1, sizeof(p));
751 return make_sock(stype, newif, p, hints, v6only, noip6,
752 rcv, snd, reuseport, transparent);
754 return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd,
755 reuseport, transparent);
759 * Add port to open ports list.
760 * @param list: list head. changed.
762 * @param ftype: if fd is UDP.
763 * @return false on failure. list in unchanged then.
766 port_insert(struct listen_port** list, int s, enum listen_type ftype)
768 struct listen_port* item = (struct listen_port*)malloc(
769 sizeof(struct listen_port));
779 /** set fd to receive source address packet info */
781 set_recvpktinfo(int s, int family)
783 #if defined(IPV6_RECVPKTINFO) || defined(IPV6_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)) || defined(IP_PKTINFO)
788 if(family == AF_INET6) {
789 # ifdef IPV6_RECVPKTINFO
790 if(setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO,
791 (void*)&on, (socklen_t)sizeof(on)) < 0) {
792 log_err("setsockopt(..., IPV6_RECVPKTINFO, ...) failed: %s",
796 # elif defined(IPV6_PKTINFO)
797 if(setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO,
798 (void*)&on, (socklen_t)sizeof(on)) < 0) {
799 log_err("setsockopt(..., IPV6_PKTINFO, ...) failed: %s",
804 log_err("no IPV6_RECVPKTINFO and no IPV6_PKTINFO option, please "
805 "disable interface-automatic in config");
807 # endif /* defined IPV6_RECVPKTINFO */
809 } else if(family == AF_INET) {
811 if(setsockopt(s, IPPROTO_IP, IP_PKTINFO,
812 (void*)&on, (socklen_t)sizeof(on)) < 0) {
813 log_err("setsockopt(..., IP_PKTINFO, ...) failed: %s",
817 # elif defined(IP_RECVDSTADDR) && defined(IP_SENDSRCADDR)
818 if(setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR,
819 (void*)&on, (socklen_t)sizeof(on)) < 0) {
820 log_err("setsockopt(..., IP_RECVDSTADDR, ...) failed: %s",
825 log_err("no IP_SENDSRCADDR or IP_PKTINFO option, please disable "
826 "interface-automatic in config");
828 # endif /* IP_PKTINFO */
835 * Helper for ports_open. Creates one interface (or NULL for default).
836 * @param ifname: The interface ip address.
837 * @param do_auto: use automatic interface detection.
838 * If enabled, then ifname must be the wildcard name.
839 * @param do_udp: if udp should be used.
840 * @param do_tcp: if udp should be used.
841 * @param hints: for getaddrinfo. family and flags have to be set by caller.
842 * @param port: Port number to use (as string).
843 * @param list: list of open ports, appended to, changed to point to list head.
844 * @param rcv: receive buffer size for UDP
845 * @param snd: send buffer size for UDP
846 * @param ssl_port: ssl service port number
847 * @param reuseport: try to set SO_REUSEPORT if nonNULL and true.
848 * set to false on exit if reuseport failed due to no kernel support.
849 * @param transparent: set IP_TRANSPARENT socket option.
850 * @return: returns false on error.
853 ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
854 struct addrinfo *hints, const char* port, struct listen_port** list,
855 size_t rcv, size_t snd, int ssl_port, int* reuseport, int transparent)
858 if(!do_udp && !do_tcp)
861 if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
862 &noip6, rcv, snd, reuseport, transparent)) == -1) {
864 log_warn("IPv6 protocol not available");
869 /* getting source addr packet info is highly non-portable */
870 if(!set_recvpktinfo(s, hints->ai_family)) {
878 if(!port_insert(list, s, listen_type_udpancil)) {
887 /* regular udp socket */
888 if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
889 &noip6, rcv, snd, reuseport, transparent)) == -1) {
891 log_warn("IPv6 protocol not available");
896 if(!port_insert(list, s, listen_type_udp)) {
906 int is_ssl = ((strchr(ifname, '@') &&
907 atoi(strchr(ifname, '@')+1) == ssl_port) ||
908 (!strchr(ifname, '@') && atoi(port) == ssl_port));
909 if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
910 &noip6, 0, 0, reuseport, transparent)) == -1) {
912 /*log_warn("IPv6 protocol not available");*/
918 verbose(VERB_ALGO, "setup TCP for SSL service");
919 if(!port_insert(list, s, is_ssl?listen_type_ssl:
933 * Add items to commpoint list in front.
934 * @param c: commpoint to add.
935 * @param front: listen struct.
936 * @return: false on failure.
939 listen_cp_insert(struct comm_point* c, struct listen_dnsport* front)
941 struct listen_list* item = (struct listen_list*)malloc(
942 sizeof(struct listen_list));
946 item->next = front->cps;
951 struct listen_dnsport*
952 listen_create(struct comm_base* base, struct listen_port* ports,
953 size_t bufsize, int tcp_accept_count, void* sslctx,
954 struct dt_env* dtenv, comm_point_callback_t* cb, void *cb_arg)
956 struct listen_dnsport* front = (struct listen_dnsport*)
957 malloc(sizeof(struct listen_dnsport));
961 front->udp_buff = sldns_buffer_new(bufsize);
962 if(!front->udp_buff) {
967 /* create comm points as needed */
969 struct comm_point* cp = NULL;
970 if(ports->ftype == listen_type_udp)
971 cp = comm_point_create_udp(base, ports->fd,
972 front->udp_buff, cb, cb_arg);
973 else if(ports->ftype == listen_type_tcp)
974 cp = comm_point_create_tcp(base, ports->fd,
975 tcp_accept_count, bufsize, cb, cb_arg);
976 else if(ports->ftype == listen_type_ssl) {
977 cp = comm_point_create_tcp(base, ports->fd,
978 tcp_accept_count, bufsize, cb, cb_arg);
980 } else if(ports->ftype == listen_type_udpancil)
981 cp = comm_point_create_udp_ancil(base, ports->fd,
982 front->udp_buff, cb, cb_arg);
984 log_err("can't create commpoint");
985 listen_delete(front);
989 cp->do_not_close = 1;
990 if(!listen_cp_insert(cp, front)) {
991 log_err("malloc failed");
992 comm_point_delete(cp);
993 listen_delete(front);
999 log_err("Could not open sockets to accept queries.");
1000 listen_delete(front);
1008 listen_list_delete(struct listen_list* list)
1010 struct listen_list *p = list, *pn;
1013 comm_point_delete(p->com);
1020 listen_delete(struct listen_dnsport* front)
1024 listen_list_delete(front->cps);
1025 sldns_buffer_free(front->udp_buff);
1030 listening_ports_open(struct config_file* cfg, int* reuseport)
1032 struct listen_port* list = NULL;
1033 struct addrinfo hints;
1034 int i, do_ip4, do_ip6;
1035 int do_tcp, do_auto;
1037 snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
1038 do_ip4 = cfg->do_ip4;
1039 do_ip6 = cfg->do_ip6;
1040 do_tcp = cfg->do_tcp;
1041 do_auto = cfg->if_automatic && cfg->do_udp;
1042 if(cfg->incoming_num_tcp == 0)
1046 memset(&hints, 0, sizeof(hints));
1047 hints.ai_flags = AI_PASSIVE;
1048 /* no name lookups on our listening ports */
1049 if(cfg->num_ifs > 0)
1050 hints.ai_flags |= AI_NUMERICHOST;
1051 hints.ai_family = AF_UNSPEC;
1055 if(!do_ip4 && !do_ip6) {
1058 /* create ip4 and ip6 ports so that return addresses are nice. */
1059 if(do_auto || cfg->num_ifs == 0) {
1061 hints.ai_family = AF_INET6;
1062 if(!ports_create_if(do_auto?"::0":"::1",
1063 do_auto, cfg->do_udp, do_tcp,
1064 &hints, portbuf, &list,
1065 cfg->so_rcvbuf, cfg->so_sndbuf,
1066 cfg->ssl_port, reuseport,
1067 cfg->ip_transparent)) {
1068 listening_ports_free(list);
1073 hints.ai_family = AF_INET;
1074 if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
1075 do_auto, cfg->do_udp, do_tcp,
1076 &hints, portbuf, &list,
1077 cfg->so_rcvbuf, cfg->so_sndbuf,
1078 cfg->ssl_port, reuseport,
1079 cfg->ip_transparent)) {
1080 listening_ports_free(list);
1084 } else for(i = 0; i<cfg->num_ifs; i++) {
1085 if(str_is_ip6(cfg->ifs[i])) {
1088 hints.ai_family = AF_INET6;
1089 if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
1090 do_tcp, &hints, portbuf, &list,
1091 cfg->so_rcvbuf, cfg->so_sndbuf,
1092 cfg->ssl_port, reuseport,
1093 cfg->ip_transparent)) {
1094 listening_ports_free(list);
1100 hints.ai_family = AF_INET;
1101 if(!ports_create_if(cfg->ifs[i], 0, cfg->do_udp,
1102 do_tcp, &hints, portbuf, &list,
1103 cfg->so_rcvbuf, cfg->so_sndbuf,
1104 cfg->ssl_port, reuseport,
1105 cfg->ip_transparent)) {
1106 listening_ports_free(list);
1114 void listening_ports_free(struct listen_port* list)
1116 struct listen_port* nx;
1119 if(list->fd != -1) {
1123 closesocket(list->fd);
1131 size_t listen_get_mem(struct listen_dnsport* listen)
1133 size_t s = sizeof(*listen) + sizeof(*listen->base) +
1134 sizeof(*listen->udp_buff) +
1135 sldns_buffer_capacity(listen->udp_buff);
1136 struct listen_list* p;
1137 for(p = listen->cps; p; p = p->next) {
1139 s += comm_point_get_mem(p->com);
1144 void listen_stop_accept(struct listen_dnsport* listen)
1146 /* do not stop the ones that have no tcp_free list
1147 * (they have already stopped listening) */
1148 struct listen_list* p;
1149 for(p=listen->cps; p; p=p->next) {
1150 if(p->com->type == comm_tcp_accept &&
1151 p->com->tcp_free != NULL) {
1152 comm_point_stop_listening(p->com);
1157 void listen_start_accept(struct listen_dnsport* listen)
1159 /* do not start the ones that have no tcp_free list, it is no
1160 * use to listen to them because they have no free tcp handlers */
1161 struct listen_list* p;
1162 for(p=listen->cps; p; p=p->next) {
1163 if(p->com->type == comm_tcp_accept &&
1164 p->com->tcp_free != NULL) {
1165 comm_point_start_listening(p->com, -1, -1);