Blame view

net/netfilter/nfnetlink.c 7.3 KB
f9e815b37   Harald Welte   [NETFITLER]: Add ...
1
2
3
4
5
  /* Netfilter messages via netlink socket. Allows for user space
   * protocol helpers and general trouble making from userspace.
   *
   * (C) 2001 by Jay Schulist <jschlst@samba.org>,
   * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
67ca39660   Pablo Neira Ayuso   [NETFILTER]: nfne...
6
   * (C) 2005,2007 by Pablo Neira Ayuso <pablo@netfilter.org>
f9e815b37   Harald Welte   [NETFITLER]: Add ...
7
8
9
10
11
12
13
14
15
   *
   * Initial netfilter messages via netlink development funded and
   * generally made possible by Network Robots, Inc. (www.networkrobots.com)
   *
   * Further development of this code funded by Astaro AG (http://www.astaro.com)
   *
   * This software may be used and distributed according to the terms
   * of the GNU General Public License, incorporated herein by reference.
   */
f9e815b37   Harald Welte   [NETFITLER]: Add ...
16
17
18
19
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/kernel.h>
f9e815b37   Harald Welte   [NETFITLER]: Add ...
20
21
22
  #include <linux/string.h>
  #include <linux/sockios.h>
  #include <linux/net.h>
f9e815b37   Harald Welte   [NETFITLER]: Add ...
23
24
  #include <linux/skbuff.h>
  #include <asm/uaccess.h>
f9e815b37   Harald Welte   [NETFITLER]: Add ...
25
26
  #include <net/sock.h>
  #include <linux/init.h>
f9e815b37   Harald Welte   [NETFITLER]: Add ...
27

573ce260b   Hong zhi guo   net-next: replace...
28
  #include <net/netlink.h>
f9e815b37   Harald Welte   [NETFITLER]: Add ...
29
30
31
  #include <linux/netfilter/nfnetlink.h>
  
  MODULE_LICENSE("GPL");
4fdb3bb72   Harald Welte   [NETLINK]: Add pr...
32
33
  MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
  MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
34
35
  
  static char __initdata nfversion[] = "0.30";
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
36
37
38
39
  static struct {
  	struct mutex				mutex;
  	const struct nfnetlink_subsystem __rcu	*subsys;
  } table[NFNL_SUBSYS_COUNT];
f9e815b37   Harald Welte   [NETFITLER]: Add ...
40

03292745b   Pablo Neira Ayuso   netlink: add nlk-...
41
42
43
44
45
46
47
48
  static const int nfnl_group2type[NFNLGRP_MAX+1] = {
  	[NFNLGRP_CONNTRACK_NEW]		= NFNL_SUBSYS_CTNETLINK,
  	[NFNLGRP_CONNTRACK_UPDATE]	= NFNL_SUBSYS_CTNETLINK,
  	[NFNLGRP_CONNTRACK_DESTROY]	= NFNL_SUBSYS_CTNETLINK,
  	[NFNLGRP_CONNTRACK_EXP_NEW]	= NFNL_SUBSYS_CTNETLINK_EXP,
  	[NFNLGRP_CONNTRACK_EXP_UPDATE]	= NFNL_SUBSYS_CTNETLINK_EXP,
  	[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
  };
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
49
  void nfnl_lock(__u8 subsys_id)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
50
  {
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
51
  	mutex_lock(&table[subsys_id].mutex);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
52
  }
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
53
  EXPORT_SYMBOL_GPL(nfnl_lock);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
54

c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
55
  void nfnl_unlock(__u8 subsys_id)
a3c5029cf   Patrick McHardy   [NETFILTER]: nfne...
56
  {
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
57
  	mutex_unlock(&table[subsys_id].mutex);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
58
  }
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
59
  EXPORT_SYMBOL_GPL(nfnl_unlock);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
60

7c8d4cb41   Patrick McHardy   [NETFILTER]: nfne...
61
  int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
62
  {
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
63
64
65
  	nfnl_lock(n->subsys_id);
  	if (table[n->subsys_id].subsys) {
  		nfnl_unlock(n->subsys_id);
0ab43f849   Harald Welte   [NETFILTER]: Core...
66
67
  		return -EBUSY;
  	}
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
68
69
  	rcu_assign_pointer(table[n->subsys_id].subsys, n);
  	nfnl_unlock(n->subsys_id);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
70
71
72
  
  	return 0;
  }
f4bc177f0   Pablo Neira Ayuso   [NETFILTER]: nfne...
73
  EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
74

7c8d4cb41   Patrick McHardy   [NETFILTER]: nfne...
75
  int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
76
  {
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
77
78
79
  	nfnl_lock(n->subsys_id);
  	table[n->subsys_id].subsys = NULL;
  	nfnl_unlock(n->subsys_id);
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
80
  	synchronize_rcu();
f9e815b37   Harald Welte   [NETFITLER]: Add ...
81
82
  	return 0;
  }
f4bc177f0   Pablo Neira Ayuso   [NETFILTER]: nfne...
83
  EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
84

7c8d4cb41   Patrick McHardy   [NETFILTER]: nfne...
85
  static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
86
87
  {
  	u_int8_t subsys_id = NFNL_SUBSYS_ID(type);
ac0f1d989   Pablo Neira Ayuso   [NETFILTER]: nfne...
88
  	if (subsys_id >= NFNL_SUBSYS_COUNT)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
89
  		return NULL;
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
90
  	return rcu_dereference(table[subsys_id].subsys);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
91
  }
7c8d4cb41   Patrick McHardy   [NETFILTER]: nfne...
92
93
  static inline const struct nfnl_callback *
  nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
94
95
  {
  	u_int8_t cb_id = NFNL_MSG_TYPE(type);
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
96

67ca39660   Pablo Neira Ayuso   [NETFILTER]: nfne...
97
  	if (cb_id >= ss->cb_count)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
98
  		return NULL;
f9e815b37   Harald Welte   [NETFITLER]: Add ...
99
100
101
  
  	return &ss->cb[cb_id];
  }
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
102
  int nfnetlink_has_listeners(struct net *net, unsigned int group)
a24276924   Patrick McHardy   [NETFILTER]: ctne...
103
  {
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
104
  	return netlink_has_listeners(net->nfnl, group);
a24276924   Patrick McHardy   [NETFILTER]: ctne...
105
106
  }
  EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
3ab1f683b   Patrick McHardy   nfnetlink: add su...
107
108
109
110
111
112
  struct sk_buff *nfnetlink_alloc_skb(struct net *net, unsigned int size,
  				    u32 dst_portid, gfp_t gfp_mask)
  {
  	return netlink_alloc_skb(net->nfnl, size, dst_portid, gfp_mask);
  }
  EXPORT_SYMBOL_GPL(nfnetlink_alloc_skb);
ec464e5dc   Patrick McHardy   netfilter: rename...
113
  int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
95c961747   Eric Dumazet   net: cleanup unsi...
114
  		   unsigned int group, int echo, gfp_t flags)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
115
  {
ec464e5dc   Patrick McHardy   netfilter: rename...
116
  	return nlmsg_notify(net->nfnl, skb, portid, group, echo, flags);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
117
  }
f4bc177f0   Pablo Neira Ayuso   [NETFILTER]: nfne...
118
  EXPORT_SYMBOL_GPL(nfnetlink_send);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
119

ec464e5dc   Patrick McHardy   netfilter: rename...
120
  int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
dd5b6ce6f   Pablo Neira Ayuso   nefilter: nfnetli...
121
  {
ec464e5dc   Patrick McHardy   netfilter: rename...
122
  	return netlink_set_err(net->nfnl, portid, group, error);
dd5b6ce6f   Pablo Neira Ayuso   nefilter: nfnetli...
123
124
  }
  EXPORT_SYMBOL_GPL(nfnetlink_set_err);
ec464e5dc   Patrick McHardy   netfilter: rename...
125
126
  int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
  		      int flags)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
127
  {
ec464e5dc   Patrick McHardy   netfilter: rename...
128
  	return netlink_unicast(net->nfnl, skb, portid, flags);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
129
  }
f4bc177f0   Pablo Neira Ayuso   [NETFILTER]: nfne...
130
  EXPORT_SYMBOL_GPL(nfnetlink_unicast);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
131
132
  
  /* Process one complete nfnetlink message. */
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
133
  static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
134
  {
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
135
  	struct net *net = sock_net(skb->sk);
7c8d4cb41   Patrick McHardy   [NETFILTER]: nfne...
136
137
  	const struct nfnl_callback *nc;
  	const struct nfnetlink_subsystem *ss;
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
138
  	int type, err;
f9e815b37   Harald Welte   [NETFITLER]: Add ...
139

df008c91f   Eric W. Biederman   net: Allow userns...
140
  	if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
141
  		return -EPERM;
37d2e7a20   Harald Welte   [NETFILTER] nfnet...
142

f9e815b37   Harald Welte   [NETFITLER]: Add ...
143
  	/* All the messages must at least contain nfgenmsg */
573ce260b   Hong zhi guo   net-next: replace...
144
  	if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
f9e815b37   Harald Welte   [NETFITLER]: Add ...
145
  		return 0;
f9e815b37   Harald Welte   [NETFITLER]: Add ...
146
147
  
  	type = nlh->nlmsg_type;
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
148
  replay:
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
149
  	rcu_read_lock();
f9e815b37   Harald Welte   [NETFITLER]: Add ...
150
  	ss = nfnetlink_get_subsys(type);
0ab43f849   Harald Welte   [NETFILTER]: Core...
151
  	if (!ss) {
95a5afca4   Johannes Berg   net: Remove CONFI...
152
  #ifdef CONFIG_MODULES
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
153
  		rcu_read_unlock();
37d2e7a20   Harald Welte   [NETFILTER] nfnet...
154
  		request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
155
  		rcu_read_lock();
37d2e7a20   Harald Welte   [NETFILTER] nfnet...
156
  		ss = nfnetlink_get_subsys(type);
0ab43f849   Harald Welte   [NETFILTER]: Core...
157
158
  		if (!ss)
  #endif
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
159
160
  		{
  			rcu_read_unlock();
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
161
  			return -EINVAL;
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
162
  		}
0ab43f849   Harald Welte   [NETFILTER]: Core...
163
  	}
f9e815b37   Harald Welte   [NETFITLER]: Add ...
164
165
  
  	nc = nfnetlink_find_client(type, ss);
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
166
167
  	if (!nc) {
  		rcu_read_unlock();
1d00a4eb4   Thomas Graf   [NETLINK]: Remove...
168
  		return -EINVAL;
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
169
  	}
f9e815b37   Harald Welte   [NETFITLER]: Add ...
170

f9e815b37   Harald Welte   [NETFITLER]: Add ...
171
  	{
573ce260b   Hong zhi guo   net-next: replace...
172
  		int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
e37305782   Patrick McHardy   [NETFILTER]: nfne...
173
  		u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
f49c857ff   Pablo Neira Ayuso   netfilter: nfnetl...
174
175
176
  		struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
  		struct nlattr *attr = (void *)nlh + min_len;
  		int attrlen = nlh->nlmsg_len - min_len;
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
177
  		__u8 subsys_id = NFNL_SUBSYS_ID(type);
f49c857ff   Pablo Neira Ayuso   netfilter: nfnetl...
178
179
180
  
  		err = nla_parse(cda, ss->cb[cb_id].attr_count,
  				attr, attrlen, ss->cb[cb_id].policy);
4009e1885   Tomasz Bursztyka   netfilter: nfnetl...
181
182
  		if (err < 0) {
  			rcu_read_unlock();
f49c857ff   Pablo Neira Ayuso   netfilter: nfnetl...
183
  			return err;
4009e1885   Tomasz Bursztyka   netfilter: nfnetl...
184
  		}
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
185

6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
186
187
188
189
190
191
  		if (nc->call_rcu) {
  			err = nc->call_rcu(net->nfnl, skb, nlh,
  					   (const struct nlattr **)cda);
  			rcu_read_unlock();
  		} else {
  			rcu_read_unlock();
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
192
193
  			nfnl_lock(subsys_id);
  			if (rcu_dereference_protected(table[subsys_id].subsys,
9df9e7832   Paul Bolle   netfilter: nfnetl...
194
  				lockdep_is_held(&table[subsys_id].mutex)) != ss ||
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
195
196
  			    nfnetlink_find_client(type, ss) != nc)
  				err = -EAGAIN;
59560a38a   Tomasz Bursztyka   netfilter: nfnetl...
197
  			else if (nc->call)
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
198
199
  				err = nc->call(net->nfnl, skb, nlh,
  						   (const struct nlattr **)cda);
59560a38a   Tomasz Bursztyka   netfilter: nfnetl...
200
201
  			else
  				err = -EINVAL;
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
202
  			nfnl_unlock(subsys_id);
6b75e3e8d   Eric Dumazet   netfilter: nfnetl...
203
  		}
e6a7d3c04   Pablo Neira Ayuso   netfilter: ctnetl...
204
205
206
  		if (err == -EAGAIN)
  			goto replay;
  		return err;
f9e815b37   Harald Welte   [NETFITLER]: Add ...
207
  	}
f9e815b37   Harald Welte   [NETFITLER]: Add ...
208
  }
cd40b7d39   Denis V. Lunev   [NET]: make netli...
209
  static void nfnetlink_rcv(struct sk_buff *skb)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
210
  {
cd40b7d39   Denis V. Lunev   [NET]: make netli...
211
  	netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
212
  }
03292745b   Pablo Neira Ayuso   netlink: add nlk-...
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  #ifdef CONFIG_MODULES
  static void nfnetlink_bind(int group)
  {
  	const struct nfnetlink_subsystem *ss;
  	int type = nfnl_group2type[group];
  
  	rcu_read_lock();
  	ss = nfnetlink_get_subsys(type);
  	if (!ss) {
  		rcu_read_unlock();
  		request_module("nfnetlink-subsys-%d", type);
  		return;
  	}
  	rcu_read_unlock();
  }
  #endif
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
229
  static int __net_init nfnetlink_net_init(struct net *net)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
230
  {
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
231
  	struct sock *nfnl;
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
232
233
234
  	struct netlink_kernel_cfg cfg = {
  		.groups	= NFNLGRP_MAX,
  		.input	= nfnetlink_rcv,
03292745b   Pablo Neira Ayuso   netlink: add nlk-...
235
236
237
  #ifdef CONFIG_MODULES
  		.bind	= nfnetlink_bind,
  #endif
a31f2d17b   Pablo Neira Ayuso   netlink: add netl...
238
  	};
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
239

9f00d9776   Pablo Neira Ayuso   netlink: hide str...
240
  	nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, &cfg);
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
241
242
243
  	if (!nfnl)
  		return -ENOMEM;
  	net->nfnl_stash = nfnl;
cf778b00e   Eric Dumazet   net: reintroduce ...
244
  	rcu_assign_pointer(net->nfnl, nfnl);
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
245
  	return 0;
f9e815b37   Harald Welte   [NETFITLER]: Add ...
246
  }
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
247
  static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
f9e815b37   Harald Welte   [NETFITLER]: Add ...
248
  {
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
249
  	struct net *net;
f9e815b37   Harald Welte   [NETFITLER]: Add ...
250

cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
251
  	list_for_each_entry(net, net_exit_list, exit_list)
a9b3cd7f3   Stephen Hemminger   rcu: convert uses...
252
  		RCU_INIT_POINTER(net->nfnl, NULL);
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
253
254
255
256
  	synchronize_net();
  	list_for_each_entry(net, net_exit_list, exit_list)
  		netlink_kernel_release(net->nfnl_stash);
  }
f9e815b37   Harald Welte   [NETFITLER]: Add ...
257

cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
258
259
260
261
262
263
264
  static struct pernet_operations nfnetlink_net_ops = {
  	.init		= nfnetlink_net_init,
  	.exit_batch	= nfnetlink_net_exit_batch,
  };
  
  static int __init nfnetlink_init(void)
  {
c14b78e7d   Pablo Neira Ayuso   netfilter: nfnetl...
265
266
267
268
  	int i;
  
  	for (i=0; i<NFNL_SUBSYS_COUNT; i++)
  		mutex_init(&table[i].mutex);
654d0fbdc   Stephen Hemminger   netfilter: cleanu...
269
270
  	pr_info("Netfilter messages via NETLINK v%s.
  ", nfversion);
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
271
  	return register_pernet_subsys(&nfnetlink_net_ops);
f9e815b37   Harald Welte   [NETFITLER]: Add ...
272
  }
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
273
274
  static void __exit nfnetlink_exit(void)
  {
654d0fbdc   Stephen Hemminger   netfilter: cleanu...
275
276
  	pr_info("Removing netfilter NETLINK layer.
  ");
cd8c20b65   Alexey Dobriyan   netfilter: nfnetl...
277
278
  	unregister_pernet_subsys(&nfnetlink_net_ops);
  }
f9e815b37   Harald Welte   [NETFITLER]: Add ...
279
280
  module_init(nfnetlink_init);
  module_exit(nfnetlink_exit);