From: Maxime Bizon <mbizon@freebox.fr>
To: netdev <netdev@vger.kernel.org>
Cc: davem <davem@davemloft.net>, kaber <kaber@trash.net>,
pablo@netfilter.org,
netfilter-devel <netfilter-devel@vger.kernel.org>
Subject: [PATCH v2] netfilter: fix bad checksum on IPv6 when NAT is performed
Date: Thu, 08 Oct 2015 22:26:12 +0200 [thread overview]
Message-ID: <1444335972.14655.388.camel@sakura.staff.proxad.net> (raw)
In-Reply-To: <1444335587.14655.387.camel@sakura.staff.proxad.net>
With this setup:
* non IPv6 checksumming capable network hardware
* GRO off
* IPv6 SNAT
I get this when I receive an UDPv6 reply: "<unknown>: hw csum failure"
Call trace:
* nf_ip6_checksum() calls __skb_checksum_complete()
* nf_nat_ipv6_csum_update() & nf_nat_ipv6_manip_pkt()
* __udp6_lib_rcv() => udp6_csum_init()
* __skb_checksum_validate_complete() "fastpath" fails because
skb->csum is incorrect.
* udpv6_recvmsg() => skb_copy_and_csum_datagram_msg()
The last call computes a valid checksum despite CHECKSUM_COMPLETE and
triggers the warning.
When we perform NAT on IPv4, we also update the IPv4 checksum, so
there is no side effect on skb->csum (since the csum over a valid IPv4
header area was already zero).
But IPv6 doesn't have such checksum, so when performing NAT we need to
update skb->csum.
Signed-off-by: Maxime Bizon <mbizon@freebox.fr>
---
net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
index 70fbaed..e44af9c 100644
--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
@@ -81,6 +81,8 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
enum nf_nat_manip_type maniptype)
{
struct ipv6hdr *ipv6h;
+ const __be32 *to;
+ __be32 *from;
__be16 frag_off;
int hdroff;
u8 nexthdr;
@@ -100,11 +102,24 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
target, maniptype))
return false;
manip_addr:
- if (maniptype == NF_NAT_MANIP_SRC)
- ipv6h->saddr = target->src.u3.in6;
- else
- ipv6h->daddr = target->dst.u3.in6;
+ if (maniptype == NF_NAT_MANIP_SRC) {
+ from = ipv6h->saddr.s6_addr32;
+ to = target->src.u3.in6.s6_addr32;
+ } else {
+ from = ipv6h->daddr.s6_addr32;
+ to = target->dst.u3.in6.s6_addr32;
+ }
+
+ if (skb->ip_summed == CHECKSUM_COMPLETE) {
+ __be32 diff[] = {
+ ~from[0], ~from[1], ~from[2], ~from[3],
+ to[0], to[1], to[2], to[3],
+ };
+
+ skb->csum = ~csum_partial(diff, sizeof(diff), ~skb->csum);
+ }
+ memcpy(from, to, sizeof (struct in6_addr));
return true;
}
--
1.9.1
--
Maxime
next prev parent reply other threads:[~2015-10-08 20:26 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-10-06 14:23 [PATCH] netfilter: fix bad checksum on IPv6 when NAT is performed Maxime Bizon
2015-10-08 20:19 ` Maxime Bizon
2015-10-08 20:26 ` Maxime Bizon [this message]
2015-10-08 21:09 ` [PATCH v2] " Tom Herbert
2015-10-08 21:26 ` Maxime Bizon
2015-10-08 22:11 ` Tom Herbert
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1444335972.14655.388.camel@sakura.staff.proxad.net \
--to=mbizon@freebox.fr \
--cc=davem@davemloft.net \
--cc=kaber@trash.net \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).