Blame view
net/netfilter/core.c
7.8 KB
601e68e10 [NETFILTER]: Fix ... |
1 |
/* netfilter.c: look after the filters for various protocols. |
f6ebe77f9 [NETFILTER]: spli... |
2 3 4 5 6 7 |
* Heavily influenced by the old firewall.c by David Bonn and Alan Cox. * * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any * way. * * Rusty Russell (C)2000 -- This code is GPL. |
f229f6ce4 netfilter: add my... |
8 |
* Patrick McHardy (c) 2006-2012 |
f6ebe77f9 [NETFILTER]: spli... |
9 |
*/ |
f6ebe77f9 [NETFILTER]: spli... |
10 11 12 13 14 15 16 17 18 19 |
#include <linux/kernel.h> #include <linux/netfilter.h> #include <net/protocol.h> #include <linux/init.h> #include <linux/skbuff.h> #include <linux/wait.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/if.h> #include <linux/netdevice.h> |
567686443 netfilter: fix va... |
20 |
#include <linux/netfilter_ipv6.h> |
f6ebe77f9 [NETFILTER]: spli... |
21 22 |
#include <linux/inetdevice.h> #include <linux/proc_fs.h> |
d486dd1fb [NETFILTER]: Swit... |
23 |
#include <linux/mutex.h> |
5a0e3ad6a include cleanup: ... |
24 |
#include <linux/slab.h> |
457c4cbc5 [NET]: Make /proc... |
25 |
#include <net/net_namespace.h> |
f6ebe77f9 [NETFILTER]: spli... |
26 27 28 |
#include <net/sock.h> #include "nf_internals.h" |
d486dd1fb [NETFILTER]: Swit... |
29 |
static DEFINE_MUTEX(afinfo_mutex); |
bce8032ef [NETFILTER]: Intr... |
30 |
|
0906a372f net/netfilter: __... |
31 |
const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly; |
bce8032ef [NETFILTER]: Intr... |
32 |
EXPORT_SYMBOL(nf_afinfo); |
2a7851bff netfilter: add nf... |
33 34 |
const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly; EXPORT_SYMBOL_GPL(nf_ipv6_ops); |
bce8032ef [NETFILTER]: Intr... |
35 |
|
1e796fda0 [NETFILTER]: cons... |
36 |
int nf_register_afinfo(const struct nf_afinfo *afinfo) |
bce8032ef [NETFILTER]: Intr... |
37 |
{ |
7926dbfa4 netfilter: don't ... |
38 |
mutex_lock(&afinfo_mutex); |
a9b3cd7f3 rcu: convert uses... |
39 |
RCU_INIT_POINTER(nf_afinfo[afinfo->family], afinfo); |
d486dd1fb [NETFILTER]: Swit... |
40 |
mutex_unlock(&afinfo_mutex); |
bce8032ef [NETFILTER]: Intr... |
41 42 43 |
return 0; } EXPORT_SYMBOL_GPL(nf_register_afinfo); |
1e796fda0 [NETFILTER]: cons... |
44 |
void nf_unregister_afinfo(const struct nf_afinfo *afinfo) |
bce8032ef [NETFILTER]: Intr... |
45 |
{ |
d486dd1fb [NETFILTER]: Swit... |
46 |
mutex_lock(&afinfo_mutex); |
a9b3cd7f3 rcu: convert uses... |
47 |
RCU_INIT_POINTER(nf_afinfo[afinfo->family], NULL); |
d486dd1fb [NETFILTER]: Swit... |
48 |
mutex_unlock(&afinfo_mutex); |
bce8032ef [NETFILTER]: Intr... |
49 50 51 |
synchronize_rcu(); } EXPORT_SYMBOL_GPL(nf_unregister_afinfo); |
7e9c6eeb1 netfilter: Introd... |
52 |
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly; |
f6ebe77f9 [NETFILTER]: spli... |
53 |
EXPORT_SYMBOL(nf_hooks); |
a2d7ec58a netfilter: use ju... |
54 |
|
d1c85c2eb netfilter: HAVE_J... |
55 |
#ifdef HAVE_JUMP_LABEL |
c5905afb0 static keys: Intr... |
56 |
struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; |
a2d7ec58a netfilter: use ju... |
57 58 |
EXPORT_SYMBOL(nf_hooks_needed); #endif |
fd706d695 [NETFILTER]: Swit... |
59 |
static DEFINE_MUTEX(nf_hook_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
60 61 62 |
int nf_register_hook(struct nf_hook_ops *reg) { |
4c6109795 [NETFILTER]: repl... |
63 |
struct nf_hook_ops *elem; |
f6ebe77f9 [NETFILTER]: spli... |
64 |
|
7926dbfa4 netfilter: don't ... |
65 |
mutex_lock(&nf_hook_mutex); |
4c6109795 [NETFILTER]: repl... |
66 67 |
list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) { if (reg->priority < elem->priority) |
f6ebe77f9 [NETFILTER]: spli... |
68 69 |
break; } |
4c6109795 [NETFILTER]: repl... |
70 |
list_add_rcu(®->list, elem->list.prev); |
fd706d695 [NETFILTER]: Swit... |
71 |
mutex_unlock(&nf_hook_mutex); |
d1c85c2eb netfilter: HAVE_J... |
72 |
#ifdef HAVE_JUMP_LABEL |
c5905afb0 static keys: Intr... |
73 |
static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]); |
a2d7ec58a netfilter: use ju... |
74 |
#endif |
f6ebe77f9 [NETFILTER]: spli... |
75 76 77 78 79 80 |
return 0; } EXPORT_SYMBOL(nf_register_hook); void nf_unregister_hook(struct nf_hook_ops *reg) { |
fd706d695 [NETFILTER]: Swit... |
81 |
mutex_lock(&nf_hook_mutex); |
f6ebe77f9 [NETFILTER]: spli... |
82 |
list_del_rcu(®->list); |
fd706d695 [NETFILTER]: Swit... |
83 |
mutex_unlock(&nf_hook_mutex); |
d1c85c2eb netfilter: HAVE_J... |
84 |
#ifdef HAVE_JUMP_LABEL |
c5905afb0 static keys: Intr... |
85 |
static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); |
a2d7ec58a netfilter: use ju... |
86 |
#endif |
f6ebe77f9 [NETFILTER]: spli... |
87 88 89 |
synchronize_net(); } EXPORT_SYMBOL(nf_unregister_hook); |
972d1cb14 [NETFILTER]: Add ... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n) { unsigned int i; int err = 0; for (i = 0; i < n; i++) { err = nf_register_hook(®[i]); if (err) goto err; } return err; err: if (i > 0) nf_unregister_hooks(reg, i); return err; } EXPORT_SYMBOL(nf_register_hooks); void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n) { |
f68c53015 netfilter: unregi... |
111 112 |
while (n-- > 0) nf_unregister_hook(®[n]); |
972d1cb14 [NETFILTER]: Add ... |
113 114 |
} EXPORT_SYMBOL(nf_unregister_hooks); |
f6ebe77f9 [NETFILTER]: spli... |
115 |
unsigned int nf_iterate(struct list_head *head, |
3db05fea5 [NETFILTER]: Repl... |
116 |
struct sk_buff *skb, |
76108cea0 netfilter: Use un... |
117 |
unsigned int hook, |
f6ebe77f9 [NETFILTER]: spli... |
118 119 |
const struct net_device *indev, const struct net_device *outdev, |
2a6decfd8 netfilter: pass '... |
120 |
struct nf_hook_ops **elemp, |
f6ebe77f9 [NETFILTER]: spli... |
121 122 123 124 125 126 127 128 129 |
int (*okfn)(struct sk_buff *), int hook_thresh) { unsigned int verdict; /* * The caller must not block between calls to this * function because of risk of continuing from deleted element. */ |
2a6decfd8 netfilter: pass '... |
130 131 |
list_for_each_entry_continue_rcu((*elemp), head, list) { if (hook_thresh > (*elemp)->priority) |
f6ebe77f9 [NETFILTER]: spli... |
132 133 134 |
continue; /* Optimization: we don't need to hold module |
601e68e10 [NETFILTER]: Fix ... |
135 |
reference here, since function can't sleep. --RR */ |
de9963f0f netfilter: nf_ite... |
136 |
repeat: |
795aa6ef6 netfilter: pass h... |
137 |
verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn); |
f6ebe77f9 [NETFILTER]: spli... |
138 139 140 141 142 143 |
if (verdict != NF_ACCEPT) { #ifdef CONFIG_NETFILTER_DEBUG if (unlikely((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)) { NFDEBUG("Evil return from %p(%u). ", |
2a6decfd8 netfilter: pass '... |
144 |
(*elemp)->hook, hook); |
f6ebe77f9 [NETFILTER]: spli... |
145 146 147 |
continue; } #endif |
2a6decfd8 netfilter: pass '... |
148 |
if (verdict != NF_REPEAT) |
f6ebe77f9 [NETFILTER]: spli... |
149 |
return verdict; |
de9963f0f netfilter: nf_ite... |
150 |
goto repeat; |
f6ebe77f9 [NETFILTER]: spli... |
151 152 153 154 155 156 157 158 |
} } return NF_ACCEPT; } /* Returns 1 if okfn() needs to be executed by the caller, * -EPERM for NF_DROP, 0 otherwise. */ |
76108cea0 netfilter: Use un... |
159 |
int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb, |
f6ebe77f9 [NETFILTER]: spli... |
160 161 162 163 164 |
struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *), int hook_thresh) { |
2a6decfd8 netfilter: pass '... |
165 |
struct nf_hook_ops *elem; |
f6ebe77f9 [NETFILTER]: spli... |
166 167 168 169 170 |
unsigned int verdict; int ret = 0; /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); |
2a6decfd8 netfilter: pass '... |
171 |
elem = list_entry_rcu(&nf_hooks[pf][hook], struct nf_hook_ops, list); |
f6ebe77f9 [NETFILTER]: spli... |
172 |
next_hook: |
3db05fea5 [NETFILTER]: Repl... |
173 |
verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev, |
f6ebe77f9 [NETFILTER]: spli... |
174 175 176 |
outdev, &elem, okfn, hook_thresh); if (verdict == NF_ACCEPT || verdict == NF_STOP) { ret = 1; |
da6836500 netfilter: allow ... |
177 |
} else if ((verdict & NF_VERDICT_MASK) == NF_DROP) { |
3db05fea5 [NETFILTER]: Repl... |
178 |
kfree_skb(skb); |
f615df76e netfilter: reduce... |
179 |
ret = NF_DROP_GETERR(verdict); |
da6836500 netfilter: allow ... |
180 181 |
if (ret == 0) ret = -EPERM; |
f9c639905 [NETFILTER]: remo... |
182 |
} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { |
1c15b6770 netfilter: pass '... |
183 184 |
int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, verdict >> NF_VERDICT_QBITS); |
563e12326 netfilter: do not... |
185 186 |
if (err < 0) { if (err == -ECANCELED) |
06cdb6349 netfilter: nfnetl... |
187 |
goto next_hook; |
563e12326 netfilter: do not... |
188 |
if (err == -ESRCH && |
94b27cc36 netfilter: allow ... |
189 190 |
(verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) goto next_hook; |
06cdb6349 netfilter: nfnetl... |
191 192 |
kfree_skb(skb); } |
f6ebe77f9 [NETFILTER]: spli... |
193 |
} |
f6ebe77f9 [NETFILTER]: spli... |
194 195 196 197 |
rcu_read_unlock(); return ret; } EXPORT_SYMBOL(nf_hook_slow); |
37d418792 [NETFILTER]: Do n... |
198 |
int skb_make_writable(struct sk_buff *skb, unsigned int writable_len) |
f6ebe77f9 [NETFILTER]: spli... |
199 |
{ |
37d418792 [NETFILTER]: Do n... |
200 |
if (writable_len > skb->len) |
f6ebe77f9 [NETFILTER]: spli... |
201 202 203 |
return 0; /* Not exclusive use of packet? Must copy. */ |
37d418792 [NETFILTER]: Do n... |
204 205 206 207 208 209 210 211 212 213 214 215 |
if (!skb_cloned(skb)) { if (writable_len <= skb_headlen(skb)) return 1; } else if (skb_clone_writable(skb, writable_len)) return 1; if (writable_len <= skb_headlen(skb)) writable_len = 0; else writable_len -= skb_headlen(skb); return !!__pskb_pull_tail(skb, writable_len); |
f6ebe77f9 [NETFILTER]: spli... |
216 217 |
} EXPORT_SYMBOL(skb_make_writable); |
c0cd11566 net:netfilter: us... |
218 |
#if IS_ENABLED(CONFIG_NF_CONNTRACK) |
f6ebe77f9 [NETFILTER]: spli... |
219 220 221 |
/* This does not belong here, but locally generated errors need it if connection tracking in use: without this, connection may not be in hash table, and hence manufactured ICMP or RST packets will not be associated with it. */ |
312a0c16c netfilter: nf_con... |
222 223 |
void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *) __rcu __read_mostly; |
f6ebe77f9 [NETFILTER]: spli... |
224 |
EXPORT_SYMBOL(ip_ct_attach); |
312a0c16c netfilter: nf_con... |
225 |
void nf_ct_attach(struct sk_buff *new, const struct sk_buff *skb) |
f6ebe77f9 [NETFILTER]: spli... |
226 |
{ |
312a0c16c netfilter: nf_con... |
227 |
void (*attach)(struct sk_buff *, const struct sk_buff *); |
f6ebe77f9 [NETFILTER]: spli... |
228 |
|
c3a47ab3e [NETFILTER]: Prop... |
229 230 231 232 233 234 |
if (skb->nfct) { rcu_read_lock(); attach = rcu_dereference(ip_ct_attach); if (attach) attach(new, skb); rcu_read_unlock(); |
f6ebe77f9 [NETFILTER]: spli... |
235 236 237 |
} } EXPORT_SYMBOL(nf_ct_attach); |
de6e05c49 [NETFILTER]: nf_c... |
238 |
|
0e60ebe04 netfilter: add __... |
239 |
void (*nf_ct_destroy)(struct nf_conntrack *) __rcu __read_mostly; |
de6e05c49 [NETFILTER]: nf_c... |
240 241 242 243 244 245 246 247 248 249 250 251 252 |
EXPORT_SYMBOL(nf_ct_destroy); void nf_conntrack_destroy(struct nf_conntrack *nfct) { void (*destroy)(struct nf_conntrack *); rcu_read_lock(); destroy = rcu_dereference(nf_ct_destroy); BUG_ON(destroy == NULL); destroy(nfct); rcu_read_unlock(); } EXPORT_SYMBOL(nf_conntrack_destroy); |
9cb017665 netfilter: add gl... |
253 |
|
5a05fae5c netfilter: nfq_ct... |
254 |
struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly; |
9cb017665 netfilter: add gl... |
255 |
EXPORT_SYMBOL_GPL(nfq_ct_hook); |
d584a61a9 netfilter: nfnetl... |
256 257 |
struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook __read_mostly; EXPORT_SYMBOL_GPL(nfq_ct_nat_hook); |
de6e05c49 [NETFILTER]: nf_c... |
258 |
#endif /* CONFIG_NF_CONNTRACK */ |
f6ebe77f9 [NETFILTER]: spli... |
259 |
|
c7232c997 netfilter: add pr... |
260 261 262 263 |
#ifdef CONFIG_NF_NAT_NEEDED void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); EXPORT_SYMBOL(nf_nat_decode_session_hook); #endif |
f3c1a44a2 netfilter: make /... |
264 265 266 267 268 |
static int __net_init netfilter_net_init(struct net *net) { #ifdef CONFIG_PROC_FS net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter", net->proc_net); |
12202fa75 netfilter: remove... |
269 270 271 |
if (!net->nf.proc_netfilter) { if (!net_eq(net, &init_net)) pr_err("cannot create netfilter proc entry"); |
f3c1a44a2 netfilter: make /... |
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
return -ENOMEM; } #endif return 0; } static void __net_exit netfilter_net_exit(struct net *net) { remove_proc_entry("netfilter", net->proc_net); } static struct pernet_operations netfilter_net_ops = { .init = netfilter_net_init, .exit = netfilter_net_exit, }; |
6d11cfdba netfilter: don't ... |
287 |
int __init netfilter_init(void) |
f6ebe77f9 [NETFILTER]: spli... |
288 |
{ |
6d11cfdba netfilter: don't ... |
289 |
int i, h, ret; |
7e9c6eeb1 netfilter: Introd... |
290 |
for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { |
f6ebe77f9 [NETFILTER]: spli... |
291 292 293 |
for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); } |
6d11cfdba netfilter: don't ... |
294 295 296 297 298 299 300 |
ret = register_pernet_subsys(&netfilter_net_ops); if (ret < 0) goto err; ret = netfilter_log_init(); if (ret < 0) goto err_pernet; |
f6ebe77f9 [NETFILTER]: spli... |
301 |
|
6d11cfdba netfilter: don't ... |
302 303 304 305 306 |
return 0; err_pernet: unregister_pernet_subsys(&netfilter_net_ops); err: return ret; |
f6ebe77f9 [NETFILTER]: spli... |
307 |
} |