Commit eeb4cb952386aac764a5cf4cf2490e50a24a8880
1 parent
1ac0bf9926
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
netfilter: xt_CT: fix assignation of the generic protocol tracker
`iptables -p all' uses 0 to match all protocols, while the conntrack subsystem uses 255. We still need `-p all' to attach the custom timeout policies for the generic protocol tracker. Moreover, we may use `iptables -p sctp' while the SCTP tracker is not loaded. In that case, we have to default on the generic protocol tracker. Another possibility is `iptables -p ip' that should be supported as well. This patch makes sure we validate all possible scenarios. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 1 changed file with 8 additions and 1 deletions Inline Diff
net/netfilter/xt_CT.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2010 Patrick McHardy <kaber@trash.net> | 2 | * Copyright (c) 2010 Patrick McHardy <kaber@trash.net> |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
6 | * published by the Free Software Foundation. | 6 | * published by the Free Software Foundation. |
7 | */ | 7 | */ |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/gfp.h> | 10 | #include <linux/gfp.h> |
11 | #include <linux/skbuff.h> | 11 | #include <linux/skbuff.h> |
12 | #include <linux/netfilter_ipv4/ip_tables.h> | 12 | #include <linux/netfilter_ipv4/ip_tables.h> |
13 | #include <linux/netfilter_ipv6/ip6_tables.h> | 13 | #include <linux/netfilter_ipv6/ip6_tables.h> |
14 | #include <linux/netfilter/x_tables.h> | 14 | #include <linux/netfilter/x_tables.h> |
15 | #include <linux/netfilter/xt_CT.h> | 15 | #include <linux/netfilter/xt_CT.h> |
16 | #include <net/netfilter/nf_conntrack.h> | 16 | #include <net/netfilter/nf_conntrack.h> |
17 | #include <net/netfilter/nf_conntrack_l4proto.h> | ||
17 | #include <net/netfilter/nf_conntrack_helper.h> | 18 | #include <net/netfilter/nf_conntrack_helper.h> |
18 | #include <net/netfilter/nf_conntrack_ecache.h> | 19 | #include <net/netfilter/nf_conntrack_ecache.h> |
19 | #include <net/netfilter/nf_conntrack_l4proto.h> | 20 | #include <net/netfilter/nf_conntrack_l4proto.h> |
20 | #include <net/netfilter/nf_conntrack_timeout.h> | 21 | #include <net/netfilter/nf_conntrack_timeout.h> |
21 | #include <net/netfilter/nf_conntrack_zones.h> | 22 | #include <net/netfilter/nf_conntrack_zones.h> |
22 | 23 | ||
23 | static unsigned int xt_ct_target_v0(struct sk_buff *skb, | 24 | static unsigned int xt_ct_target_v0(struct sk_buff *skb, |
24 | const struct xt_action_param *par) | 25 | const struct xt_action_param *par) |
25 | { | 26 | { |
26 | const struct xt_ct_target_info *info = par->targinfo; | 27 | const struct xt_ct_target_info *info = par->targinfo; |
27 | struct nf_conn *ct = info->ct; | 28 | struct nf_conn *ct = info->ct; |
28 | 29 | ||
29 | /* Previously seen (loopback)? Ignore. */ | 30 | /* Previously seen (loopback)? Ignore. */ |
30 | if (skb->nfct != NULL) | 31 | if (skb->nfct != NULL) |
31 | return XT_CONTINUE; | 32 | return XT_CONTINUE; |
32 | 33 | ||
33 | atomic_inc(&ct->ct_general.use); | 34 | atomic_inc(&ct->ct_general.use); |
34 | skb->nfct = &ct->ct_general; | 35 | skb->nfct = &ct->ct_general; |
35 | skb->nfctinfo = IP_CT_NEW; | 36 | skb->nfctinfo = IP_CT_NEW; |
36 | 37 | ||
37 | return XT_CONTINUE; | 38 | return XT_CONTINUE; |
38 | } | 39 | } |
39 | 40 | ||
40 | static unsigned int xt_ct_target_v1(struct sk_buff *skb, | 41 | static unsigned int xt_ct_target_v1(struct sk_buff *skb, |
41 | const struct xt_action_param *par) | 42 | const struct xt_action_param *par) |
42 | { | 43 | { |
43 | const struct xt_ct_target_info_v1 *info = par->targinfo; | 44 | const struct xt_ct_target_info_v1 *info = par->targinfo; |
44 | struct nf_conn *ct = info->ct; | 45 | struct nf_conn *ct = info->ct; |
45 | 46 | ||
46 | /* Previously seen (loopback)? Ignore. */ | 47 | /* Previously seen (loopback)? Ignore. */ |
47 | if (skb->nfct != NULL) | 48 | if (skb->nfct != NULL) |
48 | return XT_CONTINUE; | 49 | return XT_CONTINUE; |
49 | 50 | ||
50 | atomic_inc(&ct->ct_general.use); | 51 | atomic_inc(&ct->ct_general.use); |
51 | skb->nfct = &ct->ct_general; | 52 | skb->nfct = &ct->ct_general; |
52 | skb->nfctinfo = IP_CT_NEW; | 53 | skb->nfctinfo = IP_CT_NEW; |
53 | 54 | ||
54 | return XT_CONTINUE; | 55 | return XT_CONTINUE; |
55 | } | 56 | } |
56 | 57 | ||
57 | static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) | 58 | static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) |
58 | { | 59 | { |
59 | if (par->family == NFPROTO_IPV4) { | 60 | if (par->family == NFPROTO_IPV4) { |
60 | const struct ipt_entry *e = par->entryinfo; | 61 | const struct ipt_entry *e = par->entryinfo; |
61 | 62 | ||
62 | if (e->ip.invflags & IPT_INV_PROTO) | 63 | if (e->ip.invflags & IPT_INV_PROTO) |
63 | return 0; | 64 | return 0; |
64 | return e->ip.proto; | 65 | return e->ip.proto; |
65 | } else if (par->family == NFPROTO_IPV6) { | 66 | } else if (par->family == NFPROTO_IPV6) { |
66 | const struct ip6t_entry *e = par->entryinfo; | 67 | const struct ip6t_entry *e = par->entryinfo; |
67 | 68 | ||
68 | if (e->ipv6.invflags & IP6T_INV_PROTO) | 69 | if (e->ipv6.invflags & IP6T_INV_PROTO) |
69 | return 0; | 70 | return 0; |
70 | return e->ipv6.proto; | 71 | return e->ipv6.proto; |
71 | } else | 72 | } else |
72 | return 0; | 73 | return 0; |
73 | } | 74 | } |
74 | 75 | ||
75 | static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) | 76 | static int xt_ct_tg_check_v0(const struct xt_tgchk_param *par) |
76 | { | 77 | { |
77 | struct xt_ct_target_info *info = par->targinfo; | 78 | struct xt_ct_target_info *info = par->targinfo; |
78 | struct nf_conntrack_tuple t; | 79 | struct nf_conntrack_tuple t; |
79 | struct nf_conn_help *help; | 80 | struct nf_conn_help *help; |
80 | struct nf_conn *ct; | 81 | struct nf_conn *ct; |
81 | int ret = 0; | 82 | int ret = 0; |
82 | u8 proto; | 83 | u8 proto; |
83 | 84 | ||
84 | if (info->flags & ~XT_CT_NOTRACK) | 85 | if (info->flags & ~XT_CT_NOTRACK) |
85 | return -EINVAL; | 86 | return -EINVAL; |
86 | 87 | ||
87 | if (info->flags & XT_CT_NOTRACK) { | 88 | if (info->flags & XT_CT_NOTRACK) { |
88 | ct = nf_ct_untracked_get(); | 89 | ct = nf_ct_untracked_get(); |
89 | atomic_inc(&ct->ct_general.use); | 90 | atomic_inc(&ct->ct_general.use); |
90 | goto out; | 91 | goto out; |
91 | } | 92 | } |
92 | 93 | ||
93 | #ifndef CONFIG_NF_CONNTRACK_ZONES | 94 | #ifndef CONFIG_NF_CONNTRACK_ZONES |
94 | if (info->zone) | 95 | if (info->zone) |
95 | goto err1; | 96 | goto err1; |
96 | #endif | 97 | #endif |
97 | 98 | ||
98 | ret = nf_ct_l3proto_try_module_get(par->family); | 99 | ret = nf_ct_l3proto_try_module_get(par->family); |
99 | if (ret < 0) | 100 | if (ret < 0) |
100 | goto err1; | 101 | goto err1; |
101 | 102 | ||
102 | memset(&t, 0, sizeof(t)); | 103 | memset(&t, 0, sizeof(t)); |
103 | ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); | 104 | ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); |
104 | ret = PTR_ERR(ct); | 105 | ret = PTR_ERR(ct); |
105 | if (IS_ERR(ct)) | 106 | if (IS_ERR(ct)) |
106 | goto err2; | 107 | goto err2; |
107 | 108 | ||
108 | ret = 0; | 109 | ret = 0; |
109 | if ((info->ct_events || info->exp_events) && | 110 | if ((info->ct_events || info->exp_events) && |
110 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, | 111 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, |
111 | GFP_KERNEL)) | 112 | GFP_KERNEL)) |
112 | goto err3; | 113 | goto err3; |
113 | 114 | ||
114 | if (info->helper[0]) { | 115 | if (info->helper[0]) { |
115 | ret = -ENOENT; | 116 | ret = -ENOENT; |
116 | proto = xt_ct_find_proto(par); | 117 | proto = xt_ct_find_proto(par); |
117 | if (!proto) { | 118 | if (!proto) { |
118 | pr_info("You must specify a L4 protocol, " | 119 | pr_info("You must specify a L4 protocol, " |
119 | "and not use inversions on it.\n"); | 120 | "and not use inversions on it.\n"); |
120 | goto err3; | 121 | goto err3; |
121 | } | 122 | } |
122 | 123 | ||
123 | ret = -ENOMEM; | 124 | ret = -ENOMEM; |
124 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); | 125 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); |
125 | if (help == NULL) | 126 | if (help == NULL) |
126 | goto err3; | 127 | goto err3; |
127 | 128 | ||
128 | ret = -ENOENT; | 129 | ret = -ENOENT; |
129 | help->helper = nf_conntrack_helper_try_module_get(info->helper, | 130 | help->helper = nf_conntrack_helper_try_module_get(info->helper, |
130 | par->family, | 131 | par->family, |
131 | proto); | 132 | proto); |
132 | if (help->helper == NULL) { | 133 | if (help->helper == NULL) { |
133 | pr_info("No such helper \"%s\"\n", info->helper); | 134 | pr_info("No such helper \"%s\"\n", info->helper); |
134 | goto err3; | 135 | goto err3; |
135 | } | 136 | } |
136 | } | 137 | } |
137 | 138 | ||
138 | __set_bit(IPS_TEMPLATE_BIT, &ct->status); | 139 | __set_bit(IPS_TEMPLATE_BIT, &ct->status); |
139 | __set_bit(IPS_CONFIRMED_BIT, &ct->status); | 140 | __set_bit(IPS_CONFIRMED_BIT, &ct->status); |
140 | out: | 141 | out: |
141 | info->ct = ct; | 142 | info->ct = ct; |
142 | return 0; | 143 | return 0; |
143 | 144 | ||
144 | err3: | 145 | err3: |
145 | nf_conntrack_free(ct); | 146 | nf_conntrack_free(ct); |
146 | err2: | 147 | err2: |
147 | nf_ct_l3proto_module_put(par->family); | 148 | nf_ct_l3proto_module_put(par->family); |
148 | err1: | 149 | err1: |
149 | return ret; | 150 | return ret; |
150 | } | 151 | } |
151 | 152 | ||
152 | static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) | 153 | static int xt_ct_tg_check_v1(const struct xt_tgchk_param *par) |
153 | { | 154 | { |
154 | struct xt_ct_target_info_v1 *info = par->targinfo; | 155 | struct xt_ct_target_info_v1 *info = par->targinfo; |
155 | struct nf_conntrack_tuple t; | 156 | struct nf_conntrack_tuple t; |
156 | struct nf_conn_help *help; | 157 | struct nf_conn_help *help; |
157 | struct nf_conn *ct; | 158 | struct nf_conn *ct; |
158 | int ret = 0; | 159 | int ret = 0; |
159 | u8 proto; | 160 | u8 proto; |
160 | 161 | ||
161 | if (info->flags & ~XT_CT_NOTRACK) | 162 | if (info->flags & ~XT_CT_NOTRACK) |
162 | return -EINVAL; | 163 | return -EINVAL; |
163 | 164 | ||
164 | if (info->flags & XT_CT_NOTRACK) { | 165 | if (info->flags & XT_CT_NOTRACK) { |
165 | ct = nf_ct_untracked_get(); | 166 | ct = nf_ct_untracked_get(); |
166 | atomic_inc(&ct->ct_general.use); | 167 | atomic_inc(&ct->ct_general.use); |
167 | goto out; | 168 | goto out; |
168 | } | 169 | } |
169 | 170 | ||
170 | #ifndef CONFIG_NF_CONNTRACK_ZONES | 171 | #ifndef CONFIG_NF_CONNTRACK_ZONES |
171 | if (info->zone) | 172 | if (info->zone) |
172 | goto err1; | 173 | goto err1; |
173 | #endif | 174 | #endif |
174 | 175 | ||
175 | ret = nf_ct_l3proto_try_module_get(par->family); | 176 | ret = nf_ct_l3proto_try_module_get(par->family); |
176 | if (ret < 0) | 177 | if (ret < 0) |
177 | goto err1; | 178 | goto err1; |
178 | 179 | ||
179 | memset(&t, 0, sizeof(t)); | 180 | memset(&t, 0, sizeof(t)); |
180 | ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); | 181 | ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); |
181 | ret = PTR_ERR(ct); | 182 | ret = PTR_ERR(ct); |
182 | if (IS_ERR(ct)) | 183 | if (IS_ERR(ct)) |
183 | goto err2; | 184 | goto err2; |
184 | 185 | ||
185 | ret = 0; | 186 | ret = 0; |
186 | if ((info->ct_events || info->exp_events) && | 187 | if ((info->ct_events || info->exp_events) && |
187 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, | 188 | !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, |
188 | GFP_KERNEL)) | 189 | GFP_KERNEL)) |
189 | goto err3; | 190 | goto err3; |
190 | 191 | ||
191 | if (info->helper[0]) { | 192 | if (info->helper[0]) { |
192 | ret = -ENOENT; | 193 | ret = -ENOENT; |
193 | proto = xt_ct_find_proto(par); | 194 | proto = xt_ct_find_proto(par); |
194 | if (!proto) { | 195 | if (!proto) { |
195 | pr_info("You must specify a L4 protocol, " | 196 | pr_info("You must specify a L4 protocol, " |
196 | "and not use inversions on it.\n"); | 197 | "and not use inversions on it.\n"); |
197 | goto err3; | 198 | goto err3; |
198 | } | 199 | } |
199 | 200 | ||
200 | ret = -ENOMEM; | 201 | ret = -ENOMEM; |
201 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); | 202 | help = nf_ct_helper_ext_add(ct, GFP_KERNEL); |
202 | if (help == NULL) | 203 | if (help == NULL) |
203 | goto err3; | 204 | goto err3; |
204 | 205 | ||
205 | ret = -ENOENT; | 206 | ret = -ENOENT; |
206 | help->helper = nf_conntrack_helper_try_module_get(info->helper, | 207 | help->helper = nf_conntrack_helper_try_module_get(info->helper, |
207 | par->family, | 208 | par->family, |
208 | proto); | 209 | proto); |
209 | if (help->helper == NULL) { | 210 | if (help->helper == NULL) { |
210 | pr_info("No such helper \"%s\"\n", info->helper); | 211 | pr_info("No such helper \"%s\"\n", info->helper); |
211 | goto err3; | 212 | goto err3; |
212 | } | 213 | } |
213 | } | 214 | } |
214 | 215 | ||
215 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 216 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
216 | if (info->timeout) { | 217 | if (info->timeout) { |
217 | typeof(nf_ct_timeout_find_get_hook) timeout_find_get; | 218 | typeof(nf_ct_timeout_find_get_hook) timeout_find_get; |
218 | struct ctnl_timeout *timeout; | 219 | struct ctnl_timeout *timeout; |
219 | struct nf_conn_timeout *timeout_ext; | 220 | struct nf_conn_timeout *timeout_ext; |
220 | 221 | ||
221 | rcu_read_lock(); | 222 | rcu_read_lock(); |
222 | timeout_find_get = | 223 | timeout_find_get = |
223 | rcu_dereference(nf_ct_timeout_find_get_hook); | 224 | rcu_dereference(nf_ct_timeout_find_get_hook); |
224 | 225 | ||
225 | if (timeout_find_get) { | 226 | if (timeout_find_get) { |
226 | const struct ipt_entry *e = par->entryinfo; | 227 | const struct ipt_entry *e = par->entryinfo; |
228 | struct nf_conntrack_l4proto *l4proto; | ||
227 | 229 | ||
228 | if (e->ip.invflags & IPT_INV_PROTO) { | 230 | if (e->ip.invflags & IPT_INV_PROTO) { |
229 | ret = -EINVAL; | 231 | ret = -EINVAL; |
230 | pr_info("You cannot use inversion on " | 232 | pr_info("You cannot use inversion on " |
231 | "L4 protocol\n"); | 233 | "L4 protocol\n"); |
232 | goto err4; | 234 | goto err4; |
233 | } | 235 | } |
234 | timeout = timeout_find_get(info->timeout); | 236 | timeout = timeout_find_get(info->timeout); |
235 | if (timeout == NULL) { | 237 | if (timeout == NULL) { |
236 | ret = -ENOENT; | 238 | ret = -ENOENT; |
237 | pr_info("No such timeout policy \"%s\"\n", | 239 | pr_info("No such timeout policy \"%s\"\n", |
238 | info->timeout); | 240 | info->timeout); |
239 | goto err4; | 241 | goto err4; |
240 | } | 242 | } |
241 | if (timeout->l3num != par->family) { | 243 | if (timeout->l3num != par->family) { |
242 | ret = -EINVAL; | 244 | ret = -EINVAL; |
243 | pr_info("Timeout policy `%s' can only be " | 245 | pr_info("Timeout policy `%s' can only be " |
244 | "used by L3 protocol number %d\n", | 246 | "used by L3 protocol number %d\n", |
245 | info->timeout, timeout->l3num); | 247 | info->timeout, timeout->l3num); |
246 | goto err4; | 248 | goto err4; |
247 | } | 249 | } |
248 | if (timeout->l4proto->l4proto != e->ip.proto) { | 250 | /* Make sure the timeout policy matches any existing |
251 | * protocol tracker, otherwise default to generic. | ||
252 | */ | ||
253 | l4proto = __nf_ct_l4proto_find(par->family, | ||
254 | e->ip.proto); | ||
255 | if (timeout->l4proto->l4proto != l4proto->l4proto) { | ||
249 | ret = -EINVAL; | 256 | ret = -EINVAL; |
250 | pr_info("Timeout policy `%s' can only be " | 257 | pr_info("Timeout policy `%s' can only be " |
251 | "used by L4 protocol number %d\n", | 258 | "used by L4 protocol number %d\n", |
252 | info->timeout, | 259 | info->timeout, |
253 | timeout->l4proto->l4proto); | 260 | timeout->l4proto->l4proto); |
254 | goto err4; | 261 | goto err4; |
255 | } | 262 | } |
256 | timeout_ext = nf_ct_timeout_ext_add(ct, timeout, | 263 | timeout_ext = nf_ct_timeout_ext_add(ct, timeout, |
257 | GFP_KERNEL); | 264 | GFP_KERNEL); |
258 | if (timeout_ext == NULL) { | 265 | if (timeout_ext == NULL) { |
259 | ret = -ENOMEM; | 266 | ret = -ENOMEM; |
260 | goto err4; | 267 | goto err4; |
261 | } | 268 | } |
262 | } else { | 269 | } else { |
263 | ret = -ENOENT; | 270 | ret = -ENOENT; |
264 | pr_info("Timeout policy base is empty\n"); | 271 | pr_info("Timeout policy base is empty\n"); |
265 | goto err4; | 272 | goto err4; |
266 | } | 273 | } |
267 | rcu_read_unlock(); | 274 | rcu_read_unlock(); |
268 | } | 275 | } |
269 | #endif | 276 | #endif |
270 | 277 | ||
271 | __set_bit(IPS_TEMPLATE_BIT, &ct->status); | 278 | __set_bit(IPS_TEMPLATE_BIT, &ct->status); |
272 | __set_bit(IPS_CONFIRMED_BIT, &ct->status); | 279 | __set_bit(IPS_CONFIRMED_BIT, &ct->status); |
273 | out: | 280 | out: |
274 | info->ct = ct; | 281 | info->ct = ct; |
275 | return 0; | 282 | return 0; |
276 | 283 | ||
277 | err4: | 284 | err4: |
278 | rcu_read_unlock(); | 285 | rcu_read_unlock(); |
279 | err3: | 286 | err3: |
280 | nf_conntrack_free(ct); | 287 | nf_conntrack_free(ct); |
281 | err2: | 288 | err2: |
282 | nf_ct_l3proto_module_put(par->family); | 289 | nf_ct_l3proto_module_put(par->family); |
283 | err1: | 290 | err1: |
284 | return ret; | 291 | return ret; |
285 | } | 292 | } |
286 | 293 | ||
287 | static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) | 294 | static void xt_ct_tg_destroy_v0(const struct xt_tgdtor_param *par) |
288 | { | 295 | { |
289 | struct xt_ct_target_info *info = par->targinfo; | 296 | struct xt_ct_target_info *info = par->targinfo; |
290 | struct nf_conn *ct = info->ct; | 297 | struct nf_conn *ct = info->ct; |
291 | struct nf_conn_help *help; | 298 | struct nf_conn_help *help; |
292 | 299 | ||
293 | if (!nf_ct_is_untracked(ct)) { | 300 | if (!nf_ct_is_untracked(ct)) { |
294 | help = nfct_help(ct); | 301 | help = nfct_help(ct); |
295 | if (help) | 302 | if (help) |
296 | module_put(help->helper->me); | 303 | module_put(help->helper->me); |
297 | 304 | ||
298 | nf_ct_l3proto_module_put(par->family); | 305 | nf_ct_l3proto_module_put(par->family); |
299 | } | 306 | } |
300 | nf_ct_put(info->ct); | 307 | nf_ct_put(info->ct); |
301 | } | 308 | } |
302 | 309 | ||
303 | static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) | 310 | static void xt_ct_tg_destroy_v1(const struct xt_tgdtor_param *par) |
304 | { | 311 | { |
305 | struct xt_ct_target_info_v1 *info = par->targinfo; | 312 | struct xt_ct_target_info_v1 *info = par->targinfo; |
306 | struct nf_conn *ct = info->ct; | 313 | struct nf_conn *ct = info->ct; |
307 | struct nf_conn_help *help; | 314 | struct nf_conn_help *help; |
308 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 315 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
309 | struct nf_conn_timeout *timeout_ext; | 316 | struct nf_conn_timeout *timeout_ext; |
310 | typeof(nf_ct_timeout_put_hook) timeout_put; | 317 | typeof(nf_ct_timeout_put_hook) timeout_put; |
311 | #endif | 318 | #endif |
312 | if (!nf_ct_is_untracked(ct)) { | 319 | if (!nf_ct_is_untracked(ct)) { |
313 | help = nfct_help(ct); | 320 | help = nfct_help(ct); |
314 | if (help) | 321 | if (help) |
315 | module_put(help->helper->me); | 322 | module_put(help->helper->me); |
316 | 323 | ||
317 | nf_ct_l3proto_module_put(par->family); | 324 | nf_ct_l3proto_module_put(par->family); |
318 | 325 | ||
319 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 326 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
320 | rcu_read_lock(); | 327 | rcu_read_lock(); |
321 | timeout_put = rcu_dereference(nf_ct_timeout_put_hook); | 328 | timeout_put = rcu_dereference(nf_ct_timeout_put_hook); |
322 | 329 | ||
323 | if (timeout_put) { | 330 | if (timeout_put) { |
324 | timeout_ext = nf_ct_timeout_find(ct); | 331 | timeout_ext = nf_ct_timeout_find(ct); |
325 | if (timeout_ext) | 332 | if (timeout_ext) |
326 | timeout_put(timeout_ext->timeout); | 333 | timeout_put(timeout_ext->timeout); |
327 | } | 334 | } |
328 | rcu_read_unlock(); | 335 | rcu_read_unlock(); |
329 | #endif | 336 | #endif |
330 | } | 337 | } |
331 | nf_ct_put(info->ct); | 338 | nf_ct_put(info->ct); |
332 | } | 339 | } |
333 | 340 | ||
334 | static struct xt_target xt_ct_tg_reg[] __read_mostly = { | 341 | static struct xt_target xt_ct_tg_reg[] __read_mostly = { |
335 | { | 342 | { |
336 | .name = "CT", | 343 | .name = "CT", |
337 | .family = NFPROTO_UNSPEC, | 344 | .family = NFPROTO_UNSPEC, |
338 | .targetsize = sizeof(struct xt_ct_target_info), | 345 | .targetsize = sizeof(struct xt_ct_target_info), |
339 | .checkentry = xt_ct_tg_check_v0, | 346 | .checkentry = xt_ct_tg_check_v0, |
340 | .destroy = xt_ct_tg_destroy_v0, | 347 | .destroy = xt_ct_tg_destroy_v0, |
341 | .target = xt_ct_target_v0, | 348 | .target = xt_ct_target_v0, |
342 | .table = "raw", | 349 | .table = "raw", |
343 | .me = THIS_MODULE, | 350 | .me = THIS_MODULE, |
344 | }, | 351 | }, |
345 | { | 352 | { |
346 | .name = "CT", | 353 | .name = "CT", |
347 | .family = NFPROTO_UNSPEC, | 354 | .family = NFPROTO_UNSPEC, |
348 | .revision = 1, | 355 | .revision = 1, |
349 | .targetsize = sizeof(struct xt_ct_target_info_v1), | 356 | .targetsize = sizeof(struct xt_ct_target_info_v1), |
350 | .checkentry = xt_ct_tg_check_v1, | 357 | .checkentry = xt_ct_tg_check_v1, |
351 | .destroy = xt_ct_tg_destroy_v1, | 358 | .destroy = xt_ct_tg_destroy_v1, |
352 | .target = xt_ct_target_v1, | 359 | .target = xt_ct_target_v1, |
353 | .table = "raw", | 360 | .table = "raw", |
354 | .me = THIS_MODULE, | 361 | .me = THIS_MODULE, |
355 | }, | 362 | }, |
356 | }; | 363 | }; |
357 | 364 | ||
358 | static int __init xt_ct_tg_init(void) | 365 | static int __init xt_ct_tg_init(void) |
359 | { | 366 | { |
360 | return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); | 367 | return xt_register_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); |
361 | } | 368 | } |
362 | 369 | ||
363 | static void __exit xt_ct_tg_exit(void) | 370 | static void __exit xt_ct_tg_exit(void) |
364 | { | 371 | { |
365 | xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); | 372 | xt_unregister_targets(xt_ct_tg_reg, ARRAY_SIZE(xt_ct_tg_reg)); |
366 | } | 373 | } |
367 | 374 | ||
368 | module_init(xt_ct_tg_init); | 375 | module_init(xt_ct_tg_init); |
369 | module_exit(xt_ct_tg_exit); | 376 | module_exit(xt_ct_tg_exit); |
370 | 377 | ||
371 | MODULE_LICENSE("GPL"); | 378 | MODULE_LICENSE("GPL"); |
372 | MODULE_DESCRIPTION("Xtables: connection tracking target"); | 379 | MODULE_DESCRIPTION("Xtables: connection tracking target"); |
373 | MODULE_ALIAS("ipt_CT"); | 380 | MODULE_ALIAS("ipt_CT"); |
374 | MODULE_ALIAS("ip6t_CT"); | 381 | MODULE_ALIAS("ip6t_CT"); |
375 | 382 |