]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- unbound tries to set the ulimit fds when started as server.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 8 Apr 2008 15:02:52 +0000 (15:02 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 8 Apr 2008 15:02:52 +0000 (15:02 +0000)
        if that does not work, it will scale back its requirements.

git-svn-id: file:///svn/unbound/trunk@1022 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/unbound.c
doc/Changelog
doc/example.conf
doc/unbound.conf.5
services/listen_dnsport.c
services/listen_dnsport.h
services/outside_network.c
util/config_file.c

index fe9187cbf03206a56ff304b35ae188b6724455f8..285b5d75a3ee5e7ef40809bea860e141dbef727a 100644 (file)
@@ -91,17 +91,22 @@ checkrlimits(struct config_file* cfg)
                        (int)cfg->incoming_num_tcp:0));
        size_t ifs = (size_t)(cfg->num_ifs==0?1:cfg->num_ifs);
        size_t listen_num = list*ifs;
-       size_t out_ifs = (size_t)(cfg->num_out_ifs==0?1:cfg->num_out_ifs);
-       size_t outnum = cfg->outgoing_num_ports*out_ifs + cfg->outgoing_num_tcp;
+       size_t out_ifs = (size_t)(cfg->num_out_ifs==0?
+               ( (cfg->do_ip4?1:0) + (cfg->do_ip6?1:0) ) :cfg->num_out_ifs);
+       size_t outudpnum = cfg->outgoing_num_ports*out_ifs;
+       size_t outtcpnum = cfg->outgoing_num_tcp;
        size_t misc = 4; /* logfile, pidfile, stdout... */
-       size_t perthread = listen_num + outnum + 2/*cmdpipe*/ + 2/*libevent*/
-               + misc; 
+       size_t perthread_noudp = listen_num + outtcpnum + 
+               2/*cmdpipe*/ + 2/*libevent*/ + misc; 
+       size_t perthread = perthread_noudp + outudpnum;
+
 #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS)
        int numthread = 1; /* it forks */
 #else
        int numthread = cfg->num_threads;
 #endif
        size_t total = numthread * perthread + misc;
+       size_t avail;
        struct rlimit rlim;
        if(getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
                log_warn("getrlimit: %s", strerror(errno));
@@ -110,13 +115,24 @@ checkrlimits(struct config_file* cfg)
        if(rlim.rlim_cur == (rlim_t)RLIM_INFINITY)
                return;
        if((size_t)rlim.rlim_cur < total) {
-               log_err("Not enough sockets available. Increase "
-                       "ulimit(open files).");
-               log_err("or decrease number of threads, outgoing num ports, "
-                       "outgoing num tcp or number of interfaces");
-               log_err("estimate %u fds high mark, %u available", 
-                       (unsigned)total, (unsigned)rlim.rlim_cur);
-               fatal_exit("Not enough file descriptors available");
+               avail = (size_t)rlim.rlim_cur;
+               rlim.rlim_cur = (rlim_t)(total + 10);
+               rlim.rlim_max = (rlim_t)(total + 10);
+               if(setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
+                       log_warn("setrlimit: %s", strerror(errno));
+                       log_warn("cannot increase max open fds from %u to %u",
+                               (unsigned)avail, (unsigned)total+10);
+                       cfg->outgoing_num_ports = (int)((avail 
+                               - numthread*perthread_noudp 
+                               - 10 /* safety margin */)
+                               /(numthread*out_ifs));
+                       log_warn("continuing with less udp ports: %u",
+                               cfg->outgoing_num_ports);
+                       log_warn("increase ulimit or decrease threads, ports in config to remove this warning");
+                       return;
+               }
+               log_warn("increased limit(open files) from %u to %u",
+                       (unsigned)avail, (unsigned)total+10);
        }
 }
 
index 585862ea1014205ffb3a1716561166d2c292ed50..9a737b17f567b275e6b0148c81e9c5598c3cb00d 100644 (file)
@@ -1,3 +1,7 @@
+8 April 2008: Wouter
+       - unbound tries to set the ulimit fds when started as server.
+         if that does not work, it will scale back its requirements.
+
 27 March 2008: Wouter
        - documented /dev/random symlink from chrootdir as FAQ entry.
 
index 77328607a5606e3a1e931ea4351e773b834591a0..0ba916eb097bc06ddc4f8946e8e805b77645780e 100644 (file)
@@ -54,7 +54,7 @@ server:
        # port range. A larger port range gives more resistance to certain
        # spoof attacks, as it gets harder to guess which port is used. 
        # But also takes more system resources (for open sockets).
-       # outgoing-range: 16
+       # outgoing-range: 256
 
        # number of outgoing simultaneous tcp buffers to hold per thread.
        # outgoing-num-tcp: 10
index 3727fa77bc5659374b62200f563371d9c5001c74..213feea78ef3200932a8e057cf98d1a5d6f84a21 100644 (file)
@@ -124,7 +124,7 @@ Default is 1053.
 .TP
 .B outgoing\-range: \fI<number>
 Number of ports to open. This number is opened per thread for every outgoing
-query interface. Must be at least 1. Default is 16.
+query interface. Must be at least 1. Default is 256.
 Larger numbers give more protection against spoofing attempts, but need
 extra resources from the operating system.
 .TP
index 5efc89be53cb67377b6044205ae60b537a6f8c4a..8d162aeeecb09e12ae7a7de520e040fccbca492d 100644 (file)
@@ -86,7 +86,7 @@ verbose_print_addr(struct addrinfo *addr)
 }
 
 int
-create_udp_sock(struct addrinfo *addr, int v6only)
+create_udp_sock(struct addrinfo *addr, int v6only, int* inuse)
 {
        int s;
 # if defined(IPV6_USE_MIN_MTU)
@@ -97,6 +97,7 @@ create_udp_sock(struct addrinfo *addr, int v6only)
        verbose_print_addr(addr);
        if((s = socket(addr->ai_family, addr->ai_socktype, 0)) == -1) {
                log_err("can't create socket: %s", strerror(errno));
+               *inuse = 0;
                return -1;
        }
        if(addr->ai_family == AF_INET6) {
@@ -107,6 +108,7 @@ create_udp_sock(struct addrinfo *addr, int v6only)
                                &val, (socklen_t)sizeof(val)) < 0) {
                                log_err("setsockopt(..., IPV6_V6ONLY"
                                        ", ...) failed: %s", strerror(errno));
+                               *inuse = 0;
                                return -1;
                        }
                }
@@ -124,16 +126,23 @@ create_udp_sock(struct addrinfo *addr, int v6only)
                        &on, (socklen_t)sizeof(on)) < 0) {
                        log_err("setsockopt(..., IPV6_USE_MIN_MTU, "
                                "...) failed: %s", strerror(errno));
+                       *inuse = 0;
                        return -1;
                }
 # endif
        }
        if(bind(s, (struct sockaddr*)addr->ai_addr, addr->ai_addrlen) != 0) {
-               log_err("can't bind socket: %s", strerror(errno));
+#ifdef EADDRINUSE
+               *inuse = (errno == EADDRINUSE);
+               if(errno != EADDRINUSE)
+#endif
+                       log_err("can't bind socket: %s", strerror(errno));
                return -1;
        }
-       if(!fd_set_nonblock(s))
+       if(!fd_set_nonblock(s)) {
+               *inuse = 0;
                return -1;
+       }
        return s;
 }
 
@@ -203,7 +212,7 @@ make_sock(int stype, const char* ifname, const char* port,
        struct addrinfo *hints, int v6only)
 {
        struct addrinfo *res = NULL;
-       int r, s;
+       int r, s, inuse;
        hints->ai_socktype = stype;
        if((r=getaddrinfo(ifname, port, hints, &res)) != 0 || !res) {
                log_err("node %s:%s getaddrinfo: %s %s", 
@@ -211,9 +220,12 @@ make_sock(int stype, const char* ifname, const char* port,
                        r==EAI_SYSTEM?(char*)strerror(errno):"");
                return -1;
        }
-       if(stype == SOCK_DGRAM)
-               s = create_udp_sock(res, v6only);
-       else    s = create_tcp_accept_sock(res, v6only);
+       if(stype == SOCK_DGRAM) {
+               s = create_udp_sock(res, v6only, &inuse);
+               if(s == -1 && inuse) {
+                       log_err("bind: address already in use");
+               }
+       }       else    s = create_tcp_accept_sock(res, v6only);
        freeaddrinfo(res);
        return s;
 }
index 59544888baf24bbf651e1239e96d5ae26442f939..9bcd421c09f0cc91a4e4a6f3a64e74a50e23f169 100644 (file)
@@ -168,8 +168,9 @@ size_t listen_get_mem(struct listen_dnsport* listen);
  * @param addr: address info ready to make socket.
  * @param v6only: if enabled, IP6 sockets get IP6ONLY option set.
  *     if enabled with value 2 IP6ONLY option is disabled.
+ * @param inuse: on error, this is set true if the port was in use.
  * @return: the socket. -1 on error.
  */
-int create_udp_sock(struct addrinfo* addr, int v6only);
+int create_udp_sock(struct addrinfo* addr, int v6only, int* inuse);
 
 #endif /* LISTEN_DNSPORT_H */
index cf8798697042c489b2939277c4722087dd32eabc..f69de0281c5efc66c69e111044ae4671f8877b07 100644 (file)
@@ -284,10 +284,12 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
   * @param ifname: on which interface to open the port.
   * @param hints: hints on family and passiveness preset.
   * @param porthint: if not -1, it gives the port to base range on.
+  * @param inuse: on error, true if the port was in use.
   * @return: file descriptor
   */
 static int 
-open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
+open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint,
+       int* inuse)
 {
        struct addrinfo *res = NULL;
        int r, s;
@@ -308,7 +310,7 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
                        r==EAI_SYSTEM?(char*)strerror(errno):"");
                return -1;
        }
-       s = create_udp_sock(res, 1);
+       s = create_udp_sock(res, 1, inuse);
        freeaddrinfo(res);
        return s;
 }
@@ -346,11 +348,23 @@ make_udp_range(struct comm_point** coms, const char* ifname,
                hints.ai_family = AF_INET6;
        hints.ai_socktype = SOCK_DGRAM;
        for(i=0; i<num_ports; i++) {
-               int fd = open_udp_port_range(ifname, &hints, porthint);
-               if(porthint != -1) 
-                       porthint++;
-               if(fd == -1)
-                       continue;
+               int fd = -1;
+               int inuse = 1;
+               while(fd == -1 && inuse) {
+                       inuse = 0;
+                       fd = open_udp_port_range(ifname, &hints, 
+                               porthint, &inuse);
+                       if(fd == -1 && porthint != -1 && inuse)
+                               verbose(VERB_DETAIL, "%sport %d already in use, skipped", 
+                                       (do_ip6?"IP6 ":""), porthint);
+                       if(porthint != -1) {
+                               porthint++;
+                               if(porthint > 65535) {
+                                       log_err("ports maxed. cannot open ports");
+                                       return done;
+                               }
+                       }
+               }
                coms[done] = comm_point_create_udp(outnet->base, fd, 
                        outnet->udp_buff, outnet_udp_cb, outnet);
                if(coms[done])
index 85b5bdd97bcabf86fe9625062ee9c4ec8ed3ee72..46ab27bce2ece58bf27ce1f36b01e13311b0dfde 100644 (file)
@@ -79,7 +79,7 @@ config_create()
        cfg->do_tcp = 1;
        cfg->use_syslog = 1;
        cfg->outgoing_base_port = cfg->port + 2000;
-       cfg->outgoing_num_ports = 16;
+       cfg->outgoing_num_ports = 256;
        cfg->outgoing_num_tcp = 10;
        cfg->incoming_num_tcp = 10;
        cfg->msg_buffer_size = 65552; /* 64 k + a small margin */
@@ -150,6 +150,8 @@ struct config_file* config_create_forlib()
        free(cfg->chrootdir);
        cfg->chrootdir = NULL;
        cfg->verbosity = 0;
+       cfg->outgoing_num_ports = 16; /* in library use, this is 'reasonable'
+               and probably within the ulimit(maxfds) of the user */
        cfg->outgoing_num_tcp = 2;
        cfg->msg_cache_size = 1024*1024;
        cfg->msg_cache_slabs = 1;