1
0
mirror of https://github.com/systemd/systemd synced 2025-09-25 23:04:46 +02:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Luca Boccassi
836540070d core: add [Enable|Disable]UnitFilesWithFlags DBUS methods
The new methods work as the unflavoured ones, but takes flags as a
single uint64_t DBUS parameters instead of different booleans, so
that it can be extended without breaking backward compatibility.
Add new flag to allow adding/removing symlinks in
[/etc|/run]/systemd/system.attached so that portable services
configuration files can be self-contained in those directories, without
affecting the system services directories.
Use the new methods and flags from portablectl --enable.

Useful in case /etc is read-only, with only the portable services
directories being mounted read-write.
2020-09-04 17:56:37 +02:00
Yu Watanabe
f3f14c573b util: constify the second argument of set_get() 2020-09-04 17:52:26 +02:00
Lennart Poettering
e825610499
Merge pull request #16880 from yuwata/network-dhcp4-cleanups
network: DHCPv4 cleanups
2020-09-04 15:54:27 +02:00
Zbigniew Jędrzejewski-Szmek
459c41b9e2
Merge pull request #16881 from yuwata/network-routing-policy-rule-cleanups
network: routing policy rule cleanups
2020-09-04 12:57:20 +02:00
Zbigniew Jędrzejewski-Szmek
a36a23f52b
Merge pull request #16952 from yuwata/resolvectl-log-level-follow-ups
resolvectl: update help message
2020-09-04 12:21:15 +02:00
Yu Watanabe
2200c3cf56 network: fixes gateway assignment through DHCPv4
This fixes the following issue:
- If a DHCP lease does not contains router option, then routes with
`Gateway=_dhcp` setting introduce unexpected results.

This also makes several failure paths critical. And adjust warnings when
classless routes are provided.
2020-09-04 11:12:03 +02:00
Yu Watanabe
3605aae161 bash-completion: resolvectl: support 'log-level' command 2020-09-04 17:03:28 +09:00
Yu Watanabe
bde4bc9bd2 resolvectl: add 'log-level' to help message
Follow-up for df9578498f3f566409fcb71229d9fc99e4ab0568.
2020-09-04 16:58:36 +09:00
Yu Watanabe
ed89e54a49 man: mention that 'networkctl reconfigure' does not reload configs 2020-09-04 09:05:45 +09:00
Yu Watanabe
c45fdad66d network: configure DHCP routes after DHCP address is ready 2020-09-04 09:05:45 +09:00
Yu Watanabe
687b3bc6f4 network: dhcp4: reset counter only when the lease address is new 2020-09-04 09:05:45 +09:00
Yu Watanabe
4dd6a3aad5 sd-ipv4acd: introduce sd_ipv4acd_get_address() 2020-09-04 09:05:45 +09:00
Yu Watanabe
5acf54a063 network: dhcp4: stop IPv4ACD before assigning new address 2020-09-04 09:05:34 +09:00
Yu Watanabe
6a776e3a18 sd-ipv4acd: do not call callback in sd_ipv4acd_stop() when it is already stopped 2020-09-04 09:04:43 +09:00
Yu Watanabe
dce1cd4188 network: voidify return value of sd_ipv4acd_stop() 2020-09-04 09:04:43 +09:00
Yu Watanabe
5c72a6d5d3 network: logs about unknown key 2020-09-04 08:48:08 +09:00
Yu Watanabe
f405179d65 network: honor already specified family when parsing from= or to= in serialized rule 2020-09-04 08:48:08 +09:00
Yu Watanabe
9d6282d120 network: do not reallocate buffer 2020-09-04 08:48:04 +09:00
Yu Watanabe
d0ac05613b network: serialize InvertRule= in [RoutingPolicyRule] 2020-09-04 08:47:22 +09:00
Yu Watanabe
1680b11df4 network: add whitespace after family= and priority= in serialized routing policy rule
This also makes priority= serialized only when its value is non-zero.
2020-09-04 08:44:19 +09:00
Yu Watanabe
3c94b20dd3 network: downgrade error level when the error is ignored 2020-09-04 08:44:14 +09:00
Yu Watanabe
7e60a37d04 network: move routing_policy_rule_read_full_file() 2020-09-04 08:42:01 +09:00
13 changed files with 302 additions and 159 deletions

View File

@ -299,7 +299,10 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
<command>reconfigure</command>
<replaceable>DEVICE…</replaceable>
</term>
<listitem><para>Reconfigure network interfaces. Takes interface name or index number.</para></listitem>
<listitem><para>Reconfigure network interfaces. Takes interface name or index number. Note that
this does not reload <filename>.netdev</filename> or <filename>.network</filename>
corresponding to the the specifed interface. So, if you edit config files, it is necessary to
call <command>networkctl reload</command> first to apply new settings.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -179,6 +179,13 @@ node /org/freedesktop/systemd1 {
DisableUnitFiles(in as files,
in b runtime,
out a(sss) changes);
EnableUnitFilesWithFlags(in as files,
in t flags,
out b carries_install_info,
out a(sss) changes);
DisableUnitFilesWithFlags(in as files,
in t flags,
out a(sss) changes);
ReenableUnitFiles(in as files,
in b runtime,
in b force,
@ -836,6 +843,10 @@ node /org/freedesktop/systemd1 {
<variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFiles()"/>
<variablelist class="dbus-method" generated="True" extra-ref="EnableUnitFilesWithFlags()"/>
<variablelist class="dbus-method" generated="True" extra-ref="DisableUnitFilesWithFlags()"/>
<variablelist class="dbus-method" generated="True" extra-ref="ReenableUnitFiles()"/>
<variablelist class="dbus-method" generated="True" extra-ref="LinkUnitFiles()"/>
@ -1292,6 +1303,20 @@ node /org/freedesktop/systemd1 {
<para>Similarly, <function>DisableUnitFiles()</function> disables one or more units in the system,
i.e. removes all symlinks to them in <filename>/etc</filename> and <filename>/run</filename>.</para>
<para>The <function>EnableUnitFilesWithFlags()</function> and <function>DisableUnitFilesWithFlags()</function>
take in options as flags instead of booleans to allow for extendability, defined as follows:</para>
<programlisting>
#define SD_SYSTEMD_UNIT_RUNTIME (UINT64_C(1) &lt;&lt; 0)
#define SD_SYSTEMD_UNIT_FORCE (UINT64_C(1) &lt;&lt; 1)
#define SD_SYSTEMD_UNIT_PORTABLE (UINT64_C(1) &lt;&lt; 2)
</programlisting>
<para><varname>SD_SYSTEMD_UNIT_RUNTIME</varname> will enable or disable the unit for runtime only,
<varname>SD_SYSTEMD_UNIT_FORCE</varname> controls whether symlinks pointing to other units shall be
replaced if necessary. <varname>SD_SYSTEMD_UNIT_PORTABLE</varname> will add or remove the symlinks in
<filename>/etc/systemd/system.attached</filename> and <filename>/run/systemd/system.attached</filename>.</para>
<para>Similarly, <function>ReenableUnitFiles()</function> applies the changes to one or more units that
would result from disabling and enabling the unit quickly one after the other in an atomic
fashion. This is useful to apply updated [Install] information contained in unit files.</para>
@ -1480,6 +1505,7 @@ node /org/freedesktop/systemd1 {
<function>RestartUnit()</function> and similar, <function>SetProperty()</function>) require
<interfacename>org.freedesktop.systemd1.manage-units</interfacename>. Operations which modify unit file
enablement state (<function>EnableUnitFiles()</function>, <function>DisableUnitFiles()</function>,
<function>EnableUnitFilesWithFlags()</function>, <function>DisableUnitFilesWithFlags()</function>,
<function>ReenableUnitFiles()</function>, <function>LinkUnitFiles()</function>,
<function>PresetUnitFiles</function>, <function>MaskUnitFiles</function>, and similar) require
<interfacename>org.freedesktop.systemd1.manage-unit-files</interfacename>. Operations which modify the

View File

@ -48,6 +48,7 @@ _resolvectl() {
[DNSSEC]='dnssec'
[DNSOVERTLS]='dnsovertls'
[STANDALONE]='statistics reset-statistics flush-caches reset-server-features'
[LOG_LEVEL]='log-level'
)
local -A ARGS=(
[FAMILY]='tcp udp sctp'
@ -95,6 +96,9 @@ _resolvectl() {
elif __contains_word "$verb" ${VERBS[STATUS]}; then
comps="$interfaces"
elif __contains_word "$verb" ${VERBS[LOG_LEVEL]}; then
comps='debug info notice warning err crit alert emerg'
elif __contains_word "$verb" ${VERBS[FAMILY]}; then
for ((i++; i < COMP_CWORD; i++)); do
if __contains_word "${COMP_WORDS[i]}" ${ARGS[FAMILY]} &&

View File

@ -34,7 +34,7 @@ int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG
int set_put(Set *s, const void *key);
/* no set_update */
/* no set_replace */
static inline void *set_get(const Set *s, void *key) {
static inline void *set_get(const Set *s, const void *key) {
return _hashmap_get(HASHMAP_BASE((Set *) s), key);
}
/* no set_get2 */

View File

@ -2083,7 +2083,7 @@ static int method_enable_unit_files_generic(
UnitFileChange *changes = NULL;
size_t n_changes = 0;
UnitFileFlags flags;
int runtime, force, r;
int r;
assert(message);
assert(m);
@ -2092,11 +2092,23 @@ static int method_enable_unit_files_generic(
if (r < 0)
return r;
r = sd_bus_message_read(message, "bb", &runtime, &force);
if (r < 0)
return r;
if (sd_bus_message_is_method_call(message, NULL, "EnableUnitFilesWithFlags")) {
uint64_t raw_flags;
flags = unit_file_bools_to_flags(runtime, force);
r = sd_bus_message_read(message, "t", &raw_flags);
if (r < 0)
return r;
if ((raw_flags & ~_UNIT_FILE_FLAGS_MASK_PUBLIC) != 0)
return -EINVAL;
flags = raw_flags;
} else {
int runtime, force;
r = sd_bus_message_read(message, "bb", &runtime, &force);
if (r < 0)
return r;
flags = unit_file_bools_to_flags(runtime, force);
}
r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
@ -2111,6 +2123,10 @@ static int method_enable_unit_files_generic(
return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes, error);
}
static int method_enable_unit_files_with_flags(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_enable_unit_files_generic(message, userdata, unit_file_enable, true, error);
}
static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_enable_unit_files_generic(message, userdata, unit_file_enable, true, error);
}
@ -2188,8 +2204,9 @@ static int method_disable_unit_files_generic(
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
UnitFileFlags flags;
size_t n_changes = 0;
int r, runtime;
int r;
assert(message);
assert(m);
@ -2198,9 +2215,24 @@ static int method_disable_unit_files_generic(
if (r < 0)
return r;
r = sd_bus_message_read(message, "b", &runtime);
if (r < 0)
return r;
if (sd_bus_message_is_method_call(message, NULL, "DisableUnitFilesWithFlags")) {
uint64_t raw_flags;
r = sd_bus_message_read(message, "t", &raw_flags);
if (r < 0)
return r;
if ((raw_flags & ~_UNIT_FILE_FLAGS_MASK_PUBLIC) != 0 ||
FLAGS_SET(raw_flags, UNIT_FILE_FORCE))
return -EINVAL;
flags = raw_flags;
} else {
int runtime;
r = sd_bus_message_read(message, "b", &runtime);
if (r < 0)
return r;
flags = unit_file_bools_to_flags(runtime, false);
}
r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
@ -2208,13 +2240,17 @@ static int method_disable_unit_files_generic(
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
r = call(m->unit_file_scope, runtime ? UNIT_FILE_RUNTIME : 0, NULL, l, &changes, &n_changes);
r = call(m->unit_file_scope, flags, NULL, l, &changes, &n_changes);
if (r < 0)
return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes, error);
}
static int method_disable_unit_files_with_flags(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
}
static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
}
@ -2984,6 +3020,23 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PARAM(changes),
method_disable_unit_files,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("EnableUnitFilesWithFlags",
"ast",
SD_BUS_PARAM(files)
SD_BUS_PARAM(flags),
"ba(sss)",
SD_BUS_PARAM(carries_install_info)
SD_BUS_PARAM(changes),
method_enable_unit_files_with_flags,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("DisableUnitFilesWithFlags",
"ast",
SD_BUS_PARAM(files)
SD_BUS_PARAM(flags),
"a(sss)",
SD_BUS_PARAM(changes),
method_disable_unit_files_with_flags,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_NAMES("ReenableUnitFiles",
"asbb",
SD_BUS_PARAM(files)

View File

@ -142,10 +142,17 @@ static void ipv4acd_client_notify(sd_ipv4acd *acd, int event) {
}
int sd_ipv4acd_stop(sd_ipv4acd *acd) {
IPv4ACDState old_state;
assert_return(acd, -EINVAL);
old_state = acd->state;
ipv4acd_reset(acd);
if (old_state == IPV4ACD_STATE_INIT)
return 0;
log_ipv4acd(acd, "STOPPED");
ipv4acd_client_notify(acd, SD_IPV4ACD_EVENT_STOP);
@ -435,6 +442,15 @@ int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address) {
return 0;
}
int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address) {
assert_return(acd, -EINVAL);
assert_return(address, -EINVAL);
address->s_addr = acd->address;
return 0;
}
int sd_ipv4acd_is_running(sd_ipv4acd *acd) {
assert_return(acd, false);

View File

@ -22,19 +22,8 @@
static int dhcp4_update_address(Link *link, bool announce);
static int dhcp4_remove_all(Link *link);
static int dhcp4_release_old_lease(Link *link, bool force);
static int dhcp4_address_callback(Address *address) {
assert(address);
assert(address->link);
/* Do not call this callback again. */
address->callback = NULL;
return dhcp4_release_old_lease(address->link, true);
}
static int dhcp4_release_old_lease(Link *link, bool force) {
static int dhcp4_release_old_lease(Link *link) {
Route *route;
Iterator i;
int k, r = 0;
@ -44,12 +33,6 @@ static int dhcp4_release_old_lease(Link *link, bool force) {
if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
return 0;
if (!force && (link->dhcp_address && !address_is_ready(link->dhcp_address))) {
log_link_debug(link, "New DHCPv4 address is not ready. The old lease will be removed later.");
link->dhcp_address->callback = dhcp4_address_callback;
return 0;
}
log_link_debug(link, "Removing old DHCPv4 address and routes.");
link_dirty(link);
@ -81,7 +64,7 @@ static void dhcp4_check_ready(Link *link) {
link->dhcp4_configured = true;
/* New address and routes are configured now. Let's release old lease. */
r = dhcp4_release_old_lease(link, false);
r = dhcp4_release_old_lease(link);
if (r < 0) {
link_enter_failed(link);
return;
@ -251,11 +234,10 @@ static int dhcp_prefix_route_from_lease(
static int link_set_dhcp_routes(Link *link) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
const struct in_addr *router;
struct in_addr address;
int r, n, i;
uint32_t table;
Route *rt;
int r, n;
assert(link);
@ -298,9 +280,9 @@ static int link_set_dhcp_routes(Link *link) {
if (n == -ENODATA)
log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
else if (n < 0)
log_link_debug_errno(link, n, "DHCP: could not get routes: %m");
return log_link_error_errno(link, n, "DHCP: could not get routes: %m");
for (i = 0; i < n; i++) {
for (int i = 0; i < n; i++) {
switch (sd_dhcp_route_get_option(static_routes[i])) {
case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
classless_route = true;
@ -312,11 +294,14 @@ static int link_set_dhcp_routes(Link *link) {
}
if (link->network->dhcp_use_routes) {
for (i = 0; i < n; i++) {
/* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
* the DHCP client MUST ignore the Static Routes option. */
if (classless_route && static_route)
log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option");
for (int i = 0; i < n; i++) {
_cleanup_(route_freep) Route *route = NULL;
/* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
the DHCP client MUST ignore the Static Routes option. */
if (classless_route &&
sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
continue;
@ -347,20 +332,20 @@ static int link_set_dhcp_routes(Link *link) {
}
if (link->network->dhcp_use_gateway) {
const struct in_addr *router;
r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
if (IN_SET(r, 0, -ENODATA))
log_link_info(link, "DHCP: No gateway received from DHCP server.");
else if (r < 0)
log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
else if (in4_addr_is_null(&router[0]))
log_link_info(link, "DHCP: Received gateway is null.");
/* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
a Router option, the DHCP client MUST ignore the Router option. */
if (classless_route && static_route)
log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
else if (classless_route)
/* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
* a Router option, the DHCP client MUST ignore the Router option. */
log_link_warning(link, "Classless static routes received from DHCP server: ignoring router option");
else {
_cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
r = route_new(&route_gw);
@ -399,20 +384,20 @@ static int link_set_dhcp_routes(Link *link) {
r = dhcp_route_configure(route, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not set router: %m");
}
LIST_FOREACH(routes, rt, link->network->static_routes) {
if (!rt->gateway_from_dhcp)
continue;
LIST_FOREACH(routes, rt, link->network->static_routes) {
if (!rt->gateway_from_dhcp)
continue;
if (rt->family != AF_INET)
continue;
if (rt->family != AF_INET)
continue;
rt->gw.in = router[0];
rt->gw.in = router[0];
r = dhcp_route_configure(rt, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m");
r = dhcp_route_configure(rt, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m");
}
}
}
@ -557,7 +542,7 @@ static int dhcp_lease_lost(Link *link) {
link->dhcp4_configured = false;
/* dhcp_lease_lost() may be called during renewing IP address. */
k = dhcp4_release_old_lease(link, true);
k = dhcp4_release_old_lease(link);
if (k < 0)
r = k;
@ -625,7 +610,7 @@ static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
assert_not_reached("Invalid IPv4ACD event.");
}
sd_ipv4acd_stop(acd);
(void) sd_ipv4acd_stop(acd);
return;
}
@ -656,6 +641,7 @@ static int configure_dhcpv4_duplicate_address_detection(Link *link) {
static int dhcp4_start_acd(Link *link) {
union in_addr_union addr;
struct in_addr old;
int r;
if (!link->network->dhcp_send_decline)
@ -664,12 +650,18 @@ static int dhcp4_start_acd(Link *link) {
if (!link->dhcp_lease)
return 0;
(void) sd_ipv4acd_stop(link->network->dhcp_acd);
link->dhcp4_address_bind = false;
r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr.in);
if (r < 0)
return r;
r = sd_ipv4acd_get_address(link->network->dhcp_acd, &old);
if (r < 0)
return r;
r = sd_ipv4acd_set_address(link->network->dhcp_acd, &addr.in);
if (r < 0)
return r;
@ -685,13 +677,41 @@ static int dhcp4_start_acd(Link *link) {
log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
}
r = sd_ipv4acd_start(link->network->dhcp_acd, true);
r = sd_ipv4acd_start(link->network->dhcp_acd, !in4_addr_equal(&addr.in, &old));
if (r < 0)
return r;
return 1;
}
static int dhcp4_address_ready_callback(Address *address) {
Link *link;
int r;
assert(address);
link = address->link;
/* Do not call this again. */
address->callback = NULL;
r = link_set_dhcp_routes(link);
if (r < 0)
return r;
/* Reconfigure static routes as kernel may remove some routes when lease expires. */
r = link_request_set_routes(link);
if (r < 0)
return r;
r = dhcp4_start_acd(link);
if (r < 0)
return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCP4 adddress: %m");
dhcp4_check_ready(link);
return 0;
}
static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@ -708,27 +728,14 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
} else if (r >= 0)
(void) manager_rtnl_process_address(rtnl, m, link->manager);
r = link_set_dhcp_routes(link);
if (r < 0) {
link_enter_failed(link);
return 1;
}
/* Add back static routes since kernel removes while DHCPv4 address is removed from when lease expires */
r = link_request_set_routes(link);
if (r < 0) {
link_enter_failed(link);
return 1;
}
r = dhcp4_start_acd(link);
if (r < 0) {
log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCP4 adddress: %m");
link_enter_failed(link);
return 1;
}
dhcp4_check_ready(link);
if (address_is_ready(link->dhcp_address)) {
r = dhcp4_address_ready_callback(link->dhcp_address);
if (r < 0) {
link_enter_failed(link);
return 1;
}
} else
link->dhcp_address->callback = dhcp4_address_ready_callback;
return 1;
}

View File

@ -1166,26 +1166,6 @@ int config_parse_routing_policy_rule_suppress_prefixlen(
return 0;
}
static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
_cleanup_free_ char *s = NULL;
size_t size;
int r;
assert(state_file);
r = read_full_file(state_file, &s, &size);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
return r;
if (size <= 0)
return -ENODATA;
*ret = TAKE_PTR(s);
return size;
}
int routing_policy_serialize_rules(Set *rules, FILE *f) {
RoutingPolicyRule *rule = NULL;
Iterator i;
@ -1195,17 +1175,25 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
SET_FOREACH(rule, rules, i) {
_cleanup_free_ char *from_str = NULL, *to_str = NULL;
bool space = false;
const char *family_str;
bool space = false;
fputs("RULE=", f);
family_str = af_to_name(rule->family);
if (family_str) {
fprintf(f, "family=%s",
family_str);
space = true;
}
if (!in_addr_is_null(rule->family, &rule->from)) {
r = in_addr_to_string(rule->family, &rule->from, &from_str);
if (r < 0)
return r;
fprintf(f, "from=%s/%hhu",
fprintf(f, "%sfrom=%s/%hhu",
space ? " " : "",
from_str, rule->from_prefixlen);
space = true;
}
@ -1221,12 +1209,6 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
space = true;
}
family_str = af_to_name(rule->family);
if (family_str)
fprintf(f, "%sfamily=%s",
space ? " " : "",
family_str);
if (rule->tos != 0) {
fprintf(f, "%stos=%hhu",
space ? " " : "",
@ -1234,9 +1216,12 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
space = true;
}
fprintf(f, "%spriority=%"PRIu32,
space ? " " : "",
rule->priority);
if (rule->priority != 0) {
fprintf(f, "%spriority=%"PRIu32,
space ? " " : "",
rule->priority);
space = true;
}
if (rule->fwmark != 0) {
fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
@ -1295,14 +1280,35 @@ int routing_policy_serialize_rules(Set *rules, FILE *f) {
space = true;
}
fprintf(f, "%stable=%"PRIu32 "\n",
fprintf(f, "%sinvert_rule=%s table=%"PRIu32"\n",
space ? " " : "",
yes_no(rule->invert_rule),
rule->table);
}
return 0;
}
static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
_cleanup_free_ char *s = NULL;
size_t size;
int r;
assert(state_file);
r = read_full_file(state_file, &s, &size);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
return r;
if (size <= 0)
return -ENODATA;
*ret = TAKE_PTR(s);
return size;
}
int routing_policy_load_rules(const char *state_file, Set **rules) {
_cleanup_strv_free_ char **l = NULL;
_cleanup_free_ char *data = NULL;
@ -1334,19 +1340,34 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
return r;
for (;;) {
_cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
_cleanup_free_ char *a = NULL;
char *b;
r = extract_first_word(&p, &word, NULL, 0);
r = extract_first_word(&p, &a, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
r = split_pair(word, "=", &a, &b);
if (r < 0)
b = strchr(a, '=');
if (!b) {
log_warning_errno(r, "Failed to parse RPDB rule, ignoring: %s", a);
continue;
}
*b++ = '\0';
if (STR_IN_SET(a, "from", "to")) {
if (streq(a, "family")) {
r = af_from_name(b);
if (r < 0) {
log_warning_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
continue;
}
if (rule->family != AF_UNSPEC && rule->family != r) {
log_warning("RPDB rule family is already specified, ignoring assignment: %s", b);
continue;
}
rule->family = r;
} if (STR_IN_SET(a, "from", "to")) {
union in_addr_union *buffer;
uint8_t *prefixlen;
@ -1358,41 +1379,36 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
prefixlen = &rule->from_prefixlen;
}
r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
if (rule->family == AF_UNSPEC)
r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
else
r = in_addr_prefix_from_string(b, rule->family, buffer, prefixlen);
if (r < 0) {
log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
log_warning_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
continue;
}
} else if (streq(a, "family")) {
r = af_from_name(b);
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
continue;
}
rule->family = r;
} else if (streq(a, "tos")) {
r = safe_atou8(b, &rule->tos);
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b);
log_warning_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b);
continue;
}
} else if (streq(a, "table")) {
r = safe_atou32(b, &rule->table);
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
log_warning_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
continue;
}
} else if (streq(a, "priority")) {
r = safe_atou32(b, &rule->priority);
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
log_warning_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
continue;
}
} else if (streq(a, "fwmark")) {
r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
log_warning_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
continue;
}
} else if (streq(a, "iif")) {
@ -1406,13 +1422,13 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
} else if (streq(a, "protocol")) {
r = safe_atou8(b, &rule->protocol);
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
log_warning_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
continue;
}
} else if (streq(a, "sourceport")) {
r = parse_ip_port_range(b, &low, &high);
if (r < 0) {
log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
log_warning_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b);
continue;
}
@ -1421,7 +1437,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
} else if (streq(a, "destinationport")) {
r = parse_ip_port_range(b, &low, &high);
if (r < 0) {
log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
log_warning_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b);
continue;
}
@ -1432,7 +1448,7 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
r = parse_uid_range(b, &lower, &upper);
if (r < 0) {
log_error_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
log_warning_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b);
continue;
}
@ -1441,14 +1457,22 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
} else if (streq(a, "suppress_prefixlen")) {
r = parse_ip_prefix_length(b, &rule->suppress_prefixlen);
if (r == -ERANGE) {
log_error_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b);
log_warning_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b);
continue;
}
if (r < 0) {
log_error_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b);
log_warning_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b);
continue;
}
}
} else if (streq(a, "invert_rule")) {
r = parse_boolean(b);
if (r < 0) {
log_warning_errno(r, "Failed to parse RPDB rule invert_rule, ignoring: %s", b);
continue;
}
rule->invert_rule = r;
} else
log_warning("Unknown RPDB rule, ignoring: %s", a);
}
r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule);

View File

@ -62,31 +62,34 @@ int main(int argc, char **argv) {
test_setup_logging(LOG_DEBUG);
test_rule_serialization("basic parsing",
"RULE=from=1.2.3.4/32 to=2.3.4.5/32 family=AF_INET tos=5 priority=0 fwmark=1/2 table=10", NULL);
"RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 priority=10 fwmark=1/2 invert_rule=yes table=10", NULL);
test_rule_serialization("ignored values",
"RULE=something=to=ignore from=1.2.3.4/32 from=1.2.3.4/32"
" \t to=2.3.4.5/24 to=2.3.4.5/32 tos=5 fwmark=2 fwmark=1 table=10 table=20",
"RULE=from=1.2.3.4/32"
" to=2.3.4.5/32 family=AF_INET tos=5 priority=0 fwmark=1/0 table=20");
"RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1/0 invert_rule=no table=20");
test_rule_serialization("ipv6",
"RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 table=6", NULL);
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=yes table=6", NULL);
assert_se(asprintf(&p, "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 table=%d", RT_TABLE_MAIN) >= 0);
assert_se(asprintf(&p, "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=no table=%d", RT_TABLE_MAIN) >= 0);
test_rule_serialization("default table",
"RULE=from=1::2/64 to=2::3/64", p);
test_rule_serialization("incoming interface",
"RULE=from=1::2/64 to=2::3/64 table=1 iif=lo",
"RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 iif=lo table=1");
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 iif=lo invert_rule=no table=1");
test_rule_serialization("outgoing interface",
"RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 oif=eth0 table=1", NULL);
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 oif=eth0 invert_rule=no table=1", NULL);
test_rule_serialization("freeing interface names",
"RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=e0 iif=e1 oif=e0 oif=e1 table=1",
"RULE=from=1::2/64 to=2::3/64 family=AF_INET6 priority=0 iif=e1 oif=e1 table=1");
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 iif=e1 oif=e1 invert_rule=no table=1");
test_rule_serialization("ignoring invalid family",
"RULE=from=1::2/64 to=2::3/64 family=AF_UNSEPC family=AF_INET table=1",
"RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=no table=1");
return 0;
}

View File

@ -392,6 +392,7 @@ static int maybe_enable_disable(sd_bus *bus, const char *path, bool enable) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
UnitFileChange *changes = NULL;
const uint64_t flags = UNIT_FILE_PORTABLE | (arg_runtime ? UNIT_FILE_RUNTIME : 0);
size_t n_changes = 0;
int r;
@ -408,7 +409,7 @@ static int maybe_enable_disable(sd_bus *bus, const char *path, bool enable) {
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
enable ? "EnableUnitFiles" : "DisableUnitFiles");
enable ? "EnableUnitFilesWithFlags" : "DisableUnitFilesWithFlags");
if (r < 0)
return bus_log_create_error(r);
@ -416,16 +417,10 @@ static int maybe_enable_disable(sd_bus *bus, const char *path, bool enable) {
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "b", arg_runtime);
r = sd_bus_message_append(m, "t", flags);
if (r < 0)
return bus_log_create_error(r);
if (enable) {
r = sd_bus_message_append(m, "b", false);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0)
return log_error_errno(r, "Failed to %s the portable service %s: %s",

View File

@ -2545,6 +2545,7 @@ static int native_help(void) {
" dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
" nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
" revert LINK Revert per-interface configuration\n"
" log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
"\nOptions:\n"
" -h --help Show this help\n"
" --version Show package version\n"

View File

@ -249,6 +249,15 @@ static int path_is_vendor_or_generator(const LookupPaths *p, const char *path) {
return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
}
static const char* config_path_from_flags(const LookupPaths *paths, UnitFileFlags flags) {
assert(paths);
if (FLAGS_SET(flags, UNIT_FILE_PORTABLE))
return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? paths->runtime_attached : paths->persistent_attached;
else
return FLAGS_SET(flags, UNIT_FILE_RUNTIME) ? paths->runtime_config : paths->persistent_config;
}
int unit_file_changes_add(
UnitFileChange **changes,
size_t *n_changes,
@ -2582,7 +2591,7 @@ int unit_file_enable(
if (r < 0)
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
config_path = config_path_from_flags(&paths, flags);
if (!config_path)
return -ENXIO;
@ -2625,7 +2634,7 @@ int unit_file_disable(
if (r < 0)
return r;
config_path = (flags & UNIT_FILE_RUNTIME) ? paths.runtime_config : paths.persistent_config;
config_path = config_path_from_flags(&paths, flags);
if (!config_path)
return -ENXIO;

View File

@ -35,9 +35,11 @@ enum UnitFileChangeType {
};
enum UnitFileFlags {
UNIT_FILE_RUNTIME = 1 << 0,
UNIT_FILE_FORCE = 1 << 1,
UNIT_FILE_DRY_RUN = 1 << 2,
UNIT_FILE_RUNTIME = 1 << 0, /* Public API via DBUS, do not change */
UNIT_FILE_FORCE = 1 << 1, /* Public API via DBUS, do not change */
UNIT_FILE_PORTABLE = 1 << 2, /* Public API via DBUS, do not change */
UNIT_FILE_DRY_RUN = 1 << 3,
_UNIT_FILE_FLAGS_MASK_PUBLIC = UNIT_FILE_RUNTIME|UNIT_FILE_PORTABLE|UNIT_FILE_FORCE,
};
/* type can either one of the UnitFileChangeTypes listed above, or a negative error.