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 19 MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); 20 MODULE_DESCRIPTION("Xtables: packet forwarding to netlink"); 21 MODULE_LICENSE("GPL"); 22 MODULE_ALIAS("ipt_NFQUEUE"); 23 MODULE_ALIAS("ip6t_NFQUEUE"); 24 MODULE_ALIAS("arpt_NFQUEUE"); 25 26 static u32 jhash_initval __read_mostly; 27 28 static unsigned int 29 nfqueue_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 36 static unsigned int 37 nfqueue_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 49 static unsigned int 50 nfqueue_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 60 static 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 85 static unsigned int 86 nfqueue_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 110 static 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 147 static int __init nfqueue_tg_init(void) 148 { 149 return xt_register_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); 150 } 151 152 static void __exit nfqueue_tg_exit(void) 153 { 154 xt_unregister_targets(nfqueue_tg_reg, ARRAY_SIZE(nfqueue_tg_reg)); 155 } 156 157 module_init(nfqueue_tg_init); 158 module_exit(nfqueue_tg_exit); 159