[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 4 Apr 2012 10:16:16 +0100
From: Nuno Martins <nuno.martins@...xamagica.pt>
To: netdev <netdev@...r.kernel.org>, nuno.martins@...xamagica.pt
Cc: Alfredo Matos <alfredo.matos@...xamagica.pt>,
Paulo Trezentos <paulo.trezentos@...xamagica.pt>
Subject: [RFC PATCH 1/2] Multiple filter function support for BPF filters
This patch introduces the possibility of attaching multiple filter functions to a PF socket, useful for custom packet filtering.
It maintains a list of registered functions, received through setsockopt from userspace.
The custom filtering functions are compatible with BPF/LSF filter in order to retain compatibility with sk_run_filter and the pcap library.
This mechanism was developed to support the network monitoring by process id on the kernel (second patch in this series).
Signed-off-by: Nuno Martins <nuno.martins@...xamagica.pt>
---
include/asm-generic/socket.h | 4 ++
include/linux/filter.h | 3 +-
include/linux/socket.h | 28 +++++++++
net/Kconfig | 8 +++
net/core/Makefile | 3 +-
net/core/filter.c | 3 +-
net/core/filter_function.c | 138 ++++++++++++++++++++++++++++++++++++++++++
net/core/sock.c | 23 ++++++-
8 files changed, 206 insertions(+), 4 deletions(-)
diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h
index b1bea03..89c45a9 100644
--- a/include/asm-generic/socket.h
+++ b/include/asm-generic/socket.h
@@ -72,4 +72,8 @@
/* Instruct lower device to use last 4-bytes of skb data as FCS */
#define SO_NOFCS 43
+#ifdef CONFIG_FILTER_FUNCTION
+#define SO_ATTACH_FILTER_FUNC 44
+#define SO_DETACH_FILTER_FUNC 45
+#endif
#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 8eeb205..8d2d9c2 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -90,6 +90,7 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
#define BPF_MISCOP(code) ((code) & 0xf8)
#define BPF_TAX 0x00
#define BPF_TXA 0x80
+#define BPF_PROC 0xf0
#ifndef BPF_MAXINSNS
#define BPF_MAXINSNS 4096
@@ -168,7 +169,7 @@ static inline void bpf_jit_compile(struct sk_filter *fp)
static inline void bpf_jit_free(struct sk_filter *fp)
{
}
-#define SK_RUN_FILTER(FILTER, SKB) sk_run_filter(SKB, FILTER->insns)
+#define SK_RUN_FILTER(FILTER, SKB) (*FILTER->bpf_func)(SKB, FILTER->insns)
#endif
enum {
diff --git a/include/linux/socket.h b/include/linux/socket.h
index da2d3e2..12acea5 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -316,6 +316,34 @@ struct ucred {
/* IPX options */
#define IPX_TYPE 1
+#ifdef CONFIG_FILTER_FUNCTION
+#define FILTER_FUNCTION_NAME_LEN 25
+struct filter_function_struct {
+ char name[FILTER_FUNCTION_NAME_LEN];
+ int pid;
+};
+
+#include <linux/list.h>
+
+struct sk_buff;
+struct sock_filter;
+struct sock;
+struct sk_filter;
+
+struct filter_function {
+ struct list_head list;
+ char name[FILTER_FUNCTION_NAME_LEN];
+ int (*init_func)(struct filter_function_struct *ffs);
+ unsigned int (*func)(const struct sk_buff *skb, const struct sock_filter *filter);
+};
+
+extern int attach_filter_function(struct filter_function_struct *ffs, struct sock *sk);
+extern int detach_filter_function(struct filter_function_struct *ffs, struct sock *sk);
+extern int register_filter_function(struct filter_function *ff);
+extern int unregister_filter_function(struct filter_function *ff);
+extern int detect_filter_function(struct sk_filter *fp);
+#endif
+
extern void cred_to_ucred(struct pid *pid, const struct cred *cred, struct ucred *ucred);
extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
diff --git a/net/Kconfig b/net/Kconfig
index e07272d..6bbce29 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -260,6 +260,14 @@ config BPF_JIT
packet sniffing (libpcap/tcpdump). Note : Admin should enable
this feature changing /proc/sys/net/core/bpf_jit_enable
+config FILTER_FUNCTION
+ bool "enable definition of a sniff function"
+ depends on MODULES
+ default y
+ ---help---
+ Dynamicaly define what sniffer function would be used to filter
+ packets
+
menu "Network testing"
config NET_PKTGEN
diff --git a/net/core/Makefile b/net/core/Makefile
index 674641b..c3378c5 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -3,7 +3,8 @@
#
obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
- gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o
+ gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o \
+ filter_function.o
obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
diff --git a/net/core/filter.c b/net/core/filter.c
index 5dea452..0aa1ac6 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -582,7 +582,8 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
{
struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
- bpf_jit_free(fp);
+ if (detect_filter_function(fp))
+ bpf_jit_free(fp);
kfree(fp);
}
EXPORT_SYMBOL(sk_filter_release_rcu);
diff --git a/net/core/filter_function.c b/net/core/filter_function.c
new file mode 100644
index 0000000..c9b62e3
--- /dev/null
+++ b/net/core/filter_function.c
@@ -0,0 +1,138 @@
+/*
+ * Packet Filtering System based on BPF / LSF
+ *
+ * Author: Nuno Martins <nuno.martins@...xamagica.pt>
+ *
+ * (c) Copyright Caixa Magica Software, LDA., 2012
+ * (c) Copyright Universidade Nova de Lisboa, 2010-2011
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifdef CONFIG_FILTER_FUNCTION
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/filter.h>
+#include <net/sock.h>
+
+LIST_HEAD(filter_list);
+/*EXPORT_SYMBOL(sniff_list);*/
+
+static DEFINE_MUTEX(filter_list_mutex);
+
+int register_filter_function(struct filter_function *ff)
+{
+ list_add(&(ff->list), &filter_list);
+
+ return 0;
+}
+EXPORT_SYMBOL(register_filter_function);
+
+static struct filter_function *find_filter_function_by_addr(void *addr)
+{
+ struct filter_function *ff;
+
+ if (addr == sk_run_filter)
+ return NULL;
+
+ list_for_each_entry(ff, &filter_list, list) {
+ if (ff->func == addr)
+ return ff;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(find_filter_function_by_addr);
+
+static struct filter_function *find_filter_function_by_name(const char *name)
+{
+ struct filter_function *ff;
+ list_for_each_entry(ff, &filter_list, list) {
+ if (strcmp(ff->name, name) == 0)
+ return ff;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(find_filter_function_by_name);
+
+int unregister_filter_function(struct filter_function *ff)
+{
+ list_del(&(ff->list));
+ return 0;
+}
+EXPORT_SYMBOL(unregister_filter_function);
+
+int attach_filter_function(struct filter_function_struct *ffs, struct sock *sk)
+{
+ struct filter_function *ff = NULL;
+ struct sk_filter *old_fp;
+
+ if (strcmp(ffs->name, "sk_run_filter") == 0) {
+ /*if (init_process_filter_function != NULL)
+ init_process_filter_function(ffs);*/
+ } else
+ ff = find_filter_function_by_name(ffs->name);
+
+ if (ff != NULL) {
+ int ret;
+ if (ff->init_func != NULL)
+ ret = ff->init_func(ffs);
+
+ if (ff->func != NULL) {
+ old_fp = rcu_dereference_protected(sk->sk_filter,
+ sock_owned_by_user(sk));
+ if (detect_filter_function(old_fp)) {
+ bpf_jit_free(old_fp);
+ }
+
+ old_fp->bpf_func = ff->func;
+ rcu_assign_pointer(sk->sk_filter, old_fp);
+ }
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(attach_filter_function);
+
+int detach_filter_function(struct filter_function_struct *ffs, struct sock *sk)
+{
+ struct sk_filter *old_fp;
+ struct filter_function *ff;
+
+ old_fp = rcu_dereference_protected(sk->sk_filter,
+ sock_owned_by_user(sk));
+
+ ff = find_filter_function_by_addr(old_fp->bpf_func);
+ if (ff) {
+ return 0;
+ }
+
+ return -1;
+}
+EXPORT_SYMBOL(detach_filter_function);
+
+int detect_filter_function(struct sk_filter *fp)
+{
+ return find_filter_function_by_addr(fp->bpf_func) ? 0 : -1;
+}
+EXPORT_SYMBOL(detect_filter_function);
+#endif
diff --git a/net/core/sock.c b/net/core/sock.c
index 9be6d0d..0583bf6d 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -769,7 +769,28 @@ set_rcvbuf:
case SO_DETACH_FILTER:
ret = sk_detach_filter(sk);
break;
-
+#ifdef CONFIG_FILTER_FUNCTION
+ case SO_ATTACH_FILTER_FUNC:
+ ret = -EINVAL;
+ if (optlen == sizeof(struct filter_function_struct)) {
+ struct filter_function_struct ff;
+ ret = -EFAULT;
+ if (copy_from_user(&ff, optval, sizeof(ff)))
+ break;
+ ret = attach_filter_function(&ff, sk);
+ }
+ break;
+ case SO_DETACH_FILTER_FUNC:
+ ret = -EINVAL;
+ if (optlen == sizeof(struct filter_function_struct)) {
+ struct filter_function_struct ff;
+ ret = -EFAULT;
+ if (copy_from_user(&ff, optval, sizeof(ff)))
+ break;
+ ret = detach_filter_function(&ff, sk);
+ }
+ break;
+#endif
case SO_PASSSEC:
if (valbool)
set_bit(SOCK_PASSSEC, &sock->flags);
--
1.7.10.rc3.11.gd8282
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists