mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
DHCPv4: do ICMP-ping check in all cases other that current lease.
This commit is contained in:
@@ -108,6 +108,11 @@ version 2.77
|
|||||||
the internal interfaces of a router. Thanks to
|
the internal interfaces of a router. Thanks to
|
||||||
Vladislav Grishenko for the patch.
|
Vladislav Grishenko for the patch.
|
||||||
|
|
||||||
|
Do ICMP-ping check for address-in-use for DHCPv4 when
|
||||||
|
the client specifies an address in DHCPDISCOVER, and when
|
||||||
|
an address in configured locally. Thanks to Alin Năstac
|
||||||
|
for spotting the problem.
|
||||||
|
|
||||||
|
|
||||||
version 2.76
|
version 2.76
|
||||||
Include 0.0.0.0/8 in DNS rebind checks. This range
|
Include 0.0.0.0/8 in DNS rebind checks. This range
|
||||||
|
|||||||
134
src/dhcp.c
134
src/dhcp.c
@@ -643,6 +643,66 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if and address is in use by sending ICMP ping.
|
||||||
|
This wrapper handles a cache and load-limiting.
|
||||||
|
Return is NULL is address in use, or a pointer to a cache entry
|
||||||
|
recording that it isn't. */
|
||||||
|
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr, unsigned int hash)
|
||||||
|
{
|
||||||
|
static struct ping_result dummy;
|
||||||
|
struct ping_result *r, *victim = NULL;
|
||||||
|
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
|
||||||
|
((float)PING_WAIT)));
|
||||||
|
|
||||||
|
/* check if we failed to ping addr sometime in the last
|
||||||
|
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
||||||
|
This avoids problems when a stupid client bangs
|
||||||
|
on us repeatedly. As a final check, if we did more
|
||||||
|
than 60% of the possible ping checks in the last
|
||||||
|
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
|
||||||
|
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
||||||
|
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
||||||
|
victim = r; /* old record */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
if (r->addr.s_addr == addr.s_addr)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* didn't find cached entry */
|
||||||
|
if ((count >= max) || option_bool(OPT_NO_PING))
|
||||||
|
{
|
||||||
|
/* overloaded, or configured not to check, return "not in use" */
|
||||||
|
dummy.hash = 0;
|
||||||
|
return &dummy;
|
||||||
|
}
|
||||||
|
else if (icmp_ping(addr))
|
||||||
|
return NULL; /* address in use. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* at this point victim may hold an expired record */
|
||||||
|
if (!victim)
|
||||||
|
{
|
||||||
|
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
||||||
|
{
|
||||||
|
victim->next = daemon->ping_results;
|
||||||
|
daemon->ping_results = victim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* record that this address is OK for 30s
|
||||||
|
without more ping checks */
|
||||||
|
if (victim)
|
||||||
|
{
|
||||||
|
victim->addr = addr;
|
||||||
|
victim->time = now;
|
||||||
|
victim->hash = hash;
|
||||||
|
}
|
||||||
|
return victim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int address_allocate(struct dhcp_context *context,
|
int address_allocate(struct dhcp_context *context,
|
||||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||||
struct dhcp_netid *netids, time_t now)
|
struct dhcp_netid *netids, time_t now)
|
||||||
@@ -661,6 +721,10 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
for (j = 0, i = 0; i < hw_len; i++)
|
for (j = 0, i = 0; i < hw_len; i++)
|
||||||
j = hwaddr[i] + (j << 6) + (j << 16) - j;
|
j = hwaddr[i] + (j << 6) + (j << 16) - j;
|
||||||
|
|
||||||
|
/* j == 0 is marker */
|
||||||
|
if (j == 0)
|
||||||
|
j = 1;
|
||||||
|
|
||||||
for (pass = 0; pass <= 1; pass++)
|
for (pass = 0; pass <= 1; pass++)
|
||||||
for (c = context; c; c = c->current)
|
for (c = context; c; c = c->current)
|
||||||
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
if (c->flags & (CONTEXT_STATIC | CONTEXT_PROXY))
|
||||||
@@ -697,67 +761,25 @@ int address_allocate(struct dhcp_context *context,
|
|||||||
(!IN_CLASSC(ntohl(addr.s_addr)) ||
|
(!IN_CLASSC(ntohl(addr.s_addr)) ||
|
||||||
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
|
((ntohl(addr.s_addr) & 0xff) != 0xff && ((ntohl(addr.s_addr) & 0xff) != 0x0))))
|
||||||
{
|
{
|
||||||
struct ping_result *r, *victim = NULL;
|
struct ping_result *r;
|
||||||
int count, max = (int)(0.6 * (((float)PING_CACHE_TIME)/
|
|
||||||
((float)PING_WAIT)));
|
|
||||||
|
|
||||||
*addrp = addr;
|
if ((r = do_icmp_ping(now, addr, j)))
|
||||||
|
{
|
||||||
/* check if we failed to ping addr sometime in the last
|
/* consec-ip mode: we offered this address for another client
|
||||||
PING_CACHE_TIME seconds. If so, assume the same situation still exists.
|
(different hash) recently, don't offer it to this one. */
|
||||||
This avoids problems when a stupid client bangs
|
if (!option_bool(OPT_CONSEC_ADDR) || r->hash == j)
|
||||||
on us repeatedly. As a final check, if we did more
|
|
||||||
than 60% of the possible ping checks in the last
|
|
||||||
PING_CACHE_TIME, we are in high-load mode, so don't do any more. */
|
|
||||||
for (count = 0, r = daemon->ping_results; r; r = r->next)
|
|
||||||
if (difftime(now, r->time) > (float)PING_CACHE_TIME)
|
|
||||||
victim = r; /* old record */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!r)
|
|
||||||
{
|
|
||||||
if ((count < max) && !option_bool(OPT_NO_PING) && icmp_ping(addr))
|
|
||||||
{
|
{
|
||||||
/* address in use: perturb address selection so that we are
|
*addrp = addr;
|
||||||
less likely to try this address again. */
|
|
||||||
if (!option_bool(OPT_CONSEC_ADDR))
|
|
||||||
c->addr_epoch++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* at this point victim may hold an expired record */
|
|
||||||
if (!victim)
|
|
||||||
{
|
|
||||||
if ((victim = whine_malloc(sizeof(struct ping_result))))
|
|
||||||
{
|
|
||||||
victim->next = daemon->ping_results;
|
|
||||||
daemon->ping_results = victim;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* record that this address is OK for 30s
|
|
||||||
without more ping checks */
|
|
||||||
if (victim)
|
|
||||||
{
|
|
||||||
victim->addr = addr;
|
|
||||||
victim->time = now;
|
|
||||||
victim->hash = j;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* address in use: perturb address selection so that we are
|
||||||
|
less likely to try this address again. */
|
||||||
|
if (!option_bool(OPT_CONSEC_ADDR))
|
||||||
|
c->addr_epoch++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||||
|
|||||||
@@ -1292,6 +1292,8 @@ struct dhcp_context *address_available(struct dhcp_context *context,
|
|||||||
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
struct dhcp_context *narrow_context(struct dhcp_context *context,
|
||||||
struct in_addr taddr,
|
struct in_addr taddr,
|
||||||
struct dhcp_netid *netids);
|
struct dhcp_netid *netids);
|
||||||
|
struct ping_result *do_icmp_ping(time_t now, struct in_addr addr,
|
||||||
|
unsigned int hash);
|
||||||
int address_allocate(struct dhcp_context *context,
|
int address_allocate(struct dhcp_context *context,
|
||||||
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
struct in_addr *addrp, unsigned char *hwaddr, int hw_len,
|
||||||
struct dhcp_netid *netids, time_t now);
|
struct dhcp_netid *netids, time_t now);
|
||||||
|
|||||||
@@ -1029,6 +1029,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
else if (have_config(config, CONFIG_DECLINED) &&
|
else if (have_config(config, CONFIG_DECLINED) &&
|
||||||
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
|
difftime(now, config->decline_time) < (float)DECLINE_BACKOFF)
|
||||||
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
|
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it was previously declined"), addrs);
|
||||||
|
else if (!do_icmp_ping(now, config->addr, 0))
|
||||||
|
my_syslog(MS_DHCP | LOG_WARNING, _("not using configured address %s because it is in use by another host"), addrs);
|
||||||
else
|
else
|
||||||
conf = config->addr;
|
conf = config->addr;
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1043,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
|
|||||||
!config_find_by_address(daemon->dhcp_conf, lease->addr))
|
!config_find_by_address(daemon->dhcp_conf, lease->addr))
|
||||||
mess->yiaddr = lease->addr;
|
mess->yiaddr = lease->addr;
|
||||||
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
|
else if (opt && address_available(context, addr, tagif_netid) && !lease_find_by_addr(addr) &&
|
||||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
!config_find_by_address(daemon->dhcp_conf, addr) && do_icmp_ping(now, addr, 0))
|
||||||
mess->yiaddr = addr;
|
mess->yiaddr = addr;
|
||||||
else if (emac_len == 0)
|
else if (emac_len == 0)
|
||||||
message = _("no unique-id");
|
message = _("no unique-id");
|
||||||
|
|||||||
Reference in New Issue
Block a user