add userspace dump filter
Subsystems (2)
RFC PATCH 1/1 add userspace dump filter
Hello,
I tried to filter dump by zone in userspace. But it seems for me that CTA_ZONE is classified larger class than CTA_MARK, then I think it allows to be filtered in kernel like CTA_MARK/CTA_MARK_MASK.
Which is preferable way?
--------
This patch adds more type to filter_dump, working in userspace, just only for nf_callback_register, not nf_callback_register2.
--- include/internal/object.h | 5 +++ include/internal/types.h | 4 ++- .../libnetfilter_conntrack.h | 6 ++++ src/callback.c | 4 +-- src/conntrack/api.c | 41 ++++++++++++++++++++-- src/conntrack/filter_dump.c | 17 +++++++++ 6 files changed, 72 insertions(+), 5 deletions(-)
include/internal/object.h +5 -0
@@ -49,6 +49,10 @@ struct nfct_handle {struct __data_container {struct nfct_handle *h;enum nf_conntrack_msg_type type; +int (*cb)(enum nf_conntrack_msg_type type, +struct nf_conntrack *ct, +void *data); +struct nf_conntrack *filter_ct;void *data; };
@@ -284,6 +288,7 @@ struct nfct_filter {struct nfct_filter_dump {struct nfct_filter_dump_mark mark;u_int8_t l3num; +struct nf_conntrack *ct;u_int32_t set; };
include/internal/types.h +3 -1
@@ -15,7 +15,9 @@ typedef int (*getobjopt)(const struct nf_conntrack *ct);typedef void (*setobjopt )(struct nf_conntrack *ct);typedef void (*set_attr_grp )(struct nf_conntrack *ct,const void *value);typedef void (*get_attr_grp )(const struct nf_conntrack *ct,void *data); -typedef void (*set_filter_dump_attr )(struct nfct_filter_dump *filter_dump,const void *value); +typedef void (*set_filter_dump_attr )(struct nfct_filter_dump *filter_dump, +const enum nfct_filter_dump_attr type, +const void *value);/* * expectation types
include/libnetfilter_conntrack/libnetfilter_conntrack.h +6 -0
@@ -536,9 +536,15 @@ struct nfct_filter_dump_mark {enum nfct_filter_dump_attr {NFCT_FILTER_DUMP_MARK =0 ,/* struct nfct_filter_dump_mark */ NFCT_FILTER_DUMP_L3NUM ,/* u_int8_t */ +NFCT_FILTER_DUMP_L4PROTO ,/* u_int8_t */ +NFCT_FILTER_DUMP_ZONE ,/* u_int16_t */ NFCT_FILTER_DUMP_MAX }; +#define NFCT_FILTER_DUMP_USER \ + (1 << NFCT_FILTER_DUMP_ZONE | \ + 1 << NFCT_FILTER_DUMP_L4PROTO) +struct nfct_filter_dump *nfct_filter_dump_create (void );void nfct_filter_dump_destroy (struct nfct_filter_dump *filter);
src/callback.c +2 -2
@@ -54,8 +54,8 @@ int __callback(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data)__parse_conntrack (nlh, nfa, ct); -if (container->h->cb) { - ret = container->h->cb (type, ct, container->data); +if (container->cb) { + ret = container->cb (type, ct, container->data); }else if (container->h->cb2) { ret = container->h->cb2 (nlh, type, ct, container->data);
src/conntrack/api.c +39 -2
77 lines not on this page · raw message
src/conntrack/filter_dump.c +17 -0
@@ -11,6 +11,7 @@static void set_filter_dump_attr_mark (struct nfct_filter_dump *filter_dump, +const enum nfct_filter_dump_attr type,const void *value) {const struct nfct_filter_dump_mark *this = value;
@@ -21,14 +22,30 @@ set_filter_dump_attr_mark(struct nfct_filter_dump *filter_dump,static void set_filter_dump_attr_family (struct nfct_filter_dump *filter_dump, +const enum nfct_filter_dump_attr type,const void *value) { filter_dump->l3num = *((u_int8_t *)value); } +const enum nf_conntrack_attr simple_dump_attr_array[] = { + [NFCT_FILTER_DUMP_ZONE ] =ATTR_ZONE , + [NFCT_FILTER_DUMP_L4PROTO ] =ATTR_L4PROTO , +}; + +static void +set_filter_dump_attr_simple (struct nfct_filter_dump *filter_dump, +const enum nfct_filter_dump_attr type, +const void *value) +{ +nfct_set_attr (filter_dump->ct, simple_dump_attr_array[type], value); +} +const set_filter_dump_attr set_filter_dump_attr_array[NFCT_FILTER_DUMP_MAX ] = { [NFCT_FILTER_DUMP_MARK ] = set_filter_dump_attr_mark, [NFCT_FILTER_DUMP_L3NUM ] = set_filter_dump_attr_family, + [NFCT_FILTER_DUMP_ZONE ] = set_filter_dump_attr_simple, + [NFCT_FILTER_DUMP_L4PROTO ] = set_filter_dump_attr_simple, }; void __build_filter_dump(struct nfnlhdr *req, size_t size,
Signature · 1 line
1.9.1
Pablo Neira Ayuso
maintainerQuoted 11 lines · Ken-ichirou MATSUZAWA
Hello,
I tried to filter dump by zone in userspace. But it seems for me that
CTA_ZONEis classified larger class thanCTA_MARK, then I think it allows to be filtered in kernel like CTA_MARK/CTA_MARK_MASK.Which is preferable way?
--------
This patch adds more type to
filter_dump, working in userspace,
If this works from userspace, then you can just filter out the conntracks from the callback handler itself. So I don't think this patch is the way to go.
The kernel side filtering aims to reduce the time to dump conntrack tables with lots of entries. If you want to add filtering by zone in the ctnetlink_dump_table path, you have to generalize the existing ctnetlink code.
My suggestion is to rework ctnetlink_dump_filter to make it look like (just quick code, I didn't even compile test it):
struct ctnetlink_dump_filter {
enum ctnetlink_filter_key key;
u_int32_t data;
u_int32_t mask;
};The keys can be:
enum ctnetlink_filter_key {
CTNL_FILTER_MARK = 0,
CTNL_FILTER_ZONE,
};
Then, from ctnetlink_dump_table() you'll need to do something like:
if (filter) {
data = ctnetlink_fetch_key(ct, filter->key);
if (!(data & filter->mask == filter->data))
continue;
}The ctnetlink_fetch_key() should look like:
static u_int32_t ctnetlink_fetch_key(const struct nf_conn *ct, u_int32_t key)
{
u_int32_t ret;
switch (key) {
case CTNL_FILTER_MARK:
ret = ct->mark;
case CTNL_FILTER_ZONE:
ret = ct->zone;
}
return ret;
}Please, if you work on this, first send us a patch to generalize the filtering "framework" for ctnetlink dumps and then add the filtering by zone.
Thank you for your understandable explanation.
2014-06-18 17:59 GMT+09:00 Pablo Neira Ayuso <[email protected]>:
Quoted 4 lines · Ken-ichirou MATSUZAWA
Please, if you work on this, first send us a patch to generalize the filtering "framework" for ctnetlink dumps and then add the filtering by zone.
How about using sk_filter? I could have understood it's not efficient than the way you told me but BPF seems more versatile and can work on the socket which both dumping and listening event.
# I think your nfct-daemon.c example in libmnl
Also I know this changes dump behavior, I need to include an indication in nla or somewhere which distinguishes from normal dump, but it's not included.
--------
This patch enables dump filtering by bpf. It is not efficient since every nf_conn needs to be translated into skb, but it can be used both event and dump socket.
--- net/netfilter/nf_conntrack_netlink.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
net/netfilter/nf_conntrack_netlink.c +18 -2
@@ -831,10 +831,26 @@ restart: cb->nlh->nlmsg_seq,NFNL_MSG_TYPE (cb->nlh->nlmsg_type), ct); -rcu_read_unlock (); -if (res <0 ) { +if (res >=0 ) { +struct sk_filter *skfilter + =rcu_dereference (skb->sk->sk_filter); +int ret =0 ; + +if (skfilter !=NULL ) { +skb_pull (skb, cb->args[2 ]); + ret =SK_RUN_FILTER (skfilter, skb); +skb_push (skb, cb->args[2 ]); +if (ret) + cb->args[2 ] = res; +else +skb_trim (skb, cb->args[2 ]); + } +rcu_read_unlock (); + }else { +rcu_read_unlock ();nf_conntrack_get (&ct->ct_general); cb->args[1 ] = (unsigned long )ct; + cb->args[2 ] =0 ;spin_unlock (lockp); goto out; }
Signature · 1 line
1.7.10.4
Pablo Neira Ayuso
maintainerQuoted 9 lines · Ken-ichirou MATSUZAWA
2014-06-18 17:59 GMT+09:00 Pablo Neira Ayuso <[email protected]>:
Quoted 4 lines · Ken-ichirou MATSUZAWA
Please, if you work on this, first send us a patch to generalize the filtering "framework" for ctnetlink dumps and then add the filtering by zone.
How about using
sk_filter? I could have understood it's not efficient than the way you told me but BPF seems more versatile and can work on the socket which both dumping and listening event.
The main reason for bpf in the event path was ENOBUFS. You can overrun the socket buffer easily with a high rate of events coming from interrupt context.
In the dump path, we have quite a lot more bandwidth since everything is running from user context and the table is dumped in chunks of one memory page. The motivation for the filtering was to reduce the time to dump large table.
Quoted 38 lines
net/netfilter/nf_conntrack_netlink.c +18
-2@@ -831,10 +831,26 @@ restart: cb->nlh->nlmsg_seq,NFNL_MSG_TYPE (cb->nlh->nlmsg_type), ct); -rcu_read_unlock (); -if (res <0 ) { +if (res >=0 ) { +struct sk_filter *skfilter + =rcu_dereference (skb->sk->sk_filter); +int ret =0 ; + +if (skfilter !=NULL ) { +skb_pull (skb, cb->args[2 ]); + ret =SK_RUN_FILTER (skfilter, skb); +skb_push (skb, cb->args[2 ]); +if (ret) + cb->args[2 ] = res; +else +skb_trim (skb, cb->args[2 ]); + } +rcu_read_unlock (); + }else { +rcu_read_unlock ();nf_conntrack_get (&ct->ct_general); cb->args[1 ] = (unsigned long )ct; + cb->args[2 ] =0 ;spin_unlock (lockp);net/netfilter/nf_conntrack_netlink.c +0
-0goto out; }Signature · 1 line
1.7.10.4