netfilter: ctnetlink: support selective event delivery
Add two masks for conntrack end expectation events to struct nf_conntrack_ecache and use them to filter events. Their default value is "all events" when the event sysctl is on and "no events" when it is off. A following patch will add specific initializations. Expectation events depend on the ecache struct of their master conntrack. Signed-off-by: Patrick McHardy <kaber@trash.net>
This commit is contained in:
Родитель
858b313300
Коммит
0cebe4b416
|
@ -74,6 +74,24 @@ enum ip_conntrack_status {
|
|||
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
|
||||
};
|
||||
|
||||
/* Connection tracking event types */
|
||||
enum ip_conntrack_events {
|
||||
IPCT_NEW, /* new conntrack */
|
||||
IPCT_RELATED, /* related conntrack */
|
||||
IPCT_DESTROY, /* destroyed conntrack */
|
||||
IPCT_REPLY, /* connection has seen two-way traffic */
|
||||
IPCT_ASSURED, /* connection status has changed to assured */
|
||||
IPCT_PROTOINFO, /* protocol information has changed */
|
||||
IPCT_HELPER, /* new helper has been set */
|
||||
IPCT_MARK, /* new mark has been set */
|
||||
IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
|
||||
IPCT_SECMARK, /* new security mark has been set */
|
||||
};
|
||||
|
||||
enum ip_conntrack_expect_events {
|
||||
IPEXP_NEW, /* new expectation */
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
struct ip_conntrack_stat {
|
||||
unsigned int searched;
|
||||
|
|
|
@ -12,28 +12,12 @@
|
|||
#include <linux/netfilter/nf_conntrack_tuple_common.h>
|
||||
#include <net/netfilter/nf_conntrack_extend.h>
|
||||
|
||||
/* Connection tracking event types */
|
||||
enum ip_conntrack_events {
|
||||
IPCT_NEW, /* new conntrack */
|
||||
IPCT_RELATED, /* related conntrack */
|
||||
IPCT_DESTROY, /* destroyed conntrack */
|
||||
IPCT_REPLY, /* connection has seen two-way traffic */
|
||||
IPCT_ASSURED, /* connection status has changed to assured */
|
||||
IPCT_PROTOINFO, /* protocol information has changed */
|
||||
IPCT_HELPER, /* new helper has been set */
|
||||
IPCT_MARK, /* new mark has been set */
|
||||
IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
|
||||
IPCT_SECMARK, /* new security mark has been set */
|
||||
};
|
||||
|
||||
enum ip_conntrack_expect_events {
|
||||
IPEXP_NEW, /* new expectation */
|
||||
};
|
||||
|
||||
struct nf_conntrack_ecache {
|
||||
unsigned long cache; /* bitops want long */
|
||||
unsigned long missed; /* missed events */
|
||||
u32 pid; /* netlink pid of destroyer */
|
||||
unsigned long cache; /* bitops want long */
|
||||
unsigned long missed; /* missed events */
|
||||
u16 ctmask; /* bitmask of ct events to be delivered */
|
||||
u16 expmask; /* bitmask of expect events to be delivered */
|
||||
u32 pid; /* netlink pid of destroyer */
|
||||
};
|
||||
|
||||
static inline struct nf_conntrack_ecache *
|
||||
|
@ -43,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct)
|
|||
}
|
||||
|
||||
static inline struct nf_conntrack_ecache *
|
||||
nf_ct_ecache_ext_add(struct nf_conn *ct, gfp_t gfp)
|
||||
nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
|
||||
{
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct nf_conntrack_ecache *e;
|
||||
|
||||
if (!net->ct.sysctl_events)
|
||||
if (!ctmask && !expmask && net->ct.sysctl_events) {
|
||||
ctmask = ~0;
|
||||
expmask = ~0;
|
||||
}
|
||||
if (!ctmask && !expmask)
|
||||
return NULL;
|
||||
|
||||
return nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
|
||||
e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
|
||||
if (e) {
|
||||
e->ctmask = ctmask;
|
||||
e->expmask = expmask;
|
||||
}
|
||||
return e;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
|
@ -83,6 +77,9 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
|
|||
if (e == NULL)
|
||||
return;
|
||||
|
||||
if (!(e->ctmask & (1 << event)))
|
||||
return;
|
||||
|
||||
set_bit(event, &e->cache);
|
||||
}
|
||||
|
||||
|
@ -93,7 +90,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
|
|||
int report)
|
||||
{
|
||||
int ret = 0;
|
||||
struct net *net = nf_ct_net(ct);
|
||||
struct nf_ct_event_notifier *notify;
|
||||
struct nf_conntrack_ecache *e;
|
||||
|
||||
|
@ -102,9 +98,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
|
|||
if (notify == NULL)
|
||||
goto out_unlock;
|
||||
|
||||
if (!net->ct.sysctl_events)
|
||||
goto out_unlock;
|
||||
|
||||
e = nf_ct_ecache_find(ct);
|
||||
if (e == NULL)
|
||||
goto out_unlock;
|
||||
|
@ -118,6 +111,9 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
|
|||
/* This is a resent of a destroy event? If so, skip missed */
|
||||
unsigned long missed = e->pid ? 0 : e->missed;
|
||||
|
||||
if (!((eventmask | missed) & e->ctmask))
|
||||
goto out_unlock;
|
||||
|
||||
ret = notify->fcn(eventmask | missed, &item);
|
||||
if (unlikely(ret < 0 || missed)) {
|
||||
spin_lock_bh(&ct->lock);
|
||||
|
@ -173,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
|
|||
u32 pid,
|
||||
int report)
|
||||
{
|
||||
struct net *net = nf_ct_exp_net(exp);
|
||||
struct nf_exp_event_notifier *notify;
|
||||
struct nf_conntrack_ecache *e;
|
||||
|
||||
rcu_read_lock();
|
||||
notify = rcu_dereference(nf_expect_event_cb);
|
||||
if (notify == NULL)
|
||||
goto out_unlock;
|
||||
|
||||
if (!net->ct.sysctl_events)
|
||||
e = nf_ct_ecache_find(exp->master);
|
||||
if (e == NULL)
|
||||
goto out_unlock;
|
||||
|
||||
{
|
||||
if (e->expmask & (1 << event)) {
|
||||
struct nf_exp_event item = {
|
||||
.exp = exp,
|
||||
.pid = pid,
|
||||
|
|
|
@ -648,7 +648,7 @@ init_conntrack(struct net *net,
|
|||
}
|
||||
|
||||
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
|
||||
nf_ct_ecache_ext_add(ct, GFP_ATOMIC);
|
||||
nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
|
||||
|
||||
spin_lock_bh(&nf_conntrack_lock);
|
||||
exp = nf_ct_find_expectation(net, tuple);
|
||||
|
|
|
@ -1281,7 +1281,7 @@ ctnetlink_create_conntrack(struct net *net,
|
|||
}
|
||||
|
||||
nf_ct_acct_ext_add(ct, GFP_ATOMIC);
|
||||
nf_ct_ecache_ext_add(ct, GFP_ATOMIC);
|
||||
nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
|
||||
|
||||
#if defined(CONFIG_NF_CONNTRACK_MARK)
|
||||
if (cda[CTA_MARK])
|
||||
|
|
Загрузка…
Ссылка в новой задаче