sd-dhcp-client: use dhcp_client_parse_message()
This also unify two IO event source handlers.
This commit is contained in:
@@ -12,15 +12,13 @@
|
||||
#include "dhcp-client-internal.h"
|
||||
#include "dhcp-client-send.h"
|
||||
#include "dhcp-lease-internal.h"
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp-packet.h"
|
||||
#include "dns-domain.h"
|
||||
#include "errno-util.h"
|
||||
#include "event-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "iovec-wrapper.h"
|
||||
#include "memory-util.h"
|
||||
#include "ip-util.h"
|
||||
#include "network-common.h"
|
||||
#include "random-util.h"
|
||||
#include "set.h"
|
||||
@@ -131,12 +129,6 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
|
||||
return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option));
|
||||
}
|
||||
|
||||
static int client_request_contains(sd_dhcp_client *client, uint8_t option) {
|
||||
assert(client);
|
||||
|
||||
return set_contains(client->req_opts, UINT8_TO_PTR(option));
|
||||
}
|
||||
|
||||
int sd_dhcp_client_set_request_address(
|
||||
sd_dhcp_client *client,
|
||||
const struct in_addr *last_addr) {
|
||||
@@ -947,195 +939,6 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata)
|
||||
return client_timeout_resend(s, usec, userdata);
|
||||
}
|
||||
|
||||
static int dhcp_option_parse_and_verify(
|
||||
sd_dhcp_client *client,
|
||||
DHCPMessage *message,
|
||||
size_t len,
|
||||
sd_dhcp_lease *lease) {
|
||||
|
||||
_cleanup_free_ char *error_message = NULL;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(message);
|
||||
assert(lease);
|
||||
|
||||
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");
|
||||
|
||||
switch (client->state) {
|
||||
case DHCP_STATE_SELECTING:
|
||||
if (r == DHCP_ACK) {
|
||||
if (!client->rapid_commit)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
|
||||
"received unexpected ACK, ignoring.");
|
||||
if (!lease->rapid_commit)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
|
||||
"received rapid ACK without Rapid Commit option, ignoring.");
|
||||
} else if (r == DHCP_OFFER) {
|
||||
if (lease->rapid_commit) {
|
||||
/* Some RFC incompliant servers provides an OFFER with a rapid commit option.
|
||||
* See https://github.com/systemd/systemd/issues/29904.
|
||||
* Let's support such servers gracefully. */
|
||||
log_dhcp_client(client, "received OFFER with Rapid Commit option, ignoring.");
|
||||
lease->rapid_commit = false;
|
||||
}
|
||||
if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0)
|
||||
lease->lifetime = client->fallback_lease_lifetime;
|
||||
} else
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
|
||||
"received unexpected message, ignoring.");
|
||||
|
||||
break;
|
||||
|
||||
case DHCP_STATE_REBOOTING:
|
||||
case DHCP_STATE_REQUESTING:
|
||||
case DHCP_STATE_RENEWING:
|
||||
case DHCP_STATE_REBINDING:
|
||||
if (r == DHCP_NAK) {
|
||||
if (client->lease && client->lease->server_address != lease->server_address)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG),
|
||||
"NAK from unexpected server, ignoring: %s",
|
||||
strna(error_message));
|
||||
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.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bootp_option_parse_and_verify(
|
||||
sd_dhcp_client *client,
|
||||
DHCPMessage *message,
|
||||
size_t len,
|
||||
sd_dhcp_lease *lease) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(message);
|
||||
assert(lease);
|
||||
|
||||
r = dhcp_option_parse(message, len, dhcp_lease_parse_options, lease, /* ret_error_message= */ NULL);
|
||||
if (r == -ENOMSG)
|
||||
r = DHCP_ACK; /* BOOTP messages don't have a DHCP message type option */
|
||||
else if (r < 0)
|
||||
return log_dhcp_client_errno(client, r, "Failed to parse BOOTP options, ignoring: %m");
|
||||
else
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG), "Received unexpected message, ignoring.");
|
||||
|
||||
log_dhcp_client(client, "BOOTP identified, using infinite lease. BOOTP siaddr=(%#x), DHCP Server Identifier=(%#x)",
|
||||
message->siaddr, lease->server_address);
|
||||
|
||||
lease->lifetime = USEC_INFINITY;
|
||||
lease->address = message->yiaddr;
|
||||
if (lease->server_address == 0)
|
||||
lease->server_address = message->siaddr;
|
||||
|
||||
/* BOOTP protocol does not have any OFFER and REQUEST process. Hence, it is mostly equivalent to
|
||||
* Rapid Commit process in DHCP. */
|
||||
lease->rapid_commit = true;
|
||||
|
||||
if (lease->address == 0)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(ENOMSG), "received lease lacks address, ignoring.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(message);
|
||||
assert(ret);
|
||||
|
||||
r = dhcp_lease_new(&lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_dhcp_client_id_is_set(&client->client_id)) {
|
||||
r = dhcp_lease_set_client_id(lease, &client->client_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (client->bootp)
|
||||
r = bootp_option_parse_and_verify(client, message, len, lease);
|
||||
else
|
||||
r = dhcp_option_parse_and_verify(client, message, len, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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.");
|
||||
|
||||
/* RFC 8925 section 3.2
|
||||
* If the client did not include the IPv6-Only Preferred option code in the Parameter Request List in
|
||||
* the DHCPDISCOVER or DHCPREQUEST message, it MUST ignore the IPv6-Only Preferred option in any
|
||||
* messages received from the server. */
|
||||
if (lease->ipv6_only_preferred_usec > 0 &&
|
||||
!client_request_contains(client, SD_DHCP_OPTION_IPV6_ONLY_PREFERRED)) {
|
||||
log_dhcp_client(client, "Received message with unrequested IPv6-only preferred option, ignoring the option.");
|
||||
lease->ipv6_only_preferred_usec = 0;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_handle_offer_or_rapid_ack(sd_dhcp_client *client, DHCPMessage *message, size_t len, const triple_timestamp *timestamp) {
|
||||
_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_set_timestamp(lease, timestamp);
|
||||
|
||||
dhcp_lease_unref_and_replace(client->lease, lease);
|
||||
|
||||
if (client->lease->rapid_commit) {
|
||||
log_dhcp_client(client, "ACK");
|
||||
return SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
|
||||
}
|
||||
|
||||
if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
|
||||
return -ENOMSG;
|
||||
|
||||
log_dhcp_client(client, "OFFER");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_enter_requesting(sd_dhcp_client *client) {
|
||||
assert(client);
|
||||
assert(client->lease);
|
||||
@@ -1186,32 +989,6 @@ 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 *message, size_t len, const triple_timestamp *timestamp) {
|
||||
_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_set_timestamp(lease, timestamp);
|
||||
|
||||
if (!client->lease)
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
|
||||
else if (lease_equal(client->lease, lease))
|
||||
r = SD_DHCP_CLIENT_EVENT_RENEW;
|
||||
else
|
||||
r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
|
||||
|
||||
dhcp_lease_unref_and_replace(client->lease, lease);
|
||||
|
||||
log_dhcp_client(client, "ACK");
|
||||
return r;
|
||||
}
|
||||
|
||||
static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||
usec_t time_now;
|
||||
int r;
|
||||
@@ -1319,14 +1096,32 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_enter_bound(sd_dhcp_client *client, int notify_event) {
|
||||
static int client_enter_bound(sd_dhcp_client *client, sd_dhcp_lease *lease) {
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(client->lease);
|
||||
assert(lease);
|
||||
|
||||
if (IN_SET(client->state, DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING))
|
||||
int notify_event;
|
||||
switch (client->state) {
|
||||
case DHCP_STATE_SELECTING:
|
||||
case DHCP_STATE_REQUESTING:
|
||||
case DHCP_STATE_REBOOTING:
|
||||
notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
|
||||
break;
|
||||
case DHCP_STATE_RENEWING:
|
||||
case DHCP_STATE_REBINDING:
|
||||
assert(client->lease);
|
||||
if (lease_equal(client->lease, lease))
|
||||
notify_event = SD_DHCP_CLIENT_EVENT_RENEW;
|
||||
else
|
||||
notify_event = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
unref_and_replace_new_ref(client->lease, lease, sd_dhcp_lease_ref, sd_dhcp_lease_unref);
|
||||
|
||||
client_disable_event_sources(client);
|
||||
|
||||
@@ -1344,136 +1139,51 @@ static int client_enter_bound(sd_dhcp_client *client, int notify_event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_verify_message_header(sd_dhcp_client *client, DHCPMessage *message, size_t len) {
|
||||
const uint8_t *expected_chaddr = NULL;
|
||||
uint8_t expected_hlen = 0;
|
||||
|
||||
assert(client);
|
||||
assert(message);
|
||||
|
||||
if (len < sizeof(DHCPMessage))
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Too small to be a DHCP message, ignoring.");
|
||||
|
||||
if (be32toh(message->magic) != DHCP_MAGIC_COOKIE)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Not a DHCP message, ignoring.");
|
||||
|
||||
if (message->op != BOOTREPLY)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Not a BOOTREPLY message, ignoring.");
|
||||
|
||||
if (message->htype != client->arp_type)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Packet type does not match client type, ignoring.");
|
||||
|
||||
if (client->arp_type == ARPHRD_ETHER) {
|
||||
expected_hlen = ETH_ALEN;
|
||||
expected_chaddr = client->hw_addr.bytes;
|
||||
}
|
||||
|
||||
if (message->hlen != expected_hlen)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received packet hlen (%u) does not match expected (%u), ignoring.",
|
||||
message->hlen, expected_hlen);
|
||||
|
||||
if (memcmp_safe(message->chaddr, expected_chaddr, expected_hlen))
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received chaddr does not match expected, ignoring.");
|
||||
|
||||
if (be32toh(message->xid) != client->xid)
|
||||
return log_dhcp_client_errno(client, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received xid (%u) does not match expected (%u), ignoring.",
|
||||
be32toh(message->xid), client->xid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, size_t len, const triple_timestamp *timestamp) {
|
||||
static int client_handle_message(sd_dhcp_client *client, const struct iovec *iov, const triple_timestamp *timestamp) {
|
||||
DHCP_CLIENT_DONT_DESTROY(client);
|
||||
int r;
|
||||
|
||||
assert(client);
|
||||
assert(message);
|
||||
assert(timestamp);
|
||||
assert(iov);
|
||||
|
||||
if (client_verify_message_header(client, message, len) < 0)
|
||||
return 0;
|
||||
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
|
||||
r = dhcp_client_parse_message(client, iov, &lease);
|
||||
if (ERRNO_IS_NEG_RESOURCE(r))
|
||||
return r;
|
||||
if (r < 0)
|
||||
return 0; /* Ignore all parse errors. */
|
||||
|
||||
switch (client->state) {
|
||||
case DHCP_STATE_SELECTING:
|
||||
switch (r) {
|
||||
|
||||
r = client_handle_offer_or_rapid_ack(client, message, len, timestamp);
|
||||
if (ERRNO_IS_NEG_RESOURCE(r))
|
||||
return r;
|
||||
if (r == -EADDRNOTAVAIL)
|
||||
/* got a rapid NAK, let's restart the client */
|
||||
return client_restart(client);
|
||||
if (r < 0)
|
||||
return 0; /* invalid message, let's ignore it */
|
||||
|
||||
if (client->lease->rapid_commit)
|
||||
/* got a successful rapid commit */
|
||||
return client_enter_bound(client, r);
|
||||
case DHCP_OFFER:
|
||||
dhcp_lease_set_timestamp(lease, timestamp);
|
||||
|
||||
unref_and_replace_new_ref(client->lease, lease, sd_dhcp_lease_ref, sd_dhcp_lease_unref);
|
||||
if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0)
|
||||
return 0; /* networkd refused the server, ignoring the message. */
|
||||
if (client->state == DHCP_STATE_STOPPED)
|
||||
return 0; /* The notify callback stopped the client. */
|
||||
return client_enter_requesting(client);
|
||||
|
||||
case DHCP_STATE_REBOOTING:
|
||||
case DHCP_STATE_REQUESTING:
|
||||
case DHCP_STATE_RENEWING:
|
||||
case DHCP_STATE_REBINDING:
|
||||
case DHCP_ACK:
|
||||
dhcp_lease_set_timestamp(lease, timestamp);
|
||||
return client_enter_bound(client, lease);
|
||||
|
||||
r = client_handle_ack(client, message, len, timestamp);
|
||||
if (ERRNO_IS_NEG_RESOURCE(r))
|
||||
return r;
|
||||
if (r == -EADDRNOTAVAIL)
|
||||
/* got a NAK, let's restart the client */
|
||||
return client_restart(client);
|
||||
if (r < 0)
|
||||
return 0; /* invalid message, let's ignore it */
|
||||
|
||||
return client_enter_bound(client, r);
|
||||
|
||||
case DHCP_STATE_BOUND:
|
||||
log_dhcp_client(client, "Unexpected DHCP message received in BOUND state, ignoring.");
|
||||
return 0;
|
||||
|
||||
case DHCP_STATE_INIT:
|
||||
case DHCP_STATE_INIT_REBOOT:
|
||||
log_dhcp_client(client, "Unexpectedly receive message without sending any requests, ignoring.");
|
||||
return 0;
|
||||
case DHCP_NAK:
|
||||
return client_restart(client);
|
||||
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int client_receive_message_udp(
|
||||
sd_event_source *s,
|
||||
int fd,
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
|
||||
sd_dhcp_client *client = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ DHCPMessage *message = NULL;
|
||||
ssize_t len, buflen;
|
||||
/* This needs to be initialized with zero. See #20741.
|
||||
* The issue is fixed on glibc-2.35 (8fba672472ae0055387e9315fc2eddfa6775ca79). */
|
||||
CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {};
|
||||
struct iovec iov;
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
static int client_receive_message(sd_dhcp_client *client, int fd, bool raw) {
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
assert(client);
|
||||
assert(fd >= 0);
|
||||
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
ssize_t buflen = next_datagram_size_fd(fd);
|
||||
if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
|
||||
return 0;
|
||||
if (buflen < 0) {
|
||||
@@ -1481,92 +1191,56 @@ int client_receive_message_udp(
|
||||
return 0;
|
||||
}
|
||||
|
||||
message = malloc0(buflen);
|
||||
if (!message)
|
||||
_cleanup_free_ void *buf = malloc0(buflen);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
iov = IOVEC_MAKE(message, buflen);
|
||||
|
||||
len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
|
||||
if (ERRNO_IS_NEG_TRANSIENT(len) || ERRNO_IS_NEG_DISCONNECT(len))
|
||||
return 0;
|
||||
if (len < 0) {
|
||||
log_dhcp_client_errno(client, len, "Could not receive message from UDP socket, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_dhcp_client(client, "Received message from UDP socket, processing.");
|
||||
r = client_handle_message(client, message, len, TRIPLE_TIMESTAMP_FROM_CMSG(&msg));
|
||||
if (r < 0)
|
||||
client_stop(client, r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int client_receive_message_raw(
|
||||
sd_event_source *s,
|
||||
int fd,
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
|
||||
sd_dhcp_client *client = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ DHCPPacket *packet = NULL;
|
||||
/* This needs to be initialized with zero. See #20741.
|
||||
* The issue is fixed on glibc-2.35 (8fba672472ae0055387e9315fc2eddfa6775ca79). */
|
||||
CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL +
|
||||
CMSG_SPACE(sizeof(struct tpacket_auxdata))) control = {};
|
||||
struct iovec iov = {};
|
||||
struct msghdr msg = {
|
||||
.msg_iov = &iov,
|
||||
.msg_iov = &IOVEC_MAKE(buf, buflen),
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
bool checksum = true;
|
||||
ssize_t buflen, len;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
|
||||
return 0;
|
||||
if (buflen < 0) {
|
||||
log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
packet = malloc0(buflen);
|
||||
if (!packet)
|
||||
return -ENOMEM;
|
||||
|
||||
iov = IOVEC_MAKE(packet, buflen);
|
||||
|
||||
len = recvmsg_safe(fd, &msg, 0);
|
||||
ssize_t len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
|
||||
if (ERRNO_IS_NEG_TRANSIENT(len) || ERRNO_IS_NEG_DISCONNECT(len))
|
||||
return 0;
|
||||
if (len < 0) {
|
||||
log_dhcp_client_errno(client, len, "Could not receive message from raw socket, ignoring: %m");
|
||||
log_dhcp_client_errno(client, len,
|
||||
"Could not receive message from %s socket, ignoring: %m",
|
||||
raw ? "RAW" : "UDP");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tpacket_auxdata *aux = CMSG_FIND_DATA(&msg, SOL_PACKET, PACKET_AUXDATA, struct tpacket_auxdata);
|
||||
if (aux)
|
||||
checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
|
||||
struct iovec payload = IOVEC_MAKE(buf, len);
|
||||
if (raw) {
|
||||
struct tpacket_auxdata *aux = CMSG_FIND_DATA(&msg, SOL_PACKET, PACKET_AUXDATA, struct tpacket_auxdata);
|
||||
bool checksum = !aux || !(aux->tp_status & TP_STATUS_CSUMNOTREADY);
|
||||
|
||||
if (dhcp_packet_verify_headers(packet, len, checksum, client->port) < 0)
|
||||
return 0;
|
||||
if (udp_packet_verify(&payload, client->port, checksum, &payload) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
len -= DHCP_IP_UDP_SIZE;
|
||||
|
||||
log_dhcp_client(client, "Received message from RAW socket, processing.");
|
||||
r = client_handle_message(client, &packet->dhcp, len, TRIPLE_TIMESTAMP_FROM_CMSG(&msg));
|
||||
log_dhcp_client(client, "Received message from %s socket, processing.", raw ? "RAW" : "UDP");
|
||||
r = client_handle_message(client, &payload, TRIPLE_TIMESTAMP_FROM_CMSG(&msg));
|
||||
if (r < 0)
|
||||
client_stop(client, r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int client_receive_message_udp(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
return client_receive_message(userdata, fd, /* raw= */ false);
|
||||
}
|
||||
|
||||
int client_receive_message_raw(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
return client_receive_message(userdata, fd, /* raw= */ true);
|
||||
}
|
||||
|
||||
int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
|
||||
if (!sd_dhcp_client_is_running(client) || client->state != DHCP_STATE_BOUND || client->bootp)
|
||||
return 0; /* do nothing */
|
||||
|
||||
Reference in New Issue
Block a user