From 21e627daa515367028879a9c3f51669b3dc6005e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 25 Jun 2018 16:20:18 +0900 Subject: [PATCH 01/12] hostname: expose product UUID on bus --- src/hostname/hostnamed.c | 50 +++++++++++++++++++ src/hostname/org.freedesktop.hostname1.policy | 10 ++++ src/libsystemd/sd-bus/bus-common-errors.c | 2 + src/libsystemd/sd-bus/bus-common-errors.h | 2 + 4 files changed, 64 insertions(+) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index b98f962ad2..d8074e6f5f 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -6,11 +6,13 @@ #include #include "alloc-util.h" +#include "bus-common-errors.h" #include "bus-util.h" #include "def.h" #include "env-util.h" #include "fileio-label.h" #include "hostname-util.h" +#include "id128-util.h" #include "os-util.h" #include "parse-util.h" #include "path-util.h" @@ -43,6 +45,8 @@ enum { typedef struct Context { char *data[_PROP_MAX]; Hashmap *polkit_registry; + sd_id128_t uuid; + bool has_uuid; } Context; static void context_reset(Context *c) { @@ -103,6 +107,11 @@ static int context_read_data(Context *c) { if (r < 0 && r != -ENOENT) return r; + r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid); + if (r < 0) + log_info_errno(r, "Failed to read product UUID, ignoring: %m"); + c->has_uuid = (r >= 0); + return 0; } @@ -598,6 +607,46 @@ static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error * return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error); } +static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + Context *c = userdata; + int interactive, r; + + assert(m); + assert(c); + + if (!c->has_uuid) + return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid"); + + r = sd_bus_message_read(m, "b", &interactive); + if (r < 0) + return r; + + r = bus_verify_polkit_async( + m, + CAP_SYS_ADMIN, + "org.freedesktop.hostname1.get-product-uuid", + NULL, + interactive, + UID_INVALID, + &c->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid)); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static const sd_bus_vtable hostname_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -620,6 +669,7 @@ static const sd_bus_vtable hostname_vtable[] = { SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("GetProductUUID", "b", "ay", method_get_product_uuid, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; diff --git a/src/hostname/org.freedesktop.hostname1.policy b/src/hostname/org.freedesktop.hostname1.policy index e1519ce86b..5bedc0b694 100644 --- a/src/hostname/org.freedesktop.hostname1.policy +++ b/src/hostname/org.freedesktop.hostname1.policy @@ -47,4 +47,14 @@ + + Get product UUID + Authentication is required to get product UUID. + + auth_admin_keep + auth_admin_keep + auth_admin_keep + + + diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index ff0790bf5a..b6e40ee8a9 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -94,5 +94,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_TRANSFER, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP), + SD_BUS_ERROR_MAP_END }; diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index daf7cdae67..a76a93644c 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -75,4 +75,6 @@ #define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" #define BUS_ERROR_TRANSFER_IN_PROGRESS "org.freedesktop.import1.TransferInProgress" +#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID" + BUS_ERROR_MAP_ELF_USE(bus_common_errors); From 27eba50e76819c447f7bea8c33ba062c5fb996c6 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 25 Jun 2018 18:23:13 +0900 Subject: [PATCH 02/12] sd-dhcp: use application specific machine ID when DUIDType=uuid but DUIDRawData= is not set --- src/libsystemd-network/dhcp-identifier.c | 26 +++++++++++++++++++++--- src/libsystemd-network/dhcp-identifier.h | 1 + src/libsystemd-network/sd-dhcp-client.c | 19 ++++++++++++----- src/libsystemd-network/sd-dhcp6-client.c | 23 +++++++++++++-------- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 91c485c6c2..4b7e7ee0ab 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -11,8 +11,9 @@ #include "udev-util.h" #include "virt.h" -#define SYSTEMD_PEN 43793 -#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define SYSTEMD_PEN 43793 +#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) +#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03) int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { struct duid d; @@ -63,13 +64,32 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { *len = sizeof(duid->type) + sizeof(duid->en); /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly; duid->en.id might not be aligned, so we need to copy */ + * directly; duid->en.id might not be aligned, so we need to copy */ hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); memcpy(duid->en.id, &hash, sizeof(duid->en.id)); return 0; } +int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len) { + sd_id128_t machine_id; + int r; + + assert(duid); + assert(len); + + r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id); + if (r < 0) + return r; + + unaligned_write_be16(&duid->type, DUID_TYPE_UUID); + memcpy(&duid->raw.data, &machine_id, sizeof(machine_id)); + + *len = sizeof(duid->type) + sizeof(machine_id); + + return 0; +} + int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { /* name is a pointer to memory in the udev_device struct, so must have the same scope */ diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 8250c76598..add546f31c 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -53,4 +53,5 @@ struct duid { int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len); int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); +int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index ff434f8ce7..1b89142053 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -381,12 +381,21 @@ static int dhcp_client_set_iaid_duid( client->client_id.ns.duid.type = htobe16(duid_type); memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); len = sizeof(client->client_id.ns.duid.type) + duid_len; - } else if (duid_type == DUID_TYPE_EN) { - r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); - if (r < 0) - return r; } else - return -EOPNOTSUPP; + switch (duid_type) { + case DUID_TYPE_EN: + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + break; + case DUID_TYPE_UUID: + r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); + if (r < 0) + return r; + break; + default: + return -EOPNOTSUPP; + } client->client_id_len = sizeof(client->client_id.type) + len + (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index ff54d7e20c..31382b5431 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -187,8 +187,8 @@ int sd_dhcp6_client_set_duid( uint16_t duid_type, const void *duid, size_t duid_len) { - int r; + assert_return(client, -EINVAL); assert_return(duid_len == 0 || duid != NULL, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -197,18 +197,25 @@ int sd_dhcp6_client_set_duid( r = dhcp_validate_duid_len(duid_type, duid_len); if (r < 0) return r; - } - if (duid != NULL) { client->duid.type = htobe16(duid_type); memcpy(&client->duid.raw.data, duid, duid_len); client->duid_len = sizeof(client->duid.type) + duid_len; - } else if (duid_type == DUID_TYPE_EN) { - r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); - if (r < 0) - return r; } else - return -EOPNOTSUPP; + switch (duid_type) { + case DUID_TYPE_EN: + r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); + if (r < 0) + return r; + break; + case DUID_TYPE_UUID: + r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); + if (r < 0) + return r; + break; + default: + return -EOPNOTSUPP; + } return 0; } From f24648a66c54a78a6e6b6490d3e7390ccbc85b92 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Aug 2018 17:28:27 +0900 Subject: [PATCH 03/12] network: move and rename link_duid() --- src/network/networkd-dhcp4.c | 4 ++-- src/network/networkd-dhcp6.c | 2 +- src/network/networkd-link.c | 13 ++++++++++--- src/network/networkd-link.h | 3 +++ src/network/networkd-manager.h | 7 ------- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 7798844e03..c49d8a0939 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -766,7 +766,7 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: { /* If configured, apply user specified DUID and/or IAID */ - const DUID *duid = link_duid(link); + const DUID *duid = link_get_duid(link); r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, link->network->iaid, @@ -779,7 +779,7 @@ int dhcp4_configure(Link *link) { } case DHCP_CLIENT_ID_DUID_ONLY: { /* If configured, apply user specified DUID */ - const DUID *duid = link_duid(link); + const DUID *duid = link_get_duid(link); r = sd_dhcp_client_set_duid(link->dhcp_client, duid->type, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 0ec4deb716..aa400bc35b 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -494,7 +494,7 @@ int dhcp6_configure(Link *link) { if (r < 0) return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m"); - duid = link_duid(link); + duid = link_get_duid(link); r = sd_dhcp6_client_set_duid(client, duid->type, duid->raw_data_len > 0 ? duid->raw_data : NULL, diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4c534e685d..6b870c5bd5 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -27,6 +27,13 @@ #include "util.h" #include "virt.h" +DUID* link_get_duid(Link *link) { + if (link->network->duid.type != _DUID_TYPE_INVALID) + return &link->network->duid; + else + return &link->manager->duid; +} + static bool link_dhcp6_enabled(Link *link) { assert(link); @@ -3430,7 +3437,7 @@ int link_update(Link *link, sd_netlink_message *m) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: { - const DUID *duid = link_duid(link); + const DUID *duid = link_get_duid(link); r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, link->network->iaid, @@ -3442,7 +3449,7 @@ int link_update(Link *link, sd_netlink_message *m) { break; } case DHCP_CLIENT_ID_DUID_ONLY: { - const DUID *duid = link_duid(link); + const DUID *duid = link_get_duid(link); r = sd_dhcp_client_set_duid(link->dhcp_client, duid->type, @@ -3466,7 +3473,7 @@ int link_update(Link *link, sd_netlink_message *m) { } if (link->dhcp6_client) { - const DUID* duid = link_duid(link); + const DUID* duid = link_get_duid(link); r = sd_dhcp6_client_set_mac(link->dhcp6_client, (const uint8_t *) &link->mac, diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index d3028bae50..35e44cd09f 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -43,6 +43,7 @@ typedef enum LinkOperationalState { typedef struct Manager Manager; typedef struct Network Network; typedef struct Address Address; +typedef struct DUID DUID; typedef struct Link { Manager *manager; @@ -123,6 +124,8 @@ typedef struct Link { Hashmap *bound_to_links; } Link; +DUID *link_get_duid(Link *link); + Link *link_unref(Link *link); Link *link_ref(Link *link); int link_get(Manager *m, int ifindex, Link **ret); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index a6cb1e2d44..d6e3fe5478 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -56,13 +56,6 @@ struct Manager { Set *rules_saved; }; -static inline const DUID* link_duid(const Link *link) { - if (link->network->duid.type != _DUID_TYPE_INVALID) - return &link->network->duid; - else - return &link->manager->duid; -} - extern const sd_bus_vtable manager_vtable[]; int manager_new(Manager **ret); From fff1f40c9bd00696788cddfbd10479606bc66a82 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 6 Aug 2018 17:33:12 +0900 Subject: [PATCH 04/12] network: introduce dhcp4_set_client_identifier() to unify duplicated codes --- src/network/networkd-dhcp4.c | 88 ++++++++++++++++++++---------------- src/network/networkd-link.c | 38 ++-------------- src/network/networkd-link.h | 1 + 3 files changed, 53 insertions(+), 74 deletions(-) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index c49d8a0939..a3bdf4f40a 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -660,6 +660,54 @@ int dhcp4_set_promote_secondaries(Link *link) { return 0; } +int dhcp4_set_client_identifier(Link *link) { + int r; + + assert(link); + assert(link->network); + assert(link->dhcp_client); + + switch (link->network->dhcp_client_identifier) { + case DHCP_CLIENT_ID_DUID: { + /* If configured, apply user specified DUID and/or IAID */ + const DUID *duid = link_get_duid(link); + + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); + if (r < 0) + return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); + break; + } + case DHCP_CLIENT_ID_DUID_ONLY: { + /* If configured, apply user specified DUID */ + const DUID *duid = link_get_duid(link); + + r = sd_dhcp_client_set_duid(link->dhcp_client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); + if (r < 0) + return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); + break; + } + case DHCP_CLIENT_ID_MAC: + r = sd_dhcp_client_set_client_id(link->dhcp_client, + ARPHRD_ETHER, + (const uint8_t *) &link->mac, + sizeof(link->mac)); + if (r < 0) + return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m"); + break; + default: + assert_not_reached("Unknown client identifier type."); + } + + return 0; +} + int dhcp4_configure(Link *link) { int r; @@ -763,43 +811,5 @@ int dhcp4_configure(Link *link) { return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m"); } - switch (link->network->dhcp_client_identifier) { - case DHCP_CLIENT_ID_DUID: { - /* If configured, apply user specified DUID and/or IAID */ - const DUID *duid = link_get_duid(link); - - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); - if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); - break; - } - case DHCP_CLIENT_ID_DUID_ONLY: { - /* If configured, apply user specified DUID */ - const DUID *duid = link_get_duid(link); - - r = sd_dhcp_client_set_duid(link->dhcp_client, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); - if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); - break; - } - case DHCP_CLIENT_ID_MAC: - r = sd_dhcp_client_set_client_id(link->dhcp_client, - ARPHRD_ETHER, - (const uint8_t *) &link->mac, - sizeof(link->mac)); - if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m"); - break; - default: - assert_not_reached("Unknown client identifier type."); - } - - return 0; + return dhcp4_set_client_identifier(link); } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 6b870c5bd5..09bc0ac907 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -3435,41 +3435,9 @@ int link_update(Link *link, sd_netlink_message *m) { if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); - switch (link->network->dhcp_client_identifier) { - case DHCP_CLIENT_ID_DUID: { - const DUID *duid = link_get_duid(link); - - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); - break; - } - case DHCP_CLIENT_ID_DUID_ONLY: { - const DUID *duid = link_get_duid(link); - - r = sd_dhcp_client_set_duid(link->dhcp_client, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update DUID in DHCP client: %m"); - break; - } - case DHCP_CLIENT_ID_MAC: - r = sd_dhcp_client_set_client_id(link->dhcp_client, - ARPHRD_ETHER, - (const uint8_t *)&link->mac, - sizeof(link->mac)); - if (r < 0) - return log_link_warning_errno(link, r, "Could not update MAC client id in DHCP client: %m"); - break; - default: - assert_not_reached("Unknown client identifier type."); - } + r = dhcp4_set_client_identifier(link); + if (r < 0) + return r; } if (link->dhcp6_client) { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 35e44cd09f..6ed11ff51c 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -159,6 +159,7 @@ int link_set_mtu(Link *link, uint32_t mtu); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); +int dhcp4_set_client_identifier(Link *link); int dhcp4_set_promote_secondaries(Link *link); int dhcp6_configure(Link *link); int dhcp6_request_address(Link *link, int ir); From 27dfc98275f7c0d84e1e95a58f50e66d81bfbda2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 3 Jul 2018 03:19:15 +0900 Subject: [PATCH 05/12] network: request product UUID when DUIDType=uuid but DUIDRawData= is not set Closes #9228. --- src/network/networkd-link.c | 139 ++++++++++++++++++++++++++++- src/network/networkd-link.h | 1 + src/network/networkd-manager.c | 59 ++++++++++++ src/network/networkd-manager.h | 7 ++ src/network/networkd-network.c | 3 + src/network/systemd-networkd.pkla | 2 +- src/network/systemd-networkd.rules | 4 +- 7 files changed, 212 insertions(+), 3 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 09bc0ac907..7e4e868d82 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 6ed11ff51c..4c13cc156e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -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); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 3792f3d700..4e14fab89f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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; +} diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index d6e3fe5478..410e00da63 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -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); diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 77ba8c678e..2fa067655e 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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); diff --git a/src/network/systemd-networkd.pkla b/src/network/systemd-networkd.pkla index fb257d933b..4d1bb4585e 100644 --- a/src/network/systemd-networkd.pkla +++ b/src/network/systemd-networkd.pkla @@ -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 diff --git a/src/network/systemd-networkd.rules b/src/network/systemd-networkd.rules index 2e4bc42bfb..b9077c1ea2 100644 --- a/src/network/systemd-networkd.rules +++ b/src/network/systemd-networkd.rules @@ -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; From 319b94bca7f1ffdce9d6cd6370a517a10442fd95 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 25 Jun 2018 21:32:41 +0900 Subject: [PATCH 06/12] man: mention that DUIDType=uuid uses the product UUID or machine-ID --- man/networkd.conf.xml | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index 5a98f8b318..f5f7acbf67 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -67,7 +67,7 @@ The following values are understood: - + If DUIDType=vendor, then the DUID value will be generated using 43793 as the vendor identifier (systemd) and hashed contents of machine-id5. @@ -76,9 +76,19 @@ - - - + + If DUIDType=uuid, and DUIDRawData= is not set, + then the product UUID is used as a DUID value. If a system does not have valid product UUID, then + an application-specific + machine-id5 + is used as a DUID value. About the application-specific machine ID, see + sd_id128_get_machine_app_specific3. + + + + + + Those values are parsed and can be used to set the DUID type field, but DUID contents must be provided using DUIDRawData=. @@ -96,8 +106,9 @@ byte separated by :. The DUID that is sent is composed of the DUID type specified by DUIDType= and the value configured here. - The DUID value specified here overrides the DUID that systemd-networkd generates using the machine-id - from the /etc/machine-id file. To configure DUID per-network, see + The DUID value specified here overrides the DUID that + systemd-networkd.service8 + generates from the machine ID. To configure DUID per-network, see systemd.network5. The configured DHCP DUID should conform to the specification in RFC 3315, @@ -125,7 +136,9 @@ DUIDRawData=00:00:ab:11:f9:2a:c2:77:29:f9:5c:00 systemd1, systemd.network5, - machine-id1 + systemd-networkd.service8, + machine-id5, + sd_id128_get_machine_app_specific3 From 9d7b8c66f5358a0b60949c6c2a063d46159ee0db Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Aug 2018 12:07:12 +0900 Subject: [PATCH 07/12] sd-dhcp: adjust type of elements in duid These values should be stored in network byte order. --- src/libsystemd-network/dhcp-identifier.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index add546f31c..cebfa8f4a8 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -27,18 +27,18 @@ struct duid { union { struct { /* DUID_TYPE_LLT */ - uint16_t htype; - uint32_t time; + be16_t htype; + be32_t time; uint8_t haddr[0]; } _packed_ llt; struct { /* DUID_TYPE_EN */ - uint32_t pen; + be32_t pen; uint8_t id[8]; } _packed_ en; struct { /* DUID_TYPE_LL */ - int16_t htype; + be16_t htype; uint8_t haddr[0]; } _packed_ ll; struct { From f7708f3ffdfaab85b4aa486d009df77621bd7a85 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Aug 2018 13:28:55 +0900 Subject: [PATCH 08/12] sd-dhcp: adjust log message --- src/libsystemd-network/sd-dhcp-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 1b89142053..6f541f6577 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -401,7 +401,7 @@ static int dhcp_client_set_iaid_duid( (append_iaid ? sizeof(client->client_id.ns.iaid) : 0); if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured IAID+DUID, restarting."); + log_dhcp_client(client, "Configured %sDUID, restarting.", append_iaid ? "IAID+" : ""); client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); sd_dhcp_client_start(client); } From 335f80a612a82a9a44631483a40107f91e2bee2b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Aug 2018 13:35:58 +0900 Subject: [PATCH 09/12] sd-dhcp: use MAC address when DUIDType=link-layer-time or link-layer but DUIDRawData= is not set --- src/libsystemd-network/dhcp-identifier.c | 53 ++++++++++++++++++++++++ src/libsystemd-network/dhcp-identifier.h | 3 ++ src/libsystemd-network/sd-dhcp-client.c | 18 +++++++- src/libsystemd-network/sd-dhcp6-client.c | 18 +++++++- 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 4b7e7ee0ab..a8ed98f29a 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ +#include + #include "libudev.h" #include "sd-id128.h" @@ -14,6 +16,7 @@ #define SYSTEMD_PEN 43793 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) #define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03) +#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { struct duid d; @@ -46,6 +49,56 @@ int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) { return 0; } +int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { + uint16_t time_from_2000y; + + assert(duid); + assert(len); + assert(addr); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + if (t < USEC_2000) + time_from_2000y = 0; + else + time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff); + + unaligned_write_be16(&duid->type, DUID_TYPE_LLT); + unaligned_write_be16(&duid->llt.htype, arp_type); + unaligned_write_be32(&duid->llt.time, time_from_2000y); + memcpy(duid->llt.haddr, addr, addr_len); + + *len = sizeof(duid->type) + sizeof(duid->llt.htype) + sizeof(duid->llt.time) + addr_len; + + return 0; +} + +int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len) { + assert(duid); + assert(len); + assert(addr); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + unaligned_write_be16(&duid->type, DUID_TYPE_LL); + unaligned_write_be16(&duid->ll.htype, arp_type); + memcpy(duid->ll.haddr, addr, addr_len); + + *len = sizeof(duid->type) + sizeof(duid->ll.htype) + addr_len; + + return 0; +} + int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { sd_id128_t machine_id; uint64_t hash; diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index cebfa8f4a8..64315d3a3b 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -5,6 +5,7 @@ #include "macro.h" #include "sparse-endian.h" +#include "time-util.h" #include "unaligned.h" typedef enum DUIDType { @@ -52,6 +53,8 @@ struct duid { } _packed_; int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len); +int dhcp_identifier_set_duid_llt(struct duid *duid, usec_t t, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); +int dhcp_identifier_set_duid_ll(struct duid *duid, const uint8_t *addr, size_t addr_len, uint16_t arp_type, size_t *len); int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_duid_uuid(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 6f541f6577..62c57c8c9f 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -383,18 +383,34 @@ static int dhcp_client_set_iaid_duid( len = sizeof(client->client_id.ns.duid.type) + duid_len; } else switch (duid_type) { + case DUID_TYPE_LLT: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, 0, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + if (r < 0) + return r; + break; case DUID_TYPE_EN: r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len); if (r < 0) return r; break; + case DUID_TYPE_LL: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_ll(&client->client_id.ns.duid, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + if (r < 0) + return r; + break; case DUID_TYPE_UUID: r = dhcp_identifier_set_duid_uuid(&client->client_id.ns.duid, &len); if (r < 0) return r; break; default: - return -EOPNOTSUPP; + return -EINVAL; } client->client_id_len = sizeof(client->client_id.type) + len + diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index 31382b5431..d4831361bf 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -203,18 +203,34 @@ int sd_dhcp6_client_set_duid( client->duid_len = sizeof(client->duid.type) + duid_len; } else switch (duid_type) { + case DUID_TYPE_LLT: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_llt(&client->duid, 0, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); + if (r < 0) + return r; + break; case DUID_TYPE_EN: r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); if (r < 0) return r; break; + case DUID_TYPE_LL: + if (!client->mac_addr || client->mac_addr_len == 0) + return -EOPNOTSUPP; + + r = dhcp_identifier_set_duid_ll(&client->duid, client->mac_addr, client->mac_addr_len, client->arp_type, &client->duid_len); + if (r < 0) + return r; + break; case DUID_TYPE_UUID: r = dhcp_identifier_set_duid_uuid(&client->duid, &client->duid_len); if (r < 0) return r; break; default: - return -EOPNOTSUPP; + return -EINVAL; } return 0; From 7e90a499ab1d5648c9169b5991b117d36fc59fad Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Aug 2018 13:55:38 +0900 Subject: [PATCH 10/12] sd-dhcp: make time value for DUID-LLT configurable --- src/libsystemd-network/sd-dhcp-client.c | 24 +++++++++++++++++++----- src/libsystemd-network/sd-dhcp6-client.c | 19 +++++++++++++++++-- src/systemd/sd-dhcp-client.h | 7 +++++++ src/systemd/sd-dhcp6-client.h | 3 +++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 62c57c8c9f..de86028a5d 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -341,13 +341,14 @@ int sd_dhcp_client_set_client_id( * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -static int dhcp_client_set_iaid_duid( +static int dhcp_client_set_iaid_duid_internal( sd_dhcp_client *client, uint32_t iaid, bool append_iaid, uint16_t duid_type, const void *duid, - size_t duid_len) { + size_t duid_len, + usec_t llt_time) { DHCP_CLIENT_DONT_DESTROY(client); int r; @@ -387,7 +388,7 @@ static int dhcp_client_set_iaid_duid( if (!client->mac_addr || client->mac_addr_len == 0) return -EOPNOTSUPP; - r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, 0, client->mac_addr, client->mac_addr_len, client->arp_type, &len); + r = dhcp_identifier_set_duid_llt(&client->client_id.ns.duid, llt_time, client->mac_addr, client->mac_addr_len, client->arp_type, &len); if (r < 0) return r; break; @@ -431,7 +432,14 @@ int sd_dhcp_client_set_iaid_duid( uint16_t duid_type, const void *duid, size_t duid_len) { - return dhcp_client_set_iaid_duid(client, iaid, true, duid_type, duid, duid_len); + return dhcp_client_set_iaid_duid_internal(client, iaid, true, duid_type, duid, duid_len, 0); +} + +int sd_dhcp_client_set_iaid_duid_llt( + sd_dhcp_client *client, + uint32_t iaid, + usec_t llt_time) { + return dhcp_client_set_iaid_duid_internal(client, iaid, true, DUID_TYPE_LLT, NULL, 0, llt_time); } int sd_dhcp_client_set_duid( @@ -439,7 +447,13 @@ int sd_dhcp_client_set_duid( uint16_t duid_type, const void *duid, size_t duid_len) { - return dhcp_client_set_iaid_duid(client, 0, false, duid_type, duid, duid_len); + return dhcp_client_set_iaid_duid_internal(client, 0, false, duid_type, duid, duid_len, 0); +} + +int sd_dhcp_client_set_duid_llt( + sd_dhcp_client *client, + usec_t llt_time) { + return dhcp_client_set_iaid_duid_internal(client, 0, false, DUID_TYPE_LLT, NULL, 0, llt_time); } int sd_dhcp_client_set_hostname( diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index d4831361bf..84c58af346 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -182,11 +182,12 @@ static int client_ensure_duid(sd_dhcp6_client *client) { * without further modification. Otherwise, if duid_type is supported, DUID * is set based on that type. Otherwise, an error is returned. */ -int sd_dhcp6_client_set_duid( +static int dhcp6_client_set_duid_internal( sd_dhcp6_client *client, uint16_t duid_type, const void *duid, - size_t duid_len) { + size_t duid_len, + usec_t llt_time) { int r; assert_return(client, -EINVAL); @@ -236,6 +237,20 @@ int sd_dhcp6_client_set_duid( return 0; } +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t duid_type, + const void *duid, + size_t duid_len) { + return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0); +} + +int sd_dhcp6_client_set_duid_llt( + sd_dhcp6_client *client, + usec_t llt_time) { + return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time); +} + int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) { assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 931b0e890b..e388552064 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -131,11 +131,18 @@ int sd_dhcp_client_set_iaid_duid( uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp_client_set_iaid_duid_llt( + sd_dhcp_client *client, + uint32_t iaid, + uint64_t llt_time); int sd_dhcp_client_set_duid( sd_dhcp_client *client, uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp_client_set_duid_llt( + sd_dhcp_client *client, + uint64_t llt_time); int sd_dhcp_client_get_client_id( sd_dhcp_client *client, uint8_t *type, diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 4f3b2d9e2e..fa36dca909 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -102,6 +102,9 @@ int sd_dhcp6_client_set_duid( uint16_t duid_type, const void *duid, size_t duid_len); +int sd_dhcp6_client_set_duid_llt( + sd_dhcp6_client *client, + uint64_t llt_time); int sd_dhcp6_client_set_iaid( sd_dhcp6_client *client, uint32_t iaid); From 0cf7c3fd215229e106304ff59e20654237726d28 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Aug 2018 13:57:48 +0900 Subject: [PATCH 11/12] network: accept additional time-value after ':' when DUIDType=link-layer-time --- src/network/networkd-conf.c | 69 +++++++++++++++++++++++- src/network/networkd-dhcp4.c | 31 +++++++---- src/network/networkd-dhcp6.c | 11 ++-- src/network/networkd-gperf.gperf | 2 +- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.h | 1 + src/network/test-networkd-conf.c | 27 ++++++---- 7 files changed, 115 insertions(+), 28 deletions(-) diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 05bbc0b3e9..334ffc3c57 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -31,7 +31,74 @@ static const char* const duid_type_table[_DUID_TYPE_MAX] = { [DUID_TYPE_UUID] = "uuid", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); -DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type"); + +int config_parse_duid_type( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ char *type_string = NULL; + const char *p = rvalue; + DUID *duid = data; + DUIDType type; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(duid); + + r = extract_first_word(&p, &type_string, ":", 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract DUID type from '%s', ignoring.", rvalue); + return 0; + } + + type = duid_type_from_string(type_string); + if (type < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to parse DUID type '%s', ignoring.", type_string); + return 0; + } + + if (!isempty(p)) { + usec_t u; + + if (type != DUID_TYPE_LLT) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + r = parse_timestamp(p, &u); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse timestamp, ignoring: %s", p); + return 0; + } + + duid->llt_time = u; + } + + duid->type = type; + + return 0; +} int config_parse_duid_rawdata( const char *unit, diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index a3bdf4f40a..18867d9401 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -669,26 +669,35 @@ int dhcp4_set_client_identifier(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: { - /* If configured, apply user specified DUID and/or IAID */ + /* If configured, apply user specified DUID and IAID */ const DUID *duid = link_get_duid(link); - r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); + if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) + r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client, + link->network->iaid, + duid->llt_time); + else + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); + return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m"); break; } case DHCP_CLIENT_ID_DUID_ONLY: { /* If configured, apply user specified DUID */ const DUID *duid = link_get_duid(link); - r = sd_dhcp_client_set_duid(link->dhcp_client, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); + if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) + r = sd_dhcp_client_set_duid_llt(link->dhcp_client, + duid->llt_time); + else + r = sd_dhcp_client_set_duid(link->dhcp_client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); break; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index aa400bc35b..fa6e18cd2c 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -495,10 +495,13 @@ int dhcp6_configure(Link *link) { return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set IAID: %m"); duid = link_get_duid(link); - r = sd_dhcp6_client_set_duid(client, - duid->type, - duid->raw_data_len > 0 ? duid->raw_data : NULL, - duid->raw_data_len); + if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) + r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time); + else + r = sd_dhcp6_client_set_duid(client, + duid->type, + duid->raw_data_len > 0 ? duid->raw_data : NULL, + duid->raw_data_len); if (r < 0) return log_link_error_errno(link, r, "DHCP6 CLIENT: Failed to set DUID: %m"); diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index 54161446bb..cc88fc0add 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -18,5 +18,5 @@ struct ConfigPerfItem; %struct-type %includes %% -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid.type) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid) DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid) diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 6ad5257f79..357231152e 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -130,7 +130,7 @@ DHCP.RequestBroadcast, config_parse_bool, DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCP.UserClass, config_parse_dhcp_user_class, 0, offsetof(Network, dhcp_user_class) -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type) +DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) DHCP.RouteTable, config_parse_dhcp_route_table, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 0cd1c75f14..484eca6a95 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -70,6 +70,7 @@ typedef struct DUID { uint8_t raw_data_len; uint8_t raw_data[MAX_DUID_LEN]; + usec_t llt_time; } DUID; typedef enum RADVPrefixDelegation { diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index fc1646f4bf..d05680d7e1 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -11,23 +11,30 @@ #include "networkd-conf.h" #include "networkd-network.h" -static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) { - DUIDType actual = 0; +static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected, usec_t expected_time) { + DUID actual = {}; int r; r = config_parse_duid_type("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL); - log_info_errno(r, "\"%s\" → %d (%m)", rvalue, actual); + log_info_errno(r, "\"%s\" → %d (%m)", rvalue, actual.type); assert_se(r == ret); - assert_se(expected == actual); + assert_se(expected == actual.type); + if (expected == DUID_TYPE_LLT) + assert_se(expected_time == actual.llt_time); } static void test_config_parse_duid_type(void) { - test_config_parse_duid_type_one("", 0, 0); - test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT); - test_config_parse_duid_type_one("vendor", 0, DUID_TYPE_EN); - test_config_parse_duid_type_one("link-layer", 0, DUID_TYPE_LL); - test_config_parse_duid_type_one("uuid", 0, DUID_TYPE_UUID); - test_config_parse_duid_type_one("foo", 0, 0); + test_config_parse_duid_type_one("", 0, 0, 0); + test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT, 0); + test_config_parse_duid_type_one("link-layer-time:2000-01-01 00:00:00 UTC", 0, DUID_TYPE_LLT, (usec_t) 946684800000000); + test_config_parse_duid_type_one("vendor", 0, DUID_TYPE_EN, 0); + test_config_parse_duid_type_one("vendor:2000-01-01 00:00:00 UTC", 0, 0, 0); + test_config_parse_duid_type_one("link-layer", 0, DUID_TYPE_LL, 0); + test_config_parse_duid_type_one("link-layer:2000-01-01 00:00:00 UTC", 0, 0, 0); + test_config_parse_duid_type_one("uuid", 0, DUID_TYPE_UUID, 0); + test_config_parse_duid_type_one("uuid:2000-01-01 00:00:00 UTC", 0, 0, 0); + test_config_parse_duid_type_one("foo", 0, 0, 0); + test_config_parse_duid_type_one("foo:2000-01-01 00:00:00 UTC", 0, 0, 0); } static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) { From 8fa266c2a4effa93c253e5dc499edabd52e8b4bb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 7 Aug 2018 14:03:57 +0900 Subject: [PATCH 12/12] man: mention that DUIDType=link-layer-time or link-layer uses MAC address --- man/networkd.conf.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index f5f7acbf67..c624d4de43 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -87,10 +87,12 @@ - + - Those values are parsed and can be used to set the DUID type - field, but DUID contents must be provided using DUIDRawData=. + If link-layer-time or link-layer is specified, + then the MAC address of the interface is used as a DUID value. The value link-layer-time + can take additional time value after a colon, e.g. link-layer-time:2018-01-23 12:34:56 UTC. + The default time value is 2000-01-01 00:00:00 UTC.