Handle changing interface indexes when binding DHCP sockets.

This commit is contained in:
Simon Kelley
2022-02-03 17:12:38 +00:00
parent 292dfa653e
commit fa580ad3eb
4 changed files with 56 additions and 26 deletions

View File

@@ -39,6 +39,14 @@ version 2.87
a local NODATA answer. The pre-2.86 behaviour is still available,
by configuring --address=/example.com/1.2.3.4 --local=/example.com/
Fix problem with binding DHCP sockets to an individual interface.
Despite the fact that the system call tales the interface _name_ as
a parameter, it actually, binds the socket to interface _index_.
Deleting the interface and creating a new one with the same name
leaves the socket bound to the old index. (Creating new sockets
always allocates a fresh index, they are not reused). We now
take this behaviour into account and keep up with changing indexes.
version 2.86
Handle DHCPREBIND requests in the DHCPv6 server code.

View File

@@ -566,12 +566,16 @@ char *whichdevice(void)
}
if (found)
return found->name;
{
char *ret = safe_malloc(strlen(found->name)+1);
strcpy(ret, found->name);
return ret;
}
return NULL;
}
void bindtodevice(char *device, int fd)
static int bindtodevice(char *device, int fd)
{
size_t len = strlen(device)+1;
if (len > IFNAMSIZ)
@@ -579,7 +583,33 @@ void bindtodevice(char *device, int fd)
/* only allowed by root. */
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, device, len) == -1 &&
errno != EPERM)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
return 2;
return 1;
}
int bind_dhcp_devices(char *bound_device)
{
int ret = 0;
if (bound_device)
{
if (daemon->dhcp)
{
if (!daemon->relay4)
ret |= bindtodevice(bound_device, daemon->dhcpfd);
if (daemon->enable_pxe && daemon->pxefd != -1)
ret |= bindtodevice(bound_device, daemon->pxefd);
}
#if defined(HAVE_DHCP6)
if (daemon->doing_dhcp6 && !daemon->relay6)
ret |= bindtodevice(bound_device, daemon->dhcp6fd);
#endif
}
return ret;
}
#endif

View File

@@ -388,27 +388,8 @@ int main (int argc, char **argv)
/* after enumerate_interfaces() */
bound_device = whichdevice();
if (daemon->dhcp)
{
if (!daemon->relay4 && bound_device)
{
bindtodevice(bound_device, daemon->dhcpfd);
did_bind = 1;
}
if (daemon->enable_pxe && bound_device && daemon->pxefd != -1)
{
bindtodevice(bound_device, daemon->pxefd);
did_bind = 1;
}
}
#endif
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device)
{
bindtodevice(bound_device, daemon->dhcp6fd);
did_bind = 1;
}
if ((did_bind = bind_dhcp_devices(bound_device)) & 2)
die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET);
#endif
}
else
@@ -1100,6 +1081,17 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP
# if defined(HAVE_LINUX_NETWORK)
if (bind_dhcp_devices(bound_device) & 2)
{
static int warned = 0;
if (!warned)
{
my_syslog(LOG_ERR, _("error binding DHCP socket to device %s"), bound_device);
warned = 1;
}
}
# endif
if (daemon->dhcp || daemon->relay4)
{
poll_listen(daemon->dhcpfd, POLLIN);

View File

@@ -1715,7 +1715,7 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
#ifdef HAVE_LINUX_NETWORK
char *whichdevice(void);
void bindtodevice(char *device, int fd);
int bind_dhcp_devices(char *bound_device);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);