From: Wouter Wijngaards Date: Tue, 8 Apr 2008 15:02:52 +0000 (+0000) Subject: - unbound tries to set the ulimit fds when started as server. X-Git-Tag: release-0.11~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d26b183ba6cf679a70141649f2b326abeb0db22e;p=thirdparty%2Funbound.git - unbound tries to set the ulimit fds when started as server. if that does not work, it will scale back its requirements. git-svn-id: file:///svn/unbound/trunk@1022 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/unbound.c b/daemon/unbound.c index fe9187cbf..285b5d75a 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -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); } } diff --git a/doc/Changelog b/doc/Changelog index 585862ea1..9a737b17f 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/doc/example.conf b/doc/example.conf index 77328607a..0ba916eb0 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -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 diff --git a/doc/unbound.conf.5 b/doc/unbound.conf.5 index 3727fa77b..213feea78 100644 --- a/doc/unbound.conf.5 +++ b/doc/unbound.conf.5 @@ -124,7 +124,7 @@ Default is 1053. .TP .B outgoing\-range: \fI 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 diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 5efc89be5..8d162aeee 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -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; } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 59544888b..9bcd421c0 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -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 */ diff --git a/services/outside_network.c b/services/outside_network.c index cf8798697..f69de0281 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -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 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]) diff --git a/util/config_file.c b/util/config_file.c index 85b5bdd97..46ab27bce 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -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;