From mboxrd@z Thu Jan 1 00:00:00 1970 From: Pablo Neira Ayuso Subject: [PATCH 7/8][CTNETLINK] send conntrack events on ctnetlink actions Date: Tue, 25 Jul 2006 15:27:05 +0200 Message-ID: <44C61C29.4050202@netfilter.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------010304020200030500030900" Cc: Harald Welte , Patrick McHardy Return-path: To: Netfilter Development Mailinglist List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: netfilter-devel-bounces@lists.netfilter.org Errors-To: netfilter-devel-bounces@lists.netfilter.org List-Id: netfilter-devel.vger.kernel.org This is a multi-part message in MIME format. --------------010304020200030500030900 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit 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 Signed-off-by: Pablo Neira Ayuso -- 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 --------------010304020200030500030900 Content-Type: text/plain; name="07send.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="07send.patch" [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 Signed-off-by: Pablo Neira Ayuso Index: net-2.6/net/netfilter/nf_conntrack_netlink.c =================================================================== --- net-2.6.orig/net/netfilter/nf_conntrack_netlink.c 2006-07-25 01:20:37.000000000 +0200 +++ net-2.6/net/netfilter/nf_conntrack_netlink.c 2006-07-25 01:43:32.000000000 +0200 @@ -798,6 +798,11 @@ ctnetlink_del_conntrack(struct sock *ctn if (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 nfattr if (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 *ctn if (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; } Index: net-2.6/net/netfilter/nf_conntrack_core.c =================================================================== --- net-2.6.orig/net/netfilter/nf_conntrack_core.c 2006-07-25 01:20:34.000000000 +0200 +++ net-2.6/net/netfilter/nf_conntrack_core.c 2006-07-25 01:20:38.000000000 +0200 @@ -1547,6 +1547,7 @@ nf_ct_iterate_cleanup(int (*iter)(struct static int kill_all(struct nf_conn *i, void *data) { + nf_conntrack_event(IPCT_DESTROY, i); return 1; } Index: net-2.6/net/ipv4/netfilter/ip_conntrack_netlink.c =================================================================== --- net-2.6.orig/net/ipv4/netfilter/ip_conntrack_netlink.c 2006-07-25 01:20:37.000000000 +0200 +++ net-2.6/net/ipv4/netfilter/ip_conntrack_netlink.c 2006-07-25 01:46:19.000000000 +0200 @@ -782,6 +782,11 @@ ctnetlink_del_conntrack(struct sock *ctn if (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 + */ + ip_conntrack_put(ct); DEBUGP("leaving\n"); @@ -1009,7 +1014,9 @@ ctnetlink_change_protoinfo(struct ip_con } static int -ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[]) +ctnetlink_change_conntrack(struct ip_conntrack *ct, + struct nfattr *cda[], + unsigned int *changelog) { int err; @@ -1019,39 +1026,49 @@ ctnetlink_change_conntrack(struct ip_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_IP_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 ip_conntrack * ctnetlink_create_conntrack(struct nfattr *cda[], struct ip_conntrack_tuple *otuple, - struct ip_conntrack_tuple *rtuple) + struct ip_conntrack_tuple *rtuple, + unsigned int *changelog) { struct ip_conntrack *ct; int err = -EINVAL; @@ -1060,7 +1077,7 @@ ctnetlink_create_conntrack(struct nfattr ct = ip_conntrack_alloc(otuple, rtuple); if (ct == NULL || IS_ERR(ct)) - return -ENOMEM; + return ERR_PTR(-ENOMEM); if (!cda[CTA_TIMEOUT-1]) goto err; @@ -1073,27 +1090,38 @@ ctnetlink_create_conntrack(struct nfattr if (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_IP_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 ct->helper = ip_conntrack_helper_find(rtuple); + if (ct->helper) + *changelog |= IPCT_HELPER; + ip_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: ip_conntrack_free(ct); - return err; + return ERR_PTR(err); } static int @@ -1102,6 +1130,8 @@ ctnetlink_new_conntrack(struct sock *ctn { struct ip_conntrack_tuple otuple, rtuple; struct ip_conntrack_tuple_hash *h = NULL; + struct ip_conntrack *ct = NULL; + unsigned int changelog = 0; int err = 0; DEBUGP("entered %s\n", __FUNCTION__); @@ -1130,28 +1160,40 @@ ctnetlink_new_conntrack(struct sock *ctn if (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(&ip_conntrack_lock); - return err; - } - /* implicit 'else' */ + changelog |= IPCT_NEW; + } else { + 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(&ip_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(&ip_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(tuplehash_to_ctrack(h), cda); + /* if everything went fine, notify others about the new conntrack */ + if (!err) { + ip_conntrack_event(changelog, ct); + ip_conntrack_put(ct); + } -out_unlock: - write_unlock_bh(&ip_conntrack_lock); return err; } Index: net-2.6/net/ipv4/netfilter/ip_conntrack_core.c =================================================================== --- net-2.6.orig/net/ipv4/netfilter/ip_conntrack_core.c 2006-07-25 01:20:34.000000000 +0200 +++ net-2.6/net/ipv4/netfilter/ip_conntrack_core.c 2006-07-25 01:20:38.000000000 +0200 @@ -1324,6 +1324,7 @@ static struct nf_sockopt_ops so_getorigd static int kill_all(struct ip_conntrack *i, void *data) { + ip_conntrack_event(IPCT_DESTROY, i); return 1; } --------------010304020200030500030900--