diff --git a/src/dnsmasq.c b/src/dnsmasq.c index bea57bc..573aac0 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -1861,8 +1861,26 @@ static void check_dns_listeners(time_t now) for (i = 0; i < MAX_PROCS; i++) if (daemon->tcp_pids[i] == 0 && daemon->tcp_pipes[i] == -1) { + char a; + daemon->tcp_pids[i] = p; daemon->tcp_pipes[i] = pipefd[0]; +#ifdef HAVE_LINUX_NETWORK + /* The child process inherits the netlink socket, + which it never uses, but when the parent (us) + uses it in the future, the answer may go to the + child, resulting in the parent blocking + forever awaiting the result. To avoid this + the child closes the netlink socket, but there's + a nasty race, since the parent may use netlink + before the child has done the close. + + To avoid this, the parent blocks here until a + single byte comes back up the pipe, which + is sent by the child after it has closed the + netlink socket. */ + retry_send(read(pipefd[0], &a, 1)); +#endif break; } } @@ -1894,9 +1912,15 @@ static void check_dns_listeners(time_t now) terminate the process. */ if (!option_bool(OPT_DEBUG)) { + char a = 0; alarm(CHILD_LIFETIME); close(pipefd[0]); /* close read end in child. */ daemon->pipe_to_parent = pipefd[1]; +#ifdef HAVE_LINUX_NETWORK + /* See comment above re netlink socket. */ + close(daemon->netlinkfd); + retry_send(write(pipefd[1], &a, 1)); +#endif } /* start with no upstream connections. */