serverid checks for RENEW and REBIND DHCP(ACK|NAK) were too strict.

Use the same test that is already used for the DHCPACK sent by
the server in the REQUESTING state.
This commit is contained in:
Nicholas J. Kain 2020-10-21 06:47:11 -04:00
parent b07ebb60a2
commit d58338b70b

View File

@ -180,28 +180,6 @@ static int bound_timeout(struct client_state_t cs[static 1], long long nowts)
return renewing_timeout(cs, nowts); return renewing_timeout(cs, nowts);
} }
static int validate_serverid(struct client_state_t cs[static 1],
struct dhcpmsg packet[static 1],
const char typemsg[static 1])
{
int found;
uint32_t sid = get_option_serverid(packet, &found);
if (!found) {
log_line("%s: Received %s with no server id. Ignoring it.",
client_config.interface, typemsg);
return 0;
}
if (cs->serverAddr != sid) {
char svrbuf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(struct in_addr){.s_addr=sid},
svrbuf, sizeof svrbuf);
log_line("%s: Received %s with an unexpected server id: %s. Ignoring it.",
client_config.interface, typemsg, svrbuf);
return 0;
}
return 1;
}
static void get_leasetime(struct client_state_t cs[static 1], static void get_leasetime(struct client_state_t cs[static 1],
struct dhcpmsg packet[static 1]) struct dhcpmsg packet[static 1])
{ {
@ -225,13 +203,39 @@ static void get_leasetime(struct client_state_t cs[static 1],
cs->dhcp_wake_ts = cs->leaseStartTime + cs->renewTime * 1000; cs->dhcp_wake_ts = cs->leaseStartTime + cs->renewTime * 1000;
} }
static bool validate_acknak(struct client_state_t cs[static 1],
struct dhcpmsg packet[static 1],
const char typemsg[static 1],
uint32_t srcaddr)
{
// Don't validate the server id. Instead validate that the
// yiaddr matches. Some networks have multiple servers
// that don't respect the serverid that was specified in
// our DHCPREQUEST.
if (memcmp(&packet->yiaddr, &cs->clientAddr, 4))
return false;
int found;
uint32_t sid = get_option_serverid(packet, &found);
if (!found) {
log_line("%s: Received %s with no server id. Ignoring it.",
client_config.interface, typemsg);
return false;
}
if (cs->serverAddr != sid) {
cs->serverAddr = sid;
cs->srcAddr = srcaddr;
}
return true;
}
static int extend_packet(struct client_state_t cs[static 1], static int extend_packet(struct client_state_t cs[static 1],
struct dhcpmsg packet[static 1], uint8_t msgtype, struct dhcpmsg packet[static 1], uint8_t msgtype,
uint32_t srcaddr) uint32_t srcaddr)
{ {
(void)srcaddr; (void)srcaddr;
if (msgtype == DHCPACK) { if (msgtype == DHCPACK) {
if (!validate_serverid(cs, packet, "a DHCP ACK")) if (!validate_acknak(cs, packet, "DHCPACK", srcaddr))
return ANP_IGNORE; return ANP_IGNORE;
cs->sent_renew_or_rebind = false; cs->sent_renew_or_rebind = false;
cs->num_dhcp_renews = 0; cs->num_dhcp_renews = 0;
@ -255,7 +259,7 @@ static int extend_packet(struct client_state_t cs[static 1],
return ANP_SUCCESS; return ANP_SUCCESS;
} }
} else if (msgtype == DHCPNAK) { } else if (msgtype == DHCPNAK) {
if (!validate_serverid(cs, packet, "a DHCP NAK")) if (!validate_acknak(cs, packet, "DHCPNAK", srcaddr))
return ANP_IGNORE; return ANP_IGNORE;
cs->sent_renew_or_rebind = false; cs->sent_renew_or_rebind = false;
cs->num_dhcp_renews = 0; cs->num_dhcp_renews = 0;
@ -298,33 +302,19 @@ static int selecting_packet(struct client_state_t cs[static 1],
client_config.interface, clibuf, svrbuf, srcbuf); client_config.interface, clibuf, svrbuf, srcbuf);
return ANP_SUCCESS; return ANP_SUCCESS;
} else if (is_requesting && msgtype == DHCPACK) { } else if (is_requesting && msgtype == DHCPACK) {
// Don't validate the server id. Instead validate that the if (!validate_acknak(cs, packet, "DHCPACK", srcaddr))
// yiaddr matches. Some networks have multiple servers return ANP_IGNORE;
// that don't respect the serverid that was specified in get_leasetime(cs, packet);
// our DHCPREQUEST.
if (!memcmp(&packet->yiaddr, &cs->clientAddr, 4)) {
uint32_t sid = get_option_serverid(packet, &found);
if (!found) {
log_line("%s: Invalid offer received: it didn't have a server id.",
client_config.interface);
return ANP_IGNORE;
}
if (cs->serverAddr != sid) {
cs->serverAddr = sid;
cs->srcAddr = srcaddr;
}
get_leasetime(cs, packet);
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->clientAddr}, inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->clientAddr},
clibuf, sizeof clibuf); clibuf, sizeof clibuf);
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->serverAddr}, inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->serverAddr},
svrbuf, sizeof svrbuf); svrbuf, sizeof svrbuf);
inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->srcAddr}, inet_ntop(AF_INET, &(struct in_addr){.s_addr=cs->srcAddr},
srcbuf, sizeof srcbuf); srcbuf, sizeof srcbuf);
log_line("%s: Received ACK: %s from server %s via %s. Validating...", log_line("%s: Received ACK: %s from server %s via %s. Validating...",
client_config.interface, clibuf, svrbuf, srcbuf); client_config.interface, clibuf, svrbuf, srcbuf);
return ANP_CHECK_IP; return ANP_CHECK_IP;
}
} }
return ANP_IGNORE; return ANP_IGNORE;
} }