aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-11-06 11:52:20 -0500
committerDavid S. Miller <davem@davemloft.net>2013-11-11 00:19:35 -0500
commit6aafeef03b9d9ecf255f3a80ed85ee070260e1ae (patch)
tree48c7f8ff1709c9874342c02c7039d4431a00b333 /net
parent9037c3579a277f3a23ba476664629fda8c35f7c4 (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>
Diffstat (limited to 'net')
-rw-r--r--net/core/skbuff.c3
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c56
-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
6 files changed, 11 insertions, 137 deletions
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
172static 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
222static unsigned int ipv6_conntrack_in(const struct nf_hook_ops *ops, 172static 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
232static unsigned int ipv6_conntrack_local(const struct nf_hook_ops *ops, 181static 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
247static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { 195static 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
636void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, 636void 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
663static int nf_ct_net_init(struct net *net) 648static 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 */
1762static unsigned int
1763ip_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,
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;