Merge pull request #30704 from yuwata/sd-dhcp-server-lease
dhcp-server: use sd_dhcp_client_id and split out lease handling to sd-dhcp-server-lease.[ch]
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,25 +25,6 @@ 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;
|
||||
|
||||
uint8_t htype; /* e.g. ARPHRD_ETHER */
|
||||
uint8_t hlen; /* e.g. ETH_ALEN */
|
||||
be32_t address;
|
||||
be32_t gateway;
|
||||
uint8_t chaddr[16];
|
||||
usec_t expiration;
|
||||
char *hostname;
|
||||
} DHCPLease;
|
||||
|
||||
struct sd_dhcp_server {
|
||||
unsigned n_ref;
|
||||
|
||||
@@ -100,7 +82,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;
|
||||
@@ -113,20 +95,12 @@ typedef struct DHCPRequest {
|
||||
triple_timestamp timestamp;
|
||||
} DHCPRequest;
|
||||
|
||||
extern const struct hash_ops dhcp_lease_hash_ops;
|
||||
|
||||
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
|
||||
size_t length, const triple_timestamp *timestamp);
|
||||
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);
|
||||
|
||||
#define log_dhcp_server_errno(server, error, fmt, ...) \
|
||||
log_interface_prefix_full_errno( \
|
||||
"DHCPv4 server: ", \
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-dhcp-server-lease.h"
|
||||
|
||||
#include "dhcp-client-id-internal.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct sd_dhcp_server_lease {
|
||||
unsigned n_ref;
|
||||
|
||||
sd_dhcp_server *server;
|
||||
|
||||
sd_dhcp_client_id client_id;
|
||||
|
||||
uint8_t htype; /* e.g. ARPHRD_ETHER */
|
||||
uint8_t hlen; /* e.g. ETH_ALEN */
|
||||
be32_t address;
|
||||
be32_t gateway;
|
||||
uint8_t chaddr[16];
|
||||
usec_t expiration;
|
||||
char *hostname;
|
||||
} sd_dhcp_server_lease;
|
||||
|
||||
extern const struct hash_ops dhcp_server_lease_hash_ops;
|
||||
|
||||
int dhcp_server_put_lease(sd_dhcp_server *server, sd_dhcp_server_lease *lease, bool is_static);
|
||||
|
||||
int dhcp_server_set_lease(sd_dhcp_server *server, be32_t address, DHCPRequest *req, usec_t expiration);
|
||||
int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server);
|
||||
|
||||
sd_dhcp_server_lease* dhcp_server_get_static_lease(sd_dhcp_server *server, const DHCPRequest *req);
|
||||
@@ -18,16 +18,17 @@ ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags) {
|
||||
}
|
||||
|
||||
static int add_lease(sd_dhcp_server *server, const struct in_addr *server_address, uint8_t i) {
|
||||
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
||||
_cleanup_(sd_dhcp_server_lease_unrefp) sd_dhcp_server_lease *lease = NULL;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
|
||||
lease = new(DHCPLease, 1);
|
||||
lease = new(sd_dhcp_server_lease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
*lease = (DHCPLease) {
|
||||
*lease = (sd_dhcp_server_lease) {
|
||||
.n_ref = 1,
|
||||
.address = htobe32(UINT32_C(10) << 24 | i),
|
||||
.chaddr = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
|
||||
.expiration = UINT64_MAX,
|
||||
@@ -35,23 +36,13 @@ 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.raw[0] = 2;
|
||||
lease->client_id.raw[1] = i;
|
||||
|
||||
lease->client_id.data[0] = 2;
|
||||
lease->client_id.data[1] = i;
|
||||
|
||||
lease->server = server; /* This must be set just before hashmap_put(). */
|
||||
|
||||
r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
||||
r = dhcp_server_put_lease(server, lease, /* is_static = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ sources = files(
|
||||
'sd-dhcp-client.c',
|
||||
'sd-dhcp-duid.c',
|
||||
'sd-dhcp-lease.c',
|
||||
'sd-dhcp-server-lease.c',
|
||||
'sd-dhcp-server.c',
|
||||
'sd-dhcp6-client.c',
|
||||
'sd-dhcp6-lease.c',
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "dhcp-server-lease-internal.h"
|
||||
|
||||
static sd_dhcp_server_lease* dhcp_server_lease_free(sd_dhcp_server_lease *lease) {
|
||||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
if (lease->server) {
|
||||
hashmap_remove_value(lease->server->bound_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||
hashmap_remove_value(lease->server->bound_leases_by_client_id, &lease->client_id, lease);
|
||||
hashmap_remove_value(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||
hashmap_remove_value(lease->server->static_leases_by_client_id, &lease->client_id, lease);
|
||||
}
|
||||
|
||||
free(lease->hostname);
|
||||
return mfree(lease);
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_server_lease, sd_dhcp_server_lease, dhcp_server_lease_free);
|
||||
|
||||
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
dhcp_server_lease_hash_ops,
|
||||
sd_dhcp_client_id,
|
||||
client_id_hash_func,
|
||||
client_id_compare_func,
|
||||
sd_dhcp_server_lease,
|
||||
sd_dhcp_server_lease_unref);
|
||||
|
||||
int dhcp_server_put_lease(sd_dhcp_server *server, sd_dhcp_server_lease *lease, bool is_static) {
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(lease);
|
||||
|
||||
lease->server = server; /* This must be set before hashmap_put(). */
|
||||
|
||||
r = hashmap_ensure_put(is_static ? &server->static_leases_by_client_id : &server->bound_leases_by_client_id,
|
||||
&dhcp_server_lease_hash_ops, &lease->client_id, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = hashmap_ensure_put(is_static ? &server->static_leases_by_address : &server->bound_leases_by_address,
|
||||
NULL, UINT32_TO_PTR(lease->address), lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_server_set_lease(sd_dhcp_server *server, be32_t address, DHCPRequest *req, usec_t expiration) {
|
||||
_cleanup_(sd_dhcp_server_lease_unrefp) sd_dhcp_server_lease *lease = NULL;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(address != 0);
|
||||
assert(req);
|
||||
assert(expiration != 0);
|
||||
|
||||
/* If a lease for the host already exists, update it. */
|
||||
lease = hashmap_get(server->bound_leases_by_client_id, &req->client_id);
|
||||
if (lease) {
|
||||
if (lease->address != address) {
|
||||
hashmap_remove_value(server->bound_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||
lease->address = address;
|
||||
|
||||
r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
lease->expiration = expiration;
|
||||
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Otherwise, add a new lease. */
|
||||
|
||||
lease = new(sd_dhcp_server_lease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
*lease = (sd_dhcp_server_lease) {
|
||||
.n_ref = 1,
|
||||
.address = address,
|
||||
.client_id = req->client_id,
|
||||
.htype = req->message->htype,
|
||||
.hlen = req->message->hlen,
|
||||
.gateway = req->message->giaddr,
|
||||
.expiration = expiration,
|
||||
};
|
||||
|
||||
memcpy(lease->chaddr, req->message->chaddr, req->message->hlen);
|
||||
|
||||
if (req->hostname) {
|
||||
lease->hostname = strdup(req->hostname);
|
||||
if (!lease->hostname)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = dhcp_server_put_lease(server, lease, /* is_static = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) {
|
||||
sd_dhcp_server_lease *lease;
|
||||
usec_t time_now;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
|
||||
r = sd_event_now(server->event, CLOCK_BOOTTIME, &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(lease, server->bound_leases_by_client_id)
|
||||
if (lease->expiration < time_now) {
|
||||
log_dhcp_server(server, "CLEAN (0x%x)", be32toh(lease->address));
|
||||
sd_dhcp_server_lease_unref(lease);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_dhcp_server_lease* dhcp_server_get_static_lease(sd_dhcp_server *server, const DHCPRequest *req) {
|
||||
sd_dhcp_server_lease *static_lease;
|
||||
sd_dhcp_client_id client_id;
|
||||
|
||||
assert(server);
|
||||
assert(req);
|
||||
|
||||
static_lease = hashmap_get(server->static_leases_by_client_id, &req->client_id);
|
||||
if (static_lease)
|
||||
return static_lease;
|
||||
|
||||
/* when no lease is found based on the client id fall back to chaddr */
|
||||
if (!client_id_data_size_is_valid(req->message->hlen))
|
||||
return NULL;
|
||||
|
||||
if (sd_dhcp_client_id_set(&client_id, /* type = */ 1, req->message->chaddr, req->message->hlen) < 0)
|
||||
return NULL;
|
||||
|
||||
return hashmap_get(server->static_leases_by_client_id, &client_id);
|
||||
}
|
||||
|
||||
int sd_dhcp_server_set_static_lease(
|
||||
sd_dhcp_server *server,
|
||||
const struct in_addr *address,
|
||||
uint8_t *client_id_raw,
|
||||
size_t client_id_size) {
|
||||
|
||||
_cleanup_(sd_dhcp_server_lease_unrefp) sd_dhcp_server_lease *lease = NULL;
|
||||
sd_dhcp_client_id client_id;
|
||||
int r;
|
||||
|
||||
assert_return(server, -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) {
|
||||
sd_dhcp_server_lease_unref(hashmap_get(server->static_leases_by_client_id, &client_id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lease = new(sd_dhcp_server_lease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
*lease = (sd_dhcp_server_lease) {
|
||||
.n_ref = 1,
|
||||
.address = address->s_addr,
|
||||
.client_id = client_id,
|
||||
};
|
||||
|
||||
r = dhcp_server_put_lease(server, lease, /* is_static = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp-packet.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "dhcp-server-lease-internal.h"
|
||||
#include "dns-domain.h"
|
||||
#include "fd-util.h"
|
||||
#include "in-addr-util.h"
|
||||
@@ -29,22 +30,6 @@
|
||||
#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
|
||||
#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
|
||||
|
||||
DHCPLease *dhcp_lease_free(DHCPLease *lease) {
|
||||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
if (lease->server) {
|
||||
hashmap_remove_value(lease->server->bound_leases_by_address, UINT32_TO_PTR(lease->address), lease);
|
||||
hashmap_remove_value(lease->server->bound_leases_by_client_id, &lease->client_id, lease);
|
||||
hashmap_remove_value(lease->server->static_leases_by_address, UINT32_TO_PTR(lease->address), 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);
|
||||
}
|
||||
|
||||
/* configures the server's address and subnet, and optionally the pool's size and offset into the subnet
|
||||
* the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address
|
||||
* moreover, the server's own address may be in the pool, and is in that case reserved in order not to
|
||||
@@ -127,38 +112,6 @@ 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,
|
||||
client_id_hash_func,
|
||||
client_id_compare_func,
|
||||
DHCPLease,
|
||||
dhcp_lease_free);
|
||||
|
||||
static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
|
||||
assert(server);
|
||||
|
||||
@@ -786,16 +739,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 +778,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 +785,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 +796,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)
|
||||
@@ -1018,44 +964,7 @@ static int dhcp_server_relay_message(sd_dhcp_server *server, DHCPMessage *messag
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
static int prepare_new_lease(DHCPLease **ret_lease, be32_t address, DHCPRequest *req, usec_t expiration) {
|
||||
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
||||
|
||||
assert(ret_lease);
|
||||
assert(address != 0);
|
||||
assert(req);
|
||||
assert(expiration != 0);
|
||||
|
||||
lease = new(DHCPLease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
*lease = (DHCPLease) {
|
||||
.address = address,
|
||||
.client_id.length = req->client_id.length,
|
||||
.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);
|
||||
|
||||
if (req->hostname) {
|
||||
lease->hostname = strdup(req->hostname);
|
||||
if (!lease->hostname)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret_lease = TAKE_PTR(lease);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, DHCPLease *existing_lease, be32_t address) {
|
||||
static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, be32_t address) {
|
||||
usec_t expiration;
|
||||
int r;
|
||||
|
||||
@@ -1067,30 +976,9 @@ static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, DHCPLeas
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (existing_lease) {
|
||||
assert(existing_lease->server);
|
||||
assert(existing_lease->address == address);
|
||||
existing_lease->expiration = expiration;
|
||||
|
||||
} else {
|
||||
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
||||
|
||||
r = prepare_new_lease(&lease, address, req, expiration);
|
||||
if (r < 0)
|
||||
return log_dhcp_server_errno(server, r, "Failed to create new lease: %m");
|
||||
|
||||
lease->server = server; /* This must be set just before hashmap_put(). */
|
||||
|
||||
r = hashmap_ensure_put(&server->bound_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
||||
if (r < 0)
|
||||
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
||||
|
||||
r = hashmap_ensure_put(&server->bound_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
||||
if (r < 0)
|
||||
return log_dhcp_server_errno(server, r, "Could not save lease: %m");
|
||||
|
||||
TAKE_PTR(lease);
|
||||
}
|
||||
r = dhcp_server_set_lease(server, address, req, expiration);
|
||||
if (r < 0)
|
||||
return log_dhcp_server_errno(server, r, "Failed to create new lease: %m");
|
||||
|
||||
r = server_send_offer_or_ack(server, req, address, DHCP_ACK);
|
||||
if (r < 0)
|
||||
@@ -1104,26 +992,6 @@ static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, DHCPLeas
|
||||
return DHCP_ACK;
|
||||
}
|
||||
|
||||
static int dhcp_server_cleanup_expired_leases(sd_dhcp_server *server) {
|
||||
DHCPLease *lease;
|
||||
usec_t time_now;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
|
||||
r = sd_event_now(server->event, CLOCK_BOOTTIME, &time_now);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(lease, server->bound_leases_by_client_id)
|
||||
if (lease->expiration < time_now) {
|
||||
log_dhcp_server(server, "CLEAN (0x%x)", be32toh(lease->address));
|
||||
dhcp_lease_free(lease);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool address_available(sd_dhcp_server *server, be32_t address) {
|
||||
assert(server);
|
||||
|
||||
@@ -1135,46 +1003,12 @@ 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) {
|
||||
DHCPLease *static_lease;
|
||||
_cleanup_free_ uint8_t *data = NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
});
|
||||
|
||||
*ret = static_lease;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(0d,1d,fe,bd,f1,24,bd,b3,47,f1,dd,6e,73,21,93,30)
|
||||
|
||||
int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length, const triple_timestamp *timestamp) {
|
||||
_cleanup_(dhcp_request_freep) DHCPRequest *req = NULL;
|
||||
_cleanup_free_ char *error_message = NULL;
|
||||
DHCPLease *existing_lease, *static_lease;
|
||||
sd_dhcp_server_lease *existing_lease, *static_lease;
|
||||
int type, r;
|
||||
|
||||
assert(server);
|
||||
@@ -1202,9 +1036,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 = dhcp_server_get_static_lease(server, req);
|
||||
|
||||
switch (type) {
|
||||
|
||||
@@ -1250,7 +1082,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
return 0;
|
||||
|
||||
if (server->rapid_commit && req->rapid_commit)
|
||||
return server_ack_request(server, req, existing_lease, address);
|
||||
return server_ack_request(server, req, address);
|
||||
|
||||
r = server_send_offer_or_ack(server, req, address, DHCP_OFFER);
|
||||
if (r < 0)
|
||||
@@ -1330,7 +1162,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
/* The client requested an address which is different from the static lease. Refuse. */
|
||||
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||
|
||||
return server_ack_request(server, req, existing_lease, address);
|
||||
return server_ack_request(server, req, address);
|
||||
}
|
||||
|
||||
if (address_is_in_pool(server, address)) {
|
||||
@@ -1340,7 +1172,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
/* We previously assigned an address, but the client requested another one. Refuse. */
|
||||
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||
|
||||
return server_ack_request(server, req, existing_lease, address);
|
||||
return server_ack_request(server, req, address);
|
||||
}
|
||||
|
||||
return server_send_nak_or_ignore(server, init_reboot, req);
|
||||
@@ -1356,7 +1188,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
if (existing_lease->address != req->message->ciaddr)
|
||||
return 0;
|
||||
|
||||
dhcp_lease_free(existing_lease);
|
||||
sd_dhcp_server_lease_unref(existing_lease);
|
||||
|
||||
if (server->callback)
|
||||
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
||||
@@ -1523,7 +1355,7 @@ on_error:
|
||||
}
|
||||
|
||||
int sd_dhcp_server_forcerenew(sd_dhcp_server *server) {
|
||||
DHCPLease *lease;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r = 0;
|
||||
|
||||
assert_return(server, -EINVAL);
|
||||
@@ -1737,56 +1569,3 @@ int sd_dhcp_server_set_relay_agent_information(
|
||||
free_and_replace(server->agent_remote_id, remote_id_dup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_server_set_static_lease(
|
||||
sd_dhcp_server *server,
|
||||
const struct in_addr *address,
|
||||
uint8_t *client_id,
|
||||
size_t client_id_size) {
|
||||
|
||||
_cleanup_(dhcp_lease_freep) DHCPLease *lease = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(server, -EINVAL);
|
||||
assert_return(client_id, -EINVAL);
|
||||
assert_return(client_id_size > 0, -EINVAL);
|
||||
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
|
||||
|
||||
/* 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));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lease = new(DHCPLease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
*lease = (DHCPLease) {
|
||||
.address = address->s_addr,
|
||||
.client_id.length = client_id_size,
|
||||
};
|
||||
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(). */
|
||||
|
||||
r = hashmap_ensure_put(&server->static_leases_by_client_id, &dhcp_lease_hash_ops, &lease->client_id, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = hashmap_ensure_put(&server->static_leases_by_address, NULL, UINT32_TO_PTR(lease->address), lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-util.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "dhcp-server-lease-internal.h"
|
||||
#include "networkd-dhcp-server-bus.h"
|
||||
#include "networkd-link-bus.h"
|
||||
#include "networkd-manager.h"
|
||||
@@ -19,7 +19,7 @@ static int property_get_leases(
|
||||
sd_bus_error *error) {
|
||||
Link *l = ASSERT_PTR(userdata);
|
||||
sd_dhcp_server *s;
|
||||
DHCPLease *lease;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <linux/nexthop.h>
|
||||
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "dhcp-server-lease-internal.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "dns-domain.h"
|
||||
@@ -892,7 +892,7 @@ static int pref64_append_json(Link *link, JsonVariant **v) {
|
||||
|
||||
static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
DHCPLease *lease;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -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(
|
||||
@@ -924,7 +924,7 @@ static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) {
|
||||
|
||||
static int dhcp_server_static_leases_append_json(Link *link, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
DHCPLease *lease;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -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;
|
||||
|
||||
@@ -26,6 +26,7 @@ _not_installed_headers = [
|
||||
'sd-dhcp-lease.h',
|
||||
'sd-dhcp-option.h',
|
||||
'sd-dhcp-protocol.h',
|
||||
'sd-dhcp-server-lease.h',
|
||||
'sd-dhcp-server.h',
|
||||
'sd-dhcp6-client.h',
|
||||
'sd-dhcp6-lease.h',
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpserverleasehfoo
|
||||
#define foosddhcpserverleasehfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_dhcp_server_lease sd_dhcp_server_lease;
|
||||
|
||||
sd_dhcp_server_lease *sd_dhcp_server_lease_ref(sd_dhcp_server_lease *lease);
|
||||
sd_dhcp_server_lease *sd_dhcp_server_lease_unref(sd_dhcp_server_lease *lease);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_server_lease, sd_dhcp_server_lease_unref);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user