]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-dhcp-server: use sd_dhcp_client_id
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 2 Jan 2024 21:06:42 +0000 (06:06 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 3 Jan 2024 06:20:31 +0000 (15:20 +0900)
src/libsystemd-network/dhcp-client-id-internal.h
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/fuzz-dhcp-server.c
src/libsystemd-network/sd-dhcp-client-id.c
src/libsystemd-network/sd-dhcp-server.c
src/libsystemd-network/test-dhcp-server.c
src/network/networkd-dhcp-server-bus.c
src/network/networkd-json.c

index eb7b1847e6768e10e4ca0716662cdeb6c9ae2e60..72f13de24e8b36a0b3982c228b0ce2369026c02b 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "dhcp-duid-internal.h"
 #include "macro.h"
+#include "siphash24.h"
 #include "sparse-endian.h"
 
 /* RFC 2132 section 9.14: its minimum length is 2.
@@ -51,3 +52,6 @@ static inline bool client_id_size_is_valid(size_t size) {
 static inline bool client_id_data_size_is_valid(size_t size) {
         return size >= MIN_CLIENT_ID_DATA_LEN && size <= MAX_CLIENT_ID_DATA_LEN;
 }
+
+void client_id_hash_func(const sd_dhcp_client_id *client_id, struct siphash *state);
+int client_id_compare_func(const sd_dhcp_client_id *a, const sd_dhcp_client_id *b);
index da9e56b943f2d09c30faeec29284370c322de9f6..5991ae6adad49f8f2e745abbaae1720035d1fd8c 100644 (file)
@@ -8,6 +8,7 @@
 #include "sd-dhcp-server.h"
 #include "sd-event.h"
 
+#include "dhcp-client-id-internal.h"
 #include "dhcp-option.h"
 #include "network-common.h"
 #include "ordered-set.h"
@@ -24,15 +25,10 @@ typedef enum DHCPRawOption {
         _DHCP_RAW_OPTION_DATA_INVALID,
 } DHCPRawOption;
 
-typedef struct DHCPClientId {
-        size_t length;
-        uint8_t *data;
-} DHCPClientId;
-
 typedef struct DHCPLease {
         sd_dhcp_server *server;
 
-        DHCPClientId client_id;
+        sd_dhcp_client_id client_id;
 
         uint8_t htype; /* e.g. ARPHRD_ETHER */
         uint8_t hlen;  /* e.g. ETH_ALEN */
@@ -100,7 +96,7 @@ typedef struct DHCPRequest {
         DHCPMessage *message;
 
         /* options */
-        DHCPClientId client_id;
+        sd_dhcp_client_id client_id;
         size_t max_optlen;
         be32_t server_id;
         be32_t requested_ip;
@@ -121,9 +117,6 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
                             DHCPRequest *req, DHCPPacket *packet,
                             int type, size_t optoffset);
 
-void client_id_hash_func(const DHCPClientId *p, struct siphash *state);
-int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b);
-
 DHCPLease *dhcp_lease_free(DHCPLease *lease);
 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPLease*, dhcp_lease_free);
 
index fddb3a59ebef6137ac65828edaa2bbcdab02ed06..3929a2a4d754bc492cd74e7bf8b56ab674345972 100644 (file)
@@ -35,15 +35,11 @@ static int add_lease(sd_dhcp_server *server, const struct in_addr *server_addres
                 .hlen = ETH_ALEN,
                 .htype = ARPHRD_ETHER,
 
-                .client_id.length = 2,
+                .client_id.size = 2,
         };
 
-        lease->client_id.data = new(uint8_t, lease->client_id.length);
-        if (!lease->client_id.data)
-                return -ENOMEM;
-
-        lease->client_id.data[0] = 2;
-        lease->client_id.data[1] = i;
+        lease->client_id.raw[0] = 2;
+        lease->client_id.raw[1] = i;
 
         lease->server = server; /* This must be set just before hashmap_put(). */
 
index 03dca4382223ea806f0db0c7d1dd47cb67aa404e..6feec25adf08ea891a79ebb5b666f582f00ceb6e 100644 (file)
@@ -157,3 +157,18 @@ int sd_dhcp_client_id_to_string_from_raw(const void *data, size_t data_size, cha
 
         return sd_dhcp_client_id_to_string(&client_id, ret);
 }
+
+void client_id_hash_func(const sd_dhcp_client_id *client_id, struct siphash *state) {
+        assert(sd_dhcp_client_id_is_set(client_id));
+        assert(state);
+
+        siphash24_compress_typesafe(client_id->size, state);
+        siphash24_compress(client_id->raw, client_id->size, state);
+}
+
+int client_id_compare_func(const sd_dhcp_client_id *a, const sd_dhcp_client_id *b) {
+        assert(sd_dhcp_client_id_is_set(a));
+        assert(sd_dhcp_client_id_is_set(b));
+
+        return memcmp_nn(a->raw, a->size, b->raw, b->size);
+}
index 7eaca0bb710b9eca09577e10a2e800082ec74d65..7ece30cf7bec1e467f6b3455135fa9b5d22e8f11 100644 (file)
@@ -40,7 +40,6 @@ DHCPLease *dhcp_lease_free(DHCPLease *lease) {
                 hashmap_remove_value(lease->server->static_leases_by_client_id, &lease->client_id, lease);
         }
 
-        free(lease->client_id.data);
         free(lease->hostname);
         return mfree(lease);
 }
@@ -127,33 +126,9 @@ int sd_dhcp_server_is_in_relay_mode(sd_dhcp_server *server) {
         return in4_addr_is_set(&server->relay_target);
 }
 
-void client_id_hash_func(const DHCPClientId *id, struct siphash *state) {
-        assert(id);
-        assert(id->length > 0);
-        assert(id->data);
-
-        siphash24_compress_typesafe(id->length, state);
-        siphash24_compress(id->data, id->length, state);
-}
-
-int client_id_compare_func(const DHCPClientId *a, const DHCPClientId *b) {
-        int r;
-
-        assert(a->length > 0);
-        assert(a->data);
-        assert(b->length > 0);
-        assert(b->data);
-
-        r = CMP(a->length, b->length);
-        if (r != 0)
-                return r;
-
-        return memcmp(a->data, b->data, a->length);
-}
-
 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
         dhcp_lease_hash_ops,
-        DHCPClientId,
+        sd_dhcp_client_id,
         client_id_hash_func,
         client_id_compare_func,
         DHCPLease,
@@ -786,16 +761,8 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
 
                 break;
         case SD_DHCP_OPTION_CLIENT_IDENTIFIER:
-                if (len >= 2) {
-                        uint8_t *data;
-
-                        data = memdup(option, len);
-                        if (!data)
-                                return -ENOMEM;
-
-                        free_and_replace(req->client_id.data, data);
-                        req->client_id.length = len;
-                }
+                if (client_id_size_is_valid(len))
+                        (void) sd_dhcp_client_id_set_raw(&req->client_id, option, len);
 
                 break;
         case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE:
@@ -833,7 +800,6 @@ static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
         if (!req)
                 return NULL;
 
-        free(req->client_id.data);
         free(req->hostname);
         return mfree(req);
 }
@@ -841,6 +807,8 @@ static DHCPRequest* dhcp_request_free(DHCPRequest *req) {
 DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free);
 
 static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMessage *message) {
+        int r;
+
         assert(req);
         assert(message);
 
@@ -850,39 +818,39 @@ static int ensure_sane_request(sd_dhcp_server *server, DHCPRequest *req, DHCPMes
                 return -EBADMSG;
 
         /* set client id based on MAC address if client did not send an explicit one */
-        if (!req->client_id.data) {
-                uint8_t *data;
-
-                if (message->hlen == 0)
+        if (!sd_dhcp_client_id_is_set(&req->client_id)) {
+                if (!client_id_data_size_is_valid(message->hlen))
                         return -EBADMSG;
 
-                data = new0(uint8_t, message->hlen + 1);
-                if (!data)
-                        return -ENOMEM;
-
-                data[0] = 0x01;
-                memcpy(data + 1, message->chaddr, message->hlen);
-
-                req->client_id.length = message->hlen + 1;
-                req->client_id.data = data;
+                r = sd_dhcp_client_id_set(&req->client_id, /* type = */ 1, message->chaddr, message->hlen);
+                if (r < 0)
+                        return r;
         }
 
         if (message->hlen == 0 || memeqzero(message->chaddr, message->hlen)) {
+                uint8_t type;
+                const void *data;
+                size_t size;
+
                 /* See RFC2131 section 4.1.1.
                  * hlen and chaddr may not be set for non-ethernet interface.
                  * Let's try to retrieve it from the client ID. */
 
-                if (!req->client_id.data)
+                if (!sd_dhcp_client_id_is_set(&req->client_id))
                         return -EBADMSG;
 
-                if (req->client_id.length <= 1 || req->client_id.length > sizeof(message->chaddr) + 1)
+                r = sd_dhcp_client_id_get(&req->client_id, &type, &data, &size);
+                if (r < 0)
+                        return r;
+
+                if (type != 1)
                         return -EBADMSG;
 
-                if (req->client_id.data[0] != 0x01)
+                if (size > sizeof(message->chaddr))
                         return -EBADMSG;
 
-                message->hlen = req->client_id.length - 1;
-                memcpy(message->chaddr, req->client_id.data + 1, message->hlen);
+                memcpy(message->chaddr, data, size);
+                message->hlen = size;
         }
 
         if (req->max_optlen < DHCP_MIN_OPTIONS_SIZE)
@@ -1032,15 +1000,12 @@ static int prepare_new_lease(DHCPLease **ret_lease, be32_t address, DHCPRequest
 
         *lease = (DHCPLease) {
                 .address = address,
-                .client_id.length = req->client_id.length,
+                .client_id = req->client_id,
                 .htype = req->message->htype,
                 .hlen = req->message->hlen,
                 .gateway = req->message->giaddr,
                 .expiration = expiration,
         };
-        lease->client_id.data = memdup(req->client_id.data, req->client_id.length);
-        if (!lease->client_id.data)
-                return -ENOMEM;
 
         memcpy(lease->chaddr, req->message->chaddr, req->message->hlen);
 
@@ -1135,38 +1100,25 @@ static bool address_available(sd_dhcp_server *server, be32_t address) {
         return true;
 }
 
-static int server_get_static_lease(sd_dhcp_server *server, const DHCPRequest *req, DHCPLease **ret) {
+static DHCPLease* server_get_static_lease(sd_dhcp_server *server, const DHCPRequest *req) {
         DHCPLease *static_lease;
-        _cleanup_free_ uint8_t *data = NULL;
+        sd_dhcp_client_id client_id;
 
         assert(server);
         assert(req);
-        assert(ret);
 
         static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id);
-        if (static_lease) {
-                *ret = static_lease;
-                return 0;
-        }
+        if (static_lease)
+                return static_lease;
 
         /* when no lease is found based on the client id fall back to chaddr */
-        data = new(uint8_t, req->message->hlen + 1);
-        if (!data)
-                return -ENOMEM;
-
-        /* set client id type to 1: Ethernet Link-Layer (RFC 2132) */
-        data[0] = 0x01;
-        memcpy(data + 1, req->message->chaddr, req->message->hlen);
-
-        static_lease = hashmap_get(server->static_leases_by_client_id,
-                                   &(DHCPClientId) {
-                                           .length = req->message->hlen + 1,
-                                           .data = data,
-                                   });
+        if (!client_id_data_size_is_valid(req->message->hlen))
+                return NULL;
 
-        *ret = static_lease;
+        if (sd_dhcp_client_id_set(&client_id, /* type = */ 1, req->message->chaddr, req->message->hlen) < 0)
+                return NULL;
 
-        return 0;
+        return hashmap_get(server->static_leases_by_client_id, &client_id);
 }
 
 #define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
@@ -1202,9 +1154,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
                 return r;
 
         existing_lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id);
-        r = server_get_static_lease(server, req, &static_lease);
-        if (r < 0)
-                return r;
+        static_lease = server_get_static_lease(server, req);
 
         switch (type) {
 
@@ -1741,28 +1691,26 @@ int sd_dhcp_server_set_relay_agent_information(
 int sd_dhcp_server_set_static_lease(
                 sd_dhcp_server *server,
                 const struct in_addr *address,
-                uint8_t *client_id,
+                uint8_t *client_id_raw,
                 size_t client_id_size) {
 
         _cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
+        sd_dhcp_client_id client_id;
         int r;
 
         assert_return(server, -EINVAL);
-        assert_return(client_id, -EINVAL);
-        assert_return(client_id_size > 0, -EINVAL);
+        assert_return(client_id_raw, -EINVAL);
+        assert_return(client_id_size_is_valid(client_id_size), -EINVAL);
         assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
 
+        r = sd_dhcp_client_id_set_raw(&client_id, client_id_raw, client_id_size);
+        if (r < 0)
+                return r;
+
         /* Static lease with an empty or omitted address is a valid entry,
          * the server removes any static lease with the specified mac address. */
         if (!address || address->s_addr == 0) {
-                DHCPClientId c;
-
-                c = (DHCPClientId) {
-                        .length = client_id_size,
-                        .data = client_id,
-                };
-
-                dhcp_lease_free(hashmap_get(server->static_leases_by_client_id, &c));
+                dhcp_lease_free(hashmap_get(server->static_leases_by_client_id, &client_id));
                 return 0;
         }
 
@@ -1772,11 +1720,8 @@ int sd_dhcp_server_set_static_lease(
 
         *lease = (DHCPLease) {
                 .address = address->s_addr,
-                .client_id.length = client_id_size,
+                .client_id = client_id,
         };
-        lease->client_id.data = memdup(client_id, client_id_size);
-        if (!lease->client_id.data)
-                return -ENOMEM;
 
         lease->server = server; /* This must be set just before hashmap_put(). */
 
index e04a819eea78617120390ad44cfcde029a4e44d1..9c343f8368d77217052c7071ecbd6ac632d4bec3 100644 (file)
@@ -223,7 +223,7 @@ static void test_message_handler(void) {
         assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test), NULL) == DHCP_ACK);
 }
 
-static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
+static uint64_t client_id_hash_helper(sd_dhcp_client_id *id, uint8_t key[HASH_KEY_SIZE]) {
         struct siphash state;
 
         siphash24_init(&state, key);
@@ -233,10 +233,10 @@ static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZ
 }
 
 static void test_client_id_hash(void) {
-        DHCPClientId a = {
-                .length = 4,
+        sd_dhcp_client_id a = {
+                .size = 4,
         }, b = {
-                .length = 4,
+                .size = 4,
         };
         uint8_t hash_key[HASH_KEY_SIZE] = {
                 '0', '1', '2', '3', '4', '5', '6', '7',
@@ -245,29 +245,25 @@ static void test_client_id_hash(void) {
 
         log_debug("/* %s */", __func__);
 
-        a.data = (uint8_t*)strdup("abcd");
-        b.data = (uint8_t*)strdup("abcd");
+        memcpy(a.raw, "abcd", 4);
+        memcpy(b.raw, "abcd", 4);
 
         assert_se(client_id_compare_func(&a, &b) == 0);
         assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
-        a.length = 3;
+        a.size = 3;
         assert_se(client_id_compare_func(&a, &b) != 0);
-        a.length = 4;
+        a.size = 4;
         assert_se(client_id_compare_func(&a, &b) == 0);
         assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
 
-        b.length = 3;
+        b.size = 3;
         assert_se(client_id_compare_func(&a, &b) != 0);
-        b.length = 4;
+        b.size = 4;
         assert_se(client_id_compare_func(&a, &b) == 0);
         assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
 
-        free(b.data);
-        b.data = (uint8_t*)strdup("abce");
+        memcpy(b.raw, "abce", 4);
         assert_se(client_id_compare_func(&a, &b) != 0);
-
-        free(a.data);
-        free(b.data);
 }
 
 static void test_static_lease(void) {
index e3397c32082d55267f2d611cc51cbd60bb3ec649..0197f8ad7b27ace378b099f63a3f50b74c07762a 100644 (file)
@@ -44,7 +44,7 @@ static int property_get_leases(
                 if (r < 0)
                         return r;
 
-                r = sd_bus_message_append_array(reply, 'y', lease->client_id.data, lease->client_id.length);
+                r = sd_bus_message_append_array(reply, 'y', lease->client_id.raw, lease->client_id.size);
                 if (r < 0)
                         return r;
 
index bc7e51ebe305e391885b762c49d3c71b7fd1c02d..f7a4ed0141ae0ce15ff384b615432c30d157a0ac 100644 (file)
@@ -909,8 +909,8 @@ static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) {
                                 JSON_BUILD_OBJECT(
                                                 JSON_BUILD_PAIR_BYTE_ARRAY(
                                                                 "ClientId",
-                                                                lease->client_id.data,
-                                                                lease->client_id.length),
+                                                                lease->client_id.raw,
+                                                                lease->client_id.size),
                                                 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address),
                                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease->hostname),
                                                 JSON_BUILD_PAIR_FINITE_USEC(
@@ -941,8 +941,8 @@ static int dhcp_server_static_leases_append_json(Link *link, JsonVariant **v) {
                                JSON_BUILD_OBJECT(
                                                JSON_BUILD_PAIR_BYTE_ARRAY(
                                                                "ClientId",
-                                                               lease->client_id.data,
-                                                               lease->client_id.length),
+                                                               lease->client_id.raw,
+                                                               lease->client_id.size),
                                                JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address)));
                 if (r < 0)
                         return r;