summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-rw-r--r--daemon/Makefile.am34
-rw-r--r--daemon/client.c292
-rw-r--r--daemon/client.h13
-rw-r--r--daemon/common.h23
-rw-r--r--daemon/icmp.c87
-rw-r--r--daemon/icmp.h11
-rw-r--r--daemon/ipqapi.c118
-rw-r--r--daemon/ipqapi.h13
-rw-r--r--daemon/main.c198
-rw-r--r--daemon/main.h14
-rw-r--r--daemon/packet.c101
-rw-r--r--daemon/packet.h15
12 files changed, 919 insertions, 0 deletions
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
new file mode 100644
index 0000000..66f66b2
--- /dev/null
+++ b/daemon/Makefile.am
@@ -0,0 +1,34 @@
+EXTRA_DIST = libdaemon
+
+CFLAGS+=-g -Wall -pipe
+
+INCLUDES = \
+ -I/usr/include/libipq \
+ -Ilibdaemon/src \
+ @PACKAGE_CFLAGS@
+
+sbin_PROGRAMS = fieryfilterd
+
+fieryfilterd_SOURCES = \
+ icmp.h icmp.c \
+ main.h main.c \
+ ipqapi.c ipqapi.h \
+ client.h client.c \
+ packet.h packet.c \
+ common.h
+
+fieryfilterd_LDADD = @PACKAGE_LIBS@ /usr/lib/libipq.a libdaemon/src/libdaemon.a
+
+dist-hook:
+ test -f libdaemon/Makefile && $(MAKE) -C libdaemon/ distclean || true
+
+copy:
+ rm -rf libdaemon/
+ tar xzf ../../libdaemon/libdaemon-0.1.tar.gz && mv libdaemon-0.1 libdaemon
+
+libdaemon/src/libdaemon.a:
+ $(MAKE) -C libdaemon/
+
+.PHONY: copy
+
+
diff --git a/daemon/client.c b/daemon/client.c
new file mode 100644
index 0000000..d4e6c3b
--- /dev/null
+++ b/daemon/client.c
@@ -0,0 +1,292 @@
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <daemon-log.h>
+
+#include "client.h"
+#include "main.h"
+#include "packet.h"
+#include "ipqapi.h"
+
+#define MAX_QUEUE_LENGTH 10
+#define BUFSIZE (10*1024)
+
+static int unix_socket = -1, client_socket = -1;
+
+static GSList *send_queue = NULL;
+static guint send_queue_length = 0;
+static guint send_index = 0;
+
+static guint8 recv_buf[BUFSIZE];
+static guint recv_index = 0;
+
+int client_init() {
+ struct sockaddr_un addr;
+ mode_t save;
+
+ save = umask(0007);
+
+ if ((unix_socket = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ umask(save);
+ daemon_log(LOG_ERR, "socket(PF_LOCAL, SOCK_STREAM, 0): %s", strerror(errno));
+ return -1;
+ }
+
+ addr.sun_family = AF_LOCAL;
+ strncpy(addr.sun_path, SOCKET_PATH, sizeof(addr.sun_path));
+ addr.sun_path[sizeof(addr.sun_path)-1] = 0;
+
+ if (bind(unix_socket, (struct sockaddr *) &addr, SUN_LEN(&addr)) < 0) {
+ close(unix_socket);
+ umask(save);
+ daemon_log(LOG_ERR, "bind(): %s", strerror(errno));
+ return (unix_socket = -1);
+ }
+
+ umask(save);
+
+ if (listen(unix_socket, 1) < 0) {
+ close(unix_socket);
+ daemon_log(LOG_ERR, "listen(): %s", strerror(errno));
+ return (unix_socket = -1);
+ }
+
+ FD_SET(unix_socket, &listen_rfds);
+
+ return 0;
+}
+
+void client_disconnect() {
+ if (client_socket < 0)
+ return;
+
+ FD_CLR(client_socket, &listen_rfds);
+ close(client_socket);
+ client_socket = -1;
+
+ while (send_queue) {
+ message_t *m = (message_t*) send_queue->data;
+ send_queue = g_slist_remove(send_queue, m);
+ g_free(m);
+ }
+
+ send_queue_length = 0;
+ send_index = 0;
+
+ recv_index = 0;
+
+ daemon_log(LOG_INFO, "Client disconnected");
+}
+
+
+void client_done() {
+ if (client_socket >= 0)
+ client_disconnect();
+
+ if (unix_socket >= 0) {
+ FD_CLR(unix_socket, &listen_rfds);
+ close(unix_socket);
+ unlink(SOCKET_PATH);
+ }
+
+ unix_socket = -1;
+}
+
+
+int client_work_send() {
+ g_assert(client_socket >= 0);
+
+ if (send_queue) {
+ size_t l;
+ ssize_t r;
+ message_t *m = (message_t*) send_queue->data;
+
+ g_assert(m);
+ l = m->length + sizeof(message_t);
+
+ if ((r = write(client_socket, ((guint8*) m) + send_index, l-send_index)) <= 0) {
+ daemon_log(LOG_ERR, "Write error on client socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ send_index += r;
+
+ if (send_index >= l) {
+ send_queue = g_slist_remove(send_queue, m);
+ send_queue_length--;
+ send_index = 0;
+
+ g_free(m);
+ }
+ }
+
+ if (!send_queue)
+ FD_CLR(client_socket, &listen_wfds);
+ else
+ FD_SET(client_socket, &listen_wfds);
+
+ return 0;
+}
+
+int client_dispatch(message_t*m) {
+ switch (m->code) {
+
+ case MSG_SET_DEFAULT_VERDICT:
+
+ if (m->length != sizeof(guint32)) {
+ daemon_log(LOG_WARNING, "Client sent MSG_SET_DEFAULT_VERDICT message with bogus size.");
+ return -1;
+ }
+
+ default_verdict = *((guint*) (m+1));
+ return 0;
+
+ case MSG_VERDICT: {
+ ipq_packet_msg_t *ipqm;
+ unsigned long packet_id;
+ guint32 verdict;
+
+ if (m->length != sizeof(unsigned long)+sizeof(guint32)) {
+ daemon_log(LOG_WARNING, "Client sent MSG_VERDICT message with bogus size.");
+ return -1;
+ }
+
+ packet_id = *((unsigned long*) (m+1));
+ verdict = *((guint32*) (((guint8*) (m+1)) + sizeof(unsigned long)));
+
+ if (log_packets)
+ daemon_log(LOG_DEBUG, "[%lu] Recieved client verdict %u", packet_id, verdict);
+
+ if ((ipqm = packet_find(packet_id))) {
+ if (ipqapi_verdict(ipqm, verdict) < 0) {
+ daemon_log(LOG_ERR, "Could not verdict.");
+ fail = TRUE;
+ }
+
+ packet_release(packet_id);
+
+ } else
+ daemon_log(LOG_WARNING, "Recieved verdict for unknown packet id, ignoring");
+
+ return 0;
+ }
+
+ default:
+ daemon_log(LOG_WARNING, "Recieved bogus message from client.");
+ return -1;
+ }
+}
+
+int client_work_recv() {
+ ssize_t r;
+ size_t l;
+
+
+ if (recv_index >= sizeof(message_t)) {
+ l = ((message_t*) recv_buf)->length + sizeof(message_t);
+
+ if (l > BUFSIZE) {
+ daemon_log(LOG_WARNING, "Client message too large");
+ return -1;
+ }
+ } else
+ l = sizeof(message_t);
+
+ if ((r = read(client_socket, recv_buf + recv_index, l - recv_index)) <= 0) {
+ if (r < 0)
+ daemon_log(LOG_WARNING, "Read error on client socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ recv_index += r;
+
+ if (recv_index >= sizeof(message_t)) {
+ if (recv_index >= ((message_t*) recv_buf)->length + sizeof(message_t)) {
+ recv_index = 0;
+
+ if (client_dispatch((message_t*) recv_buf))
+ client_disconnect();
+ }
+ }
+ return 0;
+}
+
+
+int client_work_accept() {
+ int fd;
+
+ if ((fd = accept(unix_socket, NULL, NULL)) < 0)
+ return -1;
+
+ if (client_socket >= 0) {
+ daemon_log(LOG_WARNING, "Client connecting while already in use, closing");
+ close(fd);
+ return 0;
+ }
+
+ client_socket = fd;
+ FD_SET(client_socket, &listen_rfds);
+
+ daemon_log(LOG_INFO, "Client connected");
+
+ return 0;
+}
+
+int client_work() {
+ int r = 0;
+
+ if (FD_ISSET(unix_socket, &select_rfds))
+ if ((r = client_work_accept()) < 0)
+ return r;
+
+ if (client_socket >= 0 && FD_ISSET(client_socket, &select_rfds))
+ if (client_work_recv() < 0)
+ client_disconnect();
+
+ if (client_socket >= 0 && FD_ISSET(client_socket, &select_wfds))
+ if (client_work_send() < 0)
+ client_disconnect();
+
+ return 0;
+}
+
+int client_send_enqueue(message_t *m) {
+ g_assert(client_socket >= 0);
+
+ if (send_queue_length+1 > MAX_QUEUE_LENGTH)
+ return -1;
+
+ send_queue = g_slist_append(send_queue, m);
+ FD_SET(client_socket, &listen_wfds);
+
+ send_queue_length++;
+ return 0;
+}
+
+int client_is_connected() {
+ return client_socket >= 0;
+}
+
+message_t* message_new(message_code_t c, guint8* d, guint s) {
+ guchar *p;
+ message_t *m;
+
+ if (!d)
+ s = 0;
+
+ m = (message_t*) (p = g_new(guint8, sizeof(message_t) + s));
+
+ if (d)
+ memcpy(p + sizeof(message_t), d, s);
+
+ m->code = c;
+ m->pid = getpid();
+ m->length = s;
+
+ return m;
+}
+
+
diff --git a/daemon/client.h b/daemon/client.h
new file mode 100644
index 0000000..9e54fb9
--- /dev/null
+++ b/daemon/client.h
@@ -0,0 +1,13 @@
+#ifndef fooclienthfoo
+#define fooclienthfoo
+
+#include "common.h"
+
+int client_init();
+void client_done();
+int client_work();
+int client_is_connected();
+int client_send_enqueue(message_t *m);
+message_t* message_new(message_code_t c, guint8* d, guint s);
+
+#endif
diff --git a/daemon/common.h b/daemon/common.h
new file mode 100644
index 0000000..4a8e6b1
--- /dev/null
+++ b/daemon/common.h
@@ -0,0 +1,23 @@
+#ifndef foocommonhfoo
+#define foocommonhfoo
+
+#include <sys/types.h>
+#include <glib.h>
+#include <libipq/libipq.h>
+
+#define SOCKET_PATH "/tmp/fieryfilter"
+
+typedef enum message_code {
+ MSG_PACKET = 0,
+ MSG_VERDICT = 1,
+ MSG_SET_DEFAULT_VERDICT = 2
+} message_code_t;
+
+typedef struct message {
+ message_code_t code;
+ pid_t pid;
+ guint32 length;
+} message_t;
+
+
+#endif
diff --git a/daemon/icmp.c b/daemon/icmp.c
new file mode 100644
index 0000000..7252b7c
--- /dev/null
+++ b/daemon/icmp.c
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <linux/ip.h>
+#include <linux/icmp.h>
+#include <linux/tcp.h>
+
+#include "icmp.h"
+
+#define BUFSIZE (10*1024)
+
+static int icmp_socket = -1;
+
+guint16 ipsum(guint8 *p, guint l) {
+ guint32 sum = 0;
+ guint i;
+
+ for (i = 0; i < l-1; i += 2)
+ sum += (p[i] << 8) + p[i+1];
+
+ if (i < l)
+ sum += p[i] << 8;
+
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ sum = (sum & 0xFFFF) + (sum >> 16);
+
+ return ~sum;
+}
+
+
+int reply_icmp_error(ipq_packet_msg_t *m, int code) {
+ static guint8 buf[BUFSIZE];
+ struct iphdr* ip = (struct iphdr*) m->payload;
+ struct icmphdr *icmp = (struct icmphdr*) buf;
+ guint l, tl;
+ struct sockaddr_in sa;
+
+ icmp->type = 3;
+ icmp->code = code;
+ icmp->checksum = 0;
+ icmp->un.frag.__unused = 0;
+ icmp->un.frag.mtu = 0;
+
+ l = ip->ihl*4 + 8;
+ memcpy(&buf[sizeof(struct icmphdr)], m->payload, l);
+
+ tl = l + sizeof(struct icmphdr);
+ icmp->checksum = htons(ipsum((guint8*) icmp, tl));
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = 0;
+ sa.sin_addr.s_addr = ip->saddr;
+
+
+ if (sendto(icmp_socket, icmp, tl, 0, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
+ perror("sendto()");
+ return -1;
+ }
+
+ return 0;
+}
+
+int icmp_init() {
+ int enable = 1;
+
+ if ((icmp_socket = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
+ perror("socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)");
+ return -1;
+
+ }
+
+ if (setsockopt(icmp_socket, SOL_SOCKET, SO_BROADCAST, (char *)&enable, sizeof(enable)) < 0) {
+ perror("setsockopt(.., SOL_SOCKET, SO_BROADCAST)");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void icmp_done() {
+ if (icmp_socket >= 0)
+ close(icmp_socket);
+
+ icmp_socket = -1;
+}
diff --git a/daemon/icmp.h b/daemon/icmp.h
new file mode 100644
index 0000000..b2b62a9
--- /dev/null
+++ b/daemon/icmp.h
@@ -0,0 +1,11 @@
+#ifndef fooipsumhfoo
+#define fooipsumhfoo
+
+#include <glib.h>
+#include <libipq/libipq.h>
+
+int reply_icmp_error(ipq_packet_msg_t *m, int code);
+int icmp_init();
+void icmp_done();
+
+#endif
diff --git a/daemon/ipqapi.c b/daemon/ipqapi.c
new file mode 100644
index 0000000..b0649bc
--- /dev/null
+++ b/daemon/ipqapi.c
@@ -0,0 +1,118 @@
+#include <string.h>
+#include <time.h>
+
+#include <daemon-log.h>
+
+#include "icmp.h"
+#include "ipqapi.h"
+#include "main.h"
+#include "client.h"
+#include "packet.h"
+
+#define BUFSIZE (10*1024)
+
+static struct ipq_handle *ipq = NULL;
+
+int ipqapi_init() {
+ int status;
+
+ if (!(ipq = ipq_create_handle(0, PF_INET))) {
+ daemon_log(LOG_ERR, "ipq_create_handle(): %s", ipq_errstr());
+ return -1;
+ }
+
+ if ((status = ipq_set_mode(ipq, IPQ_COPY_PACKET, BUFSIZE)) < 0) {
+ daemon_log(LOG_ERR, "ipq_set_mode(): %s", ipq_errstr());
+ daemon_log(LOG_INFO, "Perhaps you should run 'modprobe ip_queue'?");
+ ipq_destroy_handle(ipq);
+ ipq = NULL;
+ return -1;
+ }
+
+ FD_SET(ipq->fd, &listen_rfds);
+
+ return 0;
+}
+
+void ipqapi_done() {
+ if (ipq) {
+ FD_CLR(ipq->fd, &listen_rfds);
+ ipq_destroy_handle(ipq);
+ }
+
+ ipq = NULL;
+}
+
+int ipqapi_work() {
+ int status;
+ static guint8 buf[BUFSIZE];
+
+ if (!FD_ISSET(ipq->fd, &select_rfds))
+ return 0;
+
+ if ((status = ipq_read(ipq, buf, BUFSIZE, 0)) < 0) {
+ daemon_log(LOG_ERR, "ipq_read(): %s", ipq_errstr());
+ return -1;
+ }
+
+ switch (ipq_message_type(buf)) {
+ case NLMSG_ERROR:
+ daemon_log(LOG_ERR, "Received error message: %s\n", strerror(ipq_get_msgerr(buf)));
+ return -1;
+
+ case IPQM_PACKET: {
+ ipq_packet_msg_t *m = ipq_get_packet(buf);
+
+ if (!m->timestamp_sec)
+ time(&m->timestamp_sec);
+
+ if (log_packets)
+ daemon_log(LOG_DEBUG, "[%lu] Recieved packet, forwarding to client", m->packet_id);
+
+ if (client_is_connected()) {
+ packet_new(m);
+ client_send_enqueue(message_new(MSG_PACKET, (guint8*) m, sizeof(ipq_packet_msg_t)+m->data_len));
+ } else {
+ if (log_packets)
+ daemon_log(LOG_DEBUG, "[%lu] No clients listening, verdicting", m->packet_id);
+
+ if (ipqapi_verdict(m, default_verdict) < 0) {
+ daemon_log(LOG_ERR, "Sending verdict failed.");
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+
+ default:
+ daemon_log(LOG_WARNING, "Recieved invalid IPQ message.");
+ return -1;
+ }
+}
+
+int ipqapi_verdict(ipq_packet_msg_t *m, guint32 resp) {
+ int nf = NF_DROP, icmp = 0;
+
+ if (resp > 17) resp = 17;
+
+ if (resp == 0)
+ nf = NF_DROP;
+ else if (resp == 1)
+ nf = NF_ACCEPT;
+ else {
+ nf = NF_DROP;
+ icmp = 1;
+ }
+
+ if (ipq_set_verdict(ipq, m->packet_id, nf, 0, NULL) < 0) {
+ daemon_log(LOG_ERR, "ipq_set_verdict(): %s", ipq_errstr());
+ return -1;
+ }
+
+
+ if (icmp)
+ return reply_icmp_error(m, resp-2);
+
+ return 0;
+}
diff --git a/daemon/ipqapi.h b/daemon/ipqapi.h
new file mode 100644
index 0000000..bac4d48
--- /dev/null
+++ b/daemon/ipqapi.h
@@ -0,0 +1,13 @@
+#ifndef fooipqapihfoo
+#define fooipqapihfoo
+
+#include <linux/netfilter.h>
+#include <libipq/libipq.h>
+#include <glib.h>
+
+int ipqapi_verdict(ipq_packet_msg_t *m, guint32 resp);
+int ipqapi_work();
+void ipqapi_done();
+int ipqapi_init();
+
+#endif
diff --git a/daemon/main.c b/daemon/main.c
new file mode 100644
index 0000000..253bf35
--- /dev/null
+++ b/daemon/main.c
@@ -0,0 +1,198 @@
+#define _GNU_SOURCE
+
+#include <signal.h>
+#include <grp.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <daemon-log.h>
+#include <daemon-signal.h>
+#include <daemon-fork.h>
+#include <daemon-pid.h>
+
+#include <config.h>
+
+#include "common.h"
+#include "main.h"
+#include "ipqapi.h"
+#include "client.h"
+#include "icmp.h"
+#include "packet.h"
+
+gboolean opt_fork = TRUE;
+gboolean opt_syslog = TRUE;
+
+fd_set listen_wfds, listen_rfds, select_wfds, select_rfds;
+
+gboolean fail = FALSE;
+
+guint32 default_verdict = 15; // ICMP packet filtered
+//guint32 default_verdict = 1; // Accept
+
+gboolean log_packets = FALSE;
+
+static gboolean _verdict_func(ipq_packet_msg_t*m) {
+ if (log_packets)
+ daemon_log(LOG_DEBUG, "[%lu] Still unanswered, verdicting", m->packet_id);
+ ipqapi_verdict(m, default_verdict);
+ return FALSE;
+}
+
+int init() {
+ if (daemon_signal_init(SIGPIPE, SIGUSR1, SIGUSR2, SIGHUP, SIGINT, SIGQUIT, SIGTERM, -1) < 0)
+ return -1;
+
+ FD_ZERO(&listen_wfds);
+ FD_ZERO(&listen_rfds);
+
+ if (ipqapi_init() < 0)
+ return -1;
+
+ if (client_init() < 0 )
+ return -1;
+
+ if (icmp_init() < 0)
+ return -1;
+
+ return 0;
+}
+
+void done() {
+ ipqapi_done();
+ client_done();
+ icmp_done();
+ packets_free();
+ daemon_signal_done();
+}
+
+int loop() {
+ int r;
+
+ daemon_log(LOG_INFO, "%s "VERSION" sucessfully initialized.", daemon_log_ident);
+
+ while (!fail) {
+ int sig;
+
+ select_rfds = listen_rfds;
+ select_wfds = listen_wfds;
+
+ if (select(FD_SETSIZE, &select_rfds, &select_wfds, NULL, NULL) < 0 && errno != EINTR) {
+ daemon_log(LOG_ERR, "select: %s", strerror(errno));
+ goto finish;
+ }
+
+ if ((sig = daemon_signal_next()) >= 0) {
+
+ switch (sig) {
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ daemon_log(LOG_INFO, "Recieved signal <%s>, exiting cleanly", strsignal(sig));
+ r = 0;
+ goto finish;
+
+ case SIGHUP:
+ daemon_log(LOG_INFO, "Recieved signal <%s>, reporting status info:", strsignal(sig));
+ daemon_log(LOG_INFO, "%u packets total, %u packets in queue", get_total_packets(), get_queued_packets());
+ break;
+
+ case SIGUSR1:
+ case SIGUSR2:
+ log_packets = sig == SIGUSR1;
+ daemon_log(LOG_INFO, "Recieved signal <%s>, %s packet logging", strsignal(sig), log_packets ? "enabling" : "disabling");
+ break;
+
+ case SIGPIPE:
+ break;
+
+ default:
+ daemon_log(LOG_WARNING, "Recieved signal <%s>, ignoring.", strsignal(sig));
+ }
+
+ } else {
+ if (client_work() < 0)
+ goto finish;
+
+ if (ipqapi_work() < 0)
+ goto finish;
+ }
+
+ packet_foreach(client_is_connected(), _verdict_func);
+ }
+
+ r = 0;
+
+finish:
+
+ daemon_log(LOG_INFO, "%s exiting.", daemon_log_ident);
+
+ return r;
+}
+
+
+int start() {
+ struct group *gr;
+ setuid(geteuid());
+
+ if (!(gr = getgrnam("fieryfilter"))) {
+ daemon_log(LOG_ERR, "Could not find group fieryfilter");
+ return 1;
+ }
+
+ if (setgid(gr->gr_gid) != 0) {
+ daemon_log(LOG_ERR, "setgid(): %s", strerror(errno));
+ return 1;
+ }
+
+ if (opt_fork) {
+ pid_t pid;
+
+ daemon_retval_init();
+
+ if ((pid = daemon_fork()) < 0)
+ return 1;
+ else if (pid != 0) {
+ int r = daemon_retval_wait(10);
+ return r < 0 ? 1 : r;
+ } else {
+ daemon_log_use_syslog = opt_syslog;
+
+ if (init() < 0) {
+ daemon_retval_send(1);
+ done();
+ return 1;
+ }
+
+ daemon_retval_send(0);
+ }
+ } else {
+ daemon_log_use_syslog = opt_syslog;
+
+ if (init() < 0) {
+ done();
+ return 1;
+ }
+ }
+
+
+ if (loop() < 0) {
+ done();
+ return 1;
+ }
+
+ done();
+ return 0;
+
+}
+
+int main(int argc, char *argv[]) {
+ if ((daemon_log_ident = strrchr(argv[0], '/')))
+ daemon_log_ident++;
+ else
+ daemon_log_ident = argv[0];
+
+ daemon_log_use_syslog = FALSE;
+
+ return start();
+}
diff --git a/daemon/main.h b/daemon/main.h
new file mode 100644
index 0000000..b4c5e5b
--- /dev/null
+++ b/daemon/main.h
@@ -0,0 +1,14 @@
+#ifndef foomainhfoo
+#define foomainhfoo
+
+#include <sys/select.h>
+
+extern fd_set listen_wfds, listen_rfds, select_wfds, select_rfds;
+
+extern gboolean fail;
+
+extern guint32 default_verdict;
+
+extern gboolean log_packets;
+
+#endif
diff --git a/daemon/packet.c b/daemon/packet.c
new file mode 100644
index 0000000..c8722f8
--- /dev/null
+++ b/daemon/packet.c
@@ -0,0 +1,101 @@
+#include <time.h>
+
+#include "packet.h"
+
+#define PACKET_TIMEOUT 30
+
+typedef struct packet_wrapper {
+ time_t timestamp;
+ ipq_packet_msg_t m;
+} packet_wrapper_t;
+
+static GSList *packets = NULL;
+static guint n_packets = 0;
+static guint total_packets = 0;
+
+guint get_queued_packets() {
+ return n_packets;
+}
+
+guint get_total_packets() {
+ return total_packets;
+}
+
+void packet_new(ipq_packet_msg_t *m) {
+ packet_wrapper_t *w = (packet_wrapper_t*) g_malloc(sizeof(packet_wrapper_t)+ m->data_len);
+ memcpy(&w->m, m, sizeof(ipq_packet_msg_t)+ m->data_len);
+ time(&w->timestamp);
+
+ packets = g_slist_prepend(packets, w);
+ n_packets++;
+ total_packets++;
+}
+
+static packet_wrapper_t* _find(unsigned long id) {
+ GSList *l;
+
+ for (l = packets; l; l = l->next) {
+ packet_wrapper_t *w = (packet_wrapper_t*) l->data;
+ if (w->m.packet_id == id)
+ return w;
+ }
+
+ return NULL;
+}
+
+ipq_packet_msg_t* packet_find(unsigned long id) {
+ packet_wrapper_t* w;
+
+ if ((w = _find(id)))
+ return &w->m;
+
+ return NULL;
+}
+
+void packet_release(unsigned long id) {
+ packet_wrapper_t *w;
+
+ w = _find(id);
+ g_assert(w);
+
+ packets = g_slist_remove(packets, w);
+ g_free(w);
+ n_packets--;
+}
+
+
+void packet_foreach(gboolean age, gboolean (*func)(ipq_packet_msg_t*)) {
+ GSList *l, *p;
+
+ for (l = packets, p = NULL; l;) {
+ gboolean remove = FALSE;
+ packet_wrapper_t *w = (packet_wrapper_t*) l->data;
+
+ if (!age || w->timestamp + PACKET_TIMEOUT < time(NULL))
+ if (!func(&w->m))
+ remove = TRUE;
+
+
+
+ if (remove) {
+ if (p)
+ p->next = l->next;
+ else
+ packets = l->next;
+
+ g_slist_free_1(l);
+
+ l = p;
+ } else
+ l = l->next;
+ }
+}
+
+void packets_free() {
+ while (packets) {
+ packet_wrapper_t *w;
+ w = (packet_wrapper_t*) packets->data;
+ packets = g_slist_remove(packets, w);
+ g_free(w);
+ }
+}
diff --git a/daemon/packet.h b/daemon/packet.h
new file mode 100644
index 0000000..49fe042
--- /dev/null
+++ b/daemon/packet.h
@@ -0,0 +1,15 @@
+#ifndef foopackethfoo
+#define foopackethfoo
+
+#include <libipq/libipq.h>
+#include <glib.h>
+
+void packet_new(ipq_packet_msg_t *m);
+ipq_packet_msg_t* packet_find(unsigned long id);
+void packet_release(unsigned long id);
+void packet_foreach(gboolean age, gboolean (*func)(ipq_packet_msg_t*));
+void packets_free();
+guint get_queued_packets();
+guint get_total_packets();
+
+#endif