]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: firewall integration with ControlGroupNFTSet=
authorTopi Miettinen <toiwoton@gmail.com>
Sun, 22 May 2022 11:21:02 +0000 (14:21 +0300)
committerTopi Miettinen <topimiettinen@users.noreply.github.com>
Wed, 8 Jun 2022 16:12:25 +0000 (16:12 +0000)
New directive `ControlGroupNFTSet=` provides a method for integrating services
into firewall rules with NFT sets.

Example:

```
table inet filter {
...
        set timesyncd {
                type cgroupsv2
        }

        chain ntp_output {
                socket cgroupv2 != @timesyncd counter drop
                accept
        }
...
}
```

/etc/systemd/system/systemd-timesyncd.service.d/override.conf
```
[Service]
ControlGroupNFTSet=inet:filter:timesyncd
```

```
$ sudo nft list set inet filter timesyncd
table inet filter {
        set timesyncd {
                type cgroupsv2
                elements = { "system.slice/systemd-timesyncd.service" }
        }
}
```

15 files changed:
man/org.freedesktop.systemd1.xml
man/systemd.resource-control.xml
src/core/cgroup.c
src/core/cgroup.h
src/core/dbus-cgroup.c
src/core/load-fragment-gperf.gperf.in
src/core/load-fragment.c
src/core/load-fragment.h
src/shared/bus-unit-util.c
test/fuzz/fuzz-unit-file/directives.mount
test/fuzz/fuzz-unit-file/directives.scope
test/fuzz/fuzz-unit-file/directives.service
test/fuzz/fuzz-unit-file/directives.slice
test/fuzz/fuzz-unit-file/directives.socket
test/fuzz/fuzz-unit-file/directives.swap

index 79748335547dfd5c442a8658bb62aa570fb677f3..6625a74073e4317c44aaf7d6795f99297a24256f 100644 (file)
@@ -2599,6 +2599,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly (bas) RestrictNetworkInterfaces = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(iss) ControlGroupNFTSet = [...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(sb) EnvironmentFiles = [...];
@@ -3170,6 +3172,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property RestrictNetworkInterfaces is not documented!-->
 
+    <!--property ControlGroupNFTSet is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -3750,6 +3754,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestrictNetworkInterfaces"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ControlGroupNFTSet"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -4487,6 +4493,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly (bas) RestrictNetworkInterfaces = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(iss) ControlGroupNFTSet = [...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(sb) EnvironmentFiles = [...];
@@ -5082,6 +5090,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property RestrictNetworkInterfaces is not documented!-->
 
+    <!--property ControlGroupNFTSet is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -5656,6 +5666,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestrictNetworkInterfaces"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ControlGroupNFTSet"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -6282,6 +6294,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly (bas) RestrictNetworkInterfaces = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(iss) ControlGroupNFTSet = [...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(sb) EnvironmentFiles = [...];
@@ -6805,6 +6819,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property RestrictNetworkInterfaces is not documented!-->
 
+    <!--property ControlGroupNFTSet is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -7297,6 +7313,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestrictNetworkInterfaces"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ControlGroupNFTSet"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -8050,6 +8068,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly (bas) RestrictNetworkInterfaces = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(iss) ControlGroupNFTSet = [...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly as Environment = ['...', ...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly a(sb) EnvironmentFiles = [...];
@@ -8559,6 +8579,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property RestrictNetworkInterfaces is not documented!-->
 
+    <!--property ControlGroupNFTSet is not documented!-->
+
     <!--property EnvironmentFiles is not documented!-->
 
     <!--property PassEnvironment is not documented!-->
@@ -9037,6 +9059,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestrictNetworkInterfaces"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ControlGroupNFTSet"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="Environment"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="EnvironmentFiles"/>
@@ -9648,6 +9672,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
       readonly a(iiqq) SocketBindDeny = [...];
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly (bas) RestrictNetworkInterfaces = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(iss) ControlGroupNFTSet = [...];
   };
   interface org.freedesktop.DBus.Peer { ... };
   interface org.freedesktop.DBus.Introspectable { ... };
@@ -9800,6 +9826,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <!--property RestrictNetworkInterfaces is not documented!-->
 
+    <!--property ControlGroupNFTSet is not documented!-->
+
     <!--Autogenerated cross-references for systemd.directives, do not edit-->
 
     <variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.systemd1.Unit"/>
@@ -9958,6 +9986,8 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestrictNetworkInterfaces"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ControlGroupNFTSet"/>
+
     <!--End of Autogenerated section-->
 
     <refsect2>
@@ -10138,6 +10168,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("false")
       readonly (bas) RestrictNetworkInterfaces = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly a(iss) ControlGroupNFTSet = [...];
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly i KillSignal = ...;
@@ -10307,6 +10339,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <!--property RestrictNetworkInterfaces is not documented!-->
 
+    <!--property ControlGroupNFTSet is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -10493,6 +10527,8 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
 
     <variablelist class="dbus-property" generated="True" extra-ref="RestrictNetworkInterfaces"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="ControlGroupNFTSet"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
index 1397b886c5c20bc7126afc51515c2559f93a034c..23b2d0f39087e644f762ca48277c1da9067ce40d 100644 (file)
@@ -1173,6 +1173,35 @@ DeviceAllow=/dev/loop-control
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>ControlGroupNFTSet=</varname><replaceable>family</replaceable>:<replaceable>table</replaceable>:<replaceable>set</replaceable></term>
+        <listitem>
+          <para>This setting provides a method for integrating dynamic cgroup IDs into firewall rules with
+          NFT sets. This option expects a whitespace separated list of NFT set definitions. Each definition
+          consists of a colon-separated tuple of NFT address family (one of <literal>arp</literal>,
+          <literal>bridge</literal>, <literal>inet</literal>, <literal>ip</literal>, <literal>ip6</literal>,
+          or <literal>netdev</literal>), table name and set name. The names of tables and sets must conform
+          to lexical restrictions of NFT table names. When a control group for a unit is realized, the cgroup
+          ID will be appended to the NFT sets and it will be be removed when the control group is
+          removed. Failures to manage the sets will be ignored.</para>
+
+          <para>Example:
+          <programlisting>[Unit]
+ControlGroupNFTSet=inet:filter:my_service
+</programlisting>
+          Corresponding NFT rules:
+          <programlisting>table inet filter {
+        set my_service {
+                type cgroupsv2
+        }
+        chain x {
+                socket cgroupv2 level 2 @my_service accept
+                drop
+        }
+}</programlisting>
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 9282b1ff200c2cf7cd02331c98f17753017a9c91..9a07a73f020388450b79715c0033d098b05b388e 100644 (file)
@@ -19,6 +19,7 @@
 #include "devnum-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "firewall-util.h"
 #include "in-addr-prefix-util.h"
 #include "inotify-util.h"
 #include "io-util.h"
@@ -279,6 +280,8 @@ void cgroup_context_done(CGroupContext *c) {
         cpu_set_reset(&c->startup_cpuset_cpus);
         cpu_set_reset(&c->cpuset_mems);
         cpu_set_reset(&c->startup_cpuset_mems);
+
+        c->nft_set_context = nft_set_context_free_many(c->nft_set_context, &c->n_nft_set_contexts);
 }
 
 static int unit_get_kernel_memory_limit(Unit *u, const char *file, uint64_t *ret) {
@@ -617,6 +620,11 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 SET_FOREACH(iface, c->restrict_network_interfaces)
                         fprintf(f, "%sRestrictNetworkInterfaces: %s\n", prefix, iface);
         }
+
+        for (size_t i = 0; i < c->n_nft_set_contexts; i++)
+                fprintf(f, "%sControlGroupNFTSet: %s:%s:%s\n", prefix,
+                        nfproto_to_string(c->nft_set_context[i].nfproto),
+                        c->nft_set_context[i].table, c->nft_set_context[i].set);
 }
 
 void cgroup_context_dump_socket_bind_item(const CGroupSocketBindItem *item, FILE *f) {
@@ -1226,6 +1234,46 @@ static void cgroup_apply_firewall(Unit *u) {
         (void) bpf_firewall_install(u);
 }
 
+static void cgroup_apply_nft_set(Unit *u) {
+        int r;
+        CGroupContext *c;
+
+        assert(u);
+
+        assert_se(c = unit_get_cgroup_context(u));
+
+        for (size_t i = 0; i < c->n_nft_set_contexts; i++) {
+                NFTSetContext *s = &c->nft_set_context[i];
+                r = nft_set_element_add_uint64(s, u->cgroup_id);
+                if (r < 0)
+                        log_warning_errno(r, "Adding NFT family %s table %s set %s cgroup %" PRIu64 " failed, ignoring: %m",
+                                 nfproto_to_string(s->nfproto),
+                                 s->table,
+                                 s->set,
+                                 u->cgroup_id);
+        }
+}
+
+static void cgroup_delete_nft_set(Unit *u) {
+        int r;
+        CGroupContext *c;
+
+        assert(u);
+
+        assert_se(c = unit_get_cgroup_context(u));
+
+        for (size_t i = 0; i < c->n_nft_set_contexts; i++) {
+                NFTSetContext *s = &c->nft_set_context[i];
+                r = nft_set_element_del_uint64(s, u->cgroup_id);
+                if (r < 0)
+                        log_warning_errno(r, "Deleting NFT family %s table %s set %s cgroup %" PRIu64 " failed, ignoring: %m",
+                                 nfproto_to_string(s->nfproto),
+                                 s->table,
+                                 s->set,
+                                 u->cgroup_id);
+        }
+}
+
 static void cgroup_apply_socket_bind(Unit *u) {
         assert(u);
 
@@ -1658,6 +1706,8 @@ static void cgroup_context_apply(
 
         if (apply_mask & CGROUP_MASK_BPF_RESTRICT_NETWORK_INTERFACES)
                 cgroup_apply_restrict_network_interfaces(u);
+
+        cgroup_apply_nft_set(u);
 }
 
 static bool unit_get_needs_bpf_firewall(Unit *u) {
@@ -2807,6 +2857,8 @@ void unit_prune_cgroup(Unit *u) {
         (void) lsm_bpf_cleanup(u); /* Remove cgroup from the global LSM BPF map */
 #endif
 
+        cgroup_delete_nft_set(u);
+
         is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
 
         r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
index 4413eeaaa0afe5dd5dac24540eb35153a7188cbe..6ac28d7ca7114feabca2d0a172dc1b6458abf226 100644 (file)
@@ -6,6 +6,7 @@
 #include "bpf-lsm.h"
 #include "cgroup-util.h"
 #include "cpu-set-util.h"
+#include "firewall-util.h"
 #include "list.h"
 #include "time-util.h"
 
@@ -194,6 +195,9 @@ struct CGroupContext {
         ManagedOOMMode moom_mem_pressure;
         uint32_t moom_mem_pressure_limit; /* Normalized to 2^32-1 == 100% */
         ManagedOOMPreference moom_preference;
+
+        NFTSetContext *nft_set_context;
+        size_t n_nft_set_contexts;
 };
 
 /* Used when querying IP accounting data */
index 9a31355a4da65e5e6adb880438a1fae90798779c..6070c21c4c34ebf8719e2b65b709d29125b545a8 100644 (file)
@@ -15,6 +15,7 @@
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "firewall-util.h"
 #include "in-addr-prefix-util.h"
 #include "ip-protocol-list.h"
 #include "limits-util.h"
@@ -443,6 +444,36 @@ static int property_get_restrict_network_interfaces(
         return sd_bus_message_close_container(reply);
 }
 
+static int property_get_cgroup_nft_set(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        int r;
+        CGroupContext *c = userdata;
+
+        assert(bus);
+        assert(reply);
+        assert(c);
+
+        r = sd_bus_message_open_container(reply, 'a', "(iss)");
+        if (r < 0)
+                return r;
+
+        for (size_t i = 0; i < c->n_nft_set_contexts; i++) {
+                NFTSetContext *s = &c->nft_set_context[i];
+
+                r = sd_bus_message_append(reply, "(iss)", s->nfproto, s->table, s->set);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(reply);
+}
+
 const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
@@ -500,6 +531,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_PROPERTY("SocketBindAllow", "a(iiqq)", property_get_socket_bind, offsetof(CGroupContext, socket_bind_allow), 0),
         SD_BUS_PROPERTY("SocketBindDeny", "a(iiqq)", property_get_socket_bind, offsetof(CGroupContext, socket_bind_deny), 0),
         SD_BUS_PROPERTY("RestrictNetworkInterfaces", "(bas)", property_get_restrict_network_interfaces, 0, 0),
+        SD_BUS_PROPERTY("ControlGroupNFTSet", "a(iss)", property_get_cgroup_nft_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_VTABLE_END
 };
 
@@ -2062,5 +2094,58 @@ int bus_cgroup_set_property(
         if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB))
                 return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
 
+        if (streq(name, "ControlGroupNFTSet")) {
+                int nfproto;
+                const char *table, *set;
+                bool empty = true;
+
+                r = sd_bus_message_enter_container(message, 'a', "(iss)");
+                if (r < 0)
+                        return r;
+
+                while ((r = sd_bus_message_read(message, "(iss)", &nfproto, &table, &set)) > 0) {
+                        const char *nfproto_name;
+
+                        nfproto_name = nfproto_to_string(nfproto);
+                        if (!nfproto_name)
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid protocol %d.", nfproto);
+
+                        if (nft_identifier_bad(table))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT table name %s.", table);
+
+                        if (nft_identifier_bad(set))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NFT set name %s.", set);
+
+                        if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                                r = nft_set_context_add(&c->nft_set_context, &c->n_nft_set_contexts, nfproto, table, set);
+                                if (r < 0)
+                                        return r;
+
+                                unit_write_settingf(
+                                                u, flags|UNIT_ESCAPE_SPECIFIERS, name,
+                                                "%s=%s:%s:%s",
+                                                name,
+                                                nfproto_name,
+                                                table,
+                                                set);
+                        }
+
+                        empty = false;
+                }
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (empty) {
+                        c->nft_set_context = nft_set_context_free_many(c->nft_set_context, &c->n_nft_set_contexts);
+                        unit_write_settingf(u, flags, name, "%s=", name);
+                }
+
+                return 1;
+        }
+
         return 0;
 }
index 7817c20c0ba9d5a42bbd556ca2cdc4dde75e2075..0db24268d19a5662d89fbf44676d9f78b301c786 100644 (file)
 {{type}}.SocketBindAllow,                  config_parse_cgroup_socket_bind,             0,                                  offsetof({{type}}, cgroup_context.socket_bind_allow)
 {{type}}.SocketBindDeny,                   config_parse_cgroup_socket_bind,             0,                                  offsetof({{type}}, cgroup_context.socket_bind_deny)
 {{type}}.RestrictNetworkInterfaces,        config_parse_restrict_network_interfaces,    0,                                  offsetof({{type}}, cgroup_context)
+{{type}}.ControlGroupNFTSet,               config_parse_cgroup_nft_set,                 0,                                  offsetof({{type}}, cgroup_context)
 {%- endmacro -%}
 
 %{
index 3ff6eae8fcead70372fba074553462131d90f688..12c1af7933f73aa67b433baed290bb619f7d84cb 100644 (file)
 #include "env-util.h"
 #include "errno-list.h"
 #include "escape.h"
+#include "execute.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "firewall-util.h"
 #include "fs-util.h"
 #include "hexdecoct.h"
 #include "io-util.h"
@@ -6520,3 +6522,88 @@ int config_parse_tty_size(
 
         return config_parse_unsigned(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
 }
+
+static int config_parse_nft_set(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                NFTSetContext **c,
+                size_t *n,
+                Unit *u) {
+        _cleanup_free_ char *family_str = NULL, *table = NULL, *set = NULL, *table_resolved = NULL, *set_resolved = NULL;
+        int nfproto, r;
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        if (isempty(rvalue)) {
+                /* Empty assignment resets the list */
+                *c = nft_set_context_free_many(*c, n);
+                return 0;
+        }
+
+        for (const char *p = rvalue;;) {
+                r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE, &family_str, &table, &set, NULL);
+                if (r == -ENOMEM)
+                        return log_oom();
+                if (r == 0)
+                        break;
+                if (r != 3) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse NFT set, ignoring: %s", p);
+                        return 0;
+                }
+
+                nfproto = nfproto_from_string(family_str);
+                if (nfproto < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown NFT protocol family, ignoring: %s", family_str);
+                        return 0;
+                }
+
+                r = unit_path_printf(u, table, &table_resolved);
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", table);
+                        return 0;
+                }
+
+                if (nft_identifier_bad(table_resolved))
+                        return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid table name %s, ignoring", table);
+
+                r = unit_path_printf(u, set, &set_resolved);
+                if (r < 0) {
+                        log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", set);
+                        return 0;
+                }
+
+                if (nft_identifier_bad(set_resolved))
+                        return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid set name %s, ignoring", set);
+
+                r = nft_set_context_add(c, n, nfproto, table_resolved, set_resolved);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        return 0;
+}
+
+int config_parse_cgroup_nft_set(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+        CGroupContext *c = data;
+        Unit *u = userdata;
+
+        return config_parse_nft_set(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &c->nft_set_context, &c->n_nft_set_contexts, u);
+}
index 26b8de28f7a09d6a18c4e2f43daa817393978832..3632b5b0962a531724f25a420cf1020c2b39d780 100644 (file)
@@ -150,6 +150,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_socket_bind);
 CONFIG_PARSER_PROTOTYPE(config_parse_restrict_network_interfaces);
 CONFIG_PARSER_PROTOTYPE(config_parse_watchdog_sec);
 CONFIG_PARSER_PROTOTYPE(config_parse_tty_size);
+CONFIG_PARSER_PROTOTYPE(config_parse_cgroup_nft_set);
 
 /* gperf prototypes */
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
index a326ca30a9a49c1edd4ec6d9339897149afddc2f..e1584c2e8dd5a031a0c7e168231da7154414b435 100644 (file)
@@ -891,6 +891,9 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                 return 1;
         }
 
+        if (streq(field, "ControlGroupNFTSet"))
+                return bus_append_nft_set(m, field, eq);
+
         return 0;
 }
 
index 0a44328e5c687869a2caac7abe57eda9153384cd..2b3331a411fe87990beac3a141eec86951239875 100644 (file)
@@ -28,6 +28,7 @@ Capabilities=
 CapabilityBoundingSet=
 ConfigurationDirectory=
 ConfigurationDirectoryMode=
+ControlGroupNFTSet=
 CoredumpFilter=
 DefaultMemoryLow=
 DefaultMemoryMin=
index 4552d0b403dec221278ee01042dbc20e59447d8d..c4d579065a6cf97f2806eb6229b0efc5e0b2ad54 100644 (file)
@@ -8,6 +8,7 @@ BlockIODeviceWeight=
 BlockIOReadBandwidth=
 BlockIOWeight=
 BlockIOWriteBandwidth=
+ControlGroupNFTSet=
 CPUAccounting=
 CPUQuota=
 CPUQuotaPeriodSec=
index 3c33d947fe2bbc3348c9ab9b01610e1bac9de9c5..30e6936d123dc8a9600575063c787c565d245c1e 100644 (file)
@@ -72,6 +72,7 @@ ConditionSecurity=
 ConditionUser=
 ConditionVirtualization=
 Conflicts=
+ControlGroupNFTSet=
 DefaultDependencies=
 Description=
 Documentation=
index ab77070c5ea1e31a12e8773e9afaee3115ad53e3..749f1795e3de7b71ce6f9c4a14218639c29aafc6 100644 (file)
@@ -8,6 +8,7 @@ BlockIODeviceWeight=
 BlockIOReadBandwidth=
 BlockIOWeight=
 BlockIOWriteBandwidth=
+ControlGroupNFTSet=
 CPUAccounting=
 CPUQuota=
 CPUQuotaPeriodSec=
index 90358fc11aa84e4642a5afaf1c5f04974d6358dd..1b1ddf8c9c7b972a86cdf5e8a7261a953033650d 100644 (file)
@@ -33,6 +33,7 @@ Capabilities=
 CapabilityBoundingSet=
 ConfigurationDirectory=
 ConfigurationDirectoryMode=
+ControlGroupNFTSet=
 CoredumpFilter=
 DefaultMemoryLow=
 DefaultMemoryMin=
index 5d057fa63060c2c791d25e6b10fa378d60b46b10..186dedbf3e8a2e773850d463fd6205f37107345a 100644 (file)
@@ -28,6 +28,7 @@ Capabilities=
 CapabilityBoundingSet=
 ConfigurationDirectory=
 ConfigurationDirectoryMode=
+ControlGroupNFTSet=
 CoredumpFilter=
 DefaultMemoryLow=
 DefaultMemoryMin=