diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-05-08 13:45:28 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2012-05-08 14:25:42 -0400 |
commit | d16cf20e2f2f13411eece7f7fb72c17d141c4a84 (patch) | |
tree | 8154b3db8cdbb4b8d9f35d4c407cfe961253f0b4 | |
parent | 6714cf5465d2803a21c6a46c1ea747795a8889fa (diff) |
netfilter: remove ip_queue support
This patch removes ip_queue support which was marked as obsolete
years ago. The nfnetlink_queue modules provides more advanced
user-space packet queueing mechanism.
This patch also removes capability code included in SELinux that
refers to ip_queue. Otherwise, we break compilation.
Several warning has been sent regarding this to the mailing list
in the past month without anyone rising the hand to stop this
with some strong argument.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | Documentation/ABI/removed/ip_queue | 9 | ||||
-rw-r--r-- | include/linux/netfilter_ipv4/Kbuild | 1 | ||||
-rw-r--r-- | include/linux/netfilter_ipv4/ip_queue.h | 72 | ||||
-rw-r--r-- | include/linux/netlink.h | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/Makefile | 3 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 639 | ||||
-rw-r--r-- | net/ipv6/netfilter/Kconfig | 22 | ||||
-rw-r--r-- | net/ipv6/netfilter/Makefile | 1 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 641 | ||||
-rw-r--r-- | security/selinux/nlmsgtab.c | 13 |
10 files changed, 10 insertions, 1393 deletions
diff --git a/Documentation/ABI/removed/ip_queue b/Documentation/ABI/removed/ip_queue new file mode 100644 index 000000000000..3243613bc2d2 --- /dev/null +++ b/Documentation/ABI/removed/ip_queue | |||
@@ -0,0 +1,9 @@ | |||
1 | What: ip_queue | ||
2 | Date: finally removed in kernel v3.5.0 | ||
3 | Contact: Pablo Neira Ayuso <pablo@netfilter.org> | ||
4 | Description: | ||
5 | ip_queue has been replaced by nfnetlink_queue which provides | ||
6 | more advanced queueing mechanism to user-space. The ip_queue | ||
7 | module was already announced to become obsolete years ago. | ||
8 | |||
9 | Users: | ||
diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 31f8bec95650..c61b8fb1a9ef 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild | |||
@@ -1,4 +1,3 @@ | |||
1 | header-y += ip_queue.h | ||
2 | header-y += ip_tables.h | 1 | header-y += ip_tables.h |
3 | header-y += ipt_CLUSTERIP.h | 2 | header-y += ipt_CLUSTERIP.h |
4 | header-y += ipt_ECN.h | 3 | header-y += ipt_ECN.h |
diff --git a/include/linux/netfilter_ipv4/ip_queue.h b/include/linux/netfilter_ipv4/ip_queue.h deleted file mode 100644 index a03507f465f8..000000000000 --- a/include/linux/netfilter_ipv4/ip_queue.h +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for queueing IPv4 packets and | ||
3 | * communicating with userspace via netlink. | ||
4 | * | ||
5 | * (C) 2000 James Morris, this code is GPL. | ||
6 | */ | ||
7 | #ifndef _IP_QUEUE_H | ||
8 | #define _IP_QUEUE_H | ||
9 | |||
10 | #ifdef __KERNEL__ | ||
11 | #ifdef DEBUG_IPQ | ||
12 | #define QDEBUG(x...) printk(KERN_DEBUG ## x) | ||
13 | #else | ||
14 | #define QDEBUG(x...) | ||
15 | #endif /* DEBUG_IPQ */ | ||
16 | #else | ||
17 | #include <net/if.h> | ||
18 | #endif /* ! __KERNEL__ */ | ||
19 | |||
20 | /* Messages sent from kernel */ | ||
21 | typedef struct ipq_packet_msg { | ||
22 | unsigned long packet_id; /* ID of queued packet */ | ||
23 | unsigned long mark; /* Netfilter mark value */ | ||
24 | long timestamp_sec; /* Packet arrival time (seconds) */ | ||
25 | long timestamp_usec; /* Packet arrvial time (+useconds) */ | ||
26 | unsigned int hook; /* Netfilter hook we rode in on */ | ||
27 | char indev_name[IFNAMSIZ]; /* Name of incoming interface */ | ||
28 | char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */ | ||
29 | __be16 hw_protocol; /* Hardware protocol (network order) */ | ||
30 | unsigned short hw_type; /* Hardware type */ | ||
31 | unsigned char hw_addrlen; /* Hardware address length */ | ||
32 | unsigned char hw_addr[8]; /* Hardware address */ | ||
33 | size_t data_len; /* Length of packet data */ | ||
34 | unsigned char payload[0]; /* Optional packet data */ | ||
35 | } ipq_packet_msg_t; | ||
36 | |||
37 | /* Messages sent from userspace */ | ||
38 | typedef struct ipq_mode_msg { | ||
39 | unsigned char value; /* Requested mode */ | ||
40 | size_t range; /* Optional range of packet requested */ | ||
41 | } ipq_mode_msg_t; | ||
42 | |||
43 | typedef struct ipq_verdict_msg { | ||
44 | unsigned int value; /* Verdict to hand to netfilter */ | ||
45 | unsigned long id; /* Packet ID for this verdict */ | ||
46 | size_t data_len; /* Length of replacement data */ | ||
47 | unsigned char payload[0]; /* Optional replacement packet */ | ||
48 | } ipq_verdict_msg_t; | ||
49 | |||
50 | typedef struct ipq_peer_msg { | ||
51 | union { | ||
52 | ipq_verdict_msg_t verdict; | ||
53 | ipq_mode_msg_t mode; | ||
54 | } msg; | ||
55 | } ipq_peer_msg_t; | ||
56 | |||
57 | /* Packet delivery modes */ | ||
58 | enum { | ||
59 | IPQ_COPY_NONE, /* Initial mode, packets are dropped */ | ||
60 | IPQ_COPY_META, /* Copy metadata */ | ||
61 | IPQ_COPY_PACKET /* Copy metadata + packet (range) */ | ||
62 | }; | ||
63 | #define IPQ_COPY_MAX IPQ_COPY_PACKET | ||
64 | |||
65 | /* Types of messages */ | ||
66 | #define IPQM_BASE 0x10 /* standard netlink messages below this */ | ||
67 | #define IPQM_MODE (IPQM_BASE + 1) /* Mode request from peer */ | ||
68 | #define IPQM_VERDICT (IPQM_BASE + 2) /* Verdict from peer */ | ||
69 | #define IPQM_PACKET (IPQM_BASE + 3) /* Packet from kernel */ | ||
70 | #define IPQM_MAX (IPQM_BASE + 4) | ||
71 | |||
72 | #endif /*_IP_QUEUE_H*/ | ||
diff --git a/include/linux/netlink.h b/include/linux/netlink.h index a2092f582a78..0f628ffa420c 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h | |||
@@ -7,7 +7,7 @@ | |||
7 | #define NETLINK_ROUTE 0 /* Routing/device hook */ | 7 | #define NETLINK_ROUTE 0 /* Routing/device hook */ |
8 | #define NETLINK_UNUSED 1 /* Unused number */ | 8 | #define NETLINK_UNUSED 1 /* Unused number */ |
9 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ | 9 | #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ |
10 | #define NETLINK_FIREWALL 3 /* Firewalling hook */ | 10 | #define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */ |
11 | #define NETLINK_SOCK_DIAG 4 /* socket monitoring */ | 11 | #define NETLINK_SOCK_DIAG 4 /* socket monitoring */ |
12 | #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ | 12 | #define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ |
13 | #define NETLINK_XFRM 6 /* ipsec */ | 13 | #define NETLINK_XFRM 6 /* ipsec */ |
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 240b68469a7a..c20674dc9452 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile | |||
@@ -66,6 +66,3 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o | |||
66 | 66 | ||
67 | # just filtering instance of ARP tables for now | 67 | # just filtering instance of ARP tables for now |
68 | obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o | 68 | obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o |
69 | |||
70 | obj-$(CONFIG_IP_NF_QUEUE) += ip_queue.o | ||
71 | |||
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c deleted file mode 100644 index 09775a1e1348..000000000000 --- a/net/ipv4/netfilter/ip_queue.c +++ /dev/null | |||
@@ -1,639 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for queueing IPv4 packets and | ||
3 | * communicating with userspace via netlink. | ||
4 | * | ||
5 | * (C) 2000-2002 James Morris <jmorris@intercode.com.au> | ||
6 | * (C) 2003-2005 Netfilter Core Team <coreteam@netfilter.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/ip.h> | ||
16 | #include <linux/notifier.h> | ||
17 | #include <linux/netdevice.h> | ||
18 | #include <linux/netfilter.h> | ||
19 | #include <linux/netfilter_ipv4/ip_queue.h> | ||
20 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
21 | #include <linux/netlink.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/sysctl.h> | ||
24 | #include <linux/proc_fs.h> | ||
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/security.h> | ||
27 | #include <linux/net.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <net/net_namespace.h> | ||
31 | #include <net/sock.h> | ||
32 | #include <net/route.h> | ||
33 | #include <net/netfilter/nf_queue.h> | ||
34 | #include <net/ip.h> | ||
35 | |||
36 | #define IPQ_QMAX_DEFAULT 1024 | ||
37 | #define IPQ_PROC_FS_NAME "ip_queue" | ||
38 | #define NET_IPQ_QMAX 2088 | ||
39 | #define NET_IPQ_QMAX_NAME "ip_queue_maxlen" | ||
40 | |||
41 | typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long); | ||
42 | |||
43 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; | ||
44 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; | ||
45 | static DEFINE_SPINLOCK(queue_lock); | ||
46 | static int peer_pid __read_mostly; | ||
47 | static unsigned int copy_range __read_mostly; | ||
48 | static unsigned int queue_total; | ||
49 | static unsigned int queue_dropped = 0; | ||
50 | static unsigned int queue_user_dropped = 0; | ||
51 | static struct sock *ipqnl __read_mostly; | ||
52 | static LIST_HEAD(queue_list); | ||
53 | static DEFINE_MUTEX(ipqnl_mutex); | ||
54 | |||
55 | static inline void | ||
56 | __ipq_enqueue_entry(struct nf_queue_entry *entry) | ||
57 | { | ||
58 | list_add_tail(&entry->list, &queue_list); | ||
59 | queue_total++; | ||
60 | } | ||
61 | |||
62 | static inline int | ||
63 | __ipq_set_mode(unsigned char mode, unsigned int range) | ||
64 | { | ||
65 | int status = 0; | ||
66 | |||
67 | switch(mode) { | ||
68 | case IPQ_COPY_NONE: | ||
69 | case IPQ_COPY_META: | ||
70 | copy_mode = mode; | ||
71 | copy_range = 0; | ||
72 | break; | ||
73 | |||
74 | case IPQ_COPY_PACKET: | ||
75 | if (range > 0xFFFF) | ||
76 | range = 0xFFFF; | ||
77 | copy_range = range; | ||
78 | copy_mode = mode; | ||
79 | break; | ||
80 | |||
81 | default: | ||
82 | status = -EINVAL; | ||
83 | |||
84 | } | ||
85 | return status; | ||
86 | } | ||
87 | |||
88 | static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data); | ||
89 | |||
90 | static inline void | ||
91 | __ipq_reset(void) | ||
92 | { | ||
93 | peer_pid = 0; | ||
94 | net_disable_timestamp(); | ||
95 | __ipq_set_mode(IPQ_COPY_NONE, 0); | ||
96 | __ipq_flush(NULL, 0); | ||
97 | } | ||
98 | |||
99 | static struct nf_queue_entry * | ||
100 | ipq_find_dequeue_entry(unsigned long id) | ||
101 | { | ||
102 | struct nf_queue_entry *entry = NULL, *i; | ||
103 | |||
104 | spin_lock_bh(&queue_lock); | ||
105 | |||
106 | list_for_each_entry(i, &queue_list, list) { | ||
107 | if ((unsigned long)i == id) { | ||
108 | entry = i; | ||
109 | break; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | if (entry) { | ||
114 | list_del(&entry->list); | ||
115 | queue_total--; | ||
116 | } | ||
117 | |||
118 | spin_unlock_bh(&queue_lock); | ||
119 | return entry; | ||
120 | } | ||
121 | |||
122 | static void | ||
123 | __ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | ||
124 | { | ||
125 | struct nf_queue_entry *entry, *next; | ||
126 | |||
127 | list_for_each_entry_safe(entry, next, &queue_list, list) { | ||
128 | if (!cmpfn || cmpfn(entry, data)) { | ||
129 | list_del(&entry->list); | ||
130 | queue_total--; | ||
131 | nf_reinject(entry, NF_DROP); | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | static void | ||
137 | ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | ||
138 | { | ||
139 | spin_lock_bh(&queue_lock); | ||
140 | __ipq_flush(cmpfn, data); | ||
141 | spin_unlock_bh(&queue_lock); | ||
142 | } | ||
143 | |||
144 | static struct sk_buff * | ||
145 | ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) | ||
146 | { | ||
147 | sk_buff_data_t old_tail; | ||
148 | size_t size = 0; | ||
149 | size_t data_len = 0; | ||
150 | struct sk_buff *skb; | ||
151 | struct ipq_packet_msg *pmsg; | ||
152 | struct nlmsghdr *nlh; | ||
153 | struct timeval tv; | ||
154 | |||
155 | switch (ACCESS_ONCE(copy_mode)) { | ||
156 | case IPQ_COPY_META: | ||
157 | case IPQ_COPY_NONE: | ||
158 | size = NLMSG_SPACE(sizeof(*pmsg)); | ||
159 | break; | ||
160 | |||
161 | case IPQ_COPY_PACKET: | ||
162 | if (entry->skb->ip_summed == CHECKSUM_PARTIAL && | ||
163 | (*errp = skb_checksum_help(entry->skb))) | ||
164 | return NULL; | ||
165 | |||
166 | data_len = ACCESS_ONCE(copy_range); | ||
167 | if (data_len == 0 || data_len > entry->skb->len) | ||
168 | data_len = entry->skb->len; | ||
169 | |||
170 | size = NLMSG_SPACE(sizeof(*pmsg) + data_len); | ||
171 | break; | ||
172 | |||
173 | default: | ||
174 | *errp = -EINVAL; | ||
175 | return NULL; | ||
176 | } | ||
177 | |||
178 | skb = alloc_skb(size, GFP_ATOMIC); | ||
179 | if (!skb) | ||
180 | goto nlmsg_failure; | ||
181 | |||
182 | old_tail = skb->tail; | ||
183 | nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh)); | ||
184 | pmsg = NLMSG_DATA(nlh); | ||
185 | memset(pmsg, 0, sizeof(*pmsg)); | ||
186 | |||
187 | pmsg->packet_id = (unsigned long )entry; | ||
188 | pmsg->data_len = data_len; | ||
189 | tv = ktime_to_timeval(entry->skb->tstamp); | ||
190 | pmsg->timestamp_sec = tv.tv_sec; | ||
191 | pmsg->timestamp_usec = tv.tv_usec; | ||
192 | pmsg->mark = entry->skb->mark; | ||
193 | pmsg->hook = entry->hook; | ||
194 | pmsg->hw_protocol = entry->skb->protocol; | ||
195 | |||
196 | if (entry->indev) | ||
197 | strcpy(pmsg->indev_name, entry->indev->name); | ||
198 | else | ||
199 | pmsg->indev_name[0] = '\0'; | ||
200 | |||
201 | if (entry->outdev) | ||
202 | strcpy(pmsg->outdev_name, entry->outdev->name); | ||
203 | else | ||
204 | pmsg->outdev_name[0] = '\0'; | ||
205 | |||
206 | if (entry->indev && entry->skb->dev && | ||
207 | entry->skb->mac_header != entry->skb->network_header) { | ||
208 | pmsg->hw_type = entry->skb->dev->type; | ||
209 | pmsg->hw_addrlen = dev_parse_header(entry->skb, | ||
210 | pmsg->hw_addr); | ||
211 | } | ||
212 | |||
213 | if (data_len) | ||
214 | if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len)) | ||
215 | BUG(); | ||
216 | |||
217 | nlh->nlmsg_len = skb->tail - old_tail; | ||
218 | return skb; | ||
219 | |||
220 | nlmsg_failure: | ||
221 | kfree_skb(skb); | ||
222 | *errp = -EINVAL; | ||
223 | printk(KERN_ERR "ip_queue: error creating packet message\n"); | ||
224 | return NULL; | ||
225 | } | ||
226 | |||
227 | static int | ||
228 | ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | ||
229 | { | ||
230 | int status = -EINVAL; | ||
231 | struct sk_buff *nskb; | ||
232 | |||
233 | if (copy_mode == IPQ_COPY_NONE) | ||
234 | return -EAGAIN; | ||
235 | |||
236 | nskb = ipq_build_packet_message(entry, &status); | ||
237 | if (nskb == NULL) | ||
238 | return status; | ||
239 | |||
240 | spin_lock_bh(&queue_lock); | ||
241 | |||
242 | if (!peer_pid) | ||
243 | goto err_out_free_nskb; | ||
244 | |||
245 | if (queue_total >= queue_maxlen) { | ||
246 | queue_dropped++; | ||
247 | status = -ENOSPC; | ||
248 | if (net_ratelimit()) | ||
249 | printk (KERN_WARNING "ip_queue: full at %d entries, " | ||
250 | "dropping packets(s). Dropped: %d\n", queue_total, | ||
251 | queue_dropped); | ||
252 | goto err_out_free_nskb; | ||
253 | } | ||
254 | |||
255 | /* netlink_unicast will either free the nskb or attach it to a socket */ | ||
256 | status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT); | ||
257 | if (status < 0) { | ||
258 | queue_user_dropped++; | ||
259 | goto err_out_unlock; | ||
260 | } | ||
261 | |||
262 | __ipq_enqueue_entry(entry); | ||
263 | |||
264 | spin_unlock_bh(&queue_lock); | ||
265 | return status; | ||
266 | |||
267 | err_out_free_nskb: | ||
268 | kfree_skb(nskb); | ||
269 | |||
270 | err_out_unlock: | ||
271 | spin_unlock_bh(&queue_lock); | ||
272 | return status; | ||
273 | } | ||
274 | |||
275 | static int | ||
276 | ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct nf_queue_entry *e) | ||
277 | { | ||
278 | int diff; | ||
279 | struct iphdr *user_iph = (struct iphdr *)v->payload; | ||
280 | struct sk_buff *nskb; | ||
281 | |||
282 | if (v->data_len < sizeof(*user_iph)) | ||
283 | return 0; | ||
284 | diff = v->data_len - e->skb->len; | ||
285 | if (diff < 0) { | ||
286 | if (pskb_trim(e->skb, v->data_len)) | ||
287 | return -ENOMEM; | ||
288 | } else if (diff > 0) { | ||
289 | if (v->data_len > 0xFFFF) | ||
290 | return -EINVAL; | ||
291 | if (diff > skb_tailroom(e->skb)) { | ||
292 | nskb = skb_copy_expand(e->skb, skb_headroom(e->skb), | ||
293 | diff, GFP_ATOMIC); | ||
294 | if (!nskb) { | ||
295 | printk(KERN_WARNING "ip_queue: error " | ||
296 | "in mangle, dropping packet\n"); | ||
297 | return -ENOMEM; | ||
298 | } | ||
299 | kfree_skb(e->skb); | ||
300 | e->skb = nskb; | ||
301 | } | ||
302 | skb_put(e->skb, diff); | ||
303 | } | ||
304 | if (!skb_make_writable(e->skb, v->data_len)) | ||
305 | return -ENOMEM; | ||
306 | skb_copy_to_linear_data(e->skb, v->payload, v->data_len); | ||
307 | e->skb->ip_summed = CHECKSUM_NONE; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) | ||
314 | { | ||
315 | struct nf_queue_entry *entry; | ||
316 | |||
317 | if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN) | ||
318 | return -EINVAL; | ||
319 | |||
320 | entry = ipq_find_dequeue_entry(vmsg->id); | ||
321 | if (entry == NULL) | ||
322 | return -ENOENT; | ||
323 | else { | ||
324 | int verdict = vmsg->value; | ||
325 | |||
326 | if (vmsg->data_len && vmsg->data_len == len) | ||
327 | if (ipq_mangle_ipv4(vmsg, entry) < 0) | ||
328 | verdict = NF_DROP; | ||
329 | |||
330 | nf_reinject(entry, verdict); | ||
331 | return 0; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | static int | ||
336 | ipq_set_mode(unsigned char mode, unsigned int range) | ||
337 | { | ||
338 | int status; | ||
339 | |||
340 | spin_lock_bh(&queue_lock); | ||
341 | status = __ipq_set_mode(mode, range); | ||
342 | spin_unlock_bh(&queue_lock); | ||
343 | return status; | ||
344 | } | ||
345 | |||
346 | static int | ||
347 | ipq_receive_peer(struct ipq_peer_msg *pmsg, | ||
348 | unsigned char type, unsigned int len) | ||
349 | { | ||
350 | int status = 0; | ||
351 | |||
352 | if (len < sizeof(*pmsg)) | ||
353 | return -EINVAL; | ||
354 | |||
355 | switch (type) { | ||
356 | case IPQM_MODE: | ||
357 | status = ipq_set_mode(pmsg->msg.mode.value, | ||
358 | pmsg->msg.mode.range); | ||
359 | break; | ||
360 | |||
361 | case IPQM_VERDICT: | ||
362 | status = ipq_set_verdict(&pmsg->msg.verdict, | ||
363 | len - sizeof(*pmsg)); | ||
364 | break; | ||
365 | default: | ||
366 | status = -EINVAL; | ||
367 | } | ||
368 | return status; | ||
369 | } | ||
370 | |||
371 | static int | ||
372 | dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) | ||
373 | { | ||
374 | if (entry->indev) | ||
375 | if (entry->indev->ifindex == ifindex) | ||
376 | return 1; | ||
377 | if (entry->outdev) | ||
378 | if (entry->outdev->ifindex == ifindex) | ||
379 | return 1; | ||
380 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
381 | if (entry->skb->nf_bridge) { | ||
382 | if (entry->skb->nf_bridge->physindev && | ||
383 | entry->skb->nf_bridge->physindev->ifindex == ifindex) | ||
384 | return 1; | ||
385 | if (entry->skb->nf_bridge->physoutdev && | ||
386 | entry->skb->nf_bridge->physoutdev->ifindex == ifindex) | ||
387 | return 1; | ||
388 | } | ||
389 | #endif | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static void | ||
394 | ipq_dev_drop(int ifindex) | ||
395 | { | ||
396 | ipq_flush(dev_cmp, ifindex); | ||
397 | } | ||
398 | |||
399 | #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) | ||
400 | |||
401 | static inline void | ||
402 | __ipq_rcv_skb(struct sk_buff *skb) | ||
403 | { | ||
404 | int status, type, pid, flags; | ||
405 | unsigned int nlmsglen, skblen; | ||
406 | struct nlmsghdr *nlh; | ||
407 | bool enable_timestamp = false; | ||
408 | |||
409 | skblen = skb->len; | ||
410 | if (skblen < sizeof(*nlh)) | ||
411 | return; | ||
412 | |||
413 | nlh = nlmsg_hdr(skb); | ||
414 | nlmsglen = nlh->nlmsg_len; | ||
415 | if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen) | ||
416 | return; | ||
417 | |||
418 | pid = nlh->nlmsg_pid; | ||
419 | flags = nlh->nlmsg_flags; | ||
420 | |||
421 | if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI) | ||
422 | RCV_SKB_FAIL(-EINVAL); | ||
423 | |||
424 | if (flags & MSG_TRUNC) | ||
425 | RCV_SKB_FAIL(-ECOMM); | ||
426 | |||
427 | type = nlh->nlmsg_type; | ||
428 | if (type < NLMSG_NOOP || type >= IPQM_MAX) | ||
429 | RCV_SKB_FAIL(-EINVAL); | ||
430 | |||
431 | if (type <= IPQM_BASE) | ||
432 | return; | ||
433 | |||
434 | if (!capable(CAP_NET_ADMIN)) | ||
435 | RCV_SKB_FAIL(-EPERM); | ||
436 | |||
437 | spin_lock_bh(&queue_lock); | ||
438 | |||
439 | if (peer_pid) { | ||
440 | if (peer_pid != pid) { | ||
441 | spin_unlock_bh(&queue_lock); | ||
442 | RCV_SKB_FAIL(-EBUSY); | ||
443 | } | ||
444 | } else { | ||
445 | enable_timestamp = true; | ||
446 | peer_pid = pid; | ||
447 | } | ||
448 | |||
449 | spin_unlock_bh(&queue_lock); | ||
450 | if (enable_timestamp) | ||
451 | net_enable_timestamp(); | ||
452 | status = ipq_receive_peer(NLMSG_DATA(nlh), type, | ||
453 | nlmsglen - NLMSG_LENGTH(0)); | ||
454 | if (status < 0) | ||
455 | RCV_SKB_FAIL(status); | ||
456 | |||
457 | if (flags & NLM_F_ACK) | ||
458 | netlink_ack(skb, nlh, 0); | ||
459 | } | ||
460 | |||
461 | static void | ||
462 | ipq_rcv_skb(struct sk_buff *skb) | ||
463 | { | ||
464 | mutex_lock(&ipqnl_mutex); | ||
465 | __ipq_rcv_skb(skb); | ||
466 | mutex_unlock(&ipqnl_mutex); | ||
467 | } | ||
468 | |||
469 | static int | ||
470 | ipq_rcv_dev_event(struct notifier_block *this, | ||
471 | unsigned long event, void *ptr) | ||
472 | { | ||
473 | struct net_device *dev = ptr; | ||
474 | |||
475 | if (!net_eq(dev_net(dev), &init_net)) | ||
476 | return NOTIFY_DONE; | ||
477 | |||
478 | /* Drop any packets associated with the downed device */ | ||
479 | if (event == NETDEV_DOWN) | ||
480 | ipq_dev_drop(dev->ifindex); | ||
481 | return NOTIFY_DONE; | ||
482 | } | ||
483 | |||
484 | static struct notifier_block ipq_dev_notifier = { | ||
485 | .notifier_call = ipq_rcv_dev_event, | ||
486 | }; | ||
487 | |||
488 | static int | ||
489 | ipq_rcv_nl_event(struct notifier_block *this, | ||
490 | unsigned long event, void *ptr) | ||
491 | { | ||
492 | struct netlink_notify *n = ptr; | ||
493 | |||
494 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_FIREWALL) { | ||
495 | spin_lock_bh(&queue_lock); | ||
496 | if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) | ||
497 | __ipq_reset(); | ||
498 | spin_unlock_bh(&queue_lock); | ||
499 | } | ||
500 | return NOTIFY_DONE; | ||
501 | } | ||
502 | |||
503 | static struct notifier_block ipq_nl_notifier = { | ||
504 | .notifier_call = ipq_rcv_nl_event, | ||
505 | }; | ||
506 | |||
507 | #ifdef CONFIG_SYSCTL | ||
508 | static struct ctl_table_header *ipq_sysctl_header; | ||
509 | |||
510 | static ctl_table ipq_table[] = { | ||
511 | { | ||
512 | .procname = NET_IPQ_QMAX_NAME, | ||
513 | .data = &queue_maxlen, | ||
514 | .maxlen = sizeof(queue_maxlen), | ||
515 | .mode = 0644, | ||
516 | .proc_handler = proc_dointvec | ||
517 | }, | ||
518 | { } | ||
519 | }; | ||
520 | #endif | ||
521 | |||
522 | #ifdef CONFIG_PROC_FS | ||
523 | static int ip_queue_show(struct seq_file *m, void *v) | ||
524 | { | ||
525 | spin_lock_bh(&queue_lock); | ||
526 | |||
527 | seq_printf(m, | ||
528 | "Peer PID : %d\n" | ||
529 | "Copy mode : %hu\n" | ||
530 | "Copy range : %u\n" | ||
531 | "Queue length : %u\n" | ||
532 | "Queue max. length : %u\n" | ||
533 | "Queue dropped : %u\n" | ||
534 | "Netlink dropped : %u\n", | ||
535 | peer_pid, | ||
536 | copy_mode, | ||
537 | copy_range, | ||
538 | queue_total, | ||
539 | queue_maxlen, | ||
540 | queue_dropped, | ||
541 | queue_user_dropped); | ||
542 | |||
543 | spin_unlock_bh(&queue_lock); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int ip_queue_open(struct inode *inode, struct file *file) | ||
548 | { | ||
549 | return single_open(file, ip_queue_show, NULL); | ||
550 | } | ||
551 | |||
552 | static const struct file_operations ip_queue_proc_fops = { | ||
553 | .open = ip_queue_open, | ||
554 | .read = seq_read, | ||
555 | .llseek = seq_lseek, | ||
556 | .release = single_release, | ||
557 | .owner = THIS_MODULE, | ||
558 | }; | ||
559 | #endif | ||
560 | |||
561 | static const struct nf_queue_handler nfqh = { | ||
562 | .name = "ip_queue", | ||
563 | .outfn = &ipq_enqueue_packet, | ||
564 | }; | ||
565 | |||
566 | static int __init ip_queue_init(void) | ||
567 | { | ||
568 | int status = -ENOMEM; | ||
569 | struct proc_dir_entry *proc __maybe_unused; | ||
570 | |||
571 | netlink_register_notifier(&ipq_nl_notifier); | ||
572 | ipqnl = netlink_kernel_create(&init_net, NETLINK_FIREWALL, 0, | ||
573 | ipq_rcv_skb, NULL, THIS_MODULE); | ||
574 | if (ipqnl == NULL) { | ||
575 | printk(KERN_ERR "ip_queue: failed to create netlink socket\n"); | ||
576 | goto cleanup_netlink_notifier; | ||
577 | } | ||
578 | |||
579 | #ifdef CONFIG_PROC_FS | ||
580 | proc = proc_create(IPQ_PROC_FS_NAME, 0, init_net.proc_net, | ||
581 | &ip_queue_proc_fops); | ||
582 | if (!proc) { | ||
583 | printk(KERN_ERR "ip_queue: failed to create proc entry\n"); | ||
584 | goto cleanup_ipqnl; | ||
585 | } | ||
586 | #endif | ||
587 | register_netdevice_notifier(&ipq_dev_notifier); | ||
588 | #ifdef CONFIG_SYSCTL | ||
589 | ipq_sysctl_header = register_net_sysctl(&init_net, "net/ipv4", ipq_table); | ||
590 | #endif | ||
591 | status = nf_register_queue_handler(NFPROTO_IPV4, &nfqh); | ||
592 | if (status < 0) { | ||
593 | printk(KERN_ERR "ip_queue: failed to register queue handler\n"); | ||
594 | goto cleanup_sysctl; | ||
595 | } | ||
596 | return status; | ||
597 | |||
598 | cleanup_sysctl: | ||
599 | #ifdef CONFIG_SYSCTL | ||
600 | unregister_net_sysctl_table(ipq_sysctl_header); | ||
601 | #endif | ||
602 | unregister_netdevice_notifier(&ipq_dev_notifier); | ||
603 | proc_net_remove(&init_net, IPQ_PROC_FS_NAME); | ||
604 | cleanup_ipqnl: __maybe_unused | ||
605 | netlink_kernel_release(ipqnl); | ||
606 | mutex_lock(&ipqnl_mutex); | ||
607 | mutex_unlock(&ipqnl_mutex); | ||
608 | |||
609 | cleanup_netlink_notifier: | ||
610 | netlink_unregister_notifier(&ipq_nl_notifier); | ||
611 | return status; | ||
612 | } | ||
613 | |||
614 | static void __exit ip_queue_fini(void) | ||
615 | { | ||
616 | nf_unregister_queue_handlers(&nfqh); | ||
617 | |||
618 | ipq_flush(NULL, 0); | ||
619 | |||
620 | #ifdef CONFIG_SYSCTL | ||
621 | unregister_net_sysctl_table(ipq_sysctl_header); | ||
622 | #endif | ||
623 | unregister_netdevice_notifier(&ipq_dev_notifier); | ||
624 | proc_net_remove(&init_net, IPQ_PROC_FS_NAME); | ||
625 | |||
626 | netlink_kernel_release(ipqnl); | ||
627 | mutex_lock(&ipqnl_mutex); | ||
628 | mutex_unlock(&ipqnl_mutex); | ||
629 | |||
630 | netlink_unregister_notifier(&ipq_nl_notifier); | ||
631 | } | ||
632 | |||
633 | MODULE_DESCRIPTION("IPv4 packet queue handler"); | ||
634 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); | ||
635 | MODULE_LICENSE("GPL"); | ||
636 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_FIREWALL); | ||
637 | |||
638 | module_init(ip_queue_init); | ||
639 | module_exit(ip_queue_fini); | ||
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index d33cddd16fbb..10135342799e 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -25,28 +25,6 @@ config NF_CONNTRACK_IPV6 | |||
25 | 25 | ||
26 | To compile it as a module, choose M here. If unsure, say N. | 26 | To compile it as a module, choose M here. If unsure, say N. |
27 | 27 | ||
28 | config IP6_NF_QUEUE | ||
29 | tristate "IP6 Userspace queueing via NETLINK (OBSOLETE)" | ||
30 | depends on INET && IPV6 && NETFILTER | ||
31 | depends on NETFILTER_ADVANCED | ||
32 | ---help--- | ||
33 | |||
34 | This option adds a queue handler to the kernel for IPv6 | ||
35 | packets which enables users to receive the filtered packets | ||
36 | with QUEUE target using libipq. | ||
37 | |||
38 | This option enables the old IPv6-only "ip6_queue" implementation | ||
39 | which has been obsoleted by the new "nfnetlink_queue" code (see | ||
40 | CONFIG_NETFILTER_NETLINK_QUEUE). | ||
41 | |||
42 | (C) Fernando Anton 2001 | ||
43 | IPv64 Project - Work based in IPv64 draft by Arturo Azcorra. | ||
44 | Universidad Carlos III de Madrid | ||
45 | Universidad Politecnica de Alcala de Henares | ||
46 | email: <fanton@it.uc3m.es>. | ||
47 | |||
48 | To compile it as a module, choose M here. If unsure, say N. | ||
49 | |||
50 | config IP6_NF_IPTABLES | 28 | config IP6_NF_IPTABLES |
51 | tristate "IP6 tables support (required for filtering)" | 29 | tristate "IP6 tables support (required for filtering)" |
52 | depends on INET && IPV6 | 30 | depends on INET && IPV6 |
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile index d4dfd0a21097..534d3f216f7b 100644 --- a/net/ipv6/netfilter/Makefile +++ b/net/ipv6/netfilter/Makefile | |||
@@ -6,7 +6,6 @@ | |||
6 | obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o | 6 | obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o |
7 | obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o | 7 | obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o |
8 | obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o | 8 | obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o |
9 | obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o | ||
10 | obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o | 9 | obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o |
11 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o | 10 | obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o |
12 | 11 | ||
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c deleted file mode 100644 index 3ca9303b3a19..000000000000 --- a/net/ipv6/netfilter/ip6_queue.c +++ /dev/null | |||
@@ -1,641 +0,0 @@ | |||
1 | /* | ||
2 | * This is a module which is used for queueing IPv6 packets and | ||
3 | * communicating with userspace via netlink. | ||
4 | * | ||
5 | * (C) 2001 Fernando Anton, this code is GPL. | ||
6 | * IPv64 Project - Work based in IPv64 draft by Arturo Azcorra. | ||
7 | * Universidad Carlos III de Madrid - Leganes (Madrid) - Spain | ||
8 | * Universidad Politecnica de Alcala de Henares - Alcala de H. (Madrid) - Spain | ||
9 | * email: fanton@it.uc3m.es | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/skbuff.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/ipv6.h> | ||
19 | #include <linux/notifier.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/netfilter.h> | ||
22 | #include <linux/netlink.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/sysctl.h> | ||
25 | #include <linux/proc_fs.h> | ||
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <net/net_namespace.h> | ||
30 | #include <net/sock.h> | ||
31 | #include <net/ipv6.h> | ||
32 | #include <net/ip6_route.h> | ||
33 | #include <net/netfilter/nf_queue.h> | ||
34 | #include <linux/netfilter_ipv4/ip_queue.h> | ||
35 | #include <linux/netfilter_ipv4/ip_tables.h> | ||
36 | #include <linux/netfilter_ipv6/ip6_tables.h> | ||
37 | |||
38 | #define IPQ_QMAX_DEFAULT 1024 | ||
39 | #define IPQ_PROC_FS_NAME "ip6_queue" | ||
40 | #define NET_IPQ_QMAX_NAME "ip6_queue_maxlen" | ||
41 | |||
42 | typedef int (*ipq_cmpfn)(struct nf_queue_entry *, unsigned long); | ||
43 | |||
44 | static unsigned char copy_mode __read_mostly = IPQ_COPY_NONE; | ||
45 | static unsigned int queue_maxlen __read_mostly = IPQ_QMAX_DEFAULT; | ||
46 | static DEFINE_SPINLOCK(queue_lock); | ||
47 | static int peer_pid __read_mostly; | ||
48 | static unsigned int copy_range __read_mostly; | ||
49 | static unsigned int queue_total; | ||
50 | static unsigned int queue_dropped = 0; | ||
51 | static unsigned int queue_user_dropped = 0; | ||
52 | static struct sock *ipqnl __read_mostly; | ||
53 | static LIST_HEAD(queue_list); | ||
54 | static DEFINE_MUTEX(ipqnl_mutex); | ||
55 | |||
56 | static inline void | ||
57 | __ipq_enqueue_entry(struct nf_queue_entry *entry) | ||
58 | { | ||
59 | list_add_tail(&entry->list, &queue_list); | ||
60 | queue_total++; | ||
61 | } | ||
62 | |||
63 | static inline int | ||
64 | __ipq_set_mode(unsigned char mode, unsigned int range) | ||
65 | { | ||
66 | int status = 0; | ||
67 | |||
68 | switch(mode) { | ||
69 | case IPQ_COPY_NONE: | ||
70 | case IPQ_COPY_META: | ||
71 | copy_mode = mode; | ||
72 | copy_range = 0; | ||
73 | break; | ||
74 | |||
75 | case IPQ_COPY_PACKET: | ||
76 | if (range > 0xFFFF) | ||
77 | range = 0xFFFF; | ||
78 | copy_range = range; | ||
79 | copy_mode = mode; | ||
80 | break; | ||
81 | |||
82 | default: | ||
83 | status = -EINVAL; | ||
84 | |||
85 | } | ||
86 | return status; | ||
87 | } | ||
88 | |||
89 | static void __ipq_flush(ipq_cmpfn cmpfn, unsigned long data); | ||
90 | |||
91 | static inline void | ||
92 | __ipq_reset(void) | ||
93 | { | ||
94 | peer_pid = 0; | ||
95 | net_disable_timestamp(); | ||
96 | __ipq_set_mode(IPQ_COPY_NONE, 0); | ||
97 | __ipq_flush(NULL, 0); | ||
98 | } | ||
99 | |||
100 | static struct nf_queue_entry * | ||
101 | ipq_find_dequeue_entry(unsigned long id) | ||
102 | { | ||
103 | struct nf_queue_entry *entry = NULL, *i; | ||
104 | |||
105 | spin_lock_bh(&queue_lock); | ||
106 | |||
107 | list_for_each_entry(i, &queue_list, list) { | ||
108 | if ((unsigned long)i == id) { | ||
109 | entry = i; | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (entry) { | ||
115 | list_del(&entry->list); | ||
116 | queue_total--; | ||
117 | } | ||
118 | |||
119 | spin_unlock_bh(&queue_lock); | ||
120 | return entry; | ||
121 | } | ||
122 | |||
123 | static void | ||
124 | __ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | ||
125 | { | ||
126 | struct nf_queue_entry *entry, *next; | ||
127 | |||
128 | list_for_each_entry_safe(entry, next, &queue_list, list) { | ||
129 | if (!cmpfn || cmpfn(entry, data)) { | ||
130 | list_del(&entry->list); | ||
131 | queue_total--; | ||
132 | nf_reinject(entry, NF_DROP); | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | ipq_flush(ipq_cmpfn cmpfn, unsigned long data) | ||
139 | { | ||
140 | spin_lock_bh(&queue_lock); | ||
141 | __ipq_flush(cmpfn, data); | ||
142 | spin_unlock_bh(&queue_lock); | ||
143 | } | ||
144 | |||
145 | static struct sk_buff * | ||
146 | ipq_build_packet_message(struct nf_queue_entry *entry, int *errp) | ||
147 | { | ||
148 | sk_buff_data_t old_tail; | ||
149 | size_t size = 0; | ||
150 | size_t data_len = 0; | ||
151 | struct sk_buff *skb; | ||
152 | struct ipq_packet_msg *pmsg; | ||
153 | struct nlmsghdr *nlh; | ||
154 | struct timeval tv; | ||
155 | |||
156 | switch (ACCESS_ONCE(copy_mode)) { | ||
157 | case IPQ_COPY_META: | ||
158 | case IPQ_COPY_NONE: | ||
159 | size = NLMSG_SPACE(sizeof(*pmsg)); | ||
160 | break; | ||
161 | |||
162 | case IPQ_COPY_PACKET: | ||
163 | if (entry->skb->ip_summed == CHECKSUM_PARTIAL && | ||
164 | (*errp = skb_checksum_help(entry->skb))) | ||
165 | return NULL; | ||
166 | |||
167 | data_len = ACCESS_ONCE(copy_range); | ||
168 | if (data_len == 0 || data_len > entry->skb->len) | ||
169 | data_len = entry->skb->len; | ||
170 | |||
171 | size = NLMSG_SPACE(sizeof(*pmsg) + data_len); | ||
172 | break; | ||
173 | |||
174 | default: | ||
175 | *errp = -EINVAL; | ||
176 | return NULL; | ||
177 | } | ||
178 | |||
179 | skb = alloc_skb(size, GFP_ATOMIC); | ||
180 | if (!skb) | ||
181 | goto nlmsg_failure; | ||
182 | |||
183 | old_tail = skb->tail; | ||
184 | nlh = NLMSG_PUT(skb, 0, 0, IPQM_PACKET, size - sizeof(*nlh)); | ||
185 | pmsg = NLMSG_DATA(nlh); | ||
186 | memset(pmsg, 0, sizeof(*pmsg)); | ||
187 | |||
188 | pmsg->packet_id = (unsigned long )entry; | ||
189 | pmsg->data_len = data_len; | ||
190 | tv = ktime_to_timeval(entry->skb->tstamp); | ||
191 | pmsg->timestamp_sec = tv.tv_sec; | ||
192 | pmsg->timestamp_usec = tv.tv_usec; | ||
193 | pmsg->mark = entry->skb->mark; | ||
194 | pmsg->hook = entry->hook; | ||
195 | pmsg->hw_protocol = entry->skb->protocol; | ||
196 | |||
197 | if (entry->indev) | ||
198 | strcpy(pmsg->indev_name, entry->indev->name); | ||
199 | else | ||
200 | pmsg->indev_name[0] = '\0'; | ||
201 | |||
202 | if (entry->outdev) | ||
203 | strcpy(pmsg->outdev_name, entry->outdev->name); | ||
204 | else | ||
205 | pmsg->outdev_name[0] = '\0'; | ||
206 | |||
207 | if (entry->indev && entry->skb->dev && | ||
208 | entry->skb->mac_header != entry->skb->network_header) { | ||
209 | pmsg->hw_type = entry->skb->dev->type; | ||
210 | pmsg->hw_addrlen = dev_parse_header(entry->skb, pmsg->hw_addr); | ||
211 | } | ||
212 | |||
213 | if (data_len) | ||
214 | if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len)) | ||
215 | BUG(); | ||
216 | |||
217 | nlh->nlmsg_len = skb->tail - old_tail; | ||
218 | return skb; | ||
219 | |||
220 | nlmsg_failure: | ||
221 | kfree_skb(skb); | ||
222 | *errp = -EINVAL; | ||
223 | printk(KERN_ERR "ip6_queue: error creating packet message\n"); | ||
224 | return NULL; | ||
225 | } | ||
226 | |||
227 | static int | ||
228 | ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) | ||
229 | { | ||
230 | int status = -EINVAL; | ||
231 | struct sk_buff *nskb; | ||
232 | |||
233 | if (copy_mode == IPQ_COPY_NONE) | ||
234 | return -EAGAIN; | ||
235 | |||
236 | nskb = ipq_build_packet_message(entry, &status); | ||
237 | if (nskb == NULL) | ||
238 | return status; | ||
239 | |||
240 | spin_lock_bh(&queue_lock); | ||
241 | |||
242 | if (!peer_pid) | ||
243 | goto err_out_free_nskb; | ||
244 | |||
245 | if (queue_total >= queue_maxlen) { | ||
246 | queue_dropped++; | ||
247 | status = -ENOSPC; | ||
248 | if (net_ratelimit()) | ||
249 | printk (KERN_WARNING "ip6_queue: fill at %d entries, " | ||
250 | "dropping packet(s). Dropped: %d\n", queue_total, | ||
251 | queue_dropped); | ||
252 | goto err_out_free_nskb; | ||
253 | } | ||
254 | |||
255 | /* netlink_unicast will either free the nskb or attach it to a socket */ | ||
256 | status = netlink_unicast(ipqnl, nskb, peer_pid, MSG_DONTWAIT); | ||
257 | if (status < 0) { | ||
258 | queue_user_dropped++; | ||
259 | goto err_out_unlock; | ||
260 | } | ||
261 | |||
262 | __ipq_enqueue_entry(entry); | ||
263 | |||
264 | spin_unlock_bh(&queue_lock); | ||
265 | return status; | ||
266 | |||
267 | err_out_free_nskb: | ||
268 | kfree_skb(nskb); | ||
269 | |||
270 | err_out_unlock: | ||
271 | spin_unlock_bh(&queue_lock); | ||
272 | return status; | ||
273 | } | ||
274 | |||
275 | static int | ||
276 | ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e) | ||
277 | { | ||
278 | int diff; | ||
279 | struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; | ||
280 | struct sk_buff *nskb; | ||
281 | |||
282 | if (v->data_len < sizeof(*user_iph)) | ||
283 | return 0; | ||
284 | diff = v->data_len - e->skb->len; | ||
285 | if (diff < 0) { | ||
286 | if (pskb_trim(e->skb, v->data_len)) | ||
287 | return -ENOMEM; | ||
288 | } else if (diff > 0) { | ||
289 | if (v->data_len > 0xFFFF) | ||
290 | return -EINVAL; | ||
291 | if (diff > skb_tailroom(e->skb)) { | ||
292 | nskb = skb_copy_expand(e->skb, skb_headroom(e->skb), | ||
293 | diff, GFP_ATOMIC); | ||
294 | if (!nskb) { | ||
295 | printk(KERN_WARNING "ip6_queue: OOM " | ||
296 | "in mangle, dropping packet\n"); | ||
297 | return -ENOMEM; | ||
298 | } | ||
299 | kfree_skb(e->skb); | ||
300 | e->skb = nskb; | ||
301 | } | ||
302 | skb_put(e->skb, diff); | ||
303 | } | ||
304 | if (!skb_make_writable(e->skb, v->data_len)) | ||
305 | return -ENOMEM; | ||
306 | skb_copy_to_linear_data(e->skb, v->payload, v->data_len); | ||
307 | e->skb->ip_summed = CHECKSUM_NONE; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int | ||
313 | ipq_set_verdict(struct ipq_verdict_msg *vmsg, unsigned int len) | ||
314 | { | ||
315 | struct nf_queue_entry *entry; | ||
316 | |||
317 | if (vmsg->value > NF_MAX_VERDICT || vmsg->value == NF_STOLEN) | ||
318 | return -EINVAL; | ||
319 | |||
320 | entry = ipq_find_dequeue_entry(vmsg->id); | ||
321 | if (entry == NULL) | ||
322 | return -ENOENT; | ||
323 | else { | ||
324 | int verdict = vmsg->value; | ||
325 | |||
326 | if (vmsg->data_len && vmsg->data_len == len) | ||
327 | if (ipq_mangle_ipv6(vmsg, entry) < 0) | ||
328 | verdict = NF_DROP; | ||
329 | |||
330 | nf_reinject(entry, verdict); | ||
331 | return 0; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | static int | ||
336 | ipq_set_mode(unsigned char mode, unsigned int range) | ||
337 | { | ||
338 | int status; | ||
339 | |||
340 | spin_lock_bh(&queue_lock); | ||
341 | status = __ipq_set_mode(mode, range); | ||
342 | spin_unlock_bh(&queue_lock); | ||
343 | return status; | ||
344 | } | ||
345 | |||
346 | static int | ||
347 | ipq_receive_peer(struct ipq_peer_msg *pmsg, | ||
348 | unsigned char type, unsigned int len) | ||
349 | { | ||
350 | int status = 0; | ||
351 | |||
352 | if (len < sizeof(*pmsg)) | ||
353 | return -EINVAL; | ||
354 | |||
355 | switch (type) { | ||
356 | case IPQM_MODE: | ||
357 | status = ipq_set_mode(pmsg->msg.mode.value, | ||
358 | pmsg->msg.mode.range); | ||
359 | break; | ||
360 | |||
361 | case IPQM_VERDICT: | ||
362 | status = ipq_set_verdict(&pmsg->msg.verdict, | ||
363 | len - sizeof(*pmsg)); | ||
364 | break; | ||
365 | default: | ||
366 | status = -EINVAL; | ||
367 | } | ||
368 | return status; | ||
369 | } | ||
370 | |||
371 | static int | ||
372 | dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) | ||
373 | { | ||
374 | if (entry->indev) | ||
375 | if (entry->indev->ifindex == ifindex) | ||
376 | return 1; | ||
377 | |||
378 | if (entry->outdev) | ||
379 | if (entry->outdev->ifindex == ifindex) | ||
380 | return 1; | ||
381 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
382 | if (entry->skb->nf_bridge) { | ||
383 | if (entry->skb->nf_bridge->physindev && | ||
384 | entry->skb->nf_bridge->physindev->ifindex == ifindex) | ||
385 | return 1; | ||
386 | if (entry->skb->nf_bridge->physoutdev && | ||
387 | entry->skb->nf_bridge->physoutdev->ifindex == ifindex) | ||
388 | return 1; | ||
389 | } | ||
390 | #endif | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static void | ||
395 | ipq_dev_drop(int ifindex) | ||
396 | { | ||
397 | ipq_flush(dev_cmp, ifindex); | ||
398 | } | ||
399 | |||
400 | #define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0) | ||
401 | |||
402 | static inline void | ||
403 | __ipq_rcv_skb(struct sk_buff *skb) | ||
404 | { | ||
405 | int status, type, pid, flags; | ||
406 | unsigned int nlmsglen, skblen; | ||
407 | struct nlmsghdr *nlh; | ||
408 | bool enable_timestamp = false; | ||
409 | |||
410 | skblen = skb->len; | ||
411 | if (skblen < sizeof(*nlh)) | ||
412 | return; | ||
413 | |||
414 | nlh = nlmsg_hdr(skb); | ||
415 | nlmsglen = nlh->nlmsg_len; | ||
416 | if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen) | ||
417 | return; | ||
418 | |||
419 | pid = nlh->nlmsg_pid; | ||
420 | flags = nlh->nlmsg_flags; | ||
421 | |||
422 | if(pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI) | ||
423 | RCV_SKB_FAIL(-EINVAL); | ||
424 | |||
425 | if (flags & MSG_TRUNC) | ||
426 | RCV_SKB_FAIL(-ECOMM); | ||
427 | |||
428 | type = nlh->nlmsg_type; | ||
429 | if (type < NLMSG_NOOP || type >= IPQM_MAX) | ||
430 | RCV_SKB_FAIL(-EINVAL); | ||
431 | |||
432 | if (type <= IPQM_BASE) | ||
433 | return; | ||
434 | |||
435 | if (!capable(CAP_NET_ADMIN)) | ||
436 | RCV_SKB_FAIL(-EPERM); | ||
437 | |||
438 | spin_lock_bh(&queue_lock); | ||
439 | |||
440 | if (peer_pid) { | ||
441 | if (peer_pid != pid) { | ||
442 | spin_unlock_bh(&queue_lock); | ||
443 | RCV_SKB_FAIL(-EBUSY); | ||
444 | } | ||
445 | } else { | ||
446 | enable_timestamp = true; | ||
447 | peer_pid = pid; | ||
448 | } | ||
449 | |||
450 | spin_unlock_bh(&queue_lock); | ||
451 | if (enable_timestamp) | ||
452 | net_enable_timestamp(); | ||
453 | |||
454 | status = ipq_receive_peer(NLMSG_DATA(nlh), type, | ||
455 | nlmsglen - NLMSG_LENGTH(0)); | ||
456 | if (status < 0) | ||
457 | RCV_SKB_FAIL(status); | ||
458 | |||
459 | if (flags & NLM_F_ACK) | ||
460 | netlink_ack(skb, nlh, 0); | ||
461 | } | ||
462 | |||
463 | static void | ||
464 | ipq_rcv_skb(struct sk_buff *skb) | ||
465 | { | ||
466 | mutex_lock(&ipqnl_mutex); | ||
467 | __ipq_rcv_skb(skb); | ||
468 | mutex_unlock(&ipqnl_mutex); | ||
469 | } | ||
470 | |||
471 | static int | ||
472 | ipq_rcv_dev_event(struct notifier_block *this, | ||
473 | unsigned long event, void *ptr) | ||
474 | { | ||
475 | struct net_device *dev = ptr; | ||
476 | |||
477 | if (!net_eq(dev_net(dev), &init_net)) | ||
478 | return NOTIFY_DONE; | ||
479 | |||
480 | /* Drop any packets associated with the downed device */ | ||
481 | if (event == NETDEV_DOWN) | ||
482 | ipq_dev_drop(dev->ifindex); | ||
483 | return NOTIFY_DONE; | ||
484 | } | ||
485 | |||
486 | static struct notifier_block ipq_dev_notifier = { | ||
487 | .notifier_call = ipq_rcv_dev_event, | ||
488 | }; | ||
489 | |||
490 | static int | ||
491 | ipq_rcv_nl_event(struct notifier_block *this, | ||
492 | unsigned long event, void *ptr) | ||
493 | { | ||
494 | struct netlink_notify *n = ptr; | ||
495 | |||
496 | if (event == NETLINK_URELEASE && n->protocol == NETLINK_IP6_FW) { | ||
497 | spin_lock_bh(&queue_lock); | ||
498 | if ((net_eq(n->net, &init_net)) && (n->pid == peer_pid)) | ||
499 | __ipq_reset(); | ||
500 | spin_unlock_bh(&queue_lock); | ||
501 | } | ||
502 | return NOTIFY_DONE; | ||
503 | } | ||
504 | |||
505 | static struct notifier_block ipq_nl_notifier = { | ||
506 | .notifier_call = ipq_rcv_nl_event, | ||
507 | }; | ||
508 | |||
509 | #ifdef CONFIG_SYSCTL | ||
510 | static struct ctl_table_header *ipq_sysctl_header; | ||
511 | |||
512 | static ctl_table ipq_table[] = { | ||
513 | { | ||
514 | .procname = NET_IPQ_QMAX_NAME, | ||
515 | .data = &queue_maxlen, | ||
516 | .maxlen = sizeof(queue_maxlen), | ||
517 | .mode = 0644, | ||
518 | .proc_handler = proc_dointvec | ||
519 | }, | ||
520 | { } | ||
521 | }; | ||
522 | #endif | ||
523 | |||
524 | #ifdef CONFIG_PROC_FS | ||
525 | static int ip6_queue_show(struct seq_file *m, void *v) | ||
526 | { | ||
527 | spin_lock_bh(&queue_lock); | ||
528 | |||
529 | seq_printf(m, | ||
530 | "Peer PID : %d\n" | ||
531 | "Copy mode : %hu\n" | ||
532 | "Copy range : %u\n" | ||
533 | "Queue length : %u\n" | ||
534 | "Queue max. length : %u\n" | ||
535 | "Queue dropped : %u\n" | ||
536 | "Netfilter dropped : %u\n", | ||
537 | peer_pid, | ||
538 | copy_mode, | ||
539 | copy_range, | ||
540 | queue_total, | ||
541 | queue_maxlen, | ||
542 | queue_dropped, | ||
543 | queue_user_dropped); | ||
544 | |||
545 | spin_unlock_bh(&queue_lock); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int ip6_queue_open(struct inode *inode, struct file *file) | ||
550 | { | ||
551 | return single_open(file, ip6_queue_show, NULL); | ||
552 | } | ||
553 | |||
554 | static const struct file_operations ip6_queue_proc_fops = { | ||
555 | .open = ip6_queue_open, | ||
556 | .read = seq_read, | ||
557 | .llseek = seq_lseek, | ||
558 | .release = single_release, | ||
559 | .owner = THIS_MODULE, | ||
560 | }; | ||
561 | #endif | ||
562 | |||
563 | static const struct nf_queue_handler nfqh = { | ||
564 | .name = "ip6_queue", | ||
565 | .outfn = &ipq_enqueue_packet, | ||
566 | }; | ||
567 | |||
568 | static int __init ip6_queue_init(void) | ||
569 | { | ||
570 | int status = -ENOMEM; | ||
571 | struct proc_dir_entry *proc __maybe_unused; | ||
572 | |||
573 | netlink_register_notifier(&ipq_nl_notifier); | ||
574 | ipqnl = netlink_kernel_create(&init_net, NETLINK_IP6_FW, 0, | ||
575 | ipq_rcv_skb, NULL, THIS_MODULE); | ||
576 | if (ipqnl == NULL) { | ||
577 | printk(KERN_ERR "ip6_queue: failed to create netlink socket\n"); | ||
578 | goto cleanup_netlink_notifier; | ||
579 | } | ||
580 | |||
581 | #ifdef CONFIG_PROC_FS | ||
582 | proc = proc_create(IPQ_PROC_FS_NAME, 0, init_net.proc_net, | ||
583 | &ip6_queue_proc_fops); | ||
584 | if (!proc) { | ||
585 | printk(KERN_ERR "ip6_queue: failed to create proc entry\n"); | ||
586 | goto cleanup_ipqnl; | ||
587 | } | ||
588 | #endif | ||
589 | register_netdevice_notifier(&ipq_dev_notifier); | ||
590 | #ifdef CONFIG_SYSCTL | ||
591 | ipq_sysctl_header = register_net_sysctl(&init_net, "net/ipv6", ipq_table); | ||
592 | #endif | ||
593 | status = nf_register_queue_handler(NFPROTO_IPV6, &nfqh); | ||
594 | if (status < 0) { | ||
595 | printk(KERN_ERR "ip6_queue: failed to register queue handler\n"); | ||
596 | goto cleanup_sysctl; | ||
597 | } | ||
598 | return status; | ||
599 | |||
600 | cleanup_sysctl: | ||
601 | #ifdef CONFIG_SYSCTL | ||
602 | unregister_net_sysctl_table(ipq_sysctl_header); | ||
603 | #endif | ||
604 | unregister_netdevice_notifier(&ipq_dev_notifier); | ||
605 | proc_net_remove(&init_net, IPQ_PROC_FS_NAME); | ||
606 | |||
607 | cleanup_ipqnl: __maybe_unused | ||
608 | netlink_kernel_release(ipqnl); | ||
609 | mutex_lock(&ipqnl_mutex); | ||
610 | mutex_unlock(&ipqnl_mutex); | ||
611 | |||
612 | cleanup_netlink_notifier: | ||
613 | netlink_unregister_notifier(&ipq_nl_notifier); | ||
614 | return status; | ||
615 | } | ||
616 | |||
617 | static void __exit ip6_queue_fini(void) | ||
618 | { | ||
619 | nf_unregister_queue_handlers(&nfqh); | ||
620 | |||
621 | ipq_flush(NULL, 0); | ||
622 | |||
623 | #ifdef CONFIG_SYSCTL | ||
624 | unregister_net_sysctl_table(ipq_sysctl_header); | ||
625 | #endif | ||
626 | unregister_netdevice_notifier(&ipq_dev_notifier); | ||
627 | proc_net_remove(&init_net, IPQ_PROC_FS_NAME); | ||
628 | |||
629 | netlink_kernel_release(ipqnl); | ||
630 | mutex_lock(&ipqnl_mutex); | ||
631 | mutex_unlock(&ipqnl_mutex); | ||
632 | |||
633 | netlink_unregister_notifier(&ipq_nl_notifier); | ||
634 | } | ||
635 | |||
636 | MODULE_DESCRIPTION("IPv6 packet queue handler"); | ||
637 | MODULE_LICENSE("GPL"); | ||
638 | MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_IP6_FW); | ||
639 | |||
640 | module_init(ip6_queue_init); | ||
641 | module_exit(ip6_queue_fini); | ||
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 0920ea3bf599..d309e7f472d8 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/netlink.h> | 14 | #include <linux/netlink.h> |
15 | #include <linux/rtnetlink.h> | 15 | #include <linux/rtnetlink.h> |
16 | #include <linux/if.h> | 16 | #include <linux/if.h> |
17 | #include <linux/netfilter_ipv4/ip_queue.h> | ||
18 | #include <linux/inet_diag.h> | 17 | #include <linux/inet_diag.h> |
19 | #include <linux/xfrm.h> | 18 | #include <linux/xfrm.h> |
20 | #include <linux/audit.h> | 19 | #include <linux/audit.h> |
@@ -70,12 +69,6 @@ static struct nlmsg_perm nlmsg_route_perms[] = | |||
70 | { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, | 69 | { RTM_SETDCB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, |
71 | }; | 70 | }; |
72 | 71 | ||
73 | static struct nlmsg_perm nlmsg_firewall_perms[] = | ||
74 | { | ||
75 | { IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE }, | ||
76 | { IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE }, | ||
77 | }; | ||
78 | |||
79 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = | 72 | static struct nlmsg_perm nlmsg_tcpdiag_perms[] = |
80 | { | 73 | { |
81 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, | 74 | { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ }, |
@@ -145,12 +138,6 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) | |||
145 | sizeof(nlmsg_route_perms)); | 138 | sizeof(nlmsg_route_perms)); |
146 | break; | 139 | break; |
147 | 140 | ||
148 | case SECCLASS_NETLINK_FIREWALL_SOCKET: | ||
149 | case SECCLASS_NETLINK_IP6FW_SOCKET: | ||
150 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_firewall_perms, | ||
151 | sizeof(nlmsg_firewall_perms)); | ||
152 | break; | ||
153 | |||
154 | case SECCLASS_NETLINK_TCPDIAG_SOCKET: | 141 | case SECCLASS_NETLINK_TCPDIAG_SOCKET: |
155 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, | 142 | err = nlmsg_perm(nlmsg_type, perm, nlmsg_tcpdiag_perms, |
156 | sizeof(nlmsg_tcpdiag_perms)); | 143 | sizeof(nlmsg_tcpdiag_perms)); |