/* Shared library add-on to iptables to add match support for random match. This file is distributed under the terms of the GNU General Public License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL 2001-10-14 Fabrice MARIE : initial development. */ #include #include #include #include #include #include #include #include #include /** * The kernel random routing returns numbers between 0 and 255. * To ease the task of the user in choosing the probability * of matching, we want him to be able to use percentages. * Therefore we have to accept numbers in percentage here, * turn them into number between 0 and 255 for the kernel module, * and turn them back to percentages when we print/save * the rule. */ /* Function which prints out usage message. */ static void help(void) { printf( "random v%s options:\n" " [--average] percent The probability in percentage of the match\n" " If ommited, a probability of 50%% percent is set.\n" " Percentage must be within : 1 <= percent <= 99.\n\n", IPTABLES_VERSION); } static struct option opts[] = { { "average", 1, 0, '1' }, { 0 } }; /* Initialize the target. */ static void init(struct ipt_entry_match *m, unsigned int *nfcache) { struct ipt_rand_info *randinfo = (struct ipt_rand_info *)(m)->data; *nfcache |= NFC_UNKNOWN; /* We assign the average to be 50 which is our default value */ /* 50 * 2.55 = 128 */ randinfo->average = 128; } #define IPT_RAND_OPT_AVERAGE 0x01 /* Function which parses command options; returns true if it ate an option */ static int parse(int c, char **argv, int invert, unsigned int *flags, const struct ipt_entry *entry, unsigned int *nfcache, struct ipt_entry_match **match) { struct ipt_rand_info *randinfo = (struct ipt_rand_info *)(*match)->data; unsigned int num; switch (c) { case '1': /* check for common mistakes... */ if (invert) exit_error(PARAMETER_PROBLEM, "Can't specify ! --average"); if (*flags & IPT_RAND_OPT_AVERAGE) exit_error(PARAMETER_PROBLEM, "Can't specify --average twice"); /* Remember, this function will interpret a leading 0 to be Octal, a leading 0x to be hexdecimal... */ if (string_to_number(optarg, 1, 99, &num) == -1 || num < 1) exit_error(PARAMETER_PROBLEM, "bad --average `%s', must be between 1 and 99", optarg); /* assign the values */ randinfo->average = (int)(num * 2.55); *flags |= IPT_RAND_OPT_AVERAGE; break; default: return 0; } return 1; } /* Final check; nothing. */ static void final_check(unsigned int flags) { } /* Prints out the targinfo. */ static void print(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric) { const struct ipt_rand_info *randinfo = (const struct ipt_rand_info *)match->data; div_t result = div((randinfo->average*100), 255); if (result.rem > 127) /* round up... */ ++result.quot; printf(" random %u%% ", result.quot); } /* Saves the union ipt_targinfo in parsable form to stdout. */ static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) { const struct ipt_rand_info *randinfo = (const struct ipt_rand_info *)match->data; div_t result = div((randinfo->average *100), 255); if (result.rem > 127) /* round up... */ ++result.quot; printf("--average %u ", result.quot); } struct iptables_match rand_match = { NULL, "random", IPTABLES_VERSION, IPT_ALIGN(sizeof(struct ipt_rand_info)), IPT_ALIGN(sizeof(struct ipt_rand_info)), &help, &init, &parse, &final_check, &print, &save, opts }; void _init(void) { register_match(&rand_match); }