quota2: add a no-change mode

This commit adds an option to xt_quota2 called "no-change". The
effect of this option, when used, is that it will skip incrementing
or decrementing the quota counter, effectively providing a quota test
only.

The reason for implementing this is so that I could have a rule check
if quota is available for a rule in the PREROUTING tables, without
actually decrementing the amount of available quota. I only wanted to
decrement the amount of available quota in the FORWARD rule.
Otherwise, the first packet of every connection would be counted
twice.
This commit is contained in:
Michael Farrell
2009-12-29 01:53:57 +10:30
committed by Jan Engelhardt
parent c82da14d2b
commit 7952a7d253
5 changed files with 44 additions and 16 deletions

View File

@@ -17,17 +17,19 @@
#include "xt_quota2.h"
enum {
FL_QUOTA = 1 << 0,
FL_NAME = 1 << 1,
FL_GROW = 1 << 2,
FL_PACKET = 1 << 3,
FL_QUOTA = 1 << 0,
FL_NAME = 1 << 1,
FL_GROW = 1 << 2,
FL_PACKET = 1 << 3,
FL_NO_CHANGE = 1 << 4,
};
static const struct option quota_mt2_opts[] = {
{.name = "grow", .has_arg = false, .val = 'g'},
{.name = "name", .has_arg = true, .val = 'n'},
{.name = "quota", .has_arg = true, .val = 'q'},
{.name = "packets", .has_arg = false, .val = 'p'},
{.name = "grow", .has_arg = false, .val = 'g'},
{.name = "no-change", .has_arg = false, .val = 'c'},
{.name = "name", .has_arg = true, .val = 'n'},
{.name = "quota", .has_arg = true, .val = 'q'},
{.name = "packets", .has_arg = false, .val = 'p'},
{NULL},
};
@@ -36,6 +38,7 @@ static void quota_mt2_help(void)
printf(
"quota match options:\n"
" --grow provide an increasing counter\n"
" --no-change never change counter/quota value for matching packets\n"
" --name name name for the file in sysfs\n"
"[!] --quota quota initial quota (bytes or packets)\n"
" --packets count packets instead of bytes\n"
@@ -56,6 +59,12 @@ quota_mt2_parse(int c, char **argv, int invert, unsigned int *flags,
info->flags |= XT_QUOTA_GROW;
*flags |= FL_GROW;
return true;
case 'c': /* no-change */
xtables_param_act(XTF_ONLY_ONCE, "quota", "--no-change", *flags & FL_NO_CHANGE);
xtables_param_act(XTF_NO_INVERT, "quota", "--no-change", invert);
info->flags |= XT_QUOTA_NO_CHANGE;
*flags |= FL_NO_CHANGE;
return true;
case 'n':
/* zero termination done on behalf of the kernel module */
xtables_param_act(XTF_ONLY_ONCE, "quota", "--name", *flags & FL_NAME);
@@ -92,6 +101,8 @@ quota_mt2_save(const void *ip, const struct xt_entry_match *match)
printf("! ");
if (q->flags & XT_QUOTA_GROW)
printf("--grow ");
if (q->flags & XT_QUOTA_NO_CHANGE)
printf("--no-change ");
if (q->flags & XT_QUOTA_PACKET)
printf("--packets ");
if (*q->name != '\0')
@@ -117,6 +128,8 @@ static void quota_mt2_print(const void *ip, const struct xt_entry_match *match,
printf("packets ");
else
printf("bytes ");
if (q->flags & XT_QUOTA_NO_CHANGE)
printf("(no-change mode) ");
}
static struct xtables_match quota_mt2_reg = {

View File

@@ -10,6 +10,12 @@ the match will return false, just like the original "quota" match. In growing
\fB\-\-grow\fP
Count upwards instead of downwards.
.TP
\fB\-\-no\-change\fP
Makes it so the counter or quota amount is never changed by packets matching
this rule. This is only really useful in "quota" mode, as it will allow you to
use complex prerouting rules in association with the quota system, without
counting a packet twice.
.TP
\fB\-\-name\fP \fIname\fP
Assign the counter a specific name. This option must be present, as an empty
name is not allowed. Names starting with a dot or names containing a slash are

View File

@@ -5,4 +5,5 @@ config NETFILTER_XT_MATCH_QUOTA2
This option adds the "quota2" match which is an advanced form of
xt_quota that also allows counting upwards, and where the counter can
be set through procfs. This allows for simple interfacing of
accounting information.
accounting information. It also allows for a test mode without changing
the quota value.

View File

@@ -199,12 +199,19 @@ quota_mt2(const struct sk_buff *skb, const struct xt_match_param *par)
spin_lock_bh(&e->lock);
if (q->flags & XT_QUOTA_GROW) {
e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
q->quota = e->quota;
/*
* While no_change is pointless in "grow" mode, we will
* implement it here simply to have a consistent behavior.
*/
if (!(q->flags & XT_QUOTA_NO_CHANGE)) {
e->quota += (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
q->quota = e->quota;
}
ret = true;
} else {
if (e->quota >= skb->len) {
e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
if (!(q->flags & XT_QUOTA_NO_CHANGE))
e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len;
ret = !ret;
} else {
/* we do not allow even small packets from now on */

View File

@@ -2,10 +2,11 @@
#define _XT_QUOTA_H
enum xt_quota_flags {
XT_QUOTA_INVERT = 1 << 0,
XT_QUOTA_GROW = 1 << 1,
XT_QUOTA_PACKET = 1 << 2,
XT_QUOTA_MASK = 0x7,
XT_QUOTA_INVERT = 1 << 0,
XT_QUOTA_GROW = 1 << 1,
XT_QUOTA_PACKET = 1 << 2,
XT_QUOTA_NO_CHANGE = 1 << 3,
XT_QUOTA_MASK = 0x0F,
};
struct xt_quota_counter;