]>
Commit | Line | Data |
---|---|---|
80e6ae8f GKH |
1 | From 0b5ccb2ee250136dd7385b1c7da28417d0d4d32d Mon Sep 17 00:00:00 2001 |
2 | From: Patrick McHardy <kaber@trash.net> | |
3 | Date: Tue, 15 Dec 2009 16:59:18 +0100 | |
4 | Subject: ipv6: reassembly: use seperate reassembly queues for conntrack and local delivery | |
5 | ||
6 | From: Patrick McHardy <kaber@trash.net> | |
7 | ||
8 | commit 0b5ccb2ee250136dd7385b1c7da28417d0d4d32d upstream. | |
9 | ||
10 | Currently the same reassembly queue might be used for packets reassembled | |
11 | by conntrack in different positions in the stack (PREROUTING/LOCAL_OUT), | |
12 | as well as local delivery. This can cause "packet jumps" when the fragment | |
13 | completing a reassembled packet is queued from a different position in the | |
14 | stack than the previous ones. | |
15 | ||
16 | Add a "user" identifier to the reassembly queue key to seperate the queues | |
17 | of each caller, similar to what we do for IPv4. | |
18 | ||
19 | Signed-off-by: Patrick McHardy <kaber@trash.net> | |
20 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
21 | ||
22 | --- | |
23 | include/net/ipv6.h | 7 +++++++ | |
24 | include/net/netfilter/ipv6/nf_conntrack_ipv6.h | 2 +- | |
25 | net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 13 +++++++++++-- | |
26 | net/ipv6/netfilter/nf_conntrack_reasm.c | 7 ++++--- | |
27 | net/ipv6/reassembly.c | 5 ++++- | |
28 | 5 files changed, 27 insertions(+), 7 deletions(-) | |
29 | ||
30 | --- a/include/net/ipv6.h | |
31 | +++ b/include/net/ipv6.h | |
32 | @@ -354,8 +354,15 @@ static inline int ipv6_prefix_equal(cons | |
33 | ||
34 | struct inet_frag_queue; | |
35 | ||
36 | +enum ip6_defrag_users { | |
37 | + IP6_DEFRAG_LOCAL_DELIVER, | |
38 | + IP6_DEFRAG_CONNTRACK_IN, | |
39 | + IP6_DEFRAG_CONNTRACK_OUT, | |
40 | +}; | |
41 | + | |
42 | struct ip6_create_arg { | |
43 | __be32 id; | |
44 | + u32 user; | |
45 | struct in6_addr *src; | |
46 | struct in6_addr *dst; | |
47 | }; | |
48 | --- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h | |
49 | +++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h | |
50 | @@ -9,7 +9,7 @@ extern struct nf_conntrack_l4proto nf_co | |
51 | ||
52 | extern int nf_ct_frag6_init(void); | |
53 | extern void nf_ct_frag6_cleanup(void); | |
54 | -extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb); | |
55 | +extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); | |
56 | extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, | |
57 | struct net_device *in, | |
58 | struct net_device *out, | |
59 | --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |
60 | +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |
61 | @@ -187,6 +187,16 @@ out: | |
62 | return nf_conntrack_confirm(skb); | |
63 | } | |
64 | ||
65 | +static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum, | |
66 | + struct sk_buff *skb) | |
67 | +{ | |
68 | + if (hooknum == NF_INET_PRE_ROUTING) | |
69 | + return IP6_DEFRAG_CONNTRACK_IN; | |
70 | + else | |
71 | + return IP6_DEFRAG_CONNTRACK_OUT; | |
72 | + | |
73 | +} | |
74 | + | |
75 | static unsigned int ipv6_defrag(unsigned int hooknum, | |
76 | struct sk_buff *skb, | |
77 | const struct net_device *in, | |
78 | @@ -199,8 +209,7 @@ static unsigned int ipv6_defrag(unsigned | |
79 | if (skb->nfct) | |
80 | return NF_ACCEPT; | |
81 | ||
82 | - reasm = nf_ct_frag6_gather(skb); | |
83 | - | |
84 | + reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb)); | |
85 | /* queued */ | |
86 | if (reasm == NULL) | |
87 | return NF_STOLEN; | |
88 | --- a/net/ipv6/netfilter/nf_conntrack_reasm.c | |
89 | +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c | |
90 | @@ -170,13 +170,14 @@ out: | |
91 | /* Creation primitives. */ | |
92 | ||
93 | static __inline__ struct nf_ct_frag6_queue * | |
94 | -fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst) | |
95 | +fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) | |
96 | { | |
97 | struct inet_frag_queue *q; | |
98 | struct ip6_create_arg arg; | |
99 | unsigned int hash; | |
100 | ||
101 | arg.id = id; | |
102 | + arg.user = user; | |
103 | arg.src = src; | |
104 | arg.dst = dst; | |
105 | ||
106 | @@ -561,7 +562,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 * | |
107 | return 0; | |
108 | } | |
109 | ||
110 | -struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) | |
111 | +struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user) | |
112 | { | |
113 | struct sk_buff *clone; | |
114 | struct net_device *dev = skb->dev; | |
115 | @@ -607,7 +608,7 @@ struct sk_buff *nf_ct_frag6_gather(struc | |
116 | if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh) | |
117 | nf_ct_frag6_evictor(); | |
118 | ||
119 | - fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr); | |
120 | + fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr); | |
121 | if (fq == NULL) { | |
122 | pr_debug("Can't find and can't create new queue\n"); | |
123 | goto ret_orig; | |
124 | --- a/net/ipv6/reassembly.c | |
125 | +++ b/net/ipv6/reassembly.c | |
126 | @@ -72,6 +72,7 @@ struct frag_queue | |
127 | struct inet_frag_queue q; | |
128 | ||
129 | __be32 id; /* fragment id */ | |
130 | + u32 user; | |
131 | struct in6_addr saddr; | |
132 | struct in6_addr daddr; | |
133 | ||
134 | @@ -141,7 +142,7 @@ int ip6_frag_match(struct inet_frag_queu | |
135 | struct ip6_create_arg *arg = a; | |
136 | ||
137 | fq = container_of(q, struct frag_queue, q); | |
138 | - return (fq->id == arg->id && | |
139 | + return (fq->id == arg->id && fq->user == arg->user && | |
140 | ipv6_addr_equal(&fq->saddr, arg->src) && | |
141 | ipv6_addr_equal(&fq->daddr, arg->dst)); | |
142 | } | |
143 | @@ -163,6 +164,7 @@ void ip6_frag_init(struct inet_frag_queu | |
144 | struct ip6_create_arg *arg = a; | |
145 | ||
146 | fq->id = arg->id; | |
147 | + fq->user = arg->user; | |
148 | ipv6_addr_copy(&fq->saddr, arg->src); | |
149 | ipv6_addr_copy(&fq->daddr, arg->dst); | |
150 | } | |
151 | @@ -244,6 +246,7 @@ fq_find(struct net *net, __be32 id, stru | |
152 | unsigned int hash; | |
153 | ||
154 | arg.id = id; | |
155 | + arg.user = IP6_DEFRAG_LOCAL_DELIVER; | |
156 | arg.src = src; | |
157 | arg.dst = dst; | |
158 |