Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4750005a authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso
Browse files

netfilter: ipset: Fix "don't update counters" mode when counters used at the matching



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

Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent c0453377
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -122,6 +122,8 @@ struct ip_set_ext {
	u64 bytes;
	char *comment;
	u32 timeout;
	u8 packets_op;
	u8 bytes_op;
};

struct ip_set;
@@ -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)
+19 −6
Original line number Diff line number Diff line
@@ -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
+1 −8
Original line number Diff line number Diff line
@@ -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
+25 −0
Original line number Diff line number Diff line
@@ -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.
+14 −23
Original line number Diff line number Diff line
@@ -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);
}

@@ -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;

@@ -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
			/* No match, reset multiple match flag */
			multi = 0;
#endif
			} else
				return mtype_data_match(data, ext,
							mext, set, flags);
		}
#if IPSET_NET_COUNT == 2
		}
@@ -1027,13 +1019,12 @@ 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)))) {
		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;
}
Loading