~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/sched/act_ipt.c

Version: ~ [ linux-6.3-rc3 ] ~ [ linux-6.2.7 ] ~ [ linux-6.1.20 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.103 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.175 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.237 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.278 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.310 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * net/sched/act_ipt.c          iptables target interface
  3  *
  4  *TODO: Add other tables. For now we only support the ipv4 table targets
  5  *
  6  *              This program is free software; you can redistribute it and/or
  7  *              modify it under the terms of the GNU General Public License
  8  *              as published by the Free Software Foundation; either version
  9  *              2 of the License, or (at your option) any later version.
 10  *
 11  * Copyright:   Jamal Hadi Salim (2002-13)
 12  */
 13 
 14 #include <linux/types.h>
 15 #include <linux/kernel.h>
 16 #include <linux/string.h>
 17 #include <linux/errno.h>
 18 #include <linux/skbuff.h>
 19 #include <linux/rtnetlink.h>
 20 #include <linux/module.h>
 21 #include <linux/init.h>
 22 #include <linux/slab.h>
 23 #include <net/netlink.h>
 24 #include <net/pkt_sched.h>
 25 #include <linux/tc_act/tc_ipt.h>
 26 #include <net/tc_act/tc_ipt.h>
 27 
 28 #include <linux/netfilter_ipv4/ip_tables.h>
 29 
 30 
 31 #define IPT_TAB_MASK     15
 32 
 33 static unsigned int ipt_net_id;
 34 static struct tc_action_ops act_ipt_ops;
 35 
 36 static unsigned int xt_net_id;
 37 static struct tc_action_ops act_xt_ops;
 38 
 39 static int ipt_init_target(struct net *net, struct xt_entry_target *t,
 40                            char *table, unsigned int hook)
 41 {
 42         struct xt_tgchk_param par;
 43         struct xt_target *target;
 44         struct ipt_entry e = {};
 45         int ret = 0;
 46 
 47         target = xt_request_find_target(AF_INET, t->u.user.name,
 48                                         t->u.user.revision);
 49         if (IS_ERR(target))
 50                 return PTR_ERR(target);
 51 
 52         t->u.kernel.target = target;
 53         memset(&par, 0, sizeof(par));
 54         par.net       = net;
 55         par.table     = table;
 56         par.entryinfo = &e;
 57         par.target    = target;
 58         par.targinfo  = t->data;
 59         par.hook_mask = hook;
 60         par.family    = NFPROTO_IPV4;
 61 
 62         ret = xt_check_target(&par, t->u.target_size - sizeof(*t), 0, false);
 63         if (ret < 0) {
 64                 module_put(t->u.kernel.target->me);
 65                 return ret;
 66         }
 67         return 0;
 68 }
 69 
 70 static void ipt_destroy_target(struct xt_entry_target *t)
 71 {
 72         struct xt_tgdtor_param par = {
 73                 .target   = t->u.kernel.target,
 74                 .targinfo = t->data,
 75                 .family   = NFPROTO_IPV4,
 76         };
 77         if (par.target->destroy != NULL)
 78                 par.target->destroy(&par);
 79         module_put(par.target->me);
 80 }
 81 
 82 static void tcf_ipt_release(struct tc_action *a, int bind)
 83 {
 84         struct tcf_ipt *ipt = to_ipt(a);
 85         ipt_destroy_target(ipt->tcfi_t);
 86         kfree(ipt->tcfi_tname);
 87         kfree(ipt->tcfi_t);
 88 }
 89 
 90 static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
 91         [TCA_IPT_TABLE] = { .type = NLA_STRING, .len = IFNAMSIZ },
 92         [TCA_IPT_HOOK]  = { .type = NLA_U32 },
 93         [TCA_IPT_INDEX] = { .type = NLA_U32 },
 94         [TCA_IPT_TARG]  = { .len = sizeof(struct xt_entry_target) },
 95 };
 96 
 97 static int __tcf_ipt_init(struct net *net, unsigned int id, struct nlattr *nla,
 98                           struct nlattr *est, struct tc_action **a,
 99                           const struct tc_action_ops *ops, int ovr, int bind)
100 {
101         struct tc_action_net *tn = net_generic(net, id);
102         struct nlattr *tb[TCA_IPT_MAX + 1];
103         struct tcf_ipt *ipt;
104         struct xt_entry_target *td, *t;
105         char *tname;
106         bool exists = false;
107         int ret = 0, err;
108         u32 hook = 0;
109         u32 index = 0;
110 
111         if (nla == NULL)
112                 return -EINVAL;
113 
114         err = nla_parse_nested(tb, TCA_IPT_MAX, nla, ipt_policy, NULL);
115         if (err < 0)
116                 return err;
117 
118         if (tb[TCA_IPT_INDEX] != NULL)
119                 index = nla_get_u32(tb[TCA_IPT_INDEX]);
120 
121         exists = tcf_hash_check(tn, index, a, bind);
122         if (exists && bind)
123                 return 0;
124 
125         if (tb[TCA_IPT_HOOK] == NULL || tb[TCA_IPT_TARG] == NULL) {
126                 if (exists)
127                         tcf_hash_release(*a, bind);
128                 return -EINVAL;
129         }
130 
131         td = (struct xt_entry_target *)nla_data(tb[TCA_IPT_TARG]);
132         if (nla_len(tb[TCA_IPT_TARG]) < td->u.target_size) {
133                 if (exists)
134                         tcf_hash_release(*a, bind);
135                 return -EINVAL;
136         }
137 
138         if (!exists) {
139                 ret = tcf_hash_create(tn, index, est, a, ops, bind,
140                                       false);
141                 if (ret)
142                         return ret;
143                 ret = ACT_P_CREATED;
144         } else {
145                 if (bind)/* dont override defaults */
146                         return 0;
147                 tcf_hash_release(*a, bind);
148 
149                 if (!ovr)
150                         return -EEXIST;
151         }
152         hook = nla_get_u32(tb[TCA_IPT_HOOK]);
153 
154         err = -ENOMEM;
155         tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
156         if (unlikely(!tname))
157                 goto err1;
158         if (tb[TCA_IPT_TABLE] == NULL ||
159             nla_strlcpy(tname, tb[TCA_IPT_TABLE], IFNAMSIZ) >= IFNAMSIZ)
160                 strcpy(tname, "mangle");
161 
162         t = kmemdup(td, td->u.target_size, GFP_KERNEL);
163         if (unlikely(!t))
164                 goto err2;
165 
166         err = ipt_init_target(net, t, tname, hook);
167         if (err < 0)
168                 goto err3;
169 
170         ipt = to_ipt(*a);
171 
172         spin_lock_bh(&ipt->tcf_lock);
173         if (ret != ACT_P_CREATED) {
174                 ipt_destroy_target(ipt->tcfi_t);
175                 kfree(ipt->tcfi_tname);
176                 kfree(ipt->tcfi_t);
177         }
178         ipt->tcfi_tname = tname;
179         ipt->tcfi_t     = t;
180         ipt->tcfi_hook  = hook;
181         spin_unlock_bh(&ipt->tcf_lock);
182         if (ret == ACT_P_CREATED)
183                 tcf_hash_insert(tn, *a);
184         return ret;
185 
186 err3:
187         kfree(t);
188 err2:
189         kfree(tname);
190 err1:
191         if (ret == ACT_P_CREATED)
192                 tcf_hash_cleanup(*a, est);
193         return err;
194 }
195 
196 static int tcf_ipt_init(struct net *net, struct nlattr *nla,
197                         struct nlattr *est, struct tc_action **a, int ovr,
198                         int bind)
199 {
200         return __tcf_ipt_init(net, ipt_net_id, nla, est, a, &act_ipt_ops, ovr,
201                               bind);
202 }
203 
204 static int tcf_xt_init(struct net *net, struct nlattr *nla,
205                        struct nlattr *est, struct tc_action **a, int ovr,
206                        int bind)
207 {
208         return __tcf_ipt_init(net, xt_net_id, nla, est, a, &act_xt_ops, ovr,
209                               bind);
210 }
211 
212 static int tcf_ipt(struct sk_buff *skb, const struct tc_action *a,
213                    struct tcf_result *res)
214 {
215         int ret = 0, result = 0;
216         struct tcf_ipt *ipt = to_ipt(a);
217         struct xt_action_param par;
218         struct nf_hook_state state = {
219                 .net    = dev_net(skb->dev),
220                 .in     = skb->dev,
221                 .hook   = ipt->tcfi_hook,
222                 .pf     = NFPROTO_IPV4,
223         };
224 
225         if (skb_unclone(skb, GFP_ATOMIC))
226                 return TC_ACT_UNSPEC;
227 
228         spin_lock(&ipt->tcf_lock);
229 
230         tcf_lastuse_update(&ipt->tcf_tm);
231         bstats_update(&ipt->tcf_bstats, skb);
232 
233         /* yes, we have to worry about both in and out dev
234          * worry later - danger - this API seems to have changed
235          * from earlier kernels
236          */
237         par.state    = &state;
238         par.target   = ipt->tcfi_t->u.kernel.target;
239         par.targinfo = ipt->tcfi_t->data;
240         ret = par.target->target(skb, &par);
241 
242         switch (ret) {
243         case NF_ACCEPT:
244                 result = TC_ACT_OK;
245                 break;
246         case NF_DROP:
247                 result = TC_ACT_SHOT;
248                 ipt->tcf_qstats.drops++;
249                 break;
250         case XT_CONTINUE:
251                 result = TC_ACT_PIPE;
252                 break;
253         default:
254                 net_notice_ratelimited("tc filter: Bogus netfilter code %d assume ACCEPT\n",
255                                        ret);
256                 result = TC_ACT_OK;
257                 break;
258         }
259         spin_unlock(&ipt->tcf_lock);
260         return result;
261 
262 }
263 
264 static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind,
265                         int ref)
266 {
267         unsigned char *b = skb_tail_pointer(skb);
268         struct tcf_ipt *ipt = to_ipt(a);
269         struct xt_entry_target *t;
270         struct tcf_t tm;
271         struct tc_cnt c;
272 
273         /* for simple targets kernel size == user size
274          * user name = target name
275          * for foolproof you need to not assume this
276          */
277 
278         t = kmemdup(ipt->tcfi_t, ipt->tcfi_t->u.user.target_size, GFP_ATOMIC);
279         if (unlikely(!t))
280                 goto nla_put_failure;
281 
282         c.bindcnt = ipt->tcf_bindcnt - bind;
283         c.refcnt = ipt->tcf_refcnt - ref;
284         strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name);
285 
286         if (nla_put(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t) ||
287             nla_put_u32(skb, TCA_IPT_INDEX, ipt->tcf_index) ||
288             nla_put_u32(skb, TCA_IPT_HOOK, ipt->tcfi_hook) ||
289             nla_put(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c) ||
290             nla_put_string(skb, TCA_IPT_TABLE, ipt->tcfi_tname))
291                 goto nla_put_failure;
292 
293         tcf_tm_dump(&tm, &ipt->tcf_tm);
294         if (nla_put_64bit(skb, TCA_IPT_TM, sizeof(tm), &tm, TCA_IPT_PAD))
295                 goto nla_put_failure;
296 
297         kfree(t);
298         return skb->len;
299 
300 nla_put_failure:
301         nlmsg_trim(skb, b);
302         kfree(t);
303         return -1;
304 }
305 
306 static int tcf_ipt_walker(struct net *net, struct sk_buff *skb,
307                           struct netlink_callback *cb, int type,
308                           const struct tc_action_ops *ops)
309 {
310         struct tc_action_net *tn = net_generic(net, ipt_net_id);
311 
312         return tcf_generic_walker(tn, skb, cb, type, ops);
313 }
314 
315 static int tcf_ipt_search(struct net *net, struct tc_action **a, u32 index)
316 {
317         struct tc_action_net *tn = net_generic(net, ipt_net_id);
318 
319         return tcf_hash_search(tn, a, index);
320 }
321 
322 static struct tc_action_ops act_ipt_ops = {
323         .kind           =       "ipt",
324         .type           =       TCA_ACT_IPT,
325         .owner          =       THIS_MODULE,
326         .act            =       tcf_ipt,
327         .dump           =       tcf_ipt_dump,
328         .cleanup        =       tcf_ipt_release,
329         .init           =       tcf_ipt_init,
330         .walk           =       tcf_ipt_walker,
331         .lookup         =       tcf_ipt_search,
332         .size           =       sizeof(struct tcf_ipt),
333 };
334 
335 static __net_init int ipt_init_net(struct net *net)
336 {
337         struct tc_action_net *tn = net_generic(net, ipt_net_id);
338 
339         return tc_action_net_init(tn, &act_ipt_ops, IPT_TAB_MASK);
340 }
341 
342 static void __net_exit ipt_exit_net(struct net *net)
343 {
344         struct tc_action_net *tn = net_generic(net, ipt_net_id);
345 
346         tc_action_net_exit(tn);
347 }
348 
349 static struct pernet_operations ipt_net_ops = {
350         .init = ipt_init_net,
351         .exit = ipt_exit_net,
352         .id   = &ipt_net_id,
353         .size = sizeof(struct tc_action_net),
354 };
355 
356 static int tcf_xt_walker(struct net *net, struct sk_buff *skb,
357                          struct netlink_callback *cb, int type,
358                          const struct tc_action_ops *ops)
359 {
360         struct tc_action_net *tn = net_generic(net, xt_net_id);
361 
362         return tcf_generic_walker(tn, skb, cb, type, ops);
363 }
364 
365 static int tcf_xt_search(struct net *net, struct tc_action **a, u32 index)
366 {
367         struct tc_action_net *tn = net_generic(net, xt_net_id);
368 
369         return tcf_hash_search(tn, a, index);
370 }
371 
372 static struct tc_action_ops act_xt_ops = {
373         .kind           =       "xt",
374         .type           =       TCA_ACT_XT,
375         .owner          =       THIS_MODULE,
376         .act            =       tcf_ipt,
377         .dump           =       tcf_ipt_dump,
378         .cleanup        =       tcf_ipt_release,
379         .init           =       tcf_xt_init,
380         .walk           =       tcf_xt_walker,
381         .lookup         =       tcf_xt_search,
382         .size           =       sizeof(struct tcf_ipt),
383 };
384 
385 static __net_init int xt_init_net(struct net *net)
386 {
387         struct tc_action_net *tn = net_generic(net, xt_net_id);
388 
389         return tc_action_net_init(tn, &act_xt_ops, IPT_TAB_MASK);
390 }
391 
392 static void __net_exit xt_exit_net(struct net *net)
393 {
394         struct tc_action_net *tn = net_generic(net, xt_net_id);
395 
396         tc_action_net_exit(tn);
397 }
398 
399 static struct pernet_operations xt_net_ops = {
400         .init = xt_init_net,
401         .exit = xt_exit_net,
402         .id   = &xt_net_id,
403         .size = sizeof(struct tc_action_net),
404 };
405 
406 MODULE_AUTHOR("Jamal Hadi Salim(2002-13)");
407 MODULE_DESCRIPTION("Iptables target actions");
408 MODULE_LICENSE("GPL");
409 MODULE_ALIAS("act_xt");
410 
411 static int __init ipt_init_module(void)
412 {
413         int ret1, ret2;
414 
415         ret1 = tcf_register_action(&act_xt_ops, &xt_net_ops);
416         if (ret1 < 0)
417                 pr_err("Failed to load xt action\n");
418 
419         ret2 = tcf_register_action(&act_ipt_ops, &ipt_net_ops);
420         if (ret2 < 0)
421                 pr_err("Failed to load ipt action\n");
422 
423         if (ret1 < 0 && ret2 < 0) {
424                 return ret1;
425         } else
426                 return 0;
427 }
428 
429 static void __exit ipt_cleanup_module(void)
430 {
431         tcf_unregister_action(&act_ipt_ops, &ipt_net_ops);
432         tcf_unregister_action(&act_xt_ops, &xt_net_ops);
433 }
434 
435 module_init(ipt_init_module);
436 module_exit(ipt_cleanup_module);
437 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp