mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-24 06:35:44 +08: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_NONE: no checksumming
|
||||||
* @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
|
* @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 {
|
enum nft_payload_csum_types {
|
||||||
NFT_PAYLOAD_CSUM_NONE,
|
NFT_PAYLOAD_CSUM_NONE,
|
||||||
NFT_PAYLOAD_CSUM_INET,
|
NFT_PAYLOAD_CSUM_INET,
|
||||||
|
NFT_PAYLOAD_CSUM_SCTP,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum nft_payload_csum_flags {
|
enum nft_payload_csum_flags {
|
||||||
|
@ -441,6 +441,7 @@ endif # NF_CONNTRACK
|
|||||||
|
|
||||||
config NF_TABLES
|
config NF_TABLES
|
||||||
select NETFILTER_NETLINK
|
select NETFILTER_NETLINK
|
||||||
|
select LIBCRC32C
|
||||||
tristate "Netfilter nf_tables support"
|
tristate "Netfilter nf_tables support"
|
||||||
help
|
help
|
||||||
nftables is the new packet classification framework that intends to
|
nftables is the new packet classification framework that intends to
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/icmpv6.h>
|
#include <linux/icmpv6.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/ipv6.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,
|
static bool nft_payload_rebuild_vlan_hdr(const struct sk_buff *skb, int mac_off,
|
||||||
struct vlan_ethhdr *veth)
|
struct vlan_ethhdr *veth)
|
||||||
@ -484,6 +485,19 @@ static int nft_payload_l4csum_offset(const struct nft_pktinfo *pkt,
|
|||||||
return 0;
|
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,
|
static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
__wsum fsum, __wsum tsum)
|
__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)
|
skb_store_bits(skb, offset, src, priv->len) < 0)
|
||||||
goto err;
|
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;
|
return;
|
||||||
err:
|
err:
|
||||||
regs->verdict.code = NFT_BREAK;
|
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_NONE:
|
||||||
case NFT_PAYLOAD_CSUM_INET:
|
case NFT_PAYLOAD_CSUM_INET:
|
||||||
break;
|
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:
|
default:
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user