[Dnsmasq-discuss] multiple offers with same IP to different MAC addresses

Simon Kelley simon at thekelleys.org.uk
Tue Feb 23 14:46:22 GMT 2016


On 20/02/16 12:51, Legacy, Allain wrote:
> We recently encountered a scenario where 2 different client machines sent discover packets at the exact same time and ended up getting offer responses for the same IP address.   I confirmed that the algorithm in dhcp.c::address_allocate() would use the same start value for both of these MAC addresses so it would appear as though we got unlucky and had a collision on the MAC address for these two specific clients.
> 
> This is the config entry:
> 
> dhcp-range=set:xyz,192.168.29.2,192.168.29.254,255.255.255.0,1d
> 
> These are the logs (first 4 bytes of MAC addresses obfuscated to 02:11:22:33 from their actual values):
> 
> daemon.log:2016-02-16T13:55:57.000 localhost dnsmasq-dhcp[12225]: info DHCPDISCOVER(eth0) 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:55:57.000 localhost dnsmasq-dhcp[12225]: info DHCPOFFER(eth0) 192.168.29.40 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:55:57.000 localhost dnsmasq-dhcp[12225]: info DHCPDISCOVER(eth0) 02:11:22:33:1b:cc
> daemon.log:2016-02-16T13:55:57.000 localhost dnsmasq-dhcp[12225]: info DHCPOFFER(eth0) 192.168.29.40 02:11:22:33:1b:cc
> daemon.log:2016-02-16T13:55:57.000 localhost dnsmasq-dhcp[12225]: info DHCPDISCOVER(eth0) 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:55:57.000 localhost dnsmasq-dhcp[12225]: info DHCPOFFER(eth0) 192.168.29.40 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:55:58.000 localhost dnsmasq-dhcp[12225]: info DHCPREQUEST(eth0) 192.168.29.40 02:11:22:33:1b:cc
> daemon.log:2016-02-16T13:55:58.000 localhost dnsmasq-dhcp[12225]: info DHCPACK(eth0) 192.168.29.40 02:11:22:33:1b:cc
> daemon.log:2016-02-16T13:55:59.000 localhost dnsmasq-dhcp[12225]: info DHCPREQUEST(eth0) 192.168.29.40 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:55:59.000 localhost dnsmasq-dhcp[12225]: info DHCPNAK(eth0) 192.168.29.40 02:11:22:33:1c:83 address in use
> daemon.log:2016-02-16T13:56:03.000 localhost dnsmasq-dhcp[12225]: info DHCPREQUEST(eth0) 192.168.29.40 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:56:03.000 localhost dnsmasq-dhcp[12225]: info DHCPNAK(eth0) 192.168.29.40 02:11:22:33:1c:83 address in use
> daemon.log:2016-02-16T13:56:07.000 localhost dnsmasq-dhcp[12225]: info DHCPDISCOVER(eth0) 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:56:07.000 localhost dnsmasq-dhcp[12225]: info DHCPOFFER(eth0) 192.168.29.41 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:56:11.000 localhost dnsmasq-dhcp[12225]: info DHCPREQUEST(eth0) 192.168.29.41 02:11:22:33:1c:83
> daemon.log:2016-02-16T13:56:11.000 localhost dnsmasq-dhcp[12225]: info DHCPACK(eth0) 192.168.29.41 02:11:22:33:1c:83
> 
> 
>>From a DHCP point of view things seem to have resolved themselves automatically at both the client and server.  There were ensuing tftp issues on the client which got the NAK and subsequently got a second IP address but I don't believe this to be related to dnsmasq.
> 
> My question is about why the duplicate IP address was even offered to the second client.  Looking at the dhcp.c::address_allocate() code it seems that this scenario is avoided only if OPT_CONSEC_ADDR is set (which we do not set).   Unless I am missing something it seems that any time the address matches and (r->hash != j) the loop should be terminated and a new address should be allocated.   Can you comment on whether this is intentional because of RFC requirements or whether this should be changed?
> 
>                     if (r->addr.s_addr == addr.s_addr)
>                      {
>                        /* consec-ip mode: we offered this address for another client
>                           (different hash) recently, don't offer it to this one. */
>                        if (option_bool(OPT_CONSEC_ADDR) && r->hash != j)
>                          break;
> 
>                        return 1;
>                      }
> 
> 
> Regards,
> Allain
> 

The log you include is exactly how it's supposed to work in the case of
a hash collision: whichever client REQUESTs the address first gets it,
and the other one gets a NAK and has to try again.

As to your question: the code doesn't have enough information to
distinguish between the _same_ client sending repeated DHCPDISCOVERs and
two or more clients with MAC addresses that hash to the same value
sending DHCPDISCOVERS.

The code you've found has a different function: in OPT_CONSEC_ADDR mode,
the address offered is simply the first free address in the dhcp-range,
so any two or more clients asking simultaneously would be offered the
same address. In effect, every multiple-client contention would be like
the hash-collision case. This code avoids that as the first client gets
offered the first free address, and that address is soft-reserved via
the ping-results table so that if another client (with different hash)
arrives before the first has had chance to REQUEST the address, the
second client gets offered an address one larger. If there are two
clients which hash to the same value, this mechanism doesn't work, and
they have to fight it out via a race to DHCPREQUEST, in the same way as
when address hashes collide in the NOT OPT_CONSEC_ADDR case. So,  when
OPT_CONSEC_ADDR is set, this mechanism make the race to DHCPREQUEST a
rare event rather than the common case, just like when OPT_CONSEC_ADDR
is NOT set.


Cheers,

Simon.










More information about the Dnsmasq-discuss mailing list