diff options
| author | Jiri Pirko <jiri@resnulli.us> | 2013-11-06 11:52:20 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-11-11 00:19:35 -0500 |
| commit | 6aafeef03b9d9ecf255f3a80ed85ee070260e1ae (patch) | |
| tree | 48c7f8ff1709c9874342c02c7039d4431a00b333 | |
| parent | 9037c3579a277f3a23ba476664629fda8c35f7c4 (diff) | |
netfilter: push reasm skb through instead of original frag skbs
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>
| -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 | 4 | ||||
| -rw-r--r-- | net/core/skbuff.c | 3 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 56 | ||||
| -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, 203 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 036ec7d8a83a..215b5ea1cb30 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
| @@ -337,11 +337,6 @@ typedef unsigned int sk_buff_data_t; | |||
| 337 | typedef unsigned char *sk_buff_data_t; | 337 | typedef unsigned char *sk_buff_data_t; |
| 338 | #endif | 338 | #endif |
| 339 | 339 | ||
| 340 | #if defined(CONFIG_NF_DEFRAG_IPV4) || defined(CONFIG_NF_DEFRAG_IPV4_MODULE) || \ | ||
| 341 | defined(CONFIG_NF_DEFRAG_IPV6) || defined(CONFIG_NF_DEFRAG_IPV6_MODULE) | ||
| 342 | #define NET_SKBUFF_NF_DEFRAG_NEEDED 1 | ||
| 343 | #endif | ||
| 344 | |||
| 345 | /** | 340 | /** |
| 346 | * struct sk_buff - socket buffer | 341 | * struct sk_buff - socket buffer |
| 347 | * @next: Next buffer in list | 342 | * @next: Next buffer in list |
| @@ -374,7 +369,6 @@ typedef unsigned char *sk_buff_data_t; | |||
| 374 | * @protocol: Packet protocol from driver | 369 | * @protocol: Packet protocol from driver |
| 375 | * @destructor: Destruct function | 370 | * @destructor: Destruct function |
| 376 | * @nfct: Associated connection, if any | 371 | * @nfct: Associated connection, if any |
| 377 | * @nfct_reasm: netfilter conntrack re-assembly pointer | ||
| 378 | * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c | 372 | * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c |
| 379 | * @skb_iif: ifindex of device we arrived on | 373 | * @skb_iif: ifindex of device we arrived on |
| 380 | * @tc_index: Traffic control index | 374 | * @tc_index: Traffic control index |
| @@ -463,9 +457,6 @@ struct sk_buff { | |||
| 463 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 457 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
| 464 | struct nf_conntrack *nfct; | 458 | struct nf_conntrack *nfct; |
| 465 | #endif | 459 | #endif |
| 466 | #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED | ||
| 467 | struct sk_buff *nfct_reasm; | ||
| 468 | #endif | ||
| 469 | #ifdef CONFIG_BRIDGE_NETFILTER | 460 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 470 | struct nf_bridge_info *nf_bridge; | 461 | struct nf_bridge_info *nf_bridge; |
| 471 | #endif | 462 | #endif |
| @@ -2595,18 +2586,6 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct) | |||
| 2595 | atomic_inc(&nfct->use); | 2586 | atomic_inc(&nfct->use); |
| 2596 | } | 2587 | } |
| 2597 | #endif | 2588 | #endif |
| 2598 | #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED | ||
| 2599 | static inline void nf_conntrack_get_reasm(struct sk_buff *skb) | ||
| 2600 | { | ||
| 2601 | if (skb) | ||
| 2602 | atomic_inc(&skb->users); | ||
| 2603 | } | ||
| 2604 | static inline void nf_conntrack_put_reasm(struct sk_buff *skb) | ||
| 2605 | { | ||
| 2606 | if (skb) | ||
| 2607 | kfree_skb(skb); | ||
| 2608 | } | ||
| 2609 | #endif | ||
| 2610 | #ifdef CONFIG_BRIDGE_NETFILTER | 2589 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 2611 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) | 2590 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) |
| 2612 | { | 2591 | { |
| @@ -2625,10 +2604,6 @@ static inline void nf_reset(struct sk_buff *skb) | |||
| 2625 | nf_conntrack_put(skb->nfct); | 2604 | nf_conntrack_put(skb->nfct); |
| 2626 | skb->nfct = NULL; | 2605 | skb->nfct = NULL; |
| 2627 | #endif | 2606 | #endif |
| 2628 | #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED | ||
| 2629 | nf_conntrack_put_reasm(skb->nfct_reasm); | ||
| 2630 | skb->nfct_reasm = NULL; | ||
| 2631 | #endif | ||
| 2632 | #ifdef CONFIG_BRIDGE_NETFILTER | 2607 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 2633 | nf_bridge_put(skb->nf_bridge); | 2608 | nf_bridge_put(skb->nf_bridge); |
| 2634 | skb->nf_bridge = NULL; | 2609 | skb->nf_bridge = NULL; |
| @@ -2650,10 +2625,6 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src) | |||
| 2650 | nf_conntrack_get(src->nfct); | 2625 | nf_conntrack_get(src->nfct); |
| 2651 | dst->nfctinfo = src->nfctinfo; | 2626 | dst->nfctinfo = src->nfctinfo; |
| 2652 | #endif | 2627 | #endif |
| 2653 | #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED | ||
| 2654 | dst->nfct_reasm = src->nfct_reasm; | ||
| 2655 | nf_conntrack_get_reasm(src->nfct_reasm); | ||
| 2656 | #endif | ||
| 2657 | #ifdef CONFIG_BRIDGE_NETFILTER | 2628 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 2658 | dst->nf_bridge = src->nf_bridge; | 2629 | dst->nf_bridge = src->nf_bridge; |
| 2659 | nf_bridge_get(src->nf_bridge); | 2630 | nf_bridge_get(src->nf_bridge); |
| @@ -2665,9 +2636,6 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src) | |||
| 2665 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 2636 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
| 2666 | nf_conntrack_put(dst->nfct); | 2637 | nf_conntrack_put(dst->nfct); |
| 2667 | #endif | 2638 | #endif |
| 2668 | #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED | ||
| 2669 | nf_conntrack_put_reasm(dst->nfct_reasm); | ||
| 2670 | #endif | ||
| 2671 | #ifdef CONFIG_BRIDGE_NETFILTER | 2639 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 2672 | nf_bridge_put(dst->nf_bridge); | 2640 | nf_bridge_put(dst->nf_bridge); |
| 2673 | #endif | 2641 | #endif |
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index cd7275f9c463..5679d927562b 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 5613412e7dc2..27666d8a0bd0 100644 --- a/include/net/netfilter/ipv6/nf_defrag_ipv6.h +++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h | |||
| @@ -6,9 +6,7 @@ void nf_defrag_ipv6_enable(void); | |||
| 6 | int nf_ct_frag6_init(void); | 6 | int nf_ct_frag6_init(void); |
| 7 | void nf_ct_frag6_cleanup(void); | 7 | void nf_ct_frag6_cleanup(void); |
| 8 | struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); | 8 | struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); |
| 9 | void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | 9 | void nf_ct_frag6_consume_orig(struct sk_buff *skb); |
| 10 | struct net_device *in, struct net_device *out, | ||
| 11 | int (*okfn)(struct sk_buff *)); | ||
| 12 | 10 | ||
| 13 | struct inet_frags_ctl; | 11 | struct inet_frags_ctl; |
| 14 | 12 | ||
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 8c5197fe55a4..8cec1e6b844d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
| @@ -592,9 +592,6 @@ static void skb_release_head_state(struct sk_buff *skb) | |||
| 592 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) | 592 | #if IS_ENABLED(CONFIG_NF_CONNTRACK) |
| 593 | nf_conntrack_put(skb->nfct); | 593 | nf_conntrack_put(skb->nfct); |
| 594 | #endif | 594 | #endif |
| 595 | #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED | ||
| 596 | nf_conntrack_put_reasm(skb->nfct_reasm); | ||
| 597 | #endif | ||
| 598 | #ifdef CONFIG_BRIDGE_NETFILTER | 595 | #ifdef CONFIG_BRIDGE_NETFILTER |
| 599 | nf_bridge_put(skb->nf_bridge); | 596 | nf_bridge_put(skb->nf_bridge); |
| 600 | #endif | 597 | #endif |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 486545eb42ce..4cbc6b290dd5 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
| @@ -169,64 +169,13 @@ out: | |||
| 169 | return nf_conntrack_confirm(skb); | 169 | return nf_conntrack_confirm(skb); |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static unsigned int __ipv6_conntrack_in(struct net *net, | ||
| 173 | unsigned int hooknum, | ||
| 174 | struct sk_buff *skb, | ||
| 175 | const struct net_device *in, | ||
| 176 | const struct net_device *out, | ||
| 177 | int (*okfn)(struct sk_buff *)) | ||
| 178 | { | ||
| 179 | struct sk_buff *reasm = skb->nfct_reasm; | ||
| 180 | const struct nf_conn_help *help; | ||
| 181 | struct nf_conn *ct; | ||
| 182 | enum ip_conntrack_info ctinfo; | ||
| 183 | |||
| 184 | /* This packet is fragmented and has reassembled packet. */ | ||
| 185 | if (reasm) { | ||
| 186 | /* Reassembled packet isn't parsed yet ? */ | ||
| 187 | if (!reasm->nfct) { | ||
| 188 | unsigned int ret; | ||
| 189 | |||
| 190 | ret = nf_conntrack_in(net, PF_INET6, hooknum, reasm); | ||
| 191 | if (ret != NF_ACCEPT) | ||
| 192 | return ret; | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Conntrack helpers need the entire reassembled packet in the | ||
| 196 | * POST_ROUTING hook. In case of unconfirmed connections NAT | ||
| 197 | * might reassign a helper, so the entire packet is also | ||
| 198 | * required. | ||
| 199 | */ | ||
| 200 | ct = nf_ct_get(reasm, &ctinfo); | ||
| 201 | if (ct != NULL && !nf_ct_is_untracked(ct)) { | ||
| 202 | help = nfct_help(ct); | ||
| 203 | if ((help && help->helper) || !nf_ct_is_confirmed(ct)) { | ||
| 204 | nf_conntrack_get_reasm(reasm); | ||
| 205 | NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, reasm, | ||
| 206 | (struct net_device *)in, | ||
| 207 | (struct net_device *)out, | ||
| 208 | okfn, NF_IP6_PRI_CONNTRACK + 1); | ||
| 209 | return NF_DROP_ERR(-ECANCELED); | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | nf_conntrack_get(reasm->nfct); | ||
| 214 | skb->nfct = reasm->nfct; | ||
| 215 | skb->nfctinfo = reasm->nfctinfo; | ||
| 216 | return NF_ACCEPT; | ||
| 217 | } | ||
| 218 | |||
| 219 | return nf_conntrack_in(net, PF_INET6, hooknum, skb); | ||
| 220 | } | ||
| 221 | |||
| 222 | static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops, | 172 | static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops, |
| 223 | struct sk_buff *skb, | 173 | struct sk_buff *skb, |
| 224 | const struct net_device *in, | 174 | const struct net_device *in, |
| 225 | const struct net_device *out, | 175 | const struct net_device *out, |
| 226 | int (*okfn)(struct sk_buff *)) | 176 | int (*okfn)(struct sk_buff *)) |
| 227 | { | 177 | { |
| 228 | return __ipv6_conntrack_in(dev_net(in), ops->hooknum, skb, in, out, | 178 | return nf_conntrack_in(dev_net(in), PF_INET6, ops->hooknum, skb); |
| 229 | okfn); | ||
| 230 | } | 179 | } |
| 231 | 180 | ||
| 232 | static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, | 181 | static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, |
| @@ -240,8 +189,7 @@ static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, | |||
| 240 | net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); | 189 | net_notice_ratelimited("ipv6_conntrack_local: packet too short\n"); |
| 241 | return NF_ACCEPT; | 190 | return NF_ACCEPT; |
| 242 | } | 191 | } |
| 243 | return __ipv6_conntrack_in(dev_net(out), ops->hooknum, skb, in, out, | 192 | return nf_conntrack_in(dev_net(out), PF_INET6, ops->hooknum, skb); |
| 244 | okfn); | ||
| 245 | } | 193 | } |
| 246 | 194 | ||
| 247 | static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { | 195 | 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 4a258263d8ec..767ab8da8218 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |||
| @@ -633,31 +633,16 @@ ret_orig: | |||
| 633 | return skb; | 633 | return skb; |
| 634 | } | 634 | } |
| 635 | 635 | ||
| 636 | void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | 636 | void nf_ct_frag6_consume_orig(struct sk_buff *skb) |
| 637 | struct net_device *in, struct net_device *out, | ||
| 638 | int (*okfn)(struct sk_buff *)) | ||
| 639 | { | 637 | { |
| 640 | struct sk_buff *s, *s2; | 638 | struct sk_buff *s, *s2; |
| 641 | unsigned int ret = 0; | ||
| 642 | 639 | ||
| 643 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { | 640 | for (s = NFCT_FRAG6_CB(skb)->orig; s;) { |
| 644 | nf_conntrack_put_reasm(s->nfct_reasm); | ||
| 645 | nf_conntrack_get_reasm(skb); | ||
| 646 | s->nfct_reasm = skb; | ||
| 647 | |||
| 648 | s2 = s->next; | 641 | s2 = s->next; |
| 649 | s->next = NULL; | 642 | s->next = NULL; |
| 650 | 643 | consume_skb(s); | |
| 651 | if (ret != -ECANCELED) | ||
| 652 | ret = NF_HOOK_THRESH(NFPROTO_IPV6, hooknum, s, | ||
| 653 | in, out, okfn, | ||
| 654 | NF_IP6_PRI_CONNTRACK_DEFRAG + 1); | ||
| 655 | else | ||
| 656 | kfree_skb(s); | ||
| 657 | |||
| 658 | s = s2; | 644 | s = s2; |
| 659 | } | 645 | } |
| 660 | nf_conntrack_put_reasm(skb); | ||
| 661 | } | 646 | } |
| 662 | 647 | ||
| 663 | static int nf_ct_net_init(struct net *net) | 648 | 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 ec483aa3f60f..7b9a748c6bac 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(const struct nf_hook_ops *ops, | |||
| 75 | if (reasm == skb) | 75 | if (reasm == skb) |
| 76 | return NF_ACCEPT; | 76 | return NF_ACCEPT; |
| 77 | 77 | ||
| 78 | nf_ct_frag6_output(ops->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, ops->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 34fda62f40f6..4f26ee46b51f 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
| @@ -1139,12 +1139,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af) | |||
| 1139 | ip_vs_fill_iph_skb(af, skb, &iph); | 1139 | ip_vs_fill_iph_skb(af, skb, &iph); |
| 1140 | #ifdef CONFIG_IP_VS_IPV6 | 1140 | #ifdef CONFIG_IP_VS_IPV6 |
| 1141 | if (af == AF_INET6) { | 1141 | if (af == AF_INET6) { |
| 1142 | if (!iph.fragoffs && skb_nfct_reasm(skb)) { | ||
| 1143 | struct sk_buff *reasm = skb_nfct_reasm(skb); | ||
| 1144 | /* Save fw mark for coming frags */ | ||
| 1145 | reasm->ipvs_property = 1; | ||
| 1146 | reasm->mark = skb->mark; | ||
| 1147 | } | ||
| 1148 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { | 1142 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { |
| 1149 | int related; | 1143 | int related; |
| 1150 | int verdict = ip_vs_out_icmp_v6(skb, &related, | 1144 | int verdict = ip_vs_out_icmp_v6(skb, &related, |
| @@ -1614,12 +1608,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
| 1614 | 1608 | ||
| 1615 | #ifdef CONFIG_IP_VS_IPV6 | 1609 | #ifdef CONFIG_IP_VS_IPV6 |
| 1616 | if (af == AF_INET6) { | 1610 | if (af == AF_INET6) { |
| 1617 | if (!iph.fragoffs && skb_nfct_reasm(skb)) { | ||
| 1618 | struct sk_buff *reasm = skb_nfct_reasm(skb); | ||
| 1619 | /* Save fw mark for coming frags. */ | ||
| 1620 | reasm->ipvs_property = 1; | ||
| 1621 | reasm->mark = skb->mark; | ||
| 1622 | } | ||
| 1623 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { | 1611 | if (unlikely(iph.protocol == IPPROTO_ICMPV6)) { |
| 1624 | int related; | 1612 | int related; |
| 1625 | int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum, | 1613 | int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum, |
| @@ -1671,9 +1659,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) | |||
| 1671 | /* sorry, all this trouble for a no-hit :) */ | 1659 | /* sorry, all this trouble for a no-hit :) */ |
| 1672 | IP_VS_DBG_PKT(12, af, pp, skb, 0, | 1660 | IP_VS_DBG_PKT(12, af, pp, skb, 0, |
| 1673 | "ip_vs_in: packet continues traversal as normal"); | 1661 | "ip_vs_in: packet continues traversal as normal"); |
| 1674 | if (iph.fragoffs && !skb_nfct_reasm(skb)) { | 1662 | if (iph.fragoffs) { |
| 1675 | /* Fragment that couldn't be mapped to a conn entry | 1663 | /* Fragment that couldn't be mapped to a conn entry |
| 1676 | * and don't have any pointer to a reasm skb | ||
| 1677 | * is missing module nf_defrag_ipv6 | 1664 | * is missing module nf_defrag_ipv6 |
| 1678 | */ | 1665 | */ |
| 1679 | IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n"); | 1666 | IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n"); |
| @@ -1756,38 +1743,6 @@ ip_vs_local_request4(const struct nf_hook_ops *ops, struct sk_buff *skb, | |||
| 1756 | #ifdef CONFIG_IP_VS_IPV6 | 1743 | #ifdef CONFIG_IP_VS_IPV6 |
| 1757 | 1744 | ||
| 1758 | /* | 1745 | /* |
| 1759 | * AF_INET6 fragment handling | ||
| 1760 | * Copy info from first fragment, to the rest of them. | ||
| 1761 | */ | ||
| 1762 | static unsigned int | ||
| 1763 | ip_vs_preroute_frag6(const struct nf_hook_ops *ops, struct sk_buff *skb, | ||
| 1764 | const struct net_device *in, | ||
| 1765 | const struct net_device *out, | ||
| 1766 | int (*okfn)(struct sk_buff *)) | ||
| 1767 | { | ||
| 1768 | struct sk_buff *reasm = skb_nfct_reasm(skb); | ||
| 1769 | struct net *net; | ||
| 1770 | |||
| 1771 | /* Skip if not a "replay" from nf_ct_frag6_output or first fragment. | ||
| 1772 | * ipvs_property is set when checking first fragment | ||
| 1773 | * in ip_vs_in() and ip_vs_out(). | ||
| 1774 | */ | ||
| 1775 | if (reasm) | ||
| 1776 | IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property); | ||
| 1777 | if (!reasm || !reasm->ipvs_property) | ||
| 1778 | return NF_ACCEPT; | ||
| 1779 | |||
| 1780 | net = skb_net(skb); | ||
| 1781 | if (!net_ipvs(net)->enable) | ||
| 1782 | return NF_ACCEPT; | ||
| 1783 | |||
| 1784 | /* Copy stored fw mark, saved in ip_vs_{in,out} */ | ||
| 1785 | skb->mark = reasm->mark; | ||
| 1786 | |||
| 1787 | return NF_ACCEPT; | ||
| 1788 | } | ||
| 1789 | |||
| 1790 | /* | ||
| 1791 | * AF_INET6 handler in NF_INET_LOCAL_IN chain | 1746 | * AF_INET6 handler in NF_INET_LOCAL_IN chain |
| 1792 | * Schedule and forward packets from remote clients | 1747 | * Schedule and forward packets from remote clients |
| 1793 | */ | 1748 | */ |
| @@ -1924,14 +1879,6 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = { | |||
| 1924 | .priority = 100, | 1879 | .priority = 100, |
| 1925 | }, | 1880 | }, |
| 1926 | #ifdef CONFIG_IP_VS_IPV6 | 1881 | #ifdef CONFIG_IP_VS_IPV6 |
| 1927 | /* After mangle & nat fetch 2:nd fragment and following */ | ||
| 1928 | { | ||
| 1929 | .hook = ip_vs_preroute_frag6, | ||
| 1930 | .owner = THIS_MODULE, | ||
| 1931 | .pf = NFPROTO_IPV6, | ||
| 1932 | .hooknum = NF_INET_PRE_ROUTING, | ||
| 1933 | .priority = NF_IP6_PRI_NAT_DST + 1, | ||
| 1934 | }, | ||
| 1935 | /* After packet filtering, change source only for VS/NAT */ | 1882 | /* After packet filtering, change source only for VS/NAT */ |
| 1936 | { | 1883 | { |
| 1937 | .hook = ip_vs_reply6, | 1884 | .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; |
