summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2022-02-03 17:12:38 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2022-02-03 17:26:28 +0000
commitfa580ad3eb3d40207425cf3dfb7dae48fe7b5680 (patch)
treee156ecc58856d1f4e89fca06df42aac1433e4836
parent292dfa653ed0353a17e8462bb950f6fdd9ef2cdc (diff)
downloaddnsmasq-fa580ad3eb3d40207425cf3dfb7dae48fe7b5680.tar.gz
Handle changing interface indexes when binding DHCP sockets.
-rw-r--r--CHANGELOG8
-rw-r--r--src/dhcp-common.c38
-rw-r--r--src/dnsmasq.c34
-rw-r--r--src/dnsmasq.h2
4 files changed, 56 insertions, 26 deletions
diff --git a/CHANGELOG b/CHANGELOG
index e7a5d4a..82835ee 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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);