* [PATCH v2] netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
@ 2024-02-20 14:55 Ignat Korchagin
2024-02-22 0:15 ` Pablo Neira Ayuso
0 siblings, 1 reply; 3+ messages in thread
From: Ignat Korchagin @ 2024-02-20 14:55 UTC (permalink / raw)
To: pablo, kadlec, fw, netfilter-devel, coreteam
Cc: kernel-team, jgriege, Ignat Korchagin
Commit d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family") added
some validation of NFPROTO_* families in the nft_compat module, but it broke
the ability to use legacy iptables modules in dual-stack nftables.
While with legacy iptables one had to independently manage IPv4 and IPv6 tables,
with nftables it is possible to have dual-stack tables sharing the rules.
Moreover, it was possible to use rules based on legacy iptables match/target
modules in dual-stack nftables. Consider the following program:
```
/* #define TBL_FAMILY NFPROTO_IPV4 */
/*
* creates something like below
* table inet testfw {
* chain input {
* type filter hook prerouting priority filter; policy accept;
* bytecode counter packets 0 bytes 0 accept
* }
* }
*
* compile:
* cc -o nftbpf nftbpf.c -lnftnl -lmnl
*/
int main(void)
{
uint8_t buf[MNL_SOCKET_BUFFER_SIZE];
uint32_t seq, rule_seq, portid;
struct mnl_nlmsg_batch *batch;
struct nlmsghdr *nlh;
struct mnl_socket *nl;
int ret;
struct xt_bpf_info_v1 *xt_bpf_info = malloc(sizeof(*xt_bpf_info));
struct nftnl_expr *m, *cnt, *im;
struct nftnl_rule *r;
struct nftnl_chain *c;
struct nftnl_table *t = nftnl_table_alloc();
if (t == NULL) {
perror("TABLE OOM");
exit(EXIT_FAILURE);
}
nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, TBL_FAMILY);
nftnl_table_set_str(t, NFTNL_TABLE_NAME, TBL_NAME);
c = nftnl_chain_alloc();
if (c == NULL) {
perror("CHAIN OOM");
exit(EXIT_FAILURE);
}
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, TBL_NAME);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, CHAIN_NAME);
nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, NF_INET_PRE_ROUTING);
nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, 0);
r = nftnl_rule_alloc();
if (r == NULL) {
perror("RULE OOM");
exit(EXIT_FAILURE);
}
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, TBL_NAME);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, CHAIN_NAME);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, TBL_FAMILY);
m = nftnl_expr_alloc("match");
if (m == NULL) {
perror("MATCH OOM");
exit(EXIT_FAILURE);
}
nftnl_expr_set_str(m, NFTNL_EXPR_MT_NAME, "bpf");
nftnl_expr_set_u32(m, NFTNL_EXPR_MT_REV, 1);
if (xt_bpf_info == NULL) {
perror("XT_BPF OOM");
exit(EXIT_FAILURE);
}
/*
* example from https://ipset.netfilter.org/iptables-extensions.man.html
* should match TCP packets
*/
xt_bpf_info->mode = XT_BPF_MODE_BYTECODE;
xt_bpf_info->bpf_program_num_elem = 4;
xt_bpf_info->bpf_program[0].code = 48;
xt_bpf_info->bpf_program[0].jt = 0;
xt_bpf_info->bpf_program[0].jf = 0;
xt_bpf_info->bpf_program[0].k = 9;
xt_bpf_info->bpf_program[1].code = 21;
xt_bpf_info->bpf_program[1].jt = 0;
xt_bpf_info->bpf_program[1].jf = 1;
xt_bpf_info->bpf_program[1].k = 6;
xt_bpf_info->bpf_program[2].code = 6;
xt_bpf_info->bpf_program[2].jt = 0;
xt_bpf_info->bpf_program[2].jf = 0;
xt_bpf_info->bpf_program[2].k = 1;
xt_bpf_info->bpf_program[3].code = 6;
xt_bpf_info->bpf_program[3].jt = 0;
xt_bpf_info->bpf_program[3].jf = 0;
xt_bpf_info->bpf_program[3].k = 0;
nftnl_expr_set(m, NFTNL_EXPR_MT_INFO, xt_bpf_info, sizeof(*xt_bpf_info));
nftnl_rule_add_expr(r, m);
cnt = nftnl_expr_alloc("counter");
if (cnt == NULL) {
perror("COUNTER OOM");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u64(cnt, NFTNL_EXPR_CTR_PACKETS, 0);
nftnl_expr_set_u64(cnt, NFTNL_EXPR_CTR_BYTES, 0);
nftnl_rule_add_expr(r, cnt);
im = nftnl_expr_alloc("immediate");
if (im == NULL) {
perror("IMMEDIATE OOM");
exit(EXIT_FAILURE);
}
nftnl_expr_set_u32(im, NFTNL_EXPR_IMM_DREG, 0);
nftnl_expr_set_u32(im, NFTNL_EXPR_IMM_VERDICT, 1);
nftnl_rule_add_expr(r, im);
seq = time(NULL);
batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWTABLE, TBL_FAMILY,
NLM_F_CREATE, seq++);
nftnl_table_nlmsg_build_payload(nlh, t);
nftnl_table_free(t);
mnl_nlmsg_batch_next(batch);
nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWCHAIN, TBL_FAMILY,
NLM_F_CREATE, seq++);
nftnl_chain_nlmsg_build_payload(nlh, c);
nftnl_chain_free(c);
mnl_nlmsg_batch_next(batch);
rule_seq = seq;
nlh = nftnl_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch),
NFT_MSG_NEWRULE, TBL_FAMILY,
NLM_F_APPEND | NLM_F_CREATE | NLM_F_ACK,
seq++);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
mnl_nlmsg_batch_next(batch);
nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
mnl_nlmsg_batch_next(batch);
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
exit(EXIT_FAILURE);
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
exit(EXIT_FAILURE);
}
portid = mnl_socket_get_portid(nl);
if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
mnl_nlmsg_batch_size(batch)) < 0) {
perror("mnl_socket_send");
exit(EXIT_FAILURE);
}
mnl_nlmsg_batch_stop(batch);
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
while (ret > 0) {
ret = mnl_cb_run(buf, ret, rule_seq, portid, NULL, NULL);
if (ret <= 0)
break;
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
}
if (ret == -1) {
perror("error");
exit(EXIT_FAILURE);
}
mnl_socket_close(nl);
return EXIT_SUCCESS;
}
```
Above creates an INET dual-stack family table using xt_bpf based rule. After
d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family") we get
EOPNOTSUPP for the above configuration.
Fix this by allowing NFPROTO_INET for nft_(match/target)_validate(), but also
restrict the functions to classic iptables hooks.
Changes in v2:
* restrict nft_(match/target)_validate() to classic iptables hooks
* rewrite example program to use unmodified libnftnl
Fixes: d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family")
Link: https://lore.kernel.org/all/Zc1PfoWN38UuFJRI@calendula/T/#mc947262582c90fec044c7a3398cc92fac7afea72
Reported-by: Jordan Griege <jgriege@cloudflare.com>
Signed-off-by: Ignat Korchagin <ignat@cloudflare.com>
---
net/netfilter/nft_compat.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
index 1f9474fefe84..d3d11dede545 100644
--- a/net/netfilter/nft_compat.c
+++ b/net/netfilter/nft_compat.c
@@ -359,10 +359,20 @@ static int nft_target_validate(const struct nft_ctx *ctx,
if (ctx->family != NFPROTO_IPV4 &&
ctx->family != NFPROTO_IPV6 &&
+ ctx->family != NFPROTO_INET &&
ctx->family != NFPROTO_BRIDGE &&
ctx->family != NFPROTO_ARP)
return -EOPNOTSUPP;
+ ret = nft_chain_validate_hooks(ctx->chain,
+ (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_IN) |
+ (1 << NF_INET_FORWARD) |
+ (1 << NF_INET_LOCAL_OUT) |
+ (1 << NF_INET_POST_ROUTING));
+ if (ret)
+ return ret;
+
if (nft_is_base_chain(ctx->chain)) {
const struct nft_base_chain *basechain =
nft_base_chain(ctx->chain);
@@ -610,10 +620,20 @@ static int nft_match_validate(const struct nft_ctx *ctx,
if (ctx->family != NFPROTO_IPV4 &&
ctx->family != NFPROTO_IPV6 &&
+ ctx->family != NFPROTO_INET &&
ctx->family != NFPROTO_BRIDGE &&
ctx->family != NFPROTO_ARP)
return -EOPNOTSUPP;
+ ret = nft_chain_validate_hooks(ctx->chain,
+ (1 << NF_INET_PRE_ROUTING) |
+ (1 << NF_INET_LOCAL_IN) |
+ (1 << NF_INET_FORWARD) |
+ (1 << NF_INET_LOCAL_OUT) |
+ (1 << NF_INET_POST_ROUTING));
+ if (ret)
+ return ret;
+
if (nft_is_base_chain(ctx->chain)) {
const struct nft_base_chain *basechain =
nft_base_chain(ctx->chain);
--
2.39.2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
2024-02-20 14:55 [PATCH v2] netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate() Ignat Korchagin
@ 2024-02-22 0:15 ` Pablo Neira Ayuso
2024-02-22 7:44 ` Ignat Korchagin
0 siblings, 1 reply; 3+ messages in thread
From: Pablo Neira Ayuso @ 2024-02-22 0:15 UTC (permalink / raw)
To: Ignat Korchagin
Cc: kadlec, fw, netfilter-devel, coreteam, kernel-team, jgriege
On Tue, Feb 20, 2024 at 02:55:09PM +0000, Ignat Korchagin wrote:
> Commit d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family") added
> some validation of NFPROTO_* families in the nft_compat module, but it broke
> the ability to use legacy iptables modules in dual-stack nftables.
>
> While with legacy iptables one had to independently manage IPv4 and IPv6 tables,
> with nftables it is possible to have dual-stack tables sharing the rules.
> Moreover, it was possible to use rules based on legacy iptables match/target
> modules in dual-stack nftables. Consider the following program:
>
> ```
>
> /* #define TBL_FAMILY NFPROTO_IPV4 */
>
> /*
> * creates something like below
> * table inet testfw {
> * chain input {
> * type filter hook prerouting priority filter; policy accept;
> * bytecode counter packets 0 bytes 0 accept
Upstream nft does not provides this. Please, clarify that this the
output with the out-of-tree patch,
> * }
> * }
> *
> * compile:
> * cc -o nftbpf nftbpf.c -lnftnl -lmnl
> */
> int main(void)
Please, no program in the commit description, it makes it too long,
I am not sure this is the good place to store this.
> ```
>
> Above creates an INET dual-stack family table using xt_bpf based rule. After
> d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family") we get
> EOPNOTSUPP for the above configuration.
>
> Fix this by allowing NFPROTO_INET for nft_(match/target)_validate(), but also
> restrict the functions to classic iptables hooks.
>
> Changes in v2:
> * restrict nft_(match/target)_validate() to classic iptables hooks
> * rewrite example program to use unmodified libnftnl
Thanks! Please send a v3 with updates.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate()
2024-02-22 0:15 ` Pablo Neira Ayuso
@ 2024-02-22 7:44 ` Ignat Korchagin
0 siblings, 0 replies; 3+ messages in thread
From: Ignat Korchagin @ 2024-02-22 7:44 UTC (permalink / raw)
To: Pablo Neira Ayuso
Cc: kadlec, fw, netfilter-devel, coreteam, kernel-team, jgriege
On Thu, Feb 22, 2024 at 12:15 AM Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> On Tue, Feb 20, 2024 at 02:55:09PM +0000, Ignat Korchagin wrote:
> > Commit d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family") added
> > some validation of NFPROTO_* families in the nft_compat module, but it broke
> > the ability to use legacy iptables modules in dual-stack nftables.
> >
> > While with legacy iptables one had to independently manage IPv4 and IPv6 tables,
> > with nftables it is possible to have dual-stack tables sharing the rules.
> > Moreover, it was possible to use rules based on legacy iptables match/target
> > modules in dual-stack nftables. Consider the following program:
> >
> > ```
> >
> > /* #define TBL_FAMILY NFPROTO_IPV4 */
> >
> > /*
> > * creates something like below
> > * table inet testfw {
> > * chain input {
> > * type filter hook prerouting priority filter; policy accept;
> > * bytecode counter packets 0 bytes 0 accept
>
> Upstream nft does not provides this. Please, clarify that this the
> output with the out-of-tree patch,
>
> > * }
> > * }
> > *
> > * compile:
> > * cc -o nftbpf nftbpf.c -lnftnl -lmnl
> > */
> > int main(void)
>
> Please, no program in the commit description, it makes it too long,
> I am not sure this is the good place to store this.
What if I replace the table and chain creation with nft commands and
just leave the code creating the rule? This would make the overall
program shorter, but would still illustrate the example
> > ```
> >
> > Above creates an INET dual-stack family table using xt_bpf based rule. After
> > d0009effa886 ("netfilter: nf_tables: validate NFPROTO_* family") we get
> > EOPNOTSUPP for the above configuration.
> >
> > Fix this by allowing NFPROTO_INET for nft_(match/target)_validate(), but also
> > restrict the functions to classic iptables hooks.
> >
> > Changes in v2:
> > * restrict nft_(match/target)_validate() to classic iptables hooks
> > * rewrite example program to use unmodified libnftnl
>
> Thanks! Please send a v3 with updates.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2024-02-22 7:45 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-20 14:55 [PATCH v2] netfilter: nf_tables: allow NFPROTO_INET in nft_(match/target)_validate() Ignat Korchagin
2024-02-22 0:15 ` Pablo Neira Ayuso
2024-02-22 7:44 ` Ignat Korchagin
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.