[Dnsmasq-discuss] Issue with SO_BINDTODEVICE for dhcp

Petr Mensik pemensik at redhat.com
Wed Jul 31 15:27:03 BST 2019


Hi Martin,

I think it would make more sense to not derive intended behaviour from
number of interfaces but allow desired behaviour to be specified explicitly.

If machines want to reuse the same address multiple times on different
interfaces, they may want explicit configuration of BINDTODEVICE
enabled. Default configuration may stay auto detection to keep backward
compatibility, but would allow configuring it without surprises.

On the other hand, it seems to me binding just to single device is
limitation of current code more that well thought requirement. More below.

After experience with TCP socket on interfaces, I think it should log
changes in listening sockets. It is nightmare to debug that in debugger.

Regards,
Petr

On 7/5/19 12:55 PM, Martin Wilck wrote:
> I've just found a strange issue with dnsmasq's dhcp server, which I
> believe is caused by the commit 9380ba7 "Set SO_BINDTODEVICE on DHCP
> sockets when doing DHCP on one interface".
> 
> I was running a single instance dnsmasq for on various local interfaces
> on my system. At the same time, I was running libvirt managed networks,
> which spawn a separate dnsmasq instance for every network created.
> (That's the way it has to be with libvirt). The configuration of the
> first, multiple-interface instance was done with "listen-address" and
> "bind-dynamic"; the listen addresses were 127.0.0.1 plus one address on
> every VLAN on this server.
> 
> Anyway, the above-mentioned commit causes strange behavior for the
> multi-interface dnsmasq instance. SO_BINDTODEVICE will be used if and
> only if exactly one of the configured interfaces is up when dnsmasq is
> started. In this case, if other interfaces are brought up later, dhcp
> queries via these new interfaces don't work, because the dhcp socket is
> bound to the first interface only. If at the time of dnsmasq startup,
> either 0 or >= 2 interfaces are up, dhcp queries work just fine from
> any interface, including those brought up later.
> 
> While this is certainly a corner case, it strongly violates the
> principle of least surprise - the status at the time of dnsmasq startup
> has an effect on whether freshly brought-up interfaces will be serviced
> later. Especially with "bind-dynamic", my expectation was that
> dynamically added interfaces would be served.

They would be, but only for DNS queries. Handling of DHCP sockets is
different, they always use SO_REUSEPORT. Only DHCP would bind to device.
DNS code is intentionally binding just one time to single address. DHCP
socket on contrary would bind to ANY address and bind it to device.

It would require multiple sockets for DHCP on each interface it listens
on. It has now just single socket globally, so listener would have to be
moved from dhcp_init/make_fd to something reacting to newaddress. Like
create_bound_listeners(0) for example? But where would be stored socket
bound to each device? daemon->dhcpfd cannot be bound to multiple interfaces.

I think possible solution would be to move socket itself into struct
irec, to daemon->interfaces. There is parameter dhcp_ok, which is
checked only in whichdevice. It is computed again on every
enumerate_interfaces after each change. It only checks whether there is
(dhcp) single device. Instead, it could create listener socket for each
interface served and bind to it.

I think current state is needed, because bigger rewrite was never done
to dhcp sockets. Without it, it has to be just single socket. structure
listener (used in dns and tftp) does not use SO_REUSEPORT, so there has
to be just single listener on single address. DHCP socket needs the
opposite, binding to every interface enabled separately.
> 
> According to the bug report that motivated the mentioned patch (
> http://codeha.us/openstack/msg09684.html), such a mixture of multi-
> interface and single-interface instances would be doomed to fail
> anyway, because of the issues related to receiving DHCP unicast
> packets. Thus perhaps this configuration should be generally forbidden
> - but I, for one, have not observed the reported unicast-packet issues
> (failing dhcp requests or renewals) up to now.
> 
> Would it perhaps be possible to re-run the SO_BINDTODEVICE logic in the
> newaddress() code path, and dynamically bind/undbind the socket if the
> number of dhcp interfaces changed between 1 and something else?
> 
> Regards,
> Martin
> 
> 
> 
> 
> _______________________________________________
> Dnsmasq-discuss mailing list
> Dnsmasq-discuss at lists.thekelleys.org.uk
> http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss
> 

-- 
Petr Menšík
Software Engineer
Red Hat, http://www.redhat.com/
email: pemensik at redhat.com  PGP: 65C6C973



More information about the Dnsmasq-discuss mailing list