Commit 053d20f5 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: nft_payload: mangle ckecksum if NFT_PAYLOAD_L4CSUM_PSEUDOHDR is set

If the NFT_PAYLOAD_L4CSUM_PSEUDOHDR flag is set, then mangle layer 4
checksum. This should not depend on csum_type NFT_PAYLOAD_CSUM_INET
since IPv6 header has no checksum field, but still an update of any of
the pseudoheader fields may trigger a layer 4 checksum update.

Fixes: 18140969 ("netfilter: nft_payload: layer 4 checksum adjustment for pseudoheader fields")
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 3e38df13
...@@ -250,6 +250,22 @@ static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt, ...@@ -250,6 +250,22 @@ static int nft_payload_l4csum_update(const struct nft_pktinfo *pkt,
return 0; return 0;
} }
static int nft_payload_csum_inet(struct sk_buff *skb, const u32 *src,
__wsum fsum, __wsum tsum, int csum_offset)
{
__sum16 sum;
if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
return -1;
nft_csum_replace(&sum, fsum, tsum);
if (!skb_make_writable(skb, csum_offset + sizeof(sum)) ||
skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
return -1;
return 0;
}
static void nft_payload_set_eval(const struct nft_expr *expr, static void nft_payload_set_eval(const struct nft_expr *expr,
struct nft_regs *regs, struct nft_regs *regs,
const struct nft_pktinfo *pkt) const struct nft_pktinfo *pkt)
...@@ -259,7 +275,6 @@ static void nft_payload_set_eval(const struct nft_expr *expr, ...@@ -259,7 +275,6 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
const u32 *src = &regs->data[priv->sreg]; const u32 *src = &regs->data[priv->sreg];
int offset, csum_offset; int offset, csum_offset;
__wsum fsum, tsum; __wsum fsum, tsum;
__sum16 sum;
switch (priv->base) { switch (priv->base) {
case NFT_PAYLOAD_LL_HEADER: case NFT_PAYLOAD_LL_HEADER:
...@@ -282,18 +297,14 @@ static void nft_payload_set_eval(const struct nft_expr *expr, ...@@ -282,18 +297,14 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
csum_offset = offset + priv->csum_offset; csum_offset = offset + priv->csum_offset;
offset += priv->offset; offset += priv->offset;
if (priv->csum_type == NFT_PAYLOAD_CSUM_INET && if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
(priv->base != NFT_PAYLOAD_TRANSPORT_HEADER || (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
skb->ip_summed != CHECKSUM_PARTIAL)) { skb->ip_summed != CHECKSUM_PARTIAL)) {
if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
goto err;
fsum = skb_checksum(skb, offset, priv->len, 0); fsum = skb_checksum(skb, offset, priv->len, 0);
tsum = csum_partial(src, priv->len, 0); tsum = csum_partial(src, priv->len, 0);
nft_csum_replace(&sum, fsum, tsum);
if (!skb_make_writable(skb, csum_offset + sizeof(sum)) || if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0) nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
goto err; goto err;
if (priv->csum_flags && if (priv->csum_flags &&
......
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