aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/netfilter/ip6t_NPT.c18
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c35
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c2
3 files changed, 33 insertions, 22 deletions
diff --git a/net/ipv6/netfilter/ip6t_NPT.c b/net/ipv6/netfilter/ip6t_NPT.c
index 7302b0b7b642..83acc1405a18 100644
--- a/net/ipv6/netfilter/ip6t_NPT.c
+++ b/net/ipv6/netfilter/ip6t_NPT.c
@@ -9,6 +9,7 @@
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/skbuff.h> 10#include <linux/skbuff.h>
11#include <linux/ipv6.h> 11#include <linux/ipv6.h>
12#include <net/ipv6.h>
12#include <linux/netfilter.h> 13#include <linux/netfilter.h>
13#include <linux/netfilter_ipv6.h> 14#include <linux/netfilter_ipv6.h>
14#include <linux/netfilter_ipv6/ip6t_NPT.h> 15#include <linux/netfilter_ipv6/ip6t_NPT.h>
@@ -18,11 +19,20 @@ static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
18{ 19{
19 struct ip6t_npt_tginfo *npt = par->targinfo; 20 struct ip6t_npt_tginfo *npt = par->targinfo;
20 __wsum src_sum = 0, dst_sum = 0; 21 __wsum src_sum = 0, dst_sum = 0;
22 struct in6_addr pfx;
21 unsigned int i; 23 unsigned int i;
22 24
23 if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64) 25 if (npt->src_pfx_len > 64 || npt->dst_pfx_len > 64)
24 return -EINVAL; 26 return -EINVAL;
25 27
28 /* Ensure that LSB of prefix is zero */
29 ipv6_addr_prefix(&pfx, &npt->src_pfx.in6, npt->src_pfx_len);
30 if (!ipv6_addr_equal(&pfx, &npt->src_pfx.in6))
31 return -EINVAL;
32 ipv6_addr_prefix(&pfx, &npt->dst_pfx.in6, npt->dst_pfx_len);
33 if (!ipv6_addr_equal(&pfx, &npt->dst_pfx.in6))
34 return -EINVAL;
35
26 for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) { 36 for (i = 0; i < ARRAY_SIZE(npt->src_pfx.in6.s6_addr16); i++) {
27 src_sum = csum_add(src_sum, 37 src_sum = csum_add(src_sum,
28 (__force __wsum)npt->src_pfx.in6.s6_addr16[i]); 38 (__force __wsum)npt->src_pfx.in6.s6_addr16[i]);
@@ -30,7 +40,7 @@ static int ip6t_npt_checkentry(const struct xt_tgchk_param *par)
30 (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]); 40 (__force __wsum)npt->dst_pfx.in6.s6_addr16[i]);
31 } 41 }
32 42
33 npt->adjustment = (__force __sum16) csum_sub(src_sum, dst_sum); 43 npt->adjustment = ~csum_fold(csum_sub(src_sum, dst_sum));
34 return 0; 44 return 0;
35} 45}
36 46
@@ -51,7 +61,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
51 61
52 idx = i / 32; 62 idx = i / 32;
53 addr->s6_addr32[idx] &= mask; 63 addr->s6_addr32[idx] &= mask;
54 addr->s6_addr32[idx] |= npt->dst_pfx.in6.s6_addr32[idx]; 64 addr->s6_addr32[idx] |= ~mask & npt->dst_pfx.in6.s6_addr32[idx];
55 } 65 }
56 66
57 if (pfx_len <= 48) 67 if (pfx_len <= 48)
@@ -66,8 +76,8 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
66 return false; 76 return false;
67 } 77 }
68 78
69 sum = (__force __sum16) csum_add((__force __wsum)addr->s6_addr16[idx], 79 sum = ~csum_fold(csum_add(csum_unfold((__force __sum16)addr->s6_addr16[idx]),
70 npt->adjustment); 80 csum_unfold(npt->adjustment)));
71 if (sum == CSUM_MANGLED_0) 81 if (sum == CSUM_MANGLED_0)
72 sum = 0; 82 sum = 0;
73 *(__force __sum16 *)&addr->s6_addr16[idx] = sum; 83 *(__force __sum16 *)&addr->s6_addr16[idx] = sum;
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 746048b13ef3..ae8ec6f27688 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -61,14 +61,27 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
61 return 1; 61 return 1;
62} 62}
63 63
64static void sctp_nat_csum(struct sk_buff *skb, sctp_sctphdr_t *sctph,
65 unsigned int sctphoff)
66{
67 __u32 crc32;
68 struct sk_buff *iter;
69
70 crc32 = sctp_start_cksum((__u8 *)sctph, skb_headlen(skb) - sctphoff);
71 skb_walk_frags(skb, iter)
72 crc32 = sctp_update_cksum((u8 *) iter->data,
73 skb_headlen(iter), crc32);
74 sctph->checksum = sctp_end_cksum(crc32);
75
76 skb->ip_summed = CHECKSUM_UNNECESSARY;
77}
78
64static int 79static int
65sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp, 80sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
66 struct ip_vs_conn *cp, struct ip_vs_iphdr *iph) 81 struct ip_vs_conn *cp, struct ip_vs_iphdr *iph)
67{ 82{
68 sctp_sctphdr_t *sctph; 83 sctp_sctphdr_t *sctph;
69 unsigned int sctphoff = iph->len; 84 unsigned int sctphoff = iph->len;
70 struct sk_buff *iter;
71 __be32 crc32;
72 85
73#ifdef CONFIG_IP_VS_IPV6 86#ifdef CONFIG_IP_VS_IPV6
74 if (cp->af == AF_INET6 && iph->fragoffs) 87 if (cp->af == AF_INET6 && iph->fragoffs)
@@ -92,13 +105,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
92 sctph = (void *) skb_network_header(skb) + sctphoff; 105 sctph = (void *) skb_network_header(skb) + sctphoff;
93 sctph->source = cp->vport; 106 sctph->source = cp->vport;
94 107
95 /* Calculate the checksum */ 108 sctp_nat_csum(skb, sctph, sctphoff);
96 crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
97 skb_walk_frags(skb, iter)
98 crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
99 crc32);
100 crc32 = sctp_end_cksum(crc32);
101 sctph->checksum = crc32;
102 109
103 return 1; 110 return 1;
104} 111}
@@ -109,8 +116,6 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
109{ 116{
110 sctp_sctphdr_t *sctph; 117 sctp_sctphdr_t *sctph;
111 unsigned int sctphoff = iph->len; 118 unsigned int sctphoff = iph->len;
112 struct sk_buff *iter;
113 __be32 crc32;
114 119
115#ifdef CONFIG_IP_VS_IPV6 120#ifdef CONFIG_IP_VS_IPV6
116 if (cp->af == AF_INET6 && iph->fragoffs) 121 if (cp->af == AF_INET6 && iph->fragoffs)
@@ -134,13 +139,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
134 sctph = (void *) skb_network_header(skb) + sctphoff; 139 sctph = (void *) skb_network_header(skb) + sctphoff;
135 sctph->dest = cp->dport; 140 sctph->dest = cp->dport;
136 141
137 /* Calculate the checksum */ 142 sctp_nat_csum(skb, sctph, sctphoff);
138 crc32 = sctp_start_cksum((u8 *) sctph, skb_headlen(skb) - sctphoff);
139 skb_walk_frags(skb, iter)
140 crc32 = sctp_update_cksum((u8 *) iter->data, skb_headlen(iter),
141 crc32);
142 crc32 = sctp_end_cksum(crc32);
143 sctph->checksum = crc32;
144 143
145 return 1; 144 return 1;
146} 145}
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index effa10c9e4e3..44fd10c539ac 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -1795,6 +1795,8 @@ int start_sync_thread(struct net *net, int state, char *mcast_ifn, __u8 syncid)
1795 GFP_KERNEL); 1795 GFP_KERNEL);
1796 if (!tinfo->buf) 1796 if (!tinfo->buf)
1797 goto outtinfo; 1797 goto outtinfo;
1798 } else {
1799 tinfo->buf = NULL;
1798 } 1800 }
1799 tinfo->id = id; 1801 tinfo->id = id;
1800 1802