All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf] ipvs: fix the checksum validations
@ 2026-07-09 20:23 Julian Anastasov
  2026-07-09 21:24 ` Florian Westphal
  2026-07-11 17:17 ` Julian Anastasov
  0 siblings, 2 replies; 4+ messages in thread
From: Julian Anastasov @ 2026-07-09 20:23 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel

TCP/UDP checksum validation for CHECKSUM_COMPLETE is broken
before the git history.

Expecting skb->csum to cover data starting from the protocol
header is wrong. As IPVS works at the IP layer, the csum for
the IP header is not subtracted yet.

ip_vs_in_icmp_v6() is missing checksum validation for ICMPv6
packets from clients.

Also, Sashiko points out that handle_response_icmp() being
common for IPv4 and IPv6 is missing the pseudo-header
calculation while validating ICMPv6 messages from real
servers which is a problem if checksum is not validated
by the hardware.

Fix the problems by creating ip_vs_checksum_common_check()
helper and use it for TCP/UDP/ICMP both for IPv4 and IPv6.

Also, ip_vs_checksum_complete() can be marked static.

Fixes: 2a3b791e6e11 ("IPVS: Add/adjust Netfilter hook functions and helpers for v6")
Link: https://sashiko.dev/#/patchset/20260708180315.77413-1-ja%40ssi.bg
Signed-off-by: Julian Anastasov <ja@ssi.bg>
---
 include/net/ip_vs.h                  |  5 ++-
 net/netfilter/ipvs/ip_vs_core.c      | 63 ++++++++++++++++++++++++++--
 net/netfilter/ipvs/ip_vs_proto_tcp.c | 35 ++--------------
 net/netfilter/ipvs/ip_vs_proto_udp.c | 39 +++--------------
 4 files changed, 71 insertions(+), 71 deletions(-)

diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 49297fec448a..fd18b1cd6471 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -2065,8 +2065,6 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		       struct ip_vs_conn *cp, int dir);
 #endif
 
-__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
-
 static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
 {
 	__be32 diff[2] = { ~old, new };
@@ -2092,6 +2090,9 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
 	return csum_partial(diff, sizeof(diff), oldsum);
 }
 
+bool ip_vs_checksum_common_check(int af, struct sk_buff *skb, int proto,
+				 int offset);
+
 /* Forget current conntrack (unconfirmed) and attach notrack entry */
 static inline void ip_vs_notrack(struct sk_buff *skb)
 {
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index c9c88c99d07b..ceb1cbf33dd7 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -867,11 +867,56 @@ static int sysctl_nat_icmp_send(struct netns_ipvs *ipvs) { return 0; }
 
 #endif
 
-__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
+static __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
 {
 	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
 }
 
+/**
+ * ip_vs_checksum_common_check - validate checksum for TCP/UDP/ICMP
+ * @af: AF_INET/AF_INET6
+ * @skb: socket buffer
+ * @proto: IPPROTO_xxx
+ * @offset: offset of protocol header
+ */
+bool ip_vs_checksum_common_check(int af, struct sk_buff *skb, int proto,
+				 int offset)
+{
+	__wsum csum;
+
+	if (skb_csum_unnecessary(skb))
+		return true;
+	if (skb->ip_summed == CHECKSUM_NONE) {
+		csum = skb_checksum(skb, offset, skb->len - offset, 0);
+	} else if (skb->ip_summed == CHECKSUM_COMPLETE) {
+		/* IPVS works at IP layer, so skb->csum covers data from
+		 * IP header, strip it up to the protocol header
+		 */
+		csum = csum_sub(skb->csum, skb_checksum(skb, 0, offset, 0));
+	} else {
+		/* No need to checksum. */
+		return true;
+	}
+#ifdef CONFIG_IP_VS_IPV6
+	if (af == AF_INET6) {
+		if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+				    &ipv6_hdr(skb)->daddr,
+				    skb->len - offset, proto,
+				    csum))
+			return false;
+	} else
+#endif
+		if (proto == IPPROTO_ICMP)
+			return !csum_fold(csum);
+		else if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
+					   ip_hdr(skb)->daddr,
+					   skb->len - offset, proto,
+					   csum))
+			return false;
+
+	return true;
+}
+
 static inline enum ip_defrag_users ip_vs_defrag_user(unsigned int hooknum)
 {
 	if (NF_INET_LOCAL_IN == hooknum)
@@ -1039,12 +1084,13 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
 				unsigned int hooknum)
 {
 	unsigned int verdict = NF_DROP;
+	int iproto = af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP;
 
 	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
 		goto after_nat;
 
 	/* Ensure the checksum is correct */
-	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
+	if (!ip_vs_checksum_common_check(af, skb, iproto, ihl)) {
 		/* Failed checksum! */
 		IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n",
 			      IP_VS_DBG_ADDR(af, snet));
@@ -1898,7 +1944,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
 	verdict = NF_DROP;
 
 	/* Ensure the checksum is correct */
-	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
+	if (!ip_vs_checksum_common_check(AF_INET, skb, IPPROTO_ICMP, ihl)) {
 		/* Failed checksum! */
 		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!\n",
 			  &iph->saddr);
@@ -2064,6 +2110,17 @@ static int ip_vs_in_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
 		goto out;
 	}
 
+	verdict = NF_DROP;
+
+	/* Ensure the checksum is correct */
+	if (!ip_vs_checksum_common_check(AF_INET6, skb, IPPROTO_ICMPV6,
+					 iph->len)) {
+		/* Failed checksum! */
+		IP_VS_DBG(1, "Incoming ICMPv6: failed checksum from %pI6c!\n",
+			  &iph->saddr);
+		goto out;
+	}
+
 	/* do the statistics and put it back */
 	ip_vs_in_stats(cp, skb);
 
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
index 8cc0a8ce6241..147cf01708ff 100644
--- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
@@ -304,39 +304,10 @@ static int
 tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 	       unsigned int tcphoff)
 {
-	switch (skb->ip_summed) {
-	case CHECKSUM_NONE:
-		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
-		fallthrough;
-	case CHECKSUM_COMPLETE:
-#ifdef CONFIG_IP_VS_IPV6
-		if (af == AF_INET6) {
-			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-					    &ipv6_hdr(skb)->daddr,
-					    skb->len - tcphoff,
-					    IPPROTO_TCP,
-					    skb->csum)) {
-				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
-						 "Failed checksum for");
-				return 0;
-			}
-		} else
-#endif
-			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
-					      ip_hdr(skb)->daddr,
-					      skb->len - tcphoff,
-					      ip_hdr(skb)->protocol,
-					      skb->csum)) {
-				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
-						 "Failed checksum for");
-				return 0;
-			}
-		break;
-	default:
-		/* No need to checksum. */
-		break;
+	if (!ip_vs_checksum_common_check(af, skb, IPPROTO_TCP, tcphoff)) {
+		IP_VS_DBG_RL_PKT(0, af, pp, skb, 0, "Failed checksum for");
+		return 0;
 	}
-
 	return 1;
 }
 
diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
index f9de632e38cd..d10713ca74f7 100644
--- a/net/netfilter/ipvs/ip_vs_proto_udp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
@@ -306,40 +306,11 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
 	if (uh == NULL)
 		return 0;
 
-	if (uh->check != 0) {
-		switch (skb->ip_summed) {
-		case CHECKSUM_NONE:
-			skb->csum = skb_checksum(skb, udphoff,
-						 skb->len - udphoff, 0);
-			fallthrough;
-		case CHECKSUM_COMPLETE:
-#ifdef CONFIG_IP_VS_IPV6
-			if (af == AF_INET6) {
-				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
-						    &ipv6_hdr(skb)->daddr,
-						    skb->len - udphoff,
-						    IPPROTO_UDP,
-						    skb->csum)) {
-					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
-							 "Failed checksum for");
-					return 0;
-				}
-			} else
-#endif
-				if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
-						      ip_hdr(skb)->daddr,
-						      skb->len - udphoff,
-						      ip_hdr(skb)->protocol,
-						      skb->csum)) {
-					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
-							 "Failed checksum for");
-					return 0;
-				}
-			break;
-		default:
-			/* No need to checksum. */
-			break;
-		}
+	if (!uh->check)
+		return 1;
+	if (!ip_vs_checksum_common_check(af, skb, IPPROTO_UDP, udphoff)) {
+		IP_VS_DBG_RL_PKT(0, af, pp, skb, 0, "Failed checksum for");
+		return 0;
 	}
 	return 1;
 }
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH nf] ipvs: fix the checksum validations
  2026-07-09 20:23 [PATCH nf] ipvs: fix the checksum validations Julian Anastasov
@ 2026-07-09 21:24 ` Florian Westphal
  2026-07-09 21:57   ` Julian Anastasov
  2026-07-11 17:17 ` Julian Anastasov
  1 sibling, 1 reply; 4+ messages in thread
From: Florian Westphal @ 2026-07-09 21:24 UTC (permalink / raw)
  To: Julian Anastasov
  Cc: Simon Horman, Pablo Neira Ayuso, lvs-devel, netfilter-devel

Julian Anastasov <ja@ssi.bg> wrote:
> TCP/UDP checksum validation for CHECKSUM_COMPLETE is broken
> before the git history.
> 
> Expecting skb->csum to cover data starting from the protocol
> header is wrong. As IPVS works at the IP layer, the csum for
> the IP header is not subtracted yet.
> 
> ip_vs_in_icmp_v6() is missing checksum validation for ICMPv6
> packets from clients.
> 
> Also, Sashiko points out that handle_response_icmp() being
> common for IPv4 and IPv6 is missing the pseudo-header
> calculation while validating ICMPv6 messages from real
> servers which is a problem if checksum is not validated
> by the hardware.
> 
> Fix the problems by creating ip_vs_checksum_common_check()
> helper and use it for TCP/UDP/ICMP both for IPv4 and IPv6.
> 
> Also, ip_vs_checksum_complete() can be marked static.

Just FYI, I'll ignore the sashiko comment wrt.
'hardcoded sizeof(struct ipv6hdr)' as thats resolved by your
earlier patch, so I plan to include this in tomorrows batch.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH nf] ipvs: fix the checksum validations
  2026-07-09 21:24 ` Florian Westphal
@ 2026-07-09 21:57   ` Julian Anastasov
  0 siblings, 0 replies; 4+ messages in thread
From: Julian Anastasov @ 2026-07-09 21:57 UTC (permalink / raw)
  To: Florian Westphal
  Cc: Simon Horman, Pablo Neira Ayuso, lvs-devel, netfilter-devel


	Hello,

On Thu, 9 Jul 2026, Florian Westphal wrote:

> Julian Anastasov <ja@ssi.bg> wrote:
> > TCP/UDP checksum validation for CHECKSUM_COMPLETE is broken
> > before the git history.
> > 
> > Expecting skb->csum to cover data starting from the protocol
> > header is wrong. As IPVS works at the IP layer, the csum for
> > the IP header is not subtracted yet.
> > 
> > ip_vs_in_icmp_v6() is missing checksum validation for ICMPv6
> > packets from clients.
> > 
> > Also, Sashiko points out that handle_response_icmp() being
> > common for IPv4 and IPv6 is missing the pseudo-header
> > calculation while validating ICMPv6 messages from real
> > servers which is a problem if checksum is not validated
> > by the hardware.
> > 
> > Fix the problems by creating ip_vs_checksum_common_check()
> > helper and use it for TCP/UDP/ICMP both for IPv4 and IPv6.
> > 
> > Also, ip_vs_checksum_complete() can be marked static.
> 
> Just FYI, I'll ignore the sashiko comment wrt.
> 'hardcoded sizeof(struct ipv6hdr)' as thats resolved by your
> earlier patch, so I plan to include this in tomorrows batch.

	Yep, both patches solve the reported problems there...

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH nf] ipvs: fix the checksum validations
  2026-07-09 20:23 [PATCH nf] ipvs: fix the checksum validations Julian Anastasov
  2026-07-09 21:24 ` Florian Westphal
@ 2026-07-11 17:17 ` Julian Anastasov
  1 sibling, 0 replies; 4+ messages in thread
From: Julian Anastasov @ 2026-07-11 17:17 UTC (permalink / raw)
  To: Simon Horman
  Cc: Pablo Neira Ayuso, Florian Westphal, lvs-devel, netfilter-devel


	Hello,

On Thu, 9 Jul 2026, Julian Anastasov wrote:

> TCP/UDP checksum validation for CHECKSUM_COMPLETE is broken
> before the git history.
> 
> Expecting skb->csum to cover data starting from the protocol
> header is wrong. As IPVS works at the IP layer, the csum for
> the IP header is not subtracted yet.
> 
> ip_vs_in_icmp_v6() is missing checksum validation for ICMPv6
> packets from clients.
> 
> Also, Sashiko points out that handle_response_icmp() being
> common for IPv4 and IPv6 is missing the pseudo-header
> calculation while validating ICMPv6 messages from real
> servers which is a problem if checksum is not validated
> by the hardware.
> 
> Fix the problems by creating ip_vs_checksum_common_check()
> helper and use it for TCP/UDP/ICMP both for IPv4 and IPv6.
> 
> Also, ip_vs_checksum_complete() can be marked static.
> 
> Fixes: 2a3b791e6e11 ("IPVS: Add/adjust Netfilter hook functions and helpers for v6")
> Link: https://sashiko.dev/#/patchset/20260708180315.77413-1-ja%40ssi.bg
> Signed-off-by: Julian Anastasov <ja@ssi.bg>

	This patch needs changes, will send v2.

pw-bot: changes-requested

> ---
>  include/net/ip_vs.h                  |  5 ++-
>  net/netfilter/ipvs/ip_vs_core.c      | 63 ++++++++++++++++++++++++++--
>  net/netfilter/ipvs/ip_vs_proto_tcp.c | 35 ++--------------
>  net/netfilter/ipvs/ip_vs_proto_udp.c | 39 +++--------------
>  4 files changed, 71 insertions(+), 71 deletions(-)
> 
> diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
> index 49297fec448a..fd18b1cd6471 100644
> --- a/include/net/ip_vs.h
> +++ b/include/net/ip_vs.h
> @@ -2065,8 +2065,6 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
>  		       struct ip_vs_conn *cp, int dir);
>  #endif
>  
> -__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset);
> -
>  static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum)
>  {
>  	__be32 diff[2] = { ~old, new };
> @@ -2092,6 +2090,9 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum)
>  	return csum_partial(diff, sizeof(diff), oldsum);
>  }
>  
> +bool ip_vs_checksum_common_check(int af, struct sk_buff *skb, int proto,
> +				 int offset);
> +
>  /* Forget current conntrack (unconfirmed) and attach notrack entry */
>  static inline void ip_vs_notrack(struct sk_buff *skb)
>  {
> diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
> index c9c88c99d07b..ceb1cbf33dd7 100644
> --- a/net/netfilter/ipvs/ip_vs_core.c
> +++ b/net/netfilter/ipvs/ip_vs_core.c
> @@ -867,11 +867,56 @@ static int sysctl_nat_icmp_send(struct netns_ipvs *ipvs) { return 0; }
>  
>  #endif
>  
> -__sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
> +static __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset)
>  {
>  	return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0));
>  }
>  
> +/**
> + * ip_vs_checksum_common_check - validate checksum for TCP/UDP/ICMP
> + * @af: AF_INET/AF_INET6
> + * @skb: socket buffer
> + * @proto: IPPROTO_xxx
> + * @offset: offset of protocol header
> + */
> +bool ip_vs_checksum_common_check(int af, struct sk_buff *skb, int proto,
> +				 int offset)
> +{
> +	__wsum csum;
> +
> +	if (skb_csum_unnecessary(skb))
> +		return true;
> +	if (skb->ip_summed == CHECKSUM_NONE) {
> +		csum = skb_checksum(skb, offset, skb->len - offset, 0);
> +	} else if (skb->ip_summed == CHECKSUM_COMPLETE) {
> +		/* IPVS works at IP layer, so skb->csum covers data from
> +		 * IP header, strip it up to the protocol header
> +		 */
> +		csum = csum_sub(skb->csum, skb_checksum(skb, 0, offset, 0));
> +	} else {
> +		/* No need to checksum. */
> +		return true;
> +	}
> +#ifdef CONFIG_IP_VS_IPV6
> +	if (af == AF_INET6) {
> +		if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
> +				    &ipv6_hdr(skb)->daddr,
> +				    skb->len - offset, proto,
> +				    csum))
> +			return false;
> +	} else
> +#endif
> +		if (proto == IPPROTO_ICMP)
> +			return !csum_fold(csum);
> +		else if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
> +					   ip_hdr(skb)->daddr,
> +					   skb->len - offset, proto,
> +					   csum))
> +			return false;
> +
> +	return true;
> +}
> +
>  static inline enum ip_defrag_users ip_vs_defrag_user(unsigned int hooknum)
>  {
>  	if (NF_INET_LOCAL_IN == hooknum)
> @@ -1039,12 +1084,13 @@ static int handle_response_icmp(int af, struct sk_buff *skb,
>  				unsigned int hooknum)
>  {
>  	unsigned int verdict = NF_DROP;
> +	int iproto = af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP;
>  
>  	if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)
>  		goto after_nat;
>  
>  	/* Ensure the checksum is correct */
> -	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
> +	if (!ip_vs_checksum_common_check(af, skb, iproto, ihl)) {
>  		/* Failed checksum! */
>  		IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n",
>  			      IP_VS_DBG_ADDR(af, snet));
> @@ -1898,7 +1944,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,
>  	verdict = NF_DROP;
>  
>  	/* Ensure the checksum is correct */
> -	if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) {
> +	if (!ip_vs_checksum_common_check(AF_INET, skb, IPPROTO_ICMP, ihl)) {
>  		/* Failed checksum! */
>  		IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!\n",
>  			  &iph->saddr);
> @@ -2064,6 +2110,17 @@ static int ip_vs_in_icmp_v6(struct netns_ipvs *ipvs, struct sk_buff *skb,
>  		goto out;
>  	}
>  
> +	verdict = NF_DROP;
> +
> +	/* Ensure the checksum is correct */
> +	if (!ip_vs_checksum_common_check(AF_INET6, skb, IPPROTO_ICMPV6,
> +					 iph->len)) {
> +		/* Failed checksum! */
> +		IP_VS_DBG(1, "Incoming ICMPv6: failed checksum from %pI6c!\n",
> +			  &iph->saddr);
> +		goto out;
> +	}
> +
>  	/* do the statistics and put it back */
>  	ip_vs_in_stats(cp, skb);
>  
> diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
> index 8cc0a8ce6241..147cf01708ff 100644
> --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
> +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
> @@ -304,39 +304,10 @@ static int
>  tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
>  	       unsigned int tcphoff)
>  {
> -	switch (skb->ip_summed) {
> -	case CHECKSUM_NONE:
> -		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
> -		fallthrough;
> -	case CHECKSUM_COMPLETE:
> -#ifdef CONFIG_IP_VS_IPV6
> -		if (af == AF_INET6) {
> -			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
> -					    &ipv6_hdr(skb)->daddr,
> -					    skb->len - tcphoff,
> -					    IPPROTO_TCP,
> -					    skb->csum)) {
> -				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
> -						 "Failed checksum for");
> -				return 0;
> -			}
> -		} else
> -#endif
> -			if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
> -					      ip_hdr(skb)->daddr,
> -					      skb->len - tcphoff,
> -					      ip_hdr(skb)->protocol,
> -					      skb->csum)) {
> -				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
> -						 "Failed checksum for");
> -				return 0;
> -			}
> -		break;
> -	default:
> -		/* No need to checksum. */
> -		break;
> +	if (!ip_vs_checksum_common_check(af, skb, IPPROTO_TCP, tcphoff)) {
> +		IP_VS_DBG_RL_PKT(0, af, pp, skb, 0, "Failed checksum for");
> +		return 0;
>  	}
> -
>  	return 1;
>  }
>  
> diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
> index f9de632e38cd..d10713ca74f7 100644
> --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
> +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
> @@ -306,40 +306,11 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
>  	if (uh == NULL)
>  		return 0;
>  
> -	if (uh->check != 0) {
> -		switch (skb->ip_summed) {
> -		case CHECKSUM_NONE:
> -			skb->csum = skb_checksum(skb, udphoff,
> -						 skb->len - udphoff, 0);
> -			fallthrough;
> -		case CHECKSUM_COMPLETE:
> -#ifdef CONFIG_IP_VS_IPV6
> -			if (af == AF_INET6) {
> -				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
> -						    &ipv6_hdr(skb)->daddr,
> -						    skb->len - udphoff,
> -						    IPPROTO_UDP,
> -						    skb->csum)) {
> -					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
> -							 "Failed checksum for");
> -					return 0;
> -				}
> -			} else
> -#endif
> -				if (csum_tcpudp_magic(ip_hdr(skb)->saddr,
> -						      ip_hdr(skb)->daddr,
> -						      skb->len - udphoff,
> -						      ip_hdr(skb)->protocol,
> -						      skb->csum)) {
> -					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
> -							 "Failed checksum for");
> -					return 0;
> -				}
> -			break;
> -		default:
> -			/* No need to checksum. */
> -			break;
> -		}
> +	if (!uh->check)
> +		return 1;
> +	if (!ip_vs_checksum_common_check(af, skb, IPPROTO_UDP, udphoff)) {
> +		IP_VS_DBG_RL_PKT(0, af, pp, skb, 0, "Failed checksum for");
> +		return 0;
>  	}
>  	return 1;
>  }
> -- 
> 2.55.0

Regards

--
Julian Anastasov <ja@ssi.bg>


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-07-11 17:17 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-09 20:23 [PATCH nf] ipvs: fix the checksum validations Julian Anastasov
2026-07-09 21:24 ` Florian Westphal
2026-07-09 21:57   ` Julian Anastasov
2026-07-11 17:17 ` Julian Anastasov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.