Commit 346e320c authored by Davide Caratti's avatar Davide Caratti Committed by Jakub Kicinski

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: default avatarDavide Caratti <dcaratti@redhat.com>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 54086c5a
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment