Merge pull request #30021 from yuwata/dhcp-client-id-cleanups
dhcp-server: save bound leases to persistent storage, and load it on start
This commit is contained in:
@@ -83,7 +83,7 @@ triple_timestamp* triple_timestamp_now(triple_timestamp *ts) {
|
||||
return ts;
|
||||
}
|
||||
|
||||
static usec_t map_clock_usec_internal(usec_t from, usec_t from_base, usec_t to_base) {
|
||||
usec_t map_clock_usec_raw(usec_t from, usec_t from_base, usec_t to_base) {
|
||||
|
||||
/* Maps the time 'from' between two clocks, based on a common reference point where the first clock
|
||||
* is at 'from_base' and the second clock at 'to_base'. Basically calculates:
|
||||
@@ -121,7 +121,7 @@ usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock) {
|
||||
if (from == USEC_INFINITY)
|
||||
return from;
|
||||
|
||||
return map_clock_usec_internal(from, now(from_clock), now(to_clock));
|
||||
return map_clock_usec_raw(from, now(from_clock), now(to_clock));
|
||||
}
|
||||
|
||||
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
|
||||
@@ -150,8 +150,8 @@ triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u)
|
||||
nowr = now(CLOCK_REALTIME);
|
||||
|
||||
ts->realtime = u;
|
||||
ts->monotonic = map_clock_usec_internal(u, nowr, now(CLOCK_MONOTONIC));
|
||||
ts->boottime = map_clock_usec_internal(u, nowr, now(CLOCK_BOOTTIME));
|
||||
ts->monotonic = map_clock_usec_raw(u, nowr, now(CLOCK_MONOTONIC));
|
||||
ts->boottime = map_clock_usec_raw(u, nowr, now(CLOCK_BOOTTIME));
|
||||
|
||||
return ts;
|
||||
}
|
||||
@@ -169,8 +169,8 @@ triple_timestamp* triple_timestamp_from_boottime(triple_timestamp *ts, usec_t u)
|
||||
nowb = now(CLOCK_BOOTTIME);
|
||||
|
||||
ts->boottime = u;
|
||||
ts->monotonic = map_clock_usec_internal(u, nowb, now(CLOCK_MONOTONIC));
|
||||
ts->realtime = map_clock_usec_internal(u, nowb, now(CLOCK_REALTIME));
|
||||
ts->monotonic = map_clock_usec_raw(u, nowb, now(CLOCK_MONOTONIC));
|
||||
ts->realtime = map_clock_usec_raw(u, nowb, now(CLOCK_REALTIME));
|
||||
|
||||
return ts;
|
||||
}
|
||||
@@ -199,8 +199,8 @@ dual_timestamp* dual_timestamp_from_boottime(dual_timestamp *ts, usec_t u) {
|
||||
}
|
||||
|
||||
nowm = now(CLOCK_BOOTTIME);
|
||||
ts->monotonic = map_clock_usec_internal(u, nowm, now(CLOCK_MONOTONIC));
|
||||
ts->realtime = map_clock_usec_internal(u, nowm, now(CLOCK_REALTIME));
|
||||
ts->monotonic = map_clock_usec_raw(u, nowm, now(CLOCK_MONOTONIC));
|
||||
ts->realtime = map_clock_usec_raw(u, nowm, now(CLOCK_REALTIME));
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ typedef enum TimestampStyle {
|
||||
usec_t now(clockid_t clock);
|
||||
nsec_t now_nsec(clockid_t clock);
|
||||
|
||||
usec_t map_clock_usec_raw(usec_t from, usec_t from_base, usec_t to_base);
|
||||
usec_t map_clock_usec(usec_t from, clockid_t from_clock, clockid_t to_clock);
|
||||
|
||||
dual_timestamp* dual_timestamp_now(dual_timestamp *ts);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "alloc-util.h"
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "dns-domain.h"
|
||||
#include "hostname-util.h"
|
||||
#include "memory-util.h"
|
||||
#include "ordered-set.h"
|
||||
#include "strv.h"
|
||||
@@ -396,27 +398,56 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t c
|
||||
}
|
||||
|
||||
int dhcp_option_parse_string(const uint8_t *option, size_t len, char **ret) {
|
||||
_cleanup_free_ char *string = NULL;
|
||||
int r;
|
||||
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
if (len <= 0)
|
||||
*ret = mfree(*ret);
|
||||
else {
|
||||
char *string;
|
||||
|
||||
/*
|
||||
* One trailing NUL byte is OK, we don't mind. See:
|
||||
* https://github.com/systemd/systemd/issues/1337
|
||||
*/
|
||||
r = make_cstring((const char *) option, len, MAKE_CSTRING_ALLOW_TRAILING_NUL, &string);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
free_and_replace(*ret, string);
|
||||
if (len <= 0) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* One trailing NUL byte is OK, we don't mind. See:
|
||||
* https://github.com/systemd/systemd/issues/1337 */
|
||||
r = make_cstring((const char *) option, len, MAKE_CSTRING_ALLOW_TRAILING_NUL, &string);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!string_is_safe(string) || !utf8_is_valid(string))
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_option_parse_hostname(const uint8_t *option, size_t len, char **ret) {
|
||||
_cleanup_free_ char *hostname = NULL;
|
||||
int r;
|
||||
|
||||
assert(option);
|
||||
assert(ret);
|
||||
|
||||
r = dhcp_option_parse_string(option, len, &hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!hostname) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hostname_is_valid(hostname, 0))
|
||||
return -EINVAL;
|
||||
|
||||
r = dns_name_is_valid(hostname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -EINVAL;
|
||||
|
||||
*ret = TAKE_PTR(hostname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,3 +44,4 @@ int dhcp_option_parse(
|
||||
char **ret_error_message);
|
||||
|
||||
int dhcp_option_parse_string(const uint8_t *option, size_t len, char **ret);
|
||||
int dhcp_option_parse_hostname(const uint8_t *option, size_t len, char **ret);
|
||||
|
||||
@@ -75,6 +75,8 @@ struct sd_dhcp_server {
|
||||
|
||||
char *agent_circuit_id;
|
||||
char *agent_remote_id;
|
||||
|
||||
char *lease_file;
|
||||
};
|
||||
|
||||
typedef struct DHCPRequest {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "dhcp-client-id-internal.h"
|
||||
#include "dhcp-server-internal.h"
|
||||
#include "json.h"
|
||||
#include "time-util.h"
|
||||
|
||||
typedef struct sd_dhcp_server_lease {
|
||||
@@ -31,3 +32,9 @@ int dhcp_server_set_lease(sd_dhcp_server *server, be32_t address, DHCPRequest *r
|
||||
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);
|
||||
|
||||
int dhcp_server_bound_leases_append_json(sd_dhcp_server *server, JsonVariant **v);
|
||||
int dhcp_server_static_leases_append_json(sd_dhcp_server *server, JsonVariant **v);
|
||||
|
||||
int dhcp_server_save_leases(sd_dhcp_server *server);
|
||||
int dhcp_server_load_leases(sd_dhcp_server *server);
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "sd-dhcp-server.c"
|
||||
|
||||
#include "fuzz.h"
|
||||
#include "path-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
/* stub out network so that the server doesn't send */
|
||||
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
|
||||
@@ -31,7 +34,7 @@ static int add_lease(sd_dhcp_server *server, const struct in_addr *server_addres
|
||||
.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,
|
||||
.expiration = usec_add(now(CLOCK_BOOTTIME), USEC_PER_DAY),
|
||||
.gateway = server_address->s_addr,
|
||||
.hlen = ETH_ALEN,
|
||||
.htype = ARPHRD_ETHER,
|
||||
@@ -62,9 +65,11 @@ static int add_static_lease(sd_dhcp_server *server, uint8_t i) {
|
||||
}
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
_cleanup_(rm_rf_physical_and_freep) char *tmpdir = NULL;
|
||||
_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;
|
||||
|
||||
if (size < sizeof(DHCPMessage))
|
||||
return 0;
|
||||
@@ -73,8 +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"));
|
||||
|
||||
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);
|
||||
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);
|
||||
@@ -89,5 +98,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
|
||||
(void) dhcp_server_handle_message(server, (DHCPMessage*) duped, size, NULL);
|
||||
|
||||
assert_se(dhcp_server_save_leases(server) >= 0);
|
||||
server->bound_leases_by_address = hashmap_free(server->bound_leases_by_address);
|
||||
server->bound_leases_by_client_id = hashmap_free(server->bound_leases_by_client_id);
|
||||
assert_se(dhcp_server_load_leases(server) >= 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -832,12 +832,16 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
|
||||
|
||||
break;
|
||||
|
||||
case SD_DHCP_OPTION_ROOT_PATH:
|
||||
r = dhcp_option_parse_string(option, len, &lease->root_path);
|
||||
case SD_DHCP_OPTION_ROOT_PATH: {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
r = dhcp_option_parse_string(option, len, &p);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse root path, ignoring: %m");
|
||||
break;
|
||||
|
||||
free_and_replace(lease->root_path, p);
|
||||
break;
|
||||
}
|
||||
case SD_DHCP_OPTION_RENEWAL_TIME:
|
||||
r = lease_parse_be32_seconds(option, len, /* max_as_infinity = */ true, &lease->t1);
|
||||
if (r < 0)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "dhcp-server-lease-internal.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
static sd_dhcp_server_lease* dhcp_server_lease_free(sd_dhcp_server_lease *lease) {
|
||||
if (!lease)
|
||||
@@ -204,3 +208,262 @@ int sd_dhcp_server_set_static_lease(
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_server_lease_append_json(sd_dhcp_server_lease *lease, JsonVariant **ret) {
|
||||
assert(lease);
|
||||
assert(ret);
|
||||
|
||||
return json_build(ret,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_BYTE_ARRAY("ClientId", lease->client_id.raw, lease->client_id.size),
|
||||
JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &(struct in_addr) { .s_addr = lease->address }),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("Hostname", lease->hostname)));
|
||||
}
|
||||
|
||||
int dhcp_server_bound_leases_append_json(sd_dhcp_server *server, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
sd_dhcp_server_lease *lease;
|
||||
usec_t now_b, now_r;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(v);
|
||||
|
||||
r = sd_event_now(server->event, CLOCK_BOOTTIME, &now_b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_now(server->event, CLOCK_REALTIME, &now_r);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(lease, server->bound_leases_by_client_id) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||
|
||||
r = dhcp_server_lease_append_json(lease, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
usec_t exp_r = map_clock_usec_raw(lease->expiration, now_b, now_r);
|
||||
|
||||
r = json_variant_merge_objectb(&w,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_UNSIGNED("ExpirationUSec", lease->expiration),
|
||||
JSON_BUILD_PAIR_UNSIGNED("ExpirationRealtimeUSec", exp_r)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_variant_append_array(&array, w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return json_variant_set_field_non_null(v, "Leases", array);
|
||||
}
|
||||
|
||||
int dhcp_server_static_leases_append_json(sd_dhcp_server *server, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(v);
|
||||
|
||||
HASHMAP_FOREACH(lease, server->static_leases_by_client_id) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||
|
||||
r = dhcp_server_lease_append_json(lease, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_variant_append_array(&array, w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return json_variant_set_field_non_null(v, "StaticLeases", array);
|
||||
}
|
||||
|
||||
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_fclose_ FILE *f = NULL;
|
||||
sd_id128_t boot_id;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
|
||||
if (!server->lease_file)
|
||||
return 0;
|
||||
|
||||
if (hashmap_isempty(server->bound_leases_by_client_id)) {
|
||||
if (unlink(server->lease_file) < 0 && errno != ENOENT)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_id128_get_boot(&boot_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_build(&v, JSON_BUILD_OBJECT(JSON_BUILD_PAIR_ID128("BootID", boot_id)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_server_bound_leases_append_json(server, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = mkdir_parents(server->lease_file, 0755);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fopen_temporary(server->lease_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
r = json_variant_dump(v, JSON_FORMAT_NEWLINE | JSON_FORMAT_FLUSH, f, /* prefix = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = conservative_rename(temp_path, server->lease_file);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
temp_path = mfree(temp_path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_dispatch_dhcp_lease(sd_dhcp_server *server, JsonVariant *v, bool use_boottime) {
|
||||
static const JsonDispatch dispatch_table_boottime[] = {
|
||||
{ "ClientId", JSON_VARIANT_ARRAY, json_dispatch_client_id, offsetof(sd_dhcp_server_lease, client_id), JSON_MANDATORY },
|
||||
{ "Address", JSON_VARIANT_ARRAY, json_dispatch_in_addr, offsetof(sd_dhcp_server_lease, address), JSON_MANDATORY },
|
||||
{ "Hostname", JSON_VARIANT_STRING, json_dispatch_string, offsetof(sd_dhcp_server_lease, hostname), 0 },
|
||||
{ "ExpirationUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(sd_dhcp_server_lease, expiration), JSON_MANDATORY },
|
||||
{ "ExpirationRealtimeUSec", _JSON_VARIANT_TYPE_INVALID, NULL, 0, JSON_MANDATORY },
|
||||
{}
|
||||
}, dispatch_table_realtime[] = {
|
||||
{ "ClientId", JSON_VARIANT_ARRAY, json_dispatch_client_id, offsetof(sd_dhcp_server_lease, client_id), JSON_MANDATORY },
|
||||
{ "Address", JSON_VARIANT_ARRAY, json_dispatch_in_addr, offsetof(sd_dhcp_server_lease, address), JSON_MANDATORY },
|
||||
{ "Hostname", JSON_VARIANT_STRING, json_dispatch_string, offsetof(sd_dhcp_server_lease, hostname), 0 },
|
||||
{ "ExpirationUSec", _JSON_VARIANT_TYPE_INVALID, NULL, 0, JSON_MANDATORY },
|
||||
{ "ExpirationRealtimeUSec", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(sd_dhcp_server_lease, expiration), JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(sd_dhcp_server_lease_unrefp) sd_dhcp_server_lease *lease = NULL;
|
||||
usec_t now_b;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(v);
|
||||
|
||||
lease = new(sd_dhcp_server_lease, 1);
|
||||
if (!lease)
|
||||
return -ENOMEM;
|
||||
|
||||
*lease = (sd_dhcp_server_lease) {
|
||||
.n_ref = 1,
|
||||
};
|
||||
|
||||
r = json_dispatch(v, use_boottime ? dispatch_table_boottime : dispatch_table_realtime, JSON_ALLOW_EXTENSIONS, lease);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_now(server->event, CLOCK_BOOTTIME, &now_b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (use_boottime) {
|
||||
if (lease->expiration < now_b)
|
||||
return 0; /* already expired */
|
||||
} else {
|
||||
usec_t now_r;
|
||||
|
||||
r = sd_event_now(server->event, CLOCK_REALTIME, &now_r);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (lease->expiration < now_r)
|
||||
return 0; /* already expired */
|
||||
|
||||
lease->expiration = map_clock_usec_raw(lease->expiration, now_r, now_b);
|
||||
}
|
||||
|
||||
r = dhcp_server_put_lease(server, lease, /* is_static = */ false);
|
||||
if (r == -EEXIST)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
TAKE_PTR(lease);
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct SavedInfo {
|
||||
sd_id128_t boot_id;
|
||||
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 },
|
||||
{}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int dhcp_server_load_leases(sd_dhcp_server *server) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
size_t n, m;
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
assert(server->event);
|
||||
|
||||
if (!server->lease_file)
|
||||
return 0;
|
||||
|
||||
r = json_parse_file(
|
||||
/* f = */ NULL,
|
||||
server->lease_file,
|
||||
/* flags = */ 0,
|
||||
&v,
|
||||
/* ret_line = */ NULL,
|
||||
/* ret_column = */ NULL);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
n = hashmap_size(server->bound_leases_by_client_id);
|
||||
|
||||
r = dhcp_server_dispatch_leases(server, v);
|
||||
|
||||
m = hashmap_size(server->bound_leases_by_client_id);
|
||||
assert(m >= n);
|
||||
log_dhcp_server(server, "Loaded %zu lease(s) from %s.", m - n, server->lease_file);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "memory-util.h"
|
||||
#include "network-common.h"
|
||||
#include "ordered-set.h"
|
||||
#include "path-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-util.h"
|
||||
#include "unaligned.h"
|
||||
@@ -30,6 +31,19 @@
|
||||
#define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR
|
||||
#define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12)
|
||||
|
||||
static void server_on_lease_change(sd_dhcp_server *server) {
|
||||
int r;
|
||||
|
||||
assert(server);
|
||||
|
||||
r = dhcp_server_save_leases(server);
|
||||
if (r < 0)
|
||||
log_dhcp_server_errno(server, r, "Failed to save leases, ignoring: %m");
|
||||
|
||||
if (server->callback)
|
||||
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
||||
}
|
||||
|
||||
/* 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
|
||||
@@ -130,6 +144,8 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
|
||||
free(server->agent_circuit_id);
|
||||
free(server->agent_remote_id);
|
||||
|
||||
free(server->lease_file);
|
||||
|
||||
free(server->ifname);
|
||||
return mfree(server);
|
||||
}
|
||||
@@ -746,14 +762,16 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us
|
||||
req->agent_info_option = (uint8_t*)option - 2;
|
||||
|
||||
break;
|
||||
case SD_DHCP_OPTION_HOST_NAME:
|
||||
r = dhcp_option_parse_string(option, len, &req->hostname);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
case SD_DHCP_OPTION_HOST_NAME: {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
|
||||
r = dhcp_option_parse_hostname(option, len, &p);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to parse hostname, ignoring: %m");
|
||||
else
|
||||
free_and_replace(req->hostname, p);
|
||||
break;
|
||||
}
|
||||
case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST:
|
||||
req->parameter_request_list = option;
|
||||
req->parameter_request_list_len = len;
|
||||
@@ -979,8 +997,7 @@ static int server_ack_request(sd_dhcp_server *server, DHCPRequest *req, be32_t a
|
||||
|
||||
log_dhcp_server(server, "ACK (0x%x)", be32toh(req->message->xid));
|
||||
|
||||
if (server->callback)
|
||||
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
||||
server_on_lease_change(server);
|
||||
|
||||
return DHCP_ACK;
|
||||
}
|
||||
@@ -1186,8 +1203,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siz
|
||||
|
||||
sd_dhcp_server_lease_unref(existing_lease);
|
||||
|
||||
if (server->callback)
|
||||
server->callback(server, SD_DHCP_SERVER_EVENT_LEASE_CHANGED, server->callback_userdata);
|
||||
server_on_lease_change(server);
|
||||
|
||||
return 0;
|
||||
}}
|
||||
@@ -1341,6 +1357,10 @@ int sd_dhcp_server_start(sd_dhcp_server *server) {
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
r = dhcp_server_load_leases(server);
|
||||
if (r < 0)
|
||||
log_dhcp_server_errno(server, r, "Failed to load lease file %s, ignoring: %m", strna(server->lease_file));
|
||||
|
||||
log_dhcp_server(server, "STARTED");
|
||||
|
||||
return 0;
|
||||
@@ -1565,3 +1585,13 @@ 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_lease_file(sd_dhcp_server *server, const char *path) {
|
||||
assert_return(server, -EINVAL);
|
||||
assert_return(!sd_dhcp_server_is_running(server), -EBUSY);
|
||||
|
||||
if (path && !path_is_safe(path))
|
||||
return -EINVAL;
|
||||
|
||||
return free_and_strdup(&server->lease_file, path);
|
||||
}
|
||||
|
||||
+36
-15
@@ -2929,6 +2929,24 @@ static int verb_reconfigure(int argc, char *argv[], void *userdata) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_persistent_storage(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(varlink_unrefp) Varlink *vl = NULL;
|
||||
bool ready;
|
||||
int r;
|
||||
|
||||
r = parse_boolean(argv[1]);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse argument: %s", argv[1]);
|
||||
ready = r;
|
||||
|
||||
r = varlink_connect_networkd(&vl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return varlink_callb_and_log(vl, "io.systemd.Network.SetPersistentStorage", /* reply = */ NULL,
|
||||
JSON_BUILD_OBJECT(JSON_BUILD_PAIR_BOOLEAN("Ready", ready)));
|
||||
}
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
@@ -2955,6 +2973,8 @@ static int help(void) {
|
||||
" cat FILES|DEVICES... Show network configuration files\n"
|
||||
" mask FILES... Mask network configuration files\n"
|
||||
" unmask FILES... Unmask network configuration files\n"
|
||||
" persistent-storage BOOL\n"
|
||||
" Notify systemd-networkd if persistent storage is ready\n"
|
||||
"\nOptions:\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
@@ -3098,21 +3118,22 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
static int networkctl_main(int argc, char *argv[]) {
|
||||
static const Verb verbs[] = {
|
||||
{ "list", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_links },
|
||||
{ "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, link_status },
|
||||
{ "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
|
||||
{ "label", 1, 1, 0, list_address_labels },
|
||||
{ "delete", 2, VERB_ANY, 0, link_delete },
|
||||
{ "up", 2, VERB_ANY, 0, link_up_down },
|
||||
{ "down", 2, VERB_ANY, 0, link_up_down },
|
||||
{ "renew", 2, VERB_ANY, VERB_ONLINE_ONLY, link_renew },
|
||||
{ "forcerenew", 2, VERB_ANY, VERB_ONLINE_ONLY, link_force_renew },
|
||||
{ "reconfigure", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_reconfigure },
|
||||
{ "reload", 1, 1, VERB_ONLINE_ONLY, verb_reload },
|
||||
{ "edit", 2, VERB_ANY, 0, verb_edit },
|
||||
{ "cat", 2, VERB_ANY, 0, verb_cat },
|
||||
{ "mask", 2, VERB_ANY, 0, verb_mask },
|
||||
{ "unmask", 2, VERB_ANY, 0, verb_unmask },
|
||||
{ "list", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_links },
|
||||
{ "status", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, link_status },
|
||||
{ "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
|
||||
{ "label", 1, 1, 0, list_address_labels },
|
||||
{ "delete", 2, VERB_ANY, 0, link_delete },
|
||||
{ "up", 2, VERB_ANY, 0, link_up_down },
|
||||
{ "down", 2, VERB_ANY, 0, link_up_down },
|
||||
{ "renew", 2, VERB_ANY, VERB_ONLINE_ONLY, link_renew },
|
||||
{ "forcerenew", 2, VERB_ANY, VERB_ONLINE_ONLY, link_force_renew },
|
||||
{ "reconfigure", 2, VERB_ANY, VERB_ONLINE_ONLY, verb_reconfigure },
|
||||
{ "reload", 1, 1, VERB_ONLINE_ONLY, verb_reload },
|
||||
{ "edit", 2, VERB_ANY, 0, verb_edit },
|
||||
{ "cat", 2, VERB_ANY, 0, verb_cat },
|
||||
{ "mask", 2, VERB_ANY, 0, verb_mask },
|
||||
{ "unmask", 2, VERB_ANY, 0, verb_unmask },
|
||||
{ "persistent-storage", 2, 2, 0, verb_persistent_storage },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-route-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
@@ -143,6 +144,55 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_start_dhcp4_server(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
if (!link->dhcp_server)
|
||||
return 0; /* Not configured yet. */
|
||||
|
||||
if (!link_has_carrier(link))
|
||||
return 0;
|
||||
|
||||
/* TODO: Maybe, also check the system time is synced. If the system does not have RTC battery, then
|
||||
* the realtime clock in not usable in the early boot stage, and all saved leases may be wrongly
|
||||
* handled as expired and dropped. */
|
||||
if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server) &&
|
||||
!link->manager->persistent_storage_is_ready)
|
||||
return 0;
|
||||
|
||||
r = sd_dhcp_server_start(link->dhcp_server);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_link_debug(link, "Offering DHCPv4 leases");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_toggle_dhcp4_server_state(Manager *manager, bool start) {
|
||||
Link *link;
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
if (!link->dhcp_server)
|
||||
continue;
|
||||
if (sd_dhcp_server_is_in_relay_mode(link->dhcp_server))
|
||||
continue;
|
||||
|
||||
if (start)
|
||||
r = link_start_dhcp4_server(link);
|
||||
else
|
||||
r = sd_dhcp_server_stop(link->dhcp_server);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Failed to %s DHCP server, ignoring: %m",
|
||||
start ? "start" : "stop");
|
||||
}
|
||||
}
|
||||
|
||||
static int dhcp_server_find_uplink(Link *link, Link **ret) {
|
||||
assert(link);
|
||||
|
||||
@@ -522,11 +572,20 @@ static int dhcp4_server_configure(Link *link) {
|
||||
return log_link_error_errno(link, r, "Failed to set DHCPv4 static lease for DHCP server: %m");
|
||||
}
|
||||
|
||||
r = sd_dhcp_server_start(link->dhcp_server);
|
||||
if (!sd_dhcp_server_is_in_relay_mode(link->dhcp_server)) {
|
||||
_cleanup_free_ char *lease_file = path_join("/var/lib/systemd/network/dhcp-server-lease/", link->ifname);
|
||||
if (!lease_file)
|
||||
return log_oom();
|
||||
|
||||
r = sd_dhcp_server_set_lease_file(link->dhcp_server, lease_file);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to load DHCPv4 server leases, ignoring: %m");
|
||||
}
|
||||
|
||||
r = link_start_dhcp4_server(link);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
|
||||
|
||||
log_link_debug(link, "Offering DHCPv4 leases");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#include "set.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
typedef struct Network Network;
|
||||
|
||||
int network_adjust_dhcp_server(Network *network, Set **addresses);
|
||||
|
||||
int link_request_dhcp_server(Link *link);
|
||||
|
||||
void manager_toggle_dhcp4_server_state(Manager *manager, bool start);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);
|
||||
|
||||
@@ -890,67 +890,6 @@ static int pref64_append_json(Link *link, JsonVariant **v) {
|
||||
return json_variant_set_field_non_null(v, "NDisc", w);
|
||||
}
|
||||
|
||||
static int dhcp_server_offered_leases_append_json(Link *link, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(v);
|
||||
|
||||
if (!link->dhcp_server)
|
||||
return 0;
|
||||
|
||||
HASHMAP_FOREACH(lease, link->dhcp_server->bound_leases_by_client_id) {
|
||||
struct in_addr address = { .s_addr = lease->address };
|
||||
|
||||
r = json_variant_append_arrayb(
|
||||
&array,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_BYTE_ARRAY(
|
||||
"ClientId",
|
||||
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(
|
||||
"ExpirationUSec", lease->expiration)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return json_variant_set_field_non_null(v, "Leases", array);
|
||||
}
|
||||
|
||||
static int dhcp_server_static_leases_append_json(Link *link, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
sd_dhcp_server_lease *lease;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(v);
|
||||
|
||||
if (!link->dhcp_server)
|
||||
return 0;
|
||||
|
||||
HASHMAP_FOREACH(lease, link->dhcp_server->static_leases_by_client_id) {
|
||||
struct in_addr address = { .s_addr = lease->address };
|
||||
|
||||
r = json_variant_append_arrayb(
|
||||
&array,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_BYTE_ARRAY(
|
||||
"ClientId",
|
||||
lease->client_id.raw,
|
||||
lease->client_id.size),
|
||||
JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Address", &address)));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return json_variant_set_field_non_null(v, "StaticLeases", array);
|
||||
}
|
||||
|
||||
static int dhcp_server_append_json(Link *link, JsonVariant **v) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||
int r;
|
||||
@@ -968,11 +907,11 @@ static int dhcp_server_append_json(Link *link, JsonVariant **v) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_server_offered_leases_append_json(link, &w);
|
||||
r = dhcp_server_bound_leases_append_json(link->dhcp_server, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp_server_static_leases_append_json(link, &w);
|
||||
r = dhcp_server_static_leases_append_json(link->dhcp_server, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bus-polkit.h"
|
||||
#include "fs-util.h"
|
||||
#include "lldp-rx-internal.h"
|
||||
#include "networkd-dhcp-server.h"
|
||||
#include "networkd-manager-varlink.h"
|
||||
#include "stat-util.h"
|
||||
#include "varlink.h"
|
||||
#include "varlink-io.systemd.Network.h"
|
||||
|
||||
@@ -164,6 +168,55 @@ static int vl_method_get_lldp_neighbors(Varlink *vlink, JsonVariant *parameters,
|
||||
JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_VARIANT(array))));
|
||||
}
|
||||
|
||||
static int vl_method_set_persistent_storage(Varlink *vlink, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "Ready", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, 0, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
bool ready;
|
||||
int r;
|
||||
|
||||
assert(vlink);
|
||||
|
||||
r = varlink_dispatch(vlink, parameters, dispatch_table, &ready);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (ready) {
|
||||
r = path_is_read_only_fs("/var/lib/systemd/network/");
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
|
||||
if (r > 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EROFS), "The directory /var/lib/systemd/network/ is read-only.");
|
||||
}
|
||||
|
||||
r = varlink_verify_polkit_async(
|
||||
vlink,
|
||||
manager->bus,
|
||||
"org.freedesktop.network1.set-persistent-storage",
|
||||
/* details= */ NULL,
|
||||
&manager->polkit_registry);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
manager->persistent_storage_is_ready = ready;
|
||||
|
||||
if (ready) {
|
||||
r = touch("/run/systemd/netif/persistent-storage-ready");
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to create /run/systemd/netif/persistent-storage-ready, ignoring: %m");
|
||||
} else {
|
||||
if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT)
|
||||
log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
|
||||
}
|
||||
|
||||
manager_toggle_dhcp4_server_state(manager, ready);
|
||||
|
||||
return varlink_reply(vlink, NULL);
|
||||
}
|
||||
|
||||
int manager_connect_varlink(Manager *m) {
|
||||
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
|
||||
int r;
|
||||
@@ -187,7 +240,8 @@ int manager_connect_varlink(Manager *m) {
|
||||
s,
|
||||
"io.systemd.Network.GetStates", vl_method_get_states,
|
||||
"io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id,
|
||||
"io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors);
|
||||
"io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors,
|
||||
"io.systemd.Network.SetPersistentStorage", vl_method_set_persistent_storage);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
|
||||
@@ -557,6 +557,29 @@ int manager_setup(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool persistent_storage_is_ready(void) {
|
||||
int r;
|
||||
|
||||
if (access("/run/systemd/netif/persistent-storage-ready", F_OK) < 0) {
|
||||
if (errno != ENOENT)
|
||||
return log_debug_errno(errno, "Failed to check if /run/systemd/netif/persistent-storage-ready exists, assuming not, ignoring: %m");
|
||||
return false;
|
||||
}
|
||||
|
||||
r = path_is_read_only_fs("/var/lib/systemd/network/");
|
||||
if (r == 0)
|
||||
return true;
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to check if /var/lib/systemd/network/ is writable: %m");
|
||||
else
|
||||
log_debug("The directory /var/lib/systemd/network/ is read-only.");
|
||||
|
||||
if (unlink("/run/systemd/netif/persistent-storage-ready") < 0 && errno != ENOENT)
|
||||
log_debug_errno(errno, "Failed to remove /run/systemd/netif/persistent-storage-ready, ignoring: %m");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int manager_new(Manager **ret, bool test_mode) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
|
||||
@@ -568,6 +591,7 @@ int manager_new(Manager **ret, bool test_mode) {
|
||||
.keep_configuration = _KEEP_CONFIGURATION_INVALID,
|
||||
.ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
|
||||
.test_mode = test_mode,
|
||||
.persistent_storage_is_ready = persistent_storage_is_ready(),
|
||||
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
|
||||
.online_state = _LINK_ONLINE_STATE_INVALID,
|
||||
.manage_foreign_routes = true,
|
||||
|
||||
@@ -41,6 +41,7 @@ struct Manager {
|
||||
bool manage_foreign_routes;
|
||||
bool manage_foreign_rules;
|
||||
bool manage_foreign_nexthops;
|
||||
bool persistent_storage_is_ready;
|
||||
|
||||
Set *dirty_links;
|
||||
Set *new_wlan_ifindices;
|
||||
|
||||
@@ -183,4 +183,15 @@
|
||||
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.network1.set-persistent-storage">
|
||||
<description gettext-domain="systemd">Specify whether persistent storage for systemd-networkd is available.</description>
|
||||
<message gettext-domain="systemd">Authentication is required to specify whether persistent storage for systemd-networkd is available.</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
||||
|
||||
@@ -40,11 +40,16 @@ static VARLINK_DEFINE_METHOD(
|
||||
VARLINK_DEFINE_INPUT(InterfaceName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT_BY_TYPE(Neighbors, LLDPNeighborsByInterface, VARLINK_ARRAY));
|
||||
|
||||
static VARLINK_DEFINE_METHOD(
|
||||
SetPersistentStorage,
|
||||
VARLINK_DEFINE_INPUT(Ready, VARLINK_BOOL, 0));
|
||||
|
||||
VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Network,
|
||||
"io.systemd.Network",
|
||||
&vl_method_GetStates,
|
||||
&vl_method_GetNamespaceId,
|
||||
&vl_method_GetLLDPNeighbors,
|
||||
&vl_method_SetPersistentStorage,
|
||||
&vl_type_LLDPNeighbor,
|
||||
&vl_type_LLDPNeighborsByInterface);
|
||||
|
||||
@@ -81,6 +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_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);
|
||||
|
||||
Reference in New Issue
Block a user