diff options
Diffstat (limited to 'daemon/ipqapi.c')
| -rw-r--r-- | daemon/ipqapi.c | 118 | 
1 files changed, 118 insertions, 0 deletions
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; +}  | 
