same as previous patch, but for udp. Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- iptables/nft-shared.c | 117 ++++++++++++++++++++++++++++++++++++++++++ iptables/nft-shared.h | 1 + 2 files changed, 118 insertions(+) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 7f6b4ff392d9..19c82854f758 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,6 +531,42 @@ static struct xt_tcp *nft_tcp_match(struct nft_xt_ctx *ctx, return tcp; } +static void nft_complete_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_complete_tcp_range(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, int sport_from, int sport_to, @@ -549,6 +603,63 @@ static void nft_complete_tcp_range(struct nft_xt_ctx *ctx, } } +static void nft_complete_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_complete_tcp(struct nft_xt_ctx *ctx, struct iptables_command_state *cs, @@ -615,6 +726,9 @@ static void nft_complete_th_port(struct nft_xt_ctx *ctx, int sport, int dport, uint8_t op) { switch (proto) { + case IPPROTO_UDP: + nft_complete_udp(ctx, cs, sport, dport, op); + break; case IPPROTO_TCP: nft_complete_tcp(ctx, cs, sport, dport, op); break; @@ -628,6 +742,9 @@ static void nft_complete_th_port_range(struct nft_xt_ctx *ctx, int dport_from, int dport_to, uint8_t op) { switch (proto) { + case IPPROTO_UDP: + nft_complete_udp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); + break; case IPPROTO_TCP: nft_complete_tcp_range(ctx, cs, sport_from, sport_to, dport_from, dport_to, op); break; diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 1468d5608158..0716c8f4a509 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -56,6 +56,7 @@ struct nft_xt_ctx { const char *table; union { struct xt_tcp *tcp; + struct xt_udp *udp; } tcpudp; uint32_t reg; -- 2.34.1