Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
linux
Public
Notifications
You must be signed in to change notification settings
Fork
0
Star
0
Code
Issues
1
Pull requests
0
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
0906a37
Documentation
arch
block
crypto
drivers
firmware
fs
include
init
ipc
kernel
lib
mm
net
802
8021q
9p
appletalk
atm
ax25
bluetooth
bridge
caif
can
core
dcb
dccp
decnet
dns_resolver
dsa
econet
ethernet
ieee802154
ipv4
ipv6
ipx
irda
iucv
key
l2tp
lapb
llc
mac80211
netfilter
ipvs
Kconfig
Makefile
core.c
nf_conntrack_acct.c
nf_conntrack_amanda.c
nf_conntrack_core.c
nf_conntrack_ecache.c
nf_conntrack_expect.c
nf_conntrack_extend.c
nf_conntrack_ftp.c
nf_conntrack_h323_asn1.c
nf_conntrack_h323_main.c
nf_conntrack_h323_types.c
nf_conntrack_helper.c
nf_conntrack_irc.c
nf_conntrack_l3proto_generic.c
nf_conntrack_netbios_ns.c
nf_conntrack_netlink.c
nf_conntrack_pptp.c
nf_conntrack_proto.c
nf_conntrack_proto_dccp.c
nf_conntrack_proto_generic.c
nf_conntrack_proto_gre.c
nf_conntrack_proto_sctp.c
nf_conntrack_proto_tcp.c
nf_conntrack_proto_udp.c
nf_conntrack_proto_udplite.c
nf_conntrack_sane.c
nf_conntrack_sip.c
nf_conntrack_standalone.c
nf_conntrack_tftp.c
nf_internals.h
nf_log.c
nf_queue.c
nf_sockopt.c
nf_tproxy_core.c
nfnetlink.c
nfnetlink_log.c
nfnetlink_queue.c
x_tables.c
xt_CHECKSUM.c
xt_CLASSIFY.c
xt_CONNSECMARK.c
xt_CT.c
xt_DSCP.c
xt_HL.c
xt_IDLETIMER.c
xt_LED.c
xt_NFLOG.c
xt_NFQUEUE.c
xt_NOTRACK.c
xt_RATEEST.c
xt_SECMARK.c
xt_TCPMSS.c
xt_TCPOPTSTRIP.c
xt_TEE.c
xt_TPROXY.c
xt_TRACE.c
xt_cluster.c
xt_comment.c
xt_connbytes.c
xt_connlimit.c
xt_connmark.c
xt_conntrack.c
xt_cpu.c
xt_dccp.c
xt_dscp.c
xt_esp.c
xt_hashlimit.c
xt_helper.c
xt_hl.c
xt_iprange.c
xt_ipvs.c
xt_length.c
xt_limit.c
xt_mac.c
xt_mark.c
xt_multiport.c
xt_osf.c
xt_owner.c
xt_physdev.c
xt_pkttype.c
xt_policy.c
xt_quota.c
xt_rateest.c
xt_realm.c
xt_recent.c
xt_repldata.h
xt_sctp.c
xt_socket.c
xt_state.c
xt_statistic.c
xt_string.c
xt_tcpmss.c
xt_tcpudp.c
xt_time.c
xt_u32.c
netlabel
netlink
netrom
packet
phonet
rds
rfkill
rose
rxrpc
sched
sctp
sunrpc
tipc
unix
wanrouter
wimax
wireless
x25
xfrm
Kconfig
Makefile
TUNABLE
compat.c
nonet.c
socket.c
sysctl_net.c
samples
scripts
security
sound
tools
usr
virt
.gitignore
.mailmap
COPYING
CREDITS
Kbuild
MAINTAINERS
Makefile
README
REPORTING-BUGS
Breadcrumbs
linux
/
net
/
netfilter
/
nf_queue.c
Copy path
Blame
Blame
Latest commit
History
History
359 lines (301 loc) · 7.67 KB
Breadcrumbs
linux
/
net
/
netfilter
/
nf_queue.c
Top
File metadata and controls
Code
Blame
359 lines (301 loc) · 7.67 KB
Raw
#include <linux/kernel.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/skbuff.h> #include <linux/netfilter.h> #include <linux/seq_file.h> #include <linux/rcupdate.h> #include <net/protocol.h> #include <net/netfilter/nf_queue.h> #include <net/dst.h> #include "nf_internals.h" /* * A queue handler may be registered for each protocol. Each is protected by * long term mutex. The handler must provide an an outfn() to accept packets * for queueing and must reinject all packets it receives, no matter what. */ static const struct nf_queue_handler __rcu *queue_handler[NFPROTO_NUMPROTO] __read_mostly; static DEFINE_MUTEX(queue_handler_mutex); /* return EBUSY when somebody else is registered, return EEXIST if the * same handler is registered, return 0 in case of success. */ int nf_register_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh) { int ret; if (pf >= ARRAY_SIZE(queue_handler)) return -EINVAL; mutex_lock(&queue_handler_mutex); if (queue_handler[pf] == qh) ret = -EEXIST; else if (queue_handler[pf]) ret = -EBUSY; else { rcu_assign_pointer(queue_handler[pf], qh); ret = 0; } mutex_unlock(&queue_handler_mutex); return ret; } EXPORT_SYMBOL(nf_register_queue_handler); /* The caller must flush their queue before this */ int nf_unregister_queue_handler(u_int8_t pf, const struct nf_queue_handler *qh) { if (pf >= ARRAY_SIZE(queue_handler)) return -EINVAL; mutex_lock(&queue_handler_mutex); if (queue_handler[pf] && queue_handler[pf] != qh) { mutex_unlock(&queue_handler_mutex); return -EINVAL; } rcu_assign_pointer(queue_handler[pf], NULL); mutex_unlock(&queue_handler_mutex); synchronize_rcu(); return 0; } EXPORT_SYMBOL(nf_unregister_queue_handler); void nf_unregister_queue_handlers(const struct nf_queue_handler *qh) { u_int8_t pf; mutex_lock(&queue_handler_mutex); for (pf = 0; pf < ARRAY_SIZE(queue_handler); pf++) { if (queue_handler[pf] == qh) rcu_assign_pointer(queue_handler[pf], NULL); } mutex_unlock(&queue_handler_mutex); synchronize_rcu(); } EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers); static void nf_queue_entry_release_refs(struct nf_queue_entry *entry) { /* Release those devices we held, or Alexey will kill me. */ if (entry->indev) dev_put(entry->indev); if (entry->outdev) dev_put(entry->outdev); #ifdef CONFIG_BRIDGE_NETFILTER if (entry->skb->nf_bridge) { struct nf_bridge_info *nf_bridge = entry->skb->nf_bridge; if (nf_bridge->physindev) dev_put(nf_bridge->physindev); if (nf_bridge->physoutdev) dev_put(nf_bridge->physoutdev); } #endif /* Drop reference to owner of hook which queued us. */ module_put(entry->elem->owner); } /* * Any packet that leaves via this function must come back * through nf_reinject(). */ static int __nf_queue(struct sk_buff *skb, struct list_head *elem, u_int8_t pf, unsigned int hook, struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *), unsigned int queuenum) { int status; struct nf_queue_entry *entry = NULL; #ifdef CONFIG_BRIDGE_NETFILTER struct net_device *physindev; struct net_device *physoutdev; #endif const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; /* QUEUE == DROP if noone is waiting, to be safe. */ rcu_read_lock(); qh = rcu_dereference(queue_handler[pf]); if (!qh) goto err_unlock; afinfo = nf_get_afinfo(pf); if (!afinfo) goto err_unlock; entry = kmalloc(sizeof(*entry) + afinfo->route_key_size, GFP_ATOMIC); if (!entry) goto err_unlock; *entry = (struct nf_queue_entry) { .skb = skb, .elem = list_entry(elem, struct nf_hook_ops, list), .pf = pf, .hook = hook, .indev = indev, .outdev = outdev, .okfn = okfn, }; /* If it's going away, ignore hook. */ if (!try_module_get(entry->elem->owner)) { rcu_read_unlock(); kfree(entry); return 0; } /* Bump dev refs so they don't vanish while packet is out */ if (indev) dev_hold(indev); if (outdev) dev_hold(outdev); #ifdef CONFIG_BRIDGE_NETFILTER if (skb->nf_bridge) { physindev = skb->nf_bridge->physindev; if (physindev) dev_hold(physindev); physoutdev = skb->nf_bridge->physoutdev; if (physoutdev) dev_hold(physoutdev); } #endif skb_dst_force(skb); afinfo->saveroute(skb, entry); status = qh->outfn(entry, queuenum); rcu_read_unlock(); if (status < 0) { nf_queue_entry_release_refs(entry); goto err; } return 1; err_unlock: rcu_read_unlock(); err: kfree_skb(skb); kfree(entry); return 1; } int nf_queue(struct sk_buff *skb, struct list_head *elem, u_int8_t pf, unsigned int hook, struct net_device *indev, struct net_device *outdev, int (*okfn)(struct sk_buff *), unsigned int queuenum) { struct sk_buff *segs; if (!skb_is_gso(skb)) return __nf_queue(skb, elem, pf, hook, indev, outdev, okfn, queuenum); switch (pf) { case NFPROTO_IPV4: skb->protocol = htons(ETH_P_IP); break; case NFPROTO_IPV6: skb->protocol = htons(ETH_P_IPV6); break; } segs = skb_gso_segment(skb, 0); kfree_skb(skb); if (IS_ERR(segs)) return 1; do { struct sk_buff *nskb = segs->next; segs->next = NULL; if (!__nf_queue(segs, elem, pf, hook, indev, outdev, okfn, queuenum)) kfree_skb(segs); segs = nskb; } while (segs); return 1; } void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) { struct sk_buff *skb = entry->skb; struct list_head *elem = &entry->elem->list; const struct nf_afinfo *afinfo; rcu_read_lock(); nf_queue_entry_release_refs(entry); /* Continue traversal iff userspace said ok... */ if (verdict == NF_REPEAT) { elem = elem->prev; verdict = NF_ACCEPT; } if (verdict == NF_ACCEPT) { afinfo = nf_get_afinfo(entry->pf); if (!afinfo || afinfo->reroute(skb, entry) < 0) verdict = NF_DROP; } if (verdict == NF_ACCEPT) { next_hook: verdict = nf_iterate(&nf_hooks[entry->pf][entry->hook], skb, entry->hook, entry->indev, entry->outdev, &elem, entry->okfn, INT_MIN); } switch (verdict & NF_VERDICT_MASK) { case NF_ACCEPT: case NF_STOP: local_bh_disable(); entry->okfn(skb); local_bh_enable(); break; case NF_QUEUE: if (!__nf_queue(skb, elem, entry->pf, entry->hook, entry->indev, entry->outdev, entry->okfn, verdict >> NF_VERDICT_BITS)) goto next_hook; break; case NF_STOLEN: default: kfree_skb(skb); } rcu_read_unlock(); kfree(entry); } EXPORT_SYMBOL(nf_reinject); #ifdef CONFIG_PROC_FS static void *seq_start(struct seq_file *seq, loff_t *pos) { if (*pos >= ARRAY_SIZE(queue_handler)) return NULL; return pos; } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; if (*pos >= ARRAY_SIZE(queue_handler)) return NULL; return pos; } static void seq_stop(struct seq_file *s, void *v) { } static int seq_show(struct seq_file *s, void *v) { int ret; loff_t *pos = v; const struct nf_queue_handler *qh; rcu_read_lock(); qh = rcu_dereference(queue_handler[*pos]); if (!qh) ret = seq_printf(s, "%2lld NONE\n", *pos); else ret = seq_printf(s, "%2lld %s\n", *pos, qh->name); rcu_read_unlock(); return ret; } static const struct seq_operations nfqueue_seq_ops = { .start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show, }; static int nfqueue_open(struct inode *inode, struct file *file) { return seq_open(file, &nfqueue_seq_ops); } static const struct file_operations nfqueue_file_ops = { .owner = THIS_MODULE, .open = nfqueue_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; #endif /* PROC_FS */ int __init netfilter_queue_init(void) { #ifdef CONFIG_PROC_FS if (!proc_create("nf_queue", S_IRUGO, proc_net_netfilter, &nfqueue_file_ops)) return -1; #endif return 0; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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
You can’t perform that action at this time.