aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPablo Neira Ayuso <pablo@netfilter.org>2008-11-18 05:56:20 -0500
committerPatrick McHardy <kaber@trash.net>2008-11-18 05:56:20 -0500
commit19abb7b090a6bce88d4e9b2914a0367f4f684432 (patch)
tree3603eafaf214ef1ab200c6e5d6d05318512a3bd6 /net/netfilter
parent226c0c0ef2abdf91b8d9cce1aaf7d4635a5e5926 (diff)
netfilter: ctnetlink: deliver events for conntracks changed from userspace
As for now, the creation and update of conntracks via ctnetlink do not propagate an event to userspace. This can result in inconsistent situations if several userspace processes modify the connection tracking table by means of ctnetlink at the same time. Specifically, using the conntrack command line tool and conntrackd at the same time can trigger unconsistencies. This patch also modifies the event cache infrastructure to pass the process PID and the ECHO flag to nfnetlink_send() to report back to userspace if the process that triggered the change needs so. Based on a suggestion from Patrick McHardy. Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_core.c25
-rw-r--r--net/netfilter/nf_conntrack_ecache.c14
-rw-r--r--net/netfilter/nf_conntrack_expect.c43
-rw-r--r--net/netfilter/nf_conntrack_netlink.c88
4 files changed, 141 insertions, 29 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 1e649fb9e0d..dc3fea09f3f 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -181,7 +181,8 @@ destroy_conntrack(struct nf_conntrack *nfct)
181 NF_CT_ASSERT(atomic_read(&nfct->use) == 0); 181 NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
182 NF_CT_ASSERT(!timer_pending(&ct->timeout)); 182 NF_CT_ASSERT(!timer_pending(&ct->timeout));
183 183
184 nf_conntrack_event(IPCT_DESTROY, ct); 184 if (!test_bit(IPS_DYING_BIT, &ct->status))
185 nf_conntrack_event(IPCT_DESTROY, ct);
185 set_bit(IPS_DYING_BIT, &ct->status); 186 set_bit(IPS_DYING_BIT, &ct->status);
186 187
187 /* To make sure we don't get any weird locking issues here: 188 /* To make sure we don't get any weird locking issues here:
@@ -972,8 +973,20 @@ void nf_ct_iterate_cleanup(struct net *net,
972} 973}
973EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); 974EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);
974 975
976struct __nf_ct_flush_report {
977 u32 pid;
978 int report;
979};
980
975static int kill_all(struct nf_conn *i, void *data) 981static int kill_all(struct nf_conn *i, void *data)
976{ 982{
983 struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data;
984
985 /* get_next_corpse sets the dying bit for us */
986 nf_conntrack_event_report(IPCT_DESTROY,
987 i,
988 fr->pid,
989 fr->report);
977 return 1; 990 return 1;
978} 991}
979 992
@@ -987,9 +1000,13 @@ void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int s
987} 1000}
988EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); 1001EXPORT_SYMBOL_GPL(nf_ct_free_hashtable);
989 1002
990void nf_conntrack_flush(struct net *net) 1003void nf_conntrack_flush(struct net *net, u32 pid, int report)
991{ 1004{
992 nf_ct_iterate_cleanup(net, kill_all, NULL); 1005 struct __nf_ct_flush_report fr = {
1006 .pid = pid,
1007 .report = report,
1008 };
1009 nf_ct_iterate_cleanup(net, kill_all, &fr);
993} 1010}
994EXPORT_SYMBOL_GPL(nf_conntrack_flush); 1011EXPORT_SYMBOL_GPL(nf_conntrack_flush);
995 1012
@@ -1005,7 +1022,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
1005 nf_ct_event_cache_flush(net); 1022 nf_ct_event_cache_flush(net);
1006 nf_conntrack_ecache_fini(net); 1023 nf_conntrack_ecache_fini(net);
1007 i_see_dead_people: 1024 i_see_dead_people:
1008 nf_conntrack_flush(net); 1025 nf_conntrack_flush(net, 0, 0);
1009 if (atomic_read(&net->ct.count) != 0) { 1026 if (atomic_read(&net->ct.count) != 0) {
1010 schedule(); 1027 schedule();
1011 goto i_see_dead_people; 1028 goto i_see_dead_people;
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index a5f5e2e65d1..dee4190209c 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -35,9 +35,17 @@ static inline void
35__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) 35__nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache)
36{ 36{
37 if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) 37 if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct)
38 && ecache->events) 38 && ecache->events) {
39 atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events, 39 struct nf_ct_event item = {
40 ecache->ct); 40 .ct = ecache->ct,
41 .pid = 0,
42 .report = 0
43 };
44
45 atomic_notifier_call_chain(&nf_conntrack_chain,
46 ecache->events,
47 &item);
48 }
41 49
42 ecache->events = 0; 50 ecache->events = 0;
43 nf_ct_put(ecache->ct); 51 nf_ct_put(ecache->ct);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 37a703bc3b8..3a8a34a6d37 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -362,7 +362,7 @@ static inline int refresh_timer(struct nf_conntrack_expect *i)
362 return 1; 362 return 1;
363} 363}
364 364
365int nf_ct_expect_related(struct nf_conntrack_expect *expect) 365static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
366{ 366{
367 const struct nf_conntrack_expect_policy *p; 367 const struct nf_conntrack_expect_policy *p;
368 struct nf_conntrack_expect *i; 368 struct nf_conntrack_expect *i;
@@ -371,11 +371,8 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
371 struct net *net = nf_ct_exp_net(expect); 371 struct net *net = nf_ct_exp_net(expect);
372 struct hlist_node *n; 372 struct hlist_node *n;
373 unsigned int h; 373 unsigned int h;
374 int ret; 374 int ret = 0;
375
376 NF_CT_ASSERT(master_help);
377 375
378 spin_lock_bh(&nf_conntrack_lock);
379 if (!master_help->helper) { 376 if (!master_help->helper) {
380 ret = -ESHUTDOWN; 377 ret = -ESHUTDOWN;
381 goto out; 378 goto out;
@@ -409,18 +406,50 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
409 printk(KERN_WARNING 406 printk(KERN_WARNING
410 "nf_conntrack: expectation table full\n"); 407 "nf_conntrack: expectation table full\n");
411 ret = -EMFILE; 408 ret = -EMFILE;
412 goto out;
413 } 409 }
410out:
411 return ret;
412}
413
414int nf_ct_expect_related(struct nf_conntrack_expect *expect)
415{
416 int ret;
417
418 spin_lock_bh(&nf_conntrack_lock);
419 ret = __nf_ct_expect_check(expect);
420 if (ret < 0)
421 goto out;
414 422
415 nf_ct_expect_insert(expect); 423 nf_ct_expect_insert(expect);
424 atomic_inc(&expect->use);
425 spin_unlock_bh(&nf_conntrack_lock);
416 nf_ct_expect_event(IPEXP_NEW, expect); 426 nf_ct_expect_event(IPEXP_NEW, expect);
417 ret = 0; 427 nf_ct_expect_put(expect);
428 return ret;
418out: 429out:
419 spin_unlock_bh(&nf_conntrack_lock); 430 spin_unlock_bh(&nf_conntrack_lock);
420 return ret; 431 return ret;
421} 432}
422EXPORT_SYMBOL_GPL(nf_ct_expect_related); 433EXPORT_SYMBOL_GPL(nf_ct_expect_related);
423 434
435int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
436 u32 pid, int report)
437{
438 int ret;
439
440 spin_lock_bh(&nf_conntrack_lock);
441 ret = __nf_ct_expect_check(expect);
442 if (ret < 0)
443 goto out;
444 nf_ct_expect_insert(expect);
445out:
446 spin_unlock_bh(&nf_conntrack_lock);
447 if (ret == 0)
448 nf_ct_expect_event_report(IPEXP_NEW, expect, pid, report);
449 return ret;
450}
451EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
452
424#ifdef CONFIG_PROC_FS 453#ifdef CONFIG_PROC_FS
425struct ct_expect_iter_state { 454struct ct_expect_iter_state {
426 struct seq_net_private p; 455 struct seq_net_private p;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4f6486cfd33..ccc5ef1d757 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -410,7 +410,8 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
410 struct nlmsghdr *nlh; 410 struct nlmsghdr *nlh;
411 struct nfgenmsg *nfmsg; 411 struct nfgenmsg *nfmsg;
412 struct nlattr *nest_parms; 412 struct nlattr *nest_parms;
413 struct nf_conn *ct = (struct nf_conn *)ptr; 413 struct nf_ct_event *item = (struct nf_ct_event *)ptr;
414 struct nf_conn *ct = item->ct;
414 struct sk_buff *skb; 415 struct sk_buff *skb;
415 unsigned int type; 416 unsigned int type;
416 sk_buff_data_t b; 417 sk_buff_data_t b;
@@ -443,7 +444,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
443 b = skb->tail; 444 b = skb->tail;
444 445
445 type |= NFNL_SUBSYS_CTNETLINK << 8; 446 type |= NFNL_SUBSYS_CTNETLINK << 8;
446 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); 447 nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg));
447 nfmsg = NLMSG_DATA(nlh); 448 nfmsg = NLMSG_DATA(nlh);
448 449
449 nlh->nlmsg_flags = flags; 450 nlh->nlmsg_flags = flags;
@@ -511,7 +512,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
511 rcu_read_unlock(); 512 rcu_read_unlock();
512 513
513 nlh->nlmsg_len = skb->tail - b; 514 nlh->nlmsg_len = skb->tail - b;
514 nfnetlink_send(skb, 0, group, 0); 515 nfnetlink_send(skb, item->pid, group, item->report);
515 return NOTIFY_DONE; 516 return NOTIFY_DONE;
516 517
517nla_put_failure: 518nla_put_failure:
@@ -722,7 +723,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
722 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); 723 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
723 else { 724 else {
724 /* Flush the whole table */ 725 /* Flush the whole table */
725 nf_conntrack_flush(&init_net); 726 nf_conntrack_flush(&init_net,
727 NETLINK_CB(skb).pid,
728 nlmsg_report(nlh));
726 return 0; 729 return 0;
727 } 730 }
728 731
@@ -743,6 +746,14 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
743 } 746 }
744 } 747 }
745 748
749 nf_conntrack_event_report(IPCT_DESTROY,
750 ct,
751 NETLINK_CB(skb).pid,
752 nlmsg_report(nlh));
753
754 /* death_by_timeout would report the event again */
755 set_bit(IPS_DYING_BIT, &ct->status);
756
746 nf_ct_kill(ct); 757 nf_ct_kill(ct);
747 nf_ct_put(ct); 758 nf_ct_put(ct);
748 759
@@ -1088,11 +1099,35 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
1088 return 0; 1099 return 0;
1089} 1100}
1090 1101
1102static inline void
1103ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report)
1104{
1105 unsigned int events = 0;
1106
1107 if (test_bit(IPS_EXPECTED_BIT, &ct->status))
1108 events |= IPCT_RELATED;
1109 else
1110 events |= IPCT_NEW;
1111
1112 nf_conntrack_event_report(IPCT_STATUS |
1113 IPCT_HELPER |
1114 IPCT_REFRESH |
1115 IPCT_PROTOINFO |
1116 IPCT_NATSEQADJ |
1117 IPCT_MARK |
1118 events,
1119 ct,
1120 pid,
1121 report);
1122}
1123
1091static int 1124static int
1092ctnetlink_create_conntrack(struct nlattr *cda[], 1125ctnetlink_create_conntrack(struct nlattr *cda[],
1093 struct nf_conntrack_tuple *otuple, 1126 struct nf_conntrack_tuple *otuple,
1094 struct nf_conntrack_tuple *rtuple, 1127 struct nf_conntrack_tuple *rtuple,
1095 struct nf_conn *master_ct) 1128 struct nf_conn *master_ct,
1129 u32 pid,
1130 int report)
1096{ 1131{
1097 struct nf_conn *ct; 1132 struct nf_conn *ct;
1098 int err = -EINVAL; 1133 int err = -EINVAL;
@@ -1198,9 +1233,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1198 ct->master = master_ct; 1233 ct->master = master_ct;
1199 } 1234 }
1200 1235
1236 nf_conntrack_get(&ct->ct_general);
1201 add_timer(&ct->timeout); 1237 add_timer(&ct->timeout);
1202 nf_conntrack_hash_insert(ct); 1238 nf_conntrack_hash_insert(ct);
1203 rcu_read_unlock(); 1239 rcu_read_unlock();
1240 ctnetlink_event_report(ct, pid, report);
1241 nf_ct_put(ct);
1204 1242
1205 return 0; 1243 return 0;
1206 1244
@@ -1265,7 +1303,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1265 err = ctnetlink_create_conntrack(cda, 1303 err = ctnetlink_create_conntrack(cda,
1266 &otuple, 1304 &otuple,
1267 &rtuple, 1305 &rtuple,
1268 master_ct); 1306 master_ct,
1307 NETLINK_CB(skb).pid,
1308 nlmsg_report(nlh));
1269 if (err < 0 && master_ct) 1309 if (err < 0 && master_ct)
1270 nf_ct_put(master_ct); 1310 nf_ct_put(master_ct);
1271 1311
@@ -1277,6 +1317,8 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1277 * so there's no need to increase the refcount */ 1317 * so there's no need to increase the refcount */
1278 err = -EEXIST; 1318 err = -EEXIST;
1279 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { 1319 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
1320 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
1321
1280 /* we only allow nat config for new conntracks */ 1322 /* we only allow nat config for new conntracks */
1281 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { 1323 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
1282 err = -EOPNOTSUPP; 1324 err = -EOPNOTSUPP;
@@ -1287,8 +1329,19 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1287 err = -EOPNOTSUPP; 1329 err = -EOPNOTSUPP;
1288 goto out_unlock; 1330 goto out_unlock;
1289 } 1331 }
1290 err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), 1332
1291 cda); 1333 err = ctnetlink_change_conntrack(ct, cda);
1334 if (err == 0) {
1335 nf_conntrack_get(&ct->ct_general);
1336 spin_unlock_bh(&nf_conntrack_lock);
1337 ctnetlink_event_report(ct,
1338 NETLINK_CB(skb).pid,
1339 nlmsg_report(nlh));
1340 nf_ct_put(ct);
1341 } else
1342 spin_unlock_bh(&nf_conntrack_lock);
1343
1344 return err;
1292 } 1345 }
1293 1346
1294out_unlock: 1347out_unlock:
@@ -1423,7 +1476,8 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1423{ 1476{
1424 struct nlmsghdr *nlh; 1477 struct nlmsghdr *nlh;
1425 struct nfgenmsg *nfmsg; 1478 struct nfgenmsg *nfmsg;
1426 struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr; 1479 struct nf_exp_event *item = (struct nf_exp_event *)ptr;
1480 struct nf_conntrack_expect *exp = item->exp;
1427 struct sk_buff *skb; 1481 struct sk_buff *skb;
1428 unsigned int type; 1482 unsigned int type;
1429 sk_buff_data_t b; 1483 sk_buff_data_t b;
@@ -1445,7 +1499,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1445 b = skb->tail; 1499 b = skb->tail;
1446 1500
1447 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; 1501 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
1448 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); 1502 nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg));
1449 nfmsg = NLMSG_DATA(nlh); 1503 nfmsg = NLMSG_DATA(nlh);
1450 1504
1451 nlh->nlmsg_flags = flags; 1505 nlh->nlmsg_flags = flags;
@@ -1459,7 +1513,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1459 rcu_read_unlock(); 1513 rcu_read_unlock();
1460 1514
1461 nlh->nlmsg_len = skb->tail - b; 1515 nlh->nlmsg_len = skb->tail - b;
1462 nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); 1516 nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report);
1463 return NOTIFY_DONE; 1517 return NOTIFY_DONE;
1464 1518
1465nla_put_failure: 1519nla_put_failure:
@@ -1673,7 +1727,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[])
1673} 1727}
1674 1728
1675static int 1729static int
1676ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) 1730ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3, u32 pid, int report)
1677{ 1731{
1678 struct nf_conntrack_tuple tuple, mask, master_tuple; 1732 struct nf_conntrack_tuple tuple, mask, master_tuple;
1679 struct nf_conntrack_tuple_hash *h = NULL; 1733 struct nf_conntrack_tuple_hash *h = NULL;
@@ -1720,7 +1774,7 @@ ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3)
1720 memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); 1774 memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
1721 exp->mask.src.u.all = mask.src.u.all; 1775 exp->mask.src.u.all = mask.src.u.all;
1722 1776
1723 err = nf_ct_expect_related(exp); 1777 err = nf_ct_expect_related_report(exp, pid, report);
1724 nf_ct_expect_put(exp); 1778 nf_ct_expect_put(exp);
1725 1779
1726out: 1780out:
@@ -1753,8 +1807,12 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1753 if (!exp) { 1807 if (!exp) {
1754 spin_unlock_bh(&nf_conntrack_lock); 1808 spin_unlock_bh(&nf_conntrack_lock);
1755 err = -ENOENT; 1809 err = -ENOENT;
1756 if (nlh->nlmsg_flags & NLM_F_CREATE) 1810 if (nlh->nlmsg_flags & NLM_F_CREATE) {
1757 err = ctnetlink_create_expect(cda, u3); 1811 err = ctnetlink_create_expect(cda,
1812 u3,
1813 NETLINK_CB(skb).pid,
1814 nlmsg_report(nlh));
1815 }
1758 return err; 1816 return err;
1759 } 1817 }
1760 1818