libxt_statistic.c revision ea146a982e26c42f9954f140276f8deeb2edbe98
1#include <stdio.h> 2#include <netdb.h> 3#include <string.h> 4#include <stdlib.h> 5#include <stddef.h> 6#include <getopt.h> 7 8#include <xtables.h> 9#include <linux/netfilter/xt_statistic.h> 10 11static void 12help(void) 13{ 14 printf( 15"statistic match v%s options:\n" 16" --mode mode Match mode (random, nth)\n" 17" random mode:\n" 18" --probability p Probability\n" 19" nth mode:\n" 20" --every n Match every nth packet\n" 21" --packet p Initial counter value (0 <= p <= n-1, default 0)\n" 22"\n", 23IPTABLES_VERSION); 24} 25 26static const struct option opts[] = { 27 { "mode", 1, 0, '1' }, 28 { "probability", 1, 0, '2' }, 29 { "every", 1, 0, '3' }, 30 { "packet", 1, 0, '4' }, 31 { 0 } 32}; 33 34static struct xt_statistic_info *info; 35 36static int 37parse(int c, char **argv, int invert, unsigned int *flags, 38 const void *entry, 39 struct xt_entry_match **match) 40{ 41 double prob; 42 43 info = (void *)(*match)->data; 44 45 if (invert) 46 info->flags |= XT_STATISTIC_INVERT; 47 48 switch (c) { 49 case '1': 50 if (*flags & 0x1) 51 exit_error(PARAMETER_PROBLEM, "double --mode"); 52 if (!strcmp(optarg, "random")) 53 info->mode = XT_STATISTIC_MODE_RANDOM; 54 else if (!strcmp(optarg, "nth")) 55 info->mode = XT_STATISTIC_MODE_NTH; 56 else 57 exit_error(PARAMETER_PROBLEM, "Bad mode `%s'", optarg); 58 *flags |= 0x1; 59 break; 60 case '2': 61 if (*flags & 0x2) 62 exit_error(PARAMETER_PROBLEM, "double --probability"); 63 prob = atof(optarg); 64 if (prob < 0 || prob > 1) 65 exit_error(PARAMETER_PROBLEM, 66 "--probability must be between 0 and 1"); 67 info->u.random.probability = 0x80000000 * prob; 68 *flags |= 0x2; 69 break; 70 case '3': 71 if (*flags & 0x4) 72 exit_error(PARAMETER_PROBLEM, "double --every"); 73 if (string_to_number(optarg, 0, 0xFFFFFFFF, 74 &info->u.nth.every) == -1) 75 exit_error(PARAMETER_PROBLEM, 76 "cannot parse --every `%s'", optarg); 77 if (info->u.nth.every == 0) 78 exit_error(PARAMETER_PROBLEM, "--every cannot be 0"); 79 info->u.nth.every--; 80 *flags |= 0x4; 81 break; 82 case '4': 83 if (*flags & 0x8) 84 exit_error(PARAMETER_PROBLEM, "double --packet"); 85 if (string_to_number(optarg, 0, 0xFFFFFFFF, 86 &info->u.nth.packet) == -1) 87 exit_error(PARAMETER_PROBLEM, 88 "cannot parse --packet `%s'", optarg); 89 *flags |= 0x8; 90 break; 91 default: 92 return 0; 93 } 94 return 1; 95} 96 97/* Final check; must have specified --mark. */ 98static void 99final_check(unsigned int flags) 100{ 101 if (!(flags & 0x1)) 102 exit_error(PARAMETER_PROBLEM, "no mode specified"); 103 if ((flags & 0x2) && (flags & (0x4 | 0x8))) 104 exit_error(PARAMETER_PROBLEM, 105 "both nth and random parameters given"); 106 if (flags & 0x2 && info->mode != XT_STATISTIC_MODE_RANDOM) 107 exit_error(PARAMETER_PROBLEM, 108 "--probability can only be used in random mode"); 109 if (flags & 0x4 && info->mode != XT_STATISTIC_MODE_NTH) 110 exit_error(PARAMETER_PROBLEM, 111 "--every can only be used in nth mode"); 112 if (flags & 0x8 && info->mode != XT_STATISTIC_MODE_NTH) 113 exit_error(PARAMETER_PROBLEM, 114 "--packet can only be used in nth mode"); 115 if ((flags & 0x8) && !(flags & 0x4)) 116 exit_error(PARAMETER_PROBLEM, 117 "--packet can only be used with --every"); 118 /* at this point, info->u.nth.every have been decreased. */ 119 if (!(info->u.nth.packet >= 0 && info->u.nth.packet <= info->u.nth.every)) 120 exit_error(PARAMETER_PROBLEM, 121 "the --packet p must be 0 <= p <= n-1"); 122 123 124 info->u.nth.count = info->u.nth.every - info->u.nth.packet; 125} 126 127/* Prints out the matchinfo. */ 128static void print_match(const struct xt_statistic_info *info, char *prefix) 129{ 130 if (info->flags & XT_STATISTIC_INVERT) 131 printf("! "); 132 133 switch (info->mode) { 134 case XT_STATISTIC_MODE_RANDOM: 135 printf("%smode random %sprobability %f ", prefix, prefix, 136 1.0 * info->u.random.probability / 0x80000000); 137 break; 138 case XT_STATISTIC_MODE_NTH: 139 printf("%smode nth %severy %u ", prefix, prefix, 140 info->u.nth.every + 1); 141 if (info->u.nth.packet) 142 printf("%spacket %u ", prefix, info->u.nth.packet); 143 break; 144 } 145} 146 147static void 148print(const void *ip, 149 const struct xt_entry_match *match, 150 int numeric) 151{ 152 struct xt_statistic_info *info = (struct xt_statistic_info *)match->data; 153 154 printf("statistic "); 155 print_match(info, ""); 156} 157 158/* Saves the union ipt_matchinfo in parsable form to stdout. */ 159static void 160save(const void *ip, const struct xt_entry_match *match) 161{ 162 struct xt_statistic_info *info = (struct xt_statistic_info *)match->data; 163 164 print_match(info, "--"); 165} 166 167static struct xtables_match statistic = { 168 .family = AF_INET, 169 .name = "statistic", 170 .version = IPTABLES_VERSION, 171 .size = XT_ALIGN(sizeof(struct xt_statistic_info)), 172 .userspacesize = offsetof(struct xt_statistic_info, u.nth.count), 173 .help = help, 174 .parse = parse, 175 .final_check = final_check, 176 .print = print, 177 .save = save, 178 .extra_opts = opts 179}; 180 181static struct xtables_match statistic6 = { 182 .family = AF_INET6, 183 .name = "statistic", 184 .version = IPTABLES_VERSION, 185 .size = XT_ALIGN(sizeof(struct xt_statistic_info)), 186 .userspacesize = offsetof(struct xt_statistic_info, u.nth.count), 187 .help = help, 188 .parse = parse, 189 .final_check = final_check, 190 .print = print, 191 .save = save, 192 .extra_opts = opts 193}; 194 195void _init(void) 196{ 197 xtables_register_match(&statistic); 198 xtables_register_match(&statistic6); 199} 200