Blame view
net/netfilter/nfnetlink_queue.c
38.4 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
7af4cc3fa [NETFILTER]: Add ... |
2 3 |
/* * This is a module which is used for queueing packets and communicating with |
67137f3cc nfnetlink_queue: ... |
4 |
* userspace via nfnetlink. |
7af4cc3fa [NETFILTER]: Add ... |
5 6 |
* * (C) 2005 by Harald Welte <laforge@netfilter.org> |
4ad9d4fa9 [NETFILTER]: nfne... |
7 |
* (C) 2007 by Patrick McHardy <kaber@trash.net> |
7af4cc3fa [NETFILTER]: Add ... |
8 9 10 11 |
* * Based on the old ipv4-only ip_queue.c: * (C) 2000-2002 James Morris <jmorris@intercode.com.au> * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> |
7af4cc3fa [NETFILTER]: Add ... |
12 |
*/ |
5191d70f8 netfilter: Replac... |
13 14 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7af4cc3fa [NETFILTER]: Add ... |
15 16 17 18 |
#include <linux/module.h> #include <linux/skbuff.h> #include <linux/init.h> #include <linux/spinlock.h> |
5a0e3ad6a include cleanup: ... |
19 |
#include <linux/slab.h> |
7af4cc3fa [NETFILTER]: Add ... |
20 21 22 |
#include <linux/notifier.h> #include <linux/netdevice.h> #include <linux/netfilter.h> |
838ab6364 [NETFILTER]: Add ... |
23 |
#include <linux/proc_fs.h> |
7af4cc3fa [NETFILTER]: Add ... |
24 25 |
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv6.h> |
c737b7c45 netfilter: bridge... |
26 |
#include <linux/netfilter_bridge.h> |
7af4cc3fa [NETFILTER]: Add ... |
27 28 |
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_queue.h> |
b7bd1809e netfilter: nfnetl... |
29 |
#include <linux/netfilter/nf_conntrack_common.h> |
7af4cc3fa [NETFILTER]: Add ... |
30 31 |
#include <linux/list.h> #include <net/sock.h> |
83111e7fe netfilter: Fix bu... |
32 |
#include <net/tcp_states.h> |
c01cd429f [NETFILTER]: nf_q... |
33 |
#include <net/netfilter/nf_queue.h> |
e81796104 netfilter: nfnetl... |
34 |
#include <net/netns/generic.h> |
7af4cc3fa [NETFILTER]: Add ... |
35 |
|
60063497a atomic: use <linu... |
36 |
#include <linux/atomic.h> |
7af4cc3fa [NETFILTER]: Add ... |
37 |
|
1109a90c0 netfilter: use IS... |
38 |
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
fbcd923c3 [NETFILTER]: add ... |
39 40 |
#include "../bridge/br_private.h" #endif |
5da773a3e netfilter: nfnetl... |
41 42 43 |
#if IS_ENABLED(CONFIG_NF_CONNTRACK) #include <net/netfilter/nf_conntrack.h> #endif |
7af4cc3fa [NETFILTER]: Add ... |
44 |
#define NFQNL_QMAX_DEFAULT 1024 |
9cefbbc9c netfilter: nfnetl... |
45 46 47 48 49 50 51 |
/* We're using struct nlattr which has 16bit nla_len. Note that nla_len * includes the header length. Thus, the maximum packet length that we * support is 65531 bytes. We send truncated packets if the specified length * is larger than that. Userspace can check for presence of NFQA_CAP_LEN * attribute to detect truncation. */ #define NFQNL_MAX_COPY_RANGE (0xffff - NLA_HDRLEN) |
7af4cc3fa [NETFILTER]: Add ... |
52 53 |
struct nfqnl_instance { struct hlist_node hlist; /* global list of queues */ |
9872bec77 [NETFILTER]: nfne... |
54 |
struct rcu_head rcu; |
7af4cc3fa [NETFILTER]: Add ... |
55 |
|
cc6bc4486 netfilter: Fix po... |
56 |
u32 peer_portid; |
7af4cc3fa [NETFILTER]: Add ... |
57 58 |
unsigned int queue_maxlen; unsigned int copy_range; |
7af4cc3fa [NETFILTER]: Add ... |
59 60 |
unsigned int queue_dropped; unsigned int queue_user_dropped; |
7af4cc3fa [NETFILTER]: Add ... |
61 62 63 |
u_int16_t queue_num; /* number of this queue */ u_int8_t copy_mode; |
fdb694a01 netfilter: Add fa... |
64 |
u_int32_t flags; /* Set using NFQA_CFG_FLAGS */ |
c463ac972 netfilter: nfnetl... |
65 66 67 68 |
/* * Following fields are dirtied for each queued packet, * keep them in same cache line if possible. */ |
886bc5034 netfilter: nf_que... |
69 |
spinlock_t lock ____cacheline_aligned_in_smp; |
c463ac972 netfilter: nfnetl... |
70 |
unsigned int queue_total; |
5863702a3 netfilter: nfnetl... |
71 |
unsigned int id_sequence; /* 'sequence' of pkt ids */ |
7af4cc3fa [NETFILTER]: Add ... |
72 73 |
struct list_head queue_list; /* packets in queue */ }; |
02f014d88 [NETFILTER]: nf_q... |
74 |
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); |
7af4cc3fa [NETFILTER]: Add ... |
75 |
|
c7d03a00b netns: make struc... |
76 |
static unsigned int nfnl_queue_net_id __read_mostly; |
7af4cc3fa [NETFILTER]: Add ... |
77 |
|
7af4cc3fa [NETFILTER]: Add ... |
78 |
#define INSTANCE_BUCKETS 16 |
e81796104 netfilter: nfnetl... |
79 80 81 82 83 84 85 86 87 |
struct nfnl_queue_net { spinlock_t instances_lock; struct hlist_head instance_table[INSTANCE_BUCKETS]; }; static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net) { return net_generic(net, nfnl_queue_net_id); } |
7af4cc3fa [NETFILTER]: Add ... |
88 89 90 |
static inline u_int8_t instance_hashfn(u_int16_t queue_num) { |
1cdb09056 netfilter: nfnetl... |
91 |
return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS; |
7af4cc3fa [NETFILTER]: Add ... |
92 93 94 |
} static struct nfqnl_instance * |
e81796104 netfilter: nfnetl... |
95 |
instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num) |
7af4cc3fa [NETFILTER]: Add ... |
96 97 |
{ struct hlist_head *head; |
7af4cc3fa [NETFILTER]: Add ... |
98 |
struct nfqnl_instance *inst; |
e81796104 netfilter: nfnetl... |
99 |
head = &q->instance_table[instance_hashfn(queue_num)]; |
b67bfe0d4 hlist: drop the n... |
100 |
hlist_for_each_entry_rcu(inst, head, hlist) { |
7af4cc3fa [NETFILTER]: Add ... |
101 102 103 104 105 106 107 |
if (inst->queue_num == queue_num) return inst; } return NULL; } static struct nfqnl_instance * |
cc6bc4486 netfilter: Fix po... |
108 |
instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid) |
7af4cc3fa [NETFILTER]: Add ... |
109 |
{ |
baab2ce7d [NETFILTER]: nfne... |
110 |
struct nfqnl_instance *inst; |
9872bec77 [NETFILTER]: nfne... |
111 |
unsigned int h; |
baab2ce7d [NETFILTER]: nfne... |
112 |
int err; |
7af4cc3fa [NETFILTER]: Add ... |
113 |
|
e81796104 netfilter: nfnetl... |
114 115 |
spin_lock(&q->instances_lock); if (instance_lookup(q, queue_num)) { |
baab2ce7d [NETFILTER]: nfne... |
116 |
err = -EEXIST; |
7af4cc3fa [NETFILTER]: Add ... |
117 |
goto out_unlock; |
baab2ce7d [NETFILTER]: nfne... |
118 |
} |
7af4cc3fa [NETFILTER]: Add ... |
119 |
|
10dfdc69e [NETFILTER] nfnet... |
120 |
inst = kzalloc(sizeof(*inst), GFP_ATOMIC); |
baab2ce7d [NETFILTER]: nfne... |
121 122 |
if (!inst) { err = -ENOMEM; |
7af4cc3fa [NETFILTER]: Add ... |
123 |
goto out_unlock; |
baab2ce7d [NETFILTER]: nfne... |
124 |
} |
7af4cc3fa [NETFILTER]: Add ... |
125 |
|
7af4cc3fa [NETFILTER]: Add ... |
126 |
inst->queue_num = queue_num; |
15e473046 netlink: Rename p... |
127 |
inst->peer_portid = portid; |
7af4cc3fa [NETFILTER]: Add ... |
128 |
inst->queue_maxlen = NFQNL_QMAX_DEFAULT; |
9cefbbc9c netfilter: nfnetl... |
129 |
inst->copy_range = NFQNL_MAX_COPY_RANGE; |
7af4cc3fa [NETFILTER]: Add ... |
130 |
inst->copy_mode = NFQNL_COPY_NONE; |
181a46a56 [NETFILTER]: Use ... |
131 |
spin_lock_init(&inst->lock); |
7af4cc3fa [NETFILTER]: Add ... |
132 |
INIT_LIST_HEAD(&inst->queue_list); |
baab2ce7d [NETFILTER]: nfne... |
133 134 |
if (!try_module_get(THIS_MODULE)) { err = -EAGAIN; |
7af4cc3fa [NETFILTER]: Add ... |
135 |
goto out_free; |
baab2ce7d [NETFILTER]: nfne... |
136 |
} |
7af4cc3fa [NETFILTER]: Add ... |
137 |
|
9872bec77 [NETFILTER]: nfne... |
138 |
h = instance_hashfn(queue_num); |
e81796104 netfilter: nfnetl... |
139 |
hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]); |
7af4cc3fa [NETFILTER]: Add ... |
140 |
|
e81796104 netfilter: nfnetl... |
141 |
spin_unlock(&q->instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
142 |
|
7af4cc3fa [NETFILTER]: Add ... |
143 144 145 146 147 |
return inst; out_free: kfree(inst); out_unlock: |
e81796104 netfilter: nfnetl... |
148 |
spin_unlock(&q->instances_lock); |
baab2ce7d [NETFILTER]: nfne... |
149 |
return ERR_PTR(err); |
7af4cc3fa [NETFILTER]: Add ... |
150 |
} |
b43d8d859 [NETFILTER]: nfne... |
151 152 |
static void nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data); |
7af4cc3fa [NETFILTER]: Add ... |
153 154 |
static void |
9872bec77 [NETFILTER]: nfne... |
155 |
instance_destroy_rcu(struct rcu_head *head) |
7af4cc3fa [NETFILTER]: Add ... |
156 |
{ |
9872bec77 [NETFILTER]: nfne... |
157 158 |
struct nfqnl_instance *inst = container_of(head, struct nfqnl_instance, rcu); |
7af4cc3fa [NETFILTER]: Add ... |
159 |
|
b43d8d859 [NETFILTER]: nfne... |
160 |
nfqnl_flush(inst, NULL, 0); |
9872bec77 [NETFILTER]: nfne... |
161 |
kfree(inst); |
7af4cc3fa [NETFILTER]: Add ... |
162 163 |
module_put(THIS_MODULE); } |
9872bec77 [NETFILTER]: nfne... |
164 |
static void |
7af4cc3fa [NETFILTER]: Add ... |
165 166 |
__instance_destroy(struct nfqnl_instance *inst) { |
9872bec77 [NETFILTER]: nfne... |
167 168 |
hlist_del_rcu(&inst->hlist); call_rcu(&inst->rcu, instance_destroy_rcu); |
7af4cc3fa [NETFILTER]: Add ... |
169 |
} |
9872bec77 [NETFILTER]: nfne... |
170 |
static void |
e81796104 netfilter: nfnetl... |
171 |
instance_destroy(struct nfnl_queue_net *q, struct nfqnl_instance *inst) |
7af4cc3fa [NETFILTER]: Add ... |
172 |
{ |
e81796104 netfilter: nfnetl... |
173 |
spin_lock(&q->instances_lock); |
9872bec77 [NETFILTER]: nfne... |
174 |
__instance_destroy(inst); |
e81796104 netfilter: nfnetl... |
175 |
spin_unlock(&q->instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
176 |
} |
7af4cc3fa [NETFILTER]: Add ... |
177 |
static inline void |
02f014d88 [NETFILTER]: nf_q... |
178 |
__enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) |
7af4cc3fa [NETFILTER]: Add ... |
179 |
{ |
0ac41e814 [NETFILTER]: {nf_... |
180 |
list_add_tail(&entry->list, &queue->queue_list); |
7af4cc3fa [NETFILTER]: Add ... |
181 182 |
queue->queue_total++; } |
97d32cf94 netfilter: nfnetl... |
183 184 185 186 187 188 |
static void __dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry) { list_del(&entry->list); queue->queue_total--; } |
02f014d88 [NETFILTER]: nf_q... |
189 |
static struct nf_queue_entry * |
b43d8d859 [NETFILTER]: nfne... |
190 |
find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) |
7af4cc3fa [NETFILTER]: Add ... |
191 |
{ |
02f014d88 [NETFILTER]: nf_q... |
192 |
struct nf_queue_entry *entry = NULL, *i; |
601e68e10 [NETFILTER]: Fix ... |
193 |
|
7af4cc3fa [NETFILTER]: Add ... |
194 |
spin_lock_bh(&queue->lock); |
b43d8d859 [NETFILTER]: nfne... |
195 196 197 198 199 200 201 |
list_for_each_entry(i, &queue->queue_list, list) { if (i->id == id) { entry = i; break; } } |
97d32cf94 netfilter: nfnetl... |
202 203 |
if (entry) __dequeue_entry(queue, entry); |
b43d8d859 [NETFILTER]: nfne... |
204 |
|
7af4cc3fa [NETFILTER]: Add ... |
205 206 207 208 |
spin_unlock_bh(&queue->lock); return entry; } |
368982cd7 netfilter: nfnetl... |
209 210 211 212 213 214 |
static void nfqnl_reinject(struct nf_queue_entry *entry, unsigned int verdict) { struct nf_ct_hook *ct_hook; int err; if (verdict == NF_ACCEPT || |
ad18d7bf6 netfilter: nfnetl... |
215 |
verdict == NF_REPEAT || |
368982cd7 netfilter: nfnetl... |
216 217 218 219 220 221 222 223 224 225 226 227 |
verdict == NF_STOP) { rcu_read_lock(); ct_hook = rcu_dereference(nf_ct_hook); if (ct_hook) { err = ct_hook->update(entry->state.net, entry->skb); if (err < 0) verdict = NF_DROP; } rcu_read_unlock(); } nf_reinject(entry, verdict); } |
7af4cc3fa [NETFILTER]: Add ... |
228 |
static void |
b43d8d859 [NETFILTER]: nfne... |
229 |
nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data) |
7af4cc3fa [NETFILTER]: Add ... |
230 |
{ |
02f014d88 [NETFILTER]: nf_q... |
231 |
struct nf_queue_entry *entry, *next; |
b43d8d859 [NETFILTER]: nfne... |
232 |
|
7af4cc3fa [NETFILTER]: Add ... |
233 |
spin_lock_bh(&queue->lock); |
b43d8d859 [NETFILTER]: nfne... |
234 235 236 237 |
list_for_each_entry_safe(entry, next, &queue->queue_list, list) { if (!cmpfn || cmpfn(entry, data)) { list_del(&entry->list); queue->queue_total--; |
368982cd7 netfilter: nfnetl... |
238 |
nfqnl_reinject(entry, NF_DROP); |
b43d8d859 [NETFILTER]: nfne... |
239 240 |
} } |
7af4cc3fa [NETFILTER]: Add ... |
241 242 |
spin_unlock_bh(&queue->lock); } |
496e4ae7d netfilter: nf_que... |
243 244 245 |
static int nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet, bool csum_verify) |
7237190df netfilter: nfnetl... |
246 247 248 249 250 |
{ __u32 flags = 0; if (packet->ip_summed == CHECKSUM_PARTIAL) flags = NFQA_SKB_CSUMNOTREADY; |
496e4ae7d netfilter: nf_que... |
251 252 |
else if (csum_verify) flags = NFQA_SKB_CSUM_NOTVERIFIED; |
7237190df netfilter: nfnetl... |
253 254 255 256 257 |
if (skb_is_gso(packet)) flags |= NFQA_SKB_GSO; return flags ? nla_put_be32(nlskb, NFQA_SKB_INFO, htonl(flags)) : 0; } |
08c0cad69 netfilter: nfnetl... |
258 259 260 |
static int nfqnl_put_sk_uidgid(struct sk_buff *skb, struct sock *sk) { const struct cred *cred; |
a8399231f netfilter: use sk... |
261 |
if (!sk_fullsock(sk)) |
08c0cad69 netfilter: nfnetl... |
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
return 0; read_lock_bh(&sk->sk_callback_lock); if (sk->sk_socket && sk->sk_socket->file) { cred = sk->sk_socket->file->f_cred; if (nla_put_be32(skb, NFQA_UID, htonl(from_kuid_munged(&init_user_ns, cred->fsuid)))) goto nla_put_failure; if (nla_put_be32(skb, NFQA_GID, htonl(from_kgid_munged(&init_user_ns, cred->fsgid)))) goto nla_put_failure; } read_unlock_bh(&sk->sk_callback_lock); return 0; nla_put_failure: read_unlock_bh(&sk->sk_callback_lock); return -1; } |
ef493bd93 netfilter: nfnetl... |
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
static u32 nfqnl_get_sk_secctx(struct sk_buff *skb, char **secdata) { u32 seclen = 0; #if IS_ENABLED(CONFIG_NETWORK_SECMARK) if (!skb || !sk_fullsock(skb->sk)) return 0; read_lock_bh(&skb->sk->sk_callback_lock); if (skb->secmark) security_secid_to_secctx(skb->secmark, secdata, &seclen); read_unlock_bh(&skb->sk->sk_callback_lock); #endif return seclen; } |
15824ab29 netfilter: bridge... |
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 |
static u32 nfqnl_get_bridge_size(struct nf_queue_entry *entry) { struct sk_buff *entskb = entry->skb; u32 nlalen = 0; if (entry->state.pf != PF_BRIDGE || !skb_mac_header_was_set(entskb)) return 0; if (skb_vlan_tag_present(entskb)) nlalen += nla_total_size(nla_total_size(sizeof(__be16)) + nla_total_size(sizeof(__be16))); if (entskb->network_header > entskb->mac_header) nlalen += nla_total_size((entskb->network_header - entskb->mac_header)); return nlalen; } static int nfqnl_put_bridge(struct nf_queue_entry *entry, struct sk_buff *skb) { struct sk_buff *entskb = entry->skb; if (entry->state.pf != PF_BRIDGE || !skb_mac_header_was_set(entskb)) return 0; if (skb_vlan_tag_present(entskb)) { struct nlattr *nest; |
ae0be8de9 netlink: make nla... |
325 |
nest = nla_nest_start(skb, NFQA_VLAN); |
15824ab29 netfilter: bridge... |
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
if (!nest) goto nla_put_failure; if (nla_put_be16(skb, NFQA_VLAN_TCI, htons(entskb->vlan_tci)) || nla_put_be16(skb, NFQA_VLAN_PROTO, entskb->vlan_proto)) goto nla_put_failure; nla_nest_end(skb, nest); } if (entskb->mac_header < entskb->network_header) { int len = (int)(entskb->network_header - entskb->mac_header); if (nla_put(skb, NFQA_L2HDR, len, skb_mac_header(entskb))) goto nla_put_failure; } return 0; nla_put_failure: return -1; } |
7af4cc3fa [NETFILTER]: Add ... |
348 |
static struct sk_buff * |
743326878 netfilter: nfnetl... |
349 |
nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, |
5863702a3 netfilter: nfnetl... |
350 351 |
struct nf_queue_entry *entry, __be32 **packet_id_ptr) |
7af4cc3fa [NETFILTER]: Add ... |
352 |
{ |
7af4cc3fa [NETFILTER]: Add ... |
353 |
size_t size; |
c5b0db326 nfnetlink: Revert... |
354 |
size_t data_len = 0, cap_len = 0; |
af2806f8f net: Export skb_z... |
355 |
unsigned int hlen = 0; |
7af4cc3fa [NETFILTER]: Add ... |
356 |
struct sk_buff *skb; |
5863702a3 netfilter: nfnetl... |
357 358 |
struct nlattr *nla; struct nfqnl_msg_packet_hdr *pmsg; |
7af4cc3fa [NETFILTER]: Add ... |
359 360 |
struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; |
3e4ead4fe [NETFILTER]: Decr... |
361 362 363 |
struct sk_buff *entskb = entry->skb; struct net_device *indev; struct net_device *outdev; |
9cb017665 netfilter: add gl... |
364 |
struct nf_conn *ct = NULL; |
3f649ab72 treewide: Remove ... |
365 |
enum ip_conntrack_info ctinfo; |
a4b4766c3 netfilter: nfnetl... |
366 |
struct nfnl_ct_hook *nfnl_ct; |
496e4ae7d netfilter: nf_que... |
367 |
bool csum_verify; |
ef493bd93 netfilter: nfnetl... |
368 369 |
char *secdata = NULL; u32 seclen = 0; |
7af4cc3fa [NETFILTER]: Add ... |
370 |
|
7e59b3fea netfilter: remove... |
371 |
size = nlmsg_total_size(sizeof(struct nfgenmsg)) |
df6fb868d [NETFILTER]: nfne... |
372 373 374 |
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hdr)) + nla_total_size(sizeof(u_int32_t)) /* ifindex */ + nla_total_size(sizeof(u_int32_t)) /* ifindex */ |
1109a90c0 netfilter: use IS... |
375 |
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
df6fb868d [NETFILTER]: nfne... |
376 377 |
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */ + nla_total_size(sizeof(u_int32_t)) /* ifindex */ |
fbcd923c3 [NETFILTER]: add ... |
378 |
#endif |
df6fb868d [NETFILTER]: nfne... |
379 380 |
+ nla_total_size(sizeof(u_int32_t)) /* mark */ + nla_total_size(sizeof(struct nfqnl_msg_packet_hw)) |
7237190df netfilter: nfnetl... |
381 |
+ nla_total_size(sizeof(u_int32_t)) /* skbinfo */ |
ae08ce002 netfilter: nfnetl... |
382 |
+ nla_total_size(sizeof(u_int32_t)); /* cap_len */ |
2456e8553 ktime: Get rid of... |
383 |
if (entskb->tstamp) |
ae08ce002 netfilter: nfnetl... |
384 |
size += nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)); |
7af4cc3fa [NETFILTER]: Add ... |
385 |
|
15824ab29 netfilter: bridge... |
386 |
size += nfqnl_get_bridge_size(entry); |
1d1de89b9 netfilter: Use nf... |
387 388 |
if (entry->state.hook <= NF_INET_FORWARD || (entry->state.hook == NF_INET_POST_ROUTING && entskb->sk == NULL)) |
496e4ae7d netfilter: nf_que... |
389 390 391 |
csum_verify = !skb_csum_unnecessary(entskb); else csum_verify = false; |
1d1de89b9 netfilter: Use nf... |
392 |
outdev = entry->state.out; |
3e4ead4fe [NETFILTER]: Decr... |
393 |
|
14cd5d4a0 locking/atomics, ... |
394 |
switch ((enum nfqnl_config_mode)READ_ONCE(queue->copy_mode)) { |
7af4cc3fa [NETFILTER]: Add ... |
395 396 |
case NFQNL_COPY_META: case NFQNL_COPY_NONE: |
7af4cc3fa [NETFILTER]: Add ... |
397 |
break; |
601e68e10 [NETFILTER]: Fix ... |
398 |
|
7af4cc3fa [NETFILTER]: Add ... |
399 |
case NFQNL_COPY_PACKET: |
00bd1cc24 netfilter: nfnetl... |
400 401 |
if (!(queue->flags & NFQA_CFG_F_GSO) && entskb->ip_summed == CHECKSUM_PARTIAL && |
c463ac972 netfilter: nfnetl... |
402 |
skb_checksum_help(entskb)) |
e7dfb09a3 [NETFILTER]: Fix ... |
403 |
return NULL; |
c463ac972 netfilter: nfnetl... |
404 |
|
14cd5d4a0 locking/atomics, ... |
405 |
data_len = READ_ONCE(queue->copy_range); |
9cefbbc9c netfilter: nfnetl... |
406 |
if (data_len > entskb->len) |
3e4ead4fe [NETFILTER]: Decr... |
407 |
data_len = entskb->len; |
601e68e10 [NETFILTER]: Fix ... |
408 |
|
af2806f8f net: Export skb_z... |
409 410 |
hlen = skb_zerocopy_headlen(entskb); hlen = min_t(unsigned int, hlen, data_len); |
ae08ce002 netfilter: nfnetl... |
411 |
size += sizeof(struct nlattr) + hlen; |
6ee584be3 netfilter: nfnetl... |
412 |
cap_len = entskb->len; |
7af4cc3fa [NETFILTER]: Add ... |
413 |
break; |
7af4cc3fa [NETFILTER]: Add ... |
414 |
} |
8e662164a netfilter: nfnetl... |
415 |
nfnl_ct = rcu_dereference(nfnl_ct_hook); |
b7bd1809e netfilter: nfnetl... |
416 |
if (queue->flags & NFQA_CFG_F_CONNTRACK) { |
a4b4766c3 netfilter: nfnetl... |
417 418 |
if (nfnl_ct != NULL) { ct = nfnl_ct->get_ct(entskb, &ctinfo); |
b7bd1809e netfilter: nfnetl... |
419 |
if (ct != NULL) |
a4b4766c3 netfilter: nfnetl... |
420 |
size += nfnl_ct->build_size(ct); |
b7bd1809e netfilter: nfnetl... |
421 422 |
} } |
7af4cc3fa [NETFILTER]: Add ... |
423 |
|
08c0cad69 netfilter: nfnetl... |
424 |
if (queue->flags & NFQA_CFG_F_UID_GID) { |
7e59b3fea netfilter: remove... |
425 |
size += (nla_total_size(sizeof(u_int32_t)) /* uid */ |
08c0cad69 netfilter: nfnetl... |
426 427 |
+ nla_total_size(sizeof(u_int32_t))); /* gid */ } |
ef493bd93 netfilter: nfnetl... |
428 429 430 431 432 |
if ((queue->flags & NFQA_CFG_F_SECCTX) && entskb->sk) { seclen = nfqnl_get_sk_secctx(entskb, &secdata); if (seclen) size += nla_total_size(seclen); } |
c5b0db326 nfnetlink: Revert... |
433 |
skb = alloc_skb(size, GFP_ATOMIC); |
36d5fe6a0 core, nfqueue, op... |
434 435 |
if (!skb) { skb_tx_error(entskb); |
77c1c03c5 netfilter: nfnetl... |
436 |
goto nlmsg_failure; |
36d5fe6a0 core, nfqueue, op... |
437 |
} |
601e68e10 [NETFILTER]: Fix ... |
438 |
|
3da07c0c2 netfilter: nfnetl... |
439 |
nlh = nlmsg_put(skb, 0, 0, |
dedb67c4b netfilter: Add nf... |
440 |
nfnl_msg_type(NFNL_SUBSYS_QUEUE, NFQNL_MSG_PACKET), |
3da07c0c2 netfilter: nfnetl... |
441 442 |
sizeof(struct nfgenmsg), 0); if (!nlh) { |
36d5fe6a0 core, nfqueue, op... |
443 |
skb_tx_error(entskb); |
3da07c0c2 netfilter: nfnetl... |
444 |
kfree_skb(skb); |
77c1c03c5 netfilter: nfnetl... |
445 |
goto nlmsg_failure; |
3da07c0c2 netfilter: nfnetl... |
446 447 |
} nfmsg = nlmsg_data(nlh); |
1d1de89b9 netfilter: Use nf... |
448 |
nfmsg->nfgen_family = entry->state.pf; |
7af4cc3fa [NETFILTER]: Add ... |
449 450 |
nfmsg->version = NFNETLINK_V0; nfmsg->res_id = htons(queue->queue_num); |
5863702a3 netfilter: nfnetl... |
451 452 453 |
nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg)); pmsg = nla_data(nla); pmsg->hw_protocol = entskb->protocol; |
1d1de89b9 netfilter: Use nf... |
454 |
pmsg->hook = entry->state.hook; |
5863702a3 netfilter: nfnetl... |
455 |
*packet_id_ptr = &pmsg->packet_id; |
7af4cc3fa [NETFILTER]: Add ... |
456 |
|
1d1de89b9 netfilter: Use nf... |
457 |
indev = entry->state.in; |
3e4ead4fe [NETFILTER]: Decr... |
458 |
if (indev) { |
1109a90c0 netfilter: use IS... |
459 |
#if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
a447189e0 nfnetlink_queue: ... |
460 461 |
if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex))) goto nla_put_failure; |
fbcd923c3 [NETFILTER]: add ... |
462 |
#else |
1d1de89b9 netfilter: Use nf... |
463 |
if (entry->state.pf == PF_BRIDGE) { |
fbcd923c3 [NETFILTER]: add ... |
464 |
/* Case 1: indev is physical input device, we need to |
601e68e10 [NETFILTER]: Fix ... |
465 |
* look for bridge group (when called from |
fbcd923c3 [NETFILTER]: add ... |
466 |
* netfilter_bridge) */ |
a447189e0 nfnetlink_queue: ... |
467 468 |
if (nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV, htonl(indev->ifindex)) || |
fbcd923c3 [NETFILTER]: add ... |
469 |
/* this is the bridge group "brX" */ |
f350a0a87 bridge: use rx_ha... |
470 |
/* rcu_read_lock()ed by __nf_queue */ |
a447189e0 nfnetlink_queue: ... |
471 472 473 |
nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(br_port_get_rcu(indev)->br->dev->ifindex))) goto nla_put_failure; |
fbcd923c3 [NETFILTER]: add ... |
474 |
} else { |
c737b7c45 netfilter: bridge... |
475 |
int physinif; |
fbcd923c3 [NETFILTER]: add ... |
476 477 |
/* Case 2: indev is bridge group, we need to look for * physical device (when called from ipv4) */ |
a447189e0 nfnetlink_queue: ... |
478 479 480 |
if (nla_put_be32(skb, NFQA_IFINDEX_INDEV, htonl(indev->ifindex))) goto nla_put_failure; |
c737b7c45 netfilter: bridge... |
481 482 483 |
physinif = nf_bridge_get_physinif(entskb); if (physinif && |
a447189e0 nfnetlink_queue: ... |
484 |
nla_put_be32(skb, NFQA_IFINDEX_PHYSINDEV, |
c737b7c45 netfilter: bridge... |
485 |
htonl(physinif))) |
a447189e0 nfnetlink_queue: ... |
486 |
goto nla_put_failure; |
fbcd923c3 [NETFILTER]: add ... |
487 488 |
} #endif |
7af4cc3fa [NETFILTER]: Add ... |
489 |
} |
3e4ead4fe [NETFILTER]: Decr... |
490 |
if (outdev) { |
1109a90c0 netfilter: use IS... |
491 |
#if !IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
a447189e0 nfnetlink_queue: ... |
492 493 |
if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex))) goto nla_put_failure; |
fbcd923c3 [NETFILTER]: add ... |
494 |
#else |
1d1de89b9 netfilter: Use nf... |
495 |
if (entry->state.pf == PF_BRIDGE) { |
fbcd923c3 [NETFILTER]: add ... |
496 |
/* Case 1: outdev is physical output device, we need to |
601e68e10 [NETFILTER]: Fix ... |
497 |
* look for bridge group (when called from |
fbcd923c3 [NETFILTER]: add ... |
498 |
* netfilter_bridge) */ |
a447189e0 nfnetlink_queue: ... |
499 500 |
if (nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV, htonl(outdev->ifindex)) || |
fbcd923c3 [NETFILTER]: add ... |
501 |
/* this is the bridge group "brX" */ |
f350a0a87 bridge: use rx_ha... |
502 |
/* rcu_read_lock()ed by __nf_queue */ |
a447189e0 nfnetlink_queue: ... |
503 504 505 |
nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(br_port_get_rcu(outdev)->br->dev->ifindex))) goto nla_put_failure; |
fbcd923c3 [NETFILTER]: add ... |
506 |
} else { |
c737b7c45 netfilter: bridge... |
507 |
int physoutif; |
fbcd923c3 [NETFILTER]: add ... |
508 509 |
/* Case 2: outdev is bridge group, we need to look for * physical output device (when called from ipv4) */ |
a447189e0 nfnetlink_queue: ... |
510 511 512 |
if (nla_put_be32(skb, NFQA_IFINDEX_OUTDEV, htonl(outdev->ifindex))) goto nla_put_failure; |
c737b7c45 netfilter: bridge... |
513 514 515 |
physoutif = nf_bridge_get_physoutif(entskb); if (physoutif && |
a447189e0 nfnetlink_queue: ... |
516 |
nla_put_be32(skb, NFQA_IFINDEX_PHYSOUTDEV, |
c737b7c45 netfilter: bridge... |
517 |
htonl(physoutif))) |
a447189e0 nfnetlink_queue: ... |
518 |
goto nla_put_failure; |
fbcd923c3 [NETFILTER]: add ... |
519 520 |
} #endif |
7af4cc3fa [NETFILTER]: Add ... |
521 |
} |
a447189e0 nfnetlink_queue: ... |
522 523 524 |
if (entskb->mark && nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark))) goto nla_put_failure; |
7af4cc3fa [NETFILTER]: Add ... |
525 |
|
2c38de4c1 netfilter: fix lo... |
526 527 |
if (indev && entskb->dev && entskb->mac_header != entskb->network_header) { |
7af4cc3fa [NETFILTER]: Add ... |
528 |
struct nfqnl_msg_packet_hw phw; |
e4d091d7b netfilter: nfnetl... |
529 530 531 532 |
int len; memset(&phw, 0, sizeof(phw)); len = dev_parse_header(entskb, phw.hw_addr); |
b95cce357 [NET]: Wrap hard_... |
533 534 |
if (len) { phw.hw_addrlen = htons(len); |
a447189e0 nfnetlink_queue: ... |
535 536 |
if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw)) goto nla_put_failure; |
b95cce357 [NET]: Wrap hard_... |
537 |
} |
7af4cc3fa [NETFILTER]: Add ... |
538 |
} |
15824ab29 netfilter: bridge... |
539 540 |
if (nfqnl_put_bridge(entry, skb) < 0) goto nla_put_failure; |
916f6efae netfilter: never ... |
541 |
if (entry->state.hook <= NF_INET_FORWARD && entskb->tstamp) { |
7af4cc3fa [NETFILTER]: Add ... |
542 |
struct nfqnl_msg_packet_timestamp ts; |
a7f188455 netfilter: nfnetl... |
543 |
struct timespec64 kts = ktime_to_timespec64(entskb->tstamp); |
b28b1e826 netfilter: nfnetl... |
544 545 546 |
ts.sec = cpu_to_be64(kts.tv_sec); ts.usec = cpu_to_be64(kts.tv_nsec / NSEC_PER_USEC); |
7af4cc3fa [NETFILTER]: Add ... |
547 |
|
a447189e0 nfnetlink_queue: ... |
548 549 |
if (nla_put(skb, NFQA_TIMESTAMP, sizeof(ts), &ts)) goto nla_put_failure; |
7af4cc3fa [NETFILTER]: Add ... |
550 |
} |
08c0cad69 netfilter: nfnetl... |
551 552 553 |
if ((queue->flags & NFQA_CFG_F_UID_GID) && entskb->sk && nfqnl_put_sk_uidgid(skb, entskb->sk) < 0) goto nla_put_failure; |
ef493bd93 netfilter: nfnetl... |
554 555 |
if (seclen && nla_put(skb, NFQA_SECCTX, seclen, secdata)) goto nla_put_failure; |
a4b4766c3 netfilter: nfnetl... |
556 |
if (ct && nfnl_ct->build(skb, ct, ctinfo, NFQA_CT, NFQA_CT_INFO) < 0) |
ae08ce002 netfilter: nfnetl... |
557 |
goto nla_put_failure; |
7f87712c0 netfilter: nfnetl... |
558 559 |
if (cap_len > data_len && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len))) |
ae08ce002 netfilter: nfnetl... |
560 |
goto nla_put_failure; |
496e4ae7d netfilter: nf_que... |
561 |
if (nfqnl_put_packet_info(skb, entskb, csum_verify)) |
7237190df netfilter: nfnetl... |
562 |
goto nla_put_failure; |
7af4cc3fa [NETFILTER]: Add ... |
563 |
if (data_len) { |
df6fb868d [NETFILTER]: nfne... |
564 |
struct nlattr *nla; |
7af4cc3fa [NETFILTER]: Add ... |
565 |
|
ae08ce002 netfilter: nfnetl... |
566 567 |
if (skb_tailroom(skb) < sizeof(*nla) + hlen) goto nla_put_failure; |
7af4cc3fa [NETFILTER]: Add ... |
568 |
|
4df864c1d networking: make ... |
569 |
nla = skb_put(skb, sizeof(*nla)); |
df6fb868d [NETFILTER]: nfne... |
570 |
nla->nla_type = NFQA_PAYLOAD; |
ae08ce002 netfilter: nfnetl... |
571 |
nla->nla_len = nla_attr_size(data_len); |
7af4cc3fa [NETFILTER]: Add ... |
572 |
|
36d5fe6a0 core, nfqueue, op... |
573 574 |
if (skb_zerocopy(skb, entskb, data_len, hlen)) goto nla_put_failure; |
7af4cc3fa [NETFILTER]: Add ... |
575 |
} |
601e68e10 [NETFILTER]: Fix ... |
576 |
|
ae08ce002 netfilter: nfnetl... |
577 |
nlh->nlmsg_len = skb->len; |
77c1c03c5 netfilter: nfnetl... |
578 579 |
if (seclen) security_release_secctx(secdata, seclen); |
7af4cc3fa [NETFILTER]: Add ... |
580 |
return skb; |
df6fb868d [NETFILTER]: nfne... |
581 |
nla_put_failure: |
36d5fe6a0 core, nfqueue, op... |
582 |
skb_tx_error(entskb); |
a67299556 netfilter: nfnetl... |
583 |
kfree_skb(skb); |
e87cc4728 net: Convert net_... |
584 585 |
net_err_ratelimited("nf_queue: error creating packet message "); |
77c1c03c5 netfilter: nfnetl... |
586 587 588 |
nlmsg_failure: if (seclen) security_release_secctx(secdata, seclen); |
7af4cc3fa [NETFILTER]: Add ... |
589 590 |
return NULL; } |
5da773a3e netfilter: nfnetl... |
591 592 593 594 595 596 597 598 599 600 601 |
static bool nf_ct_drop_unconfirmed(const struct nf_queue_entry *entry) { #if IS_ENABLED(CONFIG_NF_CONNTRACK) static const unsigned long flags = IPS_CONFIRMED | IPS_DYING; const struct nf_conn *ct = (void *)skb_nfct(entry->skb); if (ct && ((ct->status & flags) == IPS_DYING)) return true; #endif return false; } |
7af4cc3fa [NETFILTER]: Add ... |
602 |
static int |
a5fedd43d netfilter: move s... |
603 604 |
__nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, struct nf_queue_entry *entry) |
7af4cc3fa [NETFILTER]: Add ... |
605 |
{ |
7af4cc3fa [NETFILTER]: Add ... |
606 |
struct sk_buff *nskb; |
f15850861 netfilter: nfnetl... |
607 |
int err = -ENOBUFS; |
5863702a3 netfilter: nfnetl... |
608 |
__be32 *packet_id_ptr; |
fdb694a01 netfilter: Add fa... |
609 |
int failopen = 0; |
7af4cc3fa [NETFILTER]: Add ... |
610 |
|
743326878 netfilter: nfnetl... |
611 |
nskb = nfqnl_build_packet_message(net, queue, entry, &packet_id_ptr); |
f15850861 netfilter: nfnetl... |
612 613 |
if (nskb == NULL) { err = -ENOMEM; |
0ef0f4658 [NETFILTER]: nfne... |
614 |
goto err_out; |
f15850861 netfilter: nfnetl... |
615 |
} |
7af4cc3fa [NETFILTER]: Add ... |
616 |
spin_lock_bh(&queue->lock); |
601e68e10 [NETFILTER]: Fix ... |
617 |
|
5da773a3e netfilter: nfnetl... |
618 619 |
if (nf_ct_drop_unconfirmed(entry)) goto err_out_free_nskb; |
7af4cc3fa [NETFILTER]: Add ... |
620 |
if (queue->queue_total >= queue->queue_maxlen) { |
fdb694a01 netfilter: Add fa... |
621 622 623 624 625 626 627 628 629 |
if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { failopen = 1; err = 0; } else { queue->queue_dropped++; net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s) ", queue->queue_total); } |
7af4cc3fa [NETFILTER]: Add ... |
630 631 |
goto err_out_free_nskb; } |
5863702a3 netfilter: nfnetl... |
632 633 |
entry->id = ++queue->id_sequence; *packet_id_ptr = htonl(entry->id); |
7af4cc3fa [NETFILTER]: Add ... |
634 635 |
/* nfnetlink_unicast will either free the nskb or add it to a socket */ |
ee9211835 netfilter: nfnetl... |
636 |
err = nfnetlink_unicast(nskb, net, queue->peer_portid); |
0ef0f4658 [NETFILTER]: nfne... |
637 |
if (err < 0) { |
931401137 netfilter: nfnetl... |
638 639 640 641 642 643 |
if (queue->flags & NFQA_CFG_F_FAIL_OPEN) { failopen = 1; err = 0; } else { queue->queue_user_dropped++; } |
7af4cc3fa [NETFILTER]: Add ... |
644 645 646 647 648 649 |
goto err_out_unlock; } __enqueue_entry(queue, entry); spin_unlock_bh(&queue->lock); |
0ef0f4658 [NETFILTER]: nfne... |
650 |
return 0; |
7af4cc3fa [NETFILTER]: Add ... |
651 652 |
err_out_free_nskb: |
601e68e10 [NETFILTER]: Fix ... |
653 |
kfree_skb(nskb); |
7af4cc3fa [NETFILTER]: Add ... |
654 655 |
err_out_unlock: spin_unlock_bh(&queue->lock); |
fdb694a01 netfilter: Add fa... |
656 |
if (failopen) |
368982cd7 netfilter: nfnetl... |
657 |
nfqnl_reinject(entry, NF_ACCEPT); |
0ef0f4658 [NETFILTER]: nfne... |
658 |
err_out: |
f15850861 netfilter: nfnetl... |
659 |
return err; |
7af4cc3fa [NETFILTER]: Add ... |
660 |
} |
a5fedd43d netfilter: move s... |
661 662 663 664 |
static struct nf_queue_entry * nf_queue_entry_dup(struct nf_queue_entry *e) { struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC); |
ed78d09d5 netfilter: make n... |
665 666 667 |
if (entry) nf_queue_entry_get_refs(entry); return entry; |
a5fedd43d netfilter: move s... |
668 |
} |
1109a90c0 netfilter: use IS... |
669 |
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
a5fedd43d netfilter: move s... |
670 671 672 673 674 675 |
/* When called from bridge netfilter, skb->data must point to MAC header * before calling skb_gso_segment(). Else, original MAC header is lost * and segmented skbs will be sent to wrong destination. */ static void nf_bridge_adjust_skb_data(struct sk_buff *skb) { |
c4b0e771f netfilter: avoid ... |
676 |
if (nf_bridge_info_get(skb)) |
a5fedd43d netfilter: move s... |
677 678 679 680 681 |
__skb_push(skb, skb->network_header - skb->mac_header); } static void nf_bridge_adjust_segmented_data(struct sk_buff *skb) { |
c4b0e771f netfilter: avoid ... |
682 |
if (nf_bridge_info_get(skb)) |
a5fedd43d netfilter: move s... |
683 684 685 686 687 688 |
__skb_pull(skb, skb->network_header - skb->mac_header); } #else #define nf_bridge_adjust_skb_data(s) do {} while (0) #define nf_bridge_adjust_segmented_data(s) do {} while (0) #endif |
a5fedd43d netfilter: move s... |
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
static int __nfqnl_enqueue_packet_gso(struct net *net, struct nfqnl_instance *queue, struct sk_buff *skb, struct nf_queue_entry *entry) { int ret = -ENOMEM; struct nf_queue_entry *entry_seg; nf_bridge_adjust_segmented_data(skb); if (skb->next == NULL) { /* last packet, no need to copy entry */ struct sk_buff *gso_skb = entry->skb; entry->skb = skb; ret = __nfqnl_enqueue_packet(net, queue, entry); if (ret) entry->skb = gso_skb; return ret; } |
a8305bff6 net: Add and use ... |
706 |
skb_mark_not_on_list(skb); |
a5fedd43d netfilter: move s... |
707 708 709 710 711 712 |
entry_seg = nf_queue_entry_dup(entry); if (entry_seg) { entry_seg->skb = skb; ret = __nfqnl_enqueue_packet(net, queue, entry_seg); if (ret) |
dd3cc111f netfilter: nf_que... |
713 |
nf_queue_entry_free(entry_seg); |
a5fedd43d netfilter: move s... |
714 715 716 717 718 719 720 721 722 |
} return ret; } static int nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) { unsigned int queued; struct nfqnl_instance *queue; |
2670ee77c net: netfilter: u... |
723 |
struct sk_buff *skb, *segs, *nskb; |
a5fedd43d netfilter: move s... |
724 |
int err = -ENOBUFS; |
9dff2c966 netfilter: Use nf... |
725 |
struct net *net = entry->state.net; |
a5fedd43d netfilter: move s... |
726 |
struct nfnl_queue_net *q = nfnl_queue_pernet(net); |
e2361cb90 netfilter: Remove... |
727 |
/* rcu_read_lock()ed by nf_hook_thresh */ |
a5fedd43d netfilter: move s... |
728 729 730 731 732 733 |
queue = instance_lookup(q, queuenum); if (!queue) return -ESRCH; if (queue->copy_mode == NFQNL_COPY_NONE) return -EINVAL; |
a5fedd43d netfilter: move s... |
734 |
skb = entry->skb; |
1d1de89b9 netfilter: Use nf... |
735 |
switch (entry->state.pf) { |
a5fedd43d netfilter: move s... |
736 737 738 739 740 741 742 |
case NFPROTO_IPV4: skb->protocol = htons(ETH_P_IP); break; case NFPROTO_IPV6: skb->protocol = htons(ETH_P_IPV6); break; } |
7b8dfe289 netfilter: nfnetl... |
743 744 |
if ((queue->flags & NFQA_CFG_F_GSO) || !skb_is_gso(skb)) return __nfqnl_enqueue_packet(net, queue, entry); |
a5fedd43d netfilter: move s... |
745 746 747 |
nf_bridge_adjust_skb_data(skb); segs = skb_gso_segment(skb, 0); /* Does not use PTR_ERR to limit the number of error codes that can be |
ed78d09d5 netfilter: make n... |
748 |
* returned by nf_queue. For instance, callers rely on -ESRCH to |
a5fedd43d netfilter: move s... |
749 750 |
* mean 'ignore this hook'. */ |
330966e50 net: make skb_gso... |
751 |
if (IS_ERR_OR_NULL(segs)) |
a5fedd43d netfilter: move s... |
752 753 754 |
goto out_err; queued = 0; err = 0; |
2670ee77c net: netfilter: u... |
755 |
skb_list_walk_safe(segs, segs, nskb) { |
a5fedd43d netfilter: move s... |
756 757 758 759 760 761 762 |
if (err == 0) err = __nfqnl_enqueue_packet_gso(net, queue, segs, entry); if (err == 0) queued++; else kfree_skb(segs); |
2670ee77c net: netfilter: u... |
763 |
} |
a5fedd43d netfilter: move s... |
764 765 766 |
if (queued) { if (err) /* some segments are already queued */ |
dd3cc111f netfilter: nf_que... |
767 |
nf_queue_entry_free(entry); |
a5fedd43d netfilter: move s... |
768 769 770 771 772 773 774 |
kfree_skb(skb); return 0; } out_err: nf_bridge_adjust_segmented_data(skb); return err; } |
7af4cc3fa [NETFILTER]: Add ... |
775 |
static int |
8c88f87cb netfilter: nfnetl... |
776 |
nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff) |
7af4cc3fa [NETFILTER]: Add ... |
777 |
{ |
e2b58a67b [NETFILTER]: {ip,... |
778 |
struct sk_buff *nskb; |
7af4cc3fa [NETFILTER]: Add ... |
779 |
|
d8a585d78 [NETFILTER]: Use ... |
780 781 782 783 |
if (diff < 0) { if (pskb_trim(e->skb, data_len)) return -ENOMEM; } else if (diff > 0) { |
7af4cc3fa [NETFILTER]: Add ... |
784 785 786 |
if (data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { |
9a732ed6d netfilter: {nfnet... |
787 788 |
nskb = skb_copy_expand(e->skb, skb_headroom(e->skb), diff, GFP_ATOMIC); |
5191d70f8 netfilter: Replac... |
789 |
if (!nskb) |
e2b58a67b [NETFILTER]: {ip,... |
790 |
return -ENOMEM; |
e2b58a67b [NETFILTER]: {ip,... |
791 792 |
kfree_skb(e->skb); e->skb = nskb; |
7af4cc3fa [NETFILTER]: Add ... |
793 794 795 |
} skb_put(e->skb, diff); } |
2cf6bffc4 netfilter: replac... |
796 |
if (skb_ensure_writable(e->skb, data_len)) |
7af4cc3fa [NETFILTER]: Add ... |
797 |
return -ENOMEM; |
27d7ff46a [SK_BUFF]: Introd... |
798 |
skb_copy_to_linear_data(e->skb, data, data_len); |
e7dfb09a3 [NETFILTER]: Fix ... |
799 |
e->skb->ip_summed = CHECKSUM_NONE; |
7af4cc3fa [NETFILTER]: Add ... |
800 801 |
return 0; } |
7af4cc3fa [NETFILTER]: Add ... |
802 803 804 805 |
static int nfqnl_set_mode(struct nfqnl_instance *queue, unsigned char mode, unsigned int range) { |
c5de0dfde [NETFILTER]: nfne... |
806 |
int status = 0; |
7af4cc3fa [NETFILTER]: Add ... |
807 808 |
spin_lock_bh(&queue->lock); |
c5de0dfde [NETFILTER]: nfne... |
809 810 811 812 813 814 815 816 817 |
switch (mode) { case NFQNL_COPY_NONE: case NFQNL_COPY_META: queue->copy_mode = mode; queue->copy_range = 0; break; case NFQNL_COPY_PACKET: queue->copy_mode = mode; |
9cefbbc9c netfilter: nfnetl... |
818 819 |
if (range == 0 || range > NFQNL_MAX_COPY_RANGE) queue->copy_range = NFQNL_MAX_COPY_RANGE; |
c5de0dfde [NETFILTER]: nfne... |
820 821 822 823 824 825 826 827 |
else queue->copy_range = range; break; default: status = -EINVAL; } |
7af4cc3fa [NETFILTER]: Add ... |
828 829 830 831 832 833 |
spin_unlock_bh(&queue->lock); return status; } static int |
02f014d88 [NETFILTER]: nf_q... |
834 |
dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
835 |
{ |
c4b0e771f netfilter: avoid ... |
836 837 838 839 840 841 842 843 844 |
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) int physinif, physoutif; physinif = nf_bridge_get_physinif(entry->skb); physoutif = nf_bridge_get_physoutif(entry->skb); if (physinif == ifindex || physoutif == ifindex) return 1; #endif |
1d1de89b9 netfilter: Use nf... |
845 846 |
if (entry->state.in) if (entry->state.in->ifindex == ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
847 |
return 1; |
1d1de89b9 netfilter: Use nf... |
848 849 |
if (entry->state.out) if (entry->state.out->ifindex == ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
850 |
return 1; |
c737b7c45 netfilter: bridge... |
851 |
|
7af4cc3fa [NETFILTER]: Add ... |
852 853 854 855 856 857 |
return 0; } /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void |
e81796104 netfilter: nfnetl... |
858 |
nfqnl_dev_drop(struct net *net, int ifindex) |
7af4cc3fa [NETFILTER]: Add ... |
859 860 |
{ int i; |
e81796104 netfilter: nfnetl... |
861 |
struct nfnl_queue_net *q = nfnl_queue_pernet(net); |
601e68e10 [NETFILTER]: Fix ... |
862 |
|
9872bec77 [NETFILTER]: nfne... |
863 |
rcu_read_lock(); |
7af4cc3fa [NETFILTER]: Add ... |
864 |
|
9872bec77 [NETFILTER]: nfne... |
865 |
for (i = 0; i < INSTANCE_BUCKETS; i++) { |
7af4cc3fa [NETFILTER]: Add ... |
866 |
struct nfqnl_instance *inst; |
e81796104 netfilter: nfnetl... |
867 |
struct hlist_head *head = &q->instance_table[i]; |
7af4cc3fa [NETFILTER]: Add ... |
868 |
|
b67bfe0d4 hlist: drop the n... |
869 |
hlist_for_each_entry_rcu(inst, head, hlist) |
b43d8d859 [NETFILTER]: nfne... |
870 |
nfqnl_flush(inst, dev_cmp, ifindex); |
7af4cc3fa [NETFILTER]: Add ... |
871 |
} |
9872bec77 [NETFILTER]: nfne... |
872 |
rcu_read_unlock(); |
7af4cc3fa [NETFILTER]: Add ... |
873 |
} |
7af4cc3fa [NETFILTER]: Add ... |
874 875 876 877 |
static int nfqnl_rcv_dev_event(struct notifier_block *this, unsigned long event, void *ptr) { |
351638e7d net: pass info st... |
878 |
struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
7af4cc3fa [NETFILTER]: Add ... |
879 880 881 |
/* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) |
e81796104 netfilter: nfnetl... |
882 |
nfqnl_dev_drop(dev_net(dev), dev->ifindex); |
7af4cc3fa [NETFILTER]: Add ... |
883 884 885 886 887 888 |
return NOTIFY_DONE; } static struct notifier_block nfqnl_dev_notifier = { .notifier_call = nfqnl_rcv_dev_event, }; |
26888dfd7 netfilter: core: ... |
889 |
static void nfqnl_nf_hook_drop(struct net *net) |
8405a8fff netfilter: nf_qeu... |
890 891 892 |
{ struct nfnl_queue_net *q = nfnl_queue_pernet(net); int i; |
8405a8fff netfilter: nf_qeu... |
893 894 895 |
for (i = 0; i < INSTANCE_BUCKETS; i++) { struct nfqnl_instance *inst; struct hlist_head *head = &q->instance_table[i]; |
26888dfd7 netfilter: core: ... |
896 |
hlist_for_each_entry_rcu(inst, head, hlist) |
039b40ee5 netfilter: nf_que... |
897 |
nfqnl_flush(inst, NULL, 0); |
8405a8fff netfilter: nf_qeu... |
898 |
} |
8405a8fff netfilter: nf_qeu... |
899 |
} |
7af4cc3fa [NETFILTER]: Add ... |
900 901 902 903 904 |
static int nfqnl_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr) { struct netlink_notify *n = ptr; |
e81796104 netfilter: nfnetl... |
905 |
struct nfnl_queue_net *q = nfnl_queue_pernet(n->net); |
7af4cc3fa [NETFILTER]: Add ... |
906 |
|
dee5817e8 netfilter: remove... |
907 |
if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { |
7af4cc3fa [NETFILTER]: Add ... |
908 |
int i; |
15e473046 netlink: Rename p... |
909 |
/* destroy all instances for this portid */ |
e81796104 netfilter: nfnetl... |
910 |
spin_lock(&q->instances_lock); |
9872bec77 [NETFILTER]: nfne... |
911 |
for (i = 0; i < INSTANCE_BUCKETS; i++) { |
b67bfe0d4 hlist: drop the n... |
912 |
struct hlist_node *t2; |
7af4cc3fa [NETFILTER]: Add ... |
913 |
struct nfqnl_instance *inst; |
e81796104 netfilter: nfnetl... |
914 |
struct hlist_head *head = &q->instance_table[i]; |
7af4cc3fa [NETFILTER]: Add ... |
915 |
|
b67bfe0d4 hlist: drop the n... |
916 |
hlist_for_each_entry_safe(inst, t2, head, hlist) { |
e81796104 netfilter: nfnetl... |
917 |
if (n->portid == inst->peer_portid) |
7af4cc3fa [NETFILTER]: Add ... |
918 919 920 |
__instance_destroy(inst); } } |
e81796104 netfilter: nfnetl... |
921 |
spin_unlock(&q->instances_lock); |
7af4cc3fa [NETFILTER]: Add ... |
922 923 924 925 926 927 928 |
} return NOTIFY_DONE; } static struct notifier_block nfqnl_rtnl_notifier = { .notifier_call = nfqnl_rcv_nl_event, }; |
8d45ff22f netfilter: bridge... |
929 930 931 932 |
static const struct nla_policy nfqa_vlan_policy[NFQA_VLAN_MAX + 1] = { [NFQA_VLAN_TCI] = { .type = NLA_U16}, [NFQA_VLAN_PROTO] = { .type = NLA_U16}, }; |
5bf758539 [NETFILTER]: nfne... |
933 934 935 936 |
static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = { [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, [NFQA_MARK] = { .type = NLA_U32 }, [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, |
9cb017665 netfilter: add gl... |
937 |
[NFQA_CT] = { .type = NLA_UNSPEC }, |
bd0779370 netfilter: nfnetl... |
938 |
[NFQA_EXP] = { .type = NLA_UNSPEC }, |
8d45ff22f netfilter: bridge... |
939 |
[NFQA_VLAN] = { .type = NLA_NESTED }, |
838ab6364 [NETFILTER]: Add ... |
940 |
}; |
97d32cf94 netfilter: nfnetl... |
941 942 943 944 |
static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) }, [NFQA_MARK] = { .type = NLA_U32 }, }; |
e81796104 netfilter: nfnetl... |
945 |
static struct nfqnl_instance * |
cc6bc4486 netfilter: Fix po... |
946 |
verdict_instance_lookup(struct nfnl_queue_net *q, u16 queue_num, u32 nlportid) |
97d32cf94 netfilter: nfnetl... |
947 948 |
{ struct nfqnl_instance *queue; |
e81796104 netfilter: nfnetl... |
949 |
queue = instance_lookup(q, queue_num); |
97d32cf94 netfilter: nfnetl... |
950 951 |
if (!queue) return ERR_PTR(-ENODEV); |
15e473046 netlink: Rename p... |
952 |
if (queue->peer_portid != nlportid) |
97d32cf94 netfilter: nfnetl... |
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 |
return ERR_PTR(-EPERM); return queue; } static struct nfqnl_msg_verdict_hdr* verdicthdr_get(const struct nlattr * const nfqa[]) { struct nfqnl_msg_verdict_hdr *vhdr; unsigned int verdict; if (!nfqa[NFQA_VERDICT_HDR]) return NULL; vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); |
c6675233f netfilter: nf_que... |
968 969 |
verdict = ntohl(vhdr->verdict) & NF_VERDICT_MASK; if (verdict > NF_MAX_VERDICT || verdict == NF_STOLEN) |
97d32cf94 netfilter: nfnetl... |
970 971 972 973 974 975 976 977 |
return NULL; return vhdr; } static int nfq_id_after(unsigned int id, unsigned int max) { return (int)(id - max) > 0; } |
7b8002a15 netfilter: nfnetl... |
978 979 980 |
static int nfqnl_recv_verdict_batch(struct net *net, struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, |
04ba724b6 netfilter: nfnetl... |
981 982 |
const struct nlattr * const nfqa[], struct netlink_ext_ack *extack) |
97d32cf94 netfilter: nfnetl... |
983 |
{ |
3da07c0c2 netfilter: nfnetl... |
984 |
struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
97d32cf94 netfilter: nfnetl... |
985 986 987 988 989 990 |
struct nf_queue_entry *entry, *tmp; unsigned int verdict, maxid; struct nfqnl_msg_verdict_hdr *vhdr; struct nfqnl_instance *queue; LIST_HEAD(batch_list); u16 queue_num = ntohs(nfmsg->res_id); |
e81796104 netfilter: nfnetl... |
991 992 993 994 |
struct nfnl_queue_net *q = nfnl_queue_pernet(net); queue = verdict_instance_lookup(q, queue_num, NETLINK_CB(skb).portid); |
97d32cf94 netfilter: nfnetl... |
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 |
if (IS_ERR(queue)) return PTR_ERR(queue); vhdr = verdicthdr_get(nfqa); if (!vhdr) return -EINVAL; verdict = ntohl(vhdr->verdict); maxid = ntohl(vhdr->id); spin_lock_bh(&queue->lock); list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) { if (nfq_id_after(entry->id, maxid)) break; __dequeue_entry(queue, entry); list_add_tail(&entry->list, &batch_list); } spin_unlock_bh(&queue->lock); if (list_empty(&batch_list)) return -ENOENT; list_for_each_entry_safe(entry, tmp, &batch_list, list) { if (nfqa[NFQA_MARK]) entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); |
368982cd7 netfilter: nfnetl... |
1022 1023 |
nfqnl_reinject(entry, verdict); |
97d32cf94 netfilter: nfnetl... |
1024 1025 1026 |
} return 0; } |
a4b4766c3 netfilter: nfnetl... |
1027 |
static struct nf_conn *nfqnl_ct_parse(struct nfnl_ct_hook *nfnl_ct, |
b7bd1809e netfilter: nfnetl... |
1028 1029 1030 1031 1032 1033 |
const struct nlmsghdr *nlh, const struct nlattr * const nfqa[], struct nf_queue_entry *entry, enum ip_conntrack_info *ctinfo) { struct nf_conn *ct; |
a4b4766c3 netfilter: nfnetl... |
1034 |
ct = nfnl_ct->get_ct(entry->skb, ctinfo); |
b7bd1809e netfilter: nfnetl... |
1035 1036 |
if (ct == NULL) return NULL; |
a4b4766c3 netfilter: nfnetl... |
1037 |
if (nfnl_ct->parse(nfqa[NFQA_CT], ct) < 0) |
b7bd1809e netfilter: nfnetl... |
1038 1039 1040 |
return NULL; if (nfqa[NFQA_EXP]) |
a4b4766c3 netfilter: nfnetl... |
1041 |
nfnl_ct->attach_expect(nfqa[NFQA_EXP], ct, |
b7bd1809e netfilter: nfnetl... |
1042 1043 1044 1045 |
NETLINK_CB(entry->skb).portid, nlmsg_report(nlh)); return ct; } |
8d45ff22f netfilter: bridge... |
1046 1047 1048 1049 1050 1051 |
static int nfqa_parse_bridge(struct nf_queue_entry *entry, const struct nlattr * const nfqa[]) { if (nfqa[NFQA_VLAN]) { struct nlattr *tb[NFQA_VLAN_MAX + 1]; int err; |
8cb081746 netlink: make val... |
1052 1053 1054 |
err = nla_parse_nested_deprecated(tb, NFQA_VLAN_MAX, nfqa[NFQA_VLAN], nfqa_vlan_policy, NULL); |
8d45ff22f netfilter: bridge... |
1055 1056 1057 1058 1059 |
if (err < 0) return err; if (!tb[NFQA_VLAN_TCI] || !tb[NFQA_VLAN_PROTO]) return -EINVAL; |
82eea4cfe nfnetlink/queue: ... |
1060 1061 1062 |
__vlan_hwaccel_put_tag(entry->skb, nla_get_be16(tb[NFQA_VLAN_PROTO]), ntohs(nla_get_be16(tb[NFQA_VLAN_TCI]))); |
8d45ff22f netfilter: bridge... |
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 |
} if (nfqa[NFQA_L2HDR]) { int mac_header_len = entry->skb->network_header - entry->skb->mac_header; if (mac_header_len != nla_len(nfqa[NFQA_L2HDR])) return -EINVAL; else if (mac_header_len > 0) memcpy(skb_mac_header(entry->skb), nla_data(nfqa[NFQA_L2HDR]), mac_header_len); } return 0; } |
7b8002a15 netfilter: nfnetl... |
1079 1080 1081 |
static int nfqnl_recv_verdict(struct net *net, struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, |
04ba724b6 netfilter: nfnetl... |
1082 1083 |
const struct nlattr * const nfqa[], struct netlink_ext_ack *extack) |
7af4cc3fa [NETFILTER]: Add ... |
1084 |
{ |
3da07c0c2 netfilter: nfnetl... |
1085 |
struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
7af4cc3fa [NETFILTER]: Add ... |
1086 |
u_int16_t queue_num = ntohs(nfmsg->res_id); |
7af4cc3fa [NETFILTER]: Add ... |
1087 1088 1089 |
struct nfqnl_msg_verdict_hdr *vhdr; struct nfqnl_instance *queue; unsigned int verdict; |
02f014d88 [NETFILTER]: nf_q... |
1090 |
struct nf_queue_entry *entry; |
3f649ab72 treewide: Remove ... |
1091 |
enum ip_conntrack_info ctinfo; |
a4b4766c3 netfilter: nfnetl... |
1092 |
struct nfnl_ct_hook *nfnl_ct; |
8c88f87cb netfilter: nfnetl... |
1093 |
struct nf_conn *ct = NULL; |
e81796104 netfilter: nfnetl... |
1094 |
struct nfnl_queue_net *q = nfnl_queue_pernet(net); |
8d45ff22f netfilter: bridge... |
1095 |
int err; |
7af4cc3fa [NETFILTER]: Add ... |
1096 |
|
00a3101f5 netfilter: nfnetl... |
1097 1098 |
queue = verdict_instance_lookup(q, queue_num, NETLINK_CB(skb).portid); |
97d32cf94 netfilter: nfnetl... |
1099 1100 |
if (IS_ERR(queue)) return PTR_ERR(queue); |
7af4cc3fa [NETFILTER]: Add ... |
1101 |
|
97d32cf94 netfilter: nfnetl... |
1102 1103 |
vhdr = verdicthdr_get(nfqa); if (!vhdr) |
84a797dd0 netfilter: nfnetl... |
1104 |
return -EINVAL; |
7af4cc3fa [NETFILTER]: Add ... |
1105 |
|
7af4cc3fa [NETFILTER]: Add ... |
1106 |
verdict = ntohl(vhdr->verdict); |
b43d8d859 [NETFILTER]: nfne... |
1107 |
entry = find_dequeue_entry(queue, ntohl(vhdr->id)); |
84a797dd0 netfilter: nfnetl... |
1108 1109 |
if (entry == NULL) return -ENOENT; |
7af4cc3fa [NETFILTER]: Add ... |
1110 |
|
8e662164a netfilter: nfnetl... |
1111 1112 |
/* rcu lock already held from nfnl->call_rcu. */ nfnl_ct = rcu_dereference(nfnl_ct_hook); |
bd0779370 netfilter: nfnetl... |
1113 |
if (nfqa[NFQA_CT]) { |
a4b4766c3 netfilter: nfnetl... |
1114 1115 |
if (nfnl_ct != NULL) ct = nfqnl_ct_parse(nfnl_ct, nlh, nfqa, entry, &ctinfo); |
bd0779370 netfilter: nfnetl... |
1116 |
} |
9cb017665 netfilter: add gl... |
1117 |
|
8d45ff22f netfilter: bridge... |
1118 1119 1120 1121 1122 |
if (entry->state.pf == PF_BRIDGE) { err = nfqa_parse_bridge(entry, nfqa); if (err < 0) return err; } |
df6fb868d [NETFILTER]: nfne... |
1123 |
if (nfqa[NFQA_PAYLOAD]) { |
8c88f87cb netfilter: nfnetl... |
1124 1125 |
u16 payload_len = nla_len(nfqa[NFQA_PAYLOAD]); int diff = payload_len - entry->skb->len; |
df6fb868d [NETFILTER]: nfne... |
1126 |
if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), |
8c88f87cb netfilter: nfnetl... |
1127 |
payload_len, entry, diff) < 0) |
7af4cc3fa [NETFILTER]: Add ... |
1128 |
verdict = NF_DROP; |
8c88f87cb netfilter: nfnetl... |
1129 |
|
b7bd1809e netfilter: nfnetl... |
1130 |
if (ct && diff) |
a4b4766c3 netfilter: nfnetl... |
1131 |
nfnl_ct->seq_adjust(entry->skb, ct, ctinfo, diff); |
7af4cc3fa [NETFILTER]: Add ... |
1132 |
} |
df6fb868d [NETFILTER]: nfne... |
1133 |
if (nfqa[NFQA_MARK]) |
ea3a66ff5 [NETFILTER]: nfne... |
1134 |
entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK])); |
601e68e10 [NETFILTER]: Fix ... |
1135 |
|
368982cd7 netfilter: nfnetl... |
1136 |
nfqnl_reinject(entry, verdict); |
7af4cc3fa [NETFILTER]: Add ... |
1137 1138 |
return 0; } |
7b8002a15 netfilter: nfnetl... |
1139 1140 |
static int nfqnl_recv_unsupp(struct net *net, struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, |
04ba724b6 netfilter: nfnetl... |
1141 1142 |
const struct nlattr * const nfqa[], struct netlink_ext_ack *extack) |
7af4cc3fa [NETFILTER]: Add ... |
1143 1144 1145 |
{ return -ENOTSUPP; } |
5bf758539 [NETFILTER]: nfne... |
1146 1147 1148 |
static const struct nla_policy nfqa_cfg_policy[NFQA_CFG_MAX+1] = { [NFQA_CFG_CMD] = { .len = sizeof(struct nfqnl_msg_config_cmd) }, [NFQA_CFG_PARAMS] = { .len = sizeof(struct nfqnl_msg_config_params) }, |
ba062ebb2 netfilter: nf_que... |
1149 1150 1151 |
[NFQA_CFG_QUEUE_MAXLEN] = { .type = NLA_U32 }, [NFQA_CFG_MASK] = { .type = NLA_U32 }, [NFQA_CFG_FLAGS] = { .type = NLA_U32 }, |
838ab6364 [NETFILTER]: Add ... |
1152 |
}; |
e3ac52981 [NETFILTER]: nf_q... |
1153 |
static const struct nf_queue_handler nfqh = { |
d4ef38354 netfilter: Remove... |
1154 1155 |
.outfn = nfqnl_enqueue_packet, .nf_hook_drop = nfqnl_nf_hook_drop, |
bbd86b9fc [NETFILTER]: add ... |
1156 |
}; |
7b8002a15 netfilter: nfnetl... |
1157 1158 |
static int nfqnl_recv_config(struct net *net, struct sock *ctnl, struct sk_buff *skb, const struct nlmsghdr *nlh, |
04ba724b6 netfilter: nfnetl... |
1159 1160 |
const struct nlattr * const nfqa[], struct netlink_ext_ack *extack) |
7af4cc3fa [NETFILTER]: Add ... |
1161 |
{ |
3da07c0c2 netfilter: nfnetl... |
1162 |
struct nfgenmsg *nfmsg = nlmsg_data(nlh); |
7af4cc3fa [NETFILTER]: Add ... |
1163 1164 |
u_int16_t queue_num = ntohs(nfmsg->res_id); struct nfqnl_instance *queue; |
9872bec77 [NETFILTER]: nfne... |
1165 |
struct nfqnl_msg_config_cmd *cmd = NULL; |
e81796104 netfilter: nfnetl... |
1166 |
struct nfnl_queue_net *q = nfnl_queue_pernet(net); |
60d2c7f9a netfilter: nfnetl... |
1167 |
__u32 flags = 0, mask = 0; |
838ab6364 [NETFILTER]: Add ... |
1168 |
int ret = 0; |
7af4cc3fa [NETFILTER]: Add ... |
1169 |
|
9872bec77 [NETFILTER]: nfne... |
1170 1171 |
if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); |
0360ae412 netfilter: kill s... |
1172 |
/* Obsolete commands without queue context */ |
9872bec77 [NETFILTER]: nfne... |
1173 |
switch (cmd->command) { |
0360ae412 netfilter: kill s... |
1174 1175 |
case NFQNL_CFG_CMD_PF_BIND: return 0; case NFQNL_CFG_CMD_PF_UNBIND: return 0; |
9872bec77 [NETFILTER]: nfne... |
1176 |
} |
9872bec77 [NETFILTER]: nfne... |
1177 |
} |
60d2c7f9a netfilter: nfnetl... |
1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 |
/* Check if we support these flags in first place, dependencies should * be there too not to break atomicity. */ if (nfqa[NFQA_CFG_FLAGS]) { if (!nfqa[NFQA_CFG_MASK]) { /* A mask is needed to specify which flags are being * changed. */ return -EINVAL; } flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS])); mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK])); if (flags >= NFQA_CFG_F_MAX) return -EOPNOTSUPP; #if !IS_ENABLED(CONFIG_NETWORK_SECMARK) if (flags & mask & NFQA_CFG_F_SECCTX) return -EOPNOTSUPP; #endif |
71b2e5f5c netfilter: nfnetl... |
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
if ((flags & mask & NFQA_CFG_F_CONNTRACK) && !rcu_access_pointer(nfnl_ct_hook)) { #ifdef CONFIG_MODULES nfnl_unlock(NFNL_SUBSYS_QUEUE); request_module("ip_conntrack_netlink"); nfnl_lock(NFNL_SUBSYS_QUEUE); if (rcu_access_pointer(nfnl_ct_hook)) return -EAGAIN; #endif return -EOPNOTSUPP; } |
60d2c7f9a netfilter: nfnetl... |
1210 |
} |
9872bec77 [NETFILTER]: nfne... |
1211 |
rcu_read_lock(); |
e81796104 netfilter: nfnetl... |
1212 |
queue = instance_lookup(q, queue_num); |
15e473046 netlink: Rename p... |
1213 |
if (queue && queue->peer_portid != NETLINK_CB(skb).portid) { |
a3c8e7fd4 [NETFILTER]: nfne... |
1214 |
ret = -EPERM; |
9872bec77 [NETFILTER]: nfne... |
1215 |
goto err_out_unlock; |
a3c8e7fd4 [NETFILTER]: nfne... |
1216 |
} |
9872bec77 [NETFILTER]: nfne... |
1217 |
if (cmd != NULL) { |
7af4cc3fa [NETFILTER]: Add ... |
1218 1219 |
switch (cmd->command) { case NFQNL_CFG_CMD_BIND: |
9872bec77 [NETFILTER]: nfne... |
1220 1221 1222 1223 |
if (queue) { ret = -EBUSY; goto err_out_unlock; } |
e81796104 netfilter: nfnetl... |
1224 1225 |
queue = instance_create(q, queue_num, NETLINK_CB(skb).portid); |
baab2ce7d [NETFILTER]: nfne... |
1226 1227 |
if (IS_ERR(queue)) { ret = PTR_ERR(queue); |
9872bec77 [NETFILTER]: nfne... |
1228 1229 |
goto err_out_unlock; } |
7af4cc3fa [NETFILTER]: Add ... |
1230 1231 |
break; case NFQNL_CFG_CMD_UNBIND: |
9872bec77 [NETFILTER]: nfne... |
1232 1233 1234 1235 |
if (!queue) { ret = -ENODEV; goto err_out_unlock; } |
e81796104 netfilter: nfnetl... |
1236 |
instance_destroy(q, queue); |
17bc6b488 netfilter: nfnetl... |
1237 |
goto err_out_unlock; |
7af4cc3fa [NETFILTER]: Add ... |
1238 |
case NFQNL_CFG_CMD_PF_BIND: |
7af4cc3fa [NETFILTER]: Add ... |
1239 |
case NFQNL_CFG_CMD_PF_UNBIND: |
7af4cc3fa [NETFILTER]: Add ... |
1240 1241 |
break; default: |
cd21f0ac4 [NETFILTER]: nfne... |
1242 |
ret = -ENOTSUPP; |
21c3c971d netfilter: nfnetl... |
1243 |
goto err_out_unlock; |
7af4cc3fa [NETFILTER]: Add ... |
1244 |
} |
7af4cc3fa [NETFILTER]: Add ... |
1245 |
} |
60d2c7f9a netfilter: nfnetl... |
1246 1247 1248 1249 |
if (!queue) { ret = -ENODEV; goto err_out_unlock; } |
df6fb868d [NETFILTER]: nfne... |
1250 |
if (nfqa[NFQA_CFG_PARAMS]) { |
60d2c7f9a netfilter: nfnetl... |
1251 1252 |
struct nfqnl_msg_config_params *params = nla_data(nfqa[NFQA_CFG_PARAMS]); |
7af4cc3fa [NETFILTER]: Add ... |
1253 1254 1255 1256 |
nfqnl_set_mode(queue, params->copy_mode, ntohl(params->copy_range)); } |
df6fb868d [NETFILTER]: nfne... |
1257 |
if (nfqa[NFQA_CFG_QUEUE_MAXLEN]) { |
60d2c7f9a netfilter: nfnetl... |
1258 |
__be32 *queue_maxlen = nla_data(nfqa[NFQA_CFG_QUEUE_MAXLEN]); |
a3c8e7fd4 [NETFILTER]: nfne... |
1259 |
|
829e17a1a [NETFILTER]: nfne... |
1260 1261 1262 1263 |
spin_lock_bh(&queue->lock); queue->queue_maxlen = ntohl(*queue_maxlen); spin_unlock_bh(&queue->lock); } |
fdb694a01 netfilter: Add fa... |
1264 |
if (nfqa[NFQA_CFG_FLAGS]) { |
fdb694a01 netfilter: Add fa... |
1265 1266 1267 1268 1269 |
spin_lock_bh(&queue->lock); queue->flags &= ~mask; queue->flags |= flags & mask; spin_unlock_bh(&queue->lock); } |
9872bec77 [NETFILTER]: nfne... |
1270 1271 |
err_out_unlock: rcu_read_unlock(); |
838ab6364 [NETFILTER]: Add ... |
1272 |
return ret; |
7af4cc3fa [NETFILTER]: Add ... |
1273 |
} |
7c8d4cb41 [NETFILTER]: nfne... |
1274 |
static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { |
84a797dd0 netfilter: nfnetl... |
1275 |
[NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp, |
37d2e7a20 [NETFILTER] nfnet... |
1276 |
.attr_count = NFQA_MAX, }, |
84a797dd0 netfilter: nfnetl... |
1277 |
[NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict, |
5bf758539 [NETFILTER]: nfne... |
1278 1279 |
.attr_count = NFQA_MAX, .policy = nfqa_verdict_policy }, |
7af4cc3fa [NETFILTER]: Add ... |
1280 |
[NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, |
5bf758539 [NETFILTER]: nfne... |
1281 1282 |
.attr_count = NFQA_CFG_MAX, .policy = nfqa_cfg_policy }, |
97d32cf94 netfilter: nfnetl... |
1283 1284 1285 |
[NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch, .attr_count = NFQA_MAX, .policy = nfqa_verdict_batch_policy }, |
7af4cc3fa [NETFILTER]: Add ... |
1286 |
}; |
7c8d4cb41 [NETFILTER]: nfne... |
1287 |
static const struct nfnetlink_subsystem nfqnl_subsys = { |
7af4cc3fa [NETFILTER]: Add ... |
1288 1289 1290 |
.name = "nf_queue", .subsys_id = NFNL_SUBSYS_QUEUE, .cb_count = NFQNL_MSG_MAX, |
7af4cc3fa [NETFILTER]: Add ... |
1291 1292 |
.cb = nfqnl_cb, }; |
838ab6364 [NETFILTER]: Add ... |
1293 1294 |
#ifdef CONFIG_PROC_FS struct iter_state { |
e81796104 netfilter: nfnetl... |
1295 |
struct seq_net_private p; |
838ab6364 [NETFILTER]: Add ... |
1296 1297 1298 1299 1300 1301 |
unsigned int bucket; }; static struct hlist_node *get_first(struct seq_file *seq) { struct iter_state *st = seq->private; |
e81796104 netfilter: nfnetl... |
1302 1303 |
struct net *net; struct nfnl_queue_net *q; |
838ab6364 [NETFILTER]: Add ... |
1304 1305 1306 |
if (!st) return NULL; |
e81796104 netfilter: nfnetl... |
1307 1308 |
net = seq_file_net(seq); q = nfnl_queue_pernet(net); |
838ab6364 [NETFILTER]: Add ... |
1309 |
for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { |
e81796104 netfilter: nfnetl... |
1310 1311 |
if (!hlist_empty(&q->instance_table[st->bucket])) return q->instance_table[st->bucket].first; |
838ab6364 [NETFILTER]: Add ... |
1312 1313 1314 1315 1316 1317 1318 |
} return NULL; } static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) { struct iter_state *st = seq->private; |
e81796104 netfilter: nfnetl... |
1319 |
struct net *net = seq_file_net(seq); |
838ab6364 [NETFILTER]: Add ... |
1320 1321 1322 |
h = h->next; while (!h) { |
e81796104 netfilter: nfnetl... |
1323 |
struct nfnl_queue_net *q; |
838ab6364 [NETFILTER]: Add ... |
1324 1325 |
if (++st->bucket >= INSTANCE_BUCKETS) return NULL; |
e81796104 netfilter: nfnetl... |
1326 1327 |
q = nfnl_queue_pernet(net); h = q->instance_table[st->bucket].first; |
838ab6364 [NETFILTER]: Add ... |
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 |
} return h; } static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) { struct hlist_node *head; head = get_first(seq); if (head) while (pos && (head = get_next(seq, head))) pos--; return pos ? NULL : head; } |
e81796104 netfilter: nfnetl... |
1342 1343 |
static void *seq_start(struct seq_file *s, loff_t *pos) __acquires(nfnl_queue_pernet(seq_file_net(s))->instances_lock) |
838ab6364 [NETFILTER]: Add ... |
1344 |
{ |
e81796104 netfilter: nfnetl... |
1345 1346 |
spin_lock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock); return get_idx(s, *pos); |
838ab6364 [NETFILTER]: Add ... |
1347 1348 1349 1350 1351 1352 1353 1354 1355 |
} static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; return get_next(s, v); } static void seq_stop(struct seq_file *s, void *v) |
e81796104 netfilter: nfnetl... |
1356 |
__releases(nfnl_queue_pernet(seq_file_net(s))->instances_lock) |
838ab6364 [NETFILTER]: Add ... |
1357 |
{ |
e81796104 netfilter: nfnetl... |
1358 |
spin_unlock(&nfnl_queue_pernet(seq_file_net(s))->instances_lock); |
838ab6364 [NETFILTER]: Add ... |
1359 1360 1361 1362 1363 |
} static int seq_show(struct seq_file *s, void *v) { const struct nfqnl_instance *inst = v; |
6b46f7b7e netfilter: Fix fo... |
1364 1365 |
seq_printf(s, "%5u %6u %5u %1u %5u %5u %5u %8u %2d ", |
e71456ae9 netfilter: Remove... |
1366 1367 1368 1369 1370 |
inst->queue_num, inst->peer_portid, inst->queue_total, inst->copy_mode, inst->copy_range, inst->queue_dropped, inst->queue_user_dropped, inst->id_sequence, 1); |
861fb1078 netfilter: Use co... |
1371 |
return 0; |
838ab6364 [NETFILTER]: Add ... |
1372 |
} |
56b3d975b [NET]: Make all i... |
1373 |
static const struct seq_operations nfqnl_seq_ops = { |
838ab6364 [NETFILTER]: Add ... |
1374 1375 1376 1377 1378 |
.start = seq_start, .next = seq_next, .stop = seq_stop, .show = seq_show, }; |
838ab6364 [NETFILTER]: Add ... |
1379 |
#endif /* PROC_FS */ |
e81796104 netfilter: nfnetl... |
1380 |
static int __net_init nfnl_queue_net_init(struct net *net) |
7af4cc3fa [NETFILTER]: Add ... |
1381 |
{ |
e81796104 netfilter: nfnetl... |
1382 1383 |
unsigned int i; struct nfnl_queue_net *q = nfnl_queue_pernet(net); |
601e68e10 [NETFILTER]: Fix ... |
1384 |
|
838ab6364 [NETFILTER]: Add ... |
1385 |
for (i = 0; i < INSTANCE_BUCKETS; i++) |
e81796104 netfilter: nfnetl... |
1386 1387 1388 1389 1390 |
INIT_HLIST_HEAD(&q->instance_table[i]); spin_lock_init(&q->instances_lock); #ifdef CONFIG_PROC_FS |
c35063722 proc: introduce p... |
1391 1392 |
if (!proc_create_net("nfnetlink_queue", 0440, net->nf.proc_netfilter, &nfqnl_seq_ops, sizeof(struct iter_state))) |
e81796104 netfilter: nfnetl... |
1393 1394 |
return -ENOMEM; #endif |
dc3ee32e9 netfilter: nf_que... |
1395 |
nf_register_queue_handler(net, &nfqh); |
e81796104 netfilter: nfnetl... |
1396 1397 1398 1399 1400 |
return 0; } static void __net_exit nfnl_queue_net_exit(struct net *net) { |
613d0776d netfilter: exit_n... |
1401 1402 |
struct nfnl_queue_net *q = nfnl_queue_pernet(net); unsigned int i; |
dc3ee32e9 netfilter: nf_que... |
1403 |
nf_unregister_queue_handler(net); |
e778f56e2 netfilter: nf_{lo... |
1404 |
#ifdef CONFIG_PROC_FS |
e81796104 netfilter: nfnetl... |
1405 |
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter); |
e778f56e2 netfilter: nf_{lo... |
1406 |
#endif |
613d0776d netfilter: exit_n... |
1407 1408 |
for (i = 0; i < INSTANCE_BUCKETS; i++) WARN_ON_ONCE(!hlist_empty(&q->instance_table[i])); |
e81796104 netfilter: nfnetl... |
1409 |
} |
dc3ee32e9 netfilter: nf_que... |
1410 1411 1412 1413 |
static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list) { synchronize_rcu(); } |
e81796104 netfilter: nfnetl... |
1414 |
static struct pernet_operations nfnl_queue_net_ops = { |
dc3ee32e9 netfilter: nf_que... |
1415 1416 1417 1418 1419 |
.init = nfnl_queue_net_init, .exit = nfnl_queue_net_exit, .exit_batch = nfnl_queue_net_exit_batch, .id = &nfnl_queue_net_id, .size = sizeof(struct nfnl_queue_net), |
e81796104 netfilter: nfnetl... |
1420 1421 1422 1423 |
}; static int __init nfnetlink_queue_init(void) { |
3bfe04980 netfilter: nfnetl... |
1424 1425 1426 1427 |
int status; status = register_pernet_subsys(&nfnl_queue_net_ops); if (status < 0) { |
5191d70f8 netfilter: Replac... |
1428 1429 |
pr_err("failed to register pernet ops "); |
3bfe04980 netfilter: nfnetl... |
1430 1431 |
goto out; } |
838ab6364 [NETFILTER]: Add ... |
1432 |
|
7af4cc3fa [NETFILTER]: Add ... |
1433 1434 1435 |
netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { |
5191d70f8 netfilter: Replac... |
1436 1437 |
pr_err("failed to create netlink socket "); |
7af4cc3fa [NETFILTER]: Add ... |
1438 1439 |
goto cleanup_netlink_notifier; } |
4e6577de7 netfilter: Add th... |
1440 1441 |
status = register_netdevice_notifier(&nfqnl_dev_notifier); if (status < 0) { |
5191d70f8 netfilter: Replac... |
1442 1443 |
pr_err("failed to register netdevice notifier "); |
4e6577de7 netfilter: Add th... |
1444 1445 |
goto cleanup_netlink_subsys; } |
7af4cc3fa [NETFILTER]: Add ... |
1446 |
return status; |
4e6577de7 netfilter: Add th... |
1447 1448 |
cleanup_netlink_subsys: nfnetlink_subsys_unregister(&nfqnl_subsys); |
7af4cc3fa [NETFILTER]: Add ... |
1449 1450 |
cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); |
639e077b4 netfilter: nfnetl... |
1451 |
unregister_pernet_subsys(&nfnl_queue_net_ops); |
3bfe04980 netfilter: nfnetl... |
1452 |
out: |
7af4cc3fa [NETFILTER]: Add ... |
1453 1454 |
return status; } |
65b4b4e81 [NETFILTER]: Rena... |
1455 |
static void __exit nfnetlink_queue_fini(void) |
7af4cc3fa [NETFILTER]: Add ... |
1456 |
{ |
32292a7ff [NETFILTER]: Fix ... |
1457 |
unregister_netdevice_notifier(&nfqnl_dev_notifier); |
32292a7ff [NETFILTER]: Fix ... |
1458 1459 |
nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); |
3bfe04980 netfilter: nfnetl... |
1460 |
unregister_pernet_subsys(&nfnl_queue_net_ops); |
67137f3cc nfnetlink_queue: ... |
1461 1462 |
rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
7af4cc3fa [NETFILTER]: Add ... |
1463 1464 1465 1466 1467 1468 |
} MODULE_DESCRIPTION("netfilter packet queue handler"); MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); MODULE_LICENSE("GPL"); MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_QUEUE); |
65b4b4e81 [NETFILTER]: Rena... |
1469 1470 |
module_init(nfnetlink_queue_init); module_exit(nfnetlink_queue_fini); |