Commit 0cebe4b4 authored by Patrick McHardy's avatar Patrick McHardy

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: default avatarPatrick McHardy <kaber@trash.net>
parent 858b3133
...@@ -74,6 +74,24 @@ enum ip_conntrack_status { ...@@ -74,6 +74,24 @@ enum ip_conntrack_status {
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), 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__ #ifdef __KERNEL__
struct ip_conntrack_stat { struct ip_conntrack_stat {
unsigned int searched; unsigned int searched;
......
...@@ -12,28 +12,12 @@ ...@@ -12,28 +12,12 @@
#include <linux/netfilter/nf_conntrack_tuple_common.h> #include <linux/netfilter/nf_conntrack_tuple_common.h>
#include <net/netfilter/nf_conntrack_extend.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 { struct nf_conntrack_ecache {
unsigned long cache; /* bitops want long */ unsigned long cache; /* bitops want long */
unsigned long missed; /* missed events */ unsigned long missed; /* missed events */
u32 pid; /* netlink pid of destroyer */ 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 * static inline struct nf_conntrack_ecache *
...@@ -43,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct) ...@@ -43,14 +27,24 @@ nf_ct_ecache_find(const struct nf_conn *ct)
} }
static inline struct nf_conntrack_ecache * 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 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 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 #ifdef CONFIG_NF_CONNTRACK_EVENTS
...@@ -83,6 +77,9 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) ...@@ -83,6 +77,9 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
if (e == NULL) if (e == NULL)
return; return;
if (!(e->ctmask & (1 << event)))
return;
set_bit(event, &e->cache); set_bit(event, &e->cache);
} }
...@@ -93,7 +90,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask, ...@@ -93,7 +90,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
int report) int report)
{ {
int ret = 0; int ret = 0;
struct net *net = nf_ct_net(ct);
struct nf_ct_event_notifier *notify; struct nf_ct_event_notifier *notify;
struct nf_conntrack_ecache *e; struct nf_conntrack_ecache *e;
...@@ -102,9 +98,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask, ...@@ -102,9 +98,6 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
if (notify == NULL) if (notify == NULL)
goto out_unlock; goto out_unlock;
if (!net->ct.sysctl_events)
goto out_unlock;
e = nf_ct_ecache_find(ct); e = nf_ct_ecache_find(ct);
if (e == NULL) if (e == NULL)
goto out_unlock; goto out_unlock;
...@@ -118,6 +111,9 @@ nf_conntrack_eventmask_report(unsigned int eventmask, ...@@ -118,6 +111,9 @@ nf_conntrack_eventmask_report(unsigned int eventmask,
/* This is a resent of a destroy event? If so, skip missed */ /* This is a resent of a destroy event? If so, skip missed */
unsigned long missed = e->pid ? 0 : e->missed; unsigned long missed = e->pid ? 0 : e->missed;
if (!((eventmask | missed) & e->ctmask))
goto out_unlock;
ret = notify->fcn(eventmask | missed, &item); ret = notify->fcn(eventmask | missed, &item);
if (unlikely(ret < 0 || missed)) { if (unlikely(ret < 0 || missed)) {
spin_lock_bh(&ct->lock); spin_lock_bh(&ct->lock);
...@@ -173,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event, ...@@ -173,18 +169,19 @@ nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
u32 pid, u32 pid,
int report) int report)
{ {
struct net *net = nf_ct_exp_net(exp);
struct nf_exp_event_notifier *notify; struct nf_exp_event_notifier *notify;
struct nf_conntrack_ecache *e;
rcu_read_lock(); rcu_read_lock();
notify = rcu_dereference(nf_expect_event_cb); notify = rcu_dereference(nf_expect_event_cb);
if (notify == NULL) if (notify == NULL)
goto out_unlock; goto out_unlock;
if (!net->ct.sysctl_events) e = nf_ct_ecache_find(exp->master);
if (e == NULL)
goto out_unlock; goto out_unlock;
{ if (e->expmask & (1 << event)) {
struct nf_exp_event item = { struct nf_exp_event item = {
.exp = exp, .exp = exp,
.pid = pid, .pid = pid,
......
...@@ -648,7 +648,7 @@ init_conntrack(struct net *net, ...@@ -648,7 +648,7 @@ init_conntrack(struct net *net,
} }
nf_ct_acct_ext_add(ct, GFP_ATOMIC); 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); spin_lock_bh(&nf_conntrack_lock);
exp = nf_ct_find_expectation(net, tuple); exp = nf_ct_find_expectation(net, tuple);
......
...@@ -1281,7 +1281,7 @@ ctnetlink_create_conntrack(struct net *net, ...@@ -1281,7 +1281,7 @@ ctnetlink_create_conntrack(struct net *net,
} }
nf_ct_acct_ext_add(ct, GFP_ATOMIC); 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 defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK]) if (cda[CTA_MARK])
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment