I noticed on my laptop that if I tried to start unwind(8) via rcctl(8)
while I already had some other process bound to tcp/udp port 53
(e.g. unbound(8)), rcctl(8) would falsely report the service started
"ok" while in /var/log/daemon unwind(8) would report:
fatal in main: could not bind to 127.0.0.1 or ::1 on port 53
Since unwind(8) daemonizes before the exit(3) call, rcctl(8) doesn't
identify the failure.
The below diff splits unwind.c:open_ports() and moves the socket
bind/listen calls to before calling daemon(3). The imsg composition is
kept in the location of the original call to open_ports() in main(). The
sockets have SOCK_CLOEXEC added to them since they're now created before
the fork/execvp dance creating the frontend and resolver processes.
Feedback or OK?
-dv@
Index: sbin/unwind/unwind.c
===================================================================
RCS file: /cvs/src/sbin/unwind/unwind.c,v
retrieving revision 1.61
diff -u -p -r1.61 unwind.c
--- sbin/unwind/unwind.c 27 Feb 2021 10:32:28 -0000 1.61
+++ sbin/unwind/unwind.c 4 Apr 2021 14:57:52 -0000
@@ -56,6 +56,13 @@ enum uw_process {
PROC_FRONTEND,
};
+struct uw_socks {
+ int tcp4sock;
+ int tcp6sock;
+ int udp4sock;
+ int udp6sock;
+};
+
__dead void usage(void);
__dead void main_shutdown(void);
@@ -71,7 +78,7 @@ static int main_imsg_send_config(struct
int main_reload(void);
int main_sendall(enum imsg_type, void *, uint16_t);
-void open_ports(void);
+void open_ports(struct uw_socks *);
void solicit_dns_proposals(void);
void send_blocklist_fd(void);
@@ -127,6 +134,7 @@ main(int argc, char *argv[])
int pipe_main2frontend[2], pipe_main2resolver[2];
int control_fd, ta_fd;
char *csock, *saved_argv0;
+ struct uw_socks socks = { -1, -1, -1, -1 };
csock = _PATH_UNWIND_SOCKET;
@@ -203,6 +211,8 @@ main(int argc, char *argv[])
log_init(debug, LOG_DAEMON);
log_setverbose(cmd_opts & (OPT_VERBOSE | OPT_VERBOSE2 | OPT_VERBOSE3));
+ open_ports(&socks);
+
if (!debug)
daemon(1, 0);
@@ -259,7 +269,15 @@ main(int argc, char *argv[])
&iev_resolver->ibuf))
fatal("could not establish imsg links");
- open_ports();
+ /* Send opened sockets to the frontend */
+ if (socks.udp4sock != -1)
+ main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, socks.udp4sock);
+ if (socks.udp6sock != -1)
+ main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, socks.udp6sock);
+ if (socks.tcp4sock != -1)
+ main_imsg_compose_frontend_fd(IMSG_TCP4SOCK, 0, socks.tcp4sock);
+ if (socks.tcp6sock != -1)
+ main_imsg_compose_frontend_fd(IMSG_TCP6SOCK, 0, socks.tcp6sock);
if ((control_fd = control_init(csock)) == -1)
fatalx("control socket setup failed");
@@ -724,7 +742,7 @@ config_clear(struct uw_conf *conf)
}
void
-open_ports(void)
+open_ports(struct uw_socks *socks)
{
struct addrinfo hints, *res0;
int udp4sock = -1, udp6sock = -1, error, bsize = 65535;
@@ -738,8 +756,9 @@ open_ports(void)
error = getaddrinfo("127.0.0.1", "domain", &hints, &res0);
if (!error && res0) {
- if ((udp4sock = socket(res0->ai_family, res0->ai_socktype,
- res0->ai_protocol)) != -1) {
+ if ((udp4sock = socket(res0->ai_family,
+ res0->ai_socktype | SOCK_CLOEXEC,
+ res0->ai_protocol)) != -1) {
if (setsockopt(udp4sock, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) == -1)
log_warn("setting SO_REUSEADDR on socket");
@@ -759,8 +778,9 @@ open_ports(void)
hints.ai_family = AF_INET6;
error = getaddrinfo("::1", "domain", &hints, &res0);
if (!error && res0) {
- if ((udp6sock = socket(res0->ai_family, res0->ai_socktype,
- res0->ai_protocol)) != -1) {
+ if ((udp6sock = socket(res0->ai_family,
+ res0->ai_socktype | SOCK_CLOEXEC,
+ res0->ai_protocol)) != -1) {
if (setsockopt(udp6sock, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) == -1)
log_warn("setting SO_REUSEADDR on socket");
@@ -783,8 +803,8 @@ open_ports(void)
error = getaddrinfo("127.0.0.1", "domain", &hints, &res0);
if (!error && res0) {
if ((tcp4sock = socket(res0->ai_family,
- res0->ai_socktype | SOCK_NONBLOCK,
- res0->ai_protocol)) != -1) {
+ res0->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC,
+ res0->ai_protocol)) != -1) {
if (setsockopt(tcp4sock, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) == -1)
log_warn("setting SO_REUSEADDR on socket");
@@ -809,8 +829,8 @@ open_ports(void)
error = getaddrinfo("::1", "domain", &hints, &res0);
if (!error && res0) {
if ((tcp6sock = socket(res0->ai_family,
- res0->ai_socktype | SOCK_NONBLOCK,
- res0->ai_protocol)) != -1) {
+ res0->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC,
+ res0->ai_protocol)) != -1) {
if (setsockopt(tcp6sock, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt)) == -1)
log_warn("setting SO_REUSEADDR on socket");
@@ -835,14 +855,10 @@ open_ports(void)
tcp6sock == -1))
fatalx("could not bind to 127.0.0.1 or ::1 on port 53");
- if (udp4sock != -1)
- main_imsg_compose_frontend_fd(IMSG_UDP4SOCK, 0, udp4sock);
- if (udp6sock != -1)
- main_imsg_compose_frontend_fd(IMSG_UDP6SOCK, 0, udp6sock);
- if (tcp4sock != -1)
- main_imsg_compose_frontend_fd(IMSG_TCP4SOCK, 0, tcp4sock);
- if (tcp6sock != -1)
- main_imsg_compose_frontend_fd(IMSG_TCP6SOCK, 0, tcp6sock);
+ socks->tcp4sock = tcp4sock;
+ socks->tcp6sock = tcp6sock;
+ socks->udp4sock = udp4sock;
+ socks->udp6sock = udp6sock;
}
void