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>
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 34fda62..4f26ee4 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1139,12 +1139,6 @@
ip_vs_fill_iph_skb(af, skb, &iph);
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
- if (!iph.fragoffs && skb_nfct_reasm(skb)) {
- struct sk_buff *reasm = skb_nfct_reasm(skb);
- /* Save fw mark for coming frags */
- reasm->ipvs_property = 1;
- reasm->mark = skb->mark;
- }
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
int related;
int verdict = ip_vs_out_icmp_v6(skb, &related,
@@ -1614,12 +1608,6 @@
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
- if (!iph.fragoffs && skb_nfct_reasm(skb)) {
- struct sk_buff *reasm = skb_nfct_reasm(skb);
- /* Save fw mark for coming frags. */
- reasm->ipvs_property = 1;
- reasm->mark = skb->mark;
- }
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
int related;
int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum,
@@ -1671,9 +1659,8 @@
/* sorry, all this trouble for a no-hit :) */
IP_VS_DBG_PKT(12, af, pp, skb, 0,
"ip_vs_in: packet continues traversal as normal");
- if (iph.fragoffs && !skb_nfct_reasm(skb)) {
+ if (iph.fragoffs) {
/* Fragment that couldn't be mapped to a conn entry
- * and don't have any pointer to a reasm skb
* is missing module nf_defrag_ipv6
*/
IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n");
@@ -1756,38 +1743,6 @@
#ifdef CONFIG_IP_VS_IPV6
/*
- * AF_INET6 fragment handling
- * Copy info from first fragment, to the rest of them.
- */
-static unsigned int
-ip_vs_preroute_frag6(const struct nf_hook_ops *ops, struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
-{
- struct sk_buff *reasm = skb_nfct_reasm(skb);
- struct net *net;
-
- /* Skip if not a "replay" from nf_ct_frag6_output or first fragment.
- * ipvs_property is set when checking first fragment
- * in ip_vs_in() and ip_vs_out().
- */
- if (reasm)
- IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property);
- if (!reasm || !reasm->ipvs_property)
- return NF_ACCEPT;
-
- net = skb_net(skb);
- if (!net_ipvs(net)->enable)
- return NF_ACCEPT;
-
- /* Copy stored fw mark, saved in ip_vs_{in,out} */
- skb->mark = reasm->mark;
-
- return NF_ACCEPT;
-}
-
-/*
* AF_INET6 handler in NF_INET_LOCAL_IN chain
* Schedule and forward packets from remote clients
*/
@@ -1924,14 +1879,6 @@
.priority = 100,
},
#ifdef CONFIG_IP_VS_IPV6
- /* After mangle & nat fetch 2:nd fragment and following */
- {
- .hook = ip_vs_preroute_frag6,
- .owner = THIS_MODULE,
- .pf = NFPROTO_IPV6,
- .hooknum = NF_INET_PRE_ROUTING,
- .priority = NF_IP6_PRI_NAT_DST + 1,
- },
/* After packet filtering, change source only for VS/NAT */
{
.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 9ef22bd..bed5f70 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
ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
{
- struct sk_buff *reasm = skb_nfct_reasm(skb);
struct ip_vs_iphdr iph;
unsigned int dataoff, datalen, matchoff, matchlen;
const char *dptr;
@@ -79,15 +78,10 @@
/* todo: IPv6 fragments:
* I think this only should be done for the first fragment. /HS
*/
- if (reasm) {
- skb = reasm;
- dataoff = iph.thoff_reasm + sizeof(struct udphdr);
- } else
- dataoff = iph.len + sizeof(struct udphdr);
+ dataoff = iph.len + sizeof(struct udphdr);
if (dataoff >= skb->len)
return -EINVAL;
- /* todo: Check if this will mess-up the reasm skb !!! /HS */
retc = skb_linearize(skb);
if (retc < 0)
return retc;