summaryrefslogtreecommitdiffstats
path: root/iptables/nft-shared.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2022-01-25 17:52:57 +0100
committerFlorian Westphal <fw@strlen.de>2022-01-29 13:38:08 +0100
commit5489493e6590b35765f676d6638c696bfe00c4b4 (patch)
tree5c9e132e3ef7e0bcb93cdce9707f2312cc5a1a16 /iptables/nft-shared.c
parent5795a1b5b611fbf7a64be34b2675f88e8f9bbaef (diff)
nft-shared: support native udp port delinearize
same as previous patch, but for udp. Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'iptables/nft-shared.c')
-rw-r--r--iptables/nft-shared.c125
1 files changed, 121 insertions, 4 deletions
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 6989a29f..f7836a01 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -495,6 +495,24 @@ nft_create_match(struct nft_xt_ctx *ctx,
return match;
}
+static struct xt_udp *nft_udp_match(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs)
+{
+ struct xt_udp *udp = ctx->tcpudp.udp;
+ struct xtables_match *match;
+
+ if (!udp) {
+ match = nft_create_match(ctx, cs, "udp");
+ if (!match)
+ return NULL;
+
+ udp = (void*)match->m->data;
+ ctx->tcpudp.udp = udp;
+ }
+
+ return udp;
+}
+
static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx,
struct iptables_command_state *cs)
{
@@ -513,11 +531,47 @@ static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx,
return tcp;
}
+static void nft_parse_udp_range(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
+{
+ struct xt_udp *udp = nft_udp_match(ctx, cs);
+
+ if (!udp)
+ return;
+
+ if (sport_from >= 0) {
+ switch (op) {
+ case NFT_RANGE_NEQ:
+ udp->invflags |= XT_UDP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_RANGE_EQ:
+ udp->spts[0] = sport_from;
+ udp->spts[1] = sport_to;
+ break;
+ }
+ }
+
+ if (dport_to >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->dpts[0] = dport_from;
+ udp->dpts[1] = dport_to;
+ break;
+ }
+ }
+}
+
static void nft_parse_tcp_range(struct nft_xt_ctx *ctx,
- struct iptables_command_state *cs,
- int sport_from, int sport_to,
- int dport_from, int dport_to,
- uint8_t op)
+ struct iptables_command_state *cs,
+ int sport_from, int sport_to,
+ int dport_from, int dport_to,
+ uint8_t op)
{
struct xt_tcp *tcp = nft_tcp_match(ctx, cs);
@@ -549,6 +603,63 @@ static void nft_parse_tcp_range(struct nft_xt_ctx *ctx,
}
}
+static void nft_parse_udp(struct nft_xt_ctx *ctx,
+ struct iptables_command_state *cs,
+ int sport, int dport,
+ uint8_t op)
+{
+ struct xt_udp *udp = nft_udp_match(ctx, cs);
+
+ if (!udp)
+ return;
+
+ if (sport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_SRCPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->spts[0] = sport;
+ udp->spts[1] = sport;
+ break;
+ case NFT_CMP_LT:
+ udp->spts[1] = sport > 1 ? sport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ udp->spts[1] = sport;
+ break;
+ case NFT_CMP_GT:
+ udp->spts[0] = sport < 0xffff ? sport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ udp->spts[0] = sport;
+ break;
+ }
+ }
+ if (dport >= 0) {
+ switch (op) {
+ case NFT_CMP_NEQ:
+ udp->invflags |= XT_UDP_INV_DSTPT;
+ /* fallthrough */
+ case NFT_CMP_EQ:
+ udp->dpts[0] = dport;
+ udp->dpts[1] = dport;
+ break;
+ case NFT_CMP_LT:
+ udp->dpts[1] = dport > 1 ? dport - 1 : 1;
+ break;
+ case NFT_CMP_LTE:
+ udp->dpts[1] = dport;
+ break;
+ case NFT_CMP_GT:
+ udp->dpts[0] = dport < 0xffff ? dport + 1 : 0xffff;
+ break;
+ case NFT_CMP_GTE:
+ udp->dpts[0] = dport;
+ break;
+ }
+ }
+}
static void nft_parse_tcp(struct nft_xt_ctx *ctx,
struct iptables_command_state *cs,
@@ -615,6 +726,9 @@ static void nft_parse_th_port(struct nft_xt_ctx *ctx,
int sport, int dport, uint8_t op)
{
switch (proto) {
+ case IPPROTO_UDP:
+ nft_parse_udp(ctx, cs, sport, dport, op);
+ break;
case IPPROTO_TCP:
nft_parse_tcp(ctx, cs, sport, dport, op);
break;
@@ -628,6 +742,9 @@ static void nft_parse_th_port_range(struct nft_xt_ctx *ctx,
int dport_from, int dport_to, uint8_t op)
{
switch (proto) {
+ case IPPROTO_UDP:
+ nft_parse_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
+ break;
case IPPROTO_TCP:
nft_parse_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op);
break;