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 /include/net | |
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>
Diffstat (limited to 'include/net')
-rw-r--r-- | include/net/ip_vs.h | 32 | ||||
-rw-r--r-- | include/net/netfilter/ipv6/nf_defrag_ipv6.h | 5 |
2 files changed, 2 insertions, 35 deletions
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 | ||