Revert NFTSet feature
This reverts PR #22587 and its follow-up commit. More specifically,
2299b1cae3 (partially),
e176f855278d5098d3fecc5aa24ba702147d42e0,
ceb46a31a01b3d3d1d6095d857e29ea214a2776b, and
51bb9076ab8c050bebb64db5035852385accda35.
The PR was merged without final approval, and has several issues:
- OSS fuzz reported issues in the conf parser,
- It calls synchrnous netlink call, it should not be especially in PID1,
- The importance of NFTSet for CGroup and DynamicUser may be
questionable, at least, there was no justification PID1 should support
it.
- For networkd, it should be implemented with Request object,
- There is no test for the feature.
Fixes #23711.
Fixes #23717.
Fixes #23719.
Fixes #23720.
Fixes #23721.
Fixes #23759.
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
#include "exec-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fileio.h"
|
||||
#include "firewall-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "in-addr-util.h"
|
||||
@@ -435,91 +434,6 @@ static int bus_append_ip_address_access(sd_bus_message *m, int family, const uni
|
||||
return sd_bus_message_close_container(m);
|
||||
}
|
||||
|
||||
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (isempty(eq)) {
|
||||
r = sd_bus_message_append(m, "(sv)", field, "a(iss)", 0);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'v', "a(iss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "(iss)");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
int family;
|
||||
|
||||
r = extract_first_word(&eq, &word, ":", 0);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse %s: %m", field);
|
||||
if (isempty(word)) {
|
||||
log_error("Failed to parse %s", field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
family = nfproto_from_string(word);
|
||||
if (family < 0)
|
||||
return log_error_errno(family, "Failed to parse %s: %m", field);
|
||||
|
||||
r = extract_first_word(&eq, &word, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse %s: %m", field);
|
||||
if (isempty(word) || isempty(eq)) {
|
||||
log_error("Failed to parse %s", field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *unescaped = NULL;
|
||||
ssize_t l;
|
||||
|
||||
l = cunescape(eq, 0, &unescaped);
|
||||
if (l < 0)
|
||||
return log_error_errno(l, "Failed to unescape %s= value: %s", field, eq);
|
||||
|
||||
r = sd_bus_message_append(m, "(iss)", family, word, eq);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
}
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
|
||||
int r;
|
||||
|
||||
@@ -977,9 +891,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -2137,9 +2048,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (STR_IN_SET(field, "DynamicUserNFTSet"))
|
||||
return bus_append_nft_set(m, field, eq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,11 @@
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "extract-word.h"
|
||||
#include "firewall-util.h"
|
||||
#include "firewall-util-private.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-table.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define NFT_SYSTEMD_DNAT_MAP_NAME "map_port_ipport"
|
||||
@@ -850,12 +848,9 @@ static int nft_message_add_setelem_ip6range(
|
||||
|
||||
#define NFT_MASQ_MSGS 3
|
||||
|
||||
static int nft_set_element_op_in_addr(
|
||||
sd_netlink *nfnl,
|
||||
const char *table,
|
||||
const char *set,
|
||||
static int fw_nftables_add_masquerade_internal(
|
||||
FirewallContext *ctx,
|
||||
bool add,
|
||||
int nfproto,
|
||||
int af,
|
||||
const union in_addr_union *source,
|
||||
unsigned int source_prefixlen) {
|
||||
@@ -870,14 +865,14 @@ static int nft_set_element_op_in_addr(
|
||||
if (af == AF_INET6 && source_prefixlen < 8)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_nfnl_message_batch_begin(nfnl, &transaction[0]);
|
||||
r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
tsize = 1;
|
||||
if (add)
|
||||
r = sd_nfnl_nft_message_new_setelems_begin(nfnl, &transaction[tsize], nfproto, table, set);
|
||||
r = sd_nfnl_nft_message_new_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME);
|
||||
else
|
||||
r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &transaction[tsize], nfproto, table, set);
|
||||
r = sd_nfnl_nft_message_del_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME);
|
||||
if (r < 0)
|
||||
goto out_unref;
|
||||
|
||||
@@ -890,12 +885,12 @@ static int nft_set_element_op_in_addr(
|
||||
|
||||
++tsize;
|
||||
assert(tsize < NFT_MASQ_MSGS);
|
||||
r = sd_nfnl_message_batch_end(nfnl, &transaction[tsize]);
|
||||
r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
++tsize;
|
||||
r = nfnl_netlink_sendv(nfnl, transaction, tsize);
|
||||
r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize);
|
||||
|
||||
out_unref:
|
||||
while (tsize > 0)
|
||||
@@ -903,65 +898,6 @@ out_unref:
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static int nft_set_element_op_in_addr_open(
|
||||
bool add,
|
||||
const NFTSetContext *nft_set_context,
|
||||
int af,
|
||||
const union in_addr_union *address,
|
||||
unsigned int prefixlen) {
|
||||
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
|
||||
const char *table, *set;
|
||||
int r, nfproto;
|
||||
|
||||
assert(nft_set_context);
|
||||
nfproto = nft_set_context->nfproto;
|
||||
table = nft_set_context->table;
|
||||
assert(table);
|
||||
set = nft_set_context->set;
|
||||
assert(set);
|
||||
|
||||
r = sd_nfnl_socket_open(&nfnl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = nft_set_element_op_in_addr(nfnl, table, set,
|
||||
add, nfproto, af, address, prefixlen);
|
||||
|
||||
log_debug("%s NFT family %s table %s set %s IP address %s",
|
||||
add ? "Added" : "Deleted",
|
||||
nfproto_to_string(nfproto), table, set,
|
||||
IN_ADDR_PREFIX_TO_STRING(af, address, prefixlen));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int nft_set_element_add_in_addr(
|
||||
const NFTSetContext *nft_set_context,
|
||||
int af,
|
||||
const union in_addr_union *address,
|
||||
unsigned int prefixlen) {
|
||||
return nft_set_element_op_in_addr_open(true, nft_set_context, af, address, prefixlen);
|
||||
}
|
||||
|
||||
int nft_set_element_del_in_addr(
|
||||
const NFTSetContext *nft_set_context,
|
||||
int af,
|
||||
const union in_addr_union *address,
|
||||
unsigned int prefixlen) {
|
||||
return nft_set_element_op_in_addr_open(false, nft_set_context, af, address, prefixlen);
|
||||
}
|
||||
|
||||
static int fw_nftables_add_masquerade_internal(
|
||||
FirewallContext *ctx,
|
||||
bool add,
|
||||
int af,
|
||||
const union in_addr_union *source,
|
||||
unsigned int source_prefixlen) {
|
||||
return nft_set_element_op_in_addr(ctx->nfnl, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME,
|
||||
add, af, af, source, source_prefixlen);
|
||||
}
|
||||
|
||||
int fw_nftables_add_masquerade(
|
||||
FirewallContext *ctx,
|
||||
bool add,
|
||||
@@ -1135,222 +1071,3 @@ int fw_nftables_add_local_dnat(
|
||||
/* table created anew; previous address already gone */
|
||||
return fw_nftables_add_local_dnat_internal(ctx, add, af, protocol, local_port, remote, remote_port, NULL);
|
||||
}
|
||||
|
||||
static const char *const nfproto_table[] = {
|
||||
[NFPROTO_ARP] = "arp",
|
||||
[NFPROTO_BRIDGE] = "bridge",
|
||||
[NFPROTO_INET] = "inet",
|
||||
[NFPROTO_IPV4] = "ip",
|
||||
[NFPROTO_IPV6] = "ip6",
|
||||
[NFPROTO_NETDEV] = "netdev",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(nfproto, int);
|
||||
|
||||
#define NFT_SET_MSGS 3
|
||||
|
||||
static int nft_set_element_op(bool add, const NFTSetContext *nft_set_context, void *element, size_t element_size) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
|
||||
sd_netlink_message *transaction[NFT_SET_MSGS] = {};
|
||||
_cleanup_free_ uint32_t *serial = NULL;
|
||||
size_t tsize;
|
||||
int r, nfproto;
|
||||
const char *table, *set;
|
||||
|
||||
assert(nft_set_context);
|
||||
nfproto = nft_set_context->nfproto;
|
||||
table = nft_set_context->table;
|
||||
assert(table);
|
||||
set = nft_set_context->set;
|
||||
assert(set);
|
||||
assert(element);
|
||||
|
||||
r = sd_nfnl_socket_open(&nfnl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_nfnl_message_batch_begin(nfnl, &transaction[0]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
tsize = 1;
|
||||
|
||||
if (add)
|
||||
r = sd_nfnl_nft_message_new_setelems_begin(nfnl, &transaction[tsize], nfproto, table, set);
|
||||
else
|
||||
r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &transaction[tsize], nfproto, table, set);
|
||||
if (r < 0)
|
||||
goto out_unref;
|
||||
|
||||
r = sd_nfnl_nft_message_add_setelem(transaction[tsize], 0, element, element_size, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_nfnl_nft_message_add_setelem_end(transaction[tsize]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
++tsize;
|
||||
assert(tsize < ELEMENTSOF(transaction));
|
||||
r = sd_nfnl_message_batch_end(nfnl, &transaction[tsize]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
++tsize;
|
||||
r = sd_netlink_sendv(nfnl, transaction, tsize, &serial);
|
||||
|
||||
out_unref:
|
||||
while (tsize > 0)
|
||||
sd_netlink_message_unref(transaction[--tsize]);
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
int nft_set_element_add_uint32(const NFTSetContext *nft_set_context, uint32_t element) {
|
||||
int r;
|
||||
|
||||
assert(nft_set_context);
|
||||
r = nft_set_element_op(true, nft_set_context, &element, sizeof(element));
|
||||
if (r == 0)
|
||||
log_debug("Added NFT family %s table %s set %s element %d",
|
||||
nfproto_to_string(nft_set_context->nfproto), nft_set_context->table, nft_set_context->set, element);
|
||||
return r;
|
||||
}
|
||||
|
||||
int nft_set_element_del_uint32(const NFTSetContext *nft_set_context, uint32_t element) {
|
||||
int r;
|
||||
|
||||
assert(nft_set_context);
|
||||
r = nft_set_element_op(false, nft_set_context, &element, sizeof(element));
|
||||
if (r == 0)
|
||||
log_debug("Deleted NFT family %s table %s set %s element %d",
|
||||
nfproto_to_string(nft_set_context->nfproto), nft_set_context->table, nft_set_context->set, element);
|
||||
return r;
|
||||
}
|
||||
|
||||
int nft_set_element_add_uint64(const NFTSetContext *nft_set_context, uint64_t element) {
|
||||
int r;
|
||||
|
||||
assert(nft_set_context);
|
||||
r = nft_set_element_op(true, nft_set_context, &element, sizeof(element));
|
||||
if (r == 0)
|
||||
log_debug("Added NFT family %s table %s set %s element %"PRIu64,
|
||||
nfproto_to_string(nft_set_context->nfproto), nft_set_context->table, nft_set_context->set, element);
|
||||
return r;
|
||||
}
|
||||
|
||||
int nft_set_element_del_uint64(const NFTSetContext *nft_set_context, uint64_t element) {
|
||||
int r;
|
||||
|
||||
assert(nft_set_context);
|
||||
r = nft_set_element_op(false, nft_set_context, &element, sizeof(element));
|
||||
if (r == 0)
|
||||
log_debug("Deleted NFT family %s table %s set %s element %"PRIu64,
|
||||
nfproto_to_string(nft_set_context->nfproto), nft_set_context->table, nft_set_context->set, element);
|
||||
return r;
|
||||
}
|
||||
|
||||
NFTSetContext* nft_set_context_free_many(NFTSetContext *s, size_t *n) {
|
||||
assert(n);
|
||||
assert(s || *n == 0);
|
||||
|
||||
for (size_t i = 0; i < *n; i++) {
|
||||
free(s[i].table);
|
||||
free(s[i].set);
|
||||
}
|
||||
|
||||
free(s);
|
||||
*n = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nft_set_context_add(NFTSetContext **s, size_t *n, int nfproto, const char *table, const char *set) {
|
||||
_cleanup_free_ char *table_dup = NULL, *set_dup = NULL;
|
||||
assert(s);
|
||||
assert(n);
|
||||
|
||||
table_dup = strdup(table);
|
||||
if (!table_dup)
|
||||
return -ENOMEM;
|
||||
|
||||
set_dup = strdup(set);
|
||||
if (!set_dup)
|
||||
return -ENOMEM;
|
||||
|
||||
NFTSetContext *c;
|
||||
c = reallocarray(*s, *n + 1, sizeof(NFTSetContext));
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
*s = c;
|
||||
|
||||
c[(*n) ++] = (NFTSetContext) {
|
||||
.nfproto = nfproto,
|
||||
.table = TAKE_PTR(table_dup),
|
||||
.set = TAKE_PTR(set_dup),
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_nft_set_context(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
NFTSetContext **nft_set_context,
|
||||
size_t *n) {
|
||||
_cleanup_free_ char *family_str = NULL, *table = NULL, *set = NULL;
|
||||
int nfproto, r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(nft_set_context);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
nft_set_context_free_many(*nft_set_context, n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const char *p = rvalue;;) {
|
||||
r = extract_many_words(&p, ":" WHITESPACE, EXTRACT_CUNESCAPE, &family_str, &table, &set, NULL);
|
||||
if (r == -ENOMEM)
|
||||
return log_oom();
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r != 3) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse IPvxNFT set, ignoring: %s", rvalue);
|
||||
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;
|
||||
}
|
||||
|
||||
if (nft_identifier_bad(table))
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid table name %s, ignoring", table);
|
||||
|
||||
if (nft_identifier_bad(set))
|
||||
return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid set name %s, ignoring", set);
|
||||
|
||||
NFTSetContext *c;
|
||||
c = reallocarray(*nft_set_context, *n + 1, sizeof(NFTSetContext));
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
*nft_set_context = c;
|
||||
|
||||
c[(*n) ++] = (NFTSetContext) {
|
||||
.nfproto = nfproto,
|
||||
.table = TAKE_PTR(table),
|
||||
.set = TAKE_PTR(set),
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,43 +29,3 @@ int fw_add_local_dnat(
|
||||
const union in_addr_union *remote,
|
||||
uint16_t remote_port,
|
||||
const union in_addr_union *previous_remote);
|
||||
|
||||
struct NFTSetContext {
|
||||
int nfproto;
|
||||
char *table;
|
||||
char *set;
|
||||
};
|
||||
typedef struct NFTSetContext NFTSetContext;
|
||||
|
||||
int nft_set_context_add(NFTSetContext **s, size_t *n, int nfproto, const char *table, const char *set);
|
||||
NFTSetContext* nft_set_context_free_many(NFTSetContext *s, size_t *n);
|
||||
int config_parse_nft_set_context(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
NFTSetContext **nft_set_context,
|
||||
size_t *n);
|
||||
|
||||
const char *nfproto_to_string(int i) _const_;
|
||||
int nfproto_from_string(const char *s) _pure_;
|
||||
|
||||
int nft_set_element_add_in_addr(
|
||||
const NFTSetContext *nft_set_context,
|
||||
int af,
|
||||
const union in_addr_union *address,
|
||||
unsigned int prefixlen);
|
||||
int nft_set_element_del_in_addr(
|
||||
const NFTSetContext *nft_set_context,
|
||||
int af,
|
||||
const union in_addr_union *address,
|
||||
unsigned int prefixlen);
|
||||
|
||||
int nft_set_element_add_uint32(const NFTSetContext *nft_set_context, uint32_t element);
|
||||
int nft_set_element_del_uint32(const NFTSetContext *nft_set_context, uint32_t element);
|
||||
int nft_set_element_add_uint64(const NFTSetContext *nft_set_context, uint64_t element);
|
||||
int nft_set_element_del_uint64(const NFTSetContext *nft_set_context, uint64_t element);
|
||||
|
||||
Reference in New Issue
Block a user