Skip to content

Commit 6e01781

Browse files
Jozsef Kadlecsikummakynes
authored andcommitted
netfilter: ipset: set match: add support to match the counters
The new revision of the set match supports to match the counters and to suppress updating the counters at matching too. At the set:list types, the updating of the subcounters can be suppressed as well. Signed-off-by: Jozsef Kadlecsik <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent de76303 commit 6e01781

File tree

6 files changed

+120
-9
lines changed

6 files changed

+120
-9
lines changed

include/linux/netfilter/ipset/ip_set.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct ip_set;
7676

7777
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
7878
const struct ip_set_ext *ext,
79-
struct ip_set_ext *mext, u32 flags);
79+
struct ip_set_ext *mext, u32 cmdflags);
8080

8181
/* Kernel API function options */
8282
struct ip_set_adt_opt {
@@ -217,10 +217,15 @@ ip_set_update_counter(struct ip_set_counter *counter,
217217
const struct ip_set_ext *ext,
218218
struct ip_set_ext *mext, u32 flags)
219219
{
220-
if (ext->packets != ULLONG_MAX) {
220+
if (ext->packets != ULLONG_MAX &&
221+
!(flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) {
221222
ip_set_add_bytes(ext->bytes, counter);
222223
ip_set_add_packets(ext->packets, counter);
223224
}
225+
if (flags & IPSET_FLAG_MATCH_COUNTERS) {
226+
mext->packets = ip_set_get_packets(counter);
227+
mext->bytes = ip_set_get_bytes(counter);
228+
}
224229
}
225230

226231
static inline bool

include/uapi/linux/netfilter/ipset/ip_set.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,28 @@ enum ipset_errno {
145145
IPSET_ERR_TYPE_SPECIFIC = 4352,
146146
};
147147

148-
/* Flags at command level */
148+
/* Flags at command level or match/target flags, lower half of cmdattrs*/
149149
enum ipset_cmd_flags {
150150
IPSET_FLAG_BIT_EXIST = 0,
151151
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
152152
IPSET_FLAG_BIT_LIST_SETNAME = 1,
153153
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
154154
IPSET_FLAG_BIT_LIST_HEADER = 2,
155155
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
156-
IPSET_FLAG_CMD_MAX = 15, /* Lower half */
156+
IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE = 3,
157+
IPSET_FLAG_SKIP_COUNTER_UPDATE =
158+
(1 << IPSET_FLAG_BIT_SKIP_COUNTER_UPDATE),
159+
IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE = 4,
160+
IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE =
161+
(1 << IPSET_FLAG_BIT_SKIP_SUBCOUNTER_UPDATE),
162+
IPSET_FLAG_BIT_MATCH_COUNTERS = 5,
163+
IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS),
164+
IPSET_FLAG_BIT_RETURN_NOMATCH = 7,
165+
IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH),
166+
IPSET_FLAG_CMD_MAX = 15,
157167
};
158168

159-
/* Flags at CADT attribute level */
169+
/* Flags at CADT attribute level, upper half of cmdattrs */
160170
enum ipset_cadt_flags {
161171
IPSET_FLAG_BIT_BEFORE = 0,
162172
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
@@ -166,7 +176,7 @@ enum ipset_cadt_flags {
166176
IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
167177
IPSET_FLAG_BIT_WITH_COUNTERS = 3,
168178
IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
169-
IPSET_FLAG_CADT_MAX = 15, /* Upper half */
179+
IPSET_FLAG_CADT_MAX = 15,
170180
};
171181

172182
/* Commands with settype-specific attributes */
@@ -195,6 +205,7 @@ enum ip_set_dim {
195205
* If changed, new revision of iptables match/target is required.
196206
*/
197207
IPSET_DIM_MAX = 6,
208+
/* Backward compatibility: set match revision 2 */
198209
IPSET_BIT_RETURN_NOMATCH = 7,
199210
};
200211

@@ -207,6 +218,18 @@ enum ip_set_kopt {
207218
IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
208219
};
209220

221+
enum {
222+
IPSET_COUNTER_NONE = 0,
223+
IPSET_COUNTER_EQ,
224+
IPSET_COUNTER_NE,
225+
IPSET_COUNTER_LT,
226+
IPSET_COUNTER_GT,
227+
};
228+
229+
struct ip_set_counter_match {
230+
__u8 op;
231+
__u64 value;
232+
};
210233

211234
/* Interface to iptables/ip6tables */
212235

include/uapi/linux/netfilter/xt_set.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,13 @@ struct xt_set_info_target_v2 {
6262
__u32 timeout;
6363
};
6464

65+
/* Revision 3 match */
66+
67+
struct xt_set_info_match_v3 {
68+
struct xt_set_info match_set;
69+
struct ip_set_counter_match packets;
70+
struct ip_set_counter_match bytes;
71+
__u32 flags;
72+
};
73+
6574
#endif /*_XT_SET_H*/

net/netfilter/ipset/ip_set_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
413413
ret = 1;
414414
} else {
415415
/* --return-nomatch: invert matched element */
416-
if ((opt->flags & IPSET_RETURN_NOMATCH) &&
416+
if ((opt->cmdflags & IPSET_FLAG_RETURN_NOMATCH) &&
417417
(set->type->features & IPSET_TYPE_NOMATCH) &&
418418
(ret > 0 || ret == -ENOTEMPTY))
419419
ret = -ret;

net/netfilter/ipset/ip_set_list_set.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,13 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
8484
{
8585
struct list_set *map = set->data;
8686
struct set_elem *e;
87-
u32 i;
87+
u32 i, cmdflags = opt->cmdflags;
8888
int ret;
8989

90+
/* Don't lookup sub-counters at all */
91+
opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
92+
if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
93+
opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
9094
for (i = 0; i < map->size; i++) {
9195
e = list_set_elem(map, i);
9296
if (e->id == IPSET_INVALID_ID)
@@ -99,7 +103,7 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
99103
if (SET_WITH_COUNTER(set))
100104
ip_set_update_counter(ext_counter(e, map),
101105
ext, &opt->ext,
102-
opt->cmdflags);
106+
cmdflags);
103107
return ret;
104108
}
105109
}

net/netfilter/xt_set.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
189189
ADT_OPT(opt, par->family, info->match_set.dim,
190190
info->match_set.flags, 0, UINT_MAX);
191191

192+
if (opt.flags & IPSET_RETURN_NOMATCH)
193+
opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
194+
192195
return match_set(info->match_set.index, skb, par, &opt,
193196
info->match_set.flags & IPSET_INV_MATCH);
194197
}
@@ -317,6 +320,52 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
317320
#define set_target_v2_checkentry set_target_v1_checkentry
318321
#define set_target_v2_destroy set_target_v1_destroy
319322

323+
/* Revision 3 match */
324+
325+
static bool
326+
match_counter(u64 counter, const struct ip_set_counter_match *info)
327+
{
328+
switch (info->op) {
329+
case IPSET_COUNTER_NONE:
330+
return true;
331+
case IPSET_COUNTER_EQ:
332+
return counter == info->value;
333+
case IPSET_COUNTER_NE:
334+
return counter != info->value;
335+
case IPSET_COUNTER_LT:
336+
return counter < info->value;
337+
case IPSET_COUNTER_GT:
338+
return counter > info->value;
339+
}
340+
return false;
341+
}
342+
343+
static bool
344+
set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
345+
{
346+
const struct xt_set_info_match_v3 *info = par->matchinfo;
347+
ADT_OPT(opt, par->family, info->match_set.dim,
348+
info->match_set.flags, info->flags, UINT_MAX);
349+
int ret;
350+
351+
if (info->packets.op != IPSET_COUNTER_NONE ||
352+
info->bytes.op != IPSET_COUNTER_NONE)
353+
opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
354+
355+
ret = match_set(info->match_set.index, skb, par, &opt,
356+
info->match_set.flags & IPSET_INV_MATCH);
357+
358+
if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
359+
return ret;
360+
361+
if (!match_counter(opt.ext.packets, &info->packets))
362+
return 0;
363+
return match_counter(opt.ext.bytes, &info->bytes);
364+
}
365+
366+
#define set_match_v3_checkentry set_match_v1_checkentry
367+
#define set_match_v3_destroy set_match_v1_destroy
368+
320369
static struct xt_match set_matches[] __read_mostly = {
321370
{
322371
.name = "set",
@@ -369,6 +418,27 @@ static struct xt_match set_matches[] __read_mostly = {
369418
.destroy = set_match_v1_destroy,
370419
.me = THIS_MODULE
371420
},
421+
/* counters support: update, match */
422+
{
423+
.name = "set",
424+
.family = NFPROTO_IPV4,
425+
.revision = 3,
426+
.match = set_match_v3,
427+
.matchsize = sizeof(struct xt_set_info_match_v3),
428+
.checkentry = set_match_v3_checkentry,
429+
.destroy = set_match_v3_destroy,
430+
.me = THIS_MODULE
431+
},
432+
{
433+
.name = "set",
434+
.family = NFPROTO_IPV6,
435+
.revision = 3,
436+
.match = set_match_v3,
437+
.matchsize = sizeof(struct xt_set_info_match_v3),
438+
.checkentry = set_match_v3_checkentry,
439+
.destroy = set_match_v3_destroy,
440+
.me = THIS_MODULE
441+
},
372442
};
373443

374444
static struct xt_target set_targets[] __read_mostly = {

0 commit comments

Comments
 (0)