1/* Shared library add-on to iptables for NFQ 2 * 3 * (C) 2005 by Harald Welte <laforge@netfilter.org> 4 * 5 * This program is distributed under the terms of GNU GPL v2, 1991 6 * 7 */ 8#include <stdio.h> 9#include <xtables.h> 10#include <linux/netfilter/xt_NFQUEUE.h> 11 12enum { 13 O_QUEUE_NUM = 0, 14 O_QUEUE_BALANCE, 15 O_QUEUE_BYPASS, 16 O_QUEUE_CPU_FANOUT, 17 F_QUEUE_NUM = 1 << O_QUEUE_NUM, 18 F_QUEUE_BALANCE = 1 << O_QUEUE_BALANCE, 19 F_QUEUE_CPU_FANOUT = 1 << O_QUEUE_CPU_FANOUT, 20}; 21 22static void NFQUEUE_help(void) 23{ 24 printf( 25"NFQUEUE target options\n" 26" --queue-num value Send packet to QUEUE number <value>.\n" 27" Valid queue numbers are 0-65535\n" 28); 29} 30 31static void NFQUEUE_help_v1(void) 32{ 33 NFQUEUE_help(); 34 printf( 35" --queue-balance first:last Balance flows between queues <value> to <value>.\n"); 36} 37 38static void NFQUEUE_help_v2(void) 39{ 40 NFQUEUE_help_v1(); 41 printf( 42" --queue-bypass Bypass Queueing if no queue instance exists.\n" 43" --queue-cpu-fanout Use current CPU (no hashing)\n"); 44} 45 46static void NFQUEUE_help_v3(void) 47{ 48 NFQUEUE_help_v2(); 49 printf( 50" --queue-cpu-fanout Use current CPU (no hashing)\n"); 51} 52 53#define s struct xt_NFQ_info 54static const struct xt_option_entry NFQUEUE_opts[] = { 55 {.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16, 56 .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum), 57 .excl = F_QUEUE_BALANCE}, 58 {.name = "queue-balance", .id = O_QUEUE_BALANCE, 59 .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM}, 60 {.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE}, 61 {.name = "queue-cpu-fanout", .id = O_QUEUE_CPU_FANOUT, 62 .type = XTTYPE_NONE, .also = F_QUEUE_BALANCE}, 63 XTOPT_TABLEEND, 64}; 65#undef s 66 67static void NFQUEUE_parse(struct xt_option_call *cb) 68{ 69 xtables_option_parse(cb); 70 if (cb->entry->id == O_QUEUE_BALANCE) 71 xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: " 72 "--queue-balance not supported (kernel too old?)"); 73} 74 75static void NFQUEUE_parse_v1(struct xt_option_call *cb) 76{ 77 struct xt_NFQ_info_v1 *info = cb->data; 78 const uint16_t *r = cb->val.u16_range; 79 80 xtables_option_parse(cb); 81 switch (cb->entry->id) { 82 case O_QUEUE_BALANCE: 83 if (cb->nvals != 2) 84 xtables_error(PARAMETER_PROBLEM, 85 "Bad range \"%s\"", cb->arg); 86 if (r[0] >= r[1]) 87 xtables_error(PARAMETER_PROBLEM, "%u should be less than %u", 88 r[0], r[1]); 89 info->queuenum = r[0]; 90 info->queues_total = r[1] - r[0] + 1; 91 break; 92 } 93} 94 95static void NFQUEUE_parse_v2(struct xt_option_call *cb) 96{ 97 struct xt_NFQ_info_v2 *info = cb->data; 98 99 NFQUEUE_parse_v1(cb); 100 switch (cb->entry->id) { 101 case O_QUEUE_BYPASS: 102 info->bypass = 1; 103 break; 104 } 105} 106 107static void NFQUEUE_parse_v3(struct xt_option_call *cb) 108{ 109 struct xt_NFQ_info_v3 *info = cb->data; 110 111 NFQUEUE_parse_v2(cb); 112 switch (cb->entry->id) { 113 case O_QUEUE_CPU_FANOUT: 114 info->flags |= NFQ_FLAG_CPU_FANOUT; 115 break; 116 } 117} 118 119static void NFQUEUE_print(const void *ip, 120 const struct xt_entry_target *target, int numeric) 121{ 122 const struct xt_NFQ_info *tinfo = 123 (const struct xt_NFQ_info *)target->data; 124 printf(" NFQUEUE num %u", tinfo->queuenum); 125} 126 127static void NFQUEUE_print_v1(const void *ip, 128 const struct xt_entry_target *target, int numeric) 129{ 130 const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data; 131 unsigned int last = tinfo->queues_total; 132 133 if (last > 1) { 134 last += tinfo->queuenum - 1; 135 printf(" NFQUEUE balance %u:%u", tinfo->queuenum, last); 136 } else { 137 printf(" NFQUEUE num %u", tinfo->queuenum); 138 } 139} 140 141static void NFQUEUE_print_v2(const void *ip, 142 const struct xt_entry_target *target, int numeric) 143{ 144 const struct xt_NFQ_info_v2 *info = (void *) target->data; 145 146 NFQUEUE_print_v1(ip, target, numeric); 147 if (info->bypass & NFQ_FLAG_BYPASS) 148 printf(" bypass"); 149} 150 151static void NFQUEUE_print_v3(const void *ip, 152 const struct xt_entry_target *target, int numeric) 153{ 154 const struct xt_NFQ_info_v3 *info = (void *)target->data; 155 156 NFQUEUE_print_v2(ip, target, numeric); 157 if (info->flags & NFQ_FLAG_CPU_FANOUT) 158 printf(" cpu-fanout"); 159} 160 161static void NFQUEUE_save(const void *ip, const struct xt_entry_target *target) 162{ 163 const struct xt_NFQ_info *tinfo = 164 (const struct xt_NFQ_info *)target->data; 165 166 printf(" --queue-num %u", tinfo->queuenum); 167} 168 169static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target) 170{ 171 const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data; 172 unsigned int last = tinfo->queues_total; 173 174 if (last > 1) { 175 last += tinfo->queuenum - 1; 176 printf(" --queue-balance %u:%u", tinfo->queuenum, last); 177 } else { 178 printf(" --queue-num %u", tinfo->queuenum); 179 } 180} 181 182static void NFQUEUE_save_v2(const void *ip, const struct xt_entry_target *target) 183{ 184 const struct xt_NFQ_info_v2 *info = (void *) target->data; 185 186 NFQUEUE_save_v1(ip, target); 187 188 if (info->bypass & NFQ_FLAG_BYPASS) 189 printf(" --queue-bypass"); 190} 191 192static void NFQUEUE_save_v3(const void *ip, 193 const struct xt_entry_target *target) 194{ 195 const struct xt_NFQ_info_v3 *info = (void *)target->data; 196 197 NFQUEUE_save_v2(ip, target); 198 if (info->flags & NFQ_FLAG_CPU_FANOUT) 199 printf(" --queue-cpu-fanout"); 200} 201 202static void NFQUEUE_init_v1(struct xt_entry_target *t) 203{ 204 struct xt_NFQ_info_v1 *tinfo = (void *)t->data; 205 tinfo->queues_total = 1; 206} 207 208static struct xtables_target nfqueue_targets[] = { 209{ 210 .family = NFPROTO_UNSPEC, 211 .name = "NFQUEUE", 212 .version = XTABLES_VERSION, 213 .size = XT_ALIGN(sizeof(struct xt_NFQ_info)), 214 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info)), 215 .help = NFQUEUE_help, 216 .print = NFQUEUE_print, 217 .save = NFQUEUE_save, 218 .x6_parse = NFQUEUE_parse, 219 .x6_options = NFQUEUE_opts 220},{ 221 .family = NFPROTO_UNSPEC, 222 .revision = 1, 223 .name = "NFQUEUE", 224 .version = XTABLES_VERSION, 225 .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v1)), 226 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v1)), 227 .help = NFQUEUE_help_v1, 228 .init = NFQUEUE_init_v1, 229 .print = NFQUEUE_print_v1, 230 .save = NFQUEUE_save_v1, 231 .x6_parse = NFQUEUE_parse_v1, 232 .x6_options = NFQUEUE_opts, 233},{ 234 .family = NFPROTO_UNSPEC, 235 .revision = 2, 236 .name = "NFQUEUE", 237 .version = XTABLES_VERSION, 238 .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v2)), 239 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v2)), 240 .help = NFQUEUE_help_v2, 241 .init = NFQUEUE_init_v1, 242 .print = NFQUEUE_print_v2, 243 .save = NFQUEUE_save_v2, 244 .x6_parse = NFQUEUE_parse_v2, 245 .x6_options = NFQUEUE_opts, 246},{ 247 .family = NFPROTO_UNSPEC, 248 .revision = 3, 249 .name = "NFQUEUE", 250 .version = XTABLES_VERSION, 251 .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v3)), 252 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v3)), 253 .help = NFQUEUE_help_v3, 254 .init = NFQUEUE_init_v1, 255 .print = NFQUEUE_print_v3, 256 .save = NFQUEUE_save_v3, 257 .x6_parse = NFQUEUE_parse_v3, 258 .x6_options = NFQUEUE_opts, 259} 260}; 261 262void _init(void) 263{ 264 xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets)); 265} 266