diff options
43 files changed, 1305 insertions, 429 deletions
diff --git a/Documentation/networking/nf_conntrack-sysctl.txt b/Documentation/networking/nf_conntrack-sysctl.txt new file mode 100644 index 000000000000..70da5086153d --- /dev/null +++ b/Documentation/networking/nf_conntrack-sysctl.txt | |||
@@ -0,0 +1,176 @@ | |||
1 | /proc/sys/net/netfilter/nf_conntrack_* Variables: | ||
2 | |||
3 | nf_conntrack_acct - BOOLEAN | ||
4 | 0 - disabled (default) | ||
5 | not 0 - enabled | ||
6 | |||
7 | Enable connection tracking flow accounting. 64-bit byte and packet | ||
8 | counters per flow are added. | ||
9 | |||
10 | nf_conntrack_buckets - INTEGER (read-only) | ||
11 | Size of hash table. If not specified as parameter during module | ||
12 | loading, the default size is calculated by dividing total memory | ||
13 | by 16384 to determine the number of buckets but the hash table will | ||
14 | never have fewer than 32 or more than 16384 buckets. | ||
15 | |||
16 | nf_conntrack_checksum - BOOLEAN | ||
17 | 0 - disabled | ||
18 | not 0 - enabled (default) | ||
19 | |||
20 | Verify checksum of incoming packets. Packets with bad checksums are | ||
21 | in INVALID state. If this is enabled, such packets will not be | ||
22 | considered for connection tracking. | ||
23 | |||
24 | nf_conntrack_count - INTEGER (read-only) | ||
25 | Number of currently allocated flow entries. | ||
26 | |||
27 | nf_conntrack_events - BOOLEAN | ||
28 | 0 - disabled | ||
29 | not 0 - enabled (default) | ||
30 | |||
31 | If this option is enabled, the connection tracking code will | ||
32 | provide userspace with connection tracking events via ctnetlink. | ||
33 | |||
34 | nf_conntrack_events_retry_timeout - INTEGER (seconds) | ||
35 | default 15 | ||
36 | |||
37 | This option is only relevant when "reliable connection tracking | ||
38 | events" are used. Normally, ctnetlink is "lossy", that is, | ||
39 | events are normally dropped when userspace listeners can't keep up. | ||
40 | |||
41 | Userspace can request "reliable event mode". When this mode is | ||
42 | active, the conntrack will only be destroyed after the event was | ||
43 | delivered. If event delivery fails, the kernel periodically | ||
44 | re-tries to send the event to userspace. | ||
45 | |||
46 | This is the maximum interval the kernel should use when re-trying | ||
47 | to deliver the destroy event. | ||
48 | |||
49 | A higher number means there will be fewer delivery retries and it | ||
50 | will take longer for a backlog to be processed. | ||
51 | |||
52 | nf_conntrack_expect_max - INTEGER | ||
53 | Maximum size of expectation table. Default value is | ||
54 | nf_conntrack_buckets / 256. Minimum is 1. | ||
55 | |||
56 | nf_conntrack_frag6_high_thresh - INTEGER | ||
57 | default 262144 | ||
58 | |||
59 | Maximum memory used to reassemble IPv6 fragments. When | ||
60 | nf_conntrack_frag6_high_thresh bytes of memory is allocated for this | ||
61 | purpose, the fragment handler will toss packets until | ||
62 | nf_conntrack_frag6_low_thresh is reached. | ||
63 | |||
64 | nf_conntrack_frag6_low_thresh - INTEGER | ||
65 | default 196608 | ||
66 | |||
67 | See nf_conntrack_frag6_low_thresh | ||
68 | |||
69 | nf_conntrack_frag6_timeout - INTEGER (seconds) | ||
70 | default 60 | ||
71 | |||
72 | Time to keep an IPv6 fragment in memory. | ||
73 | |||
74 | nf_conntrack_generic_timeout - INTEGER (seconds) | ||
75 | default 600 | ||
76 | |||
77 | Default for generic timeout. This refers to layer 4 unknown/unsupported | ||
78 | protocols. | ||
79 | |||
80 | nf_conntrack_helper - BOOLEAN | ||
81 | 0 - disabled | ||
82 | not 0 - enabled (default) | ||
83 | |||
84 | Enable automatic conntrack helper assignment. | ||
85 | |||
86 | nf_conntrack_icmp_timeout - INTEGER (seconds) | ||
87 | default 30 | ||
88 | |||
89 | Default for ICMP timeout. | ||
90 | |||
91 | nf_conntrack_icmpv6_timeout - INTEGER (seconds) | ||
92 | default 30 | ||
93 | |||
94 | Default for ICMP6 timeout. | ||
95 | |||
96 | nf_conntrack_log_invalid - INTEGER | ||
97 | 0 - disable (default) | ||
98 | 1 - log ICMP packets | ||
99 | 6 - log TCP packets | ||
100 | 17 - log UDP packets | ||
101 | 33 - log DCCP packets | ||
102 | 41 - log ICMPv6 packets | ||
103 | 136 - log UDPLITE packets | ||
104 | 255 - log packets of any protocol | ||
105 | |||
106 | Log invalid packets of a type specified by value. | ||
107 | |||
108 | nf_conntrack_max - INTEGER | ||
109 | Size of connection tracking table. Default value is | ||
110 | nf_conntrack_buckets value * 4. | ||
111 | |||
112 | nf_conntrack_tcp_be_liberal - BOOLEAN | ||
113 | 0 - disabled (default) | ||
114 | not 0 - enabled | ||
115 | |||
116 | Be conservative in what you do, be liberal in what you accept from others. | ||
117 | If it's non-zero, we mark only out of window RST segments as INVALID. | ||
118 | |||
119 | nf_conntrack_tcp_loose - BOOLEAN | ||
120 | 0 - disabled | ||
121 | not 0 - enabled (default) | ||
122 | |||
123 | If it is set to zero, we disable picking up already established | ||
124 | connections. | ||
125 | |||
126 | nf_conntrack_tcp_max_retrans - INTEGER | ||
127 | default 3 | ||
128 | |||
129 | Maximum number of packets that can be retransmitted without | ||
130 | received an (acceptable) ACK from the destination. If this number | ||
131 | is reached, a shorter timer will be started. | ||
132 | |||
133 | nf_conntrack_tcp_timeout_close - INTEGER (seconds) | ||
134 | default 10 | ||
135 | |||
136 | nf_conntrack_tcp_timeout_close_wait - INTEGER (seconds) | ||
137 | default 60 | ||
138 | |||
139 | nf_conntrack_tcp_timeout_established - INTEGER (seconds) | ||
140 | default 432000 (5 days) | ||
141 | |||
142 | nf_conntrack_tcp_timeout_fin_wait - INTEGER (seconds) | ||
143 | default 120 | ||
144 | |||
145 | nf_conntrack_tcp_timeout_last_ack - INTEGER (seconds) | ||
146 | default 30 | ||
147 | |||
148 | nf_conntrack_tcp_timeout_max_retrans - INTEGER (seconds) | ||
149 | default 300 | ||
150 | |||
151 | nf_conntrack_tcp_timeout_syn_recv - INTEGER (seconds) | ||
152 | default 60 | ||
153 | |||
154 | nf_conntrack_tcp_timeout_syn_sent - INTEGER (seconds) | ||
155 | default 120 | ||
156 | |||
157 | nf_conntrack_tcp_timeout_time_wait - INTEGER (seconds) | ||
158 | default 120 | ||
159 | |||
160 | nf_conntrack_tcp_timeout_unacknowledged - INTEGER (seconds) | ||
161 | default 300 | ||
162 | |||
163 | nf_conntrack_timestamp - BOOLEAN | ||
164 | 0 - disabled (default) | ||
165 | not 0 - enabled | ||
166 | |||
167 | Enable connection tracking flow timestamping. | ||
168 | |||
169 | nf_conntrack_udp_timeout - INTEGER (seconds) | ||
170 | default 30 | ||
171 | |||
172 | nf_conntrack_udp_timeout_stream2 - INTEGER (seconds) | ||
173 | default 180 | ||
174 | |||
175 | This extended timeout will be used in case there is an UDP stream | ||
176 | detected. | ||
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 387bdd02945d..ba7f571a2b1c 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
@@ -4,12 +4,15 @@ | |||
4 | 4 | ||
5 | #include <net/netfilter/nf_conntrack_expect.h> | 5 | #include <net/netfilter/nf_conntrack_expect.h> |
6 | 6 | ||
7 | #include <linux/types.h> | ||
8 | |||
7 | #define SIP_PORT 5060 | 9 | #define SIP_PORT 5060 |
8 | #define SIP_TIMEOUT 3600 | 10 | #define SIP_TIMEOUT 3600 |
9 | 11 | ||
10 | struct nf_ct_sip_master { | 12 | struct nf_ct_sip_master { |
11 | unsigned int register_cseq; | 13 | unsigned int register_cseq; |
12 | unsigned int invite_cseq; | 14 | unsigned int invite_cseq; |
15 | __be16 forced_dport; | ||
13 | }; | 16 | }; |
14 | 17 | ||
15 | enum sip_expectation_classes { | 18 | enum sip_expectation_classes { |
diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h index 463ae8e16696..2bdb7a15fe06 100644 --- a/include/net/netfilter/nf_conntrack_acct.h +++ b/include/net/netfilter/nf_conntrack_acct.h | |||
@@ -57,7 +57,9 @@ static inline void nf_ct_set_acct(struct net *net, bool enable) | |||
57 | net->ct.sysctl_acct = enable; | 57 | net->ct.sysctl_acct = enable; |
58 | } | 58 | } |
59 | 59 | ||
60 | extern int nf_conntrack_acct_init(struct net *net); | 60 | extern int nf_conntrack_acct_pernet_init(struct net *net); |
61 | extern void nf_conntrack_acct_fini(struct net *net); | 61 | extern void nf_conntrack_acct_pernet_fini(struct net *net); |
62 | 62 | ||
63 | extern int nf_conntrack_acct_init(void); | ||
64 | extern void nf_conntrack_acct_fini(void); | ||
63 | #endif /* _NF_CONNTRACK_ACCT_H */ | 65 | #endif /* _NF_CONNTRACK_ACCT_H */ |
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index e98aeb3da033..930275fa2ea6 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h | |||
@@ -25,12 +25,19 @@ extern unsigned int nf_conntrack_in(struct net *net, | |||
25 | unsigned int hooknum, | 25 | unsigned int hooknum, |
26 | struct sk_buff *skb); | 26 | struct sk_buff *skb); |
27 | 27 | ||
28 | extern int nf_conntrack_init(struct net *net); | 28 | extern int nf_conntrack_init_net(struct net *net); |
29 | extern void nf_conntrack_cleanup(struct net *net); | 29 | extern void nf_conntrack_cleanup_net(struct net *net); |
30 | 30 | ||
31 | extern int nf_conntrack_proto_init(struct net *net); | 31 | extern int nf_conntrack_proto_pernet_init(struct net *net); |
32 | extern void nf_conntrack_proto_fini(struct net *net); | 32 | extern void nf_conntrack_proto_pernet_fini(struct net *net); |
33 | 33 | ||
34 | extern int nf_conntrack_proto_init(void); | ||
35 | extern void nf_conntrack_proto_fini(void); | ||
36 | |||
37 | extern int nf_conntrack_init_start(void); | ||
38 | extern void nf_conntrack_cleanup_start(void); | ||
39 | |||
40 | extern void nf_conntrack_init_end(void); | ||
34 | extern void nf_conntrack_cleanup_end(void); | 41 | extern void nf_conntrack_cleanup_end(void); |
35 | 42 | ||
36 | extern bool | 43 | extern bool |
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 5654d292efd4..092dc651689f 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h | |||
@@ -207,9 +207,11 @@ nf_ct_expect_event(enum ip_conntrack_expect_events event, | |||
207 | nf_ct_expect_event_report(event, exp, 0, 0); | 207 | nf_ct_expect_event_report(event, exp, 0, 0); |
208 | } | 208 | } |
209 | 209 | ||
210 | extern int nf_conntrack_ecache_init(struct net *net); | 210 | extern int nf_conntrack_ecache_pernet_init(struct net *net); |
211 | extern void nf_conntrack_ecache_fini(struct net *net); | 211 | extern void nf_conntrack_ecache_pernet_fini(struct net *net); |
212 | 212 | ||
213 | extern int nf_conntrack_ecache_init(void); | ||
214 | extern void nf_conntrack_ecache_fini(void); | ||
213 | #else /* CONFIG_NF_CONNTRACK_EVENTS */ | 215 | #else /* CONFIG_NF_CONNTRACK_EVENTS */ |
214 | 216 | ||
215 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, | 217 | static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, |
@@ -232,12 +234,21 @@ static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, | |||
232 | u32 portid, | 234 | u32 portid, |
233 | int report) {} | 235 | int report) {} |
234 | 236 | ||
235 | static inline int nf_conntrack_ecache_init(struct net *net) | 237 | static inline int nf_conntrack_ecache_pernet_init(struct net *net) |
236 | { | 238 | { |
237 | return 0; | 239 | return 0; |
238 | } | 240 | } |
239 | 241 | ||
240 | static inline void nf_conntrack_ecache_fini(struct net *net) | 242 | static inline void nf_conntrack_ecache_pernet_fini(struct net *net) |
243 | { | ||
244 | } | ||
245 | |||
246 | static inline int nf_conntrack_ecache_init(void) | ||
247 | { | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static inline void nf_conntrack_ecache_fini(void) | ||
241 | { | 252 | { |
242 | } | 253 | } |
243 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ | 254 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ |
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index cc13f377a705..cbbae7621e22 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h | |||
@@ -69,8 +69,11 @@ struct nf_conntrack_expect_policy { | |||
69 | 69 | ||
70 | #define NF_CT_EXPECT_CLASS_DEFAULT 0 | 70 | #define NF_CT_EXPECT_CLASS_DEFAULT 0 |
71 | 71 | ||
72 | int nf_conntrack_expect_init(struct net *net); | 72 | int nf_conntrack_expect_pernet_init(struct net *net); |
73 | void nf_conntrack_expect_fini(struct net *net); | 73 | void nf_conntrack_expect_pernet_fini(struct net *net); |
74 | |||
75 | int nf_conntrack_expect_init(void); | ||
76 | void nf_conntrack_expect_fini(void); | ||
74 | 77 | ||
75 | struct nf_conntrack_expect * | 78 | struct nf_conntrack_expect * |
76 | __nf_ct_expect_find(struct net *net, u16 zone, | 79 | __nf_ct_expect_find(struct net *net, u16 zone, |
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h index 8b4d1fc29096..977bc8a46444 100644 --- a/include/net/netfilter/nf_conntrack_extend.h +++ b/include/net/netfilter/nf_conntrack_extend.h | |||
@@ -23,6 +23,9 @@ enum nf_ct_ext_id { | |||
23 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 23 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
24 | NF_CT_EXT_TIMEOUT, | 24 | NF_CT_EXT_TIMEOUT, |
25 | #endif | 25 | #endif |
26 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
27 | NF_CT_EXT_LABELS, | ||
28 | #endif | ||
26 | NF_CT_EXT_NUM, | 29 | NF_CT_EXT_NUM, |
27 | }; | 30 | }; |
28 | 31 | ||
@@ -33,6 +36,7 @@ enum nf_ct_ext_id { | |||
33 | #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone | 36 | #define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone |
34 | #define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp | 37 | #define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp |
35 | #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout | 38 | #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout |
39 | #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels | ||
36 | 40 | ||
37 | /* Extensions: optional stuff which isn't permanently in struct. */ | 41 | /* Extensions: optional stuff which isn't permanently in struct. */ |
38 | struct nf_ct_ext { | 42 | struct nf_ct_ext { |
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index 9aad956d1008..ce27edf57570 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h | |||
@@ -82,8 +82,11 @@ static inline void *nfct_help_data(const struct nf_conn *ct) | |||
82 | return (void *)help->data; | 82 | return (void *)help->data; |
83 | } | 83 | } |
84 | 84 | ||
85 | extern int nf_conntrack_helper_init(struct net *net); | 85 | extern int nf_conntrack_helper_pernet_init(struct net *net); |
86 | extern void nf_conntrack_helper_fini(struct net *net); | 86 | extern void nf_conntrack_helper_pernet_fini(struct net *net); |
87 | |||
88 | extern int nf_conntrack_helper_init(void); | ||
89 | extern void nf_conntrack_helper_fini(void); | ||
87 | 90 | ||
88 | extern int nf_conntrack_broadcast_help(struct sk_buff *skb, | 91 | extern int nf_conntrack_broadcast_help(struct sk_buff *skb, |
89 | unsigned int protoff, | 92 | unsigned int protoff, |
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 6f7c13f4ac03..3bb89eac3fa1 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h | |||
@@ -76,11 +76,16 @@ struct nf_conntrack_l3proto { | |||
76 | 76 | ||
77 | extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX]; | 77 | extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX]; |
78 | 78 | ||
79 | /* Protocol registration. */ | 79 | /* Protocol pernet registration. */ |
80 | extern int nf_conntrack_l3proto_register(struct net *net, | 80 | extern int nf_ct_l3proto_pernet_register(struct net *net, |
81 | struct nf_conntrack_l3proto *proto); | 81 | struct nf_conntrack_l3proto *proto); |
82 | extern void nf_conntrack_l3proto_unregister(struct net *net, | 82 | extern void nf_ct_l3proto_pernet_unregister(struct net *net, |
83 | struct nf_conntrack_l3proto *proto); | 83 | struct nf_conntrack_l3proto *proto); |
84 | |||
85 | /* Protocol global registration. */ | ||
86 | extern int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto); | ||
87 | extern void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto); | ||
88 | |||
84 | extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto); | 89 | extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto); |
85 | extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p); | 90 | extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p); |
86 | 91 | ||
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index c3be4aef6bf7..914d8d900798 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h | |||
@@ -121,12 +121,16 @@ extern struct nf_conntrack_l4proto * | |||
121 | nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto); | 121 | nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto); |
122 | extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); | 122 | extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); |
123 | 123 | ||
124 | /* Protocol registration. */ | 124 | /* Protocol pernet registration. */ |
125 | extern int nf_conntrack_l4proto_register(struct net *net, | 125 | extern int nf_ct_l4proto_pernet_register(struct net *net, |
126 | struct nf_conntrack_l4proto *proto); | 126 | struct nf_conntrack_l4proto *proto); |
127 | extern void nf_conntrack_l4proto_unregister(struct net *net, | 127 | extern void nf_ct_l4proto_pernet_unregister(struct net *net, |
128 | struct nf_conntrack_l4proto *proto); | 128 | struct nf_conntrack_l4proto *proto); |
129 | 129 | ||
130 | /* Protocol global registration. */ | ||
131 | extern int nf_ct_l4proto_register(struct nf_conntrack_l4proto *proto); | ||
132 | extern void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *proto); | ||
133 | |||
130 | static inline void nf_ct_kfree_compat_sysctl_table(struct nf_proto_net *pn) | 134 | static inline void nf_ct_kfree_compat_sysctl_table(struct nf_proto_net *pn) |
131 | { | 135 | { |
132 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | 136 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h new file mode 100644 index 000000000000..c985695283b3 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_labels.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #include <linux/types.h> | ||
2 | #include <net/net_namespace.h> | ||
3 | #include <linux/netfilter/nf_conntrack_common.h> | ||
4 | #include <linux/netfilter/nf_conntrack_tuple_common.h> | ||
5 | #include <net/netfilter/nf_conntrack.h> | ||
6 | #include <net/netfilter/nf_conntrack_extend.h> | ||
7 | |||
8 | #include <uapi/linux/netfilter/xt_connlabel.h> | ||
9 | |||
10 | struct nf_conn_labels { | ||
11 | u8 words; | ||
12 | unsigned long bits[]; | ||
13 | }; | ||
14 | |||
15 | static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct) | ||
16 | { | ||
17 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
18 | return nf_ct_ext_find(ct, NF_CT_EXT_LABELS); | ||
19 | #else | ||
20 | return NULL; | ||
21 | #endif | ||
22 | } | ||
23 | |||
24 | static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct) | ||
25 | { | ||
26 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
27 | struct nf_conn_labels *cl_ext; | ||
28 | struct net *net = nf_ct_net(ct); | ||
29 | u8 words; | ||
30 | |||
31 | words = ACCESS_ONCE(net->ct.label_words); | ||
32 | if (words == 0 || WARN_ON_ONCE(words > 8)) | ||
33 | return NULL; | ||
34 | |||
35 | cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS, | ||
36 | words * sizeof(long), GFP_ATOMIC); | ||
37 | if (cl_ext != NULL) | ||
38 | cl_ext->words = words; | ||
39 | |||
40 | return cl_ext; | ||
41 | #else | ||
42 | return NULL; | ||
43 | #endif | ||
44 | } | ||
45 | |||
46 | bool nf_connlabel_match(const struct nf_conn *ct, u16 bit); | ||
47 | int nf_connlabel_set(struct nf_conn *ct, u16 bit); | ||
48 | |||
49 | int nf_connlabels_replace(struct nf_conn *ct, | ||
50 | const u32 *data, const u32 *mask, unsigned int words); | ||
51 | |||
52 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
53 | int nf_conntrack_labels_init(void); | ||
54 | void nf_conntrack_labels_fini(void); | ||
55 | #else | ||
56 | static inline int nf_conntrack_labels_init(void) { return 0; } | ||
57 | static inline void nf_conntrack_labels_fini(void) {} | ||
58 | #endif | ||
diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h index e41e472d08f2..d23aceb16d94 100644 --- a/include/net/netfilter/nf_conntrack_timeout.h +++ b/include/net/netfilter/nf_conntrack_timeout.h | |||
@@ -76,15 +76,15 @@ nf_ct_timeout_lookup(struct net *net, struct nf_conn *ct, | |||
76 | } | 76 | } |
77 | 77 | ||
78 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 78 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
79 | extern int nf_conntrack_timeout_init(struct net *net); | 79 | extern int nf_conntrack_timeout_init(void); |
80 | extern void nf_conntrack_timeout_fini(struct net *net); | 80 | extern void nf_conntrack_timeout_fini(void); |
81 | #else | 81 | #else |
82 | static inline int nf_conntrack_timeout_init(struct net *net) | 82 | static inline int nf_conntrack_timeout_init(void) |
83 | { | 83 | { |
84 | return 0; | 84 | return 0; |
85 | } | 85 | } |
86 | 86 | ||
87 | static inline void nf_conntrack_timeout_fini(struct net *net) | 87 | static inline void nf_conntrack_timeout_fini(void) |
88 | { | 88 | { |
89 | return; | 89 | return; |
90 | } | 90 | } |
diff --git a/include/net/netfilter/nf_conntrack_timestamp.h b/include/net/netfilter/nf_conntrack_timestamp.h index fc9c82b1f06b..b00461413efd 100644 --- a/include/net/netfilter/nf_conntrack_timestamp.h +++ b/include/net/netfilter/nf_conntrack_timestamp.h | |||
@@ -48,15 +48,28 @@ static inline void nf_ct_set_tstamp(struct net *net, bool enable) | |||
48 | } | 48 | } |
49 | 49 | ||
50 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP | 50 | #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP |
51 | extern int nf_conntrack_tstamp_init(struct net *net); | 51 | extern int nf_conntrack_tstamp_pernet_init(struct net *net); |
52 | extern void nf_conntrack_tstamp_fini(struct net *net); | 52 | extern void nf_conntrack_tstamp_pernet_fini(struct net *net); |
53 | |||
54 | extern int nf_conntrack_tstamp_init(void); | ||
55 | extern void nf_conntrack_tstamp_fini(void); | ||
53 | #else | 56 | #else |
54 | static inline int nf_conntrack_tstamp_init(struct net *net) | 57 | static inline int nf_conntrack_tstamp_pernet_init(struct net *net) |
58 | { | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static inline void nf_conntrack_tstamp_pernet_fini(struct net *net) | ||
63 | { | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | static inline int nf_conntrack_tstamp_init(void) | ||
55 | { | 68 | { |
56 | return 0; | 69 | return 0; |
57 | } | 70 | } |
58 | 71 | ||
59 | static inline void nf_conntrack_tstamp_fini(struct net *net) | 72 | static inline void nf_conntrack_tstamp_fini(void) |
60 | { | 73 | { |
61 | return; | 74 | return; |
62 | } | 75 | } |
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h index 923cb20051ed..c9c0c538b68b 100644 --- a/include/net/netns/conntrack.h +++ b/include/net/netns/conntrack.h | |||
@@ -84,6 +84,10 @@ struct netns_ct { | |||
84 | int sysctl_auto_assign_helper; | 84 | int sysctl_auto_assign_helper; |
85 | bool auto_assign_helper_warned; | 85 | bool auto_assign_helper_warned; |
86 | struct nf_ip_net nf_ct_proto; | 86 | struct nf_ip_net nf_ct_proto; |
87 | #if defined(CONFIG_NF_CONNTRACK_LABELS) | ||
88 | unsigned int labels_used; | ||
89 | u8 label_words; | ||
90 | #endif | ||
87 | #ifdef CONFIG_NF_NAT_NEEDED | 91 | #ifdef CONFIG_NF_NAT_NEEDED |
88 | struct hlist_head *nat_bysource; | 92 | struct hlist_head *nat_bysource; |
89 | unsigned int nat_htable_size; | 93 | unsigned int nat_htable_size; |
diff --git a/include/uapi/linux/netfilter/Kbuild b/include/uapi/linux/netfilter/Kbuild index 08f555fef13f..41115776d76f 100644 --- a/include/uapi/linux/netfilter/Kbuild +++ b/include/uapi/linux/netfilter/Kbuild | |||
@@ -35,9 +35,11 @@ header-y += xt_TCPOPTSTRIP.h | |||
35 | header-y += xt_TEE.h | 35 | header-y += xt_TEE.h |
36 | header-y += xt_TPROXY.h | 36 | header-y += xt_TPROXY.h |
37 | header-y += xt_addrtype.h | 37 | header-y += xt_addrtype.h |
38 | header-y += xt_bpf.h | ||
38 | header-y += xt_cluster.h | 39 | header-y += xt_cluster.h |
39 | header-y += xt_comment.h | 40 | header-y += xt_comment.h |
40 | header-y += xt_connbytes.h | 41 | header-y += xt_connbytes.h |
42 | header-y += xt_connlabel.h | ||
41 | header-y += xt_connlimit.h | 43 | header-y += xt_connlimit.h |
42 | header-y += xt_connmark.h | 44 | header-y += xt_connmark.h |
43 | header-y += xt_conntrack.h | 45 | header-y += xt_conntrack.h |
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h index 1644cdd8be91..d69483fb3825 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_common.h +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h | |||
@@ -101,6 +101,7 @@ enum ip_conntrack_events { | |||
101 | IPCT_MARK, /* new mark has been set */ | 101 | IPCT_MARK, /* new mark has been set */ |
102 | IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ | 102 | IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */ |
103 | IPCT_SECMARK, /* new security mark has been set */ | 103 | IPCT_SECMARK, /* new security mark has been set */ |
104 | IPCT_LABEL, /* new connlabel has been set */ | ||
104 | }; | 105 | }; |
105 | 106 | ||
106 | enum ip_conntrack_expect_events { | 107 | enum ip_conntrack_expect_events { |
diff --git a/include/uapi/linux/netfilter/nfnetlink_conntrack.h b/include/uapi/linux/netfilter/nfnetlink_conntrack.h index 86e930cf3dfb..08fabc6c93f3 100644 --- a/include/uapi/linux/netfilter/nfnetlink_conntrack.h +++ b/include/uapi/linux/netfilter/nfnetlink_conntrack.h | |||
@@ -49,6 +49,8 @@ enum ctattr_type { | |||
49 | CTA_SECCTX, | 49 | CTA_SECCTX, |
50 | CTA_TIMESTAMP, | 50 | CTA_TIMESTAMP, |
51 | CTA_MARK_MASK, | 51 | CTA_MARK_MASK, |
52 | CTA_LABELS, | ||
53 | CTA_LABELS_MASK, | ||
52 | __CTA_MAX | 54 | __CTA_MAX |
53 | }; | 55 | }; |
54 | #define CTA_MAX (__CTA_MAX - 1) | 56 | #define CTA_MAX (__CTA_MAX - 1) |
diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h new file mode 100644 index 000000000000..5dda450eb55b --- /dev/null +++ b/include/uapi/linux/netfilter/xt_bpf.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef _XT_BPF_H | ||
2 | #define _XT_BPF_H | ||
3 | |||
4 | #include <linux/filter.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | #define XT_BPF_MAX_NUM_INSTR 64 | ||
8 | |||
9 | struct xt_bpf_info { | ||
10 | __u16 bpf_program_num_elem; | ||
11 | struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR]; | ||
12 | |||
13 | /* only used in the kernel */ | ||
14 | struct sk_filter *filter __attribute__((aligned(8))); | ||
15 | }; | ||
16 | |||
17 | #endif /*_XT_BPF_H */ | ||
diff --git a/include/uapi/linux/netfilter/xt_connlabel.h b/include/uapi/linux/netfilter/xt_connlabel.h new file mode 100644 index 000000000000..c4bc9ee9b330 --- /dev/null +++ b/include/uapi/linux/netfilter/xt_connlabel.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #include <linux/types.h> | ||
2 | |||
3 | #define XT_CONNLABEL_MAXBIT 127 | ||
4 | enum xt_connlabel_mtopts { | ||
5 | XT_CONNLABEL_OP_INVERT = 1 << 0, | ||
6 | XT_CONNLABEL_OP_SET = 1 << 1, | ||
7 | }; | ||
8 | |||
9 | struct xt_connlabel_mtinfo { | ||
10 | __u16 bit; | ||
11 | __u16 options; | ||
12 | }; | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index fcdd0c2406e6..48990ada0e1e 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -420,54 +420,43 @@ static int ipv4_net_init(struct net *net) | |||
420 | { | 420 | { |
421 | int ret = 0; | 421 | int ret = 0; |
422 | 422 | ||
423 | ret = nf_conntrack_l4proto_register(net, | 423 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp4); |
424 | &nf_conntrack_l4proto_tcp4); | ||
425 | if (ret < 0) { | 424 | if (ret < 0) { |
426 | pr_err("nf_conntrack_l4proto_tcp4 :protocol register failed\n"); | 425 | pr_err("nf_conntrack_tcp4: pernet registration failed\n"); |
427 | goto out_tcp; | 426 | goto out_tcp; |
428 | } | 427 | } |
429 | ret = nf_conntrack_l4proto_register(net, | 428 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp4); |
430 | &nf_conntrack_l4proto_udp4); | ||
431 | if (ret < 0) { | 429 | if (ret < 0) { |
432 | pr_err("nf_conntrack_l4proto_udp4 :protocol register failed\n"); | 430 | pr_err("nf_conntrack_udp4: pernet registration failed\n"); |
433 | goto out_udp; | 431 | goto out_udp; |
434 | } | 432 | } |
435 | ret = nf_conntrack_l4proto_register(net, | 433 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmp); |
436 | &nf_conntrack_l4proto_icmp); | ||
437 | if (ret < 0) { | 434 | if (ret < 0) { |
438 | pr_err("nf_conntrack_l4proto_icmp4 :protocol register failed\n"); | 435 | pr_err("nf_conntrack_icmp4: pernet registration failed\n"); |
439 | goto out_icmp; | 436 | goto out_icmp; |
440 | } | 437 | } |
441 | ret = nf_conntrack_l3proto_register(net, | 438 | ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv4); |
442 | &nf_conntrack_l3proto_ipv4); | ||
443 | if (ret < 0) { | 439 | if (ret < 0) { |
444 | pr_err("nf_conntrack_l3proto_ipv4 :protocol register failed\n"); | 440 | pr_err("nf_conntrack_ipv4: pernet registration failed\n"); |
445 | goto out_ipv4; | 441 | goto out_ipv4; |
446 | } | 442 | } |
447 | return 0; | 443 | return 0; |
448 | out_ipv4: | 444 | out_ipv4: |
449 | nf_conntrack_l4proto_unregister(net, | 445 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmp); |
450 | &nf_conntrack_l4proto_icmp); | ||
451 | out_icmp: | 446 | out_icmp: |
452 | nf_conntrack_l4proto_unregister(net, | 447 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp4); |
453 | &nf_conntrack_l4proto_udp4); | ||
454 | out_udp: | 448 | out_udp: |
455 | nf_conntrack_l4proto_unregister(net, | 449 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp4); |
456 | &nf_conntrack_l4proto_tcp4); | ||
457 | out_tcp: | 450 | out_tcp: |
458 | return ret; | 451 | return ret; |
459 | } | 452 | } |
460 | 453 | ||
461 | static void ipv4_net_exit(struct net *net) | 454 | static void ipv4_net_exit(struct net *net) |
462 | { | 455 | { |
463 | nf_conntrack_l3proto_unregister(net, | 456 | nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv4); |
464 | &nf_conntrack_l3proto_ipv4); | 457 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmp); |
465 | nf_conntrack_l4proto_unregister(net, | 458 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp4); |
466 | &nf_conntrack_l4proto_icmp); | 459 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp4); |
467 | nf_conntrack_l4proto_unregister(net, | ||
468 | &nf_conntrack_l4proto_udp4); | ||
469 | nf_conntrack_l4proto_unregister(net, | ||
470 | &nf_conntrack_l4proto_tcp4); | ||
471 | } | 460 | } |
472 | 461 | ||
473 | static struct pernet_operations ipv4_net_ops = { | 462 | static struct pernet_operations ipv4_net_ops = { |
@@ -500,16 +489,49 @@ static int __init nf_conntrack_l3proto_ipv4_init(void) | |||
500 | pr_err("nf_conntrack_ipv4: can't register hooks.\n"); | 489 | pr_err("nf_conntrack_ipv4: can't register hooks.\n"); |
501 | goto cleanup_pernet; | 490 | goto cleanup_pernet; |
502 | } | 491 | } |
492 | |||
493 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp4); | ||
494 | if (ret < 0) { | ||
495 | pr_err("nf_conntrack_ipv4: can't register tcp4 proto.\n"); | ||
496 | goto cleanup_hooks; | ||
497 | } | ||
498 | |||
499 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp4); | ||
500 | if (ret < 0) { | ||
501 | pr_err("nf_conntrack_ipv4: can't register udp4 proto.\n"); | ||
502 | goto cleanup_tcp4; | ||
503 | } | ||
504 | |||
505 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmp); | ||
506 | if (ret < 0) { | ||
507 | pr_err("nf_conntrack_ipv4: can't register icmpv4 proto.\n"); | ||
508 | goto cleanup_udp4; | ||
509 | } | ||
510 | |||
511 | ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv4); | ||
512 | if (ret < 0) { | ||
513 | pr_err("nf_conntrack_ipv4: can't register ipv4 proto.\n"); | ||
514 | goto cleanup_icmpv4; | ||
515 | } | ||
516 | |||
503 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | 517 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
504 | ret = nf_conntrack_ipv4_compat_init(); | 518 | ret = nf_conntrack_ipv4_compat_init(); |
505 | if (ret < 0) | 519 | if (ret < 0) |
506 | goto cleanup_hooks; | 520 | goto cleanup_proto; |
507 | #endif | 521 | #endif |
508 | return ret; | 522 | return ret; |
509 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | 523 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
524 | cleanup_proto: | ||
525 | nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | ||
526 | #endif | ||
527 | cleanup_icmpv4: | ||
528 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmp); | ||
529 | cleanup_udp4: | ||
530 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp4); | ||
531 | cleanup_tcp4: | ||
532 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp4); | ||
510 | cleanup_hooks: | 533 | cleanup_hooks: |
511 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); | 534 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); |
512 | #endif | ||
513 | cleanup_pernet: | 535 | cleanup_pernet: |
514 | unregister_pernet_subsys(&ipv4_net_ops); | 536 | unregister_pernet_subsys(&ipv4_net_ops); |
515 | cleanup_sockopt: | 537 | cleanup_sockopt: |
@@ -523,6 +545,10 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void) | |||
523 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) | 545 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) |
524 | nf_conntrack_ipv4_compat_fini(); | 546 | nf_conntrack_ipv4_compat_fini(); |
525 | #endif | 547 | #endif |
548 | nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv4); | ||
549 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmp); | ||
550 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp4); | ||
551 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp4); | ||
526 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); | 552 | nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops)); |
527 | unregister_pernet_subsys(&ipv4_net_ops); | 553 | unregister_pernet_subsys(&ipv4_net_ops); |
528 | nf_unregister_sockopt(&so_getorigdst); | 554 | nf_unregister_sockopt(&so_getorigdst); |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 137e245860ab..8a45bb20bedb 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -421,54 +421,43 @@ static int ipv6_net_init(struct net *net) | |||
421 | { | 421 | { |
422 | int ret = 0; | 422 | int ret = 0; |
423 | 423 | ||
424 | ret = nf_conntrack_l4proto_register(net, | 424 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_tcp6); |
425 | &nf_conntrack_l4proto_tcp6); | ||
426 | if (ret < 0) { | 425 | if (ret < 0) { |
427 | printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n"); | 426 | pr_err("nf_conntrack_tcp6: pernet registration failed\n"); |
428 | goto out; | 427 | goto out; |
429 | } | 428 | } |
430 | ret = nf_conntrack_l4proto_register(net, | 429 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udp6); |
431 | &nf_conntrack_l4proto_udp6); | ||
432 | if (ret < 0) { | 430 | if (ret < 0) { |
433 | printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n"); | 431 | pr_err("nf_conntrack_udp6: pernet registration failed\n"); |
434 | goto cleanup_tcp6; | 432 | goto cleanup_tcp6; |
435 | } | 433 | } |
436 | ret = nf_conntrack_l4proto_register(net, | 434 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_icmpv6); |
437 | &nf_conntrack_l4proto_icmpv6); | ||
438 | if (ret < 0) { | 435 | if (ret < 0) { |
439 | printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n"); | 436 | pr_err("nf_conntrack_icmp6: pernet registration failed\n"); |
440 | goto cleanup_udp6; | 437 | goto cleanup_udp6; |
441 | } | 438 | } |
442 | ret = nf_conntrack_l3proto_register(net, | 439 | ret = nf_ct_l3proto_pernet_register(net, &nf_conntrack_l3proto_ipv6); |
443 | &nf_conntrack_l3proto_ipv6); | ||
444 | if (ret < 0) { | 440 | if (ret < 0) { |
445 | printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n"); | 441 | pr_err("nf_conntrack_ipv6: pernet registration failed.\n"); |
446 | goto cleanup_icmpv6; | 442 | goto cleanup_icmpv6; |
447 | } | 443 | } |
448 | return 0; | 444 | return 0; |
449 | cleanup_icmpv6: | 445 | cleanup_icmpv6: |
450 | nf_conntrack_l4proto_unregister(net, | 446 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); |
451 | &nf_conntrack_l4proto_icmpv6); | ||
452 | cleanup_udp6: | 447 | cleanup_udp6: |
453 | nf_conntrack_l4proto_unregister(net, | 448 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); |
454 | &nf_conntrack_l4proto_udp6); | ||
455 | cleanup_tcp6: | 449 | cleanup_tcp6: |
456 | nf_conntrack_l4proto_unregister(net, | 450 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); |
457 | &nf_conntrack_l4proto_tcp6); | ||
458 | out: | 451 | out: |
459 | return ret; | 452 | return ret; |
460 | } | 453 | } |
461 | 454 | ||
462 | static void ipv6_net_exit(struct net *net) | 455 | static void ipv6_net_exit(struct net *net) |
463 | { | 456 | { |
464 | nf_conntrack_l3proto_unregister(net, | 457 | nf_ct_l3proto_pernet_unregister(net, &nf_conntrack_l3proto_ipv6); |
465 | &nf_conntrack_l3proto_ipv6); | 458 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_icmpv6); |
466 | nf_conntrack_l4proto_unregister(net, | 459 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udp6); |
467 | &nf_conntrack_l4proto_icmpv6); | 460 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_tcp6); |
468 | nf_conntrack_l4proto_unregister(net, | ||
469 | &nf_conntrack_l4proto_udp6); | ||
470 | nf_conntrack_l4proto_unregister(net, | ||
471 | &nf_conntrack_l4proto_tcp6); | ||
472 | } | 461 | } |
473 | 462 | ||
474 | static struct pernet_operations ipv6_net_ops = { | 463 | static struct pernet_operations ipv6_net_ops = { |
@@ -491,19 +480,52 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
491 | 480 | ||
492 | ret = register_pernet_subsys(&ipv6_net_ops); | 481 | ret = register_pernet_subsys(&ipv6_net_ops); |
493 | if (ret < 0) | 482 | if (ret < 0) |
494 | goto cleanup_pernet; | 483 | goto cleanup_sockopt; |
484 | |||
495 | ret = nf_register_hooks(ipv6_conntrack_ops, | 485 | ret = nf_register_hooks(ipv6_conntrack_ops, |
496 | ARRAY_SIZE(ipv6_conntrack_ops)); | 486 | ARRAY_SIZE(ipv6_conntrack_ops)); |
497 | if (ret < 0) { | 487 | if (ret < 0) { |
498 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " | 488 | pr_err("nf_conntrack_ipv6: can't register pre-routing defrag " |
499 | "hook.\n"); | 489 | "hook.\n"); |
500 | goto cleanup_ipv6; | 490 | goto cleanup_pernet; |
491 | } | ||
492 | |||
493 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_tcp6); | ||
494 | if (ret < 0) { | ||
495 | pr_err("nf_conntrack_ipv6: can't register tcp6 proto.\n"); | ||
496 | goto cleanup_hooks; | ||
497 | } | ||
498 | |||
499 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udp6); | ||
500 | if (ret < 0) { | ||
501 | pr_err("nf_conntrack_ipv6: can't register udp6 proto.\n"); | ||
502 | goto cleanup_tcp6; | ||
503 | } | ||
504 | |||
505 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_icmpv6); | ||
506 | if (ret < 0) { | ||
507 | pr_err("nf_conntrack_ipv6: can't register icmpv6 proto.\n"); | ||
508 | goto cleanup_udp6; | ||
509 | } | ||
510 | |||
511 | ret = nf_ct_l3proto_register(&nf_conntrack_l3proto_ipv6); | ||
512 | if (ret < 0) { | ||
513 | pr_err("nf_conntrack_ipv6: can't register ipv6 proto.\n"); | ||
514 | goto cleanup_icmpv6; | ||
501 | } | 515 | } |
502 | return ret; | 516 | return ret; |
503 | 517 | ||
504 | cleanup_ipv6: | 518 | cleanup_icmpv6: |
505 | unregister_pernet_subsys(&ipv6_net_ops); | 519 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); |
520 | cleanup_udp6: | ||
521 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); | ||
522 | cleanup_tcp6: | ||
523 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | ||
524 | cleanup_hooks: | ||
525 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | ||
506 | cleanup_pernet: | 526 | cleanup_pernet: |
527 | unregister_pernet_subsys(&ipv6_net_ops); | ||
528 | cleanup_sockopt: | ||
507 | nf_unregister_sockopt(&so_getorigdst6); | 529 | nf_unregister_sockopt(&so_getorigdst6); |
508 | return ret; | 530 | return ret; |
509 | } | 531 | } |
@@ -511,6 +533,10 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) | |||
511 | static void __exit nf_conntrack_l3proto_ipv6_fini(void) | 533 | static void __exit nf_conntrack_l3proto_ipv6_fini(void) |
512 | { | 534 | { |
513 | synchronize_net(); | 535 | synchronize_net(); |
536 | nf_ct_l3proto_unregister(&nf_conntrack_l3proto_ipv6); | ||
537 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_tcp6); | ||
538 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udp6); | ||
539 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_icmpv6); | ||
514 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); | 540 | nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); |
515 | unregister_pernet_subsys(&ipv6_net_ops); | 541 | unregister_pernet_subsys(&ipv6_net_ops); |
516 | nf_unregister_sockopt(&so_getorigdst6); | 542 | nf_unregister_sockopt(&so_getorigdst6); |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 49e96df5fbc4..eb2c8ebf6d99 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -124,6 +124,12 @@ config NF_CONNTRACK_TIMESTAMP | |||
124 | 124 | ||
125 | If unsure, say `N'. | 125 | If unsure, say `N'. |
126 | 126 | ||
127 | config NF_CONNTRACK_LABELS | ||
128 | bool | ||
129 | help | ||
130 | This option enables support for assigning user-defined flag bits | ||
131 | to connection tracking entries. It selected by the connlabel match. | ||
132 | |||
127 | config NF_CT_PROTO_DCCP | 133 | config NF_CT_PROTO_DCCP |
128 | tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)' | 134 | tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)' |
129 | depends on EXPERIMENTAL | 135 | depends on EXPERIMENTAL |
@@ -805,6 +811,15 @@ config NETFILTER_XT_MATCH_ADDRTYPE | |||
805 | If you want to compile it as a module, say M here and read | 811 | If you want to compile it as a module, say M here and read |
806 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. | 812 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. |
807 | 813 | ||
814 | config NETFILTER_XT_MATCH_BPF | ||
815 | tristate '"bpf" match support' | ||
816 | depends on NETFILTER_ADVANCED | ||
817 | help | ||
818 | BPF matching applies a linux socket filter to each packet and | ||
819 | accepts those for which the filter returns non-zero. | ||
820 | |||
821 | To compile it as a module, choose M here. If unsure, say N. | ||
822 | |||
808 | config NETFILTER_XT_MATCH_CLUSTER | 823 | config NETFILTER_XT_MATCH_CLUSTER |
809 | tristate '"cluster" match support' | 824 | tristate '"cluster" match support' |
810 | depends on NF_CONNTRACK | 825 | depends on NF_CONNTRACK |
@@ -842,6 +857,18 @@ config NETFILTER_XT_MATCH_CONNBYTES | |||
842 | If you want to compile it as a module, say M here and read | 857 | If you want to compile it as a module, say M here and read |
843 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. | 858 | <file:Documentation/kbuild/modules.txt>. If unsure, say `N'. |
844 | 859 | ||
860 | config NETFILTER_XT_MATCH_CONNLABEL | ||
861 | tristate '"connlabel" match support' | ||
862 | select NF_CONNTRACK_LABELS | ||
863 | depends on NETFILTER_ADVANCED | ||
864 | ---help--- | ||
865 | This match allows you to test and assign userspace-defined labels names | ||
866 | to a connection. The kernel only stores bit values - mapping | ||
867 | names to bits is done by userspace. | ||
868 | |||
869 | Unlike connmark, more than 32 flag bits may be assigned to a | ||
870 | connection simultaneously. | ||
871 | |||
845 | config NETFILTER_XT_MATCH_CONNLIMIT | 872 | config NETFILTER_XT_MATCH_CONNLIMIT |
846 | tristate '"connlimit" match support"' | 873 | tristate '"connlimit" match support"' |
847 | depends on NF_CONNTRACK | 874 | depends on NF_CONNTRACK |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 32596978df1d..a1abf87d43bf 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -4,6 +4,7 @@ nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_exp | |||
4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o | 4 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMEOUT) += nf_conntrack_timeout.o |
5 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o | 5 | nf_conntrack-$(CONFIG_NF_CONNTRACK_TIMESTAMP) += nf_conntrack_timestamp.o |
6 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o | 6 | nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o |
7 | nf_conntrack-$(CONFIG_NF_CONNTRACK_LABELS) += nf_conntrack_labels.o | ||
7 | 8 | ||
8 | obj-$(CONFIG_NETFILTER) = netfilter.o | 9 | obj-$(CONFIG_NETFILTER) = netfilter.o |
9 | 10 | ||
@@ -98,9 +99,11 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_IDLETIMER) += xt_IDLETIMER.o | |||
98 | 99 | ||
99 | # matches | 100 | # matches |
100 | obj-$(CONFIG_NETFILTER_XT_MATCH_ADDRTYPE) += xt_addrtype.o | 101 | obj-$(CONFIG_NETFILTER_XT_MATCH_ADDRTYPE) += xt_addrtype.o |
102 | obj-$(CONFIG_NETFILTER_XT_MATCH_BPF) += xt_bpf.o | ||
101 | obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o | 103 | obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o |
102 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o | 104 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o |
103 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o | 105 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o |
106 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLABEL) += xt_connlabel.o | ||
104 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o | 107 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o |
105 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o | 108 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o |
106 | obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o | 109 | obj-$(CONFIG_NETFILTER_XT_MATCH_CPU) += xt_cpu.o |
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c index 7df424e2d10c..2d3030ab5b61 100644 --- a/net/netfilter/nf_conntrack_acct.c +++ b/net/netfilter/nf_conntrack_acct.c | |||
@@ -106,36 +106,26 @@ static void nf_conntrack_acct_fini_sysctl(struct net *net) | |||
106 | } | 106 | } |
107 | #endif | 107 | #endif |
108 | 108 | ||
109 | int nf_conntrack_acct_init(struct net *net) | 109 | int nf_conntrack_acct_pernet_init(struct net *net) |
110 | { | 110 | { |
111 | int ret; | ||
112 | |||
113 | net->ct.sysctl_acct = nf_ct_acct; | 111 | net->ct.sysctl_acct = nf_ct_acct; |
112 | return nf_conntrack_acct_init_sysctl(net); | ||
113 | } | ||
114 | 114 | ||
115 | if (net_eq(net, &init_net)) { | 115 | void nf_conntrack_acct_pernet_fini(struct net *net) |
116 | ret = nf_ct_extend_register(&acct_extend); | 116 | { |
117 | if (ret < 0) { | 117 | nf_conntrack_acct_fini_sysctl(net); |
118 | printk(KERN_ERR "nf_conntrack_acct: Unable to register extension\n"); | 118 | } |
119 | goto out_extend_register; | ||
120 | } | ||
121 | } | ||
122 | 119 | ||
123 | ret = nf_conntrack_acct_init_sysctl(net); | 120 | int nf_conntrack_acct_init(void) |
121 | { | ||
122 | int ret = nf_ct_extend_register(&acct_extend); | ||
124 | if (ret < 0) | 123 | if (ret < 0) |
125 | goto out_sysctl; | 124 | pr_err("nf_conntrack_acct: Unable to register extension\n"); |
126 | |||
127 | return 0; | ||
128 | |||
129 | out_sysctl: | ||
130 | if (net_eq(net, &init_net)) | ||
131 | nf_ct_extend_unregister(&acct_extend); | ||
132 | out_extend_register: | ||
133 | return ret; | 125 | return ret; |
134 | } | 126 | } |
135 | 127 | ||
136 | void nf_conntrack_acct_fini(struct net *net) | 128 | void nf_conntrack_acct_fini(void) |
137 | { | 129 | { |
138 | nf_conntrack_acct_fini_sysctl(net); | 130 | nf_ct_extend_unregister(&acct_extend); |
139 | if (net_eq(net, &init_net)) | ||
140 | nf_ct_extend_unregister(&acct_extend); | ||
141 | } | 131 | } |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index e4a0c4fb3a7c..c8e001a9c45b 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <net/netfilter/nf_conntrack_zones.h> | 45 | #include <net/netfilter/nf_conntrack_zones.h> |
46 | #include <net/netfilter/nf_conntrack_timestamp.h> | 46 | #include <net/netfilter/nf_conntrack_timestamp.h> |
47 | #include <net/netfilter/nf_conntrack_timeout.h> | 47 | #include <net/netfilter/nf_conntrack_timeout.h> |
48 | #include <net/netfilter/nf_conntrack_labels.h> | ||
48 | #include <net/netfilter/nf_nat.h> | 49 | #include <net/netfilter/nf_nat.h> |
49 | #include <net/netfilter/nf_nat_core.h> | 50 | #include <net/netfilter/nf_nat_core.h> |
50 | 51 | ||
@@ -763,6 +764,7 @@ void nf_conntrack_free(struct nf_conn *ct) | |||
763 | } | 764 | } |
764 | EXPORT_SYMBOL_GPL(nf_conntrack_free); | 765 | EXPORT_SYMBOL_GPL(nf_conntrack_free); |
765 | 766 | ||
767 | |||
766 | /* Allocate a new conntrack: we return -ENOMEM if classification | 768 | /* Allocate a new conntrack: we return -ENOMEM if classification |
767 | failed due to stress. Otherwise it really is unclassifiable. */ | 769 | failed due to stress. Otherwise it really is unclassifiable. */ |
768 | static struct nf_conntrack_tuple_hash * | 770 | static struct nf_conntrack_tuple_hash * |
@@ -809,6 +811,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, | |||
809 | 811 | ||
810 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); | 812 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
811 | nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); | 813 | nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); |
814 | nf_ct_labels_ext_add(ct); | ||
812 | 815 | ||
813 | ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL; | 816 | ecache = tmpl ? nf_ct_ecache_find(tmpl) : NULL; |
814 | nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0, | 817 | nf_ct_ecache_ext_add(ct, ecache ? ecache->ctmask : 0, |
@@ -1331,18 +1334,42 @@ static int untrack_refs(void) | |||
1331 | return cnt; | 1334 | return cnt; |
1332 | } | 1335 | } |
1333 | 1336 | ||
1334 | static void nf_conntrack_cleanup_init_net(void) | 1337 | void nf_conntrack_cleanup_start(void) |
1338 | { | ||
1339 | RCU_INIT_POINTER(ip_ct_attach, NULL); | ||
1340 | } | ||
1341 | |||
1342 | void nf_conntrack_cleanup_end(void) | ||
1335 | { | 1343 | { |
1344 | RCU_INIT_POINTER(nf_ct_destroy, NULL); | ||
1336 | while (untrack_refs() > 0) | 1345 | while (untrack_refs() > 0) |
1337 | schedule(); | 1346 | schedule(); |
1338 | 1347 | ||
1339 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 1348 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
1340 | nf_ct_extend_unregister(&nf_ct_zone_extend); | 1349 | nf_ct_extend_unregister(&nf_ct_zone_extend); |
1341 | #endif | 1350 | #endif |
1351 | nf_conntrack_proto_fini(); | ||
1352 | nf_conntrack_labels_fini(); | ||
1353 | nf_conntrack_helper_fini(); | ||
1354 | nf_conntrack_timeout_fini(); | ||
1355 | nf_conntrack_ecache_fini(); | ||
1356 | nf_conntrack_tstamp_fini(); | ||
1357 | nf_conntrack_acct_fini(); | ||
1358 | nf_conntrack_expect_fini(); | ||
1342 | } | 1359 | } |
1343 | 1360 | ||
1344 | static void nf_conntrack_cleanup_net(struct net *net) | 1361 | /* |
1362 | * Mishearing the voices in his head, our hero wonders how he's | ||
1363 | * supposed to kill the mall. | ||
1364 | */ | ||
1365 | void nf_conntrack_cleanup_net(struct net *net) | ||
1345 | { | 1366 | { |
1367 | /* | ||
1368 | * This makes sure all current packets have passed through | ||
1369 | * netfilter framework. Roll on, two-stage module | ||
1370 | * delete... | ||
1371 | */ | ||
1372 | synchronize_net(); | ||
1346 | i_see_dead_people: | 1373 | i_see_dead_people: |
1347 | nf_ct_iterate_cleanup(net, kill_all, NULL); | 1374 | nf_ct_iterate_cleanup(net, kill_all, NULL); |
1348 | nf_ct_release_dying_list(net); | 1375 | nf_ct_release_dying_list(net); |
@@ -1352,38 +1379,17 @@ static void nf_conntrack_cleanup_net(struct net *net) | |||
1352 | } | 1379 | } |
1353 | 1380 | ||
1354 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); | 1381 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); |
1355 | nf_conntrack_helper_fini(net); | 1382 | nf_conntrack_proto_pernet_fini(net); |
1356 | nf_conntrack_timeout_fini(net); | 1383 | nf_conntrack_helper_pernet_fini(net); |
1357 | nf_conntrack_ecache_fini(net); | 1384 | nf_conntrack_ecache_pernet_fini(net); |
1358 | nf_conntrack_tstamp_fini(net); | 1385 | nf_conntrack_tstamp_pernet_fini(net); |
1359 | nf_conntrack_acct_fini(net); | 1386 | nf_conntrack_acct_pernet_fini(net); |
1360 | nf_conntrack_expect_fini(net); | 1387 | nf_conntrack_expect_pernet_fini(net); |
1361 | kmem_cache_destroy(net->ct.nf_conntrack_cachep); | 1388 | kmem_cache_destroy(net->ct.nf_conntrack_cachep); |
1362 | kfree(net->ct.slabname); | 1389 | kfree(net->ct.slabname); |
1363 | free_percpu(net->ct.stat); | 1390 | free_percpu(net->ct.stat); |
1364 | } | 1391 | } |
1365 | 1392 | ||
1366 | /* Mishearing the voices in his head, our hero wonders how he's | ||
1367 | supposed to kill the mall. */ | ||
1368 | void nf_conntrack_cleanup(struct net *net) | ||
1369 | { | ||
1370 | if (net_eq(net, &init_net)) | ||
1371 | RCU_INIT_POINTER(ip_ct_attach, NULL); | ||
1372 | |||
1373 | /* This makes sure all current packets have passed through | ||
1374 | netfilter framework. Roll on, two-stage module | ||
1375 | delete... */ | ||
1376 | synchronize_net(); | ||
1377 | nf_conntrack_proto_fini(net); | ||
1378 | nf_conntrack_cleanup_net(net); | ||
1379 | } | ||
1380 | |||
1381 | void nf_conntrack_cleanup_end(void) | ||
1382 | { | ||
1383 | RCU_INIT_POINTER(nf_ct_destroy, NULL); | ||
1384 | nf_conntrack_cleanup_init_net(); | ||
1385 | } | ||
1386 | |||
1387 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) | 1393 | void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) |
1388 | { | 1394 | { |
1389 | struct hlist_nulls_head *hash; | 1395 | struct hlist_nulls_head *hash; |
@@ -1474,7 +1480,7 @@ void nf_ct_untracked_status_or(unsigned long bits) | |||
1474 | } | 1480 | } |
1475 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); | 1481 | EXPORT_SYMBOL_GPL(nf_ct_untracked_status_or); |
1476 | 1482 | ||
1477 | static int nf_conntrack_init_init_net(void) | 1483 | int nf_conntrack_init_start(void) |
1478 | { | 1484 | { |
1479 | int max_factor = 8; | 1485 | int max_factor = 8; |
1480 | int ret, cpu; | 1486 | int ret, cpu; |
@@ -1501,11 +1507,44 @@ static int nf_conntrack_init_init_net(void) | |||
1501 | printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n", | 1507 | printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n", |
1502 | NF_CONNTRACK_VERSION, nf_conntrack_htable_size, | 1508 | NF_CONNTRACK_VERSION, nf_conntrack_htable_size, |
1503 | nf_conntrack_max); | 1509 | nf_conntrack_max); |
1510 | |||
1511 | ret = nf_conntrack_expect_init(); | ||
1512 | if (ret < 0) | ||
1513 | goto err_expect; | ||
1514 | |||
1515 | ret = nf_conntrack_acct_init(); | ||
1516 | if (ret < 0) | ||
1517 | goto err_acct; | ||
1518 | |||
1519 | ret = nf_conntrack_tstamp_init(); | ||
1520 | if (ret < 0) | ||
1521 | goto err_tstamp; | ||
1522 | |||
1523 | ret = nf_conntrack_ecache_init(); | ||
1524 | if (ret < 0) | ||
1525 | goto err_ecache; | ||
1526 | |||
1527 | ret = nf_conntrack_timeout_init(); | ||
1528 | if (ret < 0) | ||
1529 | goto err_timeout; | ||
1530 | |||
1531 | ret = nf_conntrack_helper_init(); | ||
1532 | if (ret < 0) | ||
1533 | goto err_helper; | ||
1534 | |||
1535 | ret = nf_conntrack_labels_init(); | ||
1536 | if (ret < 0) | ||
1537 | goto err_labels; | ||
1538 | |||
1504 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 1539 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
1505 | ret = nf_ct_extend_register(&nf_ct_zone_extend); | 1540 | ret = nf_ct_extend_register(&nf_ct_zone_extend); |
1506 | if (ret < 0) | 1541 | if (ret < 0) |
1507 | goto err_extend; | 1542 | goto err_extend; |
1508 | #endif | 1543 | #endif |
1544 | ret = nf_conntrack_proto_init(); | ||
1545 | if (ret < 0) | ||
1546 | goto err_proto; | ||
1547 | |||
1509 | /* Set up fake conntrack: to never be deleted, not in any hashes */ | 1548 | /* Set up fake conntrack: to never be deleted, not in any hashes */ |
1510 | for_each_possible_cpu(cpu) { | 1549 | for_each_possible_cpu(cpu) { |
1511 | struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu); | 1550 | struct nf_conn *ct = &per_cpu(nf_conntrack_untracked, cpu); |
@@ -1516,12 +1555,38 @@ static int nf_conntrack_init_init_net(void) | |||
1516 | nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); | 1555 | nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED); |
1517 | return 0; | 1556 | return 0; |
1518 | 1557 | ||
1558 | err_proto: | ||
1519 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 1559 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
1560 | nf_ct_extend_unregister(&nf_ct_zone_extend); | ||
1520 | err_extend: | 1561 | err_extend: |
1521 | #endif | 1562 | #endif |
1563 | nf_conntrack_labels_fini(); | ||
1564 | err_labels: | ||
1565 | nf_conntrack_helper_fini(); | ||
1566 | err_helper: | ||
1567 | nf_conntrack_timeout_fini(); | ||
1568 | err_timeout: | ||
1569 | nf_conntrack_ecache_fini(); | ||
1570 | err_ecache: | ||
1571 | nf_conntrack_tstamp_fini(); | ||
1572 | err_tstamp: | ||
1573 | nf_conntrack_acct_fini(); | ||
1574 | err_acct: | ||
1575 | nf_conntrack_expect_fini(); | ||
1576 | err_expect: | ||
1522 | return ret; | 1577 | return ret; |
1523 | } | 1578 | } |
1524 | 1579 | ||
1580 | void nf_conntrack_init_end(void) | ||
1581 | { | ||
1582 | /* For use by REJECT target */ | ||
1583 | RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); | ||
1584 | RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); | ||
1585 | |||
1586 | /* Howto get NAT offsets */ | ||
1587 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | ||
1588 | } | ||
1589 | |||
1525 | /* | 1590 | /* |
1526 | * We need to use special "null" values, not used in hash table | 1591 | * We need to use special "null" values, not used in hash table |
1527 | */ | 1592 | */ |
@@ -1529,7 +1594,7 @@ err_extend: | |||
1529 | #define DYING_NULLS_VAL ((1<<30)+1) | 1594 | #define DYING_NULLS_VAL ((1<<30)+1) |
1530 | #define TEMPLATE_NULLS_VAL ((1<<30)+2) | 1595 | #define TEMPLATE_NULLS_VAL ((1<<30)+2) |
1531 | 1596 | ||
1532 | static int nf_conntrack_init_net(struct net *net) | 1597 | int nf_conntrack_init_net(struct net *net) |
1533 | { | 1598 | { |
1534 | int ret; | 1599 | int ret; |
1535 | 1600 | ||
@@ -1565,35 +1630,36 @@ static int nf_conntrack_init_net(struct net *net) | |||
1565 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); | 1630 | printk(KERN_ERR "Unable to create nf_conntrack_hash\n"); |
1566 | goto err_hash; | 1631 | goto err_hash; |
1567 | } | 1632 | } |
1568 | ret = nf_conntrack_expect_init(net); | 1633 | ret = nf_conntrack_expect_pernet_init(net); |
1569 | if (ret < 0) | 1634 | if (ret < 0) |
1570 | goto err_expect; | 1635 | goto err_expect; |
1571 | ret = nf_conntrack_acct_init(net); | 1636 | ret = nf_conntrack_acct_pernet_init(net); |
1572 | if (ret < 0) | 1637 | if (ret < 0) |
1573 | goto err_acct; | 1638 | goto err_acct; |
1574 | ret = nf_conntrack_tstamp_init(net); | 1639 | ret = nf_conntrack_tstamp_pernet_init(net); |
1575 | if (ret < 0) | 1640 | if (ret < 0) |
1576 | goto err_tstamp; | 1641 | goto err_tstamp; |
1577 | ret = nf_conntrack_ecache_init(net); | 1642 | ret = nf_conntrack_ecache_pernet_init(net); |
1578 | if (ret < 0) | 1643 | if (ret < 0) |
1579 | goto err_ecache; | 1644 | goto err_ecache; |
1580 | ret = nf_conntrack_timeout_init(net); | 1645 | ret = nf_conntrack_helper_pernet_init(net); |
1581 | if (ret < 0) | ||
1582 | goto err_timeout; | ||
1583 | ret = nf_conntrack_helper_init(net); | ||
1584 | if (ret < 0) | 1646 | if (ret < 0) |
1585 | goto err_helper; | 1647 | goto err_helper; |
1648 | ret = nf_conntrack_proto_pernet_init(net); | ||
1649 | if (ret < 0) | ||
1650 | goto err_proto; | ||
1586 | return 0; | 1651 | return 0; |
1652 | |||
1653 | err_proto: | ||
1654 | nf_conntrack_helper_pernet_fini(net); | ||
1587 | err_helper: | 1655 | err_helper: |
1588 | nf_conntrack_timeout_fini(net); | 1656 | nf_conntrack_ecache_pernet_fini(net); |
1589 | err_timeout: | ||
1590 | nf_conntrack_ecache_fini(net); | ||
1591 | err_ecache: | 1657 | err_ecache: |
1592 | nf_conntrack_tstamp_fini(net); | 1658 | nf_conntrack_tstamp_pernet_fini(net); |
1593 | err_tstamp: | 1659 | err_tstamp: |
1594 | nf_conntrack_acct_fini(net); | 1660 | nf_conntrack_acct_pernet_fini(net); |
1595 | err_acct: | 1661 | err_acct: |
1596 | nf_conntrack_expect_fini(net); | 1662 | nf_conntrack_expect_pernet_fini(net); |
1597 | err_expect: | 1663 | err_expect: |
1598 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); | 1664 | nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size); |
1599 | err_hash: | 1665 | err_hash: |
@@ -1610,38 +1676,3 @@ s16 (*nf_ct_nat_offset)(const struct nf_conn *ct, | |||
1610 | enum ip_conntrack_dir dir, | 1676 | enum ip_conntrack_dir dir, |
1611 | u32 seq); | 1677 | u32 seq); |
1612 | EXPORT_SYMBOL_GPL(nf_ct_nat_offset); | 1678 | EXPORT_SYMBOL_GPL(nf_ct_nat_offset); |
1613 | |||
1614 | int nf_conntrack_init(struct net *net) | ||
1615 | { | ||
1616 | int ret; | ||
1617 | |||
1618 | if (net_eq(net, &init_net)) { | ||
1619 | ret = nf_conntrack_init_init_net(); | ||
1620 | if (ret < 0) | ||
1621 | goto out_init_net; | ||
1622 | } | ||
1623 | ret = nf_conntrack_proto_init(net); | ||
1624 | if (ret < 0) | ||
1625 | goto out_proto; | ||
1626 | ret = nf_conntrack_init_net(net); | ||
1627 | if (ret < 0) | ||
1628 | goto out_net; | ||
1629 | |||
1630 | if (net_eq(net, &init_net)) { | ||
1631 | /* For use by REJECT target */ | ||
1632 | RCU_INIT_POINTER(ip_ct_attach, nf_conntrack_attach); | ||
1633 | RCU_INIT_POINTER(nf_ct_destroy, destroy_conntrack); | ||
1634 | |||
1635 | /* Howto get NAT offsets */ | ||
1636 | RCU_INIT_POINTER(nf_ct_nat_offset, NULL); | ||
1637 | } | ||
1638 | return 0; | ||
1639 | |||
1640 | out_net: | ||
1641 | nf_conntrack_proto_fini(net); | ||
1642 | out_proto: | ||
1643 | if (net_eq(net, &init_net)) | ||
1644 | nf_conntrack_cleanup_init_net(); | ||
1645 | out_init_net: | ||
1646 | return ret; | ||
1647 | } | ||
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index faa978f1714b..b5d2eb8bf0d5 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c | |||
@@ -233,38 +233,27 @@ static void nf_conntrack_event_fini_sysctl(struct net *net) | |||
233 | } | 233 | } |
234 | #endif /* CONFIG_SYSCTL */ | 234 | #endif /* CONFIG_SYSCTL */ |
235 | 235 | ||
236 | int nf_conntrack_ecache_init(struct net *net) | 236 | int nf_conntrack_ecache_pernet_init(struct net *net) |
237 | { | 237 | { |
238 | int ret; | ||
239 | |||
240 | net->ct.sysctl_events = nf_ct_events; | 238 | net->ct.sysctl_events = nf_ct_events; |
241 | net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; | 239 | net->ct.sysctl_events_retry_timeout = nf_ct_events_retry_timeout; |
240 | return nf_conntrack_event_init_sysctl(net); | ||
241 | } | ||
242 | 242 | ||
243 | if (net_eq(net, &init_net)) { | 243 | void nf_conntrack_ecache_pernet_fini(struct net *net) |
244 | ret = nf_ct_extend_register(&event_extend); | 244 | { |
245 | if (ret < 0) { | 245 | nf_conntrack_event_fini_sysctl(net); |
246 | printk(KERN_ERR "nf_ct_event: Unable to register " | 246 | } |
247 | "event extension.\n"); | ||
248 | goto out_extend_register; | ||
249 | } | ||
250 | } | ||
251 | 247 | ||
252 | ret = nf_conntrack_event_init_sysctl(net); | 248 | int nf_conntrack_ecache_init(void) |
249 | { | ||
250 | int ret = nf_ct_extend_register(&event_extend); | ||
253 | if (ret < 0) | 251 | if (ret < 0) |
254 | goto out_sysctl; | 252 | pr_err("nf_ct_event: Unable to register event extension.\n"); |
255 | |||
256 | return 0; | ||
257 | |||
258 | out_sysctl: | ||
259 | if (net_eq(net, &init_net)) | ||
260 | nf_ct_extend_unregister(&event_extend); | ||
261 | out_extend_register: | ||
262 | return ret; | 253 | return ret; |
263 | } | 254 | } |
264 | 255 | ||
265 | void nf_conntrack_ecache_fini(struct net *net) | 256 | void nf_conntrack_ecache_fini(void) |
266 | { | 257 | { |
267 | nf_conntrack_event_fini_sysctl(net); | 258 | nf_ct_extend_unregister(&event_extend); |
268 | if (net_eq(net, &init_net)) | ||
269 | nf_ct_extend_unregister(&event_extend); | ||
270 | } | 259 | } |
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 527651a53a45..bdd341899ed3 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c | |||
@@ -587,53 +587,50 @@ static void exp_proc_remove(struct net *net) | |||
587 | 587 | ||
588 | module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400); | 588 | module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400); |
589 | 589 | ||
590 | int nf_conntrack_expect_init(struct net *net) | 590 | int nf_conntrack_expect_pernet_init(struct net *net) |
591 | { | 591 | { |
592 | int err = -ENOMEM; | 592 | int err = -ENOMEM; |
593 | 593 | ||
594 | if (net_eq(net, &init_net)) { | ||
595 | if (!nf_ct_expect_hsize) { | ||
596 | nf_ct_expect_hsize = net->ct.htable_size / 256; | ||
597 | if (!nf_ct_expect_hsize) | ||
598 | nf_ct_expect_hsize = 1; | ||
599 | } | ||
600 | nf_ct_expect_max = nf_ct_expect_hsize * 4; | ||
601 | } | ||
602 | |||
603 | net->ct.expect_count = 0; | 594 | net->ct.expect_count = 0; |
604 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0); | 595 | net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize, 0); |
605 | if (net->ct.expect_hash == NULL) | 596 | if (net->ct.expect_hash == NULL) |
606 | goto err1; | 597 | goto err1; |
607 | 598 | ||
608 | if (net_eq(net, &init_net)) { | ||
609 | nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", | ||
610 | sizeof(struct nf_conntrack_expect), | ||
611 | 0, 0, NULL); | ||
612 | if (!nf_ct_expect_cachep) | ||
613 | goto err2; | ||
614 | } | ||
615 | |||
616 | err = exp_proc_init(net); | 599 | err = exp_proc_init(net); |
617 | if (err < 0) | 600 | if (err < 0) |
618 | goto err3; | 601 | goto err2; |
619 | 602 | ||
620 | return 0; | 603 | return 0; |
621 | |||
622 | err3: | ||
623 | if (net_eq(net, &init_net)) | ||
624 | kmem_cache_destroy(nf_ct_expect_cachep); | ||
625 | err2: | 604 | err2: |
626 | nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); | 605 | nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); |
627 | err1: | 606 | err1: |
628 | return err; | 607 | return err; |
629 | } | 608 | } |
630 | 609 | ||
631 | void nf_conntrack_expect_fini(struct net *net) | 610 | void nf_conntrack_expect_pernet_fini(struct net *net) |
632 | { | 611 | { |
633 | exp_proc_remove(net); | 612 | exp_proc_remove(net); |
634 | if (net_eq(net, &init_net)) { | ||
635 | rcu_barrier(); /* Wait for call_rcu() before destroy */ | ||
636 | kmem_cache_destroy(nf_ct_expect_cachep); | ||
637 | } | ||
638 | nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); | 613 | nf_ct_free_hashtable(net->ct.expect_hash, nf_ct_expect_hsize); |
639 | } | 614 | } |
615 | |||
616 | int nf_conntrack_expect_init(void) | ||
617 | { | ||
618 | if (!nf_ct_expect_hsize) { | ||
619 | nf_ct_expect_hsize = nf_conntrack_htable_size / 256; | ||
620 | if (!nf_ct_expect_hsize) | ||
621 | nf_ct_expect_hsize = 1; | ||
622 | } | ||
623 | nf_ct_expect_max = nf_ct_expect_hsize * 4; | ||
624 | nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect", | ||
625 | sizeof(struct nf_conntrack_expect), | ||
626 | 0, 0, NULL); | ||
627 | if (!nf_ct_expect_cachep) | ||
628 | return -ENOMEM; | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | void nf_conntrack_expect_fini(void) | ||
633 | { | ||
634 | rcu_barrier(); /* Wait for call_rcu() before destroy */ | ||
635 | kmem_cache_destroy(nf_ct_expect_cachep); | ||
636 | } | ||
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 884f2b39319a..2f380f73c4c0 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -423,44 +423,41 @@ static struct nf_ct_ext_type helper_extend __read_mostly = { | |||
423 | .id = NF_CT_EXT_HELPER, | 423 | .id = NF_CT_EXT_HELPER, |
424 | }; | 424 | }; |
425 | 425 | ||
426 | int nf_conntrack_helper_init(struct net *net) | 426 | int nf_conntrack_helper_pernet_init(struct net *net) |
427 | { | 427 | { |
428 | int err; | ||
429 | |||
430 | net->ct.auto_assign_helper_warned = false; | 428 | net->ct.auto_assign_helper_warned = false; |
431 | net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper; | 429 | net->ct.sysctl_auto_assign_helper = nf_ct_auto_assign_helper; |
430 | return nf_conntrack_helper_init_sysctl(net); | ||
431 | } | ||
432 | 432 | ||
433 | if (net_eq(net, &init_net)) { | 433 | void nf_conntrack_helper_pernet_fini(struct net *net) |
434 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ | 434 | { |
435 | nf_ct_helper_hash = | 435 | nf_conntrack_helper_fini_sysctl(net); |
436 | nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0); | 436 | } |
437 | if (!nf_ct_helper_hash) | ||
438 | return -ENOMEM; | ||
439 | 437 | ||
440 | err = nf_ct_extend_register(&helper_extend); | 438 | int nf_conntrack_helper_init(void) |
441 | if (err < 0) | 439 | { |
442 | goto err1; | 440 | int ret; |
441 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ | ||
442 | nf_ct_helper_hash = | ||
443 | nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0); | ||
444 | if (!nf_ct_helper_hash) | ||
445 | return -ENOMEM; | ||
446 | |||
447 | ret = nf_ct_extend_register(&helper_extend); | ||
448 | if (ret < 0) { | ||
449 | pr_err("nf_ct_helper: Unable to register helper extension.\n"); | ||
450 | goto out_extend; | ||
443 | } | 451 | } |
444 | 452 | ||
445 | err = nf_conntrack_helper_init_sysctl(net); | ||
446 | if (err < 0) | ||
447 | goto out_sysctl; | ||
448 | |||
449 | return 0; | 453 | return 0; |
450 | 454 | out_extend: | |
451 | out_sysctl: | ||
452 | if (net_eq(net, &init_net)) | ||
453 | nf_ct_extend_unregister(&helper_extend); | ||
454 | err1: | ||
455 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); | 455 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); |
456 | return err; | 456 | return ret; |
457 | } | 457 | } |
458 | 458 | ||
459 | void nf_conntrack_helper_fini(struct net *net) | 459 | void nf_conntrack_helper_fini(void) |
460 | { | 460 | { |
461 | nf_conntrack_helper_fini_sysctl(net); | 461 | nf_ct_extend_unregister(&helper_extend); |
462 | if (net_eq(net, &init_net)) { | 462 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); |
463 | nf_ct_extend_unregister(&helper_extend); | ||
464 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_hsize); | ||
465 | } | ||
466 | } | 463 | } |
diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c new file mode 100644 index 000000000000..8fe2e99428b7 --- /dev/null +++ b/net/netfilter/nf_conntrack_labels.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * test/set flag bits stored in conntrack extension area. | ||
3 | * | ||
4 | * (C) 2013 Astaro GmbH & Co KG | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/export.h> | ||
13 | #include <linux/jhash.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include <net/netfilter/nf_conntrack_ecache.h> | ||
19 | #include <net/netfilter/nf_conntrack_labels.h> | ||
20 | |||
21 | static unsigned int label_bits(const struct nf_conn_labels *l) | ||
22 | { | ||
23 | unsigned int longs = l->words; | ||
24 | return longs * BITS_PER_LONG; | ||
25 | } | ||
26 | |||
27 | bool nf_connlabel_match(const struct nf_conn *ct, u16 bit) | ||
28 | { | ||
29 | struct nf_conn_labels *labels = nf_ct_labels_find(ct); | ||
30 | |||
31 | if (!labels) | ||
32 | return false; | ||
33 | |||
34 | return bit < label_bits(labels) && test_bit(bit, labels->bits); | ||
35 | } | ||
36 | EXPORT_SYMBOL_GPL(nf_connlabel_match); | ||
37 | |||
38 | int nf_connlabel_set(struct nf_conn *ct, u16 bit) | ||
39 | { | ||
40 | struct nf_conn_labels *labels = nf_ct_labels_find(ct); | ||
41 | |||
42 | if (!labels || bit >= label_bits(labels)) | ||
43 | return -ENOSPC; | ||
44 | |||
45 | if (test_bit(bit, labels->bits)) | ||
46 | return 0; | ||
47 | |||
48 | if (test_and_set_bit(bit, labels->bits)) | ||
49 | nf_conntrack_event_cache(IPCT_LABEL, ct); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(nf_connlabel_set); | ||
54 | |||
55 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK) | ||
56 | static void replace_u32(u32 *address, u32 mask, u32 new) | ||
57 | { | ||
58 | u32 old, tmp; | ||
59 | |||
60 | do { | ||
61 | old = *address; | ||
62 | tmp = (old & mask) ^ new; | ||
63 | } while (cmpxchg(address, old, tmp) != old); | ||
64 | } | ||
65 | |||
66 | int nf_connlabels_replace(struct nf_conn *ct, | ||
67 | const u32 *data, | ||
68 | const u32 *mask, unsigned int words32) | ||
69 | { | ||
70 | struct nf_conn_labels *labels; | ||
71 | unsigned int size, i; | ||
72 | u32 *dst; | ||
73 | |||
74 | labels = nf_ct_labels_find(ct); | ||
75 | if (!labels) | ||
76 | return -ENOSPC; | ||
77 | |||
78 | size = labels->words * sizeof(long); | ||
79 | if (size < (words32 * sizeof(u32))) | ||
80 | words32 = size / sizeof(u32); | ||
81 | |||
82 | dst = (u32 *) labels->bits; | ||
83 | if (words32) { | ||
84 | for (i = 0; i < words32; i++) | ||
85 | replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]); | ||
86 | } | ||
87 | |||
88 | size /= sizeof(u32); | ||
89 | for (i = words32; i < size; i++) /* pad */ | ||
90 | replace_u32(&dst[i], 0, 0); | ||
91 | |||
92 | nf_conntrack_event_cache(IPCT_LABEL, ct); | ||
93 | return 0; | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(nf_connlabels_replace); | ||
96 | #endif | ||
97 | |||
98 | static struct nf_ct_ext_type labels_extend __read_mostly = { | ||
99 | .len = sizeof(struct nf_conn_labels), | ||
100 | .align = __alignof__(struct nf_conn_labels), | ||
101 | .id = NF_CT_EXT_LABELS, | ||
102 | }; | ||
103 | |||
104 | int nf_conntrack_labels_init(void) | ||
105 | { | ||
106 | return nf_ct_extend_register(&labels_extend); | ||
107 | } | ||
108 | |||
109 | void nf_conntrack_labels_fini(void) | ||
110 | { | ||
111 | nf_ct_extend_unregister(&labels_extend); | ||
112 | } | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 627b0e50b238..2334cc5d2b16 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <net/netfilter/nf_conntrack_acct.h> | 43 | #include <net/netfilter/nf_conntrack_acct.h> |
44 | #include <net/netfilter/nf_conntrack_zones.h> | 44 | #include <net/netfilter/nf_conntrack_zones.h> |
45 | #include <net/netfilter/nf_conntrack_timestamp.h> | 45 | #include <net/netfilter/nf_conntrack_timestamp.h> |
46 | #include <net/netfilter/nf_conntrack_labels.h> | ||
46 | #ifdef CONFIG_NF_NAT_NEEDED | 47 | #ifdef CONFIG_NF_NAT_NEEDED |
47 | #include <net/netfilter/nf_nat_core.h> | 48 | #include <net/netfilter/nf_nat_core.h> |
48 | #include <net/netfilter/nf_nat_l4proto.h> | 49 | #include <net/netfilter/nf_nat_l4proto.h> |
@@ -323,6 +324,40 @@ nla_put_failure: | |||
323 | #define ctnetlink_dump_secctx(a, b) (0) | 324 | #define ctnetlink_dump_secctx(a, b) (0) |
324 | #endif | 325 | #endif |
325 | 326 | ||
327 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
328 | static int ctnetlink_label_size(const struct nf_conn *ct) | ||
329 | { | ||
330 | struct nf_conn_labels *labels = nf_ct_labels_find(ct); | ||
331 | |||
332 | if (!labels) | ||
333 | return 0; | ||
334 | return nla_total_size(labels->words * sizeof(long)); | ||
335 | } | ||
336 | |||
337 | static int | ||
338 | ctnetlink_dump_labels(struct sk_buff *skb, const struct nf_conn *ct) | ||
339 | { | ||
340 | struct nf_conn_labels *labels = nf_ct_labels_find(ct); | ||
341 | unsigned int len, i; | ||
342 | |||
343 | if (!labels) | ||
344 | return 0; | ||
345 | |||
346 | len = labels->words * sizeof(long); | ||
347 | i = 0; | ||
348 | do { | ||
349 | if (labels->bits[i] != 0) | ||
350 | return nla_put(skb, CTA_LABELS, len, labels->bits); | ||
351 | i++; | ||
352 | } while (i < labels->words); | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | #else | ||
357 | #define ctnetlink_dump_labels(a, b) (0) | ||
358 | #define ctnetlink_label_size(a) (0) | ||
359 | #endif | ||
360 | |||
326 | #define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple) | 361 | #define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple) |
327 | 362 | ||
328 | static inline int | 363 | static inline int |
@@ -463,6 +498,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, | |||
463 | ctnetlink_dump_helpinfo(skb, ct) < 0 || | 498 | ctnetlink_dump_helpinfo(skb, ct) < 0 || |
464 | ctnetlink_dump_mark(skb, ct) < 0 || | 499 | ctnetlink_dump_mark(skb, ct) < 0 || |
465 | ctnetlink_dump_secctx(skb, ct) < 0 || | 500 | ctnetlink_dump_secctx(skb, ct) < 0 || |
501 | ctnetlink_dump_labels(skb, ct) < 0 || | ||
466 | ctnetlink_dump_id(skb, ct) < 0 || | 502 | ctnetlink_dump_id(skb, ct) < 0 || |
467 | ctnetlink_dump_use(skb, ct) < 0 || | 503 | ctnetlink_dump_use(skb, ct) < 0 || |
468 | ctnetlink_dump_master(skb, ct) < 0 || | 504 | ctnetlink_dump_master(skb, ct) < 0 || |
@@ -561,6 +597,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct) | |||
561 | + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */ | 597 | + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */ |
562 | #endif | 598 | #endif |
563 | + ctnetlink_proto_size(ct) | 599 | + ctnetlink_proto_size(ct) |
600 | + ctnetlink_label_size(ct) | ||
564 | ; | 601 | ; |
565 | } | 602 | } |
566 | 603 | ||
@@ -662,6 +699,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) | |||
662 | && ctnetlink_dump_secctx(skb, ct) < 0) | 699 | && ctnetlink_dump_secctx(skb, ct) < 0) |
663 | goto nla_put_failure; | 700 | goto nla_put_failure; |
664 | #endif | 701 | #endif |
702 | if (events & (1 << IPCT_LABEL) && | ||
703 | ctnetlink_dump_labels(skb, ct) < 0) | ||
704 | goto nla_put_failure; | ||
665 | 705 | ||
666 | if (events & (1 << IPCT_RELATED) && | 706 | if (events & (1 << IPCT_RELATED) && |
667 | ctnetlink_dump_master(skb, ct) < 0) | 707 | ctnetlink_dump_master(skb, ct) < 0) |
@@ -921,6 +961,7 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name, | |||
921 | return 0; | 961 | return 0; |
922 | } | 962 | } |
923 | 963 | ||
964 | #define __CTA_LABELS_MAX_LENGTH ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE) | ||
924 | static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { | 965 | static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { |
925 | [CTA_TUPLE_ORIG] = { .type = NLA_NESTED }, | 966 | [CTA_TUPLE_ORIG] = { .type = NLA_NESTED }, |
926 | [CTA_TUPLE_REPLY] = { .type = NLA_NESTED }, | 967 | [CTA_TUPLE_REPLY] = { .type = NLA_NESTED }, |
@@ -937,6 +978,10 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = { | |||
937 | [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NLA_NESTED }, | 978 | [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NLA_NESTED }, |
938 | [CTA_ZONE] = { .type = NLA_U16 }, | 979 | [CTA_ZONE] = { .type = NLA_U16 }, |
939 | [CTA_MARK_MASK] = { .type = NLA_U32 }, | 980 | [CTA_MARK_MASK] = { .type = NLA_U32 }, |
981 | [CTA_LABELS] = { .type = NLA_BINARY, | ||
982 | .len = __CTA_LABELS_MAX_LENGTH }, | ||
983 | [CTA_LABELS_MASK] = { .type = NLA_BINARY, | ||
984 | .len = __CTA_LABELS_MAX_LENGTH }, | ||
940 | }; | 985 | }; |
941 | 986 | ||
942 | static int | 987 | static int |
@@ -1465,6 +1510,31 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct, | |||
1465 | #endif | 1510 | #endif |
1466 | 1511 | ||
1467 | static int | 1512 | static int |
1513 | ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) | ||
1514 | { | ||
1515 | #ifdef CONFIG_NF_CONNTRACK_LABELS | ||
1516 | size_t len = nla_len(cda[CTA_LABELS]); | ||
1517 | const void *mask = cda[CTA_LABELS_MASK]; | ||
1518 | |||
1519 | if (len & (sizeof(u32)-1)) /* must be multiple of u32 */ | ||
1520 | return -EINVAL; | ||
1521 | |||
1522 | if (mask) { | ||
1523 | if (nla_len(cda[CTA_LABELS_MASK]) == 0 || | ||
1524 | nla_len(cda[CTA_LABELS_MASK]) != len) | ||
1525 | return -EINVAL; | ||
1526 | mask = nla_data(cda[CTA_LABELS_MASK]); | ||
1527 | } | ||
1528 | |||
1529 | len /= sizeof(u32); | ||
1530 | |||
1531 | return nf_connlabels_replace(ct, nla_data(cda[CTA_LABELS]), mask, len); | ||
1532 | #else | ||
1533 | return -EOPNOTSUPP; | ||
1534 | #endif | ||
1535 | } | ||
1536 | |||
1537 | static int | ||
1468 | ctnetlink_change_conntrack(struct nf_conn *ct, | 1538 | ctnetlink_change_conntrack(struct nf_conn *ct, |
1469 | const struct nlattr * const cda[]) | 1539 | const struct nlattr * const cda[]) |
1470 | { | 1540 | { |
@@ -1510,6 +1580,11 @@ ctnetlink_change_conntrack(struct nf_conn *ct, | |||
1510 | return err; | 1580 | return err; |
1511 | } | 1581 | } |
1512 | #endif | 1582 | #endif |
1583 | if (cda[CTA_LABELS]) { | ||
1584 | err = ctnetlink_attach_labels(ct, cda); | ||
1585 | if (err < 0) | ||
1586 | return err; | ||
1587 | } | ||
1513 | 1588 | ||
1514 | return 0; | 1589 | return 0; |
1515 | } | 1590 | } |
@@ -1598,6 +1673,8 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, | |||
1598 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); | 1673 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
1599 | nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); | 1674 | nf_ct_tstamp_ext_add(ct, GFP_ATOMIC); |
1600 | nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC); | 1675 | nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC); |
1676 | nf_ct_labels_ext_add(ct); | ||
1677 | |||
1601 | /* we must add conntrack extensions before confirmation. */ | 1678 | /* we must add conntrack extensions before confirmation. */ |
1602 | ct->status |= IPS_CONFIRMED; | 1679 | ct->status |= IPS_CONFIRMED; |
1603 | 1680 | ||
@@ -1716,6 +1793,10 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | |||
1716 | else | 1793 | else |
1717 | events = IPCT_NEW; | 1794 | events = IPCT_NEW; |
1718 | 1795 | ||
1796 | if (cda[CTA_LABELS] && | ||
1797 | ctnetlink_attach_labels(ct, cda) == 0) | ||
1798 | events |= (1 << IPCT_LABEL); | ||
1799 | |||
1719 | nf_conntrack_eventmask_report((1 << IPCT_REPLY) | | 1800 | nf_conntrack_eventmask_report((1 << IPCT_REPLY) | |
1720 | (1 << IPCT_ASSURED) | | 1801 | (1 << IPCT_ASSURED) | |
1721 | (1 << IPCT_HELPER) | | 1802 | (1 << IPCT_HELPER) | |
@@ -1983,6 +2064,8 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct) | |||
1983 | if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0) | 2064 | if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0) |
1984 | goto nla_put_failure; | 2065 | goto nla_put_failure; |
1985 | #endif | 2066 | #endif |
2067 | if (ctnetlink_dump_labels(skb, ct) < 0) | ||
2068 | goto nla_put_failure; | ||
1986 | rcu_read_unlock(); | 2069 | rcu_read_unlock(); |
1987 | return 0; | 2070 | return 0; |
1988 | 2071 | ||
@@ -2011,6 +2094,11 @@ ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) | |||
2011 | if (err < 0) | 2094 | if (err < 0) |
2012 | return err; | 2095 | return err; |
2013 | } | 2096 | } |
2097 | if (cda[CTA_LABELS]) { | ||
2098 | err = ctnetlink_attach_labels(ct, cda); | ||
2099 | if (err < 0) | ||
2100 | return err; | ||
2101 | } | ||
2014 | #if defined(CONFIG_NF_CONNTRACK_MARK) | 2102 | #if defined(CONFIG_NF_CONNTRACK_MARK) |
2015 | if (cda[CTA_MARK]) | 2103 | if (cda[CTA_MARK]) |
2016 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); | 2104 | ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); |
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 51e928db48c8..58ab4050830c 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c | |||
@@ -212,8 +212,7 @@ static void nf_ct_l3proto_unregister_sysctl(struct net *net, | |||
212 | #endif | 212 | #endif |
213 | } | 213 | } |
214 | 214 | ||
215 | static int | 215 | int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto) |
216 | nf_conntrack_l3proto_register_net(struct nf_conntrack_l3proto *proto) | ||
217 | { | 216 | { |
218 | int ret = 0; | 217 | int ret = 0; |
219 | struct nf_conntrack_l3proto *old; | 218 | struct nf_conntrack_l3proto *old; |
@@ -242,8 +241,9 @@ out_unlock: | |||
242 | return ret; | 241 | return ret; |
243 | 242 | ||
244 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_register); | ||
245 | 245 | ||
246 | int nf_conntrack_l3proto_register(struct net *net, | 246 | int nf_ct_l3proto_pernet_register(struct net *net, |
247 | struct nf_conntrack_l3proto *proto) | 247 | struct nf_conntrack_l3proto *proto) |
248 | { | 248 | { |
249 | int ret = 0; | 249 | int ret = 0; |
@@ -254,22 +254,11 @@ int nf_conntrack_l3proto_register(struct net *net, | |||
254 | return ret; | 254 | return ret; |
255 | } | 255 | } |
256 | 256 | ||
257 | ret = nf_ct_l3proto_register_sysctl(net, proto); | 257 | return nf_ct_l3proto_register_sysctl(net, proto); |
258 | if (ret < 0) | ||
259 | return ret; | ||
260 | |||
261 | if (net == &init_net) { | ||
262 | ret = nf_conntrack_l3proto_register_net(proto); | ||
263 | if (ret < 0) | ||
264 | nf_ct_l3proto_unregister_sysctl(net, proto); | ||
265 | } | ||
266 | |||
267 | return ret; | ||
268 | } | 258 | } |
269 | EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register); | 259 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_register); |
270 | 260 | ||
271 | static void | 261 | void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto) |
272 | nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto) | ||
273 | { | 262 | { |
274 | BUG_ON(proto->l3proto >= AF_MAX); | 263 | BUG_ON(proto->l3proto >= AF_MAX); |
275 | 264 | ||
@@ -283,19 +272,17 @@ nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto) | |||
283 | 272 | ||
284 | synchronize_rcu(); | 273 | synchronize_rcu(); |
285 | } | 274 | } |
275 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_unregister); | ||
286 | 276 | ||
287 | void nf_conntrack_l3proto_unregister(struct net *net, | 277 | void nf_ct_l3proto_pernet_unregister(struct net *net, |
288 | struct nf_conntrack_l3proto *proto) | 278 | struct nf_conntrack_l3proto *proto) |
289 | { | 279 | { |
290 | if (net == &init_net) | ||
291 | nf_conntrack_l3proto_unregister_net(proto); | ||
292 | |||
293 | nf_ct_l3proto_unregister_sysctl(net, proto); | 280 | nf_ct_l3proto_unregister_sysctl(net, proto); |
294 | 281 | ||
295 | /* Remove all contrack entries for this protocol */ | 282 | /* Remove all contrack entries for this protocol */ |
296 | nf_ct_iterate_cleanup(net, kill_l3proto, proto); | 283 | nf_ct_iterate_cleanup(net, kill_l3proto, proto); |
297 | } | 284 | } |
298 | EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister); | 285 | EXPORT_SYMBOL_GPL(nf_ct_l3proto_pernet_unregister); |
299 | 286 | ||
300 | static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, | 287 | static struct nf_proto_net *nf_ct_l4proto_net(struct net *net, |
301 | struct nf_conntrack_l4proto *l4proto) | 288 | struct nf_conntrack_l4proto *l4proto) |
@@ -376,8 +363,7 @@ void nf_ct_l4proto_unregister_sysctl(struct net *net, | |||
376 | 363 | ||
377 | /* FIXME: Allow NULL functions and sub in pointers to generic for | 364 | /* FIXME: Allow NULL functions and sub in pointers to generic for |
378 | them. --RR */ | 365 | them. --RR */ |
379 | static int | 366 | int nf_ct_l4proto_register(struct nf_conntrack_l4proto *l4proto) |
380 | nf_conntrack_l4proto_register_net(struct nf_conntrack_l4proto *l4proto) | ||
381 | { | 367 | { |
382 | int ret = 0; | 368 | int ret = 0; |
383 | 369 | ||
@@ -431,8 +417,9 @@ out_unlock: | |||
431 | mutex_unlock(&nf_ct_proto_mutex); | 417 | mutex_unlock(&nf_ct_proto_mutex); |
432 | return ret; | 418 | return ret; |
433 | } | 419 | } |
420 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_register); | ||
434 | 421 | ||
435 | int nf_conntrack_l4proto_register(struct net *net, | 422 | int nf_ct_l4proto_pernet_register(struct net *net, |
436 | struct nf_conntrack_l4proto *l4proto) | 423 | struct nf_conntrack_l4proto *l4proto) |
437 | { | 424 | { |
438 | int ret = 0; | 425 | int ret = 0; |
@@ -452,22 +439,13 @@ int nf_conntrack_l4proto_register(struct net *net, | |||
452 | if (ret < 0) | 439 | if (ret < 0) |
453 | goto out; | 440 | goto out; |
454 | 441 | ||
455 | if (net == &init_net) { | ||
456 | ret = nf_conntrack_l4proto_register_net(l4proto); | ||
457 | if (ret < 0) { | ||
458 | nf_ct_l4proto_unregister_sysctl(net, pn, l4proto); | ||
459 | goto out; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | pn->users++; | 442 | pn->users++; |
464 | out: | 443 | out: |
465 | return ret; | 444 | return ret; |
466 | } | 445 | } |
467 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register); | 446 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_register); |
468 | 447 | ||
469 | static void | 448 | void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *l4proto) |
470 | nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto) | ||
471 | { | 449 | { |
472 | BUG_ON(l4proto->l3proto >= PF_MAX); | 450 | BUG_ON(l4proto->l3proto >= PF_MAX); |
473 | 451 | ||
@@ -482,15 +460,13 @@ nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto) | |||
482 | 460 | ||
483 | synchronize_rcu(); | 461 | synchronize_rcu(); |
484 | } | 462 | } |
463 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister); | ||
485 | 464 | ||
486 | void nf_conntrack_l4proto_unregister(struct net *net, | 465 | void nf_ct_l4proto_pernet_unregister(struct net *net, |
487 | struct nf_conntrack_l4proto *l4proto) | 466 | struct nf_conntrack_l4proto *l4proto) |
488 | { | 467 | { |
489 | struct nf_proto_net *pn = NULL; | 468 | struct nf_proto_net *pn = NULL; |
490 | 469 | ||
491 | if (net == &init_net) | ||
492 | nf_conntrack_l4proto_unregister_net(l4proto); | ||
493 | |||
494 | pn = nf_ct_l4proto_net(net, l4proto); | 470 | pn = nf_ct_l4proto_net(net, l4proto); |
495 | if (pn == NULL) | 471 | if (pn == NULL) |
496 | return; | 472 | return; |
@@ -501,11 +477,10 @@ void nf_conntrack_l4proto_unregister(struct net *net, | |||
501 | /* Remove all contrack entries for this protocol */ | 477 | /* Remove all contrack entries for this protocol */ |
502 | nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); | 478 | nf_ct_iterate_cleanup(net, kill_l4proto, l4proto); |
503 | } | 479 | } |
504 | EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister); | 480 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_pernet_unregister); |
505 | 481 | ||
506 | int nf_conntrack_proto_init(struct net *net) | 482 | int nf_conntrack_proto_pernet_init(struct net *net) |
507 | { | 483 | { |
508 | unsigned int i; | ||
509 | int err; | 484 | int err; |
510 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, | 485 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, |
511 | &nf_conntrack_l4proto_generic); | 486 | &nf_conntrack_l4proto_generic); |
@@ -520,19 +495,12 @@ int nf_conntrack_proto_init(struct net *net) | |||
520 | if (err < 0) | 495 | if (err < 0) |
521 | return err; | 496 | return err; |
522 | 497 | ||
523 | if (net == &init_net) { | ||
524 | for (i = 0; i < AF_MAX; i++) | ||
525 | rcu_assign_pointer(nf_ct_l3protos[i], | ||
526 | &nf_conntrack_l3proto_generic); | ||
527 | } | ||
528 | |||
529 | pn->users++; | 498 | pn->users++; |
530 | return 0; | 499 | return 0; |
531 | } | 500 | } |
532 | 501 | ||
533 | void nf_conntrack_proto_fini(struct net *net) | 502 | void nf_conntrack_proto_pernet_fini(struct net *net) |
534 | { | 503 | { |
535 | unsigned int i; | ||
536 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, | 504 | struct nf_proto_net *pn = nf_ct_l4proto_net(net, |
537 | &nf_conntrack_l4proto_generic); | 505 | &nf_conntrack_l4proto_generic); |
538 | 506 | ||
@@ -540,9 +508,21 @@ void nf_conntrack_proto_fini(struct net *net) | |||
540 | nf_ct_l4proto_unregister_sysctl(net, | 508 | nf_ct_l4proto_unregister_sysctl(net, |
541 | pn, | 509 | pn, |
542 | &nf_conntrack_l4proto_generic); | 510 | &nf_conntrack_l4proto_generic); |
543 | if (net == &init_net) { | 511 | } |
544 | /* free l3proto protocol tables */ | 512 | |
545 | for (i = 0; i < PF_MAX; i++) | 513 | int nf_conntrack_proto_init(void) |
546 | kfree(nf_ct_protos[i]); | 514 | { |
547 | } | 515 | unsigned int i; |
516 | for (i = 0; i < AF_MAX; i++) | ||
517 | rcu_assign_pointer(nf_ct_l3protos[i], | ||
518 | &nf_conntrack_l3proto_generic); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | void nf_conntrack_proto_fini(void) | ||
523 | { | ||
524 | unsigned int i; | ||
525 | /* free l3proto protocol tables */ | ||
526 | for (i = 0; i < PF_MAX; i++) | ||
527 | kfree(nf_ct_protos[i]); | ||
548 | } | 528 | } |
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index a8ae287bc7af..432f95780003 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c | |||
@@ -935,32 +935,27 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | |||
935 | static __net_init int dccp_net_init(struct net *net) | 935 | static __net_init int dccp_net_init(struct net *net) |
936 | { | 936 | { |
937 | int ret = 0; | 937 | int ret = 0; |
938 | ret = nf_conntrack_l4proto_register(net, | 938 | ret = nf_ct_l4proto_pernet_register(net, &dccp_proto4); |
939 | &dccp_proto4); | ||
940 | if (ret < 0) { | 939 | if (ret < 0) { |
941 | pr_err("nf_conntrack_l4proto_dccp4 :protocol register failed.\n"); | 940 | pr_err("nf_conntrack_dccp4: pernet registration failed.\n"); |
942 | goto out; | 941 | goto out; |
943 | } | 942 | } |
944 | ret = nf_conntrack_l4proto_register(net, | 943 | ret = nf_ct_l4proto_pernet_register(net, &dccp_proto6); |
945 | &dccp_proto6); | ||
946 | if (ret < 0) { | 944 | if (ret < 0) { |
947 | pr_err("nf_conntrack_l4proto_dccp6 :protocol register failed.\n"); | 945 | pr_err("nf_conntrack_dccp6: pernet registration failed.\n"); |
948 | goto cleanup_dccp4; | 946 | goto cleanup_dccp4; |
949 | } | 947 | } |
950 | return 0; | 948 | return 0; |
951 | cleanup_dccp4: | 949 | cleanup_dccp4: |
952 | nf_conntrack_l4proto_unregister(net, | 950 | nf_ct_l4proto_pernet_unregister(net, &dccp_proto4); |
953 | &dccp_proto4); | ||
954 | out: | 951 | out: |
955 | return ret; | 952 | return ret; |
956 | } | 953 | } |
957 | 954 | ||
958 | static __net_exit void dccp_net_exit(struct net *net) | 955 | static __net_exit void dccp_net_exit(struct net *net) |
959 | { | 956 | { |
960 | nf_conntrack_l4proto_unregister(net, | 957 | nf_ct_l4proto_pernet_unregister(net, &dccp_proto6); |
961 | &dccp_proto6); | 958 | nf_ct_l4proto_pernet_unregister(net, &dccp_proto4); |
962 | nf_conntrack_l4proto_unregister(net, | ||
963 | &dccp_proto4); | ||
964 | } | 959 | } |
965 | 960 | ||
966 | static struct pernet_operations dccp_net_ops = { | 961 | static struct pernet_operations dccp_net_ops = { |
@@ -972,11 +967,33 @@ static struct pernet_operations dccp_net_ops = { | |||
972 | 967 | ||
973 | static int __init nf_conntrack_proto_dccp_init(void) | 968 | static int __init nf_conntrack_proto_dccp_init(void) |
974 | { | 969 | { |
975 | return register_pernet_subsys(&dccp_net_ops); | 970 | int ret; |
971 | |||
972 | ret = nf_ct_l4proto_register(&dccp_proto4); | ||
973 | if (ret < 0) | ||
974 | goto out_dccp4; | ||
975 | |||
976 | ret = nf_ct_l4proto_register(&dccp_proto6); | ||
977 | if (ret < 0) | ||
978 | goto out_dccp6; | ||
979 | |||
980 | ret = register_pernet_subsys(&dccp_net_ops); | ||
981 | if (ret < 0) | ||
982 | goto out_pernet; | ||
983 | |||
984 | return 0; | ||
985 | out_pernet: | ||
986 | nf_ct_l4proto_unregister(&dccp_proto6); | ||
987 | out_dccp6: | ||
988 | nf_ct_l4proto_unregister(&dccp_proto4); | ||
989 | out_dccp4: | ||
990 | return ret; | ||
976 | } | 991 | } |
977 | 992 | ||
978 | static void __exit nf_conntrack_proto_dccp_fini(void) | 993 | static void __exit nf_conntrack_proto_dccp_fini(void) |
979 | { | 994 | { |
995 | nf_ct_l4proto_unregister(&dccp_proto6); | ||
996 | nf_ct_l4proto_unregister(&dccp_proto4); | ||
980 | unregister_pernet_subsys(&dccp_net_ops); | 997 | unregister_pernet_subsys(&dccp_net_ops); |
981 | } | 998 | } |
982 | 999 | ||
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index b09b7af7f6f8..bd7d01d9c7e7 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c | |||
@@ -397,15 +397,15 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = { | |||
397 | static int proto_gre_net_init(struct net *net) | 397 | static int proto_gre_net_init(struct net *net) |
398 | { | 398 | { |
399 | int ret = 0; | 399 | int ret = 0; |
400 | ret = nf_conntrack_l4proto_register(net, &nf_conntrack_l4proto_gre4); | 400 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_gre4); |
401 | if (ret < 0) | 401 | if (ret < 0) |
402 | pr_err("nf_conntrack_l4proto_gre4 :protocol register failed.\n"); | 402 | pr_err("nf_conntrack_gre4: pernet registration failed.\n"); |
403 | return ret; | 403 | return ret; |
404 | } | 404 | } |
405 | 405 | ||
406 | static void proto_gre_net_exit(struct net *net) | 406 | static void proto_gre_net_exit(struct net *net) |
407 | { | 407 | { |
408 | nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_gre4); | 408 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_gre4); |
409 | nf_ct_gre_keymap_flush(net); | 409 | nf_ct_gre_keymap_flush(net); |
410 | } | 410 | } |
411 | 411 | ||
@@ -418,11 +418,26 @@ static struct pernet_operations proto_gre_net_ops = { | |||
418 | 418 | ||
419 | static int __init nf_ct_proto_gre_init(void) | 419 | static int __init nf_ct_proto_gre_init(void) |
420 | { | 420 | { |
421 | return register_pernet_subsys(&proto_gre_net_ops); | 421 | int ret; |
422 | |||
423 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4); | ||
424 | if (ret < 0) | ||
425 | goto out_gre4; | ||
426 | |||
427 | ret = register_pernet_subsys(&proto_gre_net_ops); | ||
428 | if (ret < 0) | ||
429 | goto out_pernet; | ||
430 | |||
431 | return 0; | ||
432 | out_pernet: | ||
433 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4); | ||
434 | out_gre4: | ||
435 | return ret; | ||
422 | } | 436 | } |
423 | 437 | ||
424 | static void __exit nf_ct_proto_gre_fini(void) | 438 | static void __exit nf_ct_proto_gre_fini(void) |
425 | { | 439 | { |
440 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4); | ||
426 | unregister_pernet_subsys(&proto_gre_net_ops); | 441 | unregister_pernet_subsys(&proto_gre_net_ops); |
427 | } | 442 | } |
428 | 443 | ||
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index c746d61f83ed..480f616d5936 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c | |||
@@ -853,33 +853,28 @@ static int sctp_net_init(struct net *net) | |||
853 | { | 853 | { |
854 | int ret = 0; | 854 | int ret = 0; |
855 | 855 | ||
856 | ret = nf_conntrack_l4proto_register(net, | 856 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_sctp4); |
857 | &nf_conntrack_l4proto_sctp4); | ||
858 | if (ret < 0) { | 857 | if (ret < 0) { |
859 | pr_err("nf_conntrack_l4proto_sctp4 :protocol register failed.\n"); | 858 | pr_err("nf_conntrack_sctp4: pernet registration failed.\n"); |
860 | goto out; | 859 | goto out; |
861 | } | 860 | } |
862 | ret = nf_conntrack_l4proto_register(net, | 861 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_sctp6); |
863 | &nf_conntrack_l4proto_sctp6); | ||
864 | if (ret < 0) { | 862 | if (ret < 0) { |
865 | pr_err("nf_conntrack_l4proto_sctp6 :protocol register failed.\n"); | 863 | pr_err("nf_conntrack_sctp6: pernet registration failed.\n"); |
866 | goto cleanup_sctp4; | 864 | goto cleanup_sctp4; |
867 | } | 865 | } |
868 | return 0; | 866 | return 0; |
869 | 867 | ||
870 | cleanup_sctp4: | 868 | cleanup_sctp4: |
871 | nf_conntrack_l4proto_unregister(net, | 869 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_sctp4); |
872 | &nf_conntrack_l4proto_sctp4); | ||
873 | out: | 870 | out: |
874 | return ret; | 871 | return ret; |
875 | } | 872 | } |
876 | 873 | ||
877 | static void sctp_net_exit(struct net *net) | 874 | static void sctp_net_exit(struct net *net) |
878 | { | 875 | { |
879 | nf_conntrack_l4proto_unregister(net, | 876 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_sctp6); |
880 | &nf_conntrack_l4proto_sctp6); | 877 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_sctp4); |
881 | nf_conntrack_l4proto_unregister(net, | ||
882 | &nf_conntrack_l4proto_sctp4); | ||
883 | } | 878 | } |
884 | 879 | ||
885 | static struct pernet_operations sctp_net_ops = { | 880 | static struct pernet_operations sctp_net_ops = { |
@@ -891,11 +886,33 @@ static struct pernet_operations sctp_net_ops = { | |||
891 | 886 | ||
892 | static int __init nf_conntrack_proto_sctp_init(void) | 887 | static int __init nf_conntrack_proto_sctp_init(void) |
893 | { | 888 | { |
894 | return register_pernet_subsys(&sctp_net_ops); | 889 | int ret; |
890 | |||
891 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp4); | ||
892 | if (ret < 0) | ||
893 | goto out_sctp4; | ||
894 | |||
895 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp6); | ||
896 | if (ret < 0) | ||
897 | goto out_sctp6; | ||
898 | |||
899 | ret = register_pernet_subsys(&sctp_net_ops); | ||
900 | if (ret < 0) | ||
901 | goto out_pernet; | ||
902 | |||
903 | return 0; | ||
904 | out_pernet: | ||
905 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6); | ||
906 | out_sctp6: | ||
907 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4); | ||
908 | out_sctp4: | ||
909 | return ret; | ||
895 | } | 910 | } |
896 | 911 | ||
897 | static void __exit nf_conntrack_proto_sctp_fini(void) | 912 | static void __exit nf_conntrack_proto_sctp_fini(void) |
898 | { | 913 | { |
914 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6); | ||
915 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4); | ||
899 | unregister_pernet_subsys(&sctp_net_ops); | 916 | unregister_pernet_subsys(&sctp_net_ops); |
900 | } | 917 | } |
901 | 918 | ||
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 4b66df209286..157489581c31 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c | |||
@@ -336,30 +336,28 @@ static int udplite_net_init(struct net *net) | |||
336 | { | 336 | { |
337 | int ret = 0; | 337 | int ret = 0; |
338 | 338 | ||
339 | ret = nf_conntrack_l4proto_register(net, | 339 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udplite4); |
340 | &nf_conntrack_l4proto_udplite4); | ||
341 | if (ret < 0) { | 340 | if (ret < 0) { |
342 | pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n"); | 341 | pr_err("nf_conntrack_udplite4: pernet registration failed.\n"); |
343 | goto out; | 342 | goto out; |
344 | } | 343 | } |
345 | ret = nf_conntrack_l4proto_register(net, | 344 | ret = nf_ct_l4proto_pernet_register(net, &nf_conntrack_l4proto_udplite6); |
346 | &nf_conntrack_l4proto_udplite6); | ||
347 | if (ret < 0) { | 345 | if (ret < 0) { |
348 | pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n"); | 346 | pr_err("nf_conntrack_udplite6: pernet registration failed.\n"); |
349 | goto cleanup_udplite4; | 347 | goto cleanup_udplite4; |
350 | } | 348 | } |
351 | return 0; | 349 | return 0; |
352 | 350 | ||
353 | cleanup_udplite4: | 351 | cleanup_udplite4: |
354 | nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4); | 352 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite4); |
355 | out: | 353 | out: |
356 | return ret; | 354 | return ret; |
357 | } | 355 | } |
358 | 356 | ||
359 | static void udplite_net_exit(struct net *net) | 357 | static void udplite_net_exit(struct net *net) |
360 | { | 358 | { |
361 | nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite6); | 359 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite6); |
362 | nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4); | 360 | nf_ct_l4proto_pernet_unregister(net, &nf_conntrack_l4proto_udplite4); |
363 | } | 361 | } |
364 | 362 | ||
365 | static struct pernet_operations udplite_net_ops = { | 363 | static struct pernet_operations udplite_net_ops = { |
@@ -371,11 +369,33 @@ static struct pernet_operations udplite_net_ops = { | |||
371 | 369 | ||
372 | static int __init nf_conntrack_proto_udplite_init(void) | 370 | static int __init nf_conntrack_proto_udplite_init(void) |
373 | { | 371 | { |
374 | return register_pernet_subsys(&udplite_net_ops); | 372 | int ret; |
373 | |||
374 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite4); | ||
375 | if (ret < 0) | ||
376 | goto out_udplite4; | ||
377 | |||
378 | ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite6); | ||
379 | if (ret < 0) | ||
380 | goto out_udplite6; | ||
381 | |||
382 | ret = register_pernet_subsys(&udplite_net_ops); | ||
383 | if (ret < 0) | ||
384 | goto out_pernet; | ||
385 | |||
386 | return 0; | ||
387 | out_pernet: | ||
388 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6); | ||
389 | out_udplite6: | ||
390 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4); | ||
391 | out_udplite4: | ||
392 | return ret; | ||
375 | } | 393 | } |
376 | 394 | ||
377 | static void __exit nf_conntrack_proto_udplite_exit(void) | 395 | static void __exit nf_conntrack_proto_udplite_exit(void) |
378 | { | 396 | { |
397 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6); | ||
398 | nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4); | ||
379 | unregister_pernet_subsys(&udplite_net_ops); | 399 | unregister_pernet_subsys(&udplite_net_ops); |
380 | } | 400 | } |
381 | 401 | ||
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index df8f4f284481..72a67bbe3518 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -1440,8 +1440,25 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff, | |||
1440 | { | 1440 | { |
1441 | enum ip_conntrack_info ctinfo; | 1441 | enum ip_conntrack_info ctinfo; |
1442 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1442 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1443 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
1444 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
1443 | unsigned int matchoff, matchlen; | 1445 | unsigned int matchoff, matchlen; |
1444 | unsigned int cseq, i; | 1446 | unsigned int cseq, i; |
1447 | union nf_inet_addr addr; | ||
1448 | __be16 port; | ||
1449 | |||
1450 | /* Many Cisco IP phones use a high source port for SIP requests, but | ||
1451 | * listen for the response on port 5060. If we are the local | ||
1452 | * router for one of these phones, save the port number from the | ||
1453 | * Via: header so that nf_nat_sip can redirect the responses to | ||
1454 | * the correct port. | ||
1455 | */ | ||
1456 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | ||
1457 | SIP_HDR_VIA_UDP, NULL, &matchoff, | ||
1458 | &matchlen, &addr, &port) > 0 && | ||
1459 | port != ct->tuplehash[dir].tuple.src.u.udp.port && | ||
1460 | nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3)) | ||
1461 | ct_sip_info->forced_dport = port; | ||
1445 | 1462 | ||
1446 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { | 1463 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { |
1447 | const struct sip_handler *handler; | 1464 | const struct sip_handler *handler; |
diff --git a/net/netfilter/nf_conntrack_snmp.c b/net/netfilter/nf_conntrack_snmp.c index 6e545e26289e..87b95a2c270c 100644 --- a/net/netfilter/nf_conntrack_snmp.c +++ b/net/netfilter/nf_conntrack_snmp.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <net/netfilter/nf_conntrack.h> | 16 | #include <net/netfilter/nf_conntrack.h> |
17 | #include <net/netfilter/nf_conntrack_helper.h> | 17 | #include <net/netfilter/nf_conntrack_helper.h> |
18 | #include <net/netfilter/nf_conntrack_expect.h> | 18 | #include <net/netfilter/nf_conntrack_expect.h> |
19 | #include <linux/netfilter/nf_conntrack_snmp.h> | ||
19 | 20 | ||
20 | #define SNMP_PORT 161 | 21 | #define SNMP_PORT 161 |
21 | 22 | ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index e7185c684816..7936bf7f90ba 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -472,13 +472,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) | |||
472 | { | 472 | { |
473 | struct ctl_table *table; | 473 | struct ctl_table *table; |
474 | 474 | ||
475 | if (net_eq(net, &init_net)) { | ||
476 | nf_ct_netfilter_header = | ||
477 | register_net_sysctl(&init_net, "net", nf_ct_netfilter_table); | ||
478 | if (!nf_ct_netfilter_header) | ||
479 | goto out; | ||
480 | } | ||
481 | |||
482 | table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), | 475 | table = kmemdup(nf_ct_sysctl_table, sizeof(nf_ct_sysctl_table), |
483 | GFP_KERNEL); | 476 | GFP_KERNEL); |
484 | if (!table) | 477 | if (!table) |
@@ -502,10 +495,6 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) | |||
502 | out_unregister_netfilter: | 495 | out_unregister_netfilter: |
503 | kfree(table); | 496 | kfree(table); |
504 | out_kmemdup: | 497 | out_kmemdup: |
505 | if (net_eq(net, &init_net)) | ||
506 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
507 | out: | ||
508 | printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n"); | ||
509 | return -ENOMEM; | 498 | return -ENOMEM; |
510 | } | 499 | } |
511 | 500 | ||
@@ -513,8 +502,6 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net) | |||
513 | { | 502 | { |
514 | struct ctl_table *table; | 503 | struct ctl_table *table; |
515 | 504 | ||
516 | if (net_eq(net, &init_net)) | ||
517 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
518 | table = net->ct.sysctl_header->ctl_table_arg; | 505 | table = net->ct.sysctl_header->ctl_table_arg; |
519 | unregister_net_sysctl_table(net->ct.sysctl_header); | 506 | unregister_net_sysctl_table(net->ct.sysctl_header); |
520 | kfree(table); | 507 | kfree(table); |
@@ -530,51 +517,85 @@ static void nf_conntrack_standalone_fini_sysctl(struct net *net) | |||
530 | } | 517 | } |
531 | #endif /* CONFIG_SYSCTL */ | 518 | #endif /* CONFIG_SYSCTL */ |
532 | 519 | ||
533 | static int nf_conntrack_net_init(struct net *net) | 520 | static int nf_conntrack_pernet_init(struct net *net) |
534 | { | 521 | { |
535 | int ret; | 522 | int ret; |
536 | 523 | ||
537 | ret = nf_conntrack_init(net); | 524 | ret = nf_conntrack_init_net(net); |
538 | if (ret < 0) | 525 | if (ret < 0) |
539 | goto out_init; | 526 | goto out_init; |
527 | |||
540 | ret = nf_conntrack_standalone_init_proc(net); | 528 | ret = nf_conntrack_standalone_init_proc(net); |
541 | if (ret < 0) | 529 | if (ret < 0) |
542 | goto out_proc; | 530 | goto out_proc; |
531 | |||
543 | net->ct.sysctl_checksum = 1; | 532 | net->ct.sysctl_checksum = 1; |
544 | net->ct.sysctl_log_invalid = 0; | 533 | net->ct.sysctl_log_invalid = 0; |
545 | ret = nf_conntrack_standalone_init_sysctl(net); | 534 | ret = nf_conntrack_standalone_init_sysctl(net); |
546 | if (ret < 0) | 535 | if (ret < 0) |
547 | goto out_sysctl; | 536 | goto out_sysctl; |
537 | |||
548 | return 0; | 538 | return 0; |
549 | 539 | ||
550 | out_sysctl: | 540 | out_sysctl: |
551 | nf_conntrack_standalone_fini_proc(net); | 541 | nf_conntrack_standalone_fini_proc(net); |
552 | out_proc: | 542 | out_proc: |
553 | nf_conntrack_cleanup(net); | 543 | nf_conntrack_cleanup_net(net); |
554 | out_init: | 544 | out_init: |
555 | return ret; | 545 | return ret; |
556 | } | 546 | } |
557 | 547 | ||
558 | static void nf_conntrack_net_exit(struct net *net) | 548 | static void nf_conntrack_pernet_exit(struct net *net) |
559 | { | 549 | { |
560 | nf_conntrack_standalone_fini_sysctl(net); | 550 | nf_conntrack_standalone_fini_sysctl(net); |
561 | nf_conntrack_standalone_fini_proc(net); | 551 | nf_conntrack_standalone_fini_proc(net); |
562 | nf_conntrack_cleanup(net); | 552 | nf_conntrack_cleanup_net(net); |
563 | } | 553 | } |
564 | 554 | ||
565 | static struct pernet_operations nf_conntrack_net_ops = { | 555 | static struct pernet_operations nf_conntrack_net_ops = { |
566 | .init = nf_conntrack_net_init, | 556 | .init = nf_conntrack_pernet_init, |
567 | .exit = nf_conntrack_net_exit, | 557 | .exit = nf_conntrack_pernet_exit, |
568 | }; | 558 | }; |
569 | 559 | ||
570 | static int __init nf_conntrack_standalone_init(void) | 560 | static int __init nf_conntrack_standalone_init(void) |
571 | { | 561 | { |
572 | return register_pernet_subsys(&nf_conntrack_net_ops); | 562 | int ret = nf_conntrack_init_start(); |
563 | if (ret < 0) | ||
564 | goto out_start; | ||
565 | |||
566 | #ifdef CONFIG_SYSCTL | ||
567 | nf_ct_netfilter_header = | ||
568 | register_net_sysctl(&init_net, "net", nf_ct_netfilter_table); | ||
569 | if (!nf_ct_netfilter_header) { | ||
570 | pr_err("nf_conntrack: can't register to sysctl.\n"); | ||
571 | goto out_sysctl; | ||
572 | } | ||
573 | #endif | ||
574 | |||
575 | ret = register_pernet_subsys(&nf_conntrack_net_ops); | ||
576 | if (ret < 0) | ||
577 | goto out_pernet; | ||
578 | |||
579 | nf_conntrack_init_end(); | ||
580 | return 0; | ||
581 | |||
582 | out_pernet: | ||
583 | #ifdef CONFIG_SYSCTL | ||
584 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
585 | out_sysctl: | ||
586 | #endif | ||
587 | nf_conntrack_cleanup_end(); | ||
588 | out_start: | ||
589 | return ret; | ||
573 | } | 590 | } |
574 | 591 | ||
575 | static void __exit nf_conntrack_standalone_fini(void) | 592 | static void __exit nf_conntrack_standalone_fini(void) |
576 | { | 593 | { |
594 | nf_conntrack_cleanup_start(); | ||
577 | unregister_pernet_subsys(&nf_conntrack_net_ops); | 595 | unregister_pernet_subsys(&nf_conntrack_net_ops); |
596 | #ifdef CONFIG_SYSCTL | ||
597 | unregister_net_sysctl_table(nf_ct_netfilter_header); | ||
598 | #endif | ||
578 | nf_conntrack_cleanup_end(); | 599 | nf_conntrack_cleanup_end(); |
579 | } | 600 | } |
580 | 601 | ||
diff --git a/net/netfilter/nf_conntrack_timeout.c b/net/netfilter/nf_conntrack_timeout.c index a878ce5b252c..93da609d9d29 100644 --- a/net/netfilter/nf_conntrack_timeout.c +++ b/net/netfilter/nf_conntrack_timeout.c | |||
@@ -37,24 +37,15 @@ static struct nf_ct_ext_type timeout_extend __read_mostly = { | |||
37 | .id = NF_CT_EXT_TIMEOUT, | 37 | .id = NF_CT_EXT_TIMEOUT, |
38 | }; | 38 | }; |
39 | 39 | ||
40 | int nf_conntrack_timeout_init(struct net *net) | 40 | int nf_conntrack_timeout_init(void) |
41 | { | 41 | { |
42 | int ret = 0; | 42 | int ret = nf_ct_extend_register(&timeout_extend); |
43 | 43 | if (ret < 0) | |
44 | if (net_eq(net, &init_net)) { | 44 | pr_err("nf_ct_timeout: Unable to register timeout extension.\n"); |
45 | ret = nf_ct_extend_register(&timeout_extend); | 45 | return ret; |
46 | if (ret < 0) { | ||
47 | printk(KERN_ERR "nf_ct_timeout: Unable to register " | ||
48 | "timeout extension.\n"); | ||
49 | return ret; | ||
50 | } | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | } | 46 | } |
55 | 47 | ||
56 | void nf_conntrack_timeout_fini(struct net *net) | 48 | void nf_conntrack_timeout_fini(void) |
57 | { | 49 | { |
58 | if (net_eq(net, &init_net)) | 50 | nf_ct_extend_unregister(&timeout_extend); |
59 | nf_ct_extend_unregister(&timeout_extend); | ||
60 | } | 51 | } |
diff --git a/net/netfilter/nf_conntrack_timestamp.c b/net/netfilter/nf_conntrack_timestamp.c index 7ea8026f07c9..902fb0a6b38a 100644 --- a/net/netfilter/nf_conntrack_timestamp.c +++ b/net/netfilter/nf_conntrack_timestamp.c | |||
@@ -88,37 +88,28 @@ static void nf_conntrack_tstamp_fini_sysctl(struct net *net) | |||
88 | } | 88 | } |
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | int nf_conntrack_tstamp_init(struct net *net) | 91 | int nf_conntrack_tstamp_pernet_init(struct net *net) |
92 | { | 92 | { |
93 | int ret; | ||
94 | |||
95 | net->ct.sysctl_tstamp = nf_ct_tstamp; | 93 | net->ct.sysctl_tstamp = nf_ct_tstamp; |
94 | return nf_conntrack_tstamp_init_sysctl(net); | ||
95 | } | ||
96 | 96 | ||
97 | if (net_eq(net, &init_net)) { | 97 | void nf_conntrack_tstamp_pernet_fini(struct net *net) |
98 | ret = nf_ct_extend_register(&tstamp_extend); | 98 | { |
99 | if (ret < 0) { | 99 | nf_conntrack_tstamp_fini_sysctl(net); |
100 | printk(KERN_ERR "nf_ct_tstamp: Unable to register " | 100 | nf_ct_extend_unregister(&tstamp_extend); |
101 | "extension\n"); | 101 | } |
102 | goto out_extend_register; | ||
103 | } | ||
104 | } | ||
105 | 102 | ||
106 | ret = nf_conntrack_tstamp_init_sysctl(net); | 103 | int nf_conntrack_tstamp_init(void) |
104 | { | ||
105 | int ret; | ||
106 | ret = nf_ct_extend_register(&tstamp_extend); | ||
107 | if (ret < 0) | 107 | if (ret < 0) |
108 | goto out_sysctl; | 108 | pr_err("nf_ct_tstamp: Unable to register extension\n"); |
109 | |||
110 | return 0; | ||
111 | |||
112 | out_sysctl: | ||
113 | if (net_eq(net, &init_net)) | ||
114 | nf_ct_extend_unregister(&tstamp_extend); | ||
115 | out_extend_register: | ||
116 | return ret; | 109 | return ret; |
117 | } | 110 | } |
118 | 111 | ||
119 | void nf_conntrack_tstamp_fini(struct net *net) | 112 | void nf_conntrack_tstamp_fini(void) |
120 | { | 113 | { |
121 | nf_conntrack_tstamp_fini_sysctl(net); | 114 | nf_ct_extend_unregister(&tstamp_extend); |
122 | if (net_eq(net, &init_net)) | ||
123 | nf_ct_extend_unregister(&tstamp_extend); | ||
124 | } | 115 | } |
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index 16303c752213..5951146e7688 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c | |||
@@ -95,6 +95,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, | |||
95 | enum ip_conntrack_info ctinfo; | 95 | enum ip_conntrack_info ctinfo; |
96 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 96 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
97 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 97 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
98 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
98 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; | 99 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
99 | unsigned int buflen; | 100 | unsigned int buflen; |
100 | union nf_inet_addr newaddr; | 101 | union nf_inet_addr newaddr; |
@@ -107,7 +108,8 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff, | |||
107 | } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) && | 108 | } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) && |
108 | ct->tuplehash[dir].tuple.dst.u.udp.port == port) { | 109 | ct->tuplehash[dir].tuple.dst.u.udp.port == port) { |
109 | newaddr = ct->tuplehash[!dir].tuple.src.u3; | 110 | newaddr = ct->tuplehash[!dir].tuple.src.u3; |
110 | newport = ct->tuplehash[!dir].tuple.src.u.udp.port; | 111 | newport = ct_sip_info->forced_dport ? : |
112 | ct->tuplehash[!dir].tuple.src.u.udp.port; | ||
111 | } else | 113 | } else |
112 | return 1; | 114 | return 1; |
113 | 115 | ||
@@ -144,6 +146,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, | |||
144 | enum ip_conntrack_info ctinfo; | 146 | enum ip_conntrack_info ctinfo; |
145 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 147 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
146 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 148 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
149 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
147 | unsigned int coff, matchoff, matchlen; | 150 | unsigned int coff, matchoff, matchlen; |
148 | enum sip_header_types hdr; | 151 | enum sip_header_types hdr; |
149 | union nf_inet_addr addr; | 152 | union nf_inet_addr addr; |
@@ -258,6 +261,21 @@ next: | |||
258 | !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) | 261 | !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) |
259 | return NF_DROP; | 262 | return NF_DROP; |
260 | 263 | ||
264 | /* Mangle destination port for Cisco phones, then fix up checksums */ | ||
265 | if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) { | ||
266 | struct udphdr *uh; | ||
267 | |||
268 | if (!skb_make_writable(skb, skb->len)) | ||
269 | return NF_DROP; | ||
270 | |||
271 | uh = (void *)skb->data + protoff; | ||
272 | uh->dest = ct_sip_info->forced_dport; | ||
273 | |||
274 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff, | ||
275 | 0, 0, NULL, 0)) | ||
276 | return NF_DROP; | ||
277 | } | ||
278 | |||
261 | return NF_ACCEPT; | 279 | return NF_ACCEPT; |
262 | } | 280 | } |
263 | 281 | ||
@@ -311,8 +329,10 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, | |||
311 | enum ip_conntrack_info ctinfo; | 329 | enum ip_conntrack_info ctinfo; |
312 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 330 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
313 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 331 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
332 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
314 | union nf_inet_addr newaddr; | 333 | union nf_inet_addr newaddr; |
315 | u_int16_t port; | 334 | u_int16_t port; |
335 | __be16 srcport; | ||
316 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; | 336 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
317 | unsigned int buflen; | 337 | unsigned int buflen; |
318 | 338 | ||
@@ -326,8 +346,9 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, | |||
326 | /* If the signalling port matches the connection's source port in the | 346 | /* If the signalling port matches the connection's source port in the |
327 | * original direction, try to use the destination port in the opposite | 347 | * original direction, try to use the destination port in the opposite |
328 | * direction. */ | 348 | * direction. */ |
329 | if (exp->tuple.dst.u.udp.port == | 349 | srcport = ct_sip_info->forced_dport ? : |
330 | ct->tuplehash[dir].tuple.src.u.udp.port) | 350 | ct->tuplehash[dir].tuple.src.u.udp.port; |
351 | if (exp->tuple.dst.u.udp.port == srcport) | ||
331 | port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); | 352 | port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); |
332 | else | 353 | else |
333 | port = ntohs(exp->tuple.dst.u.udp.port); | 354 | port = ntohs(exp->tuple.dst.u.udp.port); |
diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c new file mode 100644 index 000000000000..12d4da8e6c77 --- /dev/null +++ b/net/netfilter/xt_bpf.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* Xtables module to match packets using a BPF filter. | ||
2 | * Copyright 2013 Google Inc. | ||
3 | * Written by Willem de Bruijn <willemb@google.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/skbuff.h> | ||
12 | #include <linux/filter.h> | ||
13 | |||
14 | #include <linux/netfilter/xt_bpf.h> | ||
15 | #include <linux/netfilter/x_tables.h> | ||
16 | |||
17 | MODULE_AUTHOR("Willem de Bruijn <willemb@google.com>"); | ||
18 | MODULE_DESCRIPTION("Xtables: BPF filter match"); | ||
19 | MODULE_LICENSE("GPL"); | ||
20 | MODULE_ALIAS("ipt_bpf"); | ||
21 | MODULE_ALIAS("ip6t_bpf"); | ||
22 | |||
23 | static int bpf_mt_check(const struct xt_mtchk_param *par) | ||
24 | { | ||
25 | struct xt_bpf_info *info = par->matchinfo; | ||
26 | struct sock_fprog program; | ||
27 | |||
28 | program.len = info->bpf_program_num_elem; | ||
29 | program.filter = (struct sock_filter __user *) info->bpf_program; | ||
30 | if (sk_unattached_filter_create(&info->filter, &program)) { | ||
31 | pr_info("bpf: check failed: parse error\n"); | ||
32 | return -EINVAL; | ||
33 | } | ||
34 | |||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
39 | { | ||
40 | const struct xt_bpf_info *info = par->matchinfo; | ||
41 | |||
42 | return SK_RUN_FILTER(info->filter, skb); | ||
43 | } | ||
44 | |||
45 | static void bpf_mt_destroy(const struct xt_mtdtor_param *par) | ||
46 | { | ||
47 | const struct xt_bpf_info *info = par->matchinfo; | ||
48 | sk_unattached_filter_destroy(info->filter); | ||
49 | } | ||
50 | |||
51 | static struct xt_match bpf_mt_reg __read_mostly = { | ||
52 | .name = "bpf", | ||
53 | .revision = 0, | ||
54 | .family = NFPROTO_UNSPEC, | ||
55 | .checkentry = bpf_mt_check, | ||
56 | .match = bpf_mt, | ||
57 | .destroy = bpf_mt_destroy, | ||
58 | .matchsize = sizeof(struct xt_bpf_info), | ||
59 | .me = THIS_MODULE, | ||
60 | }; | ||
61 | |||
62 | static int __init bpf_mt_init(void) | ||
63 | { | ||
64 | return xt_register_match(&bpf_mt_reg); | ||
65 | } | ||
66 | |||
67 | static void __exit bpf_mt_exit(void) | ||
68 | { | ||
69 | xt_unregister_match(&bpf_mt_reg); | ||
70 | } | ||
71 | |||
72 | module_init(bpf_mt_init); | ||
73 | module_exit(bpf_mt_exit); | ||
diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c new file mode 100644 index 000000000000..9f8719df2001 --- /dev/null +++ b/net/netfilter/xt_connlabel.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * (C) 2013 Astaro GmbH & Co KG | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/skbuff.h> | ||
11 | #include <net/netfilter/nf_conntrack.h> | ||
12 | #include <net/netfilter/nf_conntrack_labels.h> | ||
13 | #include <linux/netfilter/x_tables.h> | ||
14 | |||
15 | MODULE_LICENSE("GPL"); | ||
16 | MODULE_AUTHOR("Florian Westphal <fw@strlen.de>"); | ||
17 | MODULE_DESCRIPTION("Xtables: add/match connection trackling labels"); | ||
18 | MODULE_ALIAS("ipt_connlabel"); | ||
19 | MODULE_ALIAS("ip6t_connlabel"); | ||
20 | |||
21 | static bool | ||
22 | connlabel_mt(const struct sk_buff *skb, struct xt_action_param *par) | ||
23 | { | ||
24 | const struct xt_connlabel_mtinfo *info = par->matchinfo; | ||
25 | enum ip_conntrack_info ctinfo; | ||
26 | struct nf_conn *ct; | ||
27 | bool invert = info->options & XT_CONNLABEL_OP_INVERT; | ||
28 | |||
29 | ct = nf_ct_get(skb, &ctinfo); | ||
30 | if (ct == NULL || nf_ct_is_untracked(ct)) | ||
31 | return invert; | ||
32 | |||
33 | if (info->options & XT_CONNLABEL_OP_SET) | ||
34 | return (nf_connlabel_set(ct, info->bit) == 0) ^ invert; | ||
35 | |||
36 | return nf_connlabel_match(ct, info->bit) ^ invert; | ||
37 | } | ||
38 | |||
39 | static int connlabel_mt_check(const struct xt_mtchk_param *par) | ||
40 | { | ||
41 | const int options = XT_CONNLABEL_OP_INVERT | | ||
42 | XT_CONNLABEL_OP_SET; | ||
43 | struct xt_connlabel_mtinfo *info = par->matchinfo; | ||
44 | int ret; | ||
45 | size_t words; | ||
46 | |||
47 | if (info->bit > XT_CONNLABEL_MAXBIT) | ||
48 | return -ERANGE; | ||
49 | |||
50 | if (info->options & ~options) { | ||
51 | pr_err("Unknown options in mask %x\n", info->options); | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | ret = nf_ct_l3proto_try_module_get(par->family); | ||
56 | if (ret < 0) { | ||
57 | pr_info("cannot load conntrack support for proto=%u\n", | ||
58 | par->family); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | par->net->ct.labels_used++; | ||
63 | words = BITS_TO_LONGS(info->bit+1); | ||
64 | if (words > par->net->ct.label_words) | ||
65 | par->net->ct.label_words = words; | ||
66 | |||
67 | return ret; | ||
68 | } | ||
69 | |||
70 | static void connlabel_mt_destroy(const struct xt_mtdtor_param *par) | ||
71 | { | ||
72 | par->net->ct.labels_used--; | ||
73 | if (par->net->ct.labels_used == 0) | ||
74 | par->net->ct.label_words = 0; | ||
75 | nf_ct_l3proto_module_put(par->family); | ||
76 | } | ||
77 | |||
78 | static struct xt_match connlabels_mt_reg __read_mostly = { | ||
79 | .name = "connlabel", | ||
80 | .family = NFPROTO_UNSPEC, | ||
81 | .checkentry = connlabel_mt_check, | ||
82 | .match = connlabel_mt, | ||
83 | .matchsize = sizeof(struct xt_connlabel_mtinfo), | ||
84 | .destroy = connlabel_mt_destroy, | ||
85 | .me = THIS_MODULE, | ||
86 | }; | ||
87 | |||
88 | static int __init connlabel_mt_init(void) | ||
89 | { | ||
90 | return xt_register_match(&connlabels_mt_reg); | ||
91 | } | ||
92 | |||
93 | static void __exit connlabel_mt_exit(void) | ||
94 | { | ||
95 | xt_unregister_match(&connlabels_mt_reg); | ||
96 | } | ||
97 | |||
98 | module_init(connlabel_mt_init); | ||
99 | module_exit(connlabel_mt_exit); | ||