Tighten up error checking in --bind-dynamic mode.

In bind-dynamic mode, its OK to fail to bind a socket to an address
given by --listen-address if no interface with that address exists
for the time being. Dnsmasq will attempt to create the socket again
when the host's network configuration changes.

The code used to ignore pretty much any error from bind(), which is
incorrect and can lead to confusing behaviour. This change make ONLY
a return of EADDRNOTAVAIL from bind() a non-error: anything else will be
fatal during startup phase, or logged after startup phase.

Thanks to Petr Menšík for the problem report and first-pass patch.
This commit is contained in:
Simon Kelley
2023-11-27 23:08:31 +00:00
parent 65c2d6afd6
commit 744231d995

View File

@@ -920,15 +920,24 @@ static int make_sock(union mysockaddr *addr, int type, int dienow)
errno = errsave; errno = errsave;
if (dienow) /* Failure to bind addresses given by --listen-address at this point
because there's no interface with the address is OK if we're doing bind-dynamic.
If/when an interface is created with the relevant address we'll notice
and attempt to bind it then. This is in the generic error path so we close the socket,
but EADDRNOTAVAIL is only a possible error from bind()
When a new address is created and we call this code again (dienow == 0) there
may still be configured addresses when don't exist, (consider >1 --listen-address,
when the first is created, the second will still be missing) so we suppress
EADDRNOTAVAIL even in that case to avoid confusing log entries.
*/
if (!option_bool(OPT_CLEVERBIND) || errno != EADDRNOTAVAIL)
{ {
/* failure to bind addresses given by --listen-address at this point if (dienow)
is OK if we're doing bind-dynamic */
if (!option_bool(OPT_CLEVERBIND))
die(s, daemon->addrbuff, EC_BADNET); die(s, daemon->addrbuff, EC_BADNET);
}
else else
my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno)); my_syslog(LOG_WARNING, s, daemon->addrbuff, strerror(errno));
}
return -1; return -1;
} }