12e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte/* iptables module for using new netfilter netlink queue
22e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
32e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * (C) 2005 by Harald Welte <laforge@netfilter.org>
42e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte *
52e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * This program is free software; you can redistribute it and/or modify
6601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki * it under the terms of the GNU General Public License version 2 as
72e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte * published by the Free Software Foundation.
8601e68e100b6bf8ba13a32db8faf92d43acaa997YOSHIFUJI Hideaki *
92e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte */
102e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
112e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/module.h>
122e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/skbuff.h>
132e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
142e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter.h>
152e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter_arp.h>
162e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/x_tables.h>
172e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte#include <linux/netfilter/xt_NFQUEUE.h>
182e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
1997a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond#include <net/netfilter/nf_queue.h>
2097a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond
212e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
222ae15b64e6a1608c840c60df38e8e5eef7b2b8c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: packet forwarding to netlink");
232e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_LICENSE("GPL");
242e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_ALIAS("ipt_NFQUEUE");
252e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_ALIAS("ip6t_NFQUEUE");
262e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald WelteMODULE_ALIAS("arpt_NFQUEUE");
272e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
2810662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphalstatic u32 jhash_initval __read_mostly;
2910662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal
302e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Weltestatic unsigned int
314b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardtnfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par)
322e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
337eb3558655aaa87a3e71a0c065dfaddda521fa6dJan Engelhardt	const struct xt_NFQ_info *tinfo = par->targinfo;
342e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
352e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte	return NF_QUEUE_NR(tinfo->queuenum);
362e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
372e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
385c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.orgstatic unsigned int
395c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.orgnfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
405c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.org{
415c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.org	const struct xt_NFQ_info_v1 *info = par->targinfo;
425c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.org	u32 queue = info->queuenum;
435c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.org
4497a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond	if (info->queues_total > 1) {
4597a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond		queue = nfqueue_hash(skb, queue, info->queues_total,
4697a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond				     par->family, jhash_initval);
4797a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond	}
4810662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	return NF_QUEUE_NR(queue);
4910662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal}
5010662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal
5194b27cc36123069966616670c3653cd6873babe9Florian Westphalstatic unsigned int
5294b27cc36123069966616670c3653cd6873babe9Florian Westphalnfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
5310662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal{
5494b27cc36123069966616670c3653cd6873babe9Florian Westphal	const struct xt_NFQ_info_v2 *info = par->targinfo;
5594b27cc36123069966616670c3653cd6873babe9Florian Westphal	unsigned int ret = nfqueue_tg_v1(skb, par);
5694b27cc36123069966616670c3653cd6873babe9Florian Westphal
5794b27cc36123069966616670c3653cd6873babe9Florian Westphal	if (info->bypass)
5894b27cc36123069966616670c3653cd6873babe9Florian Westphal		ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
5994b27cc36123069966616670c3653cd6873babe9Florian Westphal	return ret;
6094b27cc36123069966616670c3653cd6873babe9Florian Westphal}
6194b27cc36123069966616670c3653cd6873babe9Florian Westphal
6294b27cc36123069966616670c3653cd6873babe9Florian Westphalstatic int nfqueue_tg_check(const struct xt_tgchk_param *par)
6394b27cc36123069966616670c3653cd6873babe9Florian Westphal{
648746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	const struct xt_NFQ_info_v3 *info = par->targinfo;
6510662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	u32 maxid;
6610662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal
6797a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond	init_hashrandom(&jhash_initval);
6897a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond
6910662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	if (info->queues_total == 0) {
7010662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		pr_err("NFQUEUE: number of total queues is 0\n");
71d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		return -EINVAL;
7210662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	}
7310662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	maxid = info->queues_total - 1 + info->queuenum;
7410662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	if (maxid > 0xffff) {
7510662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n",
7610662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		       info->queues_total, maxid);
774a5a5c73b7cfee46a0b1411903cfa0dea532deecJan Engelhardt		return -ERANGE;
7810662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	}
798746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	if (par->target->revision == 2 && info->flags > 1)
808746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		return -EINVAL;
818746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	if (par->target->revision == 3 && info->flags & ~NFQ_FLAG_MASK)
8294b27cc36123069966616670c3653cd6873babe9Florian Westphal		return -EINVAL;
838746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org
84d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt	return 0;
8510662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal}
8610662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal
878746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.orgstatic unsigned int
888746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.orgnfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
898746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org{
908746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	const struct xt_NFQ_info_v3 *info = par->targinfo;
918746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	u32 queue = info->queuenum;
92d954777324ffcba0b2f8119c102237426c654eebHolger Eitzenberger	int ret;
938746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org
948746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	if (info->queues_total > 1) {
958746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		if (info->flags & NFQ_FLAG_CPU_FANOUT) {
968746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org			int cpu = smp_processor_id();
978746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org
988746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org			queue = info->queuenum + cpu % info->queues_total;
9997a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond		} else {
10097a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond			queue = nfqueue_hash(skb, queue, info->queues_total,
10197a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond					     par->family, jhash_initval);
10297a2d41c47a2246c3387a937c62126c9faefe875Eric Leblond		}
1038746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	}
1045c33448c405adfe1562df76215f24ef0a7947872holger@eitzenberger.org
105d954777324ffcba0b2f8119c102237426c654eebHolger Eitzenberger	ret = NF_QUEUE_NR(queue);
106d954777324ffcba0b2f8119c102237426c654eebHolger Eitzenberger	if (info->flags & NFQ_FLAG_BYPASS)
107d954777324ffcba0b2f8119c102237426c654eebHolger Eitzenberger		ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
108d954777324ffcba0b2f8119c102237426c654eebHolger Eitzenberger
109d954777324ffcba0b2f8119c102237426c654eebHolger Eitzenberger	return ret;
1108746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org}
1118746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org
112d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic struct xt_target nfqueue_tg_reg[] __read_mostly = {
1134470bbc749e5551cce914529309456f631e25120Patrick McHardy	{
1144470bbc749e5551cce914529309456f631e25120Patrick McHardy		.name		= "NFQUEUE",
11561f5abcab152cbee3a041f8b9bcfe7afc83409caFlorian Westphal		.family		= NFPROTO_UNSPEC,
116d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt		.target		= nfqueue_tg,
1174470bbc749e5551cce914529309456f631e25120Patrick McHardy		.targetsize	= sizeof(struct xt_NFQ_info),
1184470bbc749e5551cce914529309456f631e25120Patrick McHardy		.me		= THIS_MODULE,
1194470bbc749e5551cce914529309456f631e25120Patrick McHardy	},
12010662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	{
12110662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		.name		= "NFQUEUE",
12210662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		.revision	= 1,
123f76a47c83247b453f25629618056a6d2c1e39103Jan Engelhardt		.family		= NFPROTO_UNSPEC,
12494b27cc36123069966616670c3653cd6873babe9Florian Westphal		.checkentry	= nfqueue_tg_check,
125f76a47c83247b453f25629618056a6d2c1e39103Jan Engelhardt		.target		= nfqueue_tg_v1,
12610662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		.targetsize	= sizeof(struct xt_NFQ_info_v1),
12710662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal		.me		= THIS_MODULE,
12810662aa3083f869c645cc2abf5d66849001e2f5dFlorian Westphal	},
12994b27cc36123069966616670c3653cd6873babe9Florian Westphal	{
13094b27cc36123069966616670c3653cd6873babe9Florian Westphal		.name		= "NFQUEUE",
13194b27cc36123069966616670c3653cd6873babe9Florian Westphal		.revision	= 2,
13294b27cc36123069966616670c3653cd6873babe9Florian Westphal		.family		= NFPROTO_UNSPEC,
13394b27cc36123069966616670c3653cd6873babe9Florian Westphal		.checkentry	= nfqueue_tg_check,
13494b27cc36123069966616670c3653cd6873babe9Florian Westphal		.target		= nfqueue_tg_v2,
13594b27cc36123069966616670c3653cd6873babe9Florian Westphal		.targetsize	= sizeof(struct xt_NFQ_info_v2),
13694b27cc36123069966616670c3653cd6873babe9Florian Westphal		.me		= THIS_MODULE,
13794b27cc36123069966616670c3653cd6873babe9Florian Westphal	},
1388746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	{
1398746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.name		= "NFQUEUE",
1408746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.revision	= 3,
1418746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.family		= NFPROTO_UNSPEC,
1428746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.checkentry	= nfqueue_tg_check,
1438746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.target		= nfqueue_tg_v3,
1448746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.targetsize	= sizeof(struct xt_NFQ_info_v3),
1458746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org		.me		= THIS_MODULE,
1468746ddcf12bb263ad240e095ef16531006caeb50holger@eitzenberger.org	},
1472e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte};
1482e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
149d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic int __init nfqueue_tg_init(void)
1502e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
151d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt	return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg));
1522e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1532e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
154d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic void __exit nfqueue_tg_exit(void)
1552e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte{
156d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardt	xt_unregister_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg));
1572e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte}
1582e4e6a17af35be359cc8f1c924f8f198fbd478ccHarald Welte
159d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_init(nfqueue_tg_init);
160d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_exit(nfqueue_tg_exit);
161