From 4f37d48f03bec7bf5e23a6e8b313c1285578c958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Gasid=C5=82o?= Date: Wed, 17 Mar 2004 14:40:03 +0000 Subject: add userspace support for 'ipt_account' match (Piotr Gasid'o) --- extensions/.account-test | 3 + extensions/libipt_account.c | 244 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100755 extensions/.account-test create mode 100644 extensions/libipt_account.c (limited to 'extensions') diff --git a/extensions/.account-test b/extensions/.account-test new file mode 100755 index 00000000..68aeb166 --- /dev/null +++ b/extensions/.account-test @@ -0,0 +1,3 @@ +#!/bin/sh +# True if account match patch is applied. +[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_account.h ] && echo account diff --git a/extensions/libipt_account.c b/extensions/libipt_account.c new file mode 100644 index 00000000..ef25d778 --- /dev/null +++ b/extensions/libipt_account.c @@ -0,0 +1,244 @@ +/* + * accounting match helper (libipt_account.c) + * (C) 2003,2004 by Piotr Gasidło (quaker@barbara.eu.org) + * + * Version: 0.1.5 + * + * 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" + + , + IPTABLES_VERSION); +}; + +static struct option opts[] = { + { "aaddr", 1, NULL, 201 }, + { "aname", 1, NULL, 202 }, + { 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); + +} + +/* 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; + + *nfcache |= NFC_UNKNOWN; + + /* set default table name to DEFAULT */ + strncpy(info->name, "DEFAULT", IPT_ACCOUNT_NAME_LEN); + +} + +/* 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); + *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 list name"); + 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); +} + +/* 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); +} + +static struct iptables_match account = { + NULL, /* struct iptables_match *next; */ + "account", /* ipt_chainlabel name; */ + IPTABLES_VERSION, /* const char *version; */ + IPT_ALIGN(sizeof(struct t_ipt_account_info)), /* Size of match data. */ + IPT_ALIGN(sizeof(struct t_ipt_account_info)), /* Size of match data relevent for userspace comparison purposes */ + &help, /* Function which prints out usage message. */ + &init, /* Initialize the match. */ + &parse, /* Function which parses command options; returns true if it ate an option */ + &final_check, /* Final check; exit if not ok. */ + &print, /* Prints out the match iff non-NULL: put space at end */ + &save, /* Saves the match info in parsable form to stdout. */ + opts /* Pointer to list of extra command-line options */ +}; + +/* Function which registers match */ +void _init(void) +{ + register_match(&account); +} + -- cgit v1.2.3