diff options
author | Jiri Pirko <jiri@resnulli.us> | 2013-11-06 11:52:20 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-12-08 10:29:25 -0500 |
commit | fddd8b501c59c87d63a0917c8e9e14bd28e3c724 (patch) | |
tree | dd715845dc99cff34e5cc63fd7fc4afdbf5a3850 | |
parent | 2d9a30962d0310d33372c245a6191499a06409f3 (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.h | 32 | ||||
-rw-r--r-- | include/net/ip_vs.h | 32 | ||||
-rw-r--r-- | include/net/netfilter/ipv6/nf_defrag_ipv6.h | 5 | ||||
-rw-r--r-- | net/core/skbuff.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 54 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_conntrack_reasm.c | 19 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_defrag_ipv6_hooks.c | 7 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_core.c | 55 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_pe_sip.c | 8 |
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; | |||
331 | typedef unsigned char *sk_buff_data_t; | 331 | typedef 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 | ||
2704 | static inline void nf_conntrack_get_reasm(struct sk_buff *skb) | ||
2705 | { | ||
2706 | if (skb) | ||
2707 | atomic_inc(&skb->users); | ||
2708 | } | ||
2709 | static 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 |
2716 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) | 2695 | static 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; | |||
109 | struct ip_vs_iphdr { | 109 | struct 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) | ||
122 | static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb) | ||
123 | { | ||
124 | return skb->nfct_reasm; | ||
125 | } | ||
126 | static 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 | ||
137 | static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb) | ||
138 | { | ||
139 | return NULL; | ||
140 | } | ||
141 | static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset, | 119 | static 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 | ||
149 | static inline void | 126 | static inline void |
150 | ip_vs_fill_ip4hdr(const void *nh, struct ip_vs_iphdr *iphdr) | 127 | ip_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); | |||
6 | extern int nf_ct_frag6_init(void); | 6 | extern int nf_ct_frag6_init(void); |
7 | extern void nf_ct_frag6_cleanup(void); | 7 | extern void nf_ct_frag6_cleanup(void); |
8 | extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); | 8 | extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); |
9 | extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | 9 | extern 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 | ||
14 | struct inet_frags_ctl; | 11 | struct 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 | ||
175 | static 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 | |||
225 | static unsigned int ipv6_conntrack_in(unsigned int hooknum, | 175 | static 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 | ||
234 | static unsigned int ipv6_conntrack_local(unsigned int hooknum, | 184 | static 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 | ||
248 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | 198 | static 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 | ||
624 | void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | 624 | void 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 | ||
651 | static int nf_ct_net_init(struct net *net) | 636 | static 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 | */ | ||
1754 | static unsigned int | ||
1755 | ip_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, | |||
65 | static int | 65 | static int |
66 | ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb) | 66 | ip_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; |