diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2022-02-03 17:12:38 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2022-02-03 17:26:28 +0000 |
commit | fa580ad3eb3d40207425cf3dfb7dae48fe7b5680 (patch) | |
tree | e156ecc58856d1f4e89fca06df42aac1433e4836 | |
parent | 292dfa653ed0353a17e8462bb950f6fdd9ef2cdc (diff) | |
download | dnsmasq-fa580ad3eb3d40207425cf3dfb7dae48fe7b5680.tar.gz |
Handle changing interface indexes when binding DHCP sockets.
-rw-r--r-- | CHANGELOG | 8 | ||||
-rw-r--r-- | src/dhcp-common.c | 38 | ||||
-rw-r--r-- | src/dnsmasq.c | 34 | ||||
-rw-r--r-- | src/dnsmasq.h | 2 |
4 files changed, 56 insertions, 26 deletions
@@ -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. diff --git a/src/dhcp-common.c b/src/dhcp-common.c index 611b5cb..95d41da 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -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 diff --git a/src/dnsmasq.c b/src/dnsmasq.c index d112a7e..7cfb493 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -387,28 +387,9 @@ int main (int argc, char **argv) #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP) /* 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); diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 2ffe808..51a1aa6 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -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); |