2 * net/sched/ipt.c iptables target interface
4 *TODO: Add other tables. For now we only support the ipv4 table targets
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.
11 * Copyright: Jamal Hadi Salim (2002-4)
14 #include <asm/uaccess.h>
15 #include <asm/system.h>
16 #include <asm/bitops.h>
17 #include <linux/config.h>
18 #include <linux/types.h>
19 #include <linux/kernel.h>
20 #include <linux/sched.h>
21 #include <linux/string.h>
23 #include <linux/socket.h>
24 #include <linux/sockios.h>
26 #include <linux/errno.h>
27 #include <linux/interrupt.h>
28 #include <linux/netdevice.h>
29 #include <linux/skbuff.h>
30 #include <linux/rtnetlink.h>
31 #include <linux/module.h>
32 #include <linux/init.h>
33 #include <linux/proc_fs.h>
35 #include <net/pkt_sched.h>
36 #include <linux/tc_act/tc_ipt.h>
37 #include <net/tc_act/tc_ipt.h>
39 #include <linux/netfilter_ipv4/ip_tables.h>
41 /* use generic hash table */
42 #define MY_TAB_SIZE 16
43 #define MY_TAB_MASK 15
46 static struct tcf_ipt *tcf_ipt_ht[MY_TAB_SIZE];
47 /* ipt hash table lock */
48 static rwlock_t ipt_lock = RW_LOCK_UNLOCKED;
50 /* ovewrride the defaults */
51 #define tcf_st tcf_ipt
52 #define tcf_t_lock ipt_lock
53 #define tcf_ht tcf_ipt_ht
55 #include <net/pkt_act.h>
58 init_targ(struct tcf_ipt *p)
60 struct ipt_target *target;
62 struct ipt_entry_target *t = p->t;
63 target = __ipt_find_target_lock(t->u.user.name, &ret);
66 printk("init_targ: Failed to find %s\n", t->u.user.name);
70 DPRINTK("init_targ: found %s\n", target->name);
71 /* we really need proper ref counting
72 seems to be only needed for modules?? Talk to laforge */
74 __MOD_INC_USE_COUNT(target->me);
76 t->u.kernel.target = target;
80 if (t->u.kernel.target->checkentry
81 && !t->u.kernel.target->checkentry(p->tname, NULL, t->data,
83 - sizeof (*t), p->hook)) {
84 /* if (t->u.kernel.target->me)
85 __MOD_DEC_USE_COUNT(t->u.kernel.target->me);
87 DPRINTK("ip_tables: check failed for `%s'.\n",
88 t->u.kernel.target->name);
96 tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind)
98 struct ipt_entry_target *t;
100 struct rtattr *tb[TCA_IPT_MAX];
106 if (NULL == a || NULL == rta ||
107 (rtattr_parse(tb, TCA_IPT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) <
113 if (tb[TCA_IPT_INDEX - 1]) {
114 index = *(u32 *) RTA_DATA(tb[TCA_IPT_INDEX - 1]);
115 DPRINTK("ipt index %d\n", index);
118 if (index && (p = tcf_hash_lookup(index)) != NULL) {
119 a->priv = (void *) p;
128 spin_unlock(&p->lock);
132 if (NULL == tb[TCA_IPT_TARG - 1] || NULL == tb[TCA_IPT_HOOK - 1]) {
136 p = kmalloc(sizeof (*p), GFP_KERNEL);
140 memset(p, 0, sizeof (*p));
143 spin_lock_init(&p->lock);
144 p->stats_lock = &p->lock;
149 hook = *(u32 *) RTA_DATA(tb[TCA_IPT_HOOK - 1]);
151 t = (struct ipt_entry_target *) RTA_DATA(tb[TCA_IPT_TARG - 1]);
153 p->t = kmalloc(t->u.target_size, GFP_KERNEL);
156 printk("ipt policy messed up \n");
157 spin_unlock(&p->lock);
164 memcpy(p->t, RTA_DATA(tb[TCA_IPT_TARG - 1]), t->u.target_size);
165 DPRINTK(" target NAME %s size %d data[0] %x data[1] %x\n",
166 t->u.user.name, t->u.target_size, t->data[0], t->data[1]);
168 p->tname = kmalloc(IFNAMSIZ, GFP_KERNEL);
170 if (p->tname == NULL) {
172 printk("ipt policy messed up 2 \n");
173 spin_unlock(&p->lock);
180 int csize = IFNAMSIZ - 1;
182 memset(p->tname, 0, IFNAMSIZ);
183 if (tb[TCA_IPT_TABLE - 1]) {
184 if (strlen((char *) RTA_DATA(tb[TCA_IPT_TABLE - 1])) <
186 csize = strlen(RTA_DATA(tb[TCA_IPT_TABLE - 1]));
187 strncpy(p->tname, RTA_DATA(tb[TCA_IPT_TABLE - 1]),
189 DPRINTK("table name %s\n", p->tname);
191 strncpy(p->tname, "mangle", 1 + strlen("mangle"));
195 if (0 > init_targ(p)) {
197 printk("ipt policy messed up 2 \n");
198 spin_unlock(&p->lock);
208 spin_unlock(&p->lock);
212 p->index = index ? : tcf_hash_new_index();
214 p->tm.lastuse = jiffies;
216 p->tm.expires = jiffies;
218 p->tm.install = jiffies;
219 #ifdef CONFIG_NET_ESTIMATOR
221 gen_new_estimator(&p->bstats, &p->rate_est, p->stats_lock, est);
223 h = tcf_hash(p->index);
224 write_lock_bh(&ipt_lock);
225 p->next = tcf_ipt_ht[h];
227 write_unlock_bh(&ipt_lock);
228 a->priv = (void *) p;
234 tcf_ipt_cleanup(struct tc_action *a, int bind)
239 return tcf_hash_release(p, bind);
244 tcf_ipt(struct sk_buff **pskb, struct tc_action *a)
246 int ret = 0, result = 0;
248 struct sk_buff *skb = *pskb;
252 if (NULL == p || NULL == skb) {
258 p->tm.lastuse = jiffies;
259 p->bstats.bytes += skb->len;
262 if (skb_cloned(skb) ) {
263 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
267 /* yes, we have to worry about both in and out dev
268 worry later - danger - this API seems to have changed
269 from earlier kernels */
271 ret = p->t->u.kernel.target->target(&skb, skb->dev, NULL,
272 p->hook, p->t->data, (void *)NULL);
278 result = TC_ACT_SHOT;
282 result = TC_ACT_PIPE;
286 printk("Bogus netfilter code %d assume ACCEPT\n", ret);
287 result = TC_POLICE_OK;
290 spin_unlock(&p->lock);
296 tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
298 struct ipt_entry_target *t;
301 unsigned char *b = skb->tail;
307 printk("BUG: tcf_ipt_dump called with NULL params\n");
310 /* for simple targets kernel size == user size
311 ** user name = target name
312 ** for foolproof you need to not assume this
315 t = kmalloc(p->t->u.user.target_size, GFP_ATOMIC);
320 c.bindcnt = p->bindcnt - bind;
321 c.refcnt = p->refcnt - ref;
322 memcpy(t, p->t, p->t->u.user.target_size);
323 strcpy(t->u.user.name, p->t->u.kernel.target->name);
325 DPRINTK("\ttcf_ipt_dump tablename %s length %d\n", p->tname,
328 ("\tdump target name %s size %d size user %d data[0] %x data[1] %x\n",
329 p->t->u.kernel.target->name, p->t->u.target_size, p->t->u.user.target_size,
330 p->t->data[0], p->t->data[1]);
331 RTA_PUT(skb, TCA_IPT_TARG, p->t->u.user.target_size, t);
332 RTA_PUT(skb, TCA_IPT_INDEX, 4, &p->index);
333 RTA_PUT(skb, TCA_IPT_HOOK, 4, &p->hook);
334 RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c);
335 RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, p->tname);
336 tm.install = jiffies_to_clock_t(jiffies - p->tm.install);
337 tm.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
338 tm.expires = jiffies_to_clock_t(p->tm.expires);
339 RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm);
343 skb_trim(skb, b - skb->data);
347 static struct tc_action_ops act_ipt_ops = {
351 .capab = TCA_CAP_NONE,
352 .owner = THIS_MODULE,
354 .dump = tcf_ipt_dump,
355 .cleanup = tcf_ipt_cleanup,
356 .lookup = tcf_hash_search,
357 .init = tcf_ipt_init,
358 .walk = tcf_generic_walker
361 MODULE_AUTHOR("Jamal Hadi Salim(2002-4)");
362 MODULE_DESCRIPTION("Iptables target actions");
363 MODULE_LICENSE("GPL");
366 ipt_init_module(void)
368 return tcf_register_action(&act_ipt_ops);
372 ipt_cleanup_module(void)
374 tcf_unregister_action(&act_ipt_ops);
377 module_init(ipt_init_module);
378 module_exit(ipt_cleanup_module);