summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd/meson.build1
-rw-r--r--src/libsystemd/sd-netlink/nfnl-message.c318
-rw-r--r--src/systemd/sd-netlink.h26
3 files changed, 345 insertions, 0 deletions
diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build
index 50716f7b94..d22a7754e2 100644
--- a/src/libsystemd/meson.build
+++ b/src/libsystemd/meson.build
@@ -81,6 +81,7 @@ libsystemd_sources = files('''
sd-netlink/netlink-types.h
sd-netlink/netlink-util.c
sd-netlink/netlink-util.h
+ sd-netlink/nfnl-message.c
sd-netlink/rtnl-message.c
sd-netlink/sd-netlink.c
sd-network/network-util.c
diff --git a/src/libsystemd/sd-netlink/nfnl-message.c b/src/libsystemd/sd-netlink/nfnl-message.c
new file mode 100644
index 0000000000..d7bcbf8ba8
--- /dev/null
+++ b/src/libsystemd/sd-netlink/nfnl-message.c
@@ -0,0 +1,318 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <netinet/in.h>
+#include <linux/if_addrlabel.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+#include <linux/nexthop.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include "sd-netlink.h"
+
+#include "format-util.h"
+#include "netlink-internal.h"
+#include "netlink-types.h"
+#include "netlink-util.h"
+#include "socket-util.h"
+#include "util.h"
+
+static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ struct nfgenmsg *nfh;
+ const NLType *nl_type;
+ size_t size;
+ int r;
+
+ assert_return(nfnl, -EINVAL);
+
+ r = type_system_root_get_type(nfnl, &nl_type, NFNL_SUBSYS_NFTABLES);
+ if (r < 0)
+ return r;
+
+ if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
+ return -EINVAL;
+
+ r = message_new_empty(nfnl, &m);
+ if (r < 0)
+ return r;
+
+ size = NLMSG_SPACE(type_get_size(nl_type));
+
+ assert(size >= sizeof(struct nlmsghdr));
+ m->hdr = malloc0(size);
+ if (!m->hdr)
+ return -ENOMEM;
+
+ m->hdr->nlmsg_flags = NLM_F_REQUEST | flags;
+
+ type_get_type_system(nl_type, &m->containers[0].type_system);
+
+ r = type_system_get_type_system(m->containers[0].type_system,
+ &m->containers[0].type_system,
+ type);
+ if (r < 0)
+ return r;
+
+ m->hdr->nlmsg_len = size;
+ m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type;
+
+ nfh = NLMSG_DATA(m->hdr);
+ nfh->nfgen_family = family;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = nfnl->serial;
+
+ *ret = TAKE_PTR(m);
+ return 0;
+}
+
+static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ struct nfgenmsg *nfh;
+ int r;
+
+ r = message_new(nfnl, &m, v);
+ if (r < 0)
+ return r;
+
+ nfh = NLMSG_DATA(m->hdr);
+ nfh->nfgen_family = AF_UNSPEC;
+ nfh->version = NFNETLINK_V0;
+ nfh->res_id = NFNL_SUBSYS_NFTABLES;
+
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) {
+ return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN);
+}
+
+int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) {
+ return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END);
+}
+
+int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family,
+ const char *table, const char *chain,
+ const char *type,
+ uint8_t hook, int prio) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE | NLM_F_ACK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_CHAIN_TABLE, table);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_CHAIN_NAME, chain);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_CHAIN_TYPE, type);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container(m, NFTA_CHAIN_HOOK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_u32(m, NFTA_HOOK_HOOKNUM, htobe32(hook));
+ if (r < 0)
+ goto cancel;
+
+ r = sd_netlink_message_append_u32(m, NFTA_HOOK_PRIORITY, htobe32(prio));
+ if (r < 0)
+ goto cancel;
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ goto cancel;
+
+ *ret = TAKE_PTR(m);
+ return 0;
+cancel:
+ sd_netlink_message_cancel_array(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE | NLM_F_ACK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, uint16_t flags) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | flags);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *chain) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE | NLM_F_ACK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_RULE_TABLE, table);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_RULE_CHAIN, chain);
+ if (r < 0)
+ return r;
+
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *set_name,
+ uint32_t set_id, uint32_t klen) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE | NLM_F_ACK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_SET_TABLE, table);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_SET_NAME, set_name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_u32(m, NFTA_SET_ID, ++set_id);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen));
+ if (r < 0)
+ return r;
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *set_name) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE | NLM_F_ACK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS);
+ if (r < 0)
+ return r;
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *set_name) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, NLM_F_ACK);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS);
+ if (r < 0)
+ return r;
+ *ret = TAKE_PTR(m);
+ return r;
+}
+
+static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) {
+ int r = sd_netlink_message_open_container(m, attr);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen);
+ if (r < 0)
+ return r;
+
+ return sd_netlink_message_close_container(m); /* attr */
+}
+
+int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m,
+ uint32_t num,
+ const void *key, uint32_t klen,
+ const void *data, uint32_t dlen) {
+ int r;
+
+ r = sd_netlink_message_open_array(m, num);
+ if (r < 0)
+ return r;
+
+ r = sd_nfnl_add_data(m, NFTA_SET_ELEM_KEY, key, klen);
+ if (r < 0)
+ goto cancel;
+
+ if (data) {
+ r = sd_nfnl_add_data(m, NFTA_SET_ELEM_DATA, data, dlen);
+ if (r < 0)
+ goto cancel;
+ }
+
+ return r;
+cancel:
+ sd_netlink_message_cancel_array(m);
+ return r;
+}
+
+int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m) {
+ return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */
+}
+
+int sd_nfnl_socket_open(sd_netlink **ret) {
+ return netlink_open_family(ret, NETLINK_NETFILTER);
+}
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index bf6d1e47ff..15fa84de28 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -219,6 +219,32 @@ int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle);
int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex);
+/* nfnl */
+int sd_nfnl_socket_open(sd_netlink **nl);
+int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret);
+int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret);
+int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table);
+int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, uint16_t nl_flags);
+int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *chain,
+ const char *type, uint8_t hook, int prio);
+int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *chain);
+int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *set_name,
+ uint32_t setid, uint32_t klen);
+int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *set_name);
+int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret,
+ int family, const char *table, const char *set_name);
+int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m,
+ uint32_t num,
+ const void *key, uint32_t klen,
+ const void *data, uint32_t dlen);
+int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m);
+
/* genl */
int sd_genl_socket_open(sd_netlink **nl);
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);