diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 162fae92cf..578676389d 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -19,6 +19,7 @@ struct sd_dhcp6_lease { uint8_t preference; bool rapid_commit; triple_timestamp timestamp; + struct in6_addr server_address; DHCP6IA ia; DHCP6IA pd; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index d65993219b..2efce4570b 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -1338,7 +1338,13 @@ static int client_parse_message( return 0; } -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len, const triple_timestamp *t) { +static int client_receive_reply( + sd_dhcp6_client *client, + DHCP6Message *reply, + size_t len, + const triple_timestamp *t, + const struct in6_addr *server_address) { + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; bool rapid_commit; int r; @@ -1355,6 +1361,8 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si return -ENOMEM; lease->timestamp = *t; + if (server_address) + lease->server_address = *server_address; r = client_parse_message(client, reply, len, lease); if (r < 0) @@ -1375,7 +1383,13 @@ 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, const triple_timestamp *t) { +static int client_receive_advertise( + sd_dhcp6_client *client, + DHCP6Message *advertise, + size_t len, + const triple_timestamp *t, + const struct in6_addr *server_address) { + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; int r; @@ -1392,6 +1406,8 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver return r; lease->timestamp = *t; + if (server_address) + lease->server_address = *server_address; r = client_parse_message(client, advertise, len, lease); if (r < 0) @@ -1426,7 +1442,10 @@ static int client_receive_message( /* This needs to be initialized with zero. See #20741. */ CMSG_BUFFER_TYPE(CMSG_SPACE_TIMEVAL) control = {}; struct iovec iov; + union sockaddr_union sa = {}; struct msghdr msg = { + .msg_name = &sa.sa, + .msg_namelen = sizeof(sa), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = &control, @@ -1435,6 +1454,7 @@ static int client_receive_message( struct cmsghdr *cmsg; triple_timestamp t = {}; _cleanup_free_ DHCP6Message *message = NULL; + struct in6_addr *server_address = NULL; ssize_t buflen, len; int r = 0; @@ -1470,6 +1490,16 @@ static int client_receive_message( return 0; } + /* msg_namelen == 0 happens when running the test-suite over a socketpair */ + if (msg.msg_namelen > 0) { + if (msg.msg_namelen != sizeof(struct sockaddr_in6) || sa.in6.sin6_family != AF_INET6) { + log_dhcp6_client(client, "Received message from invalid source, ignoring."); + return 0; + } + + server_address = &sa.in6.sin6_addr; + } + CMSG_FOREACH(cmsg, &msg) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP && @@ -1494,7 +1524,7 @@ static int client_receive_message( switch (client->state) { case DHCP6_STATE_INFORMATION_REQUEST: - r = client_receive_reply(client, message, len, &t); + r = client_receive_reply(client, message, len, &t, server_address); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received reply message, ignoring: %m"); return 0; @@ -1507,7 +1537,7 @@ static int client_receive_message( break; case DHCP6_STATE_SOLICITATION: - r = client_receive_advertise(client, message, len, &t); + r = client_receive_advertise(client, message, len, &t, server_address); if (r < 0) { log_dhcp6_client_errno(client, r, "Failed to process received advertise message, ignoring: %m"); return 0; @@ -1523,7 +1553,7 @@ static int client_receive_message( case DHCP6_STATE_RENEW: case DHCP6_STATE_REBIND: - r = client_receive_reply(client, message, len, &t); + r = client_receive_reply(client, message, len, &t, server_address); 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 97521ba5c5..19fdbdcc84 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -24,6 +24,14 @@ int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_ return 0; } +int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret) { + assert_return(lease, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = lease->server_address; + 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/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 3cc457a02d..170cf7d57d 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1129,6 +1129,7 @@ simple_log: static int dhcp6_request_address( Link *link, + const struct in6_addr *server_address, const struct in6_addr *ip6_addr, usec_t lifetime_preferred_usec, usec_t lifetime_valid_usec) { @@ -1142,6 +1143,7 @@ static int dhcp6_request_address( return log_oom(); addr->source = NETWORK_CONFIG_SOURCE_DHCP6; + addr->provider.in6 = *server_address; addr->family = AF_INET6; addr->in_addr.in6 = *ip6_addr; addr->flags = IFA_F_NOPREFIXROUTE; @@ -1169,6 +1171,7 @@ static int dhcp6_request_address( } static int dhcp6_address_acquired(Link *link) { + struct in6_addr server_address; usec_t timestamp_usec; int r; @@ -1179,6 +1182,10 @@ static int dhcp6_address_acquired(Link *link) { if (!link->network->dhcp6_use_address) return 0; + r = sd_dhcp6_lease_get_server_address(link->dhcp6_lease, &server_address); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get server address of DHCPv6 lease: %m"); + r = sd_dhcp6_lease_get_timestamp(link->dhcp6_lease, clock_boottime_or_monotonic(), ×tamp_usec); if (r < 0) return log_link_warning_errno(link, r, "Failed to get timestamp of DHCPv6 lease: %m"); @@ -1191,7 +1198,7 @@ static int dhcp6_address_acquired(Link *link) { if (r < 0) break; - r = dhcp6_request_address(link, &ip6_addr, + r = dhcp6_request_address(link, &server_address, &ip6_addr, usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec), usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec)); if (r < 0) diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index 04c6383051..472276def1 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -30,6 +30,7 @@ _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); +int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret); void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,