From 63d51b566ea270b45b5b34b1feab37b8faa28232 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 9 May 2004 23:20:43 +0000 Subject: main fieryfilter work git-svn-id: file:///home/lennart/svn/public/fieryfilter/fieryfilter@31 79e6afc9-17da-0310-ae3c-b873bff394f4 --- daemon/Makefile.am | 34 +++++++ daemon/client.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++++++++ daemon/client.h | 13 +++ daemon/common.h | 23 +++++ daemon/icmp.c | 87 ++++++++++++++++ daemon/icmp.h | 11 ++ daemon/ipqapi.c | 118 ++++++++++++++++++++++ daemon/ipqapi.h | 13 +++ daemon/main.c | 198 ++++++++++++++++++++++++++++++++++++ daemon/main.h | 14 +++ daemon/packet.c | 101 ++++++++++++++++++ daemon/packet.h | 15 +++ 12 files changed, 919 insertions(+) create mode 100644 daemon/Makefile.am create mode 100644 daemon/client.c create mode 100644 daemon/client.h create mode 100644 daemon/common.h create mode 100644 daemon/icmp.c create mode 100644 daemon/icmp.h create mode 100644 daemon/ipqapi.c create mode 100644 daemon/ipqapi.h create mode 100644 daemon/main.c create mode 100644 daemon/main.h create mode 100644 daemon/packet.c create mode 100644 daemon/packet.h (limited to 'daemon') 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 +#include +#include +#include +#include + +#include + +#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 +#include +#include + +#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 +#include +#include + +#include +#include +#include + +#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 +#include + +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 +#include + +#include + +#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 +#include +#include + +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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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 + +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 + +#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 +#include + +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 -- cgit