xref: /openbmc/linux/net/netfilter/xt_NFQUEUE.c (revision b7019ac5)
1 /* iptables module for using new netfilter netlink queue
2  *
3  * (C) 2005 by Harald Welte <laforge@netfilter.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  */
10 
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 
16 #include <linux/netfilter.h>
17 #include <linux/netfilter_arp.h>
18 #include <linux/netfilter/x_tables.h>
19 #include <linux/netfilter/xt_NFQUEUE.h>
20 
21 #include <net/netfilter/nf_queue.h>
22 
23 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
24 MODULE_DESCRIPTION("Xtables: packet forwarding to netlink");
25 MODULE_LICENSE("GPL");
26 MODULE_ALIAS("ipt_NFQUEUE");
27 MODULE_ALIAS("ip6t_NFQUEUE");
28 MODULE_ALIAS("arpt_NFQUEUE");
29 
30 static u32 jhash_initval __read_mostly;
31 
32 static unsigned int
33 nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par)
34 {
35 	const struct xt_NFQ_info *tinfo = par->targinfo;
36 
37 	return NF_QUEUE_NR(tinfo->queuenum);
38 }
39 
40 static unsigned int
41 nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
42 {
43 	const struct xt_NFQ_info_v1 *info = par->targinfo;
44 	u32 queue = info->queuenum;
45 
46 	if (info->queues_total > 1) {
47 		queue = nfqueue_hash(skb, queue, info->queues_total,
48 				     xt_family(par), jhash_initval);
49 	}
50 	return NF_QUEUE_NR(queue);
51 }
52 
53 static unsigned int
54 nfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
55 {
56 	const struct xt_NFQ_info_v2 *info = par->targinfo;
57 	unsigned int ret = nfqueue_tg_v1(skb, par);
58 
59 	if (info->bypass)
60 		ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
61 	return ret;
62 }
63 
64 static int nfqueue_tg_check(const struct xt_tgchk_param *par)
65 {
66 	const struct xt_NFQ_info_v3 *info = par->targinfo;
67 	u32 maxid;
68 
69 	init_hashrandom(&jhash_initval);
70 
71 	if (info->queues_total == 0) {
72 		pr_info_ratelimited("number of total queues is 0\n");
73 		return -EINVAL;
74 	}
75 	maxid = info->queues_total - 1 + info->queuenum;
76 	if (maxid > 0xffff) {
77 		pr_info_ratelimited("number of queues (%u) out of range (got %u)\n",
78 				    info->queues_total, maxid);
79 		return -ERANGE;
80 	}
81 	if (par->target->revision == 2 && info->flags > 1)
82 		return -EINVAL;
83 	if (par->target->revision == 3 && info->flags & ~NFQ_FLAG_MASK)
84 		return -EINVAL;
85 
86 	return 0;
87 }
88 
89 static unsigned int
90 nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
91 {
92 	const struct xt_NFQ_info_v3 *info = par->targinfo;
93 	u32 queue = info->queuenum;
94 	int ret;
95 
96 	if (info->queues_total > 1) {
97 		if (info->flags & NFQ_FLAG_CPU_FANOUT) {
98 			int cpu = smp_processor_id();
99 
100 			queue = info->queuenum + cpu % info->queues_total;
101 		} else {
102 			queue = nfqueue_hash(skb, queue, info->queues_total,
103 					     xt_family(par), jhash_initval);
104 		}
105 	}
106 
107 	ret = NF_QUEUE_NR(queue);
108 	if (info->flags & NFQ_FLAG_BYPASS)
109 		ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
110 
111 	return ret;
112 }
113 
114 static struct xt_target nfqueue_tg_reg[] __read_mostly = {
115 	{
116 		.name		= "NFQUEUE",
117 		.family		= NFPROTO_UNSPEC,
118 		.target		= nfqueue_tg,
119 		.targetsize	= sizeof(struct xt_NFQ_info),
120 		.me		= THIS_MODULE,
121 	},
122 	{
123 		.name		= "NFQUEUE",
124 		.revision	= 1,
125 		.family		= NFPROTO_UNSPEC,
126 		.checkentry	= nfqueue_tg_check,
127 		.target		= nfqueue_tg_v1,
128 		.targetsize	= sizeof(struct xt_NFQ_info_v1),
129 		.me		= THIS_MODULE,
130 	},
131 	{
132 		.name		= "NFQUEUE",
133 		.revision	= 2,
134 		.family		= NFPROTO_UNSPEC,
135 		.checkentry	= nfqueue_tg_check,
136 		.target		= nfqueue_tg_v2,
137 		.targetsize	= sizeof(struct xt_NFQ_info_v2),
138 		.me		= THIS_MODULE,
139 	},
140 	{
141 		.name		= "NFQUEUE",
142 		.revision	= 3,
143 		.family		= NFPROTO_UNSPEC,
144 		.checkentry	= nfqueue_tg_check,
145 		.target		= nfqueue_tg_v3,
146 		.targetsize	= sizeof(struct xt_NFQ_info_v3),
147 		.me		= THIS_MODULE,
148 	},
149 };
150 
151 static int __init nfqueue_tg_init(void)
152 {
153 	return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg));
154 }
155 
156 static void __exit nfqueue_tg_exit(void)
157 {
158 	xt_unregister_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg));
159 }
160 
161 module_init(nfqueue_tg_init);
162 module_exit(nfqueue_tg_exit);
163