xt_NFQUEUE.c (3830B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* iptables module for using new netfilter netlink queue 3 * 4 * (C) 2005 by Harald Welte <laforge@netfilter.org> 5 */ 6 7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8 9#include <linux/module.h> 10#include <linux/skbuff.h> 11 12#include <linux/netfilter.h> 13#include <linux/netfilter_arp.h> 14#include <linux/netfilter/x_tables.h> 15#include <linux/netfilter/xt_NFQUEUE.h> 16 17#include <net/netfilter/nf_queue.h> 18 19MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 20MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); 21MODULE_LICENSE("GPL"); 22MODULE_ALIAS("ipt_NFQUEUE"); 23MODULE_ALIAS("ip6t_NFQUEUE"); 24MODULE_ALIAS("arpt_NFQUEUE"); 25 26static u32 jhash_initval __read_mostly; 27 28static unsigned int 29nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) 30{ 31 const struct xt_NFQ_info *tinfo = par->targinfo; 32 33 return NF_QUEUE_NR(tinfo->queuenum); 34} 35 36static unsigned int 37nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) 38{ 39 const struct xt_NFQ_info_v1 *info = par->targinfo; 40 u32 queue = info->queuenum; 41 42 if (info->queues_total > 1) { 43 queue = nfqueue_hash(skb, queue, info->queues_total, 44 xt_family(par), jhash_initval); 45 } 46 return NF_QUEUE_NR(queue); 47} 48 49static unsigned int 50nfqueue_tg_v2(struct sk_buff *skb, const struct xt_action_param *par) 51{ 52 const struct xt_NFQ_info_v2 *info = par->targinfo; 53 unsigned int ret = nfqueue_tg_v1(skb, par); 54 55 if (info->bypass) 56 ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; 57 return ret; 58} 59 60static int nfqueue_tg_check(const struct xt_tgchk_param *par) 61{ 62 const struct xt_NFQ_info_v3 *info = par->targinfo; 63 u32 maxid; 64 65 init_hashrandom(&jhash_initval); 66 67 if (info->queues_total == 0) { 68 pr_info_ratelimited("number of total queues is 0\n"); 69 return -EINVAL; 70 } 71 maxid = info->queues_total - 1 + info->queuenum; 72 if (maxid > 0xffff) { 73 pr_info_ratelimited("number of queues (%u) out of range (got %u)\n", 74 info->queues_total, maxid); 75 return -ERANGE; 76 } 77 if (par->target->revision == 2 && info->flags > 1) 78 return -EINVAL; 79 if (par->target->revision == 3 && info->flags & ~NFQ_FLAG_MASK) 80 return -EINVAL; 81 82 return 0; 83} 84 85static unsigned int 86nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par) 87{ 88 const struct xt_NFQ_info_v3 *info = par->targinfo; 89 u32 queue = info->queuenum; 90 int ret; 91 92 if (info->queues_total > 1) { 93 if (info->flags & NFQ_FLAG_CPU_FANOUT) { 94 int cpu = smp_processor_id(); 95 96 queue = info->queuenum + cpu % info->queues_total; 97 } else { 98 queue = nfqueue_hash(skb, queue, info->queues_total, 99 xt_family(par), jhash_initval); 100 } 101 } 102 103 ret = NF_QUEUE_NR(queue); 104 if (info->flags & NFQ_FLAG_BYPASS) 105 ret |= NF_VERDICT_FLAG_QUEUE_BYPASS; 106 107 return ret; 108} 109 110static struct xt_target nfqueue_tg_reg[] __read_mostly = { 111 { 112 .name = "NFQUEUE", 113 .family = NFPROTO_UNSPEC, 114 .target = nfqueue_tg, 115 .targetsize = sizeof(struct xt_NFQ_info), 116 .me = THIS_MODULE, 117 }, 118 { 119 .name = "NFQUEUE", 120 .revision = 1, 121 .family = NFPROTO_UNSPEC, 122 .checkentry = nfqueue_tg_check, 123 .target = nfqueue_tg_v1, 124 .targetsize = sizeof(struct xt_NFQ_info_v1), 125 .me = THIS_MODULE, 126 }, 127 { 128 .name = "NFQUEUE", 129 .revision = 2, 130 .family = NFPROTO_UNSPEC, 131 .checkentry = nfqueue_tg_check, 132 .target = nfqueue_tg_v2, 133 .targetsize = sizeof(struct xt_NFQ_info_v2), 134 .me = THIS_MODULE, 135 }, 136 { 137 .name = "NFQUEUE", 138 .revision = 3, 139 .family = NFPROTO_UNSPEC, 140 .checkentry = nfqueue_tg_check, 141 .target = nfqueue_tg_v3, 142 .targetsize = sizeof(struct xt_NFQ_info_v3), 143 .me = THIS_MODULE, 144 }, 145}; 146 147static int __init nfqueue_tg_init(void) 148{ 149 return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); 150} 151 152static void __exit nfqueue_tg_exit(void) 153{ 154 xt_unregister_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); 155} 156 157module_init(nfqueue_tg_init); 158module_exit(nfqueue_tg_exit);