X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=extensions%2Flibipt_account.c;fp=extensions%2Flibipt_account.c;h=d049a03df7ffe775b147f6ea0e844eededfc35f5;hb=87eee0d249c8a07ce0c8a64430d8792aacc7870f;hp=0000000000000000000000000000000000000000;hpb=52e4f4e0628f3e80b5dae46faf617c9c78c4e04a;p=iptables.git diff --git a/extensions/libipt_account.c b/extensions/libipt_account.c new file mode 100644 index 0000000..d049a03 --- /dev/null +++ b/extensions/libipt_account.c @@ -0,0 +1,277 @@ +/* + * accounting match helper (libipt_account.c) + * (C) 2003,2004 by Piotr Gasid³o (quaker@barbara.eu.org) + * + * Version: 0.1.6 + * + * This software is distributed under the terms of GNU GPL + */ + +#include +#include +#include +#include +#include + +#include + +#ifndef HIPQUAD +#define HIPQUAD(addr) \ + ((unsigned char *)&addr)[3], \ + ((unsigned char *)&addr)[2], \ + ((unsigned char *)&addr)[1], \ + ((unsigned char *)&addr)[0] +#endif + +static void help(void) { + printf( + "account v%s options:\n" + "--aaddr network/netmask\n" + " defines network/netmask for which make statistics.\n" + "--aname name\n" + " defines name of list where statistics will be kept. If no is\n" + " specified DEFAULT will be used.\n" + "--ashort\n" + " table will colect only short statistics (only total counters\n" + " without splitting it into protocols.\n" + , + IPTABLES_VERSION); +}; + +static struct option opts[] = { + { .name = "aaddr", .has_arg = 1, .flag = NULL, .val = 201 }, + { .name = "aname", .has_arg = 1, .flag = NULL, .val = 202 }, + { .name = "ashort", .has_arg = 0, .flag = NULL, .val = 203 }, + { .name = 0, .has_arg = 0, .flag = 0, .val = 0 } +}; + +/* Helper functions for parse_network */ +int parseip(const char *parameter, u_int32_t *ip) { + + char buffer[16], *bufferptr, *dot; + unsigned int i, shift, part; + + if (strlen(parameter) > 15) + return 0; + + strncpy(buffer, parameter, 15); + buffer[15] = 0; + + bufferptr = buffer; + + for (i = 0, shift = 24, *ip = 0; i < 3; i++, shift -= 8) { + /* no dot */ + if ((dot = strchr(bufferptr, '.')) == NULL) + return 0; + /* not a number */ + if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) + return 0; + /* to big number */ + if (part > 255) + return 0; + *ip |= part << shift; + bufferptr = dot + 1; + } + /* not a number */ + if ((part = strtol(bufferptr, (char**)NULL, 10)) < 0) + return 0; + /* to big number */ + if (part > 255) + return 0; + *ip |= part; + return 1; +} + +static void parsenetwork(const char *parameter, u_int32_t *network) { + if (!parseip(parameter, network)) + exit_error(PARAMETER_PROBLEM, "account: wrong ip in network"); +} + +static void parsenetmaskasbits(const char *parameter, u_int32_t *netmask) { + + u_int32_t bits; + + if ((bits = strtol(parameter, (char **)NULL, 10)) < 0 || bits > 32) + exit_error(PARAMETER_PROBLEM, "account: wrong netmask"); + + *netmask = 0xffffffff << (32 - bits); +} + +static void parsenetmaskasip(const char *parameter, u_int32_t *netmask) { + if (!parseip(parameter, netmask)) + exit_error(PARAMETER_PROBLEM, "account: wrong ip in netmask"); +} + +static void parsenetmask(const char *parameter, u_int32_t *netmask) +{ + if (strchr(parameter, '.') != NULL) + parsenetmaskasip(parameter, netmask); + else + parsenetmaskasbits(parameter, netmask); +} + +static void parsenetworkandnetmask(const char *parameter, u_int32_t *network, u_int32_t *netmask) +{ + + char buffer[32], *slash; + + if (strlen(parameter) > 31) + /* text is to long, even for 255.255.255.255/255.255.255.255 */ + exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); + + strncpy(buffer, parameter, 31); + buffer[31] = 0; + + /* check whether netmask is given */ + if ((slash = strchr(buffer, '/')) != NULL) { + parsenetmask(slash + 1, netmask); + *slash = 0; + } else + *netmask = 0xffffffff; + parsenetwork(buffer, network); + + if ((*network & *netmask) != *network) + exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); +} + + +/* Function gets network & netmask from argument after --aaddr */ +static void parse_network(const char *parameter, struct t_ipt_account_info *info) { + + parsenetworkandnetmask(parameter, &info->network, &info->netmask); + +} + +/* validate netmask */ +inline int valid_netmask(u_int32_t netmask) { + while (netmask & 0x80000000) + netmask <<= 1; + if (netmask != 0) + return 0; + return 1; +} + +/* validate network/netmask pair */ +inline int valid_network_and_netmask(struct t_ipt_account_info *info) { + if (!valid_netmask(info->netmask)) + return 0; + if ((info->network & info->netmask) != info->network) + return 0; + return 1; +} + + + +/* Function initializes match */ +static void init(struct ipt_entry_match *match, + unsigned int *nfcache) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)(match)->data; + + + /* set default table name to DEFAULT */ + strncpy(info->name, "DEFAULT", IPT_ACCOUNT_NAME_LEN); + info->shortlisting = 0; + +} + +/* Function parses match's arguments */ +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 t_ipt_account_info *info = (struct t_ipt_account_info *)(*match)->data; + + switch (c) { + + /* --aaddr */ + case 201: + parse_network(optarg, info); + if (!valid_network_and_netmask(info)) + exit_error(PARAMETER_PROBLEM, "account: wrong network/netmask"); + *flags = 1; + break; + + /* --aname */ + case 202: + if (strlen(optarg) < IPT_ACCOUNT_NAME_LEN) + strncpy(info->name, optarg, IPT_ACCOUNT_NAME_LEN); + else + exit_error(PARAMETER_PROBLEM, "account: Too long table name"); + break; + /* --ashort */ + case 203: + info->shortlisting = 1; + break; + default: + return 0; + } + return 1; +} + +/* Final check whether network/netmask was specified */ +static void final_check(unsigned int flags) { + if (!flags) + exit_error(PARAMETER_PROBLEM, "account: You need specify '--aaddr' parameter"); +} + +/* Function used for printing rule with account match for iptables -L */ +static void print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; + + printf("account: "); + printf("network/netmask: "); + printf("%u.%u.%u.%u/%u.%u.%u.%u ", + HIPQUAD(info->network), + HIPQUAD(info->netmask) + ); + + printf("name: %s ", info->name); + if (info->shortlisting) + printf("short-listing "); +} + +/* Function used for saving rule containing account match */ +static void save(const struct ipt_ip *ip, + const struct ipt_entry_match *match) { + + struct t_ipt_account_info *info = (struct t_ipt_account_info *)match->data; + + printf("--aaddr "); + printf("%u.%u.%u.%u/%u.%u.%u.%u ", + HIPQUAD(info->network), + HIPQUAD(info->netmask) + ); + + printf("--aname %s ", info->name); + if (info->shortlisting) + printf("--ashort "); +} + +static struct iptables_match account = { + .next = NULL, + .name = "account", + .version = IPTABLES_VERSION, + .size = IPT_ALIGN(sizeof(struct t_ipt_account_info)), + .userspacesize = IPT_ALIGN(sizeof(struct t_ipt_account_info)), + .help = &help, + .init = &init, + .parse = &parse, + .final_check = &final_check, + .print = &print, + .save = &save, + .extra_opts = opts +}; + +/* Function which registers match */ +void _init(void) +{ + register_match(&account); +} +