216 lines
4.8 KiB
C
216 lines
4.8 KiB
C
/*
|
|
* netquota match (libipt_netquota.c)
|
|
* netfilter userspace part (iptables)
|
|
*
|
|
* by Olaf Rempel <razzor at kopf minus tisch dot de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <stddef.h> /* offsetof() ... */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <iptables.h>
|
|
#include <string.h>
|
|
#include <getopt.h>
|
|
|
|
#include <linux/netfilter_ipv4/ipt_netquota.h>
|
|
|
|
static void help(void)
|
|
{
|
|
printf("netquota v%s options:\n"
|
|
"--nq-name name\n"
|
|
" defines name of this netquota. defaults to \"DEFAULT\".\n"
|
|
"--nq-src network/netmask\n"
|
|
" defines a netquota by source IP address.\n"
|
|
"--nq-dst network/netmask\n"
|
|
" defines a netquota by destination IP address.\n",
|
|
IPTABLES_VERSION);
|
|
};
|
|
|
|
static struct option opts[] = {
|
|
{"nq-src", 1, NULL, 's'},
|
|
{"nq-dst", 1, NULL, 'd'},
|
|
{"nq-name", 1, NULL, 'n'},
|
|
{0}
|
|
};
|
|
|
|
/* Function which initializes the match */
|
|
static void init(struct ipt_entry_match *match, unsigned int *nfcache)
|
|
{
|
|
struct ipt_netquota_info *info =
|
|
(struct ipt_netquota_info *)match->data;
|
|
|
|
/* set default table name to DEFAULT */
|
|
strncpy(info->name, "DEFAULT", IPT_NETQUOTA_NAME_LEN);
|
|
|
|
*nfcache |= NFC_UNKNOWN;
|
|
}
|
|
|
|
/* Function which parses the 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 ipt_netquota_info *info =
|
|
(struct ipt_netquota_info *)(*match)->data;
|
|
struct in_addr *addrs = NULL, mask;
|
|
unsigned int naddrs = 0, i;
|
|
|
|
switch (c) {
|
|
case 'n':
|
|
/* --nq-name */
|
|
if (strlen(optarg) < IPT_NETQUOTA_NAME_LEN)
|
|
strncpy(info->name, optarg, IPT_NETQUOTA_NAME_LEN);
|
|
else
|
|
exit_error(PARAMETER_PROBLEM,
|
|
"netquota: Quota name too long");
|
|
break;
|
|
|
|
case 's':
|
|
/* --nq-src */
|
|
parse_hostnetworkmask(optarg, &addrs, &mask, &naddrs);
|
|
if (naddrs > 0) {
|
|
info->network = ntohl(addrs->s_addr);
|
|
info->netmask = ntohl(mask.s_addr);
|
|
info->mode |= IPT_NETQUOTA_SRC_MATCH;
|
|
for (i = 0; i < naddrs; i++)
|
|
free(&addrs[i]);
|
|
*flags |= 1;
|
|
} else {
|
|
exit_error(PARAMETER_PROBLEM,
|
|
"netquota: Invalid '--nq-src' parameter");
|
|
}
|
|
break;
|
|
|
|
case 'd':
|
|
/* --nq-dst */
|
|
parse_hostnetworkmask(optarg, &addrs, &mask, &naddrs);
|
|
if (naddrs > 0) {
|
|
info->network = ntohl(addrs->s_addr);
|
|
info->netmask = ntohl(mask.s_addr);
|
|
info->mode |= IPT_NETQUOTA_DST_MATCH;
|
|
for (i = 0; i < naddrs; i++)
|
|
free(&addrs[i]);
|
|
*flags |= 2;
|
|
} else {
|
|
exit_error(PARAMETER_PROBLEM,
|
|
"netquota: Invalid '--nq-dst' parameter");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* Final check whether network/netmask was specified */
|
|
static void final_check(unsigned int flags)
|
|
{
|
|
switch (flags) {
|
|
case 0:
|
|
exit_error(PARAMETER_PROBLEM,
|
|
"netquota: You must specify a '--nq-src' or '--nq-dst' "
|
|
"parameter");
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
return;
|
|
break;
|
|
|
|
case 3:
|
|
exit_error(PARAMETER_PROBLEM,
|
|
"netquota: You can only specify either a"
|
|
" '--nq-src' or a '--nq-dst' parameter");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Host byte order IP address to dotted string */
|
|
static char *haddr_to_dotted(u_int32_t ip)
|
|
{
|
|
struct in_addr tmp;
|
|
tmp.s_addr = htonl(ip);
|
|
return addr_to_dotted(&tmp);
|
|
}
|
|
|
|
/* Host byte order network mask to CIDR / dotted string */
|
|
static char *hmask_to_dotted(u_int32_t mask)
|
|
{
|
|
struct in_addr tmp;
|
|
tmp.s_addr = htonl(mask);
|
|
return mask_to_dotted(&tmp);
|
|
}
|
|
|
|
/* Function used for printing a rule with iptables -L */
|
|
static void
|
|
print(const struct ipt_ip *ip, const struct ipt_entry_match *match, int numeric)
|
|
{
|
|
struct ipt_netquota_info *info =
|
|
(struct ipt_netquota_info *)match->data;
|
|
|
|
printf("netquota: %s ", info->name);
|
|
|
|
switch (info->mode) {
|
|
case IPT_NETQUOTA_SRC_MATCH:
|
|
printf("src");
|
|
break;
|
|
|
|
case IPT_NETQUOTA_DST_MATCH:
|
|
printf("dst");
|
|
break;
|
|
}
|
|
|
|
printf("(%s%s)", haddr_to_dotted(info->network),
|
|
hmask_to_dotted(info->netmask));
|
|
}
|
|
|
|
/* Function used for saving a rule with iptables-save */
|
|
static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
|
|
{
|
|
struct ipt_netquota_info *info =
|
|
(struct ipt_netquota_info *)match->data;
|
|
|
|
printf("--nq-name %s ", info->name);
|
|
|
|
switch (info->mode) {
|
|
case IPT_NETQUOTA_SRC_MATCH:
|
|
printf("--nq-src ");
|
|
break;
|
|
|
|
case IPT_NETQUOTA_DST_MATCH:
|
|
printf("--nq-dst ");
|
|
break;
|
|
}
|
|
|
|
printf("%s%s", haddr_to_dotted(info->network),
|
|
hmask_to_dotted(info->netmask));
|
|
}
|
|
|
|
static struct iptables_match netquota = {
|
|
NULL,
|
|
"netquota",
|
|
IPTABLES_VERSION,
|
|
IPT_ALIGN(sizeof(struct ipt_netquota_info)),
|
|
offsetof(struct ipt_netquota_info, mode),
|
|
&help,
|
|
&init,
|
|
&parse,
|
|
&final_check,
|
|
&print,
|
|
&save,
|
|
opts
|
|
};
|
|
|
|
/* Function which registers the match */
|
|
void _init(void)
|
|
{
|
|
register_match(&netquota);
|
|
}
|