Skip to content

Commit

Permalink
Add a heuristic to detect when server ignores dhcp renews.
Browse files Browse the repository at this point in the history
If we get no response to three renews (unicast), switch to sending
rebinds (broadcast).  Servers are supposed to always reply with
a DHCPACK or DHCPNAK even if the server doesn't update its internal
lease duration database, so this behavior should be RFC compliant.
  • Loading branch information
niklata committed Oct 19, 2020
1 parent f436589 commit 32bc422
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/ndhc.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct client_state_t {
int epollFd, signalFd, listenFd, arpFd, nlFd, rfkillFd;
int server_arp_sent, router_arp_sent;
uint32_t nlPortId;
unsigned int num_dhcp_requests;
unsigned int num_dhcp_requests, num_dhcp_renews;
uint32_t clientAddr, serverAddr, srcAddr, routerAddr;
uint32_t lease, xid;
uint8_t routerArp[6], serverArp[6];
Expand Down
8 changes: 7 additions & 1 deletion src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
#include "netlink.h"
#include "coroutine.h"

#define IGNORED_RENEWS_BEFORE_REBIND 3

#define SEL_SUCCESS 0
#define SEL_FAIL -1

Expand Down Expand Up @@ -78,6 +80,7 @@ static void reinit_shared_deconfig(struct client_state_t cs[static 1])
cs->xid = nk_random_u32(&cs->rnd_state);
cs->clientAddr = 0;
cs->num_dhcp_requests = 0;
cs->num_dhcp_renews = 0;
cs->server_arp_sent = 0;
cs->router_arp_sent = 0;
cs->server_arp_state = ARP_QUERY;
Expand Down Expand Up @@ -150,7 +153,7 @@ static int renewing_timeout(struct client_state_t cs[static 1],
long long nowts)
{
long long rbt = cs->leaseStartTime + cs->rebindTime * 1000;
if (nowts >= rbt)
if (nowts >= rbt || cs->num_dhcp_renews >= IGNORED_RENEWS_BEFORE_REBIND)
return rebinding_timeout(cs, nowts);
start_dhcp_listen(cs);
if (send_renew(cs) < 0) {
Expand All @@ -159,6 +162,7 @@ static int renewing_timeout(struct client_state_t cs[static 1],
return BTO_HARDFAIL;
}
cs->sent_renew_or_rebind = true;
++cs->num_dhcp_renews;
long long ts0 = nowts + (50 + nk_random_u32(&cs->rnd_state) % 20) * 1000;
cs->dhcp_wake_ts = ts0 < rbt ? ts0 : rbt;
return BTO_WAIT;
Expand Down Expand Up @@ -230,6 +234,7 @@ static int extend_packet(struct client_state_t cs[static 1],
if (!validate_serverid(cs, packet, "a DHCP ACK"))
return ANP_IGNORE;
cs->sent_renew_or_rebind = false;
cs->num_dhcp_renews = 0;
get_leasetime(cs, packet);

// Did we receive a lease with a different IP than we had before?
Expand All @@ -253,6 +258,7 @@ static int extend_packet(struct client_state_t cs[static 1],
if (!validate_serverid(cs, packet, "a DHCP NAK"))
return ANP_IGNORE;
cs->sent_renew_or_rebind = false;
cs->num_dhcp_renews = 0;
log_line("%s: Our request was rejected. Searching for a new lease...",
client_config.interface);
reinit_selecting(cs, 3000);
Expand Down

0 comments on commit 32bc422

Please sign in to comment.