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