From: Florian Westphal <fw@strlen.de>
To: <netfilter-devel@vger.kernel.org>
Cc: Florian Westphal <fw@strlen.de>
Subject: [PATCH iptables-nft 1/7] nft-shared: support native tcp port delinearize
Date: Tue, 25 Jan 2022 17:52:55 +0100 [thread overview]
Message-ID: <20220125165301.5960-2-fw@strlen.de> (raw)
In-Reply-To: <20220125165301.5960-1-fw@strlen.de>
This extends iptables-nft dissector to decode native tcp
port matching. nft ruleset:
table ip filter {
chain INPUT {
type filter hook input priority filter; policy accept;
tcp sport 12345
tcp sport 12345 tcp dport 6789
tcp sport < 1024
tcp dport >= 1024
}
}
$ iptables-nft-save
-A INPUT -p tcp -m tcp --sport 12345
-A INPUT -p tcp -m tcp --sport 12345 --dport 6789
-A INPUT -p tcp -m tcp --sport 0:1023
-A INPUT -p tcp -m tcp --dport 1024:65535
This would allow to extend iptables-nft to prefer
native payload expressions for --sport,dport in the future.
Also, parse_cmp must not clear the "payload" flag, this is because
cmp-based range expressions will contain following sequence:
payload => reg1
cmp reg1 > minv
cmp reg1 < maxv
... so second cmp would work.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
iptables/nft-shared.c | 178 +++++++++++++++++++++++++++++++++++++++++-
iptables/nft-shared.h | 3 +
2 files changed, 179 insertions(+), 2 deletions(-)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index d0d0d558dde4..674c72b35ae7 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -468,6 +468,170 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->flags |= NFT_XT_CTX_BITWISE;
}
+static struct xtables_match *
+nft_create_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ const char *name)
+{
+ struct xtables_match *match;
+ struct xt_entry_match *m;
+ unsigned int size;
+
+ match = xtables_find_match(name, XTF_TRY_LOAD,
+ &cs->matches);
+ if (!match)
+ return NULL;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size;
+ m = xtables_calloc(1, size);
+ m->u.match_size = size;
+ m->u.user.revision = match->revision;
+
+ strcpy(m->u.user.name, match->name);
+ match->m = m;
+
+ xs_init_match(match);
+
+ return match;
+}
+
+static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs)
+{
+ struct xt_tcp *tcp = ctx->tcpudp.tcp;
+ struct xtables_match *match;
+
+ if (!tcp) {
+ match = nft_create_match(ctx, cs, "tcp");
+ if (!match)
+ return NULL;
+
+ tcp = (void*)match->m->data;
+ ctx->tcpudp.tcp = tcp;
+ }
+
+ return tcp;
+}
+
+static void nft_complete_tcp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport, int dport,
+ uint8_t op)
+{
+ struct xt_tcp *tcp = nft_tcp_match(ctx, cs);
+
+ if (!tcp)
+ return;
+
+ if (sport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->spts[0] = sport;
+ tcp->spts[1] = sport;
+ break;
+ case NFT_CMP_LT:
+ tcp->spts[1] = sport > 1 ? sport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ tcp->spts[1] = sport;
+ break;
+ case NFT_CMP_GT:
+ tcp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ tcp->spts[0] = sport;
+ break;
+ }
+ }
+
+ if (dport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ tcp->invflags |= XT_TCP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ tcp->dpts[0] = dport;
+ tcp->dpts[1] = dport;
+ break;
+ case NFT_CMP_LT:
+ tcp->dpts[1] = dport > 1 ? dport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ tcp->dpts[1] = dport;
+ break;
+ case NFT_CMP_GT:
+ tcp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ tcp->dpts[0] = dport;
+ break;
+ }
+ }
+}
+
+static void nft_complete_th_port(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ uint8_t proto,
+ int sport, int dport, uint8_t op)
+{
+ switch (proto) {
+ case IPPROTO_TCP:
+ nft_complete_tcp(ctx, cs, sport, dport, op);
+ break;
+ }
+}
+
+static void nft_complete_transport(struct nft_xt_ctx *ctx,
+ struct nftnl_expr *e, void *data)
+{
+ struct iptables_command_state *cs = data;
+ uint32_t sdport;
+ uint16_t port;
+ uint8_t proto, op;
+ unsigned int len;
+
+ switch (ctx->h->family) {
+ case NFPROTO_IPV4:
+ proto = ctx->cs->fw.ip.proto;
+ break;
+ case NFPROTO_IPV6:
+ proto = ctx->cs->fw6.ipv6.proto;
+ break;
+ default:
+ proto = 0;
+ break;
+ }
+
+ nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len);
+ op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+
+ switch(ctx->payload.offset) {
+ case 0: /* th->sport */
+ switch (len) {
+ case 2: /* load sport only */
+ port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
+ nft_complete_th_port(ctx, cs, proto, port, -1, op);
+ return;
+ case 4: /* load both src and dst port */
+ sdport = ntohl(nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_DATA));
+ nft_complete_th_port(ctx, cs, proto, sdport >> 16, sdport & 0xffff, op);
+ return;
+ }
+ break;
+ case 2: /* th->dport */
+ switch (len) {
+ case 2:
+ port = ntohs(nftnl_expr_get_u16(e, NFTNL_EXPR_CMP_DATA));
+ nft_complete_th_port(ctx, cs, proto, -1, port, op);
+ return;
+ }
+ break;
+ }
+}
+
static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
void *data = ctx->cs;
@@ -483,8 +647,18 @@ static void nft_parse_cmp(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
}
/* bitwise context is interpreted from payload */
if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
- ctx->h->ops->parse_payload(ctx, e, data);
- ctx->flags &= ~NFT_XT_CTX_PAYLOAD;
+ switch (ctx->payload.base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ if (ctx->h->family == NFPROTO_BRIDGE)
+ ctx->h->ops->parse_payload(ctx, e, data);
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ ctx->h->ops->parse_payload(ctx, e, data);
+ break;
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ nft_complete_transport(ctx, e, data);
+ break;
+ }
}
}
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index c3241f4b8c72..0a8be7099aa2 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -53,6 +53,9 @@ struct nft_xt_ctx {
struct nft_handle *h;
uint32_t flags;
const char *table;
+ union {
+ struct xt_tcp *tcp;
+ } tcpudp;
uint32_t reg;
struct {
--
2.34.1
next prev parent reply other threads:[~2022-01-25 16:58 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-25 16:52 [PATCH iptables-nft 0/7] iptables: prefer native expressions for udp and tcp matches Florian Westphal
2022-01-25 16:52 ` Florian Westphal [this message]
2022-01-25 16:52 ` [PATCH iptables-nft 2/7] nft-shared: support native tcp port range delinearize Florian Westphal
2022-01-25 16:52 ` [PATCH iptables-nft 3/7] nft-shared: support native udp port delinearize Florian Westphal
2022-01-25 16:52 ` [PATCH iptables-nft 4/7] nft: prefer native expressions instead of udp match Florian Westphal
2022-01-25 16:52 ` [PATCH iptables-nft 5/7] nft: prefer native expressions instead of tcp match Florian Westphal
2022-01-25 16:53 ` [PATCH iptables-nft 6/7] nft-shared: add tcp flag dissection Florian Westphal
2022-01-25 16:53 ` [PATCH iptables-nft 7/7] nft: add support for native tcp flag matching Florian Westphal
2022-01-29 12:44 ` [PATCH iptables-nft 0/7] iptables: prefer native expressions for udp and tcp matches Florian Westphal
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220125165301.5960-2-fw@strlen.de \
--to=fw@strlen.de \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.