network: request product UUID when DUIDType=uuid but DUIDRawData= is not set

Closes #9228.
This commit is contained in:
Yu Watanabe 2018-07-03 03:19:15 +09:00
parent fff1f40c9b
commit 27dfc98275
7 changed files with 212 additions and 3 deletions

View File

@ -8,6 +8,7 @@
#include "alloc-util.h"
#include "bus-util.h"
#include "dhcp-identifier.h"
#include "dhcp-lease-internal.h"
#include "fd-util.h"
#include "fileio.h"
@ -546,8 +547,10 @@ static void link_free(Link *link) {
sd_ndisc_unref(link->ndisc);
sd_radv_unref(link->radv);
if (link->manager)
if (link->manager) {
hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
set_remove(link->manager->links_requesting_uuid, link);
}
free(link->ifname);
@ -2891,6 +2894,134 @@ static int link_configure(Link *link) {
return link_enter_join_netdev(link);
}
static int duid_set_uuid(DUID *duid, sd_id128_t uuid) {
assert(duid);
if (duid->raw_data_len > 0)
return 0;
if (duid->type != DUID_TYPE_UUID)
return -EINVAL;
memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t));
duid->raw_data_len = sizeof(sd_id128_t);
return 1;
}
int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
Manager *manager = userdata;
const sd_bus_error *e;
const void *a;
size_t sz;
DUID *duid;
Link *link;
int r;
assert(m);
assert(manager);
e = sd_bus_message_get_error(m);
if (e) {
log_error_errno(sd_bus_error_get_errno(e),
"Could not get product UUID. Fallback to use application specific machine ID as DUID-UUID: %s",
e->message);
goto configure;
}
r = sd_bus_message_read_array(m, 'y', &a, &sz);
if (r < 0)
goto configure;
if (sz != sizeof(sd_id128_t)) {
log_error("Invalid product UUID. Fallback to use application specific machine ID as DUID-UUID.");
goto configure;
}
memcpy(&manager->product_uuid, a, sz);
while ((duid = set_steal_first(manager->duids_requesting_uuid)))
(void) duid_set_uuid(duid, manager->product_uuid);
manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid);
configure:
while ((link = set_steal_first(manager->links_requesting_uuid))) {
r = link_configure(link);
if (r < 0)
log_link_error_errno(link, r, "Failed to configure link: %m");
}
manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
/* To avoid calling GetProductUUID() bus method so frequently, set the flag below
* even if the method fails. */
manager->has_product_uuid = true;
return 1;
}
static bool link_requires_uuid(Link *link) {
const DUID *duid;
assert(link);
assert(link->manager);
assert(link->network);
duid = link_get_duid(link);
if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0)
return false;
if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
return true;
if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link))
return true;
return false;
}
static int link_configure_duid(Link *link) {
Manager *m;
DUID *duid;
int r;
assert(link);
assert(link->manager);
assert(link->network);
m = link->manager;
duid = link_get_duid(link);
if (!link_requires_uuid(link))
return 1;
if (m->has_product_uuid) {
(void) duid_set_uuid(duid, m->product_uuid);
return 1;
}
if (!m->links_requesting_uuid) {
r = manager_request_product_uuid(m, link);
if (r < 0) {
if (r == -ENOMEM)
return r;
log_link_warning_errno(link, r, "Failed to get product UUID. Fallback to use application specific machine ID as DUID-UUID: %m");
return 1;
}
} else {
r = set_put(m->links_requesting_uuid, link);
if (r < 0)
return log_oom();
r = set_put(m->duids_requesting_uuid, duid);
if (r < 0)
return log_oom();
}
return 0;
}
static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
_cleanup_(link_unrefp) Link *link = userdata;
@ -2946,6 +3077,12 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
if (r < 0)
return r;
/* link_configure_duid() returns 0 if it requests product UUID. In that case,
* link_configure() is called later asynchronously. */
r = link_configure_duid(link);
if (r <= 0)
return r;
r = link_configure(link);
if (r < 0)
return r;

View File

@ -125,6 +125,7 @@ typedef struct Link {
} Link;
DUID *link_get_duid(Link *link);
int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
Link *link_unref(Link *link);
Link *link_ref(Link *link);

View File

@ -114,6 +114,8 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
(void) manager_set_hostname(m, m->dynamic_hostname);
if (m->dynamic_timezone)
(void) manager_set_timezone(m, m->dynamic_timezone);
if (m->links_requesting_uuid)
(void) manager_request_product_uuid(m, NULL);
return 0;
}
@ -1459,6 +1461,9 @@ void manager_free(Manager *m) {
link_unref(link);
hashmap_free(m->links);
set_free(m->links_requesting_uuid);
set_free(m->duids_requesting_uuid);
hashmap_free(m->networks_by_name);
while ((netdev = hashmap_first(m->netdevs)))
@ -1831,3 +1836,57 @@ int manager_set_timezone(Manager *m, const char *tz) {
return 0;
}
int manager_request_product_uuid(Manager *m, Link *link) {
int r;
assert(m);
if (m->has_product_uuid)
return 0;
log_debug("Requesting product UUID");
if (link) {
DUID *duid;
assert_se(duid = link_get_duid(link));
r = set_ensure_allocated(&m->links_requesting_uuid, NULL);
if (r < 0)
return log_oom();
r = set_ensure_allocated(&m->duids_requesting_uuid, NULL);
if (r < 0)
return log_oom();
r = set_put(m->links_requesting_uuid, link);
if (r < 0)
return log_oom();
r = set_put(m->duids_requesting_uuid, duid);
if (r < 0)
return log_oom();
}
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
log_debug("Not connected to system bus, requesting product UUID later.");
return 0;
}
r = sd_bus_call_method_async(
m->bus,
NULL,
"org.freedesktop.hostname1",
"/org/freedesktop/hostname1",
"org.freedesktop.hostname1",
"GetProductUUID",
get_product_uuid_handler,
m,
"b",
false);
if (r < 0)
return log_warning_errno(r, "Failed to get product UUID: %m");
return 0;
}

View File

@ -5,6 +5,7 @@
#include "sd-bus.h"
#include "sd-event.h"
#include "sd-id128.h"
#include "sd-netlink.h"
#include "sd-resolve.h"
#include "udev.h"
@ -48,6 +49,11 @@ struct Manager {
usec_t network_dirs_ts_usec;
DUID duid;
sd_id128_t product_uuid;
bool has_product_uuid;
Set *links_requesting_uuid;
Set *duids_requesting_uuid;
char* dynamic_hostname;
char* dynamic_timezone;
@ -85,6 +91,7 @@ Link* manager_find_uplink(Manager *m, Link *exclude);
int manager_set_hostname(Manager *m, const char *hostname);
int manager_set_timezone(Manager *m, const char *timezone);
int manager_request_product_uuid(Manager *m, Link *link);
Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link);

View File

@ -415,6 +415,9 @@ void network_free(Network *network) {
if (network->manager->networks_by_name)
hashmap_remove(network->manager->networks_by_name, network->name);
if (network->manager->duids_requesting_uuid)
set_remove(network->manager->duids_requesting_uuid, &network->duid);
}
free(network->name);

View File

@ -1,4 +1,4 @@
[Allow systemd-networkd to set timezone and transient hostname]
Identity=unix-user:systemd-network
Action=org.freedesktop.hostname1.set-hostname;org.freedesktop.timedate1.set-timezone;
Action=org.freedesktop.hostname1.set-hostname;org.freedesktop.hostname1.get-product-uuid;org.freedesktop.timedate1.set-timezone;
ResultAny=yes

View File

@ -1,6 +1,8 @@
// Allow systemd-networkd to set timezone and transient hostname
// Allow systemd-networkd to set timezone, get product UUID,
// and transient hostname
polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.hostname1.set-hostname" ||
action.id == "org.freedesktop.hostname1.get-product-uuid" ||
action.id == "org.freedesktop.timedate1.set-timezone") &&
subject.user == "systemd-network") {
return polkit.Result.YES;