/* * 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); }