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 F_QUEUE_NUM = 1 << O_QUEUE_NUM, 17 F_QUEUE_BALANCE = 1 << O_QUEUE_BALANCE, 18}; 19 20static void NFQUEUE_help(void) 21{ 22 printf( 23"NFQUEUE target options\n" 24" --queue-num value Send packet to QUEUE number <value>.\n" 25" Valid queue numbers are 0-65535\n" 26); 27} 28 29static void NFQUEUE_help_v1(void) 30{ 31 NFQUEUE_help(); 32 printf( 33" --queue-balance first:last Balance flows between queues <value> to <value>.\n"); 34} 35 36static void NFQUEUE_help_v2(void) 37{ 38 NFQUEUE_help_v1(); 39 printf( 40" --queue-bypass Bypass Queueing if no queue instance exists.\n"); 41} 42 43#define s struct xt_NFQ_info 44static const struct xt_option_entry NFQUEUE_opts[] = { 45 {.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16, 46 .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum), 47 .excl = F_QUEUE_BALANCE}, 48 {.name = "queue-balance", .id = O_QUEUE_BALANCE, 49 .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM}, 50 {.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE}, 51 XTOPT_TABLEEND, 52}; 53#undef s 54 55static void NFQUEUE_parse(struct xt_option_call *cb) 56{ 57 xtables_option_parse(cb); 58 if (cb->entry->id == O_QUEUE_BALANCE) 59 xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: " 60 "--queue-balance not supported (kernel too old?)"); 61} 62 63static void NFQUEUE_parse_v1(struct xt_option_call *cb) 64{ 65 struct xt_NFQ_info_v1 *info = cb->data; 66 const uint16_t *r = cb->val.u16_range; 67 68 xtables_option_parse(cb); 69 switch (cb->entry->id) { 70 case O_QUEUE_BALANCE: 71 if (cb->nvals != 2) 72 xtables_error(PARAMETER_PROBLEM, 73 "Bad range \"%s\"", cb->arg); 74 if (r[0] >= r[1]) 75 xtables_error(PARAMETER_PROBLEM, "%u should be less than %u", 76 r[0], r[1]); 77 info->queuenum = r[0]; 78 info->queues_total = r[1] - r[0] + 1; 79 break; 80 } 81} 82 83static void NFQUEUE_parse_v2(struct xt_option_call *cb) 84{ 85 struct xt_NFQ_info_v2 *info = cb->data; 86 87 NFQUEUE_parse_v1(cb); 88 switch (cb->entry->id) { 89 case O_QUEUE_BYPASS: 90 info->bypass = 1; 91 break; 92 } 93} 94 95static void NFQUEUE_print(const void *ip, 96 const struct xt_entry_target *target, int numeric) 97{ 98 const struct xt_NFQ_info *tinfo = 99 (const struct xt_NFQ_info *)target->data; 100 printf(" NFQUEUE num %u", tinfo->queuenum); 101} 102 103static void NFQUEUE_print_v1(const void *ip, 104 const struct xt_entry_target *target, int numeric) 105{ 106 const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data; 107 unsigned int last = tinfo->queues_total; 108 109 if (last > 1) { 110 last += tinfo->queuenum - 1; 111 printf(" NFQUEUE balance %u:%u", tinfo->queuenum, last); 112 } else { 113 printf(" NFQUEUE num %u", tinfo->queuenum); 114 } 115} 116 117static void NFQUEUE_print_v2(const void *ip, 118 const struct xt_entry_target *target, int numeric) 119{ 120 const struct xt_NFQ_info_v2 *info = (void *) target->data; 121 122 NFQUEUE_print_v1(ip, target, numeric); 123 if (info->bypass) 124 printf(" bypass"); 125} 126 127static void NFQUEUE_save(const void *ip, const struct xt_entry_target *target) 128{ 129 const struct xt_NFQ_info *tinfo = 130 (const struct xt_NFQ_info *)target->data; 131 132 printf(" --queue-num %u", tinfo->queuenum); 133} 134 135static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target) 136{ 137 const struct xt_NFQ_info_v1 *tinfo = (const void *)target->data; 138 unsigned int last = tinfo->queues_total; 139 140 if (last > 1) { 141 last += tinfo->queuenum - 1; 142 printf(" --queue-balance %u:%u", tinfo->queuenum, last); 143 } else { 144 printf(" --queue-num %u", tinfo->queuenum); 145 } 146} 147 148static void NFQUEUE_save_v2(const void *ip, const struct xt_entry_target *target) 149{ 150 const struct xt_NFQ_info_v2 *info = (void *) target->data; 151 152 NFQUEUE_save_v1(ip, target); 153 154 if (info->bypass) 155 printf("--queue-bypass "); 156} 157 158static void NFQUEUE_init_v1(struct xt_entry_target *t) 159{ 160 struct xt_NFQ_info_v1 *tinfo = (void *)t->data; 161 tinfo->queues_total = 1; 162} 163 164static struct xtables_target nfqueue_targets[] = { 165{ 166 .family = NFPROTO_UNSPEC, 167 .name = "NFQUEUE", 168 .version = XTABLES_VERSION, 169 .size = XT_ALIGN(sizeof(struct xt_NFQ_info)), 170 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info)), 171 .help = NFQUEUE_help, 172 .print = NFQUEUE_print, 173 .save = NFQUEUE_save, 174 .x6_parse = NFQUEUE_parse, 175 .x6_options = NFQUEUE_opts 176},{ 177 .family = NFPROTO_UNSPEC, 178 .revision = 1, 179 .name = "NFQUEUE", 180 .version = XTABLES_VERSION, 181 .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v1)), 182 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v1)), 183 .help = NFQUEUE_help_v1, 184 .init = NFQUEUE_init_v1, 185 .print = NFQUEUE_print_v1, 186 .save = NFQUEUE_save_v1, 187 .x6_parse = NFQUEUE_parse_v1, 188 .x6_options = NFQUEUE_opts, 189},{ 190 .family = NFPROTO_UNSPEC, 191 .revision = 2, 192 .name = "NFQUEUE", 193 .version = XTABLES_VERSION, 194 .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v2)), 195 .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v2)), 196 .help = NFQUEUE_help_v2, 197 .init = NFQUEUE_init_v1, 198 .print = NFQUEUE_print_v2, 199 .save = NFQUEUE_save_v2, 200 .x6_parse = NFQUEUE_parse_v2, 201 .x6_options = NFQUEUE_opts, 202} 203}; 204 205void _init(void) 206{ 207 xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets)); 208} 209