diff options
Diffstat (limited to 'src/dnsmasq.c')
-rw-r--r-- | src/dnsmasq.c | 211 |
1 files changed, 128 insertions, 83 deletions
diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 2306c48..602daed 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -1,4 +1,4 @@ -/* dnsmasq is Copyright (c) 2000-2020 Simon Kelley +/* dnsmasq is Copyright (c) 2000-2021 Simon Kelley This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ struct daemon *daemon; static volatile pid_t pid = 0; static volatile int pipewrite; -static int set_dns_listeners(time_t now); +static void set_dns_listeners(void); static void check_dns_listeners(time_t now); static void sig_handler(int sig); static void async_event(int pipe, time_t now); @@ -109,7 +109,6 @@ int main (int argc, char **argv) daemon->packet_buff_sz = daemon->edns_pktsz + MAXDNAME + RRFIXEDSZ; daemon->packet = safe_malloc(daemon->packet_buff_sz); - daemon->addrbuff = safe_malloc(ADDRSTRLEN); if (option_bool(OPT_EXTRALOG)) daemon->addrbuff2 = safe_malloc(ADDRSTRLEN); @@ -135,6 +134,13 @@ int main (int argc, char **argv) } #endif +#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS) + /* CONNTRACK UBUS code uses this buffer, so if not allocated above, + we need to allocate it here. */ + if (option_bool(OPT_CMARK_ALST_EN) && !daemon->workspacename) + daemon->workspacename = safe_malloc(MAXDNAME); +#endif + #ifdef HAVE_DHCP if (!daemon->lease_file) { @@ -205,8 +211,13 @@ int main (int argc, char **argv) #endif #ifdef HAVE_CONNTRACK - if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport)) - die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF); + if (option_bool(OPT_CONNTRACK)) + { + if (daemon->query_port != 0 || daemon->osport) + die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF); + + need_cap_net_admin = 1; + } #else if (option_bool(OPT_CONNTRACK)) die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF); @@ -237,9 +248,16 @@ int main (int argc, char **argv) die(_("Ubus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF); #endif + /* Handle only one of min_port/max_port being set. */ + if (daemon->min_port != 0 && daemon->max_port == 0) + daemon->max_port = MAX_PORT; + + if (daemon->max_port != 0 && daemon->min_port == 0) + daemon->min_port = MIN_PORT; + if (daemon->max_port < daemon->min_port) die(_("max_port cannot be smaller than min_port"), NULL, EC_BADCONF); - + now = dnsmasq_time(); if (daemon->auth_zones) @@ -390,8 +408,16 @@ int main (int argc, char **argv) if (daemon->port != 0) { cache_init(); - blockdata_init(); + hash_questions_init(); + + /* Scale random socket pool by ftabsize, but + limit it based on available fds. */ + daemon->numrrand = daemon->ftabsize/2; + if (daemon->numrrand > max_fd/3) + daemon->numrrand = max_fd/3; + /* safe_malloc returns zero'd memory */ + daemon->randomsocks = safe_malloc(daemon->numrrand * sizeof(struct randfd)); } #ifdef HAVE_INOTIFY @@ -415,8 +441,6 @@ int main (int argc, char **argv) #ifdef HAVE_DBUS { char *err; - daemon->dbus = NULL; - daemon->watches = NULL; if ((err = dbus_init())) die(_("DBus error: %s"), err, EC_MISC); } @@ -427,8 +451,9 @@ int main (int argc, char **argv) if (option_bool(OPT_UBUS)) #ifdef HAVE_UBUS { - daemon->ubus = NULL; - ubus_init(); + char *err; + if ((err = ubus_init())) + die(_("UBus error: %s"), err, EC_MISC); } #else die(_("UBus not available: set HAVE_UBUS in src/config.h"), NULL, EC_BADCONF); @@ -980,7 +1005,7 @@ int main (int argc, char **argv) a single file will be sent to may clients (the file only needs one fd). */ - max_fd -= 30; /* use other than TFTP */ + max_fd -= 30 + daemon->numrrand; /* use other than TFTP */ if (max_fd < 0) max_fd = 5; @@ -1010,7 +1035,7 @@ int main (int argc, char **argv) close(err_pipe[1]); if (daemon->port != 0) - check_servers(); + check_servers(0); pid = getpid(); @@ -1025,16 +1050,10 @@ int main (int argc, char **argv) while (1) { - int t, timeout = -1; + int timeout = -1; poll_reset(); - /* if we are out of resources, find how long we have to wait - for some to come free, we'll loop around then and restart - listening for queries */ - if ((t = set_dns_listeners(now)) != 0) - timeout = t * 1000; - /* Whilst polling for the dbus, or doing a tftp transfer, wake every quarter second */ if (daemon->tftp_trans || (option_bool(OPT_DBUS) && !daemon->dbus)) @@ -1044,15 +1063,18 @@ int main (int argc, char **argv) else if (is_dad_listeners()) timeout = 1000; + set_dns_listeners(); + #ifdef HAVE_DBUS - set_dbus_listeners(); + if (option_bool(OPT_DBUS)) + set_dbus_listeners(); #endif - + #ifdef HAVE_UBUS if (option_bool(OPT_UBUS)) set_ubus_listeners(); #endif - + #ifdef HAVE_DHCP if (daemon->dhcp || daemon->relay4) { @@ -1172,28 +1194,44 @@ int main (int argc, char **argv) #ifdef HAVE_DBUS /* if we didn't create a DBus connection, retry now. */ - if (option_bool(OPT_DBUS) && !daemon->dbus) + if (option_bool(OPT_DBUS)) { - char *err; - if ((err = dbus_init())) - my_syslog(LOG_WARNING, _("DBus error: %s"), err); - if (daemon->dbus) - my_syslog(LOG_INFO, _("connected to system DBus")); + if (!daemon->dbus) + { + char *err = dbus_init(); + + if (daemon->dbus) + my_syslog(LOG_INFO, _("connected to system DBus")); + else if (err) + { + my_syslog(LOG_ERR, _("DBus error: %s"), err); + reset_option_bool(OPT_DBUS); /* fatal error, stop trying. */ + } + } + + check_dbus_listeners(); } - check_dbus_listeners(); #endif #ifdef HAVE_UBUS + /* if we didn't create a UBus connection, retry now. */ if (option_bool(OPT_UBUS)) - { - /* if we didn't create a UBus connection, retry now. */ - if (!daemon->ubus) - { - ubus_init(); - } + { + if (!daemon->ubus) + { + char *err = ubus_init(); - check_ubus_listeners(); - } + if (daemon->ubus) + my_syslog(LOG_INFO, _("connected to system UBus")); + else if (err) + { + my_syslog(LOG_ERR, _("UBus error: %s"), err); + reset_option_bool(OPT_UBUS); /* fatal error, stop trying. */ + } + } + + check_ubus_listeners(); + } #endif check_dns_listeners(now); @@ -1426,7 +1464,7 @@ static void async_event(int pipe, time_t now) } if (check) - check_servers(); + check_servers(0); } #ifdef HAVE_DHCP @@ -1625,7 +1663,7 @@ static void poll_resolv(int force, int do_reload, time_t now) { my_syslog(LOG_INFO, _("reading %s"), latest->name); warned = 0; - check_servers(); + check_servers(0); if (option_bool(OPT_RELOAD) && do_reload) clear_cache_and_reload(now); } @@ -1668,11 +1706,12 @@ void clear_cache_and_reload(time_t now) #endif } -static int set_dns_listeners(time_t now) +static void set_dns_listeners(void) { struct serverfd *serverfdp; struct listener *listener; - int wait = 0, i; + struct randfd_list *rfl; + int i; #ifdef HAVE_TFTP int tftp = 0; @@ -1685,66 +1724,68 @@ static int set_dns_listeners(time_t now) } #endif - /* will we be able to get memory? */ - if (daemon->port != 0) - get_new_frec(now, &wait, NULL); - for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) poll_listen(serverfdp->fd, POLLIN); - if (daemon->port != 0 && !daemon->osport) - for (i = 0; i < RANDOM_SOCKS; i++) - if (daemon->randomsocks[i].refcount != 0) - poll_listen(daemon->randomsocks[i].fd, POLLIN); - + for (i = 0; i < daemon->numrrand; i++) + if (daemon->randomsocks[i].refcount != 0) + poll_listen(daemon->randomsocks[i].fd, POLLIN); + + /* Check overflow random sockets too. */ + for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next) + poll_listen(rfl->rfd->fd, POLLIN); + + /* check to see if we have free tcp process slots. */ + for (i = MAX_PROCS - 1; i >= 0; i--) + if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) + break; + for (listener = daemon->listeners; listener; listener = listener->next) { - /* only listen for queries if we have resources */ - if (listener->fd != -1 && wait == 0) + if (listener->fd != -1) poll_listen(listener->fd, POLLIN); - - /* death of a child goes through the select loop, so - we don't need to explicitly arrange to wake up here */ - if (listener->tcpfd != -1) - for (i = 0; i < MAX_PROCS; i++) - if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) - { - poll_listen(listener->tcpfd, POLLIN); - break; - } - + + /* Only listen for TCP connections when a process slot + is available. Death of a child goes through the select loop, so + we don't need to explicitly arrange to wake up here, + we'll be called again when a slot becomes available. */ + if (listener->tcpfd != -1 && i >= 0) + poll_listen(listener->tcpfd, POLLIN); + #ifdef HAVE_TFTP /* tftp == 0 in single-port mode. */ if (tftp <= daemon->tftp_max && listener->tftpfd != -1) poll_listen(listener->tftpfd, POLLIN); #endif - } if (!option_bool(OPT_DEBUG)) for (i = 0; i < MAX_PROCS; i++) if (daemon->tcp_pipes[i] != -1) poll_listen(daemon->tcp_pipes[i], POLLIN); - - return wait; } static void check_dns_listeners(time_t now) { struct serverfd *serverfdp; struct listener *listener; + struct randfd_list *rfl; int i; int pipefd[2]; for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next) if (poll_check(serverfdp->fd, POLLIN)) - reply_query(serverfdp->fd, serverfdp->source_addr.sa.sa_family, now); + reply_query(serverfdp->fd, now); - if (daemon->port != 0 && !daemon->osport) - for (i = 0; i < RANDOM_SOCKS; i++) - if (daemon->randomsocks[i].refcount != 0 && - poll_check(daemon->randomsocks[i].fd, POLLIN)) - reply_query(daemon->randomsocks[i].fd, daemon->randomsocks[i].family, now); + for (i = 0; i < daemon->numrrand; i++) + if (daemon->randomsocks[i].refcount != 0 && + poll_check(daemon->randomsocks[i].fd, POLLIN)) + reply_query(daemon->randomsocks[i].fd, now); + + /* Check overflow random sockets too. */ + for (rfl = daemon->rfl_poll; rfl; rfl = rfl->next) + if (poll_check(rfl->rfd->fd, POLLIN)) + reply_query(rfl->rfd->fd, now); /* Races. The child process can die before we read all of the data from the pipe, or vice versa. Therefore send tcp_pids to zero when we wait() the @@ -1773,7 +1814,16 @@ static void check_dns_listeners(time_t now) tftp_request(listener, now); #endif - if (listener->tcpfd != -1 && poll_check(listener->tcpfd, POLLIN)) + /* check to see if we have a free tcp process slot. + Note that we can't assume that because we had + at least one a poll() time, that we still do. + There may be more waiting connections after + poll() returns then free process slots. */ + for (i = MAX_PROCS - 1; i >= 0; i--) + if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) + break; + + if (listener->tcpfd != -1 && i >= 0 && poll_check(listener->tcpfd, POLLIN)) { int confd, client_ok = 1; struct irec *iface = NULL; @@ -1863,7 +1913,6 @@ static void check_dns_listeners(time_t now) close(pipefd[0]); else { - int i; #ifdef HAVE_LINUX_NETWORK /* The child process inherits the netlink socket, which it never uses, but when the parent (us) @@ -1883,13 +1932,9 @@ static void check_dns_listeners(time_t now) read_write(pipefd[0], &a, 1, 1); #endif - for (i = 0; i < MAX_PROCS; i++) - if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) - { - daemon->tcp_pids[i] = p; - daemon->tcp_pipes[i] = pipefd[0]; - break; - } + /* i holds index of free slot */ + daemon->tcp_pids[i] = p; + daemon->tcp_pipes[i] = pipefd[0]; } close(confd); @@ -2068,7 +2113,7 @@ int delay_dhcp(time_t start, int sec, int fd, uint32_t addr, unsigned short id) poll_reset(); if (fd != -1) poll_listen(fd, POLLIN); - set_dns_listeners(now); + set_dns_listeners(); set_log_writer(); #ifdef HAVE_DHCP6 |