From 653ddc1d184b173698a4cf6ba780bdeada81bd60 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 15 Oct 2021 04:19:59 +0900 Subject: [PATCH] sd-dhcp6-client: introduce sd_dhcp6_lease_get_timestamp() --- src/libsystemd-network/dhcp6-lease-internal.h | 1 + src/libsystemd-network/dhcp6-network.c | 4 ++ src/libsystemd-network/sd-dhcp6-client.c | 50 +++++++++++++++---- src/libsystemd-network/sd-dhcp6-lease.c | 13 +++++ src/systemd/sd-dhcp6-lease.h | 3 ++ 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 8801497b72..66af241df5 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -18,6 +18,7 @@ struct sd_dhcp6_lease { size_t serverid_len; uint8_t preference; bool rapid_commit; + triple_timestamp timestamp; DHCP6IA ia; DHCP6IA pd; diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 4f7bd53de4..eedd92d3c2 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -47,6 +47,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *local_address) { if (r < 0) return r; + r = setsockopt_int(s, SOL_SOCKET, SO_TIMESTAMP, true); + if (r < 0) + return r; + r = bind(s, &src.sa, sizeof(src.in6)); if (r < 0) return -errno; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index aacdf06980..9a6be64789 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -21,6 +21,7 @@ #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" +#include "io-util.h" #include "network-common.h" #include "random-util.h" #include "socket-util.h" @@ -1341,13 +1342,14 @@ static int client_parse_message( return 0; } -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { +static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len, const triple_timestamp *t) { _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; bool rapid_commit; int r; assert(client); assert(reply); + assert(t); if (reply->type != DHCP6_MESSAGE_REPLY) return 0; @@ -1356,6 +1358,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si if (r < 0) return -ENOMEM; + lease->timestamp = *t; + r = client_parse_message(client, reply, len, lease); if (r < 0) return r; @@ -1375,11 +1379,15 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si return DHCP6_STATE_BOUND; } -static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { +static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len, const triple_timestamp *t) { _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; int r; + assert(client); + assert(advertise); + assert(t); + if (advertise->type != DHCP6_MESSAGE_ADVERTISE) return 0; @@ -1387,6 +1395,8 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver if (r < 0) return r; + lease->timestamp = *t; + r = client_parse_message(client, advertise, len, lease); if (r < 0) return r; @@ -1417,6 +1427,17 @@ static int client_receive_message( sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); + /* This needs to be initialized with zero. See #20741. */ + 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), + }; + struct cmsghdr *cmsg; + triple_timestamp t = {}; _cleanup_free_ DHCP6Message *message = NULL; ssize_t buflen, len; int r = 0; @@ -1427,9 +1448,8 @@ static int client_receive_message( buflen = next_datagram_size_fd(fd); if (buflen == -ENETDOWN) - /* the link is down. Don't return an error or the I/O event - source will be disconnected and we won't be able to receive - packets again when the link comes back. */ + /* the link is down. Don't return an error or the I/O event source will be disconnected + * and we won't be able to receive packets again when the link comes back. */ return 0; if (buflen < 0) return buflen; @@ -1438,7 +1458,9 @@ static int client_receive_message( if (!message) return -ENOMEM; - len = recv(fd, message, buflen, 0); + iov = IOVEC_MAKE(message, buflen); + + len = recvmsg_safe(fd, &msg, MSG_DONTWAIT); if (len < 0) { /* see comment above for why we shouldn't error out on ENETDOWN. */ if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN)) @@ -1452,6 +1474,16 @@ static int client_receive_message( return 0; } + CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SO_TIMESTAMP && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) + triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg))); + } + + if (!triple_timestamp_is_set(&t)) + triple_timestamp_get(&t); + if (!IN_SET(message->type, DHCP6_MESSAGE_ADVERTISE, DHCP6_MESSAGE_REPLY, DHCP6_MESSAGE_RECONFIGURE)) { const char *type_str = dhcp6_message_type_to_string(message->type); if (type_str) @@ -1466,7 +1498,7 @@ static int client_receive_message( switch (client->state) { case DHCP6_STATE_INFORMATION_REQUEST: - r = client_receive_reply(client, message, len); + r = client_receive_reply(client, message, len, &t); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m"); return 0; @@ -1479,7 +1511,7 @@ static int client_receive_message( break; case DHCP6_STATE_SOLICITATION: - r = client_receive_advertise(client, message, len); + r = client_receive_advertise(client, message, len, &t); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m"); return 0; @@ -1495,7 +1527,7 @@ static int client_receive_message( case DHCP6_STATE_RENEW: case DHCP6_STATE_REBIND: - r = client_receive_reply(client, message, len); + r = client_receive_reply(client, message, len, &t); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m"); return 0; diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index c55b06d2f7..6c7ffc7999 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -11,6 +11,19 @@ #include "strv.h" #include "util.h" +int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) { + assert_return(lease, -EINVAL); + assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP); + assert_return(clock_supported(clock), -EOPNOTSUPP); + assert_return(ret, -EINVAL); + + if (!triple_timestamp_is_set(&lease->timestamp)) + return -ENODATA; + + *ret = triple_timestamp_by_clock(&lease->timestamp, clock); + return 0; +} + int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { DHCP6Address *addr; uint32_t valid = 0, t; diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index a10901e5cb..04c6383051 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -21,6 +21,7 @@ #include #include +#include #include "_sd-common.h" @@ -28,6 +29,8 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp6_lease sd_dhcp6_lease; +int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret); + void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr,