Skip to content

Commit 346e320

Browse files
dcarattikuba-moo
authored andcommitted
netfilter: nftables: allow re-computing sctp CRC-32C in 'payload' statements
nftables payload statements are used to mangle SCTP headers, but they can only replace the Internet Checksum. As a consequence, nftables rules that mangle sport/dport/vtag in SCTP headers potentially generate packets that are discarded by the receiver, unless the CRC-32C is "offloaded" (e.g the rule mangles a skb having 'ip_summed' equal to 'CHECKSUM_PARTIAL'. Fix this extending uAPI definitions and L4 checksum update function, in a way that userspace programs (e.g. nft) can instruct the kernel to compute CRC-32C in SCTP headers. Also ensure that LIBCRC32C is built if NF_TABLES is 'y' or 'm' in the kernel build configuration. Signed-off-by: Davide Caratti <dcaratti@redhat.com> Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 54086c5 commit 346e320

3 files changed

Lines changed: 31 additions & 0 deletions

File tree

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,10 +749,12 @@ enum nft_payload_bases {
749749
*
750750
* @NFT_PAYLOAD_CSUM_NONE: no checksumming
751751
* @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
752+
* @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309)
752753
*/
753754
enum nft_payload_csum_types {
754755
NFT_PAYLOAD_CSUM_NONE,
755756
NFT_PAYLOAD_CSUM_INET,
757+
NFT_PAYLOAD_CSUM_SCTP,
756758
};
757759

758760
enum nft_payload_csum_flags {

net/netfilter/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ endif # NF_CONNTRACK
441441

442442
config NF_TABLES
443443
select NETFILTER_NETLINK
444+
select LIBCRC32C
444445
tristate "Netfilter nf_tables support"
445446
help
446447
nftables is the new packet classification framework that intends to

net/netfilter/nft_payload.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/icmpv6.h>
2323
#include <linux/ip.h>
2424
#include <linux/ipv6.h>
25+
#include <net/sctp/checksum.h>
2526

2627
static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
2728
struct vlan_ethhdr *veth)
@@ -484,6 +485,19 @@ static int nft_payload_l4csum_offset(const struct nft_pktinfo *pkt,
484485
return 0;
485486
}
486487

488+
static int nft_payload_csum_sctp(struct sk_buff *skb, int offset)
489+
{
490+
struct sctphdr *sh;
491+
492+
if (skb_ensure_writable(skb, offset + sizeof(*sh)))
493+
return -1;
494+
495+
sh = (struct sctphdr *)(skb->data + offset);
496+
sh->checksum = sctp_compute_cksum(skb, offset);
497+
skb->ip_summed = CHECKSUM_UNNECESSARY;
498+
return 0;
499+
}
500+
487501
static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt,
488502
struct sk_buff *skb,
489503
__wsum fsum, __wsum tsum)
@@ -587,6 +601,13 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
587601
skb_store_bits(skb, offset, src, priv->len) < 0)
588602
goto err;
589603

604+
if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
605+
pkt->tprot == IPPROTO_SCTP &&
606+
skb->ip_summed != CHECKSUM_PARTIAL) {
607+
if (nft_payload_csum_sctp(skb, pkt->xt.thoff))
608+
goto err;
609+
}
610+
590611
return;
591612
err:
592613
regs->verdict.code = NFT_BREAK;
@@ -623,6 +644,13 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
623644
case NFT_PAYLOAD_CSUM_NONE:
624645
case NFT_PAYLOAD_CSUM_INET:
625646
break;
647+
case NFT_PAYLOAD_CSUM_SCTP:
648+
if (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER)
649+
return -EINVAL;
650+
651+
if (priv->csum_offset != offsetof(struct sctphdr, checksum))
652+
return -EINVAL;
653+
break;
626654
default:
627655
return -EOPNOTSUPP;
628656
}

0 commit comments

Comments
 (0)