1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-10 01:17:44 +03:00

sd-dhcp-client: add fallback subnet masks

The DHCP RFC does not require the DHCP server to send a subnet mask, so if it
is missing, let's try to use the default subnet masks based on address class.
In case the class the address belongs to does not have a default subnet mask,
we fail as before.

Also improve logging when handling invalid dhcp messages, and simply ignore them
rather than stop the whole dhcp client.
This commit is contained in:
Tom Gundersen 2014-03-19 16:05:44 +01:00
parent 022446adf9
commit 9e64dd7276
3 changed files with 69 additions and 13 deletions

View File

@ -57,5 +57,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file);
int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret);
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);
DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref);
#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp)

View File

@ -673,8 +673,10 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
return r;
r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
if (r != DHCP_OFFER)
if (r != DHCP_OFFER) {
log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
return -ENOMSG;
}
lease->next_server = offer->siaddr;
@ -682,9 +684,21 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
if (lease->address == INADDR_ANY ||
lease->server_address == INADDR_ANY ||
lease->subnet_mask == INADDR_ANY ||
lease->lifetime == 0)
lease->lifetime == 0) {
log_dhcp_client(client, "receieved lease lacks address, server "
"address or lease lifetime, ignoring");
return -ENOMSG;
}
if (lease->subnet_mask == INADDR_ANY) {
r = dhcp_lease_set_default_subnet_mask(lease);
if (r < 0) {
log_dhcp_client(client, "receieved lease lacks subnet "
"mask, and a fallback one can not be "
"generated, ignoring");
return -ENOMSG;
}
}
client->lease = lease;
lease = NULL;
@ -709,8 +723,10 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
return DHCP_EVENT_NO_LEASE;
}
if (r != DHCP_ACK)
if (r != DHCP_ACK) {
log_dhcp_client(client, "receieved message was not an ACK, ignoring");
return -ENOMSG;
}
lease->next_server = ack->siaddr;
@ -718,8 +734,21 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
if (lease->address == INADDR_ANY ||
lease->server_address == INADDR_ANY ||
lease->subnet_mask == INADDR_ANY || lease->lifetime == 0)
lease->lifetime == 0) {
log_dhcp_client(client, "receieved lease lacks address, server "
"address or lease lifetime, ignoring");
return -ENOMSG;
}
if (lease->subnet_mask == INADDR_ANY) {
r = dhcp_lease_set_default_subnet_mask(lease);
if (r < 0) {
log_dhcp_client(client, "receieved lease lacks subnet "
"mask, and a fallback one can not be "
"generated, ignoring");
return -ENOMSG;
}
}
r = DHCP_EVENT_IP_ACQUIRE;
if (client->lease) {
@ -940,7 +969,9 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
client->event_priority);
if (r < 0)
goto error;
}
} else if (r == -ENOMSG)
/* invalid message, let's ignore it */
return 0;
break;
@ -950,7 +981,6 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
case DHCP_STATE_REBINDING:
r = client_handle_ack(client, message, len);
if (r == DHCP_EVENT_NO_LEASE) {
client->timeout_resend =
@ -967,9 +997,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
}
goto error;
}
if (r >= 0) {
} else if (r >= 0) {
client->timeout_resend =
sd_event_source_unref(client->timeout_resend);
@ -994,9 +1022,9 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
client->receive_message =
sd_event_source_unref(client->receive_message);
client->fd = safe_close(client->fd);
}
r = 0;
} else if (r == -ENOMSG)
/* invalid message, let's ignore it */
return 0;
break;

View File

@ -481,3 +481,29 @@ int dhcp_lease_load(const char *lease_file, sd_dhcp_lease **ret) {
return 0;
}
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) {
uint32_t address;
assert(lease);
assert(lease->address != INADDR_ANY);
address = be32toh(lease->address);
/* fall back to the default subnet masks based on address class */
if ((address >> 31) == 0x0)
/* class A, leading bits: 0 */
lease->subnet_mask = htobe32(0xff000000);
else if ((address >> 30) == 0x2)
/* class B, leading bits 10 */
lease->subnet_mask = htobe32(0xffff0000);
else if ((address >> 29) == 0x6)
/* class C, leading bits 110 */
lease->subnet_mask = htobe32(0xffffff00);
else
/* class D or E, no default mask. give up */
return -ERANGE;
return 0;
}