mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Set SO_BINDTODEVICE on DHCP sockets when doing DHCP on one interface
only. Fixes OpenSTack use-case.
This commit is contained in:
@@ -81,6 +81,13 @@ version 2.61
|
||||
may erroneously look like a valid CNAME to a non-exitant
|
||||
name. Thanks to Ben Winslow for finding this.
|
||||
|
||||
Call SO_BINDTODEVICE on the DHCP socket(s) when doing DHCP
|
||||
on exacly one interface and --bind-interfaces is set. This
|
||||
makes the OpenStack use-case of one dnsmasq per virtual
|
||||
interface work. This is only available on Linux; it's not
|
||||
supported on other platforms. Thanks to Vishvananda Ishaya
|
||||
and thr OpenStack team for the suggestion.
|
||||
|
||||
|
||||
version 2.60
|
||||
Fix compilation problem in Mac OS X Lion. Thanks to Olaf
|
||||
|
||||
@@ -451,6 +451,41 @@ void join_multicast(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void bindtodevice(int fd)
|
||||
{
|
||||
/* 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
|
||||
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
|
||||
individual processes don't always see the packets they should.
|
||||
SO_BINDTODEVICE is only available Linux. */
|
||||
|
||||
struct irec *iface, *found;
|
||||
|
||||
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
|
||||
if (iface->dhcp_ok)
|
||||
{
|
||||
if (!found)
|
||||
found = iface;
|
||||
else if (strcmp(found->name, iface->name) != 0)
|
||||
{
|
||||
/* more than one. */
|
||||
found = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct opttab_t {
|
||||
char *name;
|
||||
|
||||
@@ -209,6 +209,21 @@ int main (int argc, char **argv)
|
||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||
if (if_tmp->name && !if_tmp->used)
|
||||
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP)
|
||||
/* after enumerate_interfaces() */
|
||||
if (daemon->dhcp)
|
||||
{
|
||||
bindtodevice(daemon->dhcpfd);
|
||||
if (daemon->enable_pxe)
|
||||
bindtodevice(daemon->pxefd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
|
||||
if (daemon->dhcp6)
|
||||
bindtodevice(daemon->dhcp6fd);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
create_wildcard_listeners();
|
||||
|
||||
@@ -388,7 +388,7 @@ struct server {
|
||||
struct irec {
|
||||
union mysockaddr addr;
|
||||
struct in_addr netmask; /* only valid for IPv4 */
|
||||
int tftp_ok, mtu, done, dad;
|
||||
int tftp_ok, dhcp_ok, mtu, done, dad;
|
||||
char *name;
|
||||
struct irec *next;
|
||||
};
|
||||
@@ -1108,6 +1108,9 @@ u16 lookup_dhcp_opt(int prot, char *name);
|
||||
u16 lookup_dhcp_len(int prot, u16 val);
|
||||
char *option_string(int prot, unsigned int opt, unsigned char *val,
|
||||
int opt_len, char *buf, int buf_len);
|
||||
#ifdef HAVE_LINUX_NETWORK
|
||||
void bindtodevice(int fd);
|
||||
#endif
|
||||
# ifdef HAVE_DHCP6
|
||||
void display_opts6(void);
|
||||
void join_multicast(void);
|
||||
|
||||
@@ -162,6 +162,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
int fd, mtu = 0, loopback;
|
||||
struct ifreq ifr;
|
||||
int tftp_ok = daemon->tftp_unlimited;
|
||||
int dhcp_ok = 1;
|
||||
#ifdef HAVE_DHCP
|
||||
struct iname *tmp;
|
||||
#endif
|
||||
@@ -191,6 +192,9 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
|
||||
loopback = ifr.ifr_flags & IFF_LOOPBACK;
|
||||
|
||||
if (loopback)
|
||||
dhcp_ok = 0;
|
||||
|
||||
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
|
||||
mtu = ifr.ifr_mtu;
|
||||
|
||||
@@ -238,7 +242,10 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
#ifdef HAVE_DHCP
|
||||
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
|
||||
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
|
||||
tftp_ok = 0;
|
||||
{
|
||||
tftp_ok = 0;
|
||||
dhcp_ok = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
@@ -254,6 +261,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
|
||||
iface->addr = *addr;
|
||||
iface->netmask = netmask;
|
||||
iface->tftp_ok = tftp_ok;
|
||||
iface->dhcp_ok = dhcp_ok;
|
||||
iface->mtu = mtu;
|
||||
iface->dad = dad;
|
||||
iface->done = 0;
|
||||
|
||||
Reference in New Issue
Block a user