[PATCHv2] ipv6: ip6mr: Recalc UDP checksum before forwarding

From: Brendan McGrath
Date: Thu Dec 14 2017 - 06:37:28 EST


Currently, when forwarding a multicast packet originating from a
Virtual Interface on a Multicast Router to one of its Physical
Interfaces, ip_summed is set to a value of CHECKSUM_UNNECESSARY and
the UDP checksum is not calculated.

The checksum value of the forwarded packet is left as is and
therefore rejected by the receiving machine(s).

This patch ensures the checksum is recalculated before forwarding.

Signed-off-by: Brendan McGrath <redmcg@xxxxxxxxxxxxxxxxxxx>
---

Changes since PATCH v1:
- fixed formatting
- clarified in git comment that issue is with packet originating on
multicast router
- check value of pkt_type instead of ip_summed

To gaurentee we don't correct the checksum on a packet that was
corrupted beforehand, I changed the code to check if pkt_type is
PACKET_LOOPBACK.

I also found that ip_summed is set to CHECKSUM_UNNECESSARY in
dev_loopback_xmit. So every packet that originates and is forwarded by
the same host will have ip_summed set to CHECKSUM_UNNECESSARY.

Note that this scenario appears to be unique to multicasting as
unicast always originates on the interface where the packet will be
sent (thus a unicast packet is never forwarded by the host on which
it originates).



net/ipv6/ip6mr.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 890f9bda..96f035f 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2077,6 +2077,14 @@ static int ip6mr_forward2(struct net *net, struct mr6_table *mrt,
ipv6h = ipv6_hdr(skb);
ipv6h->hop_limit--;

+ if (ipv6h->nexthdr == NEXTHDR_UDP &&
+ skb->pkt_type == PACKET_LOOPBACK) {
+ struct udphdr *uh = udp_hdr(skb);
+
+ udp6_set_csum(false, skb, &ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr, ntohs(uh->len));
+ }
+
IP6CB(skb)->flags |= IP6SKB_FORWARDED;

return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
--
2.7.4