diff --git a/src/dhcp-common.c b/src/dhcp-common.c index 5b0756d..028178a 100644 --- a/src/dhcp-common.c +++ b/src/dhcp-common.c @@ -444,7 +444,7 @@ void dhcp_update_configs(struct dhcp_config *configs) } #ifdef HAVE_LINUX_NETWORK -void bindtodevice(int fd) +char *whichdevice(void) { /* If we are doing DHCP on exactly one interface, and running linux, do SO_BINDTODEVICE to that device. This is for the use case of (eg) OpenStack, which runs a new @@ -459,13 +459,13 @@ void bindtodevice(int fd) struct irec *iface, *found; struct iname *if_tmp; - + if (!daemon->if_names) - return; - + return NULL; + for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*'))) - return; + return NULL; for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next) if (iface->dhcp_ok) @@ -473,18 +473,24 @@ void bindtodevice(int fd) if (!found) found = iface; else if (strcmp(found->name, iface->name) != 0) - return; /* more than one. */ + return NULL; /* more than one. */ } - + if (found) - { - struct ifreq ifr; - strcpy(ifr.ifr_name, found->name); - /* only allowed by root. */ - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 && - errno != EPERM) - die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET); - } + return found->name; + + return NULL; +} + +void bindtodevice(char *device, int fd) +{ + struct ifreq ifr; + + strcpy(ifr.ifr_name, device); + /* only allowed by root. */ + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) == -1 && + errno != EPERM) + die(_("failed to set SO_BINDTODEVICE on DHCP socket: %s"), NULL, EC_BADNET); } #endif diff --git a/src/dnsmasq.c b/src/dnsmasq.c index f1c9500..83d77d8 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -50,6 +50,8 @@ int main (int argc, char **argv) #if defined(HAVE_LINUX_NETWORK) cap_user_header_t hdr = NULL; cap_user_data_t data = NULL; + char *bound_device = NULL; + int did_bind = 0; #endif #if defined(HAVE_DHCP) || defined(HAVE_DHCP6) struct dhcp_context *context; @@ -239,18 +241,29 @@ 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) - bindtodevice(daemon->dhcpfd); - if (daemon->enable_pxe) - bindtodevice(daemon->pxefd); + if (!daemon->relay4 && bound_device) + { + bindtodevice(bound_device, daemon->dhcpfd); + did_bind = 1; + } + if (daemon->enable_pxe && bound_device) + { + bindtodevice(bound_device, daemon->pxefd); + did_bind = 1; + } } #endif #if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6) - if (daemon->doing_dhcp6 && !daemon->relay6) - bindtodevice(daemon->dhcp6fd); + if (daemon->doing_dhcp6 && !daemon->relay6 && bound_device) + { + bindtodevice(bound_device, daemon->dhcp6fd); + did_bind = 1; + } #endif } else @@ -659,6 +672,11 @@ int main (int argc, char **argv) my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled")); # endif +# ifdef HAVE_LINUX_NETWORK + if (did_bind) + my_syslog(MS_DHCP | LOG_INFO, _("DHCP, sockets bound exclusively to interface %s"), bound_device); +# endif + /* after dhcp_contruct_contexts */ if (daemon->dhcp || daemon->doing_dhcp6) lease_find_interfaces(now); diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 272d0a2..adf0828 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1268,7 +1268,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs, int hw_type, char *hostname); int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type); #ifdef HAVE_LINUX_NETWORK -void bindtodevice(int fd); +char *whichdevice(void); +void bindtodevice(char *device, int fd); #endif # ifdef HAVE_DHCP6 void display_opts6(void);