]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ipvs: skip ipv6 extension headers for csum checks
authorJulian Anastasov <ja@ssi.bg>
Sat, 14 Feb 2026 14:58:49 +0000 (16:58 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Jun 2026 11:42:38 +0000 (13:42 +0200)
commit 05cfe9863ef049d98141dc2969eefde72fb07625 upstream.

Protocol checksum validation fails for IPv6 if there are extension
headers before the protocol header. iph->len already contains its
offset, so use it to fix the problem.

Fixes: 2906f66a5682 ("ipvs: SCTP Trasport Loadbalancing Support")
Fixes: 0bbdd42b7efa ("IPVS: Extend protocol DNAT/SNAT and state handlers")
Signed-off-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Nazar Kalashnikov <nazarkalashnikov0@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/netfilter/ipvs/ip_vs_proto_sctp.c
net/netfilter/ipvs/ip_vs_proto_tcp.c
net/netfilter/ipvs/ip_vs_proto_udp.c

index 83e452916403d50549ec08cc2b40bc882dbdf2d4..63c78a1f3918a79690616227c217a4c8edac05f5 100644 (file)
@@ -10,7 +10,8 @@
 #include <net/ip_vs.h>
 
 static int
-sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
+sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+               unsigned int sctphoff);
 
 static int
 sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                int ret;
 
                /* Some checks before mangling */
-               if (!sctp_csum_check(cp->af, skb, pp))
+               if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
                        return 0;
 
                /* Call application helper if needed */
@@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                int ret;
 
                /* Some checks before mangling */
-               if (!sctp_csum_check(cp->af, skb, pp))
+               if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
                        return 0;
 
                /* Call application helper if needed */
@@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 }
 
 static int
-sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+               unsigned int sctphoff)
 {
-       unsigned int sctphoff;
        struct sctphdr *sh;
        __le32 cmp, val;
 
-#ifdef CONFIG_IP_VS_IPV6
-       if (af == AF_INET6)
-               sctphoff = sizeof(struct ipv6hdr);
-       else
-#endif
-               sctphoff = ip_hdrlen(skb);
-
        sh = (struct sctphdr *)(skb->data + sctphoff);
        cmp = sh->checksum;
        val = sctp_compute_cksum(skb, sctphoff);
index 7da51390cea6b8c5ebd9d474823c1b9126432324..ede4fa3b63f52d22a7ac3167edff0c414c64f881 100644 (file)
@@ -29,7 +29,8 @@
 #include <net/ip_vs.h>
 
 static int
-tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
+tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+              unsigned int tcphoff);
 
 static int
 tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -166,7 +167,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                int ret;
 
                /* Some checks before mangling */
-               if (!tcp_csum_check(cp->af, skb, pp))
+               if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
                        return 0;
 
                /* Call application helper if needed */
@@ -244,7 +245,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                int ret;
 
                /* Some checks before mangling */
-               if (!tcp_csum_check(cp->af, skb, pp))
+               if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
                        return 0;
 
                /*
@@ -301,17 +302,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+              unsigned int tcphoff)
 {
-       unsigned int tcphoff;
-
-#ifdef CONFIG_IP_VS_IPV6
-       if (af == AF_INET6)
-               tcphoff = sizeof(struct ipv6hdr);
-       else
-#endif
-               tcphoff = ip_hdrlen(skb);
-
        switch (skb->ip_summed) {
        case CHECKSUM_NONE:
                skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
@@ -322,7 +315,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
                        if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
                                            &ipv6_hdr(skb)->daddr,
                                            skb->len - tcphoff,
-                                           ipv6_hdr(skb)->nexthdr,
+                                           IPPROTO_TCP,
                                            skb->csum)) {
                                IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
                                                 "Failed checksum for");
index 68260d91c98870e74ccae77db3b0f496e3d194d2..ffbebda547fc105897648841ace263182499cc0e 100644 (file)
@@ -25,7 +25,8 @@
 #include <net/ip6_checksum.h>
 
 static int
-udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
+udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+              unsigned int udphoff);
 
 static int
 udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -155,7 +156,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                int ret;
 
                /* Some checks before mangling */
-               if (!udp_csum_check(cp->af, skb, pp))
+               if (!udp_csum_check(cp->af, skb, pp, udphoff))
                        return 0;
 
                /*
@@ -238,7 +239,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
                int ret;
 
                /* Some checks before mangling */
-               if (!udp_csum_check(cp->af, skb, pp))
+               if (!udp_csum_check(cp->af, skb, pp, udphoff))
                        return 0;
 
                /*
@@ -297,17 +298,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+              unsigned int udphoff)
 {
        struct udphdr _udph, *uh;
-       unsigned int udphoff;
-
-#ifdef CONFIG_IP_VS_IPV6
-       if (af == AF_INET6)
-               udphoff = sizeof(struct ipv6hdr);
-       else
-#endif
-               udphoff = ip_hdrlen(skb);
 
        uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
        if (uh == NULL)
@@ -325,7 +319,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
                                if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
                                                    &ipv6_hdr(skb)->daddr,
                                                    skb->len - udphoff,
-                                                   ipv6_hdr(skb)->nexthdr,
+                                                   IPPROTO_UDP,
                                                    skb->csum)) {
                                        IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
                                                         "Failed checksum for");