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 
12 enum {
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 
NFQUEUE_help(void)22 static 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 
NFQUEUE_help_v1(void)31 static 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 
NFQUEUE_help_v2(void)38 static 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 
NFQUEUE_help_v3(void)46 static 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
54 static 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 
NFQUEUE_parse(struct xt_option_call * cb)67 static 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 
NFQUEUE_parse_v1(struct xt_option_call * cb)75 static 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 
NFQUEUE_parse_v2(struct xt_option_call * cb)95 static 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 
NFQUEUE_parse_v3(struct xt_option_call * cb)107 static 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 
NFQUEUE_print(const void * ip,const struct xt_entry_target * target,int numeric)119 static 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 
NFQUEUE_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)127 static 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 
NFQUEUE_print_v2(const void * ip,const struct xt_entry_target * target,int numeric)141 static 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 
NFQUEUE_print_v3(const void * ip,const struct xt_entry_target * target,int numeric)151 static 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 
NFQUEUE_save(const void * ip,const struct xt_entry_target * target)161 static 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 
NFQUEUE_save_v1(const void * ip,const struct xt_entry_target * target)169 static 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 
NFQUEUE_save_v2(const void * ip,const struct xt_entry_target * target)182 static 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 
NFQUEUE_save_v3(const void * ip,const struct xt_entry_target * target)192 static 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 
NFQUEUE_init_v1(struct xt_entry_target * t)202 static 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 
208 static 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 
_init(void)262 void _init(void)
263 {
264 	xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets));
265 }
266