Merge pull request #31791 from yuwata/sd-dhcp-server-several-preparations

sd-dhcp-server: several cleanups and extension
This commit is contained in:
Luca Boccassi
2024-03-15 15:04:04 +00:00
committed by GitHub
7 changed files with 121 additions and 47 deletions

View File

@@ -76,6 +76,7 @@ struct sd_dhcp_server {
char *agent_circuit_id;
char *agent_remote_id;
int lease_dir_fd;
char *lease_file;
};

View File

@@ -38,3 +38,8 @@ int dhcp_server_static_leases_append_json(sd_dhcp_server *server, JsonVariant **
int dhcp_server_save_leases(sd_dhcp_server *server);
int dhcp_server_load_leases(sd_dhcp_server *server);
int dhcp_server_leases_file_get_server_address(
int dir_fd,
const char *path,
struct in_addr *ret_address,
uint8_t *ret_prefixlen);

View File

@@ -69,7 +69,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
struct in_addr address = { .s_addr = htobe32(UINT32_C(10) << 24 | UINT32_C(1))};
_cleanup_free_ uint8_t *duped = NULL;
_cleanup_free_ char *lease_file = NULL;
_cleanup_close_ int dir_fd = -EBADF;
if (size < sizeof(DHCPMessage))
return 0;
@@ -78,12 +78,12 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(duped = memdup(data, size));
assert_se(mkdtemp_malloc(NULL, &tmpdir) >= 0);
assert_se(lease_file = path_join(tmpdir, "leases"));
dir_fd = mkdtemp_open(NULL, 0, &tmpdir);
assert_se(dir_fd >= 0);
assert_se(sd_dhcp_server_new(&server, 1) >= 0);
assert_se(sd_dhcp_server_attach_event(server, NULL, 0) >= 0);
assert_se(sd_dhcp_server_set_lease_file(server, lease_file) >= 0);
assert_se(sd_dhcp_server_set_lease_file(server, dir_fd, "leases") >= 0);
server->fd = open("/dev/null", O_RDWR|O_CLOEXEC|O_NOCTTY);
assert_se(server->fd >= 0);
assert_se(sd_dhcp_server_configure_pool(server, &address, 24, 0, 0) >= 0);

View File

@@ -286,7 +286,7 @@ int dhcp_server_static_leases_append_json(sd_dhcp_server *server, JsonVariant **
int dhcp_server_save_leases(sd_dhcp_server *server) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
sd_id128_t boot_id;
int r;
@@ -307,7 +307,11 @@ int dhcp_server_save_leases(sd_dhcp_server *server) {
if (r < 0)
return r;
r = json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_ID128("BootID", boot_id)));
r = json_build(&v, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR_ID128("BootID", boot_id),
JSON_BUILD_PAIR_IN4_ADDR("Address", &(struct in_addr) { .s_addr = server->address }),
JSON_BUILD_PAIR_UNSIGNED("PrefixLength",
in4_addr_netmask_to_prefixlen(&(struct in_addr) { .s_addr = server->netmask }))));
if (r < 0)
return r;
@@ -315,11 +319,11 @@ int dhcp_server_save_leases(sd_dhcp_server *server) {
if (r < 0)
return r;
r = mkdir_parents(server->lease_file, 0755);
r = mkdirat_parents(server->lease_dir_fd, server->lease_file, 0755);
if (r < 0)
return r;
r = fopen_temporary(server->lease_file, &f, &temp_path);
r = fopen_temporary_at(server->lease_dir_fd, server->lease_file, &f, &temp_path);
if (r < 0)
return r;
@@ -327,14 +331,17 @@ int dhcp_server_save_leases(sd_dhcp_server *server) {
r = json_variant_dump(v, JSON_FORMAT_NEWLINE | JSON_FORMAT_FLUSH, f, /* prefix = */ NULL);
if (r < 0)
return r;
goto failure;
r = conservative_rename(temp_path, server->lease_file);
r = conservative_renameat(server->lease_dir_fd, temp_path, server->lease_dir_fd, server->lease_file);
if (r < 0)
return r;
goto failure;
temp_path = mfree(temp_path);
return 0;
failure:
(void) unlinkat(server->lease_dir_fd, temp_path, /* flags = */ 0);
return r;
}
static int json_dispatch_dhcp_lease(sd_dhcp_server *server, JsonVariant *v, bool use_boottime) {
@@ -405,37 +412,51 @@ static int json_dispatch_dhcp_lease(sd_dhcp_server *server, JsonVariant *v, bool
typedef struct SavedInfo {
sd_id128_t boot_id;
struct in_addr address;
uint8_t prefixlen;
JsonVariant *leases;
} SavedInfo;
static int dhcp_server_dispatch_leases(sd_dhcp_server *server, JsonVariant *v) {
static const JsonDispatch dispatch_table[] = {
{ "BootID", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(SavedInfo, boot_id), JSON_MANDATORY },
{ "Leases", JSON_VARIANT_ARRAY, json_dispatch_variant_noref, offsetof(SavedInfo, leases), JSON_MANDATORY },
static void saved_info_done(SavedInfo *info) {
if (!info)
return;
json_variant_unref(info->leases);
}
static int load_leases_file(int dir_fd, const char *path, SavedInfo *ret) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(path);
assert(ret);
r = json_parse_file_at(
/* f = */ NULL,
dir_fd,
path,
/* flags = */ 0,
&v,
/* ret_line = */ NULL,
/* ret_column = */ NULL);
if (r < 0)
return r;
static const JsonDispatch dispatch_lease_file_table[] = {
{ "BootID", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(SavedInfo, boot_id), JSON_MANDATORY },
{ "Address", JSON_VARIANT_ARRAY, json_dispatch_in_addr, offsetof(SavedInfo, address), JSON_MANDATORY },
{ "PrefixLength", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint8, offsetof(SavedInfo, prefixlen), JSON_MANDATORY },
{ "Leases", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(SavedInfo, leases), JSON_MANDATORY },
{}
};
SavedInfo info = {};
sd_id128_t boot_id;
int r;
r = json_dispatch(v, dispatch_table, JSON_ALLOW_EXTENSIONS, &info);
if (r < 0)
return r;
r = sd_id128_get_boot(&boot_id);
if (r < 0)
return r;
JsonVariant *i;
JSON_VARIANT_ARRAY_FOREACH(i, info.leases)
RET_GATHER(r, json_dispatch_dhcp_lease(server, i, /* use_boottime = */ sd_id128_equal(info.boot_id, boot_id)));
return r;
return json_dispatch(v, dispatch_lease_file_table, JSON_ALLOW_EXTENSIONS, ret);
}
int dhcp_server_load_leases(sd_dhcp_server *server) {
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(saved_info_done) SavedInfo info = {};
sd_id128_t boot_id;
size_t n, m;
int r;
@@ -445,21 +466,21 @@ int dhcp_server_load_leases(sd_dhcp_server *server) {
if (!server->lease_file)
return 0;
r = json_parse_file(
/* f = */ NULL,
server->lease_file,
/* flags = */ 0,
&v,
/* ret_line = */ NULL,
/* ret_column = */ NULL);
r = load_leases_file(server->lease_dir_fd, server->lease_file, &info);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
r = sd_id128_get_boot(&boot_id);
if (r < 0)
return r;
n = hashmap_size(server->bound_leases_by_client_id);
r = dhcp_server_dispatch_leases(server, v);
JsonVariant *i;
JSON_VARIANT_ARRAY_FOREACH(i, info.leases)
RET_GATHER(r, json_dispatch_dhcp_lease(server, i, /* use_boottime = */ sd_id128_equal(info.boot_id, boot_id)));
m = hashmap_size(server->bound_leases_by_client_id);
assert(m >= n);
@@ -467,3 +488,26 @@ int dhcp_server_load_leases(sd_dhcp_server *server) {
return r;
}
int dhcp_server_leases_file_get_server_address(
int dir_fd,
const char *path,
struct in_addr *ret_address,
uint8_t *ret_prefixlen) {
_cleanup_(saved_info_done) SavedInfo info = {};
int r;
if (!ret_address && !ret_prefixlen)
return 0;
r = load_leases_file(dir_fd, path, &info);
if (r < 0)
return r;
if (ret_address)
*ret_address = info.address;
if (ret_prefixlen)
*ret_prefixlen = info.prefixlen;
return 0;
}

View File

@@ -144,6 +144,7 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
free(server->agent_circuit_id);
free(server->agent_remote_id);
safe_close(server->lease_dir_fd);
free(server->lease_file);
free(server->ifname);
@@ -174,6 +175,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
.default_lease_time = DHCP_DEFAULT_LEASE_TIME_USEC,
.max_lease_time = DHCP_MAX_LEASE_TIME_USEC,
.rapid_commit = true,
.lease_dir_fd = -EBADF,
};
*ret = TAKE_PTR(server);
@@ -1586,12 +1588,34 @@ int sd_dhcp_server_set_relay_agent_information(
return 0;
}
int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, const char *path) {
int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char *path) {
int r;
assert_return(server, -EINVAL);
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
if (path && !path_is_safe(path))
if (!path) {
/* When NULL, clear the previous assignment. */
server->lease_file = mfree(server->lease_file);
server->lease_dir_fd = safe_close(server->lease_dir_fd);
return 0;
}
if (!path_is_safe(path))
return -EINVAL;
return free_and_strdup(&server->lease_file, path);
if (dir_fd < 0 && dir_fd != AT_FDCWD)
return -EBADF;
_cleanup_close_ int fd = -EBADF;
fd = fd_reopen(dir_fd, O_CLOEXEC | O_DIRECTORY | O_PATH);
if (fd < 0)
return fd;
r = free_and_strdup(&server->lease_file, path);
if (r < 0)
return r;
server->lease_dir_fd = TAKE_FD(fd);
return 0;
}

View File

@@ -577,7 +577,7 @@ static int dhcp4_server_configure(Link *link) {
if (!lease_file)
return log_oom();
r = sd_dhcp_server_set_lease_file(link->dhcp_server, lease_file);
r = sd_dhcp_server_set_lease_file(link->dhcp_server, AT_FDCWD, lease_file);
if (r < 0)
log_link_warning_errno(link, r, "Failed to load DHCPv4 server leases, ignoring: %m");
}

View File

@@ -81,7 +81,7 @@ int sd_dhcp_server_set_smtp(sd_dhcp_server *server, const struct in_addr smtp[],
int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v);
int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v);
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);
int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, const char *path);
int sd_dhcp_server_set_lease_file(sd_dhcp_server *server, int dir_fd, const char *path);
int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint64_t t);
int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint64_t t);