diff options
-rw-r--r-- | include/net/netfilter/nf_conntrack.h | 2 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_ecache.h | 57 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack_expect.h | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 25 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_ecache.c | 14 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 43 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 88 |
7 files changed, 197 insertions, 34 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index f11255e1ea35..2e0c53641cbe 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -199,7 +199,7 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); | |||
199 | 199 | ||
200 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); | 200 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); |
201 | 201 | ||
202 | extern void nf_conntrack_flush(struct net *net); | 202 | extern void nf_conntrack_flush(struct net *net, u32 pid, int report); |
203 | 203 | ||
204 | extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, | 204 | extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, |
205 | unsigned int nhoff, u_int16_t l3num, | 205 | unsigned int nhoff, u_int16_t l3num, |
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 1285ff26a014..0ff0dc69ca4a 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h | |||
@@ -17,6 +17,13 @@ struct nf_conntrack_ecache { | |||
17 | unsigned int events; | 17 | unsigned int events; |
18 | }; | 18 | }; |
19 | 19 | ||
20 | /* This structure is passed to event handler */ | ||
21 | struct nf_ct_event { | ||
22 | struct nf_conn *ct; | ||
23 | u32 pid; | ||
24 | int report; | ||
25 | }; | ||
26 | |||
20 | extern struct atomic_notifier_head nf_conntrack_chain; | 27 | extern struct atomic_notifier_head nf_conntrack_chain; |
21 | extern int nf_conntrack_register_notifier(struct notifier_block *nb); | 28 | extern int nf_conntrack_register_notifier(struct notifier_block *nb); |
22 | extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); | 29 | extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); |
@@ -39,22 +46,56 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) | |||
39 | local_bh_enable(); | 46 | local_bh_enable(); |
40 | } | 47 | } |
41 | 48 | ||
42 | static inline void nf_conntrack_event(enum ip_conntrack_events event, | 49 | static inline void |
43 | struct nf_conn *ct) | 50 | nf_conntrack_event_report(enum ip_conntrack_events event, |
51 | struct nf_conn *ct, | ||
52 | u32 pid, | ||
53 | int report) | ||
44 | { | 54 | { |
55 | struct nf_ct_event item = { | ||
56 | .ct = ct, | ||
57 | .pid = pid, | ||
58 | .report = report | ||
59 | }; | ||
45 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) | 60 | if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) |
46 | atomic_notifier_call_chain(&nf_conntrack_chain, event, ct); | 61 | atomic_notifier_call_chain(&nf_conntrack_chain, event, &item); |
47 | } | 62 | } |
48 | 63 | ||
64 | static inline void | ||
65 | nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) | ||
66 | { | ||
67 | nf_conntrack_event_report(event, ct, 0, 0); | ||
68 | } | ||
69 | |||
70 | struct nf_exp_event { | ||
71 | struct nf_conntrack_expect *exp; | ||
72 | u32 pid; | ||
73 | int report; | ||
74 | }; | ||
75 | |||
49 | extern struct atomic_notifier_head nf_ct_expect_chain; | 76 | extern struct atomic_notifier_head nf_ct_expect_chain; |
50 | extern int nf_ct_expect_register_notifier(struct notifier_block *nb); | 77 | extern int nf_ct_expect_register_notifier(struct notifier_block *nb); |
51 | extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb); | 78 | extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb); |
52 | 79 | ||
53 | static inline void | 80 | static inline void |
81 | nf_ct_expect_event_report(enum ip_conntrack_expect_events event, | ||
82 | struct nf_conntrack_expect *exp, | ||
83 | u32 pid, | ||
84 | int report) | ||
85 | { | ||
86 | struct nf_exp_event item = { | ||
87 | .exp = exp, | ||
88 | .pid = pid, | ||
89 | .report = report | ||
90 | }; | ||
91 | atomic_notifier_call_chain(&nf_ct_expect_chain, event, &item); | ||
92 | } | ||
93 | |||
94 | static inline void | ||
54 | nf_ct_expect_event(enum ip_conntrack_expect_events event, | 95 | nf_ct_expect_event(enum ip_conntrack_expect_events event, |
55 | struct nf_conntrack_expect *exp) | 96 | struct nf_conntrack_expect *exp) |
56 | { | 97 | { |
57 | atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp); | 98 | nf_ct_expect_event_report(event, exp, 0, 0); |
58 | } | 99 | } |
59 | 100 | ||
60 | extern int nf_conntrack_ecache_init(struct net *net); | 101 | extern int nf_conntrack_ecache_init(struct net *net); |
@@ -66,9 +107,17 @@ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, | |||
66 | struct nf_conn *ct) {} | 107 | struct nf_conn *ct) {} |
67 | static inline void nf_conntrack_event(enum ip_conntrack_events event, | 108 | static inline void nf_conntrack_event(enum ip_conntrack_events event, |
68 | struct nf_conn *ct) {} | 109 | struct nf_conn *ct) {} |
110 | static inline void nf_conntrack_event_report(enum ip_conntrack_events event, | ||
111 | struct nf_conn *ct, | ||
112 | u32 pid, | ||
113 | int report) {} | ||
69 | static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} | 114 | static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} |
70 | static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, | 115 | static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, |
71 | struct nf_conntrack_expect *exp) {} | 116 | struct nf_conntrack_expect *exp) {} |
117 | static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, | ||
118 | struct nf_conntrack_expect *exp, | ||
119 | u32 pid, | ||
120 | int report) {} | ||
72 | static inline void nf_ct_event_cache_flush(struct net *net) {} | 121 | static inline void nf_ct_event_cache_flush(struct net *net) {} |
73 | 122 | ||
74 | static inline int nf_conntrack_ecache_init(struct net *net) | 123 | static inline int nf_conntrack_ecache_init(struct net *net) |
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 37a7fc1164b0..ab17a159ac66 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h | |||
@@ -100,6 +100,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t, | |||
100 | u_int8_t, const __be16 *, const __be16 *); | 100 | u_int8_t, const __be16 *, const __be16 *); |
101 | void nf_ct_expect_put(struct nf_conntrack_expect *exp); | 101 | void nf_ct_expect_put(struct nf_conntrack_expect *exp); |
102 | int nf_ct_expect_related(struct nf_conntrack_expect *expect); | 102 | int nf_ct_expect_related(struct nf_conntrack_expect *expect); |
103 | int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, | ||
104 | u32 pid, int report); | ||
103 | 105 | ||
104 | #endif /*_NF_CONNTRACK_EXPECT_H*/ | 106 | #endif /*_NF_CONNTRACK_EXPECT_H*/ |
105 | 107 | ||
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 1e649fb9e0df..dc3fea09f3fc 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 | } |
973 | EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); | 974 | EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); |
974 | 975 | ||
976 | struct __nf_ct_flush_report { | ||
977 | u32 pid; | ||
978 | int report; | ||
979 | }; | ||
980 | |||
975 | static int kill_all(struct nf_conn *i, void *data) | 981 | static 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 | } |
988 | EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); | 1001 | EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); |
989 | 1002 | ||
990 | void nf_conntrack_flush(struct net *net) | 1003 | void 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 | } |
994 | EXPORT_SYMBOL_GPL(nf_conntrack_flush); | 1011 | EXPORT_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 a5f5e2e65d13..dee4190209cc 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 37a703bc3b8e..3a8a34a6d37c 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 | ||
365 | int nf_ct_expect_related(struct nf_conntrack_expect *expect) | 365 | static 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 | } |
410 | out: | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | int 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; | ||
418 | out: | 429 | out: |
419 | spin_unlock_bh(&nf_conntrack_lock); | 430 | spin_unlock_bh(&nf_conntrack_lock); |
420 | return ret; | 431 | return ret; |
421 | } | 432 | } |
422 | EXPORT_SYMBOL_GPL(nf_ct_expect_related); | 433 | EXPORT_SYMBOL_GPL(nf_ct_expect_related); |
423 | 434 | ||
435 | int 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); | ||
445 | out: | ||
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 | } | ||
451 | EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); | ||
452 | |||
424 | #ifdef CONFIG_PROC_FS | 453 | #ifdef CONFIG_PROC_FS |
425 | struct ct_expect_iter_state { | 454 | struct 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 4f6486cfd337..ccc5ef1d7573 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 | ||
517 | nla_put_failure: | 518 | nla_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 | ||
1102 | static inline void | ||
1103 | ctnetlink_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 | |||
1091 | static int | 1124 | static int |
1092 | ctnetlink_create_conntrack(struct nlattr *cda[], | 1125 | ctnetlink_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 | ||
1294 | out_unlock: | 1347 | out_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 | ||
1465 | nla_put_failure: | 1519 | nla_put_failure: |
@@ -1673,7 +1727,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[]) | |||
1673 | } | 1727 | } |
1674 | 1728 | ||
1675 | static int | 1729 | static int |
1676 | ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) | 1730 | ctnetlink_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 | ||
1726 | out: | 1780 | out: |
@@ -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 | ||