Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 1 | /* iptables module for using new netfilter netlink queue |
| 2 | * |
| 3 | * (C) 2005 by Harald Welte <laforge@netfilter.org> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
YOSHIFUJI Hideaki | 601e68e | 2007-02-12 11:15:49 -0800 | [diff] [blame] | 6 | * it under the terms of the GNU General Public License version 2 as |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 7 | * published by the Free Software Foundation. |
YOSHIFUJI Hideaki | 601e68e | 2007-02-12 11:15:49 -0800 | [diff] [blame] | 8 | * |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 9 | */ |
| 10 | |
Florian Westphal | e016c5e | 2018-02-09 15:52:02 +0100 | [diff] [blame] | 11 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 12 | |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 13 | #include <linux/module.h> |
| 14 | #include <linux/skbuff.h> |
| 15 | |
| 16 | #include <linux/netfilter.h> |
| 17 | #include <linux/netfilter_arp.h> |
| 18 | #include <linux/netfilter/x_tables.h> |
| 19 | #include <linux/netfilter/xt_NFQUEUE.h> |
| 20 | |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 21 | #include <net/netfilter/nf_queue.h> |
| 22 | |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); |
Jan Engelhardt | 2ae15b6 | 2008-01-14 23:42:28 -0800 | [diff] [blame] | 24 | MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 25 | MODULE_LICENSE("GPL"); |
| 26 | MODULE_ALIAS("ipt_NFQUEUE"); |
| 27 | MODULE_ALIAS("ip6t_NFQUEUE"); |
| 28 | MODULE_ALIAS("arpt_NFQUEUE"); |
| 29 | |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 30 | static u32 jhash_initval __read_mostly; |
| 31 | |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 32 | static unsigned int |
Jan Engelhardt | 4b560b4 | 2009-07-05 19:43:26 +0200 | [diff] [blame] | 33 | nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 34 | { |
Jan Engelhardt | 7eb3558 | 2008-10-08 11:35:19 +0200 | [diff] [blame] | 35 | const struct xt_NFQ_info *tinfo = par->targinfo; |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 36 | |
| 37 | return NF_QUEUE_NR(tinfo->queuenum); |
| 38 | } |
| 39 | |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 40 | static unsigned int |
Jan Engelhardt | 4b560b4 | 2009-07-05 19:43:26 +0200 | [diff] [blame] | 41 | nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 42 | { |
| 43 | const struct xt_NFQ_info_v1 *info = par->targinfo; |
| 44 | u32 queue = info->queuenum; |
| 45 | |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 46 | if (info->queues_total > 1) { |
| 47 | queue = nfqueue_hash(skb, queue, info->queues_total, |
Pablo Neira Ayuso | 613dbd9 | 2016-11-03 10:56:21 +0100 | [diff] [blame] | 48 | xt_family(par), jhash_initval); |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 49 | } |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 50 | return NF_QUEUE_NR(queue); |
| 51 | } |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 52 | |
Florian Westphal | 94b27cc | 2011-01-18 16:08:30 +0100 | [diff] [blame] | 53 | static unsigned int |
| 54 | nfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 55 | { |
Florian Westphal | 94b27cc | 2011-01-18 16:08:30 +0100 | [diff] [blame] | 56 | const struct xt_NFQ_info_v2 *info = par->targinfo; |
| 57 | unsigned int ret = nfqueue_tg_v1(skb, par); |
| 58 | |
| 59 | if (info->bypass) |
| 60 | ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; |
| 61 | return ret; |
| 62 | } |
| 63 | |
| 64 | static int nfqueue_tg_check(const struct xt_tgchk_param *par) |
| 65 | { |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 66 | const struct xt_NFQ_info_v3 *info = par->targinfo; |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 67 | u32 maxid; |
| 68 | |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 69 | init_hashrandom(&jhash_initval); |
| 70 | |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 71 | if (info->queues_total == 0) { |
Florian Westphal | e016c5e | 2018-02-09 15:52:02 +0100 | [diff] [blame] | 72 | pr_info_ratelimited("number of total queues is 0\n"); |
Jan Engelhardt | d6b00a5 | 2010-03-25 16:34:45 +0100 | [diff] [blame] | 73 | return -EINVAL; |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 74 | } |
| 75 | maxid = info->queues_total - 1 + info->queuenum; |
| 76 | if (maxid > 0xffff) { |
Florian Westphal | e016c5e | 2018-02-09 15:52:02 +0100 | [diff] [blame] | 77 | pr_info_ratelimited("number of queues (%u) out of range (got %u)\n", |
| 78 | info->queues_total, maxid); |
Jan Engelhardt | 4a5a5c7 | 2010-03-19 17:32:59 +0100 | [diff] [blame] | 79 | return -ERANGE; |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 80 | } |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 81 | if (par->target->revision == 2 && info->flags > 1) |
Florian Westphal | 94b27cc | 2011-01-18 16:08:30 +0100 | [diff] [blame] | 82 | return -EINVAL; |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 83 | if (par->target->revision == 3 && info->flags & ~NFQ_FLAG_MASK) |
| 84 | return -EINVAL; |
| 85 | |
Jan Engelhardt | d6b00a5 | 2010-03-25 16:34:45 +0100 | [diff] [blame] | 86 | return 0; |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 87 | } |
| 88 | |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 89 | static unsigned int |
| 90 | nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) |
| 91 | { |
| 92 | const struct xt_NFQ_info_v3 *info = par->targinfo; |
| 93 | u32 queue = info->queuenum; |
Holger Eitzenberger | d954777 | 2013-10-28 14:42:33 +0100 | [diff] [blame] | 94 | int ret; |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 95 | |
| 96 | if (info->queues_total > 1) { |
| 97 | if (info->flags & NFQ_FLAG_CPU_FANOUT) { |
| 98 | int cpu = smp_processor_id(); |
| 99 | |
| 100 | queue = info->queuenum + cpu % info->queues_total; |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 101 | } else { |
| 102 | queue = nfqueue_hash(skb, queue, info->queues_total, |
Pablo Neira Ayuso | 613dbd9 | 2016-11-03 10:56:21 +0100 | [diff] [blame] | 103 | xt_family(par), jhash_initval); |
Eric Leblond | 97a2d41 | 2013-12-06 00:24:12 +0100 | [diff] [blame] | 104 | } |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 105 | } |
holger@eitzenberger.org | 5c33448 | 2013-03-23 10:04:04 +0000 | [diff] [blame] | 106 | |
Holger Eitzenberger | d954777 | 2013-10-28 14:42:33 +0100 | [diff] [blame] | 107 | ret = NF_QUEUE_NR(queue); |
| 108 | if (info->flags & NFQ_FLAG_BYPASS) |
| 109 | ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; |
| 110 | |
| 111 | return ret; |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 112 | } |
| 113 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 114 | static struct xt_target nfqueue_tg_reg[] __read_mostly = { |
Patrick McHardy | 4470bbc | 2006-08-22 00:34:04 -0700 | [diff] [blame] | 115 | { |
| 116 | .name = "NFQUEUE", |
Florian Westphal | 61f5abc | 2009-06-05 13:18:07 +0200 | [diff] [blame] | 117 | .family = NFPROTO_UNSPEC, |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 118 | .target = nfqueue_tg, |
Patrick McHardy | 4470bbc | 2006-08-22 00:34:04 -0700 | [diff] [blame] | 119 | .targetsize = sizeof(struct xt_NFQ_info), |
| 120 | .me = THIS_MODULE, |
| 121 | }, |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 122 | { |
| 123 | .name = "NFQUEUE", |
| 124 | .revision = 1, |
Jan Engelhardt | f76a47c | 2009-06-05 15:22:15 +0200 | [diff] [blame] | 125 | .family = NFPROTO_UNSPEC, |
Florian Westphal | 94b27cc | 2011-01-18 16:08:30 +0100 | [diff] [blame] | 126 | .checkentry = nfqueue_tg_check, |
Jan Engelhardt | f76a47c | 2009-06-05 15:22:15 +0200 | [diff] [blame] | 127 | .target = nfqueue_tg_v1, |
Florian Westphal | 10662aa | 2009-06-05 13:24:24 +0200 | [diff] [blame] | 128 | .targetsize = sizeof(struct xt_NFQ_info_v1), |
| 129 | .me = THIS_MODULE, |
| 130 | }, |
Florian Westphal | 94b27cc | 2011-01-18 16:08:30 +0100 | [diff] [blame] | 131 | { |
| 132 | .name = "NFQUEUE", |
| 133 | .revision = 2, |
| 134 | .family = NFPROTO_UNSPEC, |
| 135 | .checkentry = nfqueue_tg_check, |
| 136 | .target = nfqueue_tg_v2, |
| 137 | .targetsize = sizeof(struct xt_NFQ_info_v2), |
| 138 | .me = THIS_MODULE, |
| 139 | }, |
holger@eitzenberger.org | 8746ddc | 2013-03-23 10:04:03 +0000 | [diff] [blame] | 140 | { |
| 141 | .name = "NFQUEUE", |
| 142 | .revision = 3, |
| 143 | .family = NFPROTO_UNSPEC, |
| 144 | .checkentry = nfqueue_tg_check, |
| 145 | .target = nfqueue_tg_v3, |
| 146 | .targetsize = sizeof(struct xt_NFQ_info_v3), |
| 147 | .me = THIS_MODULE, |
| 148 | }, |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 149 | }; |
| 150 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 151 | static int __init nfqueue_tg_init(void) |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 152 | { |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 153 | return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 154 | } |
| 155 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 156 | static void __exit nfqueue_tg_exit(void) |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 157 | { |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 158 | xt_unregister_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); |
Harald Welte | 2e4e6a1 | 2006-01-12 13:30:04 -0800 | [diff] [blame] | 159 | } |
| 160 | |
Jan Engelhardt | d3c5ee6 | 2007-12-04 23:24:03 -0800 | [diff] [blame] | 161 | module_init(nfqueue_tg_init); |
| 162 | module_exit(nfqueue_tg_exit); |