]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.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)
committerFlorian Westphal <fw@strlen.de>
Tue, 17 Feb 2026 14:04:20 +0000 (15:04 +0100)
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>
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 f68a1533ee455eb0261b53628cb467cdf1c420af..8cc0a8ce62411261e5b3e39df764817fb788695c 100644 (file)
@@ -28,7 +28,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,
@@ -165,7 +166,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 */
@@ -243,7 +244,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;
 
                /*
@@ -300,17 +301,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);
@@ -321,7 +314,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 0f0107c80dd235700cd763fbf2f522a8e5859fab..f9de632e38cdd6b93e4baa3817ab566fdbd2df5c 100644 (file)
@@ -24,7 +24,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,
@@ -154,7 +155,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;
 
                /*
@@ -237,7 +238,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;
 
                /*
@@ -296,17 +297,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)
@@ -324,7 +318,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");