diff options
Diffstat (limited to 'net/netfilter')
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 20 | ||||
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_sctp.c | 15 | ||||
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_tcp.c | 44 | ||||
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_proto_udp.c | 50 |
4 files changed, 45 insertions, 84 deletions
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index bafab93451d0..c8b512725e6e 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -867,7 +867,7 @@ 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)); } @@ -1038,13 +1038,14 @@ static int handle_response_icmp(int af, struct sk_buff *skb, unsigned int offset, unsigned int ihl, unsigned int hooknum) { + int iproto = af == AF_INET6 ? IPPROTO_ICMPV6 : IPPROTO_ICMP; unsigned int verdict = NF_DROP; 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(skb, ihl, iproto, af)) { /* Failed checksum! */ IP_VS_DBG_BUF(1, "Forward ICMP: failed checksum from %s!\n", IP_VS_DBG_ADDR(af, snet)); @@ -1898,7 +1899,8 @@ 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_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ || tunnel) && + !ip_vs_checksum_common_check(skb, ihl, IPPROTO_ICMP, AF_INET)) { /* Failed checksum! */ IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!\n", &iph->saddr); @@ -2064,6 +2066,18 @@ 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_FWD_METHOD(cp) == IP_VS_CONN_F_MASQ && + !ip_vs_checksum_common_check(skb, iph->len, IPPROTO_ICMPV6, + AF_INET6)) { + /* 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_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index c67317be17df..f6f732b7dfa8 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c @@ -11,7 +11,7 @@ static int sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, - unsigned int sctphoff); + struct ip_vs_iphdr *iph); static int sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb, @@ -109,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, sctphoff)) + if (!sctp_csum_check(cp->af, skb, pp, iph)) return 0; /* Call application helper if needed */ @@ -157,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, sctphoff)) + if (!sctp_csum_check(cp->af, skb, pp, iph)) return 0; /* Call application helper if needed */ @@ -187,19 +187,22 @@ 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, - unsigned int sctphoff) + struct ip_vs_iphdr *iph) { + unsigned int sctphoff = iph->len; struct sctphdr *sh; __le32 cmp, val; + if (!ip_vs_checksum_needed(skb, af)) + return 1; sh = (struct sctphdr *)(skb->data + sctphoff); cmp = sh->checksum; val = sctp_compute_cksum(skb, sctphoff); if (val != cmp) { /* CRC failure, dump it. */ - IP_VS_DBG_RL_PKT(0, af, pp, skb, 0, - "Failed checksum for"); + IP_VS_DBG_RL_PKT(0, af, pp, skb, iph->off, + "Failed checksum for"); return 0; } return 1; diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index f86b763efcc4..533fce3e5e4e 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -29,7 +29,7 @@ static int tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, - unsigned int tcphoff); + struct ip_vs_iphdr *iph); static int tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb, @@ -166,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, tcphoff)) + if (!tcp_csum_check(cp->af, skb, pp, iph)) return 0; /* Call application helper if needed */ @@ -244,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, tcphoff)) + if (!tcp_csum_check(cp->af, skb, pp, iph)) return 0; /* @@ -302,41 +302,13 @@ 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, - unsigned int tcphoff) + struct ip_vs_iphdr *iph) { - 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(skb, iph->len, IPPROTO_TCP, af)) { + IP_VS_DBG_RL_PKT(0, af, pp, skb, iph->off, + "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 58f9e255927e..de3597347542 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -25,7 +25,7 @@ static int udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp, - unsigned int udphoff); + struct ip_vs_iphdr *iph); static int udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb, @@ -155,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, udphoff)) + if (!udp_csum_check(cp->af, skb, pp, iph)) return 0; /* @@ -238,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, udphoff)) + if (!udp_csum_check(cp->af, skb, pp, iph)) return 0; /* @@ -298,48 +298,20 @@ 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, - unsigned int udphoff) + struct ip_vs_iphdr *iph) { struct udphdr _udph, *uh; - uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph); + uh = skb_header_pointer(skb, iph->len, sizeof(_udph), &_udph); 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(skb, iph->len, IPPROTO_UDP, af)) { + IP_VS_DBG_RL_PKT(0, af, pp, skb, iph->off, + "Failed checksum for"); + return 0; } return 1; } |
