libxt_NFQUEUE.c revision 6924b4987d88fbe383bec4da4cf331cc466c245e
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 <stdbool.h>
9#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <getopt.h>
13
14#include <xtables.h>
15#include <linux/netfilter/x_tables.h>
16#include <linux/netfilter/xt_NFQUEUE.h>
17
18static void NFQUEUE_help(void)
19{
20	printf(
21"NFQUEUE target options\n"
22"  --queue-num value		Send packet to QUEUE number <value>.\n"
23"  		                Valid queue numbers are 0-65535\n"
24);
25}
26
27static void NFQUEUE_help_v1(void)
28{
29	NFQUEUE_help();
30	printf(
31"  --queue-balance first:last	Balance flows between queues <value> to <value>.\n");
32}
33
34static void NFQUEUE_help_v2(void)
35{
36	NFQUEUE_help_v1();
37	printf(
38"  --queue-bypass		Bypass Queueing if no queue instance exists.\n");
39}
40
41static const struct option NFQUEUE_opts[] = {
42	{.name = "queue-num",     .has_arg = true, .val = 'F'},
43	{.name = "queue-balance", .has_arg = true, .val = 'B'},
44	{.name = "queue-bypass",  .has_arg = false,.val = 'P'},
45	XT_GETOPT_TABLEEND,
46};
47
48static void exit_badqueue(const char *s)
49{
50	xtables_error(PARAMETER_PROBLEM, "Invalid queue number `%s'\n", s);
51}
52
53static void
54parse_num(const char *s, struct xt_NFQ_info *tinfo)
55{
56	unsigned int num;
57
58	if (!xtables_strtoui(s, NULL, &num, 0, UINT16_MAX))
59		exit_badqueue(s);
60
61	tinfo->queuenum = num;
62}
63
64static int
65NFQUEUE_parse(int c, char **argv, int invert, unsigned int *flags,
66              const void *entry, struct xt_entry_target **target)
67{
68	struct xt_NFQ_info *tinfo
69		= (struct xt_NFQ_info *)(*target)->data;
70
71	switch (c) {
72	case 'F':
73		if (*flags)
74			xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: "
75				   "Only use --queue-num ONCE!");
76		parse_num(optarg, tinfo);
77		break;
78	case 'B':
79		xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: "
80				   "--queue-balance not supported (kernel too old?)");
81	}
82
83	return 1;
84}
85
86static int
87NFQUEUE_parse_v1(int c, char **argv, int invert, unsigned int *flags,
88                 const void *entry, struct xt_entry_target **target)
89{
90	struct xt_NFQ_info_v1 *info = (void *)(*target)->data;
91	char *colon;
92	unsigned int firstqueue, lastqueue;
93
94	switch (c) {
95	case 'F': /* fallthrough */
96	case 'B':
97		if (*flags)
98			xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: "
99				   "Only use --queue-num ONCE!");
100
101		if (!xtables_strtoui(optarg, &colon, &firstqueue, 0, UINT16_MAX))
102			exit_badqueue(optarg);
103
104		info->queuenum = firstqueue;
105
106		if (c == 'F') {
107			if (*colon)
108				exit_badqueue(optarg);
109			break;
110		}
111
112		if (*colon != ':')
113			xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", optarg);
114
115		if (!xtables_strtoui(colon + 1, NULL, &lastqueue, 1, UINT16_MAX))
116			exit_badqueue(optarg);
117
118		if (firstqueue >= lastqueue)
119			xtables_error(PARAMETER_PROBLEM, "%u should be less than %u",
120							firstqueue, lastqueue);
121		info->queues_total = lastqueue - firstqueue + 1;
122		break;
123	}
124
125	return 1;
126}
127
128static int
129NFQUEUE_parse_v2(int c, char **argv, int invert, unsigned int *flags,
130                 const void *entry, struct xt_entry_target **target)
131{
132	if (c == 'P') {
133		struct xt_NFQ_info_v2 *info = (void *)(*target)->data;
134		info->bypass = 1;
135		return 1;
136	}
137	return NFQUEUE_parse_v1(c, argv, invert, flags, entry, target);
138}
139
140static void NFQUEUE_print(const void *ip,
141                          const struct xt_entry_target *target, int numeric)
142{
143	const struct xt_NFQ_info *tinfo =
144		(const struct xt_NFQ_info *)target->data;
145	printf("NFQUEUE num %u", tinfo->queuenum);
146}
147
148static void NFQUEUE_print_v1(const void *ip,
149                             const struct xt_entry_target *target, int numeric)
150{
151	const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data;
152	unsigned int last = tinfo->queues_total;
153
154	if (last > 1) {
155		last += tinfo->queuenum - 1;
156		printf("NFQUEUE balance %u:%u", tinfo->queuenum, last);
157	} else {
158		printf("NFQUEUE num %u", tinfo->queuenum);
159	}
160}
161
162static void NFQUEUE_print_v2(const void *ip,
163                             const struct xt_entry_target *target, int numeric)
164{
165	const struct xt_NFQ_info_v2 *info = (void *) target->data;
166
167	NFQUEUE_print_v1(ip, target, numeric);
168	if (info->bypass)
169		printf(" bypass");
170}
171
172static void NFQUEUE_save(const void *ip, const struct xt_entry_target *target)
173{
174	const struct xt_NFQ_info *tinfo =
175		(const struct xt_NFQ_info *)target->data;
176
177	printf("--queue-num %u ", tinfo->queuenum);
178}
179
180static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target)
181{
182	const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data;
183	unsigned int last = tinfo->queues_total;
184
185	if (last > 1) {
186		last += tinfo->queuenum - 1;
187		printf("--queue-balance %u:%u ", tinfo->queuenum, last);
188	} else {
189		printf("--queue-num %u ", tinfo->queuenum);
190	}
191}
192
193static void NFQUEUE_save_v2(const void *ip, const struct xt_entry_target *target)
194{
195	const struct xt_NFQ_info_v2 *info = (void *) target->data;
196
197	NFQUEUE_save_v1(ip, target);
198
199	if (info->bypass)
200		printf("--queue-bypass ");
201}
202
203static void NFQUEUE_init_v1(struct xt_entry_target *t)
204{
205	struct xt_NFQ_info_v1 *tinfo = (void *)t->data;
206	tinfo->queues_total = 1;
207}
208
209static struct xtables_target nfqueue_targets[] = {
210{
211	.family		= NFPROTO_UNSPEC,
212	.name		= "NFQUEUE",
213	.version	= XTABLES_VERSION,
214	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info)),
215	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info)),
216	.help		= NFQUEUE_help,
217	.parse		= NFQUEUE_parse,
218	.print		= NFQUEUE_print,
219	.save		= NFQUEUE_save,
220	.extra_opts	= NFQUEUE_opts
221},{
222	.family		= NFPROTO_UNSPEC,
223	.revision	= 1,
224	.name		= "NFQUEUE",
225	.version	= XTABLES_VERSION,
226	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info_v1)),
227	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info_v1)),
228	.help		= NFQUEUE_help_v1,
229	.init		= NFQUEUE_init_v1,
230	.parse		= NFQUEUE_parse_v1,
231	.print		= NFQUEUE_print_v1,
232	.save		= NFQUEUE_save_v1,
233	.extra_opts	= NFQUEUE_opts,
234},{
235	.family		= NFPROTO_UNSPEC,
236	.revision	= 2,
237	.name		= "NFQUEUE",
238	.version	= XTABLES_VERSION,
239	.size		= XT_ALIGN(sizeof(struct xt_NFQ_info_v2)),
240	.userspacesize	= XT_ALIGN(sizeof(struct xt_NFQ_info_v2)),
241	.help		= NFQUEUE_help_v2,
242	.init		= NFQUEUE_init_v1,
243	.parse		= NFQUEUE_parse_v2,
244	.print		= NFQUEUE_print_v2,
245	.save		= NFQUEUE_save_v2,
246	.extra_opts	= NFQUEUE_opts,
247}
248};
249
250void _init(void)
251{
252	xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets));
253}
254