Hi,

Here is a new feature which can help firewalls to be more application
aware, so more useful for people.

Our previous discussion about cn_net and firewalls:
http://marc2.theaimsgroup.com/?t=115976957500002&r=1&w=2

Please, I would really like to have feedback and comments on that tool,
in order to improve it.

Thanks a lot,
Samir Bellabes

tree af484e2d54e2dc43312f171efe1426b236e97bd7
parent 1539b98b561754252dd520b98fa03a688a4f81b5
author Samir Bellabes <[EMAIL PROTECTED]> 1170995340 +0100
committer Samir Bellabes <[EMAIL PROTECTED]> 1170995340 +0100

[PATCH] Network Events Connector

This patch adds a connector which reports networking's events to
userspace.

It's sending events when a userspace application is using
syscalls so with LSM, we are catching this, at hooks : socket_listen,
socket_bind, socket_connect, socket_shutdown and sk_free_security.

Wanted events are dynamically manage from userspace, in a hashtable. A
daemon, cn_net_daemon, is listening for the connector in userspace.

daemon and doc are available here :
http://people.mandriva.com/~sbellabes/cn_net/

Signed-off-by: Samir Bellabes <[EMAIL PROTECTED]>

------------------------------------------------------------------------------

 drivers/connector/Kconfig  |    8 
 drivers/connector/Makefile |    1 
 drivers/connector/cn_net.c |  619 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/cn_net.h     |  122 ++++++++
 include/linux/connector.h  |    5 
 5 files changed, 753 insertions(+), 2 deletions(-)

------------------------------------------------------------------------------

diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig
index e0bdc0d..0b04952 100644
--- a/drivers/connector/Kconfig
+++ b/drivers/connector/Kconfig
@@ -18,4 +18,12 @@ config PROC_EVENTS
          Provide a connector that reports process events to userspace. Send
          events such as fork, exec, id change (uid, gid, suid, etc), and exit.
 
+config NET_EVENTS
+       boolean "Report network events to userspace"
+       depends on CONNECTOR=y && SECURITY_NETWORK
+       default y
+       ---help---
+         Provide a connector that reports networking's events to userspace.
+         Send events such as DCCP/TCP listen/close and UDP bind/close.
+
 endmenu
diff --git a/drivers/connector/Makefile b/drivers/connector/Makefile
index 1f255e4..436bb5d 100644
--- a/drivers/connector/Makefile
+++ b/drivers/connector/Makefile
@@ -1,4 +1,5 @@
 obj-$(CONFIG_CONNECTOR)                += cn.o
 obj-$(CONFIG_PROC_EVENTS)      += cn_proc.o
+obj-$(CONFIG_NET_EVENTS)       += cn_net.o
 
 cn-y                           += cn_queue.o connector.o
diff --git a/drivers/connector/cn_net.c b/drivers/connector/cn_net.c
new file mode 100644
index 0000000..1f681f6
--- /dev/null
+++ b/drivers/connector/cn_net.c
@@ -0,0 +1,619 @@
+/* 
+ * drivers/connector/cn_net.c
+ *
+ * Network events connector
+ * Samir Bellabes <[EMAIL PROTECTED]>
+ *
+ *     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.
+ */ 
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/security.h>
+#include <linux/netlink.h>
+#include <linux/connector.h>
+#include <linux/net.h>
+#include <net/sock.h>
+#include <net/inet_sock.h>
+#include <linux/in.h>
+#include <linux/ipv6.h>
+#include <linux/in6.h>
+#include <linux/jhash.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+
+#include <linux/cn_net.h>
+
+static atomic_t net_event_num_listeners = ATOMIC_INIT(0);
+static struct cb_id cn_net_event_id = { CN_IDX_NET, CN_VAL_NET };
+static char cn_net_event_name[] = "cn_net_event";
+static int secondary = 0;
+
+static struct list_head *hash = NULL;
+static rwlock_t hash_lock = RW_LOCK_UNLOCKED;
+static int hash_size = 4;
+module_param(hash_size, uint, 0600);
+
+#if defined(CONFIG_NET_EVENTS)
+#define MY_NAME THIS_MODULE->name
+#else
+#define MY_NAME "cn_net"
+#endif
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/**
+ * is_same_event()
+ * check if two events are the same or not
+ */                     
+static unsigned int is_same_event(struct event one, struct event two) {
+       return ((one.syscall_num == two.syscall_num) &&
+               (one.protocol == two.protocol));
+}
+
+/**
+ * check_event()
+ * look for a match in the hash table
+ * Returns 1 if data is in the hash table
+ */
+static unsigned int check_event(struct event_list *data) {
+       unsigned int err = 0, h = 0;
+       struct list_head *l;
+       struct event_list *evl;
+
+       h = jhash(&(data->ev), sizeof(struct event), 0) % hash_size;
+
+       read_lock(&hash_lock);
+       l = &hash[h];
+       list_for_each_entry(evl, l, list) {
+               if (is_same_event(evl->ev, data->ev)) {
+                       err = 1;
+                       break;
+               }
+       }
+       read_unlock(&hash_lock);
+       return err;
+}
+
+/**
+ * check_wanted_data
+ * We don't send unwanted informations to userspace, according to the
+ * dynamic configuration in the hash table.
+ * @sock: sock which is changing its state
+ * Returns: 1 if data have to be send to userspace
+ */
+static int check_wanted_data(struct sock *sk, enum cn_net_socket syscall_num) {
+       struct event_list *data = NULL;
+       unsigned int err = 0;
+
+       if (!sk)
+               return -EINVAL;
+       
+       data = kzalloc(sizeof(struct event_list), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       data->ev.syscall_num = syscall_num;
+       data->ev.protocol = sk->sk_protocol;
+       INIT_LIST_HEAD(&(data->list));
+
+       /* check if the event is already registered */
+       err = check_event(data);
+       kfree(data);
+       return err;
+}
+
+/**
+ * dump_event() dumps the entire hash_table in log
+ */
+static void dump_event(struct list_head *hash) {
+       unsigned int i = 0;
+       struct list_head *l = NULL;
+       struct event_list *evl = NULL;
+       
+       read_lock(&hash_lock);
+       for (i = 0; i < hash_size; i++) {
+               l = &hash[i];
+               printk(KERN_INFO "----\n");
+               printk(KERN_INFO "%d.\n", i);
+               list_for_each_entry(evl, l, list) {
+                       printk(KERN_INFO " %d:%s\n",
+                              evl->ev.protocol, 
syscall_name[evl->ev.syscall_num]);
+               }
+       }
+       read_unlock(&hash_lock);
+
+       return;
+}
+
+/**
+ * deletion of all elements in the hashtable
+ */
+static enum ack_err clean_all_event(struct list_head *hash) {
+       unsigned int i = 0;
+       struct event_list *evl = NULL;
+       
+       write_lock(&hash_lock);
+       for (i = 0; i < hash_size; i++) {
+               while(!list_empty(&hash[i])) {
+                       evl = list_entry(hash[i].next, struct event_list, list);
+                       if (evl) {
+                               list_del(&evl->list);
+                               kfree(evl);
+                       }
+               }
+       }
+       write_unlock(&hash_lock);
+       /* hash table is now empty */
+       return CN_NET_ACK_SUCCES;
+}
+
+/**
+ * add a entry to the hash table
+ * we are checking if we register a same event twice
+ */
+static enum ack_err add_event(struct list_head *hash, struct event ev) {
+
+       struct event_list *data = NULL;
+       unsigned int h = 0;
+       enum ack_err err = CN_NET_ACK_SUCCES;
+       
+       data = kzalloc(sizeof(struct event_list), GFP_KERNEL);
+       if (!data) {
+               err = CN_NET_ACK_ENOMEM;
+               return err;
+       }
+       data->ev.syscall_num = ev.syscall_num;
+       data->ev.protocol = ev.protocol;
+       INIT_LIST_HEAD(&(data->list));
+
+       /* check if the event is already registered */
+       if (check_event(data)) {
+               kfree(data);
+               err = CN_NET_ACK_EINCONFIG;
+               return err;
+       }
+       h = jhash(&(data->ev), sizeof(struct event), 0) % hash_size;
+
+       write_lock(&hash_lock);
+       list_add_tail(&data->list, &hash[h]);
+       write_unlock(&hash_lock);
+
+       return err;
+}
+
+/**
+ * delete a entry from the hash table
+ * we are checking if we delete a unregistered event
+ */
+static enum ack_err del_event(struct list_head *hash, struct event ev) {
+       
+       struct event_list *data;
+       unsigned int h = 0;
+       enum ack_err err = CN_NET_ACK_EINCONFIG;
+       struct list_head *l = NULL;
+       struct event_list *evl = NULL;
+
+       data = kzalloc(sizeof(struct event_list), GFP_KERNEL);
+       if (!data) {
+               err = CN_NET_ACK_ENOMEM;
+               return err;
+       }
+       data->ev.syscall_num = ev.syscall_num;
+       data->ev.protocol = ev.protocol;
+       INIT_LIST_HEAD(&(data->list));
+
+       h = jhash(&(data->ev), sizeof(struct event), 0) % hash_size;
+
+       write_lock(&hash_lock);
+       l = &hash[h];
+       list_for_each_entry(evl, l, list) {
+               if (is_same_event(evl->ev, data->ev)) {
+                       list_del(&evl->list);
+                       kfree(evl);
+                       err = CN_NET_ACK_SUCCES;
+                       break;
+               }
+       }
+       write_unlock(&hash_lock);
+       kfree(data);
+
+       return err;
+}
+
+/**
+ * do_register()
+ * check if userpace protocol version is same as kernel protocol version
+ */
+static enum ack_err do_register(__u32 version) {
+       enum ack_err err = CN_NET_ACK_SUCCES;
+
+       DEBUGP(KERN_INFO "do_register: %d %d\n",
+              version, CN_NET_VERSION);
+
+       if (version == CN_NET_VERSION)
+               atomic_inc(&net_event_num_listeners);
+       else
+               err = CN_NET_ACK_EBADPROTO;
+       return err;
+}
+
+/** 
+ * do_config()
+ * execute config asked by userspace
+ * return enum ack_err
+ */
+static enum ack_err do_config(struct msg_config *cfg) {
+       enum ack_err err = CN_NET_ACK_SUCCES;
+
+       DEBUGP(KERN_INFO "do_config: %s %s %d\n",
+              config_name[cfg->config_cmd],
+              syscall_name[cfg->ev.syscall_num],
+              cfg->ev.protocol);
+
+       switch (cfg->config_cmd) {
+       case CN_NET_CONFIG_ADD:
+               err = add_event(hash, cfg->ev);
+               break;
+       case CN_NET_CONFIG_DEL:
+               err = del_event(hash, cfg->ev);
+               break;
+       case CN_NET_CONFIG_FLUSH:
+               err = clean_all_event(hash);
+               break;
+       default:
+               err = CN_NET_ACK_EINTYPE;
+               break;
+       };
+       
+       return err;
+}
+
+/**
+ * cn_net_ack
+ * Send an acknowledgement message to userspace
+ *
+ * Use 0 for SUCCESS, EFOO otherwise. (see enum ack_err)
+ */
+static void cn_net_ack(enum ack_err err, unsigned int rcvd_seq, unsigned int 
rcvd_ack, enum msg_type msg_type)
+{
+       struct cn_msg *m;
+       struct net_event *net_ev;
+       __u8 buffer[CN_NET_MSG_SIZE];
+
+       DEBUGP(KERN_INFO "cn_net_ack: listen=%d\n", 
atomic_read(&net_event_num_listeners));
+       
+       if (atomic_read(&net_event_num_listeners) < 1 && err != 
CN_NET_ACK_EBADPROTO)
+               return;
+
+       m = (struct cn_msg *) buffer;
+       net_ev = (struct net_event *) m->data;
+
+       net_ev->msg_type = msg_type;
+       ktime_get_real_ts(&net_ev->timestamp);
+       net_ev->net_event_data.ack = err;
+       memcpy(&m->id, &cn_net_event_id, sizeof(m->id));
+       m->seq = rcvd_seq;
+       m->ack = rcvd_ack + 1;
+       m->len = sizeof(struct net_event);
+       cn_netlink_send(m, CN_IDX_NET, gfp_any());
+}
+
+/**
+ * cn_net_ctl
+ * connector callback
+ * @data: message receive from userspace via the connector
+ */
+void cn_net_ctl(void *data) {
+       struct cn_msg *m = data;
+       struct net_event *net_ev = NULL;
+       enum msg_type msg_type;
+       enum ack_err err = CN_NET_ACK_SUCCES;
+
+       if (m->len != sizeof(struct net_event)) {
+               printk(KERN_WARNING "cn_net_ctl : message with bad size, 
discard\n");
+               return;
+       }
+
+       net_ev = (struct net_event *) m->data;
+
+       if (net_ev->msg_type != CN_NET_LISTEN && 
+           atomic_read(&net_event_num_listeners) < 1) {
+               printk(KERN_WARNING "cn_net_ctl : register first\n");
+               return;
+       }
+       msg_type = CN_NET_ACK;  /* default response message type */
+
+       switch (net_ev->msg_type) {
+       case CN_NET_NONE:       /* want to play ping pong ? */
+               msg_type = net_ev->msg_type;
+               break;
+       case CN_NET_ACK:        /* userspace is ack'ing - check that */
+               /* FIXME: we don't send an ACK to an ACK */
+               /* we just check which message is ack */
+               goto out;
+               break;
+       case CN_NET_DATA:       /* CN_NET_DATA can't be used by userspace */
+               err = CN_NET_ACK_EINTYPE;
+               break;
+       case CN_NET_CONFIG:     /* configuring kernel's behaviour */
+               err = do_config(&(net_ev->net_event_data.config));
+               break;
+       case CN_NET_LISTEN:     /* userspace is registering */
+               err = do_register(net_ev->net_event_data.version);
+               break;
+       case CN_NET_IGNORE:     /* userspace is unregistering */
+               atomic_dec(&net_event_num_listeners);
+               break;
+       case CN_NET_DUMP:     /* dumping hash table -- debug purpose */
+               dump_event(hash);
+               break;
+       default:
+               err = CN_NET_ACK_EINTYPE;
+               break;
+       };
+       cn_net_ack(err, m->seq, m->ack, msg_type);
+out:
+       return;
+}
+
+/**
+ * cn_net_send_event
+ * send data to userspace
+ * @sock: sock which sock->sk->sk_state change to the state identified by 
@event
+ */
+static void cn_net_send_event(struct sock *sk, struct sockaddr *address,
+                             enum cn_net_socket syscall_num) {
+                        
+       struct net_event *net_ev;
+       struct cn_msg *m;
+       struct inet_sock *inet = inet_sk(sk);
+       struct sockaddr_in *addr4 = NULL;
+       struct sockaddr_in6 *addr6 = NULL;
+       struct task_struct *me = current;
+
+       __u8 buffer[CN_NET_MSG_SIZE];
+
+       DEBUGP(KERN_INFO "cn_net_ack: listen=%d\n", 
atomic_read(&net_event_num_listeners));
+
+       if (atomic_read(&net_event_num_listeners) < 1)
+               goto out;
+       
+       m = (struct cn_msg *) buffer;
+       net_ev = (struct net_event *) m->data;
+       
+       switch (syscall_num) {
+       case CN_NET_SOCKET_LISTEN:
+       case CN_NET_SOCKET_SHUTDOWN:
+       case CN_NET_SK_FREE_SECURITY:
+               switch (sk->sk_family) {
+               case AF_INET:
+                       net_ev->net_event_data.data.saddr.ipv4 = inet->saddr;
+                       net_ev->net_event_data.data.daddr.ipv4 = inet->daddr;
+                       break;
+               case AF_INET6:
+                       memcpy(&(net_ev->net_event_data.data.saddr.ipv6),
+                              &(inet->pinet6->saddr), sizeof(struct in6_addr));
+                       memcpy(&(net_ev->net_event_data.data.daddr.ipv6),
+                              &(inet->pinet6->daddr), sizeof(struct in6_addr));
+                       break;
+               default:
+                       /* other protocol, sending nothing */
+                       goto out;
+                       break;
+               };
+               net_ev->net_event_data.data.sport = ntohs(inet->sport);
+               net_ev->net_event_data.data.dport = ntohs(inet->dport);
+               break;
+       case CN_NET_SOCKET_BIND:
+               switch (sk->sk_family) {
+               case AF_INET:
+                       addr4 = (struct sockaddr_in *) address;
+                       net_ev->net_event_data.data.saddr.ipv4 = 
addr4->sin_addr.s_addr;
+                       net_ev->net_event_data.data.daddr.ipv4 = inet->daddr;
+                       net_ev->net_event_data.data.sport = 
ntohs(addr4->sin_port);
+                       net_ev->net_event_data.data.dport = ntohs(inet->dport);
+                       break;
+               case AF_INET6:
+                       addr6 = (struct sockaddr_in6 *) address;
+                       memcpy(&(net_ev->net_event_data.data.saddr.ipv6),
+                              &(addr6->sin6_addr), sizeof(struct in6_addr));
+                       memcpy(&(net_ev->net_event_data.data.daddr.ipv6),
+                              &(inet->pinet6->daddr), sizeof(struct in6_addr));
+                       net_ev->net_event_data.data.sport = 
ntohs(addr6->sin6_port);
+                       net_ev->net_event_data.data.dport = ntohs(inet->dport);
+                       break;
+               default:
+                       /* other protocol, sending nothing */
+                       goto out;
+                       break;
+               };
+               break;
+       case CN_NET_SOCKET_CONNECT:
+               switch (sk->sk_family) {
+               case AF_INET:
+                       addr4 = (struct sockaddr_in *) address;
+                       net_ev->net_event_data.data.saddr.ipv4 = inet->saddr;
+                       net_ev->net_event_data.data.daddr.ipv4 = 
addr4->sin_addr.s_addr;
+                       net_ev->net_event_data.data.sport = ntohs(inet->sport);
+                       net_ev->net_event_data.data.dport = 
ntohs(addr4->sin_port);
+                       break;
+               case AF_INET6:
+                       addr6 = (struct sockaddr_in6 *) address;
+                       memcpy(&(net_ev->net_event_data.data.saddr.ipv6),
+                              &(inet->pinet6->saddr), sizeof(struct in6_addr));
+                       memcpy(&(net_ev->net_event_data.data.daddr.ipv6),
+                              &(addr6->sin6_addr), sizeof(struct in6_addr));
+                       net_ev->net_event_data.data.sport = ntohs(inet->sport);
+                       net_ev->net_event_data.data.dport = 
ntohs(addr6->sin6_port);
+                       break;
+               default:
+                       /* other protocol, sending nothing */
+                       goto out;
+                       break;
+               };
+               break;
+       default:
+               /* Bad syscall_num */
+               break;
+       };
+       net_ev->msg_type = CN_NET_DATA;
+       ktime_get_real_ts(&net_ev->timestamp);
+       net_ev->net_event_data.data.uid = me->uid;
+       get_task_comm(net_ev->net_event_data.data.taskname, me);
+       net_ev->net_event_data.data.ev.protocol = sk->sk_protocol;
+       net_ev->net_event_data.data.ev.syscall_num = syscall_num;
+       net_ev->net_event_data.data.family = sk->sk_family;
+       memcpy(&m->id, &cn_net_event_id, sizeof(m->id));
+       m->seq = get_random_int();
+       m->ack = 0;
+       m->len = sizeof(struct net_event);
+       
+       cn_netlink_send(m, CN_IDX_NET, gfp_any());
+out:
+       return;
+}
+
+static int cn_net_socket_listen(struct socket *sock, int backlog) {
+
+       DEBUGP(KERN_INFO "cn_net_socket_listen\n");
+       if (check_wanted_data(sock->sk, CN_NET_SOCKET_LISTEN) > 0)
+               cn_net_send_event(sock->sk, NULL, CN_NET_SOCKET_LISTEN);
+
+       return 0;
+}
+
+static int cn_net_socket_bind(struct socket *sock,
+                             struct sockaddr *address, int addrlen) {
+
+       DEBUGP(KERN_INFO "cn_net_socket_bind\n");
+       if (check_wanted_data(sock->sk, CN_NET_SOCKET_BIND) > 0)
+               cn_net_send_event(sock->sk, address, CN_NET_SOCKET_BIND);
+
+       return 0;
+}
+
+static int cn_net_socket_connect(struct socket *sock, struct sockaddr 
*address, int addrlen) {
+       
+       DEBUGP(KERN_INFO "cn_net_socket_connect\n");
+       if (check_wanted_data(sock->sk, CN_NET_SOCKET_CONNECT) > 0)
+               cn_net_send_event(sock->sk, address, CN_NET_SOCKET_CONNECT);
+
+       return 0;
+}
+
+static int cn_net_socket_shutdown(struct socket *sock, int how) {
+
+       DEBUGP(KERN_INFO "cn_net_socket_shutdown\n");
+       if (check_wanted_data(sock->sk, CN_NET_SOCKET_SHUTDOWN) > 0)
+               cn_net_send_event(sock->sk, NULL, CN_NET_SOCKET_SHUTDOWN);
+
+       return 0;
+}
+
+static int cn_net_sk_free_security(struct sock *sk) {
+       
+       DEBUGP(KERN_INFO "cn_net_sk_free_security\n");
+       if (check_wanted_data(sk, CN_NET_SK_FREE_SECURITY) > 0)
+               cn_net_send_event(sk, NULL, CN_NET_SK_FREE_SECURITY);
+
+       return 0;
+}
+
+static struct security_operations cn_net_security_ops = {
+       .socket_listen          = cn_net_socket_listen,
+       .socket_bind            = cn_net_socket_bind,
+       .socket_connect         = cn_net_socket_connect,
+       .socket_shutdown        = cn_net_socket_shutdown,
+       .sk_free_security       = cn_net_sk_free_security,
+};
+
+static int __init init(void) {
+       int err, i;
+
+       err = cn_add_callback(&cn_net_event_id, cn_net_event_name, &cn_net_ctl);
+
+       if (err) {
+               printk(KERN_WARNING "cn_net: Failure add connector callback\n");
+               goto out;
+       }
+
+       if (register_security(&cn_net_security_ops)) {
+               printk(KERN_INFO "cn_net: Failure registering with kernel\n");
+               if (mod_reg_security(MY_NAME, &cn_net_security_ops)) {
+                       printk(KERN_WARNING
+                              "cn_net: Failure registering with primary 
security"
+                              " module\n");
+                       err = -EINVAL;
+                       goto out_security;
+               }
+               secondary = 1;
+       }
+
+
+       hash = kzalloc(sizeof(struct list_head) * hash_size, GFP_KERNEL);
+       if (!hash)
+               goto out_nomem_hash;
+       
+       for (i = 0; i < hash_size; i++)
+               INIT_LIST_HEAD(&(hash[i]));
+
+       printk(KERN_INFO "cn_net: module loaded\n");
+
+       return 0;
+
+out_nomem_hash:
+       err = -ENOMEM;
+
+       if (secondary) {
+               if (mod_unreg_security(MY_NAME, &cn_net_security_ops))
+                       printk(KERN_INFO "cn_net: Failure unregistering with"
+                              " primary security module\n");
+       } else {
+               if (unregister_security(&cn_net_security_ops))
+                       printk(KERN_INFO "cn_net: Failure unregistering with "
+                              "kernel\n");
+       }
+
+out_security:
+       cn_del_callback(&cn_net_event_id);
+out:
+       return err;
+}
+
+static void __exit fini(void) {
+       if (secondary) {
+               if (mod_unreg_security(MY_NAME, &cn_net_security_ops))
+                       printk(KERN_INFO "cn_net: Failure unregistering with"
+                              " primary security module\n");
+       } else {
+               if (unregister_security(&cn_net_security_ops))
+                       printk(KERN_INFO "cn_net: Failure unregistering with "
+                              "kernel\n");
+       }
+       
+       cn_del_callback(&cn_net_event_id);
+       
+       /* clean memory */
+       if (hash) {
+               clean_all_event(hash);
+               kfree(hash);
+       }
+
+       printk(KERN_INFO "cn_net: network events module unloaded\n");
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_DESCRIPTION("Network events module");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Samir Bellabes <[EMAIL PROTECTED]>");
diff --git a/include/linux/cn_net.h b/include/linux/cn_net.h
new file mode 100644
index 0000000..6604053
--- /dev/null
+++ b/include/linux/cn_net.h
@@ -0,0 +1,122 @@
+/* 
+ * include/linux/cn_net.h
+ *
+ * Network events connector
+ * Samir Bellabes <[EMAIL PROTECTED]>
+ *
+ *     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.
+ */ 
+
+#ifndef CN_NET_H
+#define CN_NET_H
+
+#include <linux/time.h>
+#include <linux/ipv6.h>
+
+#define CN_NET_VERSION 0x1
+
+#define CN_NET_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct net_event))
+
+char *syscall_name[] = { "LISTEN", "BIND", "CONNECT", "SHUTDOWN", "SK_FREE" };
+char *msg_type_name[] = { "CN_NET_NONE", "CN_NET_ACK", "CN_NET_DATA",
+                         "CN_NET_CONFIG", "CN_NET_LISTEN", "CN_NET_IGNORE",
+                         "CN_NET_DUMP" };
+char *config_name[] = {"CN_NET_CONFIG_ADD", "CN_NET_CONFIG_DEL", 
"CN_NET_CONFIG_FLUSH" };
+
+/**
+ * identify which syscall has been called.
+ */
+enum cn_net_socket {
+       CN_NET_SOCKET_LISTEN    = 0,
+       CN_NET_SOCKET_BIND      = 1,
+       CN_NET_SOCKET_CONNECT   = 2,
+       CN_NET_SOCKET_SHUTDOWN  = 3,
+       CN_NET_SK_FREE_SECURITY = 4,
+       CN_NET_SOCKET_MAX       = 5,
+};
+
+/**
+ * Protocol message type
+ */
+enum msg_type {
+       CN_NET_NONE     = 0,
+       CN_NET_ACK      = 1,    
+       CN_NET_DATA     = 2,
+       CN_NET_CONFIG   = 3,
+       CN_NET_LISTEN   = 4,
+       CN_NET_IGNORE   = 5,
+       CN_NET_DUMP     = 6,
+};
+
+/**
+ * values for CN_NET_ACK messages
+ */
+enum ack_err {
+       CN_NET_ACK_SUCCES       = 0,
+       CN_NET_ACK_ENOMEM       = 1,
+       CN_NET_ACK_EINCONFIG    = 2,
+       CN_NET_ACK_EINTYPE      = 3,
+       CN_NET_ACK_EBADPROTO    = 4,
+};
+
+/**
+ * values for CN_NET_CONFIG messages
+ */
+enum config_cmd {
+       CN_NET_CONFIG_ADD       = 0,
+       CN_NET_CONFIG_DEL       = 1,
+       CN_NET_CONFIG_FLUSH     = 2,
+};
+
+struct event {
+       enum cn_net_socket syscall_num;
+       __u8 protocol;
+};
+
+struct event_list {
+       struct list_head list;
+       struct event ev;
+};
+
+struct msg_config {
+       enum config_cmd config_cmd;
+       struct event ev; 
+};
+
+struct net_event {
+       enum msg_type msg_type;
+       struct timespec timestamp;
+       union {
+               /* protocol version number */
+               __u32 version;
+
+               /* generic ack for both userspace and kernel */
+               enum ack_err ack;
+
+               /* send data to userspace */
+               struct {
+                       struct event ev;
+                       uid_t uid;
+                       unsigned char taskname[TASK_COMM_LEN];
+                       unsigned int family;
+                       union {
+                               struct in6_addr ipv6;
+                               __u32 ipv4;
+                       } saddr;
+                       union {
+                               struct in6_addr ipv6;
+                               __u32 ipv4;
+                       } daddr;
+                       unsigned int sport;
+                       unsigned int dport;
+               } data;
+
+               /* send config to kernel */
+               struct msg_config config;
+       } net_event_data;
+};
+
+#endif /* CN_NET_H */
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 10eb56b..3042360 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -36,9 +36,10 @@ #define CN_IDX_CIFS                  0x2
 #define CN_VAL_CIFS                     0x1
 #define CN_W1_IDX                      0x3     /* w1 communication */
 #define CN_W1_VAL                      0x1
+#define CN_IDX_NET                     0x4
+#define CN_VAL_NET                     0x1
 
-
-#define CN_NETLINK_USERS               4
+#define CN_NETLINK_USERS               5
 
 /*
  * Maximum connector's message size.
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to