Patrick McHardy | 10e0fbb | 2006-08-31 14:01:35 +0000 | [diff] [blame] | 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 <iptables.h> |
| 9 | #include <linux/netfilter/xt_statistic.h> |
| 10 | |
| 11 | static void |
| 12 | help(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", |
| 23 | IPTABLES_VERSION); |
| 24 | } |
| 25 | |
| 26 | static 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 | |
| 34 | static struct xt_statistic_info *info; |
| 35 | |
| 36 | static int |
| 37 | parse(int c, char **argv, int invert, unsigned int *flags, |
| 38 | const struct ipt_entry *entry, |
| 39 | unsigned int *nfcache, |
| 40 | struct ipt_entry_match **match) |
| 41 | { |
| 42 | double prob; |
| 43 | |
| 44 | info = (void *)(*match)->data; |
| 45 | |
| 46 | if (invert) |
| 47 | info->flags |= XT_STATISTIC_INVERT; |
| 48 | |
| 49 | switch (c) { |
| 50 | case '1': |
| 51 | if (*flags & 0x1) |
| 52 | exit_error(PARAMETER_PROBLEM, "double --mode"); |
| 53 | if (!strcmp(optarg, "random")) |
| 54 | info->mode = XT_STATISTIC_MODE_RANDOM; |
| 55 | else if (!strcmp(optarg, "nth")) |
| 56 | info->mode = XT_STATISTIC_MODE_NTH; |
| 57 | else |
| 58 | exit_error(PARAMETER_PROBLEM, "Bad mode `%s'", optarg); |
| 59 | *flags |= 0x1; |
| 60 | break; |
| 61 | case '2': |
| 62 | if (*flags & 0x2) |
| 63 | exit_error(PARAMETER_PROBLEM, "double --probability"); |
| 64 | prob = atof(optarg); |
| 65 | if (prob < 0 || prob > 1) |
| 66 | exit_error(PARAMETER_PROBLEM, |
| 67 | "--probability must be between 0 and 1"); |
| 68 | info->u.random.probability = 0x80000000 * prob; |
| 69 | *flags |= 0x2; |
| 70 | break; |
| 71 | case '3': |
| 72 | if (*flags & 0x4) |
| 73 | exit_error(PARAMETER_PROBLEM, "double --every"); |
| 74 | if (string_to_number(optarg, 0, 0xFFFFFFFF, |
| 75 | &info->u.nth.every) == -1) |
| 76 | exit_error(PARAMETER_PROBLEM, |
| 77 | "cannot parse --every `%s'", optarg); |
| 78 | if (info->u.nth.every == 0) |
| 79 | exit_error(PARAMETER_PROBLEM, "--every cannot be 0"); |
| 80 | info->u.nth.every--; |
| 81 | *flags |= 0x4; |
| 82 | break; |
| 83 | case '4': |
| 84 | if (*flags & 0x8) |
| 85 | exit_error(PARAMETER_PROBLEM, "double --packet"); |
| 86 | if (string_to_number(optarg, 0, 0xFFFFFFFF, |
| 87 | &info->u.nth.packet) == -1) |
| 88 | exit_error(PARAMETER_PROBLEM, |
| 89 | "cannot parse --packet `%s'", optarg); |
| 90 | *flags |= 0x8; |
| 91 | break; |
| 92 | default: |
| 93 | return 0; |
| 94 | } |
| 95 | return 1; |
| 96 | } |
| 97 | |
| 98 | /* Final check; must have specified --mark. */ |
| 99 | static void |
| 100 | final_check(unsigned int flags) |
| 101 | { |
| 102 | if (!(flags & 0x1)) |
| 103 | exit_error(PARAMETER_PROBLEM, "no mode specified"); |
| 104 | if ((flags & 0x2) && (flags & (0x4 | 0x8))) |
| 105 | exit_error(PARAMETER_PROBLEM, |
| 106 | "both nth and random parameters given"); |
| 107 | if (flags & 0x2 && info->mode != XT_STATISTIC_MODE_RANDOM) |
| 108 | exit_error(PARAMETER_PROBLEM, |
| 109 | "--probability can only be used in random mode"); |
| 110 | if (flags & 0x4 && info->mode != XT_STATISTIC_MODE_NTH) |
| 111 | exit_error(PARAMETER_PROBLEM, |
| 112 | "--every can only be used in nth mode"); |
| 113 | if (flags & 0x8 && info->mode != XT_STATISTIC_MODE_NTH) |
| 114 | exit_error(PARAMETER_PROBLEM, |
| 115 | "--packet can only be used in nth mode"); |
Nicolas Bouliane | 0c6bf10 | 2007-07-03 12:52:55 +0000 | [diff] [blame] | 116 | if ((flags & 0x8) && !(flags & 0x4)) |
| 117 | exit_error(PARAMETER_PROBLEM, |
| 118 | "--packet can only be used with --every"); |
| 119 | /* at this point, info->u.nth.every have been decreased. */ |
| 120 | if (!(info->u.nth.packet >= 0 && info->u.nth.packet <= info->u.nth.every)) |
| 121 | exit_error(PARAMETER_PROBLEM, |
| 122 | "the --packet p must be 0 <= p <= n-1"); |
| 123 | |
| 124 | |
Patrick McHardy | 10e0fbb | 2006-08-31 14:01:35 +0000 | [diff] [blame] | 125 | info->u.nth.count = info->u.nth.every - info->u.nth.packet; |
| 126 | } |
| 127 | |
| 128 | /* Prints out the matchinfo. */ |
| 129 | static void print_match(const struct xt_statistic_info *info, char *prefix) |
| 130 | { |
| 131 | if (info->flags & XT_STATISTIC_INVERT) |
| 132 | printf("! "); |
| 133 | |
| 134 | switch (info->mode) { |
| 135 | case XT_STATISTIC_MODE_RANDOM: |
| 136 | printf("%smode random %sprobability %f ", prefix, prefix, |
| 137 | 1.0 * info->u.random.probability / 0x80000000); |
| 138 | break; |
| 139 | case XT_STATISTIC_MODE_NTH: |
| 140 | printf("%smode nth %severy %u ", prefix, prefix, |
| 141 | info->u.nth.every + 1); |
| 142 | if (info->u.nth.packet) |
| 143 | printf("%spacket %u ", prefix, info->u.nth.packet); |
| 144 | break; |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | static void |
| 149 | print(const struct ipt_ip *ip, |
| 150 | const struct ipt_entry_match *match, |
| 151 | int numeric) |
| 152 | { |
| 153 | struct xt_statistic_info *info = (struct xt_statistic_info *)match->data; |
| 154 | |
| 155 | printf("statistic "); |
| 156 | print_match(info, ""); |
| 157 | } |
| 158 | |
| 159 | /* Saves the union ipt_matchinfo in parsable form to stdout. */ |
| 160 | static void |
| 161 | save(const struct ipt_ip *ip, const struct ipt_entry_match *match) |
| 162 | { |
| 163 | struct xt_statistic_info *info = (struct xt_statistic_info *)match->data; |
| 164 | |
| 165 | print_match(info, "--"); |
| 166 | } |
| 167 | |
| 168 | static struct iptables_match statistic = { |
| 169 | .name = "statistic", |
| 170 | .version = IPTABLES_VERSION, |
| 171 | .size = IPT_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 | |
| 181 | void _init(void) |
| 182 | { |
| 183 | register_match(&statistic); |
| 184 | } |