Skip to content

Commit

Permalink
netfilter: ipset: Fix "don't update counters" mode when counters used…
Browse files Browse the repository at this point in the history
… at the matching

The matching of the counters was not taken into account, fixed.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Jozsef Kadlecsik authored and Pablo Neira Ayuso committed Jan 8, 2018
1 parent c045337 commit 4750005
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 128 deletions.
6 changes: 6 additions & 0 deletions include/linux/netfilter/ipset/ip_set.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ struct ip_set_ext {
u64 bytes;
char *comment;
u32 timeout;
u8 packets_op;
u8 bytes_op;
};

struct ip_set;
Expand Down Expand Up @@ -339,6 +341,10 @@ extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext);
extern int ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set,
const void *e, bool active);
extern bool ip_set_match_extensions(struct ip_set *set,
const struct ip_set_ext *ext,
struct ip_set_ext *mext,
u32 flags, void *data);

static inline int
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
Expand Down
25 changes: 19 additions & 6 deletions include/linux/netfilter/ipset/ip_set_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,33 @@ ip_set_get_packets(const struct ip_set_counter *counter)
return (u64)atomic64_read(&(counter)->packets);
}

static inline bool
ip_set_match_counter(u64 counter, u64 match, u8 op)
{
switch (op) {
case IPSET_COUNTER_NONE:
return true;
case IPSET_COUNTER_EQ:
return counter == match;
case IPSET_COUNTER_NE:
return counter != match;
case IPSET_COUNTER_LT:
return counter < match;
case IPSET_COUNTER_GT:
return counter > match;
}
return false;
}

static inline void
ip_set_update_counter(struct ip_set_counter *counter,
const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
const struct ip_set_ext *ext, u32 flags)
{
if (ext->packets != ULLONG_MAX &&
!(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) {
ip_set_add_bytes(ext->bytes, counter);
ip_set_add_packets(ext->packets, counter);
}
if (flags & IPSET_FLAG_MATCH_COUNTERS) {
mext->packets = ip_set_get_packets(counter);
mext->bytes = ip_set_get_bytes(counter);
}
}

static inline bool
Expand Down
9 changes: 1 addition & 8 deletions net/netfilter/ipset/ip_set_bitmap_gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,

if (ret <= 0)
return ret;
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(x, set)))
return 0;
if (SET_WITH_COUNTER(set))
ip_set_update_counter(ext_counter(x, set), ext, mext, flags);
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(x, set), ext, mext, flags);
return 1;
return ip_set_match_extensions(set, ext, mext, flags, x);
}

static int
Expand Down
25 changes: 25 additions & 0 deletions net/netfilter/ipset/ip_set_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,31 @@ ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set,
}
EXPORT_SYMBOL_GPL(ip_set_put_extensions);

bool
ip_set_match_extensions(struct ip_set *set, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags, void *data)
{
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(data, set)))
return false;
if (SET_WITH_COUNTER(set)) {
struct ip_set_counter *counter = ext_counter(data, set);

if (flags & IPSET_FLAG_MATCH_COUNTERS &&
!(ip_set_match_counter(ip_set_get_packets(counter),
mext->packets, mext->packets_op) &&
ip_set_match_counter(ip_set_get_bytes(counter),
mext->bytes, mext->bytes_op)))
return false;
ip_set_update_counter(counter, ext, flags);
}
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(data, set),
ext, mext, flags);
return true;
}
EXPORT_SYMBOL_GPL(ip_set_match_extensions);

/* Creating/destroying/renaming/swapping affect the existence and
* the properties of a set. All of these can be executed from userspace
* only and serialized by the nfnl mutex indirectly from nfnetlink.
Expand Down
37 changes: 14 additions & 23 deletions net/netfilter/ipset/ip_set_hash_gen.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,12 +917,9 @@ static inline int
mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
struct ip_set_ext *mext, struct ip_set *set, u32 flags)
{
if (SET_WITH_COUNTER(set))
ip_set_update_counter(ext_counter(data, set),
ext, mext, flags);
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(data, set),
ext, mext, flags);
if (!ip_set_match_extensions(set, ext, mext, flags, data))
return 0;
/* nomatch entries return -ENOTEMPTY */
return mtype_do_data_match(data);
}

Expand All @@ -941,9 +938,9 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
struct mtype_elem *data;
#if IPSET_NET_COUNT == 2
struct mtype_elem orig = *d;
int i, j = 0, k;
int ret, i, j = 0, k;
#else
int i, j = 0;
int ret, i, j = 0;
#endif
u32 key, multi = 0;

Expand All @@ -969,18 +966,13 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
data = ahash_data(n, i, set->dsize);
if (!mtype_data_equal(data, d, &multi))
continue;
if (SET_WITH_TIMEOUT(set)) {
if (!ip_set_timeout_expired(
ext_timeout(data, set)))
return mtype_data_match(data, ext,
mext, set,
flags);
ret = mtype_data_match(data, ext, mext, set, flags);
if (ret != 0)
return ret;
#ifdef IP_SET_HASH_WITH_MULTI
multi = 0;
/* No match, reset multiple match flag */
multi = 0;
#endif
} else
return mtype_data_match(data, ext,
mext, set, flags);
}
#if IPSET_NET_COUNT == 2
}
Expand Down Expand Up @@ -1027,12 +1019,11 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (!test_bit(i, n->used))
continue;
data = ahash_data(n, i, set->dsize);
if (mtype_data_equal(data, d, &multi) &&
!(SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(data, set)))) {
ret = mtype_data_match(data, ext, mext, set, flags);
if (!mtype_data_equal(data, d, &multi))
continue;
ret = mtype_data_match(data, ext, mext, set, flags);
if (ret != 0)
goto out;
}
}
out:
return ret;
Expand Down
21 changes: 6 additions & 15 deletions net/netfilter/ipset/ip_set_list_set.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,30 +55,21 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
{
struct list_set *map = set->data;
struct ip_set_ext *mext = &opt->ext;
struct set_elem *e;
u32 cmdflags = opt->cmdflags;
u32 flags = opt->cmdflags;
int ret;

/* Don't lookup sub-counters at all */
opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
list_for_each_entry_rcu(e, &map->members, list) {
if (SET_WITH_TIMEOUT(set) &&
ip_set_timeout_expired(ext_timeout(e, set)))
continue;
ret = ip_set_test(e->id, skb, par, opt);
if (ret > 0) {
if (SET_WITH_COUNTER(set))
ip_set_update_counter(ext_counter(e, set),
ext, &opt->ext,
cmdflags);
if (SET_WITH_SKBINFO(set))
ip_set_get_skbinfo(ext_skbinfo(e, set),
ext, &opt->ext,
cmdflags);
return ret;
}
if (ret <= 0)
continue;
if (ip_set_match_extensions(set, ext, mext, flags, e))
return 1;
}
return 0;
}
Expand Down
Loading

0 comments on commit 4750005

Please sign in to comment.