send conntrack events on ctnetlink actions
Subsystems (2)
Pablo Neira Ayuso
maintainerPATCH 7/8 send conntrack events on ctnetlink actions
Currently only conntrack events generated by the conntrack core are delivered to userspace via ctnetlink. This patch force the generation of event notifications on ctnetlink actions.
Example scenario: you have two process listening to ctnetlink and one of them creates/changes/destroy a conntrack upon certain events
Signature · 1 line
The dawn of the fourth age of Linux firewalling is coming; a time of great struggle and heroic deeds -- J.Kadlecsik got inspired by J.Morris
[CTNETLINK] send conntrack events on ctnetlink actions
Currently only conntrack events generated by the conntrack core are delivered to userspace via ctnetlink. This patch force the generation of event notifications on ctnetlink actions.
Example scenario: you have two process listening to ctnetlink and one of them creates/changes/destroy a conntrack upon certain events
net/netfilter/nf_conntrack_netlink.c +68 -27
@@ -798,6 +798,11 @@ ctnetlink_del_conntrack(struct sock *ctnif (del_timer (&ct->timeout)) ct->timeout.function ((unsigned long )ct); +/* +* destroy_conntrack() throws IPCT_DESTROY events, +* so do not call nf_conntrack_event here again +*/ +nf_ct_put (ct);DEBUGP ("leaving\n" );
@@ -1030,7 +1035,9 @@ ctnetlink_change_protoinfo(struct nf_con }static int -ctnetlink_change_conntrack (struct nf_conn *ct,struct nfattr *cda[]) +ctnetlink_change_conntrack (struct nf_conn *ct, +struct nfattr *cda[], +unsigned int *changelog) {int err;
@@ -1040,39 +1047,49 @@ ctnetlink_change_conntrack(struct nf_con err =ctnetlink_change_helper (ct, cda);if (err <0 )return err; + *changelog |=IPCT_HELPER ; }if (cda[CTA_TIMEOUT -1 ]) { err =ctnetlink_change_timeout (ct, cda);if (err <0 )return err; + *changelog |=IPCT_REFRESH ; }if (cda[CTA_STATUS -1 ]) { err =ctnetlink_change_status (ct, cda);if (err <0 )return err; + *changelog |=IPCT_STATUS ; }if (cda[CTA_PROTOINFO -1 ]) { err =ctnetlink_change_protoinfo (ct, cda);if (err <0 )return err; + *changelog |=IPCT_PROTOINFO ; }#if defined(CONFIG_NF_CONNTRACK_MARK ) -if (cda[CTA_MARK -1 ]) +if (cda[CTA_MARK -1 ]) { ct->mark =ntohl (*(u_int32_t *)NFA_DATA (cda[CTA_MARK -1 ])); + *changelog |=IPCT_MARK ; + }#endif +/* make sure this conntrack does not vanish on event notification */ +atomic_inc (&ct->ct_general.use); +DEBUGP ("all done\n" );return 0 ; } -static int +static struct nf_conn *ctnetlink_create_conntrack (struct nfattr *cda[],struct nf_conntrack_tuple *otuple, -struct nf_conntrack_tuple *rtuple) +struct nf_conntrack_tuple *rtuple, +unsigned int *changelog) {struct nf_conn *ct;struct nf_conn_help *help;
@@ -1082,7 +1099,7 @@ ctnetlink_create_conntrack(struct nfattr ct =nf_conntrack_alloc (otuple, rtuple);if (ct ==NULL ||IS_ERR (ct)) -return -ENOMEM ; +return ERR_PTR (-ENOMEM );if (!cda[CTA_TIMEOUT -1 ]) goto err;
@@ -1095,29 +1112,39 @@ ctnetlink_create_conntrack(struct nfattrif (err <0 ) goto err; + *changelog |=IPCT_REFRESH |IPCT_STATUS ; +if (cda[CTA_PROTOINFO -1 ]) { err =ctnetlink_change_protoinfo (ct, cda);if (err <0 ) -return err; + goto err; + *changelog |=IPCT_PROTOINFO ; }#if defined(CONFIG_NF_CONNTRACK_MARK ) -if (cda[CTA_MARK -1 ]) +if (cda[CTA_MARK -1 ]) { ct->mark =ntohl (*(u_int32_t *)NFA_DATA (cda[CTA_MARK -1 ])); + *changelog |=IPCT_MARK ; + }#endif help =nfct_help (ct); -if (help) +if (help) { help->helper =nf_ct_helper_find (rtuple); + *changelog |=IPCT_HELPER ; + }nf_conntrack_hash_insert (ct);add_timer (&ct->timeout); +/* make sure this conntrack does not vanish on event notification */ +atomic_inc (&ct->ct_general.use); +DEBUGP ("conntrack with id %u inserted\n" , ct->id); -return 0 ; +return ct; err:nf_conntrack_free (ct); -return err; +return ERR_PTR (err); } static int
@@ -1126,8 +1153,10 @@ ctnetlink_new_conntrack(struct sock *ctn {struct nf_conntrack_tuple otuple, rtuple;struct nf_conntrack_tuple_hash *h =NULL ; +struct nf_conn *ct =NULL ;struct nfgenmsg *nfmsg =NLMSG_DATA (nlh);u_int8_t u3 = nfmsg->nfgen_family; +unsigned int changelog =0 ;int err =0 ;DEBUGP ("entered %s\n" , __FUNCTION__);
@@ -1156,28 +1185,40 @@ ctnetlink_new_conntrack(struct sock *ctnif (h ==NULL ) {DEBUGP ("no such conntrack, create new\n" ); err = -ENOENT ; -if (nlh->nlmsg_flags &NLM_F_CREATE ) - err =ctnetlink_create_conntrack (cda, &otuple, &rtuple); +if (nlh->nlmsg_flags &NLM_F_CREATE ) { + ct =ctnetlink_create_conntrack (cda, + &otuple, + &rtuple, + &changelog); + err =0 ; +if (IS_ERR (ct)) + err =PTR_ERR (ct); + }write_unlock_bh (&nf_conntrack_lock); -return err; - } -/* implicit 'else' */ + changelog |=IPCT_NEW ; + }else { + ct =nf_ct_tuplehash_to_ctrack (h); +/* we only allow nat config for new conntracks */ +if (cda[CTA_NAT_SRC -1 ] || cda[CTA_NAT_DST -1 ]) { +write_unlock_bh (&nf_conntrack_lock); +return -EINVAL ; + } -/* we only allow nat config for new conntracks */ -if (cda[CTA_NAT_SRC -1 ] || cda[CTA_NAT_DST -1 ]) { - err = -EINVAL ; - goto out_unlock; +/* We manipulate the conntrack inside the global conntrack +* table lock, so there's no need to increase the refcount */ +DEBUGP ("conntrack found\n" ); + err = -EEXIST ; +if (!(nlh->nlmsg_flags &NLM_F_EXCL )) + err =ctnetlink_change_conntrack (ct, cda, &changelog); +write_unlock_bh (&nf_conntrack_lock); } -/* We manipulate the conntrack inside the global conntrack table lock, -* so there's no need to increase the refcount */ -DEBUGP ("conntrack found\n" ); - err = -EEXIST ; -if (!(nlh->nlmsg_flags &NLM_F_EXCL )) - err =ctnetlink_change_conntrack (nf_ct_tuplehash_to_ctrack (h), cda); +/* if everything went fine, notify others about the new conntrack */ +if (!err) { +nf_conntrack_event (changelog, ct); +nf_ct_put (ct); + } -out_unlock: -write_unlock_bh (&nf_conntrack_lock);return err; }
net/netfilter/nf_conntrack_core.c +1 -0
@@ -1547,6 +1547,7 @@ nf_ct_iterate_cleanup(int (*iter)(structstatic int kill_all (struct nf_conn *i,void *data) { +nf_conntrack_event (IPCT_DESTROY , i);return 1 ; }
net/ipv4/netfilter/ip_conntrack_netlink.c +68 -26
188 lines not on this page · raw message
net/ipv4/netfilter/ip_conntrack_core.c +1 -0
@@ -1324,6 +1324,7 @@ static struct nf_sockopt_ops so_getorigdstatic int kill_all (struct ip_conntrack *i,void *data) { +ip_conntrack_event (IPCT_DESTROY , i);return 1 ; }
Quoted 6 lines · Pablo Neira Ayuso
Currently only conntrack events generated by the conntrack core are delivered to userspace via ctnetlink. This patch force the generation of event notifications on ctnetlink actions.
Example scenario: you have two process listening to ctnetlink and one of them creates/changes/destroy a conntrack upon certain events
This doesn't apply without 4/8. I also think sending incremental netlink updates is questionable here, if no conntrack events are configured other listeners can only get the entire new state by doing an additional dump.