diff options
Diffstat (limited to 'framework/src/suricata/src/source-nflog.c')
-rw-r--r-- | framework/src/suricata/src/source-nflog.c | 550 |
1 files changed, 0 insertions, 550 deletions
diff --git a/framework/src/suricata/src/source-nflog.c b/framework/src/suricata/src/source-nflog.c deleted file mode 100644 index 7722244f..00000000 --- a/framework/src/suricata/src/source-nflog.c +++ /dev/null @@ -1,550 +0,0 @@ -/* Copyright (C) 2014 Open Information Security Foundation - * - * You can copy, redistribute or modify this Program under the terms of - * the GNU General Public License version 2 as published by the Free - * Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -/** - * \file - * - * \author Giuseppe Longo <giuseppelng@gmail.com> - * - * Netfilter's netfilter_log support - */ -#include "suricata-common.h" -#include "suricata.h" -#include "decode.h" -#include "packet-queue.h" - -#include "threads.h" -#include "threadvars.h" -#include "tm-threads.h" -#include "tm-modules.h" -#include "tm-queuehandlers.h" -#include "tmqh-packetpool.h" - -#include "runmodes.h" -#include "util-error.h" -#include "util-device.h" - -#ifndef HAVE_NFLOG -/** Handle the case where no NFLOG support is compiled in. - * - */ - -TmEcode NoNFLOGSupportExit(ThreadVars *, void *, void **); - -void TmModuleReceiveNFLOGRegister (void) -{ - tmm_modules[TMM_RECEIVENFLOG].name = "ReceiveNFLOG"; - tmm_modules[TMM_RECEIVENFLOG].ThreadInit = NoNFLOGSupportExit; -} - -void TmModuleDecodeNFLOGRegister (void) -{ - tmm_modules[TMM_DECODENFLOG].name = "DecodeNFLOG"; - tmm_modules[TMM_DECODENFLOG].ThreadInit = NoNFLOGSupportExit; -} - -TmEcode NoNFLOGSupportExit(ThreadVars *tv, void *initdata, void **data) -{ - SCLogError(SC_ERR_NFLOG_NOSUPPORT,"Error creating thread %s: you do not have support for nflog " - "enabled please recompile with --enable-nflog", tv->name); - exit(EXIT_FAILURE); -} - -#else /* implied we do have NFLOG support */ - -#include "source-nflog.h" - -TmEcode ReceiveNFLOGThreadInit(ThreadVars *, void *, void **); -TmEcode ReceiveNFLOGThreadDeinit(ThreadVars *, void *); -TmEcode ReceiveNFLOGLoop(ThreadVars *, void *, void *); -void ReceiveNFLOGThreadExitStats(ThreadVars *, void *); - -TmEcode DecodeNFLOGThreadInit(ThreadVars *, void *, void **); -TmEcode DecodeNFLOGThreadDeinit(ThreadVars *tv, void *data); -TmEcode DecodeNFLOG(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); - -static int runmode_workers; - -/* Structure to hold thread specific variables */ -typedef struct NFLOGThreadVars_ { - ThreadVars *tv; - TmSlot *slot; - - char *data; - int datalen; - - uint16_t group; - uint32_t nlbufsiz; - uint32_t nlbufsiz_max; - uint32_t qthreshold; - uint32_t qtimeout; - - struct nflog_handle *h; - struct nflog_g_handle *gh; - - LiveDevice *livedev; - int nful_overrun_warned; - - /* counters */ - uint32_t pkts; - uint64_t bytes; - uint32_t errs; - - uint16_t capture_kernel_packets; - uint16_t capture_kernel_drops; -} NFLOGThreadVars; - -/** - * \brief Registration function for ReceiveNFLOG - */ -void TmModuleReceiveNFLOGRegister (void) -{ - tmm_modules[TMM_RECEIVENFLOG].name = "ReceiveNFLOG"; - tmm_modules[TMM_RECEIVENFLOG].ThreadInit = ReceiveNFLOGThreadInit; - tmm_modules[TMM_RECEIVENFLOG].Func = NULL; - tmm_modules[TMM_RECEIVENFLOG].PktAcqLoop = ReceiveNFLOGLoop; - tmm_modules[TMM_RECEIVENFLOG].ThreadExitPrintStats = ReceiveNFLOGThreadExitStats; - tmm_modules[TMM_RECEIVENFLOG].ThreadDeinit = ReceiveNFLOGThreadDeinit; - tmm_modules[TMM_RECEIVENFLOG].RegisterTests = NULL; - tmm_modules[TMM_RECEIVENFLOG].flags = TM_FLAG_RECEIVE_TM; -} - -/** - * \brief Registration function for DecodeNFLOG - */ -void TmModuleDecodeNFLOGRegister (void) -{ - tmm_modules[TMM_DECODENFLOG].name = "DecodeNFLOG"; - tmm_modules[TMM_DECODENFLOG].ThreadInit = DecodeNFLOGThreadInit; - tmm_modules[TMM_DECODENFLOG].Func = DecodeNFLOG; - tmm_modules[TMM_DECODENFLOG].ThreadExitPrintStats = NULL; - tmm_modules[TMM_DECODENFLOG].ThreadDeinit = DecodeNFLOGThreadDeinit; - tmm_modules[TMM_DECODENFLOG].RegisterTests = NULL; - tmm_modules[TMM_DECODENFLOG].flags = TM_FLAG_DECODE_TM; -} - -/** - * \brief NFLOG callback function - * This function setup a packet from a nflog message - */ -static int NFLOGCallback(struct nflog_g_handle *gh, struct nfgenmsg *msg, - struct nflog_data *nfa, void *data) -{ - NFLOGThreadVars *ntv = (NFLOGThreadVars *) data; - struct nfulnl_msg_packet_hdr *ph; - char *payload; - int ret; - - /* grab a packet*/ - Packet *p = PacketGetFromQueueOrAlloc(); - if (p == NULL) - return -1; - - PKT_SET_SRC(p, PKT_SRC_WIRE); - - ph = nflog_get_msg_packet_hdr(nfa); - if (ph != NULL) { - p->nflog_v.hw_protocol = ph->hw_protocol; - } - - p->nflog_v.ifi = nflog_get_indev(nfa); - p->nflog_v.ifo = nflog_get_outdev(nfa); - - ret = nflog_get_payload(nfa, &payload); - - if (ret > 0) { - if (ret > 65536) { - SCLogWarning(SC_ERR_INVALID_ARGUMENTS, "NFLOG sent too big packet"); - SET_PKT_LEN(p, 0); - } else if (runmode_workers) - PacketSetData(p, (uint8_t *)payload, ret); - else - PacketCopyData(p, (uint8_t *)payload, ret); - } else if (ret == -1) - SET_PKT_LEN(p, 0); - - ret = nflog_get_timestamp(nfa, &p->ts); - if (ret != 0) { - memset(&p->ts, 0, sizeof(struct timeval)); - gettimeofday(&p->ts, NULL); - } - - p->datalink = DLT_RAW; - -#ifdef COUNTERS - ntv->pkts++; - ntv->bytes += GET_PKT_LEN(p); -#endif - (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1); - - if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) { - TmqhOutputPacketpool(ntv->tv, p); - return -1; - } - - return 0; -} - -/** - * \brief Receives packet from a nflog group via libnetfilter_log - * This is a setup function for recieving packets via libnetfilter_log. - * \param tv pointer to ThreadVars - * \param initdata pointer to the group passed from the user - * \param data pointer gets populated with NFLOGThreadVars - * \retvalTM_ECODE_OK on success - * \retval TM_ECODE_FAILED on error - */ -TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, void *initdata, void **data) -{ - NflogGroupConfig *nflconfig = initdata; - - if (initdata == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); - SCReturnInt(TM_ECODE_FAILED); - } - - NFLOGThreadVars *ntv = SCMalloc(sizeof(NFLOGThreadVars)); - if (unlikely(ntv == NULL)) { - nflconfig->DerefFunc(nflconfig); - SCReturnInt(TM_ECODE_FAILED); - } - memset(ntv, 0, sizeof(NFLOGThreadVars)); - - ntv->tv = tv; - ntv->group = nflconfig->group; - ntv->nlbufsiz = nflconfig->nlbufsiz; - ntv->nlbufsiz_max = nflconfig->nlbufsiz_max; - ntv->qthreshold = nflconfig->qthreshold; - ntv->qtimeout = nflconfig->qtimeout; - ntv->nful_overrun_warned = nflconfig->nful_overrun_warned; - - ntv->h = nflog_open(); - if (ntv->h == NULL) { - SCLogError(SC_ERR_NFLOG_OPEN, "nflog_open() failed"); - SCFree(ntv); - return TM_ECODE_FAILED; - } - - SCLogDebug("binding netfilter_log as nflog handler for AF_INET and AF_INET6"); - - if (nflog_bind_pf(ntv->h, AF_INET) < 0) { - SCLogError(SC_ERR_NFLOG_BIND, "nflog_bind_pf() for AF_INET failed"); - exit(EXIT_FAILURE); - } - if (nflog_bind_pf(ntv->h, AF_INET6) < 0) { - SCLogError(SC_ERR_NFLOG_BIND, "nflog_bind_pf() for AF_INET6 failed"); - exit(EXIT_FAILURE); - } - - ntv->gh = nflog_bind_group(ntv->h, ntv->group); - if (!ntv->gh) { - SCLogError(SC_ERR_NFLOG_OPEN, "nflog_bind_group() failed"); - SCFree(ntv); - return TM_ECODE_FAILED; - } - - if (nflog_set_mode(ntv->gh, NFULNL_COPY_PACKET, 0xFFFF) < 0) { - SCLogError(SC_ERR_NFLOG_SET_MODE, "can't set packet_copy mode"); - SCFree(ntv); - return TM_ECODE_FAILED; - } - - nflog_callback_register(ntv->gh, &NFLOGCallback, (void *)ntv); - - if (ntv->nlbufsiz < ntv->nlbufsiz_max) - ntv->nlbufsiz = nfnl_rcvbufsiz(nflog_nfnlh(ntv->h), ntv->nlbufsiz); - else { - SCLogError(SC_ERR_NFLOG_MAX_BUFSIZ, "Maximum buffer size (%d) in NFLOG " - "has been reached", ntv->nlbufsiz); - return TM_ECODE_FAILED; - } - - if (nflog_set_qthresh(ntv->gh, ntv->qthreshold) >= 0) - SCLogDebug("NFLOG netlink queue threshold has been set to %d", - ntv->qthreshold); - else - SCLogDebug("NFLOG netlink queue threshold can't be set to %d", - ntv->qthreshold); - - if (nflog_set_timeout(ntv->gh, ntv->qtimeout) >= 0) - SCLogDebug("NFLOG netlink queue timeout has been set to %d", - ntv->qtimeout); - else - SCLogDebug("NFLOG netlink queue timeout can't be set to %d", - ntv->qtimeout); - - ntv->livedev = LiveGetDevice(nflconfig->numgroup); - if (ntv->livedev == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); - SCFree(ntv); - SCReturnInt(TM_ECODE_FAILED); - } - - /* set a timeout to the socket so we can check for a signal - * in case we don't get packets for a longer period. */ - struct timeval timev; - timev.tv_sec = 1; - timev.tv_usec = 0; - - int fd = nflog_fd(ntv->h); - if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)) == -1) { - SCLogWarning(SC_WARN_NFLOG_SETSOCKOPT, "can't set socket " - "timeout: %s", strerror(errno)); - } - -#ifdef PACKET_STATISTICS - ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ntv->tv); - ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ntv->tv); -#endif - - char *active_runmode = RunmodeGetActive(); - if (active_runmode && !strcmp("workers", active_runmode)) - runmode_workers = 1; - else - runmode_workers = 0; - -#define T_DATA_SIZE 70000 - ntv->data = SCMalloc(T_DATA_SIZE); - if (ntv->data == NULL) { - nflconfig->DerefFunc(nflconfig); - SCFree(ntv); - SCReturnInt(TM_ECODE_FAILED); - } - - ntv->datalen = T_DATA_SIZE; -#undef T_DATA_SIZE - - *data = (void *)ntv; - - nflconfig->DerefFunc(nflconfig); - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief DeInit function unbind group and close nflog's handle - * \param tv pointer to ThreadVars - * \param data pointer that gets cast into NFLogThreadVars - * \retval TM_ECODE_OK is always returned - */ -TmEcode ReceiveNFLOGThreadDeinit(ThreadVars *tv, void *data) -{ - NFLOGThreadVars *ntv = (NFLOGThreadVars *)data; - - SCLogDebug("closing nflog group %d", ntv->group); - if (nflog_unbind_pf(ntv->h, AF_INET) < 0) { - SCLogError(SC_ERR_NFLOG_UNBIND, "nflog_unbind_pf() for AF_INET failed"); - exit(EXIT_FAILURE); - } - - if (nflog_unbind_pf(ntv->h, AF_INET6) < 0) { - SCLogError(SC_ERR_NFLOG_UNBIND, "nflog_unbind_pf() for AF_INET6 failed"); - exit(EXIT_FAILURE); - } - - if (ntv->gh) { - nflog_unbind_group(ntv->gh); - ntv->gh = NULL; - } - - if (ntv->h) { - nflog_close(ntv->h); - ntv->h = NULL; - } - - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief Increases netlink buffer size - * - * This function netlink's buffer size until - * the max buffer size is reached - * - * \param data pointer that gets cast into NFLOGThreadVars - * \param size netlink buffer size - */ -static int NFLOGSetnlbufsiz(void *data, unsigned int size) -{ - SCEnter(); - NFLOGThreadVars *ntv = (NFLOGThreadVars *)data; - - if (size < ntv->nlbufsiz_max) { - ntv->nlbufsiz = nfnl_rcvbufsiz(nflog_nfnlh(ntv->h), ntv->nlbufsiz); - return 1; - } - - SCLogWarning(SC_WARN_NFLOG_MAXBUFSIZ_REACHED, - "Maximum buffer size (%d) in NFLOG has been " - "reached. Please, consider raising " - "`buffer-size` and `max-size` in nflog configuration", - ntv->nlbufsiz); - return 0; - -} - -/** - * \brief Recieves packets from a group via libnetfilter_log. - * - * This function recieves packets from a group and passes - * the packet on to the nflog callback function. - * - * \param tv pointer to ThreadVars - * \param data pointer that gets cast into NFLOGThreadVars - * \param slot slot containing task information - * \retval TM_ECODE_OK on success - * \retval TM_ECODE_FAILED on failure - */ -TmEcode ReceiveNFLOGLoop(ThreadVars *tv, void *data, void *slot) -{ - SCEnter(); - NFLOGThreadVars *ntv = (NFLOGThreadVars *)data; - int rv, fd; - int ret = -1; - - ntv->slot = ((TmSlot *) slot)->slot_next; - - fd = nflog_fd(ntv->h); - if (fd < 0) { - SCLogError(SC_ERR_NFLOG_FD, "Can't obtain a file descriptor"); - SCReturnInt(TM_ECODE_FAILED); - } - - while (1) { - if (suricata_ctl_flags != 0) - break; - - rv = recv(fd, ntv->data, ntv->datalen, 0); - if (rv < 0) { - /*We received an error on socket read */ - if (errno == EINTR || errno == EWOULDBLOCK) { - /*Nothing for us to process */ - continue; - } else if (errno == ENOBUFS) { - if (!ntv->nful_overrun_warned) { - int s = ntv->nlbufsiz * 2; - if (NFLOGSetnlbufsiz((void *)ntv, s)) { - SCLogWarning(SC_WARN_NFLOG_LOSING_EVENTS, - "We are losing events, " - "increasing buffer size " - "to %d", ntv->nlbufsiz); - } else { - ntv->nful_overrun_warned = 1; - } - } - continue; - } else { - SCLogWarning(SC_WARN_NFLOG_RECV, - "Read from NFLOG fd failed: %s", - strerror(errno)); - SCReturnInt(TM_ECODE_FAILED); - } - } - - ret = nflog_handle_packet(ntv->h, ntv->data, rv); - if (ret != 0) - SCLogWarning(SC_ERR_NFLOG_HANDLE_PKT, - "nflog_handle_packet error %" PRId32 "", ret); - - StatsSyncCountersIfSignalled(tv); - } - - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief This function prints stats to the screen at exit - * \param tv pointer to ThreadVars - * \param data pointer that gets cast into NFLOGThreadVars - */ -void ReceiveNFLOGThreadExitStats(ThreadVars *tv, void *data) -{ - SCEnter(); - NFLOGThreadVars *ntv = (NFLOGThreadVars *)data; - - SCLogNotice("(%s) Pkts %" PRIu32 ", Bytes %" PRIu64 "", - tv->name, ntv->pkts, ntv->bytes); -} - - -/** - * \brief Decode IPv4/v6 packets. - * - * \param tv pointer to ThreadVars - * \param p pointer to the current packet - * \param data pointer that gets cast into NFLOGThreadVars for ptv - * \param pq pointer to the current PacketQueue - * - * \retval TM_ECODE_OK is always returned - */ -TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - SCEnter(); - IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p); - IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p); - DecodeThreadVars *dtv = (DecodeThreadVars *)data; - - DecodeUpdatePacketCounters(tv, dtv, p); - - if (IPV4_GET_RAW_VER(ip4h) == 4) { - SCLogDebug("IPv4 packet"); - DecodeIPV4(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - } else if(IPV6_GET_RAW_VER(ip6h) == 6) { - SCLogDebug("IPv6 packet"); - DecodeIPV6(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - } else { - SCLogDebug("packet unsupported by NFLOG, first byte: %02x", *GET_PKT_DATA(p)); - } - - PacketDecodeFinalize(tv, dtv, p); - - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief This an Init function for DecodeNFLOG - * - * \param tv pointer to ThreadVars - * \param initdata pointer to initilization data. - * \param data pointer that gets cast into NFLOGThreadVars - * \retval TM_ECODE_OK is returned on success - * \retval TM_ECODE_FAILED is returned on error - */ -TmEcode DecodeNFLOGThreadInit(ThreadVars *tv, void *initdata, void **data) -{ - DecodeThreadVars *dtv = NULL; - dtv = DecodeThreadVarsAlloc(tv); - - if (dtv == NULL) - SCReturnInt(TM_ECODE_FAILED); - - DecodeRegisterPerfCounters(dtv, tv); - - *data = (void *)dtv; - - SCReturnInt(TM_ECODE_OK); -} - -TmEcode DecodeNFLOGThreadDeinit(ThreadVars *tv, void *data) -{ - if (data != NULL) - DecodeThreadVarsFree(tv, data); - SCReturnInt(TM_ECODE_OK); -} - -#endif /* NFLOG */ |