mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 10:46:33 +00:00
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>
This commit is contained in:
parent
54086c5a7f
commit
346e320cb2
@ -749,10 +749,12 @@ enum nft_payload_bases {
|
||||
*
|
||||
* @NFT_PAYLOAD_CSUM_NONE: no checksumming
|
||||
* @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
|
||||
* @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309)
|
||||
*/
|
||||
enum nft_payload_csum_types {
|
||||
NFT_PAYLOAD_CSUM_NONE,
|
||||
NFT_PAYLOAD_CSUM_INET,
|
||||
NFT_PAYLOAD_CSUM_SCTP,
|
||||
};
|
||||
|
||||
enum nft_payload_csum_flags {
|
||||
|
@ -441,6 +441,7 @@ endif # NF_CONNTRACK
|
||||
|
||||
config NF_TABLES
|
||||
select NETFILTER_NETLINK
|
||||
select LIBCRC32C
|
||||
tristate "Netfilter nf_tables support"
|
||||
help
|
||||
nftables is the new packet classification framework that intends to
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/sctp/checksum.h>
|
||||
|
||||
static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
|
||||
struct vlan_ethhdr *veth)
|
||||
@ -484,6 +485,19 @@ static int nft_payload_l4csum_offset(const struct nft_pktinfo *pkt,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_payload_csum_sctp(struct sk_buff *skb, int offset)
|
||||
{
|
||||
struct sctphdr *sh;
|
||||
|
||||
if (skb_ensure_writable(skb, offset + sizeof(*sh)))
|
||||
return -1;
|
||||
|
||||
sh = (struct sctphdr *)(skb->data + offset);
|
||||
sh->checksum = sctp_compute_cksum(skb, offset);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt,
|
||||
struct sk_buff *skb,
|
||||
__wsum fsum, __wsum tsum)
|
||||
@ -587,6 +601,13 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
|
||||
skb_store_bits(skb, offset, src, priv->len) < 0)
|
||||
goto err;
|
||||
|
||||
if (priv->csum_type == NFT_PAYLOAD_CSUM_SCTP &&
|
||||
pkt->tprot == IPPROTO_SCTP &&
|
||||
skb->ip_summed != CHECKSUM_PARTIAL) {
|
||||
if (nft_payload_csum_sctp(skb, pkt->xt.thoff))
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
err:
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
@ -623,6 +644,13 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
|
||||
case NFT_PAYLOAD_CSUM_NONE:
|
||||
case NFT_PAYLOAD_CSUM_INET:
|
||||
break;
|
||||
case NFT_PAYLOAD_CSUM_SCTP:
|
||||
if (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER)
|
||||
return -EINVAL;
|
||||
|
||||
if (priv->csum_offset != offsetof(struct sctphdr, checksum))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user