nftables: allow to remove nftables table, rule, set, and so on (#43673)
This adds 'add' boolean parameter to sd_nfnl_nft_message_new_table() and friends, so that we can remove nftables table and so on. In test-firewall-util, before and after running test cases, remove the garbage nftables test table.
This commit is contained in:
@@ -196,20 +196,50 @@ int sd_nfnl_message_new(
|
||||
uint16_t subsys,
|
||||
uint16_t msg_type,
|
||||
uint16_t flags);
|
||||
int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret,
|
||||
int nfproto, const char *table);
|
||||
int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret,
|
||||
int nfproto, 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 nfproto, const char *table, const char *chain);
|
||||
int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret,
|
||||
int nfproto, const char *table, const char *set_name,
|
||||
uint32_t set_id, uint32_t klen);
|
||||
int sd_nfnl_nft_message_new_setelems(sd_netlink *nfnl, sd_netlink_message **ret,
|
||||
int add, int nfproto, const char *table, const char *set_name);
|
||||
int sd_nfnl_nft_message_append_setelem(sd_netlink_message *m,
|
||||
uint32_t index,
|
||||
const void *key, size_t key_len,
|
||||
const void *data, size_t data_len,
|
||||
uint32_t flags);
|
||||
int sd_nfnl_nft_message_new_table(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add,
|
||||
int nfproto,
|
||||
const char *table);
|
||||
int sd_nfnl_nft_message_new_basechain(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add,
|
||||
int nfproto,
|
||||
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 add,
|
||||
int nfproto,
|
||||
const char *table,
|
||||
const char *chain);
|
||||
int sd_nfnl_nft_message_new_set(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add,
|
||||
int nfproto,
|
||||
const char *table,
|
||||
const char *set_name,
|
||||
uint32_t set_id,
|
||||
uint32_t klen);
|
||||
int sd_nfnl_nft_message_new_setelems(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add,
|
||||
int nfproto,
|
||||
const char *table,
|
||||
const char *set_name);
|
||||
int sd_nfnl_nft_message_append_setelem(
|
||||
sd_netlink_message *m,
|
||||
uint32_t index,
|
||||
const void *key,
|
||||
size_t key_len,
|
||||
const void *data,
|
||||
size_t data_len,
|
||||
uint32_t flags);
|
||||
|
||||
@@ -232,6 +232,7 @@ int sd_nfnl_call_batch(
|
||||
int sd_nfnl_nft_message_new_basechain(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add, /* boolean */
|
||||
int nfproto,
|
||||
const char *table,
|
||||
const char *chain,
|
||||
@@ -242,9 +243,16 @@ int sd_nfnl_nft_message_new_basechain(
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(nfnl);
|
||||
assert(ret);
|
||||
assert(table);
|
||||
assert(chain);
|
||||
assert(!add || type);
|
||||
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWCHAIN, NLM_F_CREATE);
|
||||
if (add)
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWCHAIN, NLM_F_CREATE);
|
||||
else
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELCHAIN, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -256,25 +264,27 @@ int sd_nfnl_nft_message_new_basechain(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_string(m, NFTA_CHAIN_TYPE, type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (add) {
|
||||
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_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)
|
||||
return r;
|
||||
r = sd_netlink_message_append_u32(m, NFTA_HOOK_HOOKNUM, htobe32(hook));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u32(m, NFTA_HOOK_PRIORITY, htobe32(prio));
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_netlink_message_append_u32(m, NFTA_HOOK_PRIORITY, htobe32(prio));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
@@ -283,15 +293,24 @@ int sd_nfnl_nft_message_new_basechain(
|
||||
int sd_nfnl_nft_message_new_table(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add, /* boolean */
|
||||
int nfproto,
|
||||
const char *table) {
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(nfnl);
|
||||
assert(ret);
|
||||
assert(table);
|
||||
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL);
|
||||
/* Note, if nfproto == AF_UNSPEC, then the kernel flushes all tables. See nf_tables_deltable() in
|
||||
* nf_tables_api.c in the kernel. */
|
||||
|
||||
if (add)
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWTABLE, NLM_F_CREATE | NLM_F_EXCL);
|
||||
else
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELTABLE, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -306,6 +325,7 @@ int sd_nfnl_nft_message_new_table(
|
||||
int sd_nfnl_nft_message_new_rule(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add, /* boolean */
|
||||
int nfproto,
|
||||
const char *table,
|
||||
const char *chain) {
|
||||
@@ -313,9 +333,15 @@ int sd_nfnl_nft_message_new_rule(
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(nfnl);
|
||||
assert(ret);
|
||||
assert(table);
|
||||
assert(chain);
|
||||
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWRULE, NLM_F_CREATE);
|
||||
if (add)
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWRULE, NLM_F_CREATE);
|
||||
else
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELRULE, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -334,6 +360,7 @@ int sd_nfnl_nft_message_new_rule(
|
||||
int sd_nfnl_nft_message_new_set(
|
||||
sd_netlink *nfnl,
|
||||
sd_netlink_message **ret,
|
||||
int add, /* boolean */
|
||||
int nfproto,
|
||||
const char *table,
|
||||
const char *set_name,
|
||||
@@ -343,9 +370,15 @@ int sd_nfnl_nft_message_new_set(
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(nfnl);
|
||||
assert(ret);
|
||||
assert(table);
|
||||
assert(set_name);
|
||||
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSET, NLM_F_CREATE);
|
||||
if (add)
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSET, NLM_F_CREATE);
|
||||
else
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELSET, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -357,13 +390,15 @@ int sd_nfnl_nft_message_new_set(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u32(m, NFTA_SET_ID, ++set_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (add) {
|
||||
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;
|
||||
r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
return r;
|
||||
@@ -380,12 +415,15 @@ int sd_nfnl_nft_message_new_setelems(
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(nfnl);
|
||||
assert(ret);
|
||||
assert(table);
|
||||
assert(set_name);
|
||||
|
||||
if (add)
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSETELEM, NLM_F_CREATE);
|
||||
else
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELSETELEM, 0);
|
||||
r = sd_nfnl_message_new(nfnl, &m, nfproto, NFNL_SUBSYS_NFTABLES, NFT_MSG_DELSETELEM, /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -412,6 +450,11 @@ int sd_nfnl_nft_message_append_setelem(
|
||||
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(key);
|
||||
assert(key_len > 0);
|
||||
assert(!data || data_len > 0);
|
||||
|
||||
r = sd_netlink_message_open_array(m, index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -153,11 +153,14 @@ static const NLAPolicy nfnl_nft_setelem_list_policies[] = {
|
||||
DEFINE_POLICY_SET(nfnl_nft_setelem_list);
|
||||
|
||||
static const NLAPolicy nfnl_subsys_nft_policies[] = {
|
||||
[NFT_MSG_DELTABLE] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_table, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_NEWTABLE] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_table, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_DELTABLE] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_table, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_NEWCHAIN] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_chain, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_DELCHAIN] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_chain, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_NEWRULE] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_rule, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_DELRULE] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_rule, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_NEWSET] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_set, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_DELSET] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_set, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_NEWSETELEM] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_setelem_list, sizeof(struct nfgenmsg)),
|
||||
[NFT_MSG_DELSETELEM] = BUILD_POLICY_NESTED_WITH_SIZE(nfnl_nft_setelem_list, sizeof(struct nfgenmsg)),
|
||||
};
|
||||
|
||||
@@ -331,7 +331,7 @@ static int sd_nfnl_message_new_masq_rule(
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(chain);
|
||||
|
||||
r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, nft_table_name(), chain);
|
||||
r = sd_nfnl_nft_message_new_rule(nfnl, &m, /* add= */ true, family, nft_table_name(), chain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -386,7 +386,7 @@ static int sd_nfnl_message_new_dnat_rule_pre(
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(chain);
|
||||
|
||||
r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, nft_table_name(), chain);
|
||||
r = sd_nfnl_nft_message_new_rule(nfnl, &m, /* add= */ true, family, nft_table_name(), chain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -449,7 +449,7 @@ static int sd_nfnl_message_new_dnat_rule_out(
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(chain);
|
||||
|
||||
r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, nft_table_name(), chain);
|
||||
r = sd_nfnl_nft_message_new_rule(nfnl, &m, /* add= */ true, family, nft_table_name(), chain);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -548,7 +548,7 @@ static int nft_new_set(
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
assert(set_name);
|
||||
|
||||
r = sd_nfnl_nft_message_new_set(nfnl, &m, family, nft_table_name(), set_name, set_id, klen);
|
||||
r = sd_nfnl_nft_message_new_set(nfnl, &m, /* add= */ true, family, nft_table_name(), set_name, set_id, klen);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -734,23 +734,23 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) {
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
/* Set F_EXCL so table add fails if the table already exists. */
|
||||
r = sd_nfnl_nft_message_new_table(nfnl, &messages[msgcnt++], family, nft_table_name());
|
||||
r = sd_nfnl_nft_message_new_table(nfnl, &messages[msgcnt++], /* add= */ true, family, nft_table_name());
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], family, nft_table_name(),
|
||||
r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], /* add= */ true, family, nft_table_name(),
|
||||
"prerouting", "nat",
|
||||
NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], family, nft_table_name(),
|
||||
r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], /* add= */ true, family, nft_table_name(),
|
||||
"output", "nat",
|
||||
NF_INET_LOCAL_OUT, NF_IP_PRI_NAT_DST + 1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], family, nft_table_name(),
|
||||
r = sd_nfnl_nft_message_new_basechain(nfnl, &messages[msgcnt++], /* add= */ true, family, nft_table_name(),
|
||||
"postrouting", "nat",
|
||||
NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC + 1);
|
||||
if (r < 0)
|
||||
@@ -802,6 +802,24 @@ static int fw_nftables_init_family(sd_netlink *nfnl, int family) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fw_nftables_del_table(sd_netlink *nfnl, int family) {
|
||||
int r;
|
||||
|
||||
assert(nfnl);
|
||||
assert(IN_SET(family, AF_INET, AF_INET6));
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
r = sd_nfnl_nft_message_new_table(nfnl, &m, /* add= */ false, family, nft_table_name());
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_nfnl_call_batch(nfnl, &m, /* n_messages= */ 1, NFNL_DEFAULT_TIMEOUT_USECS);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_message_append_setelem_iprange(
|
||||
sd_netlink_message *m,
|
||||
const union in_addr_union *source,
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "conf-parser-forward.h"
|
||||
#include "forward.h"
|
||||
|
||||
int fw_nftables_del_table(sd_netlink *nfnl, int family);
|
||||
|
||||
int fw_nftables_add_masquerade(
|
||||
sd_netlink *nfnl,
|
||||
bool add,
|
||||
|
||||
@@ -79,14 +79,28 @@ static int intro(void) {
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_NFT_TABLE_NAME", "io.systemd-test.nat", /* overwrite= */ true));
|
||||
ASSERT_OK_ERRNO(setenv("SYSTEMD_FIREWALL_UTIL_DNAT_MAP_NAME", "test_map_port_ipport", /* overwrite= */ true));
|
||||
|
||||
r = sd_nfnl_socket_open(&nfnl);
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *nl = NULL;
|
||||
r = sd_nfnl_socket_open(&nl);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "Failed to initialize nftables");
|
||||
|
||||
r = fw_nftables_del_table(nl, AF_INET);
|
||||
if (r < 0)
|
||||
return log_tests_skipped_errno(r, "Failed to clear nftables test table");
|
||||
|
||||
ASSERT_OK(fw_nftables_del_table(nl, AF_INET6));
|
||||
|
||||
nfnl = TAKE_PTR(nl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int outro(void) {
|
||||
if (!nfnl)
|
||||
return 0;
|
||||
|
||||
ASSERT_OK(fw_nftables_del_table(nfnl, AF_INET));
|
||||
ASSERT_OK(fw_nftables_del_table(nfnl, AF_INET6));
|
||||
|
||||
sd_netlink_unref(nfnl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user