1/* Shared library add-on to iptables for NFQ
2 *
3 * (C) 2005 by Harald Welte <laforge@netfilter.org>
4 *
5 * This program is distributed under the terms of GNU GPL v2, 1991
6 *
7 */
8#include <stdio.h>
9#include <xtables.h>
10#include <linux/netfilter/xt_NFQUEUE.h>
11
12enum {
13	O_QUEUE_NUM = 0,
14	O_QUEUE_BALANCE,
15	O_QUEUE_BYPASS,
16	O_QUEUE_CPU_FANOUT,
17	F_QUEUE_NUM     = 1 << O_QUEUE_NUM,
18	F_QUEUE_BALANCE = 1 << O_QUEUE_BALANCE,
19	F_QUEUE_CPU_FANOUT = 1 << O_QUEUE_CPU_FANOUT,
20};
21
22static void NFQUEUE_help(void)
23{
24	printf(
25"NFQUEUE target options\n"
26"  --queue-num value		Send packet to QUEUE number <value>.\n"
27"  		                Valid queue numbers are 0-65535\n"
28);
29}
30
31static void NFQUEUE_help_v1(void)
32{
33	NFQUEUE_help();
34	printf(
35"  --queue-balance first:last	Balance flows between queues <value> to <value>.\n");
36}
37
38static void NFQUEUE_help_v2(void)
39{
40	NFQUEUE_help_v1();
41	printf(
42"  --queue-bypass		Bypass Queueing if no queue instance exists.\n"
43"  --queue-cpu-fanout	Use current CPU (no hashing)\n");
44}
45
46static void NFQUEUE_help_v3(void)
47{
48	NFQUEUE_help_v2();
49	printf(
50"  --queue-cpu-fanout	Use current CPU (no hashing)\n");
51}
52
53#define s struct xt_NFQ_info
54static const struct xt_option_entry NFQUEUE_opts[] = {
55	{.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16,
56	 .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum),
57	 .excl = F_QUEUE_BALANCE},
58	{.name = "queue-balance", .id = O_QUEUE_BALANCE,
59	 .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM},
60	{.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE},
61	{.name = "queue-cpu-fanout", .id = O_QUEUE_CPU_FANOUT,
62	 .type = XTTYPE_NONE, .also = F_QUEUE_BALANCE},
63	XTOPT_TABLEEND,
64};
65#undef s
66
67static void NFQUEUE_parse(struct xt_option_call *cb)
68{
69	xtables_option_parse(cb);
70	if (cb->entry->id == O_QUEUE_BALANCE)
71		xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: "
72				   "--queue-balance not supported (kernel too old?)");
73}
74
75static void NFQUEUE_parse_v1(struct xt_option_call *cb)
76{
77	struct xt_NFQ_info_v1 *info = cb->data;
78	const uint16_t *r = cb->val.u16_range;
79
80	xtables_option_parse(cb);
81	switch (cb->entry->id) {
82	case O_QUEUE_BALANCE:
83		if (cb->nvals != 2)
84			xtables_error(PARAMETER_PROBLEM,
85				"Bad range \"%s\"", cb->arg);
86		if (r[0] >= r[1])
87			xtables_error(PARAMETER_PROBLEM, "%u should be less than %u",
88				r[0], r[1]);
89		info->queuenum = r[0];
90		info->queues_total = r[1] - r[0] + 1;
91		break;
92	}
93}
94
95static void NFQUEUE_parse_v2(struct xt_option_call *cb)
96{
97	struct xt_NFQ_info_v2 *info = cb->data;
98
99	NFQUEUE_parse_v1(cb);
100	switch (cb->entry->id) {
101	case O_QUEUE_BYPASS:
102		info->bypass = 1;
103		break;
104	}
105}
106
107static void NFQUEUE_parse_v3(struct xt_option_call *cb)
108{
109	struct xt_NFQ_info_v3 *info = cb->data;
110
111	NFQUEUE_parse_v2(cb);
112	switch (cb->entry->id) {
113	case O_QUEUE_CPU_FANOUT:
114		info->flags |= NFQ_FLAG_CPU_FANOUT;
115		break;
116	}
117}
118
119static void NFQUEUE_print(const void *ip,
120                          const struct xt_entry_target *target, int numeric)
121{
122	const struct xt_NFQ_info *tinfo =
123		(const struct xt_NFQ_info *)target->data;
124	printf(" NFQUEUE num %u", tinfo->queuenum);
125}
126
127static void NFQUEUE_print_v1(const void *ip,
128                             const struct xt_entry_target *target, int numeric)
129{
130	const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data;
131	unsigned int last = tinfo->queues_total;
132
133	if (last > 1) {
134		last += tinfo->queuenum - 1;
135		printf(" NFQUEUE balance %u:%u", tinfo->queuenum, last);
136	} else {
137		printf(" NFQUEUE num %u", tinfo->queuenum);
138	}
139}
140
141static void NFQUEUE_print_v2(const void *ip,
142                             const struct xt_entry_target *target, int numeric)
143{
144	const struct xt_NFQ_info_v2 *info = (void *) target->data;
145
146	NFQUEUE_print_v1(ip, target, numeric);
147	if (info->bypass & NFQ_FLAG_BYPASS)
148		printf(" bypass");
149}
150
151static void NFQUEUE_print_v3(const void *ip,
152                             const struct xt_entry_target *target, int numeric)
153{
154	const struct xt_NFQ_info_v3 *info = (void *)target->data;
155
156	NFQUEUE_print_v2(ip, target, numeric);
157	if (info->flags & NFQ_FLAG_CPU_FANOUT)
158		printf(" cpu-fanout");
159}
160
161static void NFQUEUE_save(const void *ip, const struct xt_entry_target *target)
162{
163	const struct xt_NFQ_info *tinfo =
164		(const struct xt_NFQ_info *)target->data;
165
166	printf(" --queue-num %u", tinfo->queuenum);
167}
168
169static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target)
170{
171	const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data;
172	unsigned int last = tinfo->queues_total;
173
174	if (last > 1) {
175		last += tinfo->queuenum - 1;
176		printf(" --queue-balance %u:%u", tinfo->queuenum, last);
177	} else {
178		printf(" --queue-num %u", tinfo->queuenum);
179	}
180}
181
182static void NFQUEUE_save_v2(const void *ip, const struct xt_entry_target *target)
183{
184	const struct xt_NFQ_info_v2 *info = (void *) target->data;
185
186	NFQUEUE_save_v1(ip, target);
187
188	if (info->bypass & NFQ_FLAG_BYPASS)
189		printf(" --queue-bypass");
190}
191
192static void NFQUEUE_save_v3(const void *ip,
193			    const struct xt_entry_target *target)
194{
195	const struct xt_NFQ_info_v3 *info = (void *)target->data;
196
197	NFQUEUE_save_v2(ip, target);
198	if (info->flags & NFQ_FLAG_CPU_FANOUT)
199		printf(" --queue-cpu-fanout");
200}
201
202static void NFQUEUE_init_v1(struct xt_entry_target *t)
203{
204	struct xt_NFQ_info_v1 *tinfo = (void *)t->data;
205	tinfo->queues_total = 1;
206}
207
208static struct xtables_target nfqueue_targets[] = {
209{
210	.family		= NFPROTO_UNSPEC,
211	.name		= "NFQUEUE",
212	.version	= XTABLES_VERSION,
213	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info)),
214	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info)),
215	.help		= NFQUEUE_help,
216	.print		= NFQUEUE_print,
217	.save		= NFQUEUE_save,
218	.x6_parse	= NFQUEUE_parse,
219	.x6_options	= NFQUEUE_opts
220},{
221	.family		= NFPROTO_UNSPEC,
222	.revision	= 1,
223	.name		= "NFQUEUE",
224	.version	= XTABLES_VERSION,
225	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info_v1)),
226	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info_v1)),
227	.help		= NFQUEUE_help_v1,
228	.init		= NFQUEUE_init_v1,
229	.print		= NFQUEUE_print_v1,
230	.save		= NFQUEUE_save_v1,
231	.x6_parse	= NFQUEUE_parse_v1,
232	.x6_options	= NFQUEUE_opts,
233},{
234	.family		= NFPROTO_UNSPEC,
235	.revision	= 2,
236	.name		= "NFQUEUE",
237	.version	= XTABLES_VERSION,
238	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info_v2)),
239	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info_v2)),
240	.help		= NFQUEUE_help_v2,
241	.init		= NFQUEUE_init_v1,
242	.print		= NFQUEUE_print_v2,
243	.save		= NFQUEUE_save_v2,
244	.x6_parse	= NFQUEUE_parse_v2,
245	.x6_options	= NFQUEUE_opts,
246},{
247	.family		= NFPROTO_UNSPEC,
248	.revision	= 3,
249	.name		= "NFQUEUE",
250	.version	= XTABLES_VERSION,
251	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info_v3)),
252	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info_v3)),
253	.help		= NFQUEUE_help_v3,
254	.init		= NFQUEUE_init_v1,
255	.print		= NFQUEUE_print_v3,
256	.save		= NFQUEUE_save_v3,
257	.x6_parse	= NFQUEUE_parse_v3,
258	.x6_options	= NFQUEUE_opts,
259}
260};
261
262void _init(void)
263{
264	xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets));
265}
266