mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- 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
This commit is contained in:
parent
ff8c2ed1bc
commit
d26b183ba6
8 changed files with 78 additions and 29 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue