sd-dhcp-client: split out client_parse_message()

No functional change, just refactoring and preparation for later
commits.
This commit is contained in:
Yu Watanabe 2023-09-21 04:39:49 +09:00
parent db849df5a1
commit f9edbb80e9
2 changed files with 70 additions and 51 deletions

View file

@ -73,6 +73,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
res = sd_dhcp_client_start(client);
assert_se(IN_SET(res, 0, -EINPROGRESS));
client->xid = 2;
client->state = DHCP_STATE_SELECTING;
(void) client_handle_offer(client, (DHCPMessage*) data, size);

View file

@ -1546,10 +1546,20 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
return client_initialize_time_events(client);
}
static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
static int client_parse_message(
sd_dhcp_client *client,
DHCPMessage *message,
size_t len,
sd_dhcp_lease **ret) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_free_ char *error_message = NULL;
int r;
assert(client);
assert(message);
assert(ret);
r = dhcp_lease_new(&lease);
if (r < 0)
return r;
@ -1562,28 +1572,66 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_
return r;
}
r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL);
if (r != DHCP_OFFER)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received message was not an OFFER, ignoring");
r = dhcp_option_parse(message, len, dhcp_lease_parse_options, lease, &error_message);
if (r < 0)
return log_dhcp_client_errno(client, r, "Failed to parse DHCP options, ignoring: %m");
lease->next_server = offer->siaddr;
lease->address = offer->yiaddr;
switch (client->state) {
case DHCP_STATE_SELECTING:
if (r != DHCP_OFFER)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received message was not an OFFER, ignoring.");
if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
lease->lifetime = client->fallback_lease_lifetime;
if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
lease->lifetime = client->fallback_lease_lifetime;
break;
case DHCP_STATE_REBOOTING:
case DHCP_STATE_REQUESTING:
case DHCP_STATE_RENEWING:
case DHCP_STATE_REBINDING:
if (r == DHCP_NAK)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"NAK: %s", strna(error_message));
if (r != DHCP_ACK)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received message was not an ACK, ignoring.");
break;
default:
assert_not_reached();
}
lease->next_server = message->siaddr;
lease->address = message->yiaddr;
if (lease->address == 0 ||
lease->server_address == 0 ||
lease->lifetime == 0)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received lease lacks address, server address or lease lifetime, ignoring");
"received lease lacks address, server address or lease lifetime, ignoring.");
r = dhcp_lease_set_default_subnet_mask(lease);
if (r < 0)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received lease lacks subnet mask, and a fallback one cannot be generated, ignoring.");
*ret = TAKE_PTR(lease);
return 0;
}
static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
int r;
assert(client);
assert(message);
r = client_parse_message(client, message, len, &lease);
if (r < 0)
return r;
dhcp_lease_unref_and_replace(client->lease, lease);
if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
@ -1643,47 +1691,17 @@ static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) {
return true;
}
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_free_ char *error_message = NULL;
int r;
r = dhcp_lease_new(&lease);
assert(client);
assert(message);
r = client_parse_message(client, message, len, &lease);
if (r < 0)
return r;
if (client->client_id_len > 0) {
r = dhcp_lease_set_client_id(lease,
(uint8_t *) &client->client_id,
client->client_id_len);
if (r < 0)
return r;
}
r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message);
if (r == DHCP_NAK)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"NAK: %s", strna(error_message));
if (r != DHCP_ACK)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received message was not an ACK, ignoring");
lease->next_server = ack->siaddr;
lease->address = ack->yiaddr;
if (lease->address == INADDR_ANY ||
lease->server_address == INADDR_ANY ||
lease->lifetime == 0)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received lease lacks address, server address or lease lifetime, ignoring");
r = dhcp_lease_set_default_subnet_mask(lease);
if (r < 0)
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
"received lease lacks subnet mask, and a fallback one cannot be generated, ignoring.");
if (!client->lease)
r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
else if (lease_equal(client->lease, lease))
@ -1851,10 +1869,10 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
case DHCP_STATE_SELECTING:
r = client_handle_offer(client, message, len);
if (r == -ENOMSG)
return 0; /* invalid message, let's ignore it */
if (r < 0)
if (ERRNO_IS_NEG_RESOURCE(r))
goto error;
if (r < 0)
return 0; /* invalid message, let's ignore it */
r = client_enter_requesting(client);
break;
@ -1865,8 +1883,8 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
case DHCP_STATE_REBINDING:
r = client_handle_ack(client, message, len);
if (r == -ENOMSG)
return 0; /* invalid message, let's ignore it */
if (ERRNO_IS_NEG_RESOURCE(r))
goto error;
if (r == -EADDRNOTAVAIL) {
/* got a NAK, let's restart the client */
client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
@ -1886,7 +1904,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i
return 0;
}
if (r < 0)
goto error;
return 0; /* invalid message, let's ignore it */
r = client_enter_bound(client, r);
break;