1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-25 10:04:04 +03:00

sd-dhcp-server: use sd_dhcp_client_id

This commit is contained in:
Yu Watanabe 2024-01-03 06:06:42 +09:00
parent cb924b9b6a
commit 95c48613f4
8 changed files with 85 additions and 136 deletions

View 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);

View 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);

View 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(). */

View 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);
}

View 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;
if (!client_id_data_size_is_valid(req->message->hlen))
return NULL;
/* set client id type to 1: Ethernet Link-Layer (RFC 2132) */
data[0] = 0x01;
memcpy(data + 1, req->message->chaddr, req->message->hlen);
if (sd_dhcp_client_id_set(&client_id, /* type = */ 1, req->message->chaddr, req->message->hlen) < 0)
return NULL;
static_lease = hashmap_get(server->static_leases_by_client_id,
&(DHCPClientId) {
.length = req->message->hlen + 1,
.data = data,
});
*ret = static_lease;
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(). */

View 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) {

View 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;

View 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;