aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-11-06 11:52:20 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-08 10:29:25 -0500
commitfddd8b501c59c87d63a0917c8e9e14bd28e3c724 (patch)
treedd715845dc99cff34e5cc63fd7fc4afdbf5a3850
parent2d9a30962d0310d33372c245a6191499a06409f3 (diff)
netfilter: push reasm skb through instead of original frag skbs
[ Upstream commit 6aafeef03b9d9ecf255f3a80ed85ee070260e1ae ] Pushing original fragments through causes several problems. For example for matching, frags may not be matched correctly. Take following example: <example> On HOSTA do: ip6tables -I INPUT -p icmpv6 -j DROP ip6tables -I INPUT -p icmpv6 -m icmp6 --icmpv6-type 128 -j ACCEPT and on HOSTB you do: ping6 HOSTA -s2000 (MTU is 1500) Incoming echo requests will be filtered out on HOSTA. This issue does not occur with smaller packets than MTU (where fragmentation does not happen) </example> As was discussed previously, the only correct solution seems to be to use reassembled skb instead of separete frags. Doing this has positive side effects in reducing sk_buff by one pointer (nfct_reasm) and also the reams dances in ipvs and conntrack can be removed. Future plan is to remove net/ipv6/netfilter/nf_conntrack_reasm.c entirely and use code in net/ipv6/reassembly.c instead. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Acked-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: Marcelo Ricardo Leitner <mleitner@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/linux/skbuff.h32
-rw-r--r--include/net/ip_vs.h32
-rw-r--r--include/net/netfilter/ipv6/nf_defrag_ipv6.h5
-rw-r--r--net/core/skbuff.c3
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c54
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c19
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c7
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c55
-rw-r--r--net/netfilter/ipvs/ip_vs_pe_sip.c8
9 files changed, 13 insertions, 202 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index eaf602781635..74db47ec09ea 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -331,11 +331,6 @@ typedef unsigned int sk_buff_data_t;
331typedef unsigned char *sk_buff_data_t; 331typedef unsigned char *sk_buff_data_t;
332#endif 332#endif
333 333
334#if defined(CONFIG_NF_DEFRAG_IPV4) || defined(CONFIG_NF_DEFRAG_IPV4_MODULE) || \
335 defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
336#define NET_SKBUFF_NF_DEFRAG_NEEDED 1
337#endif
338
339/** 334/**
340 * struct sk_buff - socket buffer 335 * struct sk_buff - socket buffer
341 * @next: Next buffer in list 336 * @next: Next buffer in list
@@ -368,7 +363,6 @@ typedef unsigned char *sk_buff_data_t;
368 * @protocol: Packet protocol from driver 363 * @protocol: Packet protocol from driver
369 * @destructor: Destruct function 364 * @destructor: Destruct function
370 * @nfct: Associated connection, if any 365 * @nfct: Associated connection, if any
371 * @nfct_reasm: netfilter conntrack re-assembly pointer
372 * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c 366 * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
373 * @skb_iif: ifindex of device we arrived on 367 * @skb_iif: ifindex of device we arrived on
374 * @tc_index: Traffic control index 368 * @tc_index: Traffic control index
@@ -455,9 +449,6 @@ struct sk_buff {
455#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 449#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
456 struct nf_conntrack *nfct; 450 struct nf_conntrack *nfct;
457#endif 451#endif
458#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
459 struct sk_buff *nfct_reasm;
460#endif
461#ifdef CONFIG_BRIDGE_NETFILTER 452#ifdef CONFIG_BRIDGE_NETFILTER
462 struct nf_bridge_info *nf_bridge; 453 struct nf_bridge_info *nf_bridge;
463#endif 454#endif
@@ -2700,18 +2691,6 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
2700 atomic_inc(&nfct->use); 2691 atomic_inc(&nfct->use);
2701} 2692}
2702#endif 2693#endif
2703#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
2704static inline void nf_conntrack_get_reasm(struct sk_buff *skb)
2705{
2706 if (skb)
2707 atomic_inc(&skb->users);
2708}
2709static inline void nf_conntrack_put_reasm(struct sk_buff *skb)
2710{
2711 if (skb)
2712 kfree_skb(skb);
2713}
2714#endif
2715#ifdef CONFIG_BRIDGE_NETFILTER 2694#ifdef CONFIG_BRIDGE_NETFILTER
2716static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) 2695static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
2717{ 2696{
@@ -2730,10 +2709,6 @@ static inline void nf_reset(struct sk_buff *skb)
2730 nf_conntrack_put(skb->nfct); 2709 nf_conntrack_put(skb->nfct);
2731 skb->nfct = NULL; 2710 skb->nfct = NULL;
2732#endif 2711#endif
2733#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
2734 nf_conntrack_put_reasm(skb->nfct_reasm);
2735 skb->nfct_reasm = NULL;
2736#endif
2737#ifdef CONFIG_BRIDGE_NETFILTER 2712#ifdef CONFIG_BRIDGE_NETFILTER
2738 nf_bridge_put(skb->nf_bridge); 2713 nf_bridge_put(skb->nf_bridge);
2739 skb->nf_bridge = NULL; 2714 skb->nf_bridge = NULL;
@@ -2755,10 +2730,6 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
2755 nf_conntrack_get(src->nfct); 2730 nf_conntrack_get(src->nfct);
2756 dst->nfctinfo = src->nfctinfo; 2731 dst->nfctinfo = src->nfctinfo;
2757#endif 2732#endif
2758#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
2759 dst->nfct_reasm = src->nfct_reasm;
2760 nf_conntrack_get_reasm(src->nfct_reasm);
2761#endif
2762#ifdef CONFIG_BRIDGE_NETFILTER 2733#ifdef CONFIG_BRIDGE_NETFILTER
2763 dst->nf_bridge = src->nf_bridge; 2734 dst->nf_bridge = src->nf_bridge;
2764 nf_bridge_get(src->nf_bridge); 2735 nf_bridge_get(src->nf_bridge);
@@ -2770,9 +2741,6 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src)
2770#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) 2741#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
2771 nf_conntrack_put(dst->nfct); 2742 nf_conntrack_put(dst->nfct);
2772#endif 2743#endif
2773#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
2774 nf_conntrack_put_reasm(dst->nfct_reasm);
2775#endif
2776#ifdef CONFIG_BRIDGE_NETFILTER 2744#ifdef CONFIG_BRIDGE_NETFILTER
2777 nf_bridge_put(dst->nf_bridge); 2745 nf_bridge_put(dst->nf_bridge);
2778#endif 2746#endif
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 4c062ccff9aa..f0c13a386bf3 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -109,7 +109,6 @@ extern int ip_vs_conn_tab_size;
109struct ip_vs_iphdr { 109struct ip_vs_iphdr {
110 __u32 len; /* IPv4 simply where L4 starts 110 __u32 len; /* IPv4 simply where L4 starts
111 IPv6 where L4 Transport Header starts */ 111 IPv6 where L4 Transport Header starts */
112 __u32 thoff_reasm; /* Transport Header Offset in nfct_reasm skb */
113 __u16 fragoffs; /* IPv6 fragment offset, 0 if first frag (or not frag)*/ 112 __u16 fragoffs; /* IPv6 fragment offset, 0 if first frag (or not frag)*/
114 __s16 protocol; 113 __s16 protocol;
115 __s32 flags; 114 __s32 flags;
@@ -117,34 +116,12 @@ struct ip_vs_iphdr {
117 union nf_inet_addr daddr; 116 union nf_inet_addr daddr;
118}; 117};
119 118
120/* Dependency to module: nf_defrag_ipv6 */
121#if defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE)
122static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb)
123{
124 return skb->nfct_reasm;
125}
126static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
127 int len, void *buffer,
128 const struct ip_vs_iphdr *ipvsh)
129{
130 if (unlikely(ipvsh->fragoffs && skb_nfct_reasm(skb)))
131 return skb_header_pointer(skb_nfct_reasm(skb),
132 ipvsh->thoff_reasm, len, buffer);
133
134 return skb_header_pointer(skb, offset, len, buffer);
135}
136#else
137static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb)
138{
139 return NULL;
140}
141static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset, 119static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
142 int len, void *buffer, 120 int len, void *buffer,
143 const struct ip_vs_iphdr *ipvsh) 121 const struct ip_vs_iphdr *ipvsh)
144{ 122{
145 return skb_header_pointer(skb, offset, len, buffer); 123 return skb_header_pointer(skb, offset, len, buffer);
146} 124}
147#endif
148 125
149static inline void 126static inline void
150ip_vs_fill_ip4hdr(const void *nh, struct ip_vs_iphdr *iphdr) 127ip_vs_fill_ip4hdr(const void *nh, struct ip_vs_iphdr *iphdr)
@@ -171,19 +148,12 @@ ip_vs_fill_iph_skb(int af, const struct sk_buff *skb, struct ip_vs_iphdr *iphdr)
171 (struct ipv6hdr *)skb_network_header(skb); 148 (struct ipv6hdr *)skb_network_header(skb);
172 iphdr->saddr.in6 = iph->saddr; 149 iphdr->saddr.in6 = iph->saddr;
173 iphdr->daddr.in6 = iph->daddr; 150 iphdr->daddr.in6 = iph->daddr;
174 /* ipv6_find_hdr() updates len, flags, thoff_reasm */ 151 /* ipv6_find_hdr() updates len, flags */
175 iphdr->thoff_reasm = 0;
176 iphdr->len = 0; 152 iphdr->len = 0;
177 iphdr->flags = 0; 153 iphdr->flags = 0;
178 iphdr->protocol = ipv6_find_hdr(skb, &iphdr->len, -1, 154 iphdr->protocol = ipv6_find_hdr(skb, &iphdr->len, -1,
179 &iphdr->fragoffs, 155 &iphdr->fragoffs,
180 &iphdr->flags); 156 &iphdr->flags);
181 /* get proto from re-assembled packet and it's offset */
182 if (skb_nfct_reasm(skb))
183 iphdr->protocol = ipv6_find_hdr(skb_nfct_reasm(skb),
184 &iphdr->thoff_reasm,
185 -1, NULL, NULL);
186
187 } else 157 } else
188#endif 158#endif
189 { 159 {
diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
index fd79c9a1779d..17920d847b40 100644
--- a/include/net/netfilter/ipv6/nf_defrag_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h
@@ -6,10 +6,7 @@ extern void nf_defrag_ipv6_enable(void);
6extern int nf_ct_frag6_init(void); 6extern int nf_ct_frag6_init(void);
7extern void nf_ct_frag6_cleanup(void); 7extern void nf_ct_frag6_cleanup(void);
8extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); 8extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user);
9extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, 9extern void nf_ct_frag6_consume_orig(struct sk_buff *skb);
10 struct net_device *in,
11 struct net_device *out,
12 int (*okfn)(struct sk_buff *));
13 10
14struct inet_frags_ctl; 11struct inet_frags_ctl;
15 12
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 1c1738cc4538..d9e8736bcdc1 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -585,9 +585,6 @@ static void skb_release_head_state(struct sk_buff *skb)
585#if IS_ENABLED(CONFIG_NF_CONNTRACK) 585#if IS_ENABLED(CONFIG_NF_CONNTRACK)
586 nf_conntrack_put(skb->nfct); 586 nf_conntrack_put(skb->nfct);
587#endif 587#endif
588#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
589 nf_conntrack_put_reasm(skb->nfct_reasm);
590#endif
591#ifdef CONFIG_BRIDGE_NETFILTER 588#ifdef CONFIG_BRIDGE_NETFILTER
592 nf_bridge_put(skb->nf_bridge); 589 nf_bridge_put(skb->nf_bridge);
593#endif 590#endif
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index c9b6a6e6a1e8..97cd7507c1a4 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -172,63 +172,13 @@ out:
172 return nf_conntrack_confirm(skb); 172 return nf_conntrack_confirm(skb);
173} 173}
174 174
175static unsigned int __ipv6_conntrack_in(struct net *net,
176 unsigned int hooknum,
177 struct sk_buff *skb,
178 const struct net_device *in,
179 const struct net_device *out,
180 int (*okfn)(struct sk_buff *))
181{
182 struct sk_buff *reasm = skb->nfct_reasm;
183 const struct nf_conn_help *help;
184 struct nf_conn *ct;
185 enum ip_conntrack_info ctinfo;
186
187 /* This packet is fragmented and has reassembled packet. */
188 if (reasm) {
189 /* Reassembled packet isn't parsed yet ? */
190 if (!reasm->nfct) {
191 unsigned int ret;
192
193 ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm);
194 if (ret != NF_ACCEPT)
195 return ret;
196 }
197
198 /* Conntrack helpers need the entire reassembled packet in the
199 * POST_ROUTING hook. In case of unconfirmed connections NAT
200 * might reassign a helper, so the entire packet is also
201 * required.
202 */
203 ct = nf_ct_get(reasm, &ctinfo);
204 if (ct != NULL && !nf_ct_is_untracked(ct)) {
205 help = nfct_help(ct);
206 if ((help && help->helper) || !nf_ct_is_confirmed(ct)) {
207 nf_conntrack_get_reasm(reasm);
208 NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
209 (struct net_device *)in,
210 (struct net_device *)out,
211 okfn, NF_IP6_PRI_CONNTRACK + 1);
212 return NF_DROP_ERR(-ECANCELED);
213 }
214 }
215
216 nf_conntrack_get(reasm->nfct);
217 skb->nfct = reasm->nfct;
218 skb->nfctinfo = reasm->nfctinfo;
219 return NF_ACCEPT;
220 }
221
222 return nf_conntrack_in(net, PF_INET6, hooknum, skb);
223}
224
225static unsigned int ipv6_conntrack_in(unsigned int hooknum, 175static unsigned int ipv6_conntrack_in(unsigned int hooknum,
226 struct sk_buff *skb, 176 struct sk_buff *skb,
227 const struct net_device *in, 177 const struct net_device *in,
228 const struct net_device *out, 178 const struct net_device *out,
229 int (*okfn)(struct sk_buff *)) 179 int (*okfn)(struct sk_buff *))
230{ 180{
231 return __ipv6_conntrack_in(dev_net(in), hooknum, skb, in, out, okfn); 181 return nf_conntrack_in(dev_net(in), PF_INET6, hooknum, skb);
232} 182}
233 183
234static unsigned int ipv6_conntrack_local(unsigned int hooknum, 184static unsigned int ipv6_conntrack_local(unsigned int hooknum,
@@ -242,7 +192,7 @@ static unsigned int ipv6_conntrack_local(unsigned int hooknum,
242 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); 192 net_notice_ratelimited("ipv6_conntrack_local: packet too short\n");
243 return NF_ACCEPT; 193 return NF_ACCEPT;
244 } 194 }
245 return __ipv6_conntrack_in(dev_net(out), hooknum, skb, in, out, okfn); 195 return nf_conntrack_in(dev_net(out), PF_INET6, hooknum, skb);
246} 196}
247 197
248static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { 198static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = {
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index dffdc1a389c5..253566a8d55b 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -621,31 +621,16 @@ ret_orig:
621 return skb; 621 return skb;
622} 622}
623 623
624void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, 624void nf_ct_frag6_consume_orig(struct sk_buff *skb)
625 struct net_device *in, struct net_device *out,
626 int (*okfn)(struct sk_buff *))
627{ 625{
628 struct sk_buff *s, *s2; 626 struct sk_buff *s, *s2;
629 unsigned int ret = 0;
630 627
631 for (s = NFCT_FRAG6_CB(skb)->orig; s;) { 628 for (s = NFCT_FRAG6_CB(skb)->orig; s;) {
632 nf_conntrack_put_reasm(s->nfct_reasm);
633 nf_conntrack_get_reasm(skb);
634 s->nfct_reasm = skb;
635
636 s2 = s->next; 629 s2 = s->next;
637 s->next = NULL; 630 s->next = NULL;
638 631 consume_skb(s);
639 if (ret != -ECANCELED)
640 ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s,
641 in, out, okfn,
642 NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
643 else
644 kfree_skb(s);
645
646 s = s2; 632 s = s2;
647 } 633 }
648 nf_conntrack_put_reasm(skb);
649} 634}
650 635
651static int nf_ct_net_init(struct net *net) 636static int nf_ct_net_init(struct net *net)
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index aacd121fe8c5..581dd9ede0de 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -75,8 +75,11 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
75 if (reasm == skb) 75 if (reasm == skb)
76 return NF_ACCEPT; 76 return NF_ACCEPT;
77 77
78 nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, 78 nf_ct_frag6_consume_orig(reasm);
79 (struct net_device *)out, okfn); 79
80 NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm,
81 (struct net_device *) in, (struct net_device *) out,
82 okfn, NF_IP6_PRI_CONNTRACK_DEFRAG + 1);
80 83
81 return NF_STOLEN; 84 return NF_STOLEN;
82} 85}
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 23b8eb53a569..21a3a475d7cd 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1131,12 +1131,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
1131 ip_vs_fill_iph_skb(af, skb, &iph); 1131 ip_vs_fill_iph_skb(af, skb, &iph);
1132#ifdef CONFIG_IP_VS_IPV6 1132#ifdef CONFIG_IP_VS_IPV6
1133 if (af == AF_INET6) { 1133 if (af == AF_INET6) {
1134 if (!iph.fragoffs && skb_nfct_reasm(skb)) {
1135 struct sk_buff *reasm = skb_nfct_reasm(skb);
1136 /* Save fw mark for coming frags */
1137 reasm->ipvs_property = 1;
1138 reasm->mark = skb->mark;
1139 }
1140 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { 1134 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
1141 int related; 1135 int related;
1142 int verdict = ip_vs_out_icmp_v6(skb, &related, 1136 int verdict = ip_vs_out_icmp_v6(skb, &related,
@@ -1606,12 +1600,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1606 1600
1607#ifdef CONFIG_IP_VS_IPV6 1601#ifdef CONFIG_IP_VS_IPV6
1608 if (af == AF_INET6) { 1602 if (af == AF_INET6) {
1609 if (!iph.fragoffs && skb_nfct_reasm(skb)) {
1610 struct sk_buff *reasm = skb_nfct_reasm(skb);
1611 /* Save fw mark for coming frags. */
1612 reasm->ipvs_property = 1;
1613 reasm->mark = skb->mark;
1614 }
1615 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { 1603 if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
1616 int related; 1604 int related;
1617 int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum, 1605 int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum,
@@ -1663,9 +1651,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
1663 /* sorry, all this trouble for a no-hit :) */ 1651 /* sorry, all this trouble for a no-hit :) */
1664 IP_VS_DBG_PKT(12, af, pp, skb, 0, 1652 IP_VS_DBG_PKT(12, af, pp, skb, 0,
1665 "ip_vs_in: packet continues traversal as normal"); 1653 "ip_vs_in: packet continues traversal as normal");
1666 if (iph.fragoffs && !skb_nfct_reasm(skb)) { 1654 if (iph.fragoffs) {
1667 /* Fragment that couldn't be mapped to a conn entry 1655 /* Fragment that couldn't be mapped to a conn entry
1668 * and don't have any pointer to a reasm skb
1669 * is missing module nf_defrag_ipv6 1656 * is missing module nf_defrag_ipv6
1670 */ 1657 */
1671 IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n"); 1658 IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n");
@@ -1748,38 +1735,6 @@ ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
1748#ifdef CONFIG_IP_VS_IPV6 1735#ifdef CONFIG_IP_VS_IPV6
1749 1736
1750/* 1737/*
1751 * AF_INET6 fragment handling
1752 * Copy info from first fragment, to the rest of them.
1753 */
1754static unsigned int
1755ip_vs_preroute_frag6(unsigned int hooknum, struct sk_buff *skb,
1756 const struct net_device *in,
1757 const struct net_device *out,
1758 int (*okfn)(struct sk_buff *))
1759{
1760 struct sk_buff *reasm = skb_nfct_reasm(skb);
1761 struct net *net;
1762
1763 /* Skip if not a "replay" from nf_ct_frag6_output or first fragment.
1764 * ipvs_property is set when checking first fragment
1765 * in ip_vs_in() and ip_vs_out().
1766 */
1767 if (reasm)
1768 IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property);
1769 if (!reasm || !reasm->ipvs_property)
1770 return NF_ACCEPT;
1771
1772 net = skb_net(skb);
1773 if (!net_ipvs(net)->enable)
1774 return NF_ACCEPT;
1775
1776 /* Copy stored fw mark, saved in ip_vs_{in,out} */
1777 skb->mark = reasm->mark;
1778
1779 return NF_ACCEPT;
1780}
1781
1782/*
1783 * AF_INET6 handler in NF_INET_LOCAL_IN chain 1738 * AF_INET6 handler in NF_INET_LOCAL_IN chain
1784 * Schedule and forward packets from remote clients 1739 * Schedule and forward packets from remote clients
1785 */ 1740 */
@@ -1916,14 +1871,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
1916 .priority = 100, 1871 .priority = 100,
1917 }, 1872 },
1918#ifdef CONFIG_IP_VS_IPV6 1873#ifdef CONFIG_IP_VS_IPV6
1919 /* After mangle & nat fetch 2:nd fragment and following */
1920 {
1921 .hook = ip_vs_preroute_frag6,
1922 .owner = THIS_MODULE,
1923 .pf = NFPROTO_IPV6,
1924 .hooknum = NF_INET_PRE_ROUTING,
1925 .priority = NF_IP6_PRI_NAT_DST + 1,
1926 },
1927 /* After packet filtering, change source only for VS/NAT */ 1874 /* After packet filtering, change source only for VS/NAT */
1928 { 1875 {
1929 .hook = ip_vs_reply6, 1876 .hook = ip_vs_reply6,
diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c
index 9ef22bdce9f1..bed5f7042529 100644
--- a/net/netfilter/ipvs/ip_vs_pe_sip.c
+++ b/net/netfilter/ipvs/ip_vs_pe_sip.c
@@ -65,7 +65,6 @@ static int get_callid(const char *dptr, unsigned int dataoff,
65static int 65static int
66ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) 66ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
67{ 67{
68 struct sk_buff *reasm = skb_nfct_reasm(skb);
69 struct ip_vs_iphdr iph; 68 struct ip_vs_iphdr iph;
70 unsigned int dataoff, datalen, matchoff, matchlen; 69 unsigned int dataoff, datalen, matchoff, matchlen;
71 const char *dptr; 70 const char *dptr;
@@ -79,15 +78,10 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
79 /* todo: IPv6 fragments: 78 /* todo: IPv6 fragments:
80 * I think this only should be done for the first fragment. /HS 79 * I think this only should be done for the first fragment. /HS
81 */ 80 */
82 if (reasm) { 81 dataoff = iph.len + sizeof(struct udphdr);
83 skb = reasm;
84 dataoff = iph.thoff_reasm + sizeof(struct udphdr);
85 } else
86 dataoff = iph.len + sizeof(struct udphdr);
87 82
88 if (dataoff >= skb->len) 83 if (dataoff >= skb->len)
89 return -EINVAL; 84 return -EINVAL;
90 /* todo: Check if this will mess-up the reasm skb !!! /HS */
91 retc = skb_linearize(skb); 85 retc = skb_linearize(skb);
92 if (retc < 0) 86 if (retc < 0)
93 return retc; 87 return retc;