aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter_bridge/ebtables.h3
-rw-r--r--include/linux/netfilter_ipv4/ipt_policy.h2
-rw-r--r--include/linux/netfilter_ipv6/ip6t_policy.h2
-rw-r--r--include/net/netfilter/nf_conntrack.h5
-rw-r--r--include/net/netfilter/nf_conntrack_ecache.h57
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h2
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h5
-rw-r--r--include/net/netfilter/nf_conntrack_l4proto.h2
-rw-r--r--include/net/netfilter/nfnetlink_log.h14
-rw-r--r--include/net/netns/x_tables.h5
-rw-r--r--net/bridge/br_netfilter.c2
-rw-r--r--net/bridge/netfilter/ebtable_broute.c26
-rw-r--r--net/bridge/netfilter/ebtable_filter.c41
-rw-r--r--net/bridge/netfilter/ebtable_nat.c38
-rw-r--r--net/bridge/netfilter/ebtables.c52
-rw-r--r--net/ipv4/netfilter.c3
-rw-r--r--net/ipv4/netfilter/arptable_filter.c12
-rw-r--r--net/ipv4/netfilter/ipt_addrtype.c16
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c23
-rw-r--r--net/ipv6/netfilter.c5
-rw-r--r--net/ipv6/netfilter/ip6table_filter.c17
-rw-r--r--net/netfilter/nf_conntrack_amanda.c1
-rw-r--r--net/netfilter/nf_conntrack_core.c61
-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_ftp.c9
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c1
-rw-r--r--net/netfilter/nf_conntrack_helper.c32
-rw-r--r--net/netfilter/nf_conntrack_irc.c1
-rw-r--r--net/netfilter/nf_conntrack_netbios_ns.c1
-rw-r--r--net/netfilter/nf_conntrack_netlink.c201
-rw-r--r--net/netfilter/nf_conntrack_pptp.c1
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c2
-rw-r--r--net/netfilter/nf_conntrack_sane.c1
-rw-r--r--net/netfilter/nf_conntrack_sip.c1
-rw-r--r--net/netfilter/nf_conntrack_tftp.c1
-rw-r--r--net/netfilter/nfnetlink_log.c4
-rw-r--r--net/netfilter/xt_NFLOG.c5
-rw-r--r--net/netfilter/xt_recent.c22
40 files changed, 514 insertions, 221 deletions
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index d45e29cd1cfb..e40ddb94b1af 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -300,7 +300,8 @@ struct ebt_table
300 300
301#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ 301#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \
302 ~(__alignof__(struct ebt_replace)-1)) 302 ~(__alignof__(struct ebt_replace)-1))
303extern int ebt_register_table(struct ebt_table *table); 303extern struct ebt_table *ebt_register_table(struct net *net,
304 struct ebt_table *table);
304extern void ebt_unregister_table(struct ebt_table *table); 305extern void ebt_unregister_table(struct ebt_table *table);
305extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, 306extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb,
306 const struct net_device *in, const struct net_device *out, 307 const struct net_device *in, const struct net_device *out,
diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h
index b9478a255301..1037fb2cd206 100644
--- a/include/linux/netfilter_ipv4/ipt_policy.h
+++ b/include/linux/netfilter_ipv4/ipt_policy.h
@@ -1,6 +1,8 @@
1#ifndef _IPT_POLICY_H 1#ifndef _IPT_POLICY_H
2#define _IPT_POLICY_H 2#define _IPT_POLICY_H
3 3
4#include <linux/netfilter/xt_policy.h>
5
4#define IPT_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM 6#define IPT_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM
5 7
6/* ipt_policy_flags */ 8/* ipt_policy_flags */
diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h
index 6bab3163d2fb..b1c449d7ec89 100644
--- a/include/linux/netfilter_ipv6/ip6t_policy.h
+++ b/include/linux/netfilter_ipv6/ip6t_policy.h
@@ -1,6 +1,8 @@
1#ifndef _IP6T_POLICY_H 1#ifndef _IP6T_POLICY_H
2#define _IP6T_POLICY_H 2#define _IP6T_POLICY_H
3 3
4#include <linux/netfilter/xt_policy.h>
5
4#define IP6T_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM 6#define IP6T_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM
5 7
6/* ip6t_policy_flags */ 8/* ip6t_policy_flags */
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index b76a8685b5b5..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
200extern void nf_conntrack_hash_insert(struct nf_conn *ct); 200extern void nf_conntrack_hash_insert(struct nf_conn *ct);
201 201
202extern void nf_conntrack_flush(struct net *net); 202extern void nf_conntrack_flush(struct net *net, u32 pid, int report);
203 203
204extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, 204extern 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,
@@ -298,5 +298,8 @@ do { \
298 local_bh_enable(); \ 298 local_bh_enable(); \
299} while (0) 299} while (0)
300 300
301#define MODULE_ALIAS_NFCT_HELPER(helper) \
302 MODULE_ALIAS("nfct-helper-" helper)
303
301#endif /* __KERNEL__ */ 304#endif /* __KERNEL__ */
302#endif /* _NF_CONNTRACK_H */ 305#endif /* _NF_CONNTRACK_H */
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 */
21struct nf_ct_event {
22 struct nf_conn *ct;
23 u32 pid;
24 int report;
25};
26
20extern struct atomic_notifier_head nf_conntrack_chain; 27extern struct atomic_notifier_head nf_conntrack_chain;
21extern int nf_conntrack_register_notifier(struct notifier_block *nb); 28extern int nf_conntrack_register_notifier(struct notifier_block *nb);
22extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); 29extern 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
42static inline void nf_conntrack_event(enum ip_conntrack_events event, 49static inline void
43 struct nf_conn *ct) 50nf_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
64static inline void
65nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
66{
67 nf_conntrack_event_report(event, ct, 0, 0);
68}
69
70struct nf_exp_event {
71 struct nf_conntrack_expect *exp;
72 u32 pid;
73 int report;
74};
75
49extern struct atomic_notifier_head nf_ct_expect_chain; 76extern struct atomic_notifier_head nf_ct_expect_chain;
50extern int nf_ct_expect_register_notifier(struct notifier_block *nb); 77extern int nf_ct_expect_register_notifier(struct notifier_block *nb);
51extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb); 78extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb);
52 79
53static inline void 80static inline void
81nf_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
94static inline void
54nf_ct_expect_event(enum ip_conntrack_expect_events event, 95nf_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
60extern int nf_conntrack_ecache_init(struct net *net); 101extern 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) {}
67static inline void nf_conntrack_event(enum ip_conntrack_events event, 108static inline void nf_conntrack_event(enum ip_conntrack_events event,
68 struct nf_conn *ct) {} 109 struct nf_conn *ct) {}
110static inline void nf_conntrack_event_report(enum ip_conntrack_events event,
111 struct nf_conn *ct,
112 u32 pid,
113 int report) {}
69static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} 114static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
70static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, 115static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
71 struct nf_conntrack_expect *exp) {} 116 struct nf_conntrack_expect *exp) {}
117static 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) {}
72static inline void nf_ct_event_cache_flush(struct net *net) {} 121static inline void nf_ct_event_cache_flush(struct net *net) {}
73 122
74static inline int nf_conntrack_ecache_init(struct net *net) 123static 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 *);
101void nf_ct_expect_put(struct nf_conntrack_expect *exp); 101void nf_ct_expect_put(struct nf_conntrack_expect *exp);
102int nf_ct_expect_related(struct nf_conntrack_expect *expect); 102int nf_ct_expect_related(struct nf_conntrack_expect *expect);
103int 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/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index f8060ab5a083..66d65a7caa39 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -39,9 +39,6 @@ struct nf_conntrack_helper
39}; 39};
40 40
41extern struct nf_conntrack_helper * 41extern struct nf_conntrack_helper *
42__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple);
43
44extern struct nf_conntrack_helper *
45__nf_conntrack_helper_find_byname(const char *name); 42__nf_conntrack_helper_find_byname(const char *name);
46 43
47extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); 44extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
@@ -49,6 +46,8 @@ extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
49 46
50extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); 47extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
51 48
49extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags);
50
52static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) 51static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
53{ 52{
54 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); 53 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 7f2f43c77284..debdaf75cecf 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -129,7 +129,7 @@ extern const struct nla_policy nf_ct_port_nla_policy[];
129 && net_ratelimit()) 129 && net_ratelimit())
130#endif 130#endif
131#else 131#else
132#define LOG_INVALID(net, proto) 0 132static inline int LOG_INVALID(struct net *net, int proto) { return 0; }
133#endif /* CONFIG_SYSCTL */ 133#endif /* CONFIG_SYSCTL */
134 134
135#endif /*_NF_CONNTRACK_PROTOCOL_H*/ 135#endif /*_NF_CONNTRACK_PROTOCOL_H*/
diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h
new file mode 100644
index 000000000000..b0569ff0775e
--- /dev/null
+++ b/include/net/netfilter/nfnetlink_log.h
@@ -0,0 +1,14 @@
1#ifndef _KER_NFNETLINK_LOG_H
2#define _KER_NFNETLINK_LOG_H
3
4void
5nfulnl_log_packet(u_int8_t pf,
6 unsigned int hooknum,
7 const struct sk_buff *skb,
8 const struct net_device *in,
9 const struct net_device *out,
10 const struct nf_loginfo *li_user,
11 const char *prefix);
12
13#endif /* _KER_NFNETLINK_LOG_H */
14
diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h
index b8093971ccb4..9554a644a8f8 100644
--- a/include/net/netns/x_tables.h
+++ b/include/net/netns/x_tables.h
@@ -4,7 +4,12 @@
4#include <linux/list.h> 4#include <linux/list.h>
5#include <linux/netfilter.h> 5#include <linux/netfilter.h>
6 6
7struct ebt_table;
8
7struct netns_xt { 9struct netns_xt {
8 struct list_head tables[NFPROTO_NUMPROTO]; 10 struct list_head tables[NFPROTO_NUMPROTO];
11 struct ebt_table *broute_table;
12 struct ebt_table *frame_filter;
13 struct ebt_table *frame_nat;
9}; 14};
10#endif 15#endif
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 274194b78247..a65e43a17fbb 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -369,7 +369,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb)
369 if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev)) 369 if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev))
370 goto free_skb; 370 goto free_skb;
371 371
372 if (!ip_route_output_key(&init_net, &rt, &fl)) { 372 if (!ip_route_output_key(dev_net(dev), &rt, &fl)) {
373 /* - Bridged-and-DNAT'ed traffic doesn't 373 /* - Bridged-and-DNAT'ed traffic doesn't
374 * require ip_forwarding. */ 374 * require ip_forwarding. */
375 if (((struct dst_entry *)rt)->dev == dev) { 375 if (((struct dst_entry *)rt)->dev == dev) {
diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
index 246626bb0c87..8604dfc1fc3b 100644
--- a/net/bridge/netfilter/ebtable_broute.c
+++ b/net/bridge/netfilter/ebtable_broute.c
@@ -56,29 +56,47 @@ static int ebt_broute(struct sk_buff *skb)
56 int ret; 56 int ret;
57 57
58 ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL, 58 ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL,
59 &broute_table); 59 dev_net(skb->dev)->xt.broute_table);
60 if (ret == NF_DROP) 60 if (ret == NF_DROP)
61 return 1; /* route it */ 61 return 1; /* route it */
62 return 0; /* bridge it */ 62 return 0; /* bridge it */
63} 63}
64 64
65static int __net_init broute_net_init(struct net *net)
66{
67 net->xt.broute_table = ebt_register_table(net, &broute_table);
68 if (IS_ERR(net->xt.broute_table))
69 return PTR_ERR(net->xt.broute_table);
70 return 0;
71}
72
73static void __net_exit broute_net_exit(struct net *net)
74{
75 ebt_unregister_table(net->xt.broute_table);
76}
77
78static struct pernet_operations broute_net_ops = {
79 .init = broute_net_init,
80 .exit = broute_net_exit,
81};
82
65static int __init ebtable_broute_init(void) 83static int __init ebtable_broute_init(void)
66{ 84{
67 int ret; 85 int ret;
68 86
69 ret = ebt_register_table(&broute_table); 87 ret = register_pernet_subsys(&broute_net_ops);
70 if (ret < 0) 88 if (ret < 0)
71 return ret; 89 return ret;
72 /* see br_input.c */ 90 /* see br_input.c */
73 rcu_assign_pointer(br_should_route_hook, ebt_broute); 91 rcu_assign_pointer(br_should_route_hook, ebt_broute);
74 return ret; 92 return 0;
75} 93}
76 94
77static void __exit ebtable_broute_fini(void) 95static void __exit ebtable_broute_fini(void)
78{ 96{
79 rcu_assign_pointer(br_should_route_hook, NULL); 97 rcu_assign_pointer(br_should_route_hook, NULL);
80 synchronize_net(); 98 synchronize_net();
81 ebt_unregister_table(&broute_table); 99 unregister_pernet_subsys(&broute_net_ops);
82} 100}
83 101
84module_init(ebtable_broute_init); 102module_init(ebtable_broute_init);
diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
index 1a58af51a2e2..2b2e8040a9c6 100644
--- a/net/bridge/netfilter/ebtable_filter.c
+++ b/net/bridge/netfilter/ebtable_filter.c
@@ -61,29 +61,36 @@ static struct ebt_table frame_filter =
61}; 61};
62 62
63static unsigned int 63static unsigned int
64ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, 64ebt_in_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
65 const struct net_device *out, int (*okfn)(struct sk_buff *)) 65 const struct net_device *out, int (*okfn)(struct sk_buff *))
66{ 66{
67 return ebt_do_table(hook, skb, in, out, &frame_filter); 67 return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_filter);
68}
69
70static unsigned int
71ebt_out_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in,
72 const struct net_device *out, int (*okfn)(struct sk_buff *))
73{
74 return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_filter);
68} 75}
69 76
70static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { 77static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
71 { 78 {
72 .hook = ebt_hook, 79 .hook = ebt_in_hook,
73 .owner = THIS_MODULE, 80 .owner = THIS_MODULE,
74 .pf = PF_BRIDGE, 81 .pf = PF_BRIDGE,
75 .hooknum = NF_BR_LOCAL_IN, 82 .hooknum = NF_BR_LOCAL_IN,
76 .priority = NF_BR_PRI_FILTER_BRIDGED, 83 .priority = NF_BR_PRI_FILTER_BRIDGED,
77 }, 84 },
78 { 85 {
79 .hook = ebt_hook, 86 .hook = ebt_in_hook,
80 .owner = THIS_MODULE, 87 .owner = THIS_MODULE,
81 .pf = PF_BRIDGE, 88 .pf = PF_BRIDGE,
82 .hooknum = NF_BR_FORWARD, 89 .hooknum = NF_BR_FORWARD,
83 .priority = NF_BR_PRI_FILTER_BRIDGED, 90 .priority = NF_BR_PRI_FILTER_BRIDGED,
84 }, 91 },
85 { 92 {
86 .hook = ebt_hook, 93 .hook = ebt_out_hook,
87 .owner = THIS_MODULE, 94 .owner = THIS_MODULE,
88 .pf = PF_BRIDGE, 95 .pf = PF_BRIDGE,
89 .hooknum = NF_BR_LOCAL_OUT, 96 .hooknum = NF_BR_LOCAL_OUT,
@@ -91,23 +98,41 @@ static struct nf_hook_ops ebt_ops_filter[] __read_mostly = {
91 }, 98 },
92}; 99};
93 100
101static int __net_init frame_filter_net_init(struct net *net)
102{
103 net->xt.frame_filter = ebt_register_table(net, &frame_filter);
104 if (IS_ERR(net->xt.frame_filter))
105 return PTR_ERR(net->xt.frame_filter);
106 return 0;
107}
108
109static void __net_exit frame_filter_net_exit(struct net *net)
110{
111 ebt_unregister_table(net->xt.frame_filter);
112}
113
114static struct pernet_operations frame_filter_net_ops = {
115 .init = frame_filter_net_init,
116 .exit = frame_filter_net_exit,
117};
118
94static int __init ebtable_filter_init(void) 119static int __init ebtable_filter_init(void)
95{ 120{
96 int ret; 121 int ret;
97 122
98 ret = ebt_register_table(&frame_filter); 123 ret = register_pernet_subsys(&frame_filter_net_ops);
99 if (ret < 0) 124 if (ret < 0)
100 return ret; 125 return ret;
101 ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); 126 ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
102 if (ret < 0) 127 if (ret < 0)
103 ebt_unregister_table(&frame_filter); 128 unregister_pernet_subsys(&frame_filter_net_ops);
104 return ret; 129 return ret;
105} 130}
106 131
107static void __exit ebtable_filter_fini(void) 132static void __exit ebtable_filter_fini(void)
108{ 133{
109 nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); 134 nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter));
110 ebt_unregister_table(&frame_filter); 135 unregister_pernet_subsys(&frame_filter_net_ops);
111} 136}
112 137
113module_init(ebtable_filter_init); 138module_init(ebtable_filter_init);
diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
index f60c1e78e575..3fe1ae87e35f 100644
--- a/net/bridge/netfilter/ebtable_nat.c
+++ b/net/bridge/netfilter/ebtable_nat.c
@@ -61,36 +61,36 @@ static struct ebt_table frame_nat =
61}; 61};
62 62
63static unsigned int 63static unsigned int
64ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in 64ebt_nat_in(unsigned int hook, struct sk_buff *skb, const struct net_device *in
65 , const struct net_device *out, int (*okfn)(struct sk_buff *)) 65 , const struct net_device *out, int (*okfn)(struct sk_buff *))
66{ 66{
67 return ebt_do_table(hook, skb, in, out, &frame_nat); 67 return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_nat);
68} 68}
69 69
70static unsigned int 70static unsigned int
71ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in 71ebt_nat_out(unsigned int hook, struct sk_buff *skb, const struct net_device *in
72 , const struct net_device *out, int (*okfn)(struct sk_buff *)) 72 , const struct net_device *out, int (*okfn)(struct sk_buff *))
73{ 73{
74 return ebt_do_table(hook, skb, in, out, &frame_nat); 74 return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_nat);
75} 75}
76 76
77static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { 77static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
78 { 78 {
79 .hook = ebt_nat_dst, 79 .hook = ebt_nat_out,
80 .owner = THIS_MODULE, 80 .owner = THIS_MODULE,
81 .pf = PF_BRIDGE, 81 .pf = PF_BRIDGE,
82 .hooknum = NF_BR_LOCAL_OUT, 82 .hooknum = NF_BR_LOCAL_OUT,
83 .priority = NF_BR_PRI_NAT_DST_OTHER, 83 .priority = NF_BR_PRI_NAT_DST_OTHER,
84 }, 84 },
85 { 85 {
86 .hook = ebt_nat_src, 86 .hook = ebt_nat_out,
87 .owner = THIS_MODULE, 87 .owner = THIS_MODULE,
88 .pf = PF_BRIDGE, 88 .pf = PF_BRIDGE,
89 .hooknum = NF_BR_POST_ROUTING, 89 .hooknum = NF_BR_POST_ROUTING,
90 .priority = NF_BR_PRI_NAT_SRC, 90 .priority = NF_BR_PRI_NAT_SRC,
91 }, 91 },
92 { 92 {
93 .hook = ebt_nat_dst, 93 .hook = ebt_nat_in,
94 .owner = THIS_MODULE, 94 .owner = THIS_MODULE,
95 .pf = PF_BRIDGE, 95 .pf = PF_BRIDGE,
96 .hooknum = NF_BR_PRE_ROUTING, 96 .hooknum = NF_BR_PRE_ROUTING,
@@ -98,23 +98,41 @@ static struct nf_hook_ops ebt_ops_nat[] __read_mostly = {
98 }, 98 },
99}; 99};
100 100
101static int __net_init frame_nat_net_init(struct net *net)
102{
103 net->xt.frame_nat = ebt_register_table(net, &frame_nat);
104 if (IS_ERR(net->xt.frame_nat))
105 return PTR_ERR(net->xt.frame_nat);
106 return 0;
107}
108
109static void __net_exit frame_nat_net_exit(struct net *net)
110{
111 ebt_unregister_table(net->xt.frame_nat);
112}
113
114static struct pernet_operations frame_nat_net_ops = {
115 .init = frame_nat_net_init,
116 .exit = frame_nat_net_exit,
117};
118
101static int __init ebtable_nat_init(void) 119static int __init ebtable_nat_init(void)
102{ 120{
103 int ret; 121 int ret;
104 122
105 ret = ebt_register_table(&frame_nat); 123 ret = register_pernet_subsys(&frame_nat_net_ops);
106 if (ret < 0) 124 if (ret < 0)
107 return ret; 125 return ret;
108 ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); 126 ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
109 if (ret < 0) 127 if (ret < 0)
110 ebt_unregister_table(&frame_nat); 128 unregister_pernet_subsys(&frame_nat_net_ops);
111 return ret; 129 return ret;
112} 130}
113 131
114static void __exit ebtable_nat_fini(void) 132static void __exit ebtable_nat_fini(void)
115{ 133{
116 nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); 134 nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat));
117 ebt_unregister_table(&frame_nat); 135 unregister_pernet_subsys(&frame_nat_net_ops);
118} 136}
119 137
120module_init(ebtable_nat_init); 138module_init(ebtable_nat_init);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 0fa208e86405..fa108c46e851 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -55,7 +55,6 @@
55 55
56 56
57static DEFINE_MUTEX(ebt_mutex); 57static DEFINE_MUTEX(ebt_mutex);
58static LIST_HEAD(ebt_tables);
59 58
60static struct xt_target ebt_standard_target = { 59static struct xt_target ebt_standard_target = {
61 .name = "standard", 60 .name = "standard",
@@ -315,9 +314,11 @@ find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
315} 314}
316 315
317static inline struct ebt_table * 316static inline struct ebt_table *
318find_table_lock(const char *name, int *error, struct mutex *mutex) 317find_table_lock(struct net *net, const char *name, int *error,
318 struct mutex *mutex)
319{ 319{
320 return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); 320 return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name,
321 "ebtable_", error, mutex);
321} 322}
322 323
323static inline int 324static inline int
@@ -944,7 +945,7 @@ static void get_counters(struct ebt_counter *oldcounters,
944} 945}
945 946
946/* replace the table */ 947/* replace the table */
947static int do_replace(void __user *user, unsigned int len) 948static int do_replace(struct net *net, void __user *user, unsigned int len)
948{ 949{
949 int ret, i, countersize; 950 int ret, i, countersize;
950 struct ebt_table_info *newinfo; 951 struct ebt_table_info *newinfo;
@@ -1016,7 +1017,7 @@ static int do_replace(void __user *user, unsigned int len)
1016 if (ret != 0) 1017 if (ret != 0)
1017 goto free_counterstmp; 1018 goto free_counterstmp;
1018 1019
1019 t = find_table_lock(tmp.name, &ret, &ebt_mutex); 1020 t = find_table_lock(net, tmp.name, &ret, &ebt_mutex);
1020 if (!t) { 1021 if (!t) {
1021 ret = -ENOENT; 1022 ret = -ENOENT;
1022 goto free_iterate; 1023 goto free_iterate;
@@ -1097,7 +1098,7 @@ free_newinfo:
1097 return ret; 1098 return ret;
1098} 1099}
1099 1100
1100int ebt_register_table(struct ebt_table *table) 1101struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table)
1101{ 1102{
1102 struct ebt_table_info *newinfo; 1103 struct ebt_table_info *newinfo;
1103 struct ebt_table *t; 1104 struct ebt_table *t;
@@ -1109,14 +1110,21 @@ int ebt_register_table(struct ebt_table *table)
1109 repl->entries_size == 0 || 1110 repl->entries_size == 0 ||
1110 repl->counters || table->private) { 1111 repl->counters || table->private) {
1111 BUGPRINT("Bad table data for ebt_register_table!!!\n"); 1112 BUGPRINT("Bad table data for ebt_register_table!!!\n");
1112 return -EINVAL; 1113 return ERR_PTR(-EINVAL);
1114 }
1115
1116 /* Don't add one table to multiple lists. */
1117 table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL);
1118 if (!table) {
1119 ret = -ENOMEM;
1120 goto out;
1113 } 1121 }
1114 1122
1115 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; 1123 countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids;
1116 newinfo = vmalloc(sizeof(*newinfo) + countersize); 1124 newinfo = vmalloc(sizeof(*newinfo) + countersize);
1117 ret = -ENOMEM; 1125 ret = -ENOMEM;
1118 if (!newinfo) 1126 if (!newinfo)
1119 return -ENOMEM; 1127 goto free_table;
1120 1128
1121 p = vmalloc(repl->entries_size); 1129 p = vmalloc(repl->entries_size);
1122 if (!p) 1130 if (!p)
@@ -1148,7 +1156,7 @@ int ebt_register_table(struct ebt_table *table)
1148 1156
1149 if (table->check && table->check(newinfo, table->valid_hooks)) { 1157 if (table->check && table->check(newinfo, table->valid_hooks)) {
1150 BUGPRINT("The table doesn't like its own initial data, lol\n"); 1158 BUGPRINT("The table doesn't like its own initial data, lol\n");
1151 return -EINVAL; 1159 return ERR_PTR(-EINVAL);
1152 } 1160 }
1153 1161
1154 table->private = newinfo; 1162 table->private = newinfo;
@@ -1157,7 +1165,7 @@ int ebt_register_table(struct ebt_table *table)
1157 if (ret != 0) 1165 if (ret != 0)
1158 goto free_chainstack; 1166 goto free_chainstack;
1159 1167
1160 list_for_each_entry(t, &ebt_tables, list) { 1168 list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) {
1161 if (strcmp(t->name, table->name) == 0) { 1169 if (strcmp(t->name, table->name) == 0) {
1162 ret = -EEXIST; 1170 ret = -EEXIST;
1163 BUGPRINT("Table name already exists\n"); 1171 BUGPRINT("Table name already exists\n");
@@ -1170,9 +1178,9 @@ int ebt_register_table(struct ebt_table *table)
1170 ret = -ENOENT; 1178 ret = -ENOENT;
1171 goto free_unlock; 1179 goto free_unlock;
1172 } 1180 }
1173 list_add(&table->list, &ebt_tables); 1181 list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]);
1174 mutex_unlock(&ebt_mutex); 1182 mutex_unlock(&ebt_mutex);
1175 return 0; 1183 return table;
1176free_unlock: 1184free_unlock:
1177 mutex_unlock(&ebt_mutex); 1185 mutex_unlock(&ebt_mutex);
1178free_chainstack: 1186free_chainstack:
@@ -1184,7 +1192,10 @@ free_chainstack:
1184 vfree(newinfo->entries); 1192 vfree(newinfo->entries);
1185free_newinfo: 1193free_newinfo:
1186 vfree(newinfo); 1194 vfree(newinfo);
1187 return ret; 1195free_table:
1196 kfree(table);
1197out:
1198 return ERR_PTR(ret);
1188} 1199}
1189 1200
1190void ebt_unregister_table(struct ebt_table *table) 1201void ebt_unregister_table(struct ebt_table *table)
@@ -1198,6 +1209,10 @@ void ebt_unregister_table(struct ebt_table *table)
1198 mutex_lock(&ebt_mutex); 1209 mutex_lock(&ebt_mutex);
1199 list_del(&table->list); 1210 list_del(&table->list);
1200 mutex_unlock(&ebt_mutex); 1211 mutex_unlock(&ebt_mutex);
1212 EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size,
1213 ebt_cleanup_entry, NULL);
1214 if (table->private->nentries)
1215 module_put(table->me);
1201 vfree(table->private->entries); 1216 vfree(table->private->entries);
1202 if (table->private->chainstack) { 1217 if (table->private->chainstack) {
1203 for_each_possible_cpu(i) 1218 for_each_possible_cpu(i)
@@ -1205,10 +1220,11 @@ void ebt_unregister_table(struct ebt_table *table)
1205 vfree(table->private->chainstack); 1220 vfree(table->private->chainstack);
1206 } 1221 }
1207 vfree(table->private); 1222 vfree(table->private);
1223 kfree(table);
1208} 1224}
1209 1225
1210/* userspace just supplied us with counters */ 1226/* userspace just supplied us with counters */
1211static int update_counters(void __user *user, unsigned int len) 1227static int update_counters(struct net *net, void __user *user, unsigned int len)
1212{ 1228{
1213 int i, ret; 1229 int i, ret;
1214 struct ebt_counter *tmp; 1230 struct ebt_counter *tmp;
@@ -1228,7 +1244,7 @@ static int update_counters(void __user *user, unsigned int len)
1228 return -ENOMEM; 1244 return -ENOMEM;
1229 } 1245 }
1230 1246
1231 t = find_table_lock(hlp.name, &ret, &ebt_mutex); 1247 t = find_table_lock(net, hlp.name, &ret, &ebt_mutex);
1232 if (!t) 1248 if (!t)
1233 goto free_tmp; 1249 goto free_tmp;
1234 1250
@@ -1386,10 +1402,10 @@ static int do_ebt_set_ctl(struct sock *sk,
1386 1402
1387 switch(cmd) { 1403 switch(cmd) {
1388 case EBT_SO_SET_ENTRIES: 1404 case EBT_SO_SET_ENTRIES:
1389 ret = do_replace(user, len); 1405 ret = do_replace(sock_net(sk), user, len);
1390 break; 1406 break;
1391 case EBT_SO_SET_COUNTERS: 1407 case EBT_SO_SET_COUNTERS:
1392 ret = update_counters(user, len); 1408 ret = update_counters(sock_net(sk), user, len);
1393 break; 1409 break;
1394 default: 1410 default:
1395 ret = -EINVAL; 1411 ret = -EINVAL;
@@ -1406,7 +1422,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1406 if (copy_from_user(&tmp, user, sizeof(tmp))) 1422 if (copy_from_user(&tmp, user, sizeof(tmp)))
1407 return -EFAULT; 1423 return -EFAULT;
1408 1424
1409 t = find_table_lock(tmp.name, &ret, &ebt_mutex); 1425 t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex);
1410 if (!t) 1426 if (!t)
1411 return ret; 1427 return ret;
1412 1428
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index c99eecf89da5..fdf6811c31a2 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -125,6 +125,7 @@ struct ip_rt_info {
125 __be32 daddr; 125 __be32 daddr;
126 __be32 saddr; 126 __be32 saddr;
127 u_int8_t tos; 127 u_int8_t tos;
128 u_int32_t mark;
128}; 129};
129 130
130static void nf_ip_saveroute(const struct sk_buff *skb, 131static void nf_ip_saveroute(const struct sk_buff *skb,
@@ -138,6 +139,7 @@ static void nf_ip_saveroute(const struct sk_buff *skb,
138 rt_info->tos = iph->tos; 139 rt_info->tos = iph->tos;
139 rt_info->daddr = iph->daddr; 140 rt_info->daddr = iph->daddr;
140 rt_info->saddr = iph->saddr; 141 rt_info->saddr = iph->saddr;
142 rt_info->mark = skb->mark;
141 } 143 }
142} 144}
143 145
@@ -150,6 +152,7 @@ static int nf_ip_reroute(struct sk_buff *skb,
150 const struct iphdr *iph = ip_hdr(skb); 152 const struct iphdr *iph = ip_hdr(skb);
151 153
152 if (!(iph->tos == rt_info->tos 154 if (!(iph->tos == rt_info->tos
155 && skb->mark == rt_info->mark
153 && iph->daddr == rt_info->daddr 156 && iph->daddr == rt_info->daddr
154 && iph->saddr == rt_info->saddr)) 157 && iph->saddr == rt_info->saddr))
155 return ip_route_me_harder(skb, RTN_UNSPEC); 158 return ip_route_me_harder(skb, RTN_UNSPEC);
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index bee3d117661a..e091187e864f 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -75,16 +75,6 @@ static unsigned int arpt_out_hook(unsigned int hook,
75 dev_net(out)->ipv4.arptable_filter); 75 dev_net(out)->ipv4.arptable_filter);
76} 76}
77 77
78static unsigned int arpt_forward_hook(unsigned int hook,
79 struct sk_buff *skb,
80 const struct net_device *in,
81 const struct net_device *out,
82 int (*okfn)(struct sk_buff *))
83{
84 return arpt_do_table(skb, hook, in, out,
85 dev_net(in)->ipv4.arptable_filter);
86}
87
88static struct nf_hook_ops arpt_ops[] __read_mostly = { 78static struct nf_hook_ops arpt_ops[] __read_mostly = {
89 { 79 {
90 .hook = arpt_in_hook, 80 .hook = arpt_in_hook,
@@ -101,7 +91,7 @@ static struct nf_hook_ops arpt_ops[] __read_mostly = {
101 .priority = NF_IP_PRI_FILTER, 91 .priority = NF_IP_PRI_FILTER,
102 }, 92 },
103 { 93 {
104 .hook = arpt_forward_hook, 94 .hook = arpt_in_hook,
105 .owner = THIS_MODULE, 95 .owner = THIS_MODULE,
106 .pf = NFPROTO_ARP, 96 .pf = NFPROTO_ARP,
107 .hooknum = NF_ARP_FORWARD, 97 .hooknum = NF_ARP_FORWARD,
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 88762f02779d..3b216be3bc9f 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -23,24 +23,25 @@ MODULE_LICENSE("GPL");
23MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 23MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
24MODULE_DESCRIPTION("Xtables: address type match for IPv4"); 24MODULE_DESCRIPTION("Xtables: address type match for IPv4");
25 25
26static inline bool match_type(const struct net_device *dev, __be32 addr, 26static inline bool match_type(struct net *net, const struct net_device *dev,
27 u_int16_t mask) 27 __be32 addr, u_int16_t mask)
28{ 28{
29 return !!(mask & (1 << inet_dev_addr_type(&init_net, dev, addr))); 29 return !!(mask & (1 << inet_dev_addr_type(net, dev, addr)));
30} 30}
31 31
32static bool 32static bool
33addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) 33addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
34{ 34{
35 struct net *net = dev_net(par->in ? par->in : par->out);
35 const struct ipt_addrtype_info *info = par->matchinfo; 36 const struct ipt_addrtype_info *info = par->matchinfo;
36 const struct iphdr *iph = ip_hdr(skb); 37 const struct iphdr *iph = ip_hdr(skb);
37 bool ret = true; 38 bool ret = true;
38 39
39 if (info->source) 40 if (info->source)
40 ret &= match_type(NULL, iph->saddr, info->source) ^ 41 ret &= match_type(net, NULL, iph->saddr, info->source) ^
41 info->invert_source; 42 info->invert_source;
42 if (info->dest) 43 if (info->dest)
43 ret &= match_type(NULL, iph->daddr, info->dest) ^ 44 ret &= match_type(net, NULL, iph->daddr, info->dest) ^
44 info->invert_dest; 45 info->invert_dest;
45 46
46 return ret; 47 return ret;
@@ -49,6 +50,7 @@ addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
49static bool 50static bool
50addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) 51addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
51{ 52{
53 struct net *net = dev_net(par->in ? par->in : par->out);
52 const struct ipt_addrtype_info_v1 *info = par->matchinfo; 54 const struct ipt_addrtype_info_v1 *info = par->matchinfo;
53 const struct iphdr *iph = ip_hdr(skb); 55 const struct iphdr *iph = ip_hdr(skb);
54 const struct net_device *dev = NULL; 56 const struct net_device *dev = NULL;
@@ -60,10 +62,10 @@ addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par)
60 dev = par->out; 62 dev = par->out;
61 63
62 if (info->source) 64 if (info->source)
63 ret &= match_type(dev, iph->saddr, info->source) ^ 65 ret &= match_type(net, dev, iph->saddr, info->source) ^
64 (info->flags & IPT_ADDRTYPE_INVERT_SOURCE); 66 (info->flags & IPT_ADDRTYPE_INVERT_SOURCE);
65 if (ret && info->dest) 67 if (ret && info->dest)
66 ret &= match_type(dev, iph->daddr, info->dest) ^ 68 ret &= match_type(net, dev, iph->daddr, info->dest) ^
67 !!(info->flags & IPT_ADDRTYPE_INVERT_DEST); 69 !!(info->flags & IPT_ADDRTYPE_INVERT_DEST);
68 return ret; 70 return ret;
69} 71}
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index a4f1c3479e23..cf95469ab9f1 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -86,24 +86,6 @@ ipt_snat_target(struct sk_buff *skb, const struct xt_target_param *par)
86 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC); 86 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC);
87} 87}
88 88
89/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
90static void warn_if_extra_mangle(struct net *net, __be32 dstip, __be32 srcip)
91{
92 static int warned = 0;
93 struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
94 struct rtable *rt;
95
96 if (ip_route_output_key(net, &rt, &fl) != 0)
97 return;
98
99 if (rt->rt_src != srcip && !warned) {
100 printk("NAT: no longer support implicit source local NAT\n");
101 printk("NAT: packet src %pI4 -> dst %pI4\n", &srcip, &dstip);
102 warned = 1;
103 }
104 ip_rt_put(rt);
105}
106
107static unsigned int 89static unsigned int
108ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par) 90ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par)
109{ 91{
@@ -119,11 +101,6 @@ ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par)
119 /* Connection must be valid and new. */ 101 /* Connection must be valid and new. */
120 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); 102 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
121 103
122 if (par->hooknum == NF_INET_LOCAL_OUT &&
123 mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)
124 warn_if_extra_mangle(dev_net(par->out), ip_hdr(skb)->daddr,
125 mr->range[0].min_ip);
126
127 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST); 104 return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST);
128} 105}
129 106
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 627e21db65df..834cea69fb53 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -56,6 +56,7 @@ EXPORT_SYMBOL(ip6_route_me_harder);
56struct ip6_rt_info { 56struct ip6_rt_info {
57 struct in6_addr daddr; 57 struct in6_addr daddr;
58 struct in6_addr saddr; 58 struct in6_addr saddr;
59 u_int32_t mark;
59}; 60};
60 61
61static void nf_ip6_saveroute(const struct sk_buff *skb, 62static void nf_ip6_saveroute(const struct sk_buff *skb,
@@ -68,6 +69,7 @@ static void nf_ip6_saveroute(const struct sk_buff *skb,
68 69
69 rt_info->daddr = iph->daddr; 70 rt_info->daddr = iph->daddr;
70 rt_info->saddr = iph->saddr; 71 rt_info->saddr = iph->saddr;
72 rt_info->mark = skb->mark;
71 } 73 }
72} 74}
73 75
@@ -79,7 +81,8 @@ static int nf_ip6_reroute(struct sk_buff *skb,
79 if (entry->hook == NF_INET_LOCAL_OUT) { 81 if (entry->hook == NF_INET_LOCAL_OUT) {
80 struct ipv6hdr *iph = ipv6_hdr(skb); 82 struct ipv6hdr *iph = ipv6_hdr(skb);
81 if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || 83 if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
82 !ipv6_addr_equal(&iph->saddr, &rt_info->saddr)) 84 !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
85 skb->mark != rt_info->mark)
83 return ip6_route_me_harder(skb); 86 return ip6_route_me_harder(skb);
84 } 87 }
85 return 0; 88 return 0;
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index b110a8a85a14..40d2e36d8fac 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -61,7 +61,7 @@ static struct xt_table packet_filter = {
61 61
62/* The work comes in here from netfilter.c. */ 62/* The work comes in here from netfilter.c. */
63static unsigned int 63static unsigned int
64ip6t_local_in_hook(unsigned int hook, 64ip6t_in_hook(unsigned int hook,
65 struct sk_buff *skb, 65 struct sk_buff *skb,
66 const struct net_device *in, 66 const struct net_device *in,
67 const struct net_device *out, 67 const struct net_device *out,
@@ -72,17 +72,6 @@ ip6t_local_in_hook(unsigned int hook,
72} 72}
73 73
74static unsigned int 74static unsigned int
75ip6t_forward_hook(unsigned int hook,
76 struct sk_buff *skb,
77 const struct net_device *in,
78 const struct net_device *out,
79 int (*okfn)(struct sk_buff *))
80{
81 return ip6t_do_table(skb, hook, in, out,
82 dev_net(in)->ipv6.ip6table_filter);
83}
84
85static unsigned int
86ip6t_local_out_hook(unsigned int hook, 75ip6t_local_out_hook(unsigned int hook,
87 struct sk_buff *skb, 76 struct sk_buff *skb,
88 const struct net_device *in, 77 const struct net_device *in,
@@ -105,14 +94,14 @@ ip6t_local_out_hook(unsigned int hook,
105 94
106static struct nf_hook_ops ip6t_ops[] __read_mostly = { 95static struct nf_hook_ops ip6t_ops[] __read_mostly = {
107 { 96 {
108 .hook = ip6t_local_in_hook, 97 .hook = ip6t_in_hook,
109 .owner = THIS_MODULE, 98 .owner = THIS_MODULE,
110 .pf = PF_INET6, 99 .pf = PF_INET6,
111 .hooknum = NF_INET_LOCAL_IN, 100 .hooknum = NF_INET_LOCAL_IN,
112 .priority = NF_IP6_PRI_FILTER, 101 .priority = NF_IP6_PRI_FILTER,
113 }, 102 },
114 { 103 {
115 .hook = ip6t_forward_hook, 104 .hook = ip6t_in_hook,
116 .owner = THIS_MODULE, 105 .owner = THIS_MODULE,
117 .pf = PF_INET6, 106 .pf = PF_INET6,
118 .hooknum = NF_INET_FORWARD, 107 .hooknum = NF_INET_FORWARD,
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index 38aedeeaf4e1..4f8fcf498545 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -30,6 +30,7 @@ MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
30MODULE_DESCRIPTION("Amanda connection tracking module"); 30MODULE_DESCRIPTION("Amanda connection tracking module");
31MODULE_LICENSE("GPL"); 31MODULE_LICENSE("GPL");
32MODULE_ALIAS("ip_conntrack_amanda"); 32MODULE_ALIAS("ip_conntrack_amanda");
33MODULE_ALIAS_NFCT_HELPER("amanda");
33 34
34module_param(master_timeout, uint, 0600); 35module_param(master_timeout, uint, 0600);
35MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); 36MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 233fdd2d7d21..7e83f74cd5de 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -39,13 +39,13 @@
39#include <net/netfilter/nf_conntrack_extend.h> 39#include <net/netfilter/nf_conntrack_extend.h>
40#include <net/netfilter/nf_conntrack_acct.h> 40#include <net/netfilter/nf_conntrack_acct.h>
41#include <net/netfilter/nf_nat.h> 41#include <net/netfilter/nf_nat.h>
42#include <net/netfilter/nf_nat_core.h>
42 43
43#define NF_CONNTRACK_VERSION "0.5.0" 44#define NF_CONNTRACK_VERSION "0.5.0"
44 45
45unsigned int 46int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct,
46(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, 47 enum nf_nat_manip_type manip,
47 enum nf_nat_manip_type manip, 48 struct nlattr *attr) __read_mostly;
48 struct nlattr *attr) __read_mostly;
49EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); 49EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook);
50 50
51DEFINE_SPINLOCK(nf_conntrack_lock); 51DEFINE_SPINLOCK(nf_conntrack_lock);
@@ -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:
@@ -586,14 +587,7 @@ init_conntrack(struct net *net,
586 nf_conntrack_get(&ct->master->ct_general); 587 nf_conntrack_get(&ct->master->ct_general);
587 NF_CT_STAT_INC(net, expect_new); 588 NF_CT_STAT_INC(net, expect_new);
588 } else { 589 } else {
589 struct nf_conntrack_helper *helper; 590 __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
590
591 helper = __nf_ct_helper_find(&repl_tuple);
592 if (helper) {
593 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
594 if (help)
595 rcu_assign_pointer(help->helper, helper);
596 }
597 NF_CT_STAT_INC(net, new); 591 NF_CT_STAT_INC(net, new);
598 } 592 }
599 593
@@ -770,7 +764,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
770 const struct nf_conntrack_tuple *newreply) 764 const struct nf_conntrack_tuple *newreply)
771{ 765{
772 struct nf_conn_help *help = nfct_help(ct); 766 struct nf_conn_help *help = nfct_help(ct);
773 struct nf_conntrack_helper *helper;
774 767
775 /* Should be unconfirmed, so not in hash table yet */ 768 /* Should be unconfirmed, so not in hash table yet */
776 NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); 769 NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
@@ -783,23 +776,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
783 return; 776 return;
784 777
785 rcu_read_lock(); 778 rcu_read_lock();
786 helper = __nf_ct_helper_find(newreply); 779 __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
787 if (helper == NULL) {
788 if (help)
789 rcu_assign_pointer(help->helper, NULL);
790 goto out;
791 }
792
793 if (help == NULL) {
794 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
795 if (help == NULL)
796 goto out;
797 } else {
798 memset(&help->help, 0, sizeof(help->help));
799 }
800
801 rcu_assign_pointer(help->helper, helper);
802out:
803 rcu_read_unlock(); 780 rcu_read_unlock();
804} 781}
805EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); 782EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
@@ -994,8 +971,20 @@ void nf_ct_iterate_cleanup(struct net *net,
994} 971}
995EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); 972EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup);
996 973
974struct __nf_ct_flush_report {
975 u32 pid;
976 int report;
977};
978
997static int kill_all(struct nf_conn *i, void *data) 979static int kill_all(struct nf_conn *i, void *data)
998{ 980{
981 struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data;
982
983 /* get_next_corpse sets the dying bit for us */
984 nf_conntrack_event_report(IPCT_DESTROY,
985 i,
986 fr->pid,
987 fr->report);
999 return 1; 988 return 1;
1000} 989}
1001 990
@@ -1009,9 +998,13 @@ void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int s
1009} 998}
1010EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); 999EXPORT_SYMBOL_GPL(nf_ct_free_hashtable);
1011 1000
1012void nf_conntrack_flush(struct net *net) 1001void nf_conntrack_flush(struct net *net, u32 pid, int report)
1013{ 1002{
1014 nf_ct_iterate_cleanup(net, kill_all, NULL); 1003 struct __nf_ct_flush_report fr = {
1004 .pid = pid,
1005 .report = report,
1006 };
1007 nf_ct_iterate_cleanup(net, kill_all, &fr);
1015} 1008}
1016EXPORT_SYMBOL_GPL(nf_conntrack_flush); 1009EXPORT_SYMBOL_GPL(nf_conntrack_flush);
1017 1010
@@ -1027,7 +1020,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
1027 nf_ct_event_cache_flush(net); 1020 nf_ct_event_cache_flush(net);
1028 nf_conntrack_ecache_fini(net); 1021 nf_conntrack_ecache_fini(net);
1029 i_see_dead_people: 1022 i_see_dead_people:
1030 nf_conntrack_flush(net); 1023 nf_conntrack_flush(net, 0, 0);
1031 if (atomic_read(&net->ct.count) != 0) { 1024 if (atomic_read(&net->ct.count) != 0) {
1032 schedule(); 1025 schedule();
1033 goto i_see_dead_people; 1026 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
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_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 629500901bd4..00fecc385f9b 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
29MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); 29MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
30MODULE_DESCRIPTION("ftp connection tracking helper"); 30MODULE_DESCRIPTION("ftp connection tracking helper");
31MODULE_ALIAS("ip_conntrack_ftp"); 31MODULE_ALIAS("ip_conntrack_ftp");
32MODULE_ALIAS_NFCT_HELPER("ftp");
32 33
33/* This is slow, but it's simple. --RR */ 34/* This is slow, but it's simple. --RR */
34static char *ftp_buffer; 35static char *ftp_buffer;
@@ -357,7 +358,7 @@ static int help(struct sk_buff *skb,
357 int ret; 358 int ret;
358 u32 seq; 359 u32 seq;
359 int dir = CTINFO2DIR(ctinfo); 360 int dir = CTINFO2DIR(ctinfo);
360 unsigned int matchlen, matchoff; 361 unsigned int uninitialized_var(matchlen), uninitialized_var(matchoff);
361 struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; 362 struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
362 struct nf_conntrack_expect *exp; 363 struct nf_conntrack_expect *exp;
363 union nf_inet_addr *daddr; 364 union nf_inet_addr *daddr;
@@ -427,10 +428,8 @@ static int help(struct sk_buff *skb,
427 connection tracking, not packet filtering. 428 connection tracking, not packet filtering.
428 However, it is necessary for accurate tracking in 429 However, it is necessary for accurate tracking in
429 this case. */ 430 this case. */
430 if (net_ratelimit()) 431 pr_debug("conntrack_ftp: partial %s %u+%u\n",
431 printk("conntrack_ftp: partial %s %u+%u\n", 432 search[dir][i].pattern, ntohl(th->seq), datalen);
432 search[dir][i].pattern,
433 ntohl(th->seq), datalen);
434 ret = NF_DROP; 433 ret = NF_DROP;
435 goto out; 434 goto out;
436 } else if (found == 0) { /* No match */ 435 } else if (found == 0) { /* No match */
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 99bc803d1dd1..687bd633c3d7 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -1827,3 +1827,4 @@ MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
1827MODULE_DESCRIPTION("H.323 connection tracking helper"); 1827MODULE_DESCRIPTION("H.323 connection tracking helper");
1828MODULE_LICENSE("GPL"); 1828MODULE_LICENSE("GPL");
1829MODULE_ALIAS("ip_conntrack_h323"); 1829MODULE_ALIAS("ip_conntrack_h323");
1830MODULE_ALIAS_NFCT_HELPER("h323");
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index c39b6a994133..a51bdac9f3a0 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -45,7 +45,7 @@ static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
45 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize; 45 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize;
46} 46}
47 47
48struct nf_conntrack_helper * 48static struct nf_conntrack_helper *
49__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) 49__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
50{ 50{
51 struct nf_conntrack_helper *helper; 51 struct nf_conntrack_helper *helper;
@@ -63,7 +63,6 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
63 } 63 }
64 return NULL; 64 return NULL;
65} 65}
66EXPORT_SYMBOL_GPL(__nf_ct_helper_find);
67 66
68struct nf_conntrack_helper * 67struct nf_conntrack_helper *
69__nf_conntrack_helper_find_byname(const char *name) 68__nf_conntrack_helper_find_byname(const char *name)
@@ -95,6 +94,35 @@ struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
95} 94}
96EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); 95EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
97 96
97int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags)
98{
99 int ret = 0;
100 struct nf_conntrack_helper *helper;
101 struct nf_conn_help *help = nfct_help(ct);
102
103 helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
104 if (helper == NULL) {
105 if (help)
106 rcu_assign_pointer(help->helper, NULL);
107 goto out;
108 }
109
110 if (help == NULL) {
111 help = nf_ct_helper_ext_add(ct, flags);
112 if (help == NULL) {
113 ret = -ENOMEM;
114 goto out;
115 }
116 } else {
117 memset(&help->help, 0, sizeof(help->help));
118 }
119
120 rcu_assign_pointer(help->helper, helper);
121out:
122 return ret;
123}
124EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper);
125
98static inline int unhelp(struct nf_conntrack_tuple_hash *i, 126static inline int unhelp(struct nf_conntrack_tuple_hash *i,
99 const struct nf_conntrack_helper *me) 127 const struct nf_conntrack_helper *me)
100{ 128{
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 4d681a04447e..409c8be58e7c 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -41,6 +41,7 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
41MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); 41MODULE_DESCRIPTION("IRC (DCC) connection tracking helper");
42MODULE_LICENSE("GPL"); 42MODULE_LICENSE("GPL");
43MODULE_ALIAS("ip_conntrack_irc"); 43MODULE_ALIAS("ip_conntrack_irc");
44MODULE_ALIAS_NFCT_HELPER("irc");
44 45
45module_param_array(ports, ushort, &ports_c, 0400); 46module_param_array(ports, ushort, &ports_c, 0400);
46MODULE_PARM_DESC(ports, "port numbers of IRC servers"); 47MODULE_PARM_DESC(ports, "port numbers of IRC servers");
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 08404e6755fb..5af4273b4668 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -37,6 +37,7 @@ MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
37MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper"); 37MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper");
38MODULE_LICENSE("GPL"); 38MODULE_LICENSE("GPL");
39MODULE_ALIAS("ip_conntrack_netbios_ns"); 39MODULE_ALIAS("ip_conntrack_netbios_ns");
40MODULE_ALIAS_NFCT_HELPER("netbios_ns");
40 41
41static unsigned int timeout __read_mostly = 3; 42static unsigned int timeout __read_mostly = 3;
42module_param(timeout, uint, 0400); 43module_param(timeout, uint, 0400);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 5f4a6516b3b6..00e8c27130ff 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -105,16 +105,14 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
105 struct nf_conntrack_l3proto *l3proto; 105 struct nf_conntrack_l3proto *l3proto;
106 struct nf_conntrack_l4proto *l4proto; 106 struct nf_conntrack_l4proto *l4proto;
107 107
108 l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); 108 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
109 ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); 109 ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto);
110 nf_ct_l3proto_put(l3proto);
111 110
112 if (unlikely(ret < 0)) 111 if (unlikely(ret < 0))
113 return ret; 112 return ret;
114 113
115 l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); 114 l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
116 ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); 115 ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto);
117 nf_ct_l4proto_put(l4proto);
118 116
119 return ret; 117 return ret;
120} 118}
@@ -151,11 +149,9 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct)
151 struct nlattr *nest_proto; 149 struct nlattr *nest_proto;
152 int ret; 150 int ret;
153 151
154 l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); 152 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
155 if (!l4proto->to_nlattr) { 153 if (!l4proto->to_nlattr)
156 nf_ct_l4proto_put(l4proto);
157 return 0; 154 return 0;
158 }
159 155
160 nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED); 156 nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED);
161 if (!nest_proto) 157 if (!nest_proto)
@@ -163,14 +159,11 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct)
163 159
164 ret = l4proto->to_nlattr(skb, nest_proto, ct); 160 ret = l4proto->to_nlattr(skb, nest_proto, ct);
165 161
166 nf_ct_l4proto_put(l4proto);
167
168 nla_nest_end(skb, nest_proto); 162 nla_nest_end(skb, nest_proto);
169 163
170 return ret; 164 return ret;
171 165
172nla_put_failure: 166nla_put_failure:
173 nf_ct_l4proto_put(l4proto);
174 return -1; 167 return -1;
175} 168}
176 169
@@ -184,7 +177,6 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
184 if (!help) 177 if (!help)
185 return 0; 178 return 0;
186 179
187 rcu_read_lock();
188 helper = rcu_dereference(help->helper); 180 helper = rcu_dereference(help->helper);
189 if (!helper) 181 if (!helper)
190 goto out; 182 goto out;
@@ -199,11 +191,9 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct)
199 191
200 nla_nest_end(skb, nest_helper); 192 nla_nest_end(skb, nest_helper);
201out: 193out:
202 rcu_read_unlock();
203 return 0; 194 return 0;
204 195
205nla_put_failure: 196nla_put_failure:
206 rcu_read_unlock();
207 return -1; 197 return -1;
208} 198}
209 199
@@ -420,7 +410,8 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
420 struct nlmsghdr *nlh; 410 struct nlmsghdr *nlh;
421 struct nfgenmsg *nfmsg; 411 struct nfgenmsg *nfmsg;
422 struct nlattr *nest_parms; 412 struct nlattr *nest_parms;
423 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;
424 struct sk_buff *skb; 415 struct sk_buff *skb;
425 unsigned int type; 416 unsigned int type;
426 sk_buff_data_t b; 417 sk_buff_data_t b;
@@ -453,7 +444,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
453 b = skb->tail; 444 b = skb->tail;
454 445
455 type |= NFNL_SUBSYS_CTNETLINK << 8; 446 type |= NFNL_SUBSYS_CTNETLINK << 8;
456 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); 447 nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg));
457 nfmsg = NLMSG_DATA(nlh); 448 nfmsg = NLMSG_DATA(nlh);
458 449
459 nlh->nlmsg_flags = flags; 450 nlh->nlmsg_flags = flags;
@@ -461,6 +452,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
461 nfmsg->version = NFNETLINK_V0; 452 nfmsg->version = NFNETLINK_V0;
462 nfmsg->res_id = 0; 453 nfmsg->res_id = 0;
463 454
455 rcu_read_lock();
464 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); 456 nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED);
465 if (!nest_parms) 457 if (!nest_parms)
466 goto nla_put_failure; 458 goto nla_put_failure;
@@ -517,13 +509,15 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
517 && ctnetlink_dump_mark(skb, ct) < 0) 509 && ctnetlink_dump_mark(skb, ct) < 0)
518 goto nla_put_failure; 510 goto nla_put_failure;
519#endif 511#endif
512 rcu_read_unlock();
520 513
521 nlh->nlmsg_len = skb->tail - b; 514 nlh->nlmsg_len = skb->tail - b;
522 nfnetlink_send(skb, 0, group, 0); 515 nfnetlink_send(skb, item->pid, group, item->report);
523 return NOTIFY_DONE; 516 return NOTIFY_DONE;
524 517
525nlmsg_failure:
526nla_put_failure: 518nla_put_failure:
519 rcu_read_unlock();
520nlmsg_failure:
527 kfree_skb(skb); 521 kfree_skb(skb);
528 return NOTIFY_DONE; 522 return NOTIFY_DONE;
529} 523}
@@ -729,7 +723,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
729 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); 723 err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
730 else { 724 else {
731 /* Flush the whole table */ 725 /* Flush the whole table */
732 nf_conntrack_flush(&init_net); 726 nf_conntrack_flush(&init_net,
727 NETLINK_CB(skb).pid,
728 nlmsg_report(nlh));
733 return 0; 729 return 0;
734 } 730 }
735 731
@@ -750,6 +746,14 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
750 } 746 }
751 } 747 }
752 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
753 nf_ct_kill(ct); 757 nf_ct_kill(ct);
754 nf_ct_put(ct); 758 nf_ct_put(ct);
755 759
@@ -795,8 +799,10 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
795 return -ENOMEM; 799 return -ENOMEM;
796 } 800 }
797 801
802 rcu_read_lock();
798 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, 803 err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
799 IPCTNL_MSG_CT_NEW, 1, ct); 804 IPCTNL_MSG_CT_NEW, 1, ct);
805 rcu_read_unlock();
800 nf_ct_put(ct); 806 nf_ct_put(ct);
801 if (err <= 0) 807 if (err <= 0)
802 goto free; 808 goto free;
@@ -922,8 +928,22 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[])
922 } 928 }
923 929
924 helper = __nf_conntrack_helper_find_byname(helpname); 930 helper = __nf_conntrack_helper_find_byname(helpname);
925 if (helper == NULL) 931 if (helper == NULL) {
932#ifdef CONFIG_MODULES
933 spin_unlock_bh(&nf_conntrack_lock);
934
935 if (request_module("nfct-helper-%s", helpname) < 0) {
936 spin_lock_bh(&nf_conntrack_lock);
937 return -EOPNOTSUPP;
938 }
939
940 spin_lock_bh(&nf_conntrack_lock);
941 helper = __nf_conntrack_helper_find_byname(helpname);
942 if (helper)
943 return -EAGAIN;
944#endif
926 return -EOPNOTSUPP; 945 return -EOPNOTSUPP;
946 }
927 947
928 if (help) { 948 if (help) {
929 if (help->helper == helper) 949 if (help->helper == helper)
@@ -1079,15 +1099,38 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
1079 return 0; 1099 return 0;
1080} 1100}
1081 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
1082static int 1124static int
1083ctnetlink_create_conntrack(struct nlattr *cda[], 1125ctnetlink_create_conntrack(struct nlattr *cda[],
1084 struct nf_conntrack_tuple *otuple, 1126 struct nf_conntrack_tuple *otuple,
1085 struct nf_conntrack_tuple *rtuple, 1127 struct nf_conntrack_tuple *rtuple,
1086 struct nf_conn *master_ct) 1128 struct nf_conn *master_ct,
1129 u32 pid,
1130 int report)
1087{ 1131{
1088 struct nf_conn *ct; 1132 struct nf_conn *ct;
1089 int err = -EINVAL; 1133 int err = -EINVAL;
1090 struct nf_conn_help *help;
1091 struct nf_conntrack_helper *helper; 1134 struct nf_conntrack_helper *helper;
1092 1135
1093 ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); 1136 ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC);
@@ -1102,16 +1145,55 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1102 ct->status |= IPS_CONFIRMED; 1145 ct->status |= IPS_CONFIRMED;
1103 1146
1104 rcu_read_lock(); 1147 rcu_read_lock();
1105 helper = __nf_ct_helper_find(rtuple); 1148 if (cda[CTA_HELP]) {
1106 if (helper) { 1149 char *helpname;
1107 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); 1150
1108 if (help == NULL) { 1151 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
1152 if (err < 0) {
1153 rcu_read_unlock();
1154 goto err;
1155 }
1156
1157 helper = __nf_conntrack_helper_find_byname(helpname);
1158 if (helper == NULL) {
1159 rcu_read_unlock();
1160#ifdef CONFIG_MODULES
1161 if (request_module("nfct-helper-%s", helpname) < 0) {
1162 err = -EOPNOTSUPP;
1163 goto err;
1164 }
1165
1166 rcu_read_lock();
1167 helper = __nf_conntrack_helper_find_byname(helpname);
1168 if (helper) {
1169 rcu_read_unlock();
1170 err = -EAGAIN;
1171 goto err;
1172 }
1173 rcu_read_unlock();
1174#endif
1175 err = -EOPNOTSUPP;
1176 goto err;
1177 } else {
1178 struct nf_conn_help *help;
1179
1180 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
1181 if (help == NULL) {
1182 rcu_read_unlock();
1183 err = -ENOMEM;
1184 goto err;
1185 }
1186
1187 /* not in hash table yet so not strictly necessary */
1188 rcu_assign_pointer(help->helper, helper);
1189 }
1190 } else {
1191 /* try an implicit helper assignation */
1192 err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
1193 if (err < 0) {
1109 rcu_read_unlock(); 1194 rcu_read_unlock();
1110 err = -ENOMEM;
1111 goto err; 1195 goto err;
1112 } 1196 }
1113 /* not in hash table yet so not strictly necessary */
1114 rcu_assign_pointer(help->helper, helper);
1115 } 1197 }
1116 1198
1117 if (cda[CTA_STATUS]) { 1199 if (cda[CTA_STATUS]) {
@@ -1151,9 +1233,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1151 ct->master = master_ct; 1233 ct->master = master_ct;
1152 } 1234 }
1153 1235
1236 nf_conntrack_get(&ct->ct_general);
1154 add_timer(&ct->timeout); 1237 add_timer(&ct->timeout);
1155 nf_conntrack_hash_insert(ct); 1238 nf_conntrack_hash_insert(ct);
1156 rcu_read_unlock(); 1239 rcu_read_unlock();
1240 ctnetlink_event_report(ct, pid, report);
1241 nf_ct_put(ct);
1157 1242
1158 return 0; 1243 return 0;
1159 1244
@@ -1209,7 +1294,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1209 goto out_unlock; 1294 goto out_unlock;
1210 } 1295 }
1211 master_ct = nf_ct_tuplehash_to_ctrack(master_h); 1296 master_ct = nf_ct_tuplehash_to_ctrack(master_h);
1212 atomic_inc(&master_ct->ct_general.use); 1297 nf_conntrack_get(&master_ct->ct_general);
1213 } 1298 }
1214 1299
1215 err = -ENOENT; 1300 err = -ENOENT;
@@ -1217,9 +1302,10 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1217 err = ctnetlink_create_conntrack(cda, 1302 err = ctnetlink_create_conntrack(cda,
1218 &otuple, 1303 &otuple,
1219 &rtuple, 1304 &rtuple,
1220 master_ct); 1305 master_ct,
1306 NETLINK_CB(skb).pid,
1307 nlmsg_report(nlh));
1221 spin_unlock_bh(&nf_conntrack_lock); 1308 spin_unlock_bh(&nf_conntrack_lock);
1222
1223 if (err < 0 && master_ct) 1309 if (err < 0 && master_ct)
1224 nf_ct_put(master_ct); 1310 nf_ct_put(master_ct);
1225 1311
@@ -1231,6 +1317,8 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1231 * so there's no need to increase the refcount */ 1317 * so there's no need to increase the refcount */
1232 err = -EEXIST; 1318 err = -EEXIST;
1233 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
1234 /* we only allow nat config for new conntracks */ 1322 /* we only allow nat config for new conntracks */
1235 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { 1323 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
1236 err = -EOPNOTSUPP; 1324 err = -EOPNOTSUPP;
@@ -1241,8 +1329,19 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1241 err = -EOPNOTSUPP; 1329 err = -EOPNOTSUPP;
1242 goto out_unlock; 1330 goto out_unlock;
1243 } 1331 }
1244 err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), 1332
1245 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;
1246 } 1345 }
1247 1346
1248out_unlock: 1347out_unlock:
@@ -1293,16 +1392,14 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb,
1293 if (!nest_parms) 1392 if (!nest_parms)
1294 goto nla_put_failure; 1393 goto nla_put_failure;
1295 1394
1296 l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); 1395 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
1297 ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); 1396 ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
1298 nf_ct_l3proto_put(l3proto);
1299 1397
1300 if (unlikely(ret < 0)) 1398 if (unlikely(ret < 0))
1301 goto nla_put_failure; 1399 goto nla_put_failure;
1302 1400
1303 l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); 1401 l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
1304 ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); 1402 ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
1305 nf_ct_l4proto_put(l4proto);
1306 if (unlikely(ret < 0)) 1403 if (unlikely(ret < 0))
1307 goto nla_put_failure; 1404 goto nla_put_failure;
1308 1405
@@ -1379,7 +1476,8 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1379{ 1476{
1380 struct nlmsghdr *nlh; 1477 struct nlmsghdr *nlh;
1381 struct nfgenmsg *nfmsg; 1478 struct nfgenmsg *nfmsg;
1382 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;
1383 struct sk_buff *skb; 1481 struct sk_buff *skb;
1384 unsigned int type; 1482 unsigned int type;
1385 sk_buff_data_t b; 1483 sk_buff_data_t b;
@@ -1401,7 +1499,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1401 b = skb->tail; 1499 b = skb->tail;
1402 1500
1403 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; 1501 type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
1404 nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); 1502 nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg));
1405 nfmsg = NLMSG_DATA(nlh); 1503 nfmsg = NLMSG_DATA(nlh);
1406 1504
1407 nlh->nlmsg_flags = flags; 1505 nlh->nlmsg_flags = flags;
@@ -1409,15 +1507,18 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1409 nfmsg->version = NFNETLINK_V0; 1507 nfmsg->version = NFNETLINK_V0;
1410 nfmsg->res_id = 0; 1508 nfmsg->res_id = 0;
1411 1509
1510 rcu_read_lock();
1412 if (ctnetlink_exp_dump_expect(skb, exp) < 0) 1511 if (ctnetlink_exp_dump_expect(skb, exp) < 0)
1413 goto nla_put_failure; 1512 goto nla_put_failure;
1513 rcu_read_unlock();
1414 1514
1415 nlh->nlmsg_len = skb->tail - b; 1515 nlh->nlmsg_len = skb->tail - b;
1416 nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); 1516 nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report);
1417 return NOTIFY_DONE; 1517 return NOTIFY_DONE;
1418 1518
1419nlmsg_failure:
1420nla_put_failure: 1519nla_put_failure:
1520 rcu_read_unlock();
1521nlmsg_failure:
1421 kfree_skb(skb); 1522 kfree_skb(skb);
1422 return NOTIFY_DONE; 1523 return NOTIFY_DONE;
1423} 1524}
@@ -1521,9 +1622,11 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
1521 if (!skb2) 1622 if (!skb2)
1522 goto out; 1623 goto out;
1523 1624
1625 rcu_read_lock();
1524 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, 1626 err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
1525 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1627 nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1526 1, exp); 1628 1, exp);
1629 rcu_read_unlock();
1527 if (err <= 0) 1630 if (err <= 0)
1528 goto free; 1631 goto free;
1529 1632
@@ -1624,7 +1727,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[])
1624} 1727}
1625 1728
1626static int 1729static int
1627ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) 1730ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3, u32 pid, int report)
1628{ 1731{
1629 struct nf_conntrack_tuple tuple, mask, master_tuple; 1732 struct nf_conntrack_tuple tuple, mask, master_tuple;
1630 struct nf_conntrack_tuple_hash *h = NULL; 1733 struct nf_conntrack_tuple_hash *h = NULL;
@@ -1653,7 +1756,7 @@ ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3)
1653 1756
1654 if (!help || !help->helper) { 1757 if (!help || !help->helper) {
1655 /* such conntrack hasn't got any helper, abort */ 1758 /* such conntrack hasn't got any helper, abort */
1656 err = -EINVAL; 1759 err = -EOPNOTSUPP;
1657 goto out; 1760 goto out;
1658 } 1761 }
1659 1762
@@ -1671,7 +1774,7 @@ ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3)
1671 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));
1672 exp->mask.src.u.all = mask.src.u.all; 1775 exp->mask.src.u.all = mask.src.u.all;
1673 1776
1674 err = nf_ct_expect_related(exp); 1777 err = nf_ct_expect_related_report(exp, pid, report);
1675 nf_ct_expect_put(exp); 1778 nf_ct_expect_put(exp);
1676 1779
1677out: 1780out:
@@ -1704,8 +1807,12 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
1704 if (!exp) { 1807 if (!exp) {
1705 spin_unlock_bh(&nf_conntrack_lock); 1808 spin_unlock_bh(&nf_conntrack_lock);
1706 err = -ENOENT; 1809 err = -ENOENT;
1707 if (nlh->nlmsg_flags & NLM_F_CREATE) 1810 if (nlh->nlmsg_flags & NLM_F_CREATE) {
1708 err = ctnetlink_create_expect(cda, u3); 1811 err = ctnetlink_create_expect(cda,
1812 u3,
1813 NETLINK_CB(skb).pid,
1814 nlmsg_report(nlh));
1815 }
1709 return err; 1816 return err;
1710 } 1817 }
1711 1818
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 1bc3001d1827..9e169ef2e854 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -37,6 +37,7 @@ MODULE_LICENSE("GPL");
37MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); 37MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
38MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); 38MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP");
39MODULE_ALIAS("ip_conntrack_pptp"); 39MODULE_ALIAS("ip_conntrack_pptp");
40MODULE_ALIAS_NFCT_HELPER("pptp");
40 41
41static DEFINE_SPINLOCK(nf_pptp_lock); 42static DEFINE_SPINLOCK(nf_pptp_lock);
42 43
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 4ab62ad85dd4..1b279f9d6bf3 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -341,7 +341,7 @@ static int __init nf_ct_proto_gre_init(void)
341 return rv; 341 return rv;
342} 342}
343 343
344static void nf_ct_proto_gre_fini(void) 344static void __exit nf_ct_proto_gre_fini(void)
345{ 345{
346 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); 346 nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
347 unregister_pernet_gen_subsys(proto_gre_net_id, &proto_gre_net_ops); 347 unregister_pernet_gen_subsys(proto_gre_net_id, &proto_gre_net_ops);
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index c2bd457bc2f2..74e037901199 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -317,7 +317,7 @@ static int sctp_packet(struct nf_conn *ct,
317 goto out; 317 goto out;
318 } 318 }
319 319
320 old_state = new_state = SCTP_CONNTRACK_MAX; 320 old_state = new_state = SCTP_CONNTRACK_NONE;
321 write_lock_bh(&sctp_lock); 321 write_lock_bh(&sctp_lock);
322 for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { 322 for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
323 /* Special cases of Verification tag check (Sec 8.5.1) */ 323 /* Special cases of Verification tag check (Sec 8.5.1) */
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index a94294b2b23c..dcfecbb81c46 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -30,6 +30,7 @@
30MODULE_LICENSE("GPL"); 30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>"); 31MODULE_AUTHOR("Michal Schmidt <mschmidt@redhat.com>");
32MODULE_DESCRIPTION("SANE connection tracking helper"); 32MODULE_DESCRIPTION("SANE connection tracking helper");
33MODULE_ALIAS_NFCT_HELPER("sane");
33 34
34static char *sane_buffer; 35static char *sane_buffer;
35 36
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 6813f1c8863f..4b572163784b 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -28,6 +28,7 @@ MODULE_LICENSE("GPL");
28MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); 28MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
29MODULE_DESCRIPTION("SIP connection tracking helper"); 29MODULE_DESCRIPTION("SIP connection tracking helper");
30MODULE_ALIAS("ip_conntrack_sip"); 30MODULE_ALIAS("ip_conntrack_sip");
31MODULE_ALIAS_NFCT_HELPER("sip");
31 32
32#define MAX_PORTS 8 33#define MAX_PORTS 8
33static unsigned short ports[MAX_PORTS]; 34static unsigned short ports[MAX_PORTS];
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index f57f6e7a71ee..46e646b2e9b9 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -22,6 +22,7 @@ MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
22MODULE_DESCRIPTION("TFTP connection tracking helper"); 22MODULE_DESCRIPTION("TFTP connection tracking helper");
23MODULE_LICENSE("GPL"); 23MODULE_LICENSE("GPL");
24MODULE_ALIAS("ip_conntrack_tftp"); 24MODULE_ALIAS("ip_conntrack_tftp");
25MODULE_ALIAS_NFCT_HELPER("tftp");
25 26
26#define MAX_PORTS 8 27#define MAX_PORTS 8
27static unsigned short ports[MAX_PORTS]; 28static unsigned short ports[MAX_PORTS];
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 41e0105d3828..2770b4e57ea0 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -30,6 +30,7 @@
30#include <linux/random.h> 30#include <linux/random.h>
31#include <net/sock.h> 31#include <net/sock.h>
32#include <net/netfilter/nf_log.h> 32#include <net/netfilter/nf_log.h>
33#include <net/netfilter/nfnetlink_log.h>
33 34
34#include <asm/atomic.h> 35#include <asm/atomic.h>
35 36
@@ -533,7 +534,7 @@ static struct nf_loginfo default_loginfo = {
533}; 534};
534 535
535/* log handler for internal netfilter logging api */ 536/* log handler for internal netfilter logging api */
536static void 537void
537nfulnl_log_packet(u_int8_t pf, 538nfulnl_log_packet(u_int8_t pf,
538 unsigned int hooknum, 539 unsigned int hooknum,
539 const struct sk_buff *skb, 540 const struct sk_buff *skb,
@@ -648,6 +649,7 @@ alloc_failure:
648 /* FIXME: statistics */ 649 /* FIXME: statistics */
649 goto unlock_and_release; 650 goto unlock_and_release;
650} 651}
652EXPORT_SYMBOL_GPL(nfulnl_log_packet);
651 653
652static int 654static int
653nfulnl_rcv_nl_event(struct notifier_block *this, 655nfulnl_rcv_nl_event(struct notifier_block *this,
diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c
index 50e3a52d3b31..a57c5cf018ec 100644
--- a/net/netfilter/xt_NFLOG.c
+++ b/net/netfilter/xt_NFLOG.c
@@ -13,6 +13,7 @@
13#include <linux/netfilter/x_tables.h> 13#include <linux/netfilter/x_tables.h>
14#include <linux/netfilter/xt_NFLOG.h> 14#include <linux/netfilter/xt_NFLOG.h>
15#include <net/netfilter/nf_log.h> 15#include <net/netfilter/nf_log.h>
16#include <net/netfilter/nfnetlink_log.h>
16 17
17MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 18MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
18MODULE_DESCRIPTION("Xtables: packet logging to netlink using NFLOG"); 19MODULE_DESCRIPTION("Xtables: packet logging to netlink using NFLOG");
@@ -31,8 +32,8 @@ nflog_tg(struct sk_buff *skb, const struct xt_target_param *par)
31 li.u.ulog.group = info->group; 32 li.u.ulog.group = info->group;
32 li.u.ulog.qthreshold = info->threshold; 33 li.u.ulog.qthreshold = info->threshold;
33 34
34 nf_log_packet(par->family, par->hooknum, skb, par->in, 35 nfulnl_log_packet(par->family, par->hooknum, skb, par->in,
35 par->out, &li, "%s", info->prefix); 36 par->out, &li, info->prefix);
36 return XT_CONTINUE; 37 return XT_CONTINUE;
37} 38}
38 39
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 3c3dd22b1d06..fe80b614a400 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -72,9 +72,6 @@ struct recent_entry {
72struct recent_table { 72struct recent_table {
73 struct list_head list; 73 struct list_head list;
74 char name[XT_RECENT_NAME_LEN]; 74 char name[XT_RECENT_NAME_LEN];
75#ifdef CONFIG_PROC_FS
76 struct proc_dir_entry *proc_old, *proc;
77#endif
78 unsigned int refcnt; 75 unsigned int refcnt;
79 unsigned int entries; 76 unsigned int entries;
80 struct list_head lru_list; 77 struct list_head lru_list;
@@ -284,6 +281,9 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
284{ 281{
285 const struct xt_recent_mtinfo *info = par->matchinfo; 282 const struct xt_recent_mtinfo *info = par->matchinfo;
286 struct recent_table *t; 283 struct recent_table *t;
284#ifdef CONFIG_PROC_FS
285 struct proc_dir_entry *pde;
286#endif
287 unsigned i; 287 unsigned i;
288 bool ret = false; 288 bool ret = false;
289 289
@@ -318,25 +318,25 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
318 for (i = 0; i < ip_list_hash_size; i++) 318 for (i = 0; i < ip_list_hash_size; i++)
319 INIT_LIST_HEAD(&t->iphash[i]); 319 INIT_LIST_HEAD(&t->iphash[i]);
320#ifdef CONFIG_PROC_FS 320#ifdef CONFIG_PROC_FS
321 t->proc = proc_create_data(t->name, ip_list_perms, recent_proc_dir, 321 pde = proc_create_data(t->name, ip_list_perms, recent_proc_dir,
322 &recent_mt_fops, t); 322 &recent_mt_fops, t);
323 if (t->proc == NULL) { 323 if (pde == NULL) {
324 kfree(t); 324 kfree(t);
325 goto out; 325 goto out;
326 } 326 }
327 pde->uid = ip_list_uid;
328 pde->gid = ip_list_gid;
327#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT 329#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT
328 t->proc_old = proc_create_data(t->name, ip_list_perms, proc_old_dir, 330 pde = proc_create_data(t->name, ip_list_perms, proc_old_dir,
329 &recent_old_fops, t); 331 &recent_old_fops, t);
330 if (t->proc_old == NULL) { 332 if (pde == NULL) {
331 remove_proc_entry(t->name, proc_old_dir); 333 remove_proc_entry(t->name, proc_old_dir);
332 kfree(t); 334 kfree(t);
333 goto out; 335 goto out;
334 } 336 }
335 t->proc_old->uid = ip_list_uid; 337 pde->uid = ip_list_uid;
336 t->proc_old->gid = ip_list_gid; 338 pde->gid = ip_list_gid;
337#endif 339#endif
338 t->proc->uid = ip_list_uid;
339 t->proc->gid = ip_list_gid;
340#endif 340#endif
341 spin_lock_bh(&recent_lock); 341 spin_lock_bh(&recent_lock);
342 list_add_tail(&t->list, &tables); 342 list_add_tail(&t->list, &tables);