From 9a814b22aab807c0f6895fd451e092070c751512 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Tue, 31 Oct 2006 12:26:02 +0000 Subject: add ifw_listen plugin --- src/Makefile | 3 + src/mandi_daemon.c | 2 + src/plugins/ifw_listen/ifw_listen.h | 18 ++++ src/plugins/ifw_listen/ifw_listen_dbus.c | 21 +++++ src/plugins/ifw_listen/ifw_listen_dbus.h | 9 ++ src/plugins/ifw_listen/libnl_ifw.c | 62 +++++++++++++ src/plugins/ifw_listen/libnl_ifw.h | 35 +++++++ src/plugins/ifw_listen/list.h | 155 +++++++++++++++++++++++++++++++ src/plugins/ifw_listen/plugin.c | 110 ++++++++++++++++++++++ src/plugins/ifw_listen/report_list.c | 87 +++++++++++++++++ src/plugins/ifw_listen/report_list.h | 24 +++++ 11 files changed, 526 insertions(+) create mode 100644 src/plugins/ifw_listen/ifw_listen.h create mode 100644 src/plugins/ifw_listen/ifw_listen_dbus.c create mode 100644 src/plugins/ifw_listen/ifw_listen_dbus.h create mode 100644 src/plugins/ifw_listen/libnl_ifw.c create mode 100644 src/plugins/ifw_listen/libnl_ifw.h create mode 100644 src/plugins/ifw_listen/list.h create mode 100644 src/plugins/ifw_listen/plugin.c create mode 100644 src/plugins/ifw_listen/report_list.c create mode 100644 src/plugins/ifw_listen/report_list.h diff --git a/src/Makefile b/src/Makefile index ba8b1c8..322c502 100644 --- a/src/Makefile +++ b/src/Makefile @@ -11,8 +11,11 @@ DAEMON_TARGET = mandi DAEMON_OBJS += $(addprefix plugins/wireless/,plugin.o wpa_ctrl.o) #CFLAGS += -DIFW_FAKE +#CFLAGS += -DIFW_LISTEN_FAKE DAEMON_OBJS += $(addprefix plugins/ifw/,plugin.o ifw_dbus.o ipset.o white_list.o black_list.o report_list.o libnl_ifw.o) +DAEMON_OBJS += $(addprefix plugins/ifw_listen/,plugin.o ifw_listen_dbus.o) + all: $(DAEMON_TARGET) .c.o: diff --git a/src/mandi_daemon.c b/src/mandi_daemon.c index 222025e..4b82c2f 100644 --- a/src/mandi_daemon.c +++ b/src/mandi_daemon.c @@ -25,9 +25,11 @@ typedef struct { extern plugin_t wpa_supplicant_plugin; extern plugin_t ifw_plugin; +extern plugin_t ifw_listen_plugin; plugin_t *plugins[] = { &wpa_supplicant_plugin, &ifw_plugin, + &ifw_listen_plugin, NULL, }; diff --git a/src/plugins/ifw_listen/ifw_listen.h b/src/plugins/ifw_listen/ifw_listen.h new file mode 100644 index 0000000..89c75fb --- /dev/null +++ b/src/plugins/ifw_listen/ifw_listen.h @@ -0,0 +1,18 @@ +#ifndef IFW_LISTEN_H +#define IFW_LISTEN_H + +#include +#include "plugin.h" + +#define IFW_LISTEN_DBUS_PATH PLUGIN_ROOT_PATH "/ifw2" +#define IFW_LISTEN_DBUS_INTERFACE PLUGIN_ROOT_INTF ".ifw2" + +typedef struct { + char program[32]; + u_int16_t port; +} msg_listen_t; + +typedef struct { +} ifw_listen_t; + +#endif /* IFW_LISTEN_H */ diff --git a/src/plugins/ifw_listen/ifw_listen_dbus.c b/src/plugins/ifw_listen/ifw_listen_dbus.c new file mode 100644 index 0000000..d98d6f7 --- /dev/null +++ b/src/plugins/ifw_listen/ifw_listen_dbus.c @@ -0,0 +1,21 @@ +#include + +#include "ifw_listen_dbus.h" + +void ifw_listen_dbus_notify_listen(DBusConnection *bus, msg_listen_t *listen) { + DBusMessage *message; + + message = dbus_message_new_signal(IFW_LISTEN_DBUS_PATH, + IFW_LISTEN_DBUS_INTERFACE, + "Listen"); + char *program = listen->program; + dbus_message_append_args(message, + DBUS_TYPE_STRING, + &program, + DBUS_TYPE_UINT32, + &listen->port, + DBUS_TYPE_INVALID); + dbus_connection_send(bus, message, NULL); + dbus_connection_flush(bus); + dbus_message_unref(message); +} diff --git a/src/plugins/ifw_listen/ifw_listen_dbus.h b/src/plugins/ifw_listen/ifw_listen_dbus.h new file mode 100644 index 0000000..a5f817d --- /dev/null +++ b/src/plugins/ifw_listen/ifw_listen_dbus.h @@ -0,0 +1,9 @@ +#ifndef IFW_LISTEN_DBUS_H +#define IFW_LISTEN_DBUS_H + +#include +#include "ifw_listen.h" + +void ifw_listen_dbus_notify_listen(DBusConnection *bus, msg_listen_t *listen); + +#endif /* IFW_LISTEN_DBUS_H */ diff --git a/src/plugins/ifw_listen/libnl_ifw.c b/src/plugins/ifw_listen/libnl_ifw.c new file mode 100644 index 0000000..bb41363 --- /dev/null +++ b/src/plugins/ifw_listen/libnl_ifw.c @@ -0,0 +1,62 @@ +/* nl_create_socket(), nl_bind_socket() and nl_read_msg() + * for Interactive Firewall + * sbellabes@mandriva.com + */ + + +#include +#include +#include +#include +#include +#include + +#include "libnl_ifw.h" + +int nl_ifw_bind_socket(int s) { + struct sockaddr_nl saddr_nl; + int res; + + memset(&saddr_nl, 0, sizeof(struct sockaddr_nl)); + saddr_nl.nl_family = AF_NETLINK; + saddr_nl.nl_pid = getpid(); + saddr_nl.nl_groups = 10; + + res = bind(s, (struct sockaddr *)&saddr_nl, sizeof(saddr_nl)); + if (res == -1) { + perror("nl_bind_socket"); + return -1; + } + return 1; +} + +int nl_ifw_create_socket(void) { + int s; + + s = socket(PF_NETLINK, SOCK_RAW, NETLINK_IFWLOG); + if (s < 0) { + perror("nl_create_socket"); + return -1; + } + + if (nl_ifw_bind_socket(s) < 0) { + close(s); + fprintf(stderr, "bind failed\n"); + return -1; + } + + return s; +} + +int nl_ifw_read_msg(int s, struct nlmsghdr *nlh, struct nl_msg *msg) { + char buf[sizeof(struct nlmsghdr) + sizeof(struct nl_msg)]; + int ret; + + ret = recv(s, &buf, sizeof(buf), 0); + if (ret > 0) { + if (nlh) memcpy(nlh, buf, sizeof(struct nlmsghdr)); + if (msg) memcpy(msg, NLMSG_DATA(buf), sizeof(struct nl_msg)); + } + + return ret; +} diff --git a/src/plugins/ifw_listen/libnl_ifw.h b/src/plugins/ifw_listen/libnl_ifw.h new file mode 100644 index 0000000..896d05c --- /dev/null +++ b/src/plugins/ifw_listen/libnl_ifw.h @@ -0,0 +1,35 @@ +/* + * libnl_ifw.h + */ + +#ifndef _LIBNL_IFW_H +#define _LIBNL_IFW_H + +#include +#include +#include +#include +#include +#include + +#define NETLINK_IFWLOG 19 + +#define PREFSIZ 32 + +struct nl_msg { /* Netlink kernel to user message */ + long timestamp_sec; /* time packet */ + char indev_name[IFNAMSIZ]; /* name of the ingoing interface */ + char outdev_name[IFNAMSIZ]; /* name of the outgoing interface */ + unsigned char prefix[PREFSIZ]; /* logging informations */ + struct iphdr ip; + union { + struct tcphdr th; + struct udphdr uh; + } h; +}; + +int nl_ifw_bind_socket(int s); +int nl_ifw_create_socket(void); +int nl_ifw_read_msg(int s, struct nlmsghdr *nlh, struct nl_msg *msg); + +#endif /* !_LIBNL_IFW_H */ diff --git a/src/plugins/ifw_listen/list.h b/src/plugins/ifw_listen/list.h new file mode 100644 index 0000000..1b55f95 --- /dev/null +++ b/src/plugins/ifw_listen/list.h @@ -0,0 +1,155 @@ +#ifndef LIST_H +#define LIST_H + +/* borrowed from kernel header linux/list.h */ + +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + + +/* borrowed from kernel header linux/kernel.h */ + +/** + * container_of - cast a member of a structure out to the containing structure + * + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - linux_offsetof(type,member) );}) + + +/* borrowed from linux/stdddef.h */ + +#define linux_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif /* LIST_H */ diff --git a/src/plugins/ifw_listen/plugin.c b/src/plugins/ifw_listen/plugin.c new file mode 100644 index 0000000..9dded4a --- /dev/null +++ b/src/plugins/ifw_listen/plugin.c @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifw_listen_dbus.h" + +static int init(plugin_t *plugin, DBusConnection *connection); +static void deinit(plugin_t *plugin, DBusConnection *connection); +static void process_listen_message(plugin_t *plugin, DBusConnection *connection, int seq, msg_listen_t *listen); +static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin); +#ifdef IFW_LISTEN_FAKE +static void generate_fake_listen(msg_listen_t *listen); +static void handle_fake(plugin_t *plugin, DBusConnection *connection); +#else +static void handle_incoming(plugin_t *plugin, DBusConnection *connection); +#endif + +static int init(plugin_t *plugin, DBusConnection *connection) { + ifw_listen_t *ifw_listen; + + ifw_listen = malloc(sizeof(ifw_listen_t)); + if (!ifw_listen) { + fprintf(stderr, "unable to malloc ifw\n"); + return -1; + } + +#ifdef IFW_LISTEN_FAKE + plugin->fd = 0; +#else + plugin->fd = nl_ifw_create_socket(); + if (plugin->fd < 0) { + fprintf(stderr, "unable to init netlink\n"); + return -1; + } +#endif + plugin->priv = (void *) ifw_listen; + + return 0; +} + +static void deinit(plugin_t *plugin, DBusConnection *connection) { + ifw_listen_t *ifw_listen = (ifw_listen_t *) plugin->priv; + close(plugin->fd); +} + +#ifdef IFW_LISTEN_FAKE +#include + +static void generate_fake_listen(msg_listen_t *listen) { + static int port = 22; + strcpy(listen->program, "sshd"); + listen->port = port++; +} + +static void handle_fake(plugin_t *plugin, DBusConnection *connection) { + static int seq = 0; + msg_listen_t fake_listen; + + read(0, NULL, 1); + + generate_fake_listen(&fake_listen); + printf("seq : %d\n", seq); + + process_listen_message(plugin, connection, seq++, &fake_listen); +} + +#else + +static void handle_incoming(plugin_t *plugin, DBusConnection *connection) { + struct nl_msg msg; + static int seq = 0; + msg_listen_t listen; + + if (nl_ifw_read_msg(plugin->fd, NULL, &msg) <= 0) { + fprintf(stderr, "unable to read packet from netlink\n"); + return; + } + + process_listen_message(plugin, connection, seq++, &listen); +} + +#endif + +static void process_listen_message(plugin_t *plugin, DBusConnection *connection, int seq, msg_listen_t *listen) { + ifw_listen_t *ifw_listen = (ifw_listen_t *) plugin->priv; + ifw_listen_dbus_notify_listen(connection, listen); +} + +static DBusHandlerResult handle_message(DBusConnection *connection, DBusMessage *message, plugin_t *plugin) { + ifw_listen_t *ifw_listen = (ifw_listen_t *) plugin->priv; + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +plugin_t ifw_listen_plugin = { + .name = "Interactive Firewall", + .path = IFW_LISTEN_DBUS_PATH, + .init = init, +#ifdef IFW_LISTEN_FAKE + .handle_incoming = handle_fake, +#else + .handle_incoming = handle_incoming, +#endif + .handle_message = handle_message, + .deinit = deinit, +}; diff --git a/src/plugins/ifw_listen/report_list.c b/src/plugins/ifw_listen/report_list.c new file mode 100644 index 0000000..ed2f3c2 --- /dev/null +++ b/src/plugins/ifw_listen/report_list.c @@ -0,0 +1,87 @@ +#include "report_list.h" + +#include +#include + +#include +#include +#include + +void report_list_init(report_list_t *list) { + INIT_LIST_HEAD(list); +} + +report_list_cell_t *report_list_add(report_list_t *list, int seq, msg_usr_t *attack) { + report_list_cell_t *cell; + + cell = malloc(sizeof(report_list_cell_t)); + if (!cell) { + fprintf(stderr, "unable to alloc enough memory for report list cell, skipping\n"); + return NULL; + } + cell->seq = seq; + cell->info = *attack; + cell->processed = 0; + INIT_LIST_HEAD(&cell->list); + list_add_tail(&cell->list, list); + + return cell; +} + +report_list_cell_t *report_list_find(report_list_t *list, u_int32_t addr, int include_processed) { + struct list_head *entry; + + __list_for_each(entry, list) { + report_list_cell_t *cell; + cell = list_entry(entry, report_list_cell_t, list); + if (cell->info.s_addr == addr && (include_processed || !cell->processed)) { + return cell; + } + } + + return NULL; +} + +report_list_cell_t *report_list_find_seq(report_list_t *list, int seq) { + struct list_head *entry; + + __list_for_each(entry, list) { + report_list_cell_t *cell; + cell = list_entry(entry, report_list_cell_t, list); + if (cell->seq == seq) { + return cell; + } + } + + return NULL; +} + +void report_list_remove(report_list_cell_t *cell) { + list_del(&cell->list); + free(cell); +} + +void report_list_clear_processed(report_list_t *list) { + report_list_cell_t *cell, *n; + + list_for_each_entry_safe(cell, n, list, list) { + if (cell->processed) { + report_list_remove(cell); + } + } +} + +void report_list_print(report_list_t *list) { + struct list_head *entry; + + printf("* report list {\n"); + __list_for_each(entry, list) { + report_list_cell_t *cell; + struct in_addr addr; + cell = list_entry(entry, report_list_cell_t, list); + addr.s_addr = cell->info.s_addr; + printf("%s (%d),\n", inet_ntoa(addr), cell->seq); + } + printf("} report list *\n"); +} + diff --git a/src/plugins/ifw_listen/report_list.h b/src/plugins/ifw_listen/report_list.h new file mode 100644 index 0000000..626afed --- /dev/null +++ b/src/plugins/ifw_listen/report_list.h @@ -0,0 +1,24 @@ +#ifndef REPORT_LIST_H +#define REPORT_LIST_H + +#include "list.h" +typedef struct list_head report_list_t; + +#include "ifw.h" + +typedef struct { + struct list_head list; + int seq; + msg_usr_t info; + char processed; +} report_list_cell_t; + +void report_list_init(report_list_t *list); +report_list_cell_t *report_list_add(report_list_t *list, int seq, msg_usr_t *attack); +report_list_cell_t *report_list_find(report_list_t *list, u_int32_t addr, int include_processed); +report_list_cell_t *report_list_find_seq(report_list_t *list, int seq); +void report_list_remove(report_list_cell_t *cell); +void report_list_clear_processed(report_list_t *list); +void report_list_print(report_list_t *list); + +#endif /* REPORT_LIST_H */ -- cgit v1.2.1