Blame view
net/netfilter/nfnetlink.c
13.2 KB
f9e815b37 [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 [NETFILTER]: nfne... |
6 |
* (C) 2005,2007 by Pablo Neira Ayuso <pablo@netfilter.org> |
f9e815b37 [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 [NETFITLER]: Add ... |
16 17 18 19 |
#include <linux/module.h> #include <linux/types.h> #include <linux/socket.h> #include <linux/kernel.h> |
f9e815b37 [NETFITLER]: Add ... |
20 21 22 |
#include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> |
f9e815b37 [NETFITLER]: Add ... |
23 24 |
#include <linux/skbuff.h> #include <asm/uaccess.h> |
f9e815b37 [NETFITLER]: Add ... |
25 26 |
#include <net/sock.h> #include <linux/init.h> |
f9e815b37 [NETFITLER]: Add ... |
27 |
|
573ce260b net-next: replace... |
28 |
#include <net/netlink.h> |
f9e815b37 [NETFITLER]: Add ... |
29 30 31 |
#include <linux/netfilter/nfnetlink.h> MODULE_LICENSE("GPL"); |
4fdb3bb72 [NETLINK]: Add pr... |
32 33 |
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); |
f9e815b37 [NETFITLER]: Add ... |
34 |
|
9c55d3b54 nfnetlink: add nf... |
35 36 37 |
#define nfnl_dereference_protected(id) \ rcu_dereference_protected(table[(id)].subsys, \ lockdep_nfnl_is_held((id))) |
f9e815b37 [NETFITLER]: Add ... |
38 |
static char __initdata nfversion[] = "0.30"; |
c14b78e7d netfilter: nfnetl... |
39 40 41 42 |
static struct { struct mutex mutex; const struct nfnetlink_subsystem __rcu *subsys; } table[NFNL_SUBSYS_COUNT]; |
f9e815b37 [NETFITLER]: Add ... |
43 |
|
03292745b netlink: add nlk-... |
44 45 46 47 48 49 50 |
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, |
97840cb67 netfilter: nfnetl... |
51 52 |
[NFNLGRP_NFTABLES] = NFNL_SUBSYS_NFTABLES, [NFNLGRP_ACCT_QUOTA] = NFNL_SUBSYS_ACCT, |
33d5a7b14 netfilter: nf_tab... |
53 |
[NFNLGRP_NFTRACE] = NFNL_SUBSYS_NFTABLES, |
03292745b netlink: add nlk-... |
54 |
}; |
c14b78e7d netfilter: nfnetl... |
55 |
void nfnl_lock(__u8 subsys_id) |
f9e815b37 [NETFITLER]: Add ... |
56 |
{ |
c14b78e7d netfilter: nfnetl... |
57 |
mutex_lock(&table[subsys_id].mutex); |
f9e815b37 [NETFITLER]: Add ... |
58 |
} |
e6a7d3c04 netfilter: ctnetl... |
59 |
EXPORT_SYMBOL_GPL(nfnl_lock); |
f9e815b37 [NETFITLER]: Add ... |
60 |
|
c14b78e7d netfilter: nfnetl... |
61 |
void nfnl_unlock(__u8 subsys_id) |
a3c5029cf [NETFILTER]: nfne... |
62 |
{ |
c14b78e7d netfilter: nfnetl... |
63 |
mutex_unlock(&table[subsys_id].mutex); |
f9e815b37 [NETFITLER]: Add ... |
64 |
} |
e6a7d3c04 netfilter: ctnetl... |
65 |
EXPORT_SYMBOL_GPL(nfnl_unlock); |
f9e815b37 [NETFITLER]: Add ... |
66 |
|
0eb5db7ad netfilter: nfnetl... |
67 |
#ifdef CONFIG_PROVE_LOCKING |
875e08294 net/nfnetlink: lo... |
68 |
bool lockdep_nfnl_is_held(u8 subsys_id) |
0eb5db7ad netfilter: nfnetl... |
69 70 71 72 73 |
{ return lockdep_is_held(&table[subsys_id].mutex); } EXPORT_SYMBOL_GPL(lockdep_nfnl_is_held); #endif |
7c8d4cb41 [NETFILTER]: nfne... |
74 |
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) |
f9e815b37 [NETFITLER]: Add ... |
75 |
{ |
c14b78e7d netfilter: nfnetl... |
76 77 78 |
nfnl_lock(n->subsys_id); if (table[n->subsys_id].subsys) { nfnl_unlock(n->subsys_id); |
0ab43f849 [NETFILTER]: Core... |
79 80 |
return -EBUSY; } |
c14b78e7d netfilter: nfnetl... |
81 82 |
rcu_assign_pointer(table[n->subsys_id].subsys, n); nfnl_unlock(n->subsys_id); |
f9e815b37 [NETFITLER]: Add ... |
83 84 85 |
return 0; } |
f4bc177f0 [NETFILTER]: nfne... |
86 |
EXPORT_SYMBOL_GPL(nfnetlink_subsys_register); |
f9e815b37 [NETFITLER]: Add ... |
87 |
|
7c8d4cb41 [NETFILTER]: nfne... |
88 |
int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n) |
f9e815b37 [NETFITLER]: Add ... |
89 |
{ |
c14b78e7d netfilter: nfnetl... |
90 91 92 |
nfnl_lock(n->subsys_id); table[n->subsys_id].subsys = NULL; nfnl_unlock(n->subsys_id); |
6b75e3e8d netfilter: nfnetl... |
93 |
synchronize_rcu(); |
f9e815b37 [NETFITLER]: Add ... |
94 95 |
return 0; } |
f4bc177f0 [NETFILTER]: nfne... |
96 |
EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); |
f9e815b37 [NETFITLER]: Add ... |
97 |
|
7c8d4cb41 [NETFILTER]: nfne... |
98 |
static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type) |
f9e815b37 [NETFITLER]: Add ... |
99 100 |
{ u_int8_t subsys_id = NFNL_SUBSYS_ID(type); |
ac0f1d989 [NETFILTER]: nfne... |
101 |
if (subsys_id >= NFNL_SUBSYS_COUNT) |
f9e815b37 [NETFITLER]: Add ... |
102 |
return NULL; |
c14b78e7d netfilter: nfnetl... |
103 |
return rcu_dereference(table[subsys_id].subsys); |
f9e815b37 [NETFITLER]: Add ... |
104 |
} |
7c8d4cb41 [NETFILTER]: nfne... |
105 106 |
static inline const struct nfnl_callback * nfnetlink_find_client(u_int16_t type, const struct nfnetlink_subsystem *ss) |
f9e815b37 [NETFITLER]: Add ... |
107 108 |
{ u_int8_t cb_id = NFNL_MSG_TYPE(type); |
601e68e10 [NETFILTER]: Fix ... |
109 |
|
67ca39660 [NETFILTER]: nfne... |
110 |
if (cb_id >= ss->cb_count) |
f9e815b37 [NETFITLER]: Add ... |
111 |
return NULL; |
f9e815b37 [NETFITLER]: Add ... |
112 113 114 |
return &ss->cb[cb_id]; } |
cd8c20b65 netfilter: nfnetl... |
115 |
int nfnetlink_has_listeners(struct net *net, unsigned int group) |
a24276924 [NETFILTER]: ctne... |
116 |
{ |
cd8c20b65 netfilter: nfnetl... |
117 |
return netlink_has_listeners(net->nfnl, group); |
a24276924 [NETFILTER]: ctne... |
118 119 |
} EXPORT_SYMBOL_GPL(nfnetlink_has_listeners); |
ec464e5dc netfilter: rename... |
120 |
int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid, |
95c961747 net: cleanup unsi... |
121 |
unsigned int group, int echo, gfp_t flags) |
f9e815b37 [NETFITLER]: Add ... |
122 |
{ |
ec464e5dc netfilter: rename... |
123 |
return nlmsg_notify(net->nfnl, skb, portid, group, echo, flags); |
f9e815b37 [NETFITLER]: Add ... |
124 |
} |
f4bc177f0 [NETFILTER]: nfne... |
125 |
EXPORT_SYMBOL_GPL(nfnetlink_send); |
f9e815b37 [NETFITLER]: Add ... |
126 |
|
ec464e5dc netfilter: rename... |
127 |
int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error) |
dd5b6ce6f nefilter: nfnetli... |
128 |
{ |
ec464e5dc netfilter: rename... |
129 |
return netlink_set_err(net->nfnl, portid, group, error); |
dd5b6ce6f nefilter: nfnetli... |
130 131 |
} EXPORT_SYMBOL_GPL(nfnetlink_set_err); |
ec464e5dc netfilter: rename... |
132 133 |
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid, int flags) |
f9e815b37 [NETFITLER]: Add ... |
134 |
{ |
ec464e5dc netfilter: rename... |
135 |
return netlink_unicast(net->nfnl, skb, portid, flags); |
f9e815b37 [NETFITLER]: Add ... |
136 |
} |
f4bc177f0 [NETFILTER]: nfne... |
137 |
EXPORT_SYMBOL_GPL(nfnetlink_unicast); |
f9e815b37 [NETFITLER]: Add ... |
138 139 |
/* Process one complete nfnetlink message. */ |
1d00a4eb4 [NETLINK]: Remove... |
140 |
static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) |
f9e815b37 [NETFITLER]: Add ... |
141 |
{ |
cd8c20b65 netfilter: nfnetl... |
142 |
struct net *net = sock_net(skb->sk); |
7c8d4cb41 [NETFILTER]: nfne... |
143 144 |
const struct nfnl_callback *nc; const struct nfnetlink_subsystem *ss; |
1d00a4eb4 [NETLINK]: Remove... |
145 |
int type, err; |
f9e815b37 [NETFITLER]: Add ... |
146 |
|
f9e815b37 [NETFITLER]: Add ... |
147 |
/* All the messages must at least contain nfgenmsg */ |
573ce260b net-next: replace... |
148 |
if (nlmsg_len(nlh) < sizeof(struct nfgenmsg)) |
f9e815b37 [NETFITLER]: Add ... |
149 |
return 0; |
f9e815b37 [NETFITLER]: Add ... |
150 151 |
type = nlh->nlmsg_type; |
e6a7d3c04 netfilter: ctnetl... |
152 |
replay: |
6b75e3e8d netfilter: nfnetl... |
153 |
rcu_read_lock(); |
f9e815b37 [NETFITLER]: Add ... |
154 |
ss = nfnetlink_get_subsys(type); |
0ab43f849 [NETFILTER]: Core... |
155 |
if (!ss) { |
95a5afca4 net: Remove CONFI... |
156 |
#ifdef CONFIG_MODULES |
6b75e3e8d netfilter: nfnetl... |
157 |
rcu_read_unlock(); |
37d2e7a20 [NETFILTER] nfnet... |
158 |
request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); |
6b75e3e8d netfilter: nfnetl... |
159 |
rcu_read_lock(); |
37d2e7a20 [NETFILTER] nfnet... |
160 |
ss = nfnetlink_get_subsys(type); |
0ab43f849 [NETFILTER]: Core... |
161 162 |
if (!ss) #endif |
6b75e3e8d netfilter: nfnetl... |
163 164 |
{ rcu_read_unlock(); |
1d00a4eb4 [NETLINK]: Remove... |
165 |
return -EINVAL; |
6b75e3e8d netfilter: nfnetl... |
166 |
} |
0ab43f849 [NETFILTER]: Core... |
167 |
} |
f9e815b37 [NETFITLER]: Add ... |
168 169 |
nc = nfnetlink_find_client(type, ss); |
6b75e3e8d netfilter: nfnetl... |
170 171 |
if (!nc) { rcu_read_unlock(); |
1d00a4eb4 [NETLINK]: Remove... |
172 |
return -EINVAL; |
6b75e3e8d netfilter: nfnetl... |
173 |
} |
f9e815b37 [NETFITLER]: Add ... |
174 |
|
f9e815b37 [NETFITLER]: Add ... |
175 |
{ |
573ce260b net-next: replace... |
176 |
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); |
e37305782 [NETFILTER]: nfne... |
177 |
u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); |
f49c857ff netfilter: nfnetl... |
178 179 180 |
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 netfilter: nfnetl... |
181 |
__u8 subsys_id = NFNL_SUBSYS_ID(type); |
f49c857ff netfilter: nfnetl... |
182 183 184 |
err = nla_parse(cda, ss->cb[cb_id].attr_count, attr, attrlen, ss->cb[cb_id].policy); |
4009e1885 netfilter: nfnetl... |
185 186 |
if (err < 0) { rcu_read_unlock(); |
f49c857ff netfilter: nfnetl... |
187 |
return err; |
4009e1885 netfilter: nfnetl... |
188 |
} |
601e68e10 [NETFILTER]: Fix ... |
189 |
|
6b75e3e8d netfilter: nfnetl... |
190 |
if (nc->call_rcu) { |
7b8002a15 netfilter: nfnetl... |
191 |
err = nc->call_rcu(net, net->nfnl, skb, nlh, |
6b75e3e8d netfilter: nfnetl... |
192 193 194 195 |
(const struct nlattr **)cda); rcu_read_unlock(); } else { rcu_read_unlock(); |
c14b78e7d netfilter: nfnetl... |
196 |
nfnl_lock(subsys_id); |
9c55d3b54 nfnetlink: add nf... |
197 |
if (nfnl_dereference_protected(subsys_id) != ss || |
6b75e3e8d netfilter: nfnetl... |
198 199 |
nfnetlink_find_client(type, ss) != nc) err = -EAGAIN; |
59560a38a netfilter: nfnetl... |
200 |
else if (nc->call) |
7b8002a15 netfilter: nfnetl... |
201 202 |
err = nc->call(net, net->nfnl, skb, nlh, (const struct nlattr **)cda); |
59560a38a netfilter: nfnetl... |
203 204 |
else err = -EINVAL; |
c14b78e7d netfilter: nfnetl... |
205 |
nfnl_unlock(subsys_id); |
6b75e3e8d netfilter: nfnetl... |
206 |
} |
e6a7d3c04 netfilter: ctnetl... |
207 208 209 |
if (err == -EAGAIN) goto replay; return err; |
f9e815b37 [NETFITLER]: Add ... |
210 |
} |
f9e815b37 [NETFITLER]: Add ... |
211 |
} |
cbb8125eb netfilter: nfnetl... |
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
struct nfnl_err { struct list_head head; struct nlmsghdr *nlh; int err; }; static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err) { struct nfnl_err *nfnl_err; nfnl_err = kmalloc(sizeof(struct nfnl_err), GFP_KERNEL); if (nfnl_err == NULL) return -ENOMEM; nfnl_err->nlh = nlh; nfnl_err->err = err; list_add_tail(&nfnl_err->head, list); return 0; } static void nfnl_err_del(struct nfnl_err *nfnl_err) { list_del(&nfnl_err->head); kfree(nfnl_err); } static void nfnl_err_reset(struct list_head *err_list) { struct nfnl_err *nfnl_err, *next; list_for_each_entry_safe(nfnl_err, next, err_list, head) nfnl_err_del(nfnl_err); } static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb) { struct nfnl_err *nfnl_err, *next; list_for_each_entry_safe(nfnl_err, next, err_list, head) { netlink_ack(skb, nfnl_err->nlh, nfnl_err->err); nfnl_err_del(nfnl_err); } } |
6742b9e31 netfilter: nfnetl... |
256 257 258 259 260 |
enum { NFNL_BATCH_FAILURE = (1 << 0), NFNL_BATCH_DONE = (1 << 1), NFNL_BATCH_REPLAY = (1 << 2), }; |
0628b123c netfilter: nfnetl... |
261 262 263 |
static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh, u_int16_t subsys_id) { |
0f8162326 netfilter: nfnetl... |
264 |
struct sk_buff *oskb = skb; |
0628b123c netfilter: nfnetl... |
265 266 267 |
struct net *net = sock_net(skb->sk); const struct nfnetlink_subsystem *ss; const struct nfnl_callback *nc; |
cbb8125eb netfilter: nfnetl... |
268 |
static LIST_HEAD(err_list); |
6742b9e31 netfilter: nfnetl... |
269 |
u32 status; |
0628b123c netfilter: nfnetl... |
270 271 272 273 274 |
int err; if (subsys_id >= NFNL_SUBSYS_COUNT) return netlink_ack(skb, nlh, -EINVAL); replay: |
6742b9e31 netfilter: nfnetl... |
275 |
status = 0; |
0f8162326 netfilter: nfnetl... |
276 277 |
skb = netlink_skb_clone(oskb, GFP_KERNEL); if (!skb) |
0628b123c netfilter: nfnetl... |
278 |
return netlink_ack(oskb, nlh, -ENOMEM); |
0628b123c netfilter: nfnetl... |
279 |
nfnl_lock(subsys_id); |
9c55d3b54 nfnetlink: add nf... |
280 |
ss = nfnl_dereference_protected(subsys_id); |
0628b123c netfilter: nfnetl... |
281 282 283 284 285 |
if (!ss) { #ifdef CONFIG_MODULES nfnl_unlock(subsys_id); request_module("nfnetlink-subsys-%d", subsys_id); nfnl_lock(subsys_id); |
9c55d3b54 nfnetlink: add nf... |
286 |
ss = nfnl_dereference_protected(subsys_id); |
0628b123c netfilter: nfnetl... |
287 288 289 290 |
if (!ss) #endif { nfnl_unlock(subsys_id); |
7c7bdf359 netfilter: nfnetl... |
291 |
netlink_ack(oskb, nlh, -EOPNOTSUPP); |
0f8162326 netfilter: nfnetl... |
292 |
return kfree_skb(skb); |
0628b123c netfilter: nfnetl... |
293 294 295 296 297 |
} } if (!ss->commit || !ss->abort) { nfnl_unlock(subsys_id); |
7c7bdf359 netfilter: nfnetl... |
298 |
netlink_ack(oskb, nlh, -EOPNOTSUPP); |
ecd15dd7e netfilter: nfnetl... |
299 |
return kfree_skb(skb); |
0628b123c netfilter: nfnetl... |
300 301 302 303 304 305 306 |
} while (skb->len >= nlmsg_total_size(0)) { int msglen, type; nlh = nlmsg_hdr(skb); err = 0; |
c58d6c936 netfilter: nfnetl... |
307 308 309 310 311 312 |
if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len || nlmsg_len(nlh) < sizeof(struct nfgenmsg)) { nfnl_err_reset(&err_list); status |= NFNL_BATCH_FAILURE; goto done; |
0628b123c netfilter: nfnetl... |
313 314 315 316 317 318 319 320 321 322 323 |
} /* Only requests are handled by the kernel */ if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { err = -EINVAL; goto ack; } type = nlh->nlmsg_type; if (type == NFNL_MSG_BATCH_BEGIN) { /* Malformed: Batch begin twice */ |
cbb8125eb netfilter: nfnetl... |
324 |
nfnl_err_reset(&err_list); |
6742b9e31 netfilter: nfnetl... |
325 |
status |= NFNL_BATCH_FAILURE; |
0628b123c netfilter: nfnetl... |
326 327 |
goto done; } else if (type == NFNL_MSG_BATCH_END) { |
6742b9e31 netfilter: nfnetl... |
328 |
status |= NFNL_BATCH_DONE; |
0628b123c netfilter: nfnetl... |
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
goto done; } else if (type < NLMSG_MIN_TYPE) { err = -EINVAL; goto ack; } /* We only accept a batch with messages for the same * subsystem. */ if (NFNL_SUBSYS_ID(type) != subsys_id) { err = -EINVAL; goto ack; } nc = nfnetlink_find_client(type, ss); if (!nc) { err = -EINVAL; goto ack; } { int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type); struct nlattr *cda[ss->cb[cb_id].attr_count + 1]; struct nlattr *attr = (void *)nlh + min_len; int attrlen = nlh->nlmsg_len - min_len; err = nla_parse(cda, ss->cb[cb_id].attr_count, attr, attrlen, ss->cb[cb_id].policy); if (err < 0) goto ack; if (nc->call_batch) { |
633c9a840 netfilter: nfnetl... |
362 |
err = nc->call_batch(net, net->nfnl, skb, nlh, |
0628b123c netfilter: nfnetl... |
363 364 365 366 367 368 369 370 |
(const struct nlattr **)cda); } /* The lock was released to autoload some module, we * have to abort and start from scratch using the * original skb. */ if (err == -EAGAIN) { |
6742b9e31 netfilter: nfnetl... |
371 372 |
status |= NFNL_BATCH_REPLAY; goto next; |
0628b123c netfilter: nfnetl... |
373 374 375 376 |
} } ack: if (nlh->nlmsg_flags & NLM_F_ACK || err) { |
cbb8125eb netfilter: nfnetl... |
377 378 379 380 381 382 383 384 385 386 |
/* Errors are delivered once the full batch has been * processed, this avoids that the same error is * reported several times when replaying the batch. */ if (nfnl_err_add(&err_list, nlh, err) < 0) { /* We failed to enqueue an error, reset the * list of errors and send OOM to userspace * pointing to the batch header. */ nfnl_err_reset(&err_list); |
7c7bdf359 netfilter: nfnetl... |
387 |
netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM); |
6742b9e31 netfilter: nfnetl... |
388 |
status |= NFNL_BATCH_FAILURE; |
cbb8125eb netfilter: nfnetl... |
389 390 |
goto done; } |
0628b123c netfilter: nfnetl... |
391 392 393 394 |
/* We don't stop processing the batch on errors, thus, * userspace gets all the errors that the batch * triggers. */ |
0628b123c netfilter: nfnetl... |
395 |
if (err) |
6742b9e31 netfilter: nfnetl... |
396 |
status |= NFNL_BATCH_FAILURE; |
0628b123c netfilter: nfnetl... |
397 |
} |
6742b9e31 netfilter: nfnetl... |
398 |
next: |
0628b123c netfilter: nfnetl... |
399 400 401 402 403 404 |
msglen = NLMSG_ALIGN(nlh->nlmsg_len); if (msglen > skb->len) msglen = skb->len; skb_pull(skb, msglen); } done: |
6742b9e31 netfilter: nfnetl... |
405 |
if (status & NFNL_BATCH_REPLAY) { |
5913beaf0 netfilter: nfnetl... |
406 |
ss->abort(net, oskb); |
6742b9e31 netfilter: nfnetl... |
407 408 409 410 411 |
nfnl_err_reset(&err_list); nfnl_unlock(subsys_id); kfree_skb(skb); goto replay; } else if (status == NFNL_BATCH_DONE) { |
5913beaf0 netfilter: nfnetl... |
412 |
ss->commit(net, oskb); |
6742b9e31 netfilter: nfnetl... |
413 |
} else { |
5913beaf0 netfilter: nfnetl... |
414 |
ss->abort(net, oskb); |
6742b9e31 netfilter: nfnetl... |
415 |
} |
0628b123c netfilter: nfnetl... |
416 |
|
cbb8125eb netfilter: nfnetl... |
417 |
nfnl_err_deliver(&err_list, oskb); |
0628b123c netfilter: nfnetl... |
418 |
nfnl_unlock(subsys_id); |
0f8162326 netfilter: nfnetl... |
419 |
kfree_skb(skb); |
0628b123c netfilter: nfnetl... |
420 |
} |
cd40b7d39 [NET]: make netli... |
421 |
static void nfnetlink_rcv(struct sk_buff *skb) |
f9e815b37 [NETFITLER]: Add ... |
422 |
{ |
0628b123c netfilter: nfnetl... |
423 |
struct nlmsghdr *nlh = nlmsg_hdr(skb); |
a9de9777d netfilter: nfnetl... |
424 |
u_int16_t res_id; |
0628b123c netfilter: nfnetl... |
425 |
int msglen; |
0628b123c netfilter: nfnetl... |
426 427 428 |
if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) return; |
90f62cf30 net: Use netlink_... |
429 |
if (!netlink_net_capable(skb, CAP_NET_ADMIN)) { |
cdbe7c2d6 nfnetlink: do not... |
430 431 432 |
netlink_ack(skb, nlh, -EPERM); return; } |
0628b123c netfilter: nfnetl... |
433 434 435 436 437 438 439 440 441 442 443 444 445 |
if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN) { struct nfgenmsg *nfgenmsg; msglen = NLMSG_ALIGN(nlh->nlmsg_len); if (msglen > skb->len) msglen = skb->len; if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg)) return; nfgenmsg = nlmsg_data(nlh); skb_pull(skb, msglen); |
a9de9777d netfilter: nfnetl... |
446 447 448 449 450 451 |
/* Work around old nft using host byte order */ if (nfgenmsg->res_id == NFNL_SUBSYS_NFTABLES) res_id = NFNL_SUBSYS_NFTABLES; else res_id = ntohs(nfgenmsg->res_id); nfnetlink_rcv_batch(skb, nlh, res_id); |
0628b123c netfilter: nfnetl... |
452 453 454 |
} else { netlink_rcv_skb(skb, &nfnetlink_rcv_msg); } |
f9e815b37 [NETFITLER]: Add ... |
455 |
} |
03292745b netlink: add nlk-... |
456 |
#ifdef CONFIG_MODULES |
023e2cfa3 netlink/genetlink... |
457 |
static int nfnetlink_bind(struct net *net, int group) |
03292745b netlink: add nlk-... |
458 459 |
{ const struct nfnetlink_subsystem *ss; |
97840cb67 netfilter: nfnetl... |
460 461 462 |
int type; if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX) |
62924af24 netfilter: nfnetl... |
463 |
return 0; |
97840cb67 netfilter: nfnetl... |
464 465 |
type = nfnl_group2type[group]; |
03292745b netlink: add nlk-... |
466 467 |
rcu_read_lock(); |
dbc3617f4 netfilter: nfnetl... |
468 |
ss = nfnetlink_get_subsys(type << 8); |
03292745b netlink: add nlk-... |
469 |
rcu_read_unlock(); |
bfe4bc71c netlink: simplify... |
470 471 |
if (!ss) request_module("nfnetlink-subsys-%d", type); |
4f5209005 netlink: have net... |
472 |
return 0; |
03292745b netlink: add nlk-... |
473 474 |
} #endif |
cd8c20b65 netfilter: nfnetl... |
475 |
static int __net_init nfnetlink_net_init(struct net *net) |
f9e815b37 [NETFITLER]: Add ... |
476 |
{ |
cd8c20b65 netfilter: nfnetl... |
477 |
struct sock *nfnl; |
a31f2d17b netlink: add netl... |
478 479 480 |
struct netlink_kernel_cfg cfg = { .groups = NFNLGRP_MAX, .input = nfnetlink_rcv, |
03292745b netlink: add nlk-... |
481 482 483 |
#ifdef CONFIG_MODULES .bind = nfnetlink_bind, #endif |
a31f2d17b netlink: add netl... |
484 |
}; |
cd8c20b65 netfilter: nfnetl... |
485 |
|
9f00d9776 netlink: hide str... |
486 |
nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, &cfg); |
cd8c20b65 netfilter: nfnetl... |
487 488 489 |
if (!nfnl) return -ENOMEM; net->nfnl_stash = nfnl; |
cf778b00e net: reintroduce ... |
490 |
rcu_assign_pointer(net->nfnl, nfnl); |
cd8c20b65 netfilter: nfnetl... |
491 |
return 0; |
f9e815b37 [NETFITLER]: Add ... |
492 |
} |
cd8c20b65 netfilter: nfnetl... |
493 |
static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list) |
f9e815b37 [NETFITLER]: Add ... |
494 |
{ |
cd8c20b65 netfilter: nfnetl... |
495 |
struct net *net; |
f9e815b37 [NETFITLER]: Add ... |
496 |
|
cd8c20b65 netfilter: nfnetl... |
497 |
list_for_each_entry(net, net_exit_list, exit_list) |
a9b3cd7f3 rcu: convert uses... |
498 |
RCU_INIT_POINTER(net->nfnl, NULL); |
cd8c20b65 netfilter: nfnetl... |
499 500 501 502 |
synchronize_net(); list_for_each_entry(net, net_exit_list, exit_list) netlink_kernel_release(net->nfnl_stash); } |
f9e815b37 [NETFITLER]: Add ... |
503 |
|
cd8c20b65 netfilter: nfnetl... |
504 505 506 507 508 509 510 |
static struct pernet_operations nfnetlink_net_ops = { .init = nfnetlink_net_init, .exit_batch = nfnetlink_net_exit_batch, }; static int __init nfnetlink_init(void) { |
c14b78e7d netfilter: nfnetl... |
511 |
int i; |
97840cb67 netfilter: nfnetl... |
512 513 |
for (i = NFNLGRP_NONE + 1; i <= NFNLGRP_MAX; i++) BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE); |
c14b78e7d netfilter: nfnetl... |
514 515 |
for (i=0; i<NFNL_SUBSYS_COUNT; i++) mutex_init(&table[i].mutex); |
654d0fbdc netfilter: cleanu... |
516 517 |
pr_info("Netfilter messages via NETLINK v%s. ", nfversion); |
cd8c20b65 netfilter: nfnetl... |
518 |
return register_pernet_subsys(&nfnetlink_net_ops); |
f9e815b37 [NETFITLER]: Add ... |
519 |
} |
cd8c20b65 netfilter: nfnetl... |
520 521 |
static void __exit nfnetlink_exit(void) { |
654d0fbdc netfilter: cleanu... |
522 523 |
pr_info("Removing netfilter NETLINK layer. "); |
cd8c20b65 netfilter: nfnetl... |
524 525 |
unregister_pernet_subsys(&nfnetlink_net_ops); } |
f9e815b37 [NETFITLER]: Add ... |
526 527 |
module_init(nfnetlink_init); module_exit(nfnetlink_exit); |