1 /* Shared library add-on to iptables for NFQ 2 * 3 * (C) 2005 by Harald Welte <laforge (at) 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 12 enum { 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 20 static 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 29 static 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 36 static 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 44 static 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 55 static 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 63 static 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 83 static 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 95 static 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 103 static 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 117 static 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 127 static 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 135 static 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 148 static 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 158 static 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 164 static 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 205 void _init(void) 206 { 207 xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets)); 208 } 209