From 19d701ddf07d855128ded0cf2b573ce468e3bdd6 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Wed, 20 Jan 2016 01:10:01 +0000 Subject: Removing Suricata and Audit from source repo, and updated build.sh to avoid building suricata. Will re-address this in C release via tar balls. Change-Id: I3710076f8b7f3313cb3cb5260c4eb0a6834d4f6e Signed-off-by: Ashlee Young --- framework/src/suricata/src/source-af-packet.c | 1919 ------------------------- 1 file changed, 1919 deletions(-) delete mode 100644 framework/src/suricata/src/source-af-packet.c (limited to 'framework/src/suricata/src/source-af-packet.c') diff --git a/framework/src/suricata/src/source-af-packet.c b/framework/src/suricata/src/source-af-packet.c deleted file mode 100644 index 3f1f44e1..00000000 --- a/framework/src/suricata/src/source-af-packet.c +++ /dev/null @@ -1,1919 +0,0 @@ -/* Copyright (C) 2011-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. - */ - -/** - * \defgroup afppacket AF_PACKET running mode - * - * @{ - */ - -/** - * \file - * - * \author Eric Leblond - * - * AF_PACKET socket acquisition support - * - * \todo watch other interface event to detect suppression of the monitored - * interface - */ - -#include "suricata-common.h" -#include "config.h" -#include "suricata.h" -#include "decode.h" -#include "packet-queue.h" -#include "threads.h" -#include "threadvars.h" -#include "tm-queuehandlers.h" -#include "tm-modules.h" -#include "tm-threads.h" -#include "tm-threads-common.h" -#include "conf.h" -#include "util-debug.h" -#include "util-device.h" -#include "util-error.h" -#include "util-privs.h" -#include "util-optimize.h" -#include "util-checksum.h" -#include "util-ioctl.h" -#include "util-host-info.h" -#include "tmqh-packetpool.h" -#include "source-af-packet.h" -#include "runmodes.h" - -#ifdef __SC_CUDA_SUPPORT__ - -#include "util-cuda.h" -#include "util-cuda-buffer.h" -#include "util-mpm-ac.h" -#include "util-cuda-handlers.h" -#include "detect-engine.h" -#include "detect-engine-mpm.h" -#include "util-cuda-vars.h" - -#endif /* __SC_CUDA_SUPPORT__ */ - -#ifdef HAVE_AF_PACKET - -#if HAVE_SYS_IOCTL_H -#include -#endif - -#if HAVE_LINUX_IF_ETHER_H -#include -#endif - -#if HAVE_LINUX_IF_PACKET_H -#include -#endif - -#if HAVE_LINUX_IF_ARP_H -#include -#endif - -#if HAVE_LINUX_FILTER_H -#include -#endif - -#if HAVE_SYS_MMAN_H -#include -#endif - -#endif /* HAVE_AF_PACKET */ - -extern int max_pending_packets; - -#ifndef HAVE_AF_PACKET - -TmEcode NoAFPSupportExit(ThreadVars *, void *, void **); - -void TmModuleReceiveAFPRegister (void) -{ - tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; - tmm_modules[TMM_RECEIVEAFP].ThreadInit = NoAFPSupportExit; - tmm_modules[TMM_RECEIVEAFP].Func = NULL; - tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = NULL; - tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; - tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; - tmm_modules[TMM_RECEIVEAFP].cap_flags = 0; - tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; -} - -/** - * \brief Registration Function for DecodeAFP. - * \todo Unit tests are needed for this module. - */ -void TmModuleDecodeAFPRegister (void) -{ - tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; - tmm_modules[TMM_DECODEAFP].ThreadInit = NoAFPSupportExit; - tmm_modules[TMM_DECODEAFP].Func = NULL; - tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; - tmm_modules[TMM_DECODEAFP].ThreadDeinit = NULL; - tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; - tmm_modules[TMM_DECODEAFP].cap_flags = 0; - tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; -} - -/** - * \brief this function prints an error message and exits. - */ -TmEcode NoAFPSupportExit(ThreadVars *tv, void *initdata, void **data) -{ - SCLogError(SC_ERR_NO_AF_PACKET,"Error creating thread %s: you do not have " - "support for AF_PACKET enabled, on Linux host please recompile " - "with --enable-af-packet", tv->name); - exit(EXIT_FAILURE); -} - -#else /* We have AF_PACKET support */ - -#define AFP_IFACE_NAME_LENGTH 48 - -#define AFP_STATE_DOWN 0 -#define AFP_STATE_UP 1 - -#define AFP_RECONNECT_TIMEOUT 500000 -#define AFP_DOWN_COUNTER_INTERVAL 40 - -#define POLL_TIMEOUT 100 - -#ifndef TP_STATUS_USER_BUSY -/* for new use latest bit available in tp_status */ -#define TP_STATUS_USER_BUSY (1 << 31) -#endif - -#ifndef TP_STATUS_VLAN_VALID -#define TP_STATUS_VLAN_VALID (1 << 4) -#endif - -/** protect pfring_set_bpf_filter, as it is not thread safe */ -static SCMutex afpacket_bpf_set_filter_lock = SCMUTEX_INITIALIZER; - -enum { - AFP_READ_OK, - AFP_READ_FAILURE, - AFP_FAILURE, - AFP_KERNEL_DROP, -}; - -enum { - AFP_FATAL_ERROR = 1, - AFP_RECOVERABLE_ERROR, -}; - -union thdr { - struct tpacket2_hdr *h2; - void *raw; -}; - -/** - * \brief Structure to hold thread specific variables. - */ -typedef struct AFPThreadVars_ -{ - /* thread specific socket */ - int socket; - /* handle state */ - unsigned char afp_state; - - /* data link type for the thread */ - int datalink; - int cooked; - - /* counters */ - uint64_t pkts; - uint64_t bytes; - uint64_t errs; - - ThreadVars *tv; - TmSlot *slot; - - uint8_t *data; /** Per function and thread data */ - int datalen; /** Length of per function and thread data */ - - int vlan_disabled; - - char iface[AFP_IFACE_NAME_LENGTH]; - LiveDevice *livedev; - int down_count; - - /* Filter */ - char *bpf_filter; - - /* socket buffer size */ - int buffer_size; - int promisc; - ChecksumValidationMode checksum_mode; - - /* IPS stuff */ - char out_iface[AFP_IFACE_NAME_LENGTH]; - AFPPeer *mpeer; - - int flags; - uint16_t capture_kernel_packets; - uint16_t capture_kernel_drops; - - int cluster_id; - int cluster_type; - - int threads; - int copy_mode; - - struct tpacket_req req; - unsigned int tp_hdrlen; - unsigned int ring_buflen; - char *ring_buf; - char *frame_buf; - unsigned int frame_offset; - int ring_size; - -} AFPThreadVars; - -TmEcode ReceiveAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); -TmEcode ReceiveAFPThreadInit(ThreadVars *, void *, void **); -void ReceiveAFPThreadExitStats(ThreadVars *, void *); -TmEcode ReceiveAFPThreadDeinit(ThreadVars *, void *); -TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot); - -TmEcode DecodeAFPThreadInit(ThreadVars *, void *, void **); -TmEcode DecodeAFPThreadDeinit(ThreadVars *tv, void *data); -TmEcode DecodeAFP(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *); - -TmEcode AFPSetBPFFilter(AFPThreadVars *ptv); -static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose); -static int AFPGetDevFlags(int fd, const char *ifname); -static int AFPDerefSocket(AFPPeer* peer); -static int AFPRefSocket(AFPPeer* peer); - -/** - * \brief Registration Function for RecieveAFP. - * \todo Unit tests are needed for this module. - */ -void TmModuleReceiveAFPRegister (void) -{ - tmm_modules[TMM_RECEIVEAFP].name = "ReceiveAFP"; - tmm_modules[TMM_RECEIVEAFP].ThreadInit = ReceiveAFPThreadInit; - tmm_modules[TMM_RECEIVEAFP].Func = NULL; - tmm_modules[TMM_RECEIVEAFP].PktAcqLoop = ReceiveAFPLoop; - tmm_modules[TMM_RECEIVEAFP].ThreadExitPrintStats = ReceiveAFPThreadExitStats; - tmm_modules[TMM_RECEIVEAFP].ThreadDeinit = NULL; - tmm_modules[TMM_RECEIVEAFP].RegisterTests = NULL; - tmm_modules[TMM_RECEIVEAFP].cap_flags = SC_CAP_NET_RAW; - tmm_modules[TMM_RECEIVEAFP].flags = TM_FLAG_RECEIVE_TM; -} - - -/** - * \defgroup afppeers AFP peers list - * - * AF_PACKET has an IPS mode were interface are peered: packet from - * on interface are sent the peered interface and the other way. The ::AFPPeer - * list is maitaining the list of peers. Each ::AFPPeer is storing the needed - * information to be able to send packet on the interface. - * A element of the list must not be destroyed during the run of Suricata as it - * is used by ::Packet and other threads. - * - * @{ - */ - -typedef struct AFPPeersList_ { - TAILQ_HEAD(, AFPPeer_) peers; /**< Head of list of fragments. */ - int cnt; - int peered; - int turn; /**< Next value for initialisation order */ - SC_ATOMIC_DECLARE(int, reached); /**< Counter used to synchronize start */ -} AFPPeersList; - -/** - * \brief Update the peer. - * - * Update the AFPPeer of a thread ie set new state, socket number - * or iface index. - * - */ -void AFPPeerUpdate(AFPThreadVars *ptv) -{ - if (ptv->mpeer == NULL) { - return; - } - (void)SC_ATOMIC_SET(ptv->mpeer->if_idx, AFPGetIfnumByDev(ptv->socket, ptv->iface, 0)); - (void)SC_ATOMIC_SET(ptv->mpeer->socket, ptv->socket); - (void)SC_ATOMIC_SET(ptv->mpeer->state, ptv->afp_state); -} - -/** - * \brief Clean and free ressource used by an ::AFPPeer - */ -void AFPPeerClean(AFPPeer *peer) -{ - if (peer->flags & AFP_SOCK_PROTECT) - SCMutexDestroy(&peer->sock_protect); - SC_ATOMIC_DESTROY(peer->socket); - SC_ATOMIC_DESTROY(peer->if_idx); - SC_ATOMIC_DESTROY(peer->state); - SCFree(peer); -} - -AFPPeersList peerslist; - - -/** - * \brief Init the global list of ::AFPPeer - */ -TmEcode AFPPeersListInit() -{ - SCEnter(); - TAILQ_INIT(&peerslist.peers); - peerslist.peered = 0; - peerslist.cnt = 0; - peerslist.turn = 0; - SC_ATOMIC_INIT(peerslist.reached); - (void) SC_ATOMIC_SET(peerslist.reached, 0); - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief Check that all ::AFPPeer got a peer - * - * \retval TM_ECODE_FAILED if some threads are not peered or TM_ECODE_OK else. - */ -TmEcode AFPPeersListCheck() -{ -#define AFP_PEERS_MAX_TRY 4 -#define AFP_PEERS_WAIT 20000 - int try = 0; - SCEnter(); - while (try < AFP_PEERS_MAX_TRY) { - if (peerslist.cnt != peerslist.peered) { - usleep(AFP_PEERS_WAIT); - } else { - SCReturnInt(TM_ECODE_OK); - } - try++; - } - SCLogError(SC_ERR_AFP_CREATE, "Threads number not equals"); - SCReturnInt(TM_ECODE_FAILED); -} - -/** - * \brief Declare a new AFP thread to AFP peers list. - */ -TmEcode AFPPeersListAdd(AFPThreadVars *ptv) -{ - SCEnter(); - AFPPeer *peer = SCMalloc(sizeof(AFPPeer)); - AFPPeer *pitem; - int mtu, out_mtu; - - if (unlikely(peer == NULL)) { - SCReturnInt(TM_ECODE_FAILED); - } - memset(peer, 0, sizeof(AFPPeer)); - SC_ATOMIC_INIT(peer->socket); - SC_ATOMIC_INIT(peer->sock_usage); - SC_ATOMIC_INIT(peer->if_idx); - SC_ATOMIC_INIT(peer->state); - peer->flags = ptv->flags; - peer->turn = peerslist.turn++; - - if (peer->flags & AFP_SOCK_PROTECT) { - SCMutexInit(&peer->sock_protect, NULL); - } - - (void)SC_ATOMIC_SET(peer->sock_usage, 0); - (void)SC_ATOMIC_SET(peer->state, AFP_STATE_DOWN); - strlcpy(peer->iface, ptv->iface, AFP_IFACE_NAME_LENGTH); - ptv->mpeer = peer; - /* add element to iface list */ - TAILQ_INSERT_TAIL(&peerslist.peers, peer, next); - - if (ptv->copy_mode != AFP_COPY_MODE_NONE) { - peerslist.cnt++; - - /* Iter to find a peer */ - TAILQ_FOREACH(pitem, &peerslist.peers, next) { - if (pitem->peer) - continue; - if (strcmp(pitem->iface, ptv->out_iface)) - continue; - peer->peer = pitem; - pitem->peer = peer; - mtu = GetIfaceMTU(ptv->iface); - out_mtu = GetIfaceMTU(ptv->out_iface); - if (mtu != out_mtu) { - SCLogError(SC_ERR_AFP_CREATE, - "MTU on %s (%d) and %s (%d) are not equal, " - "transmission of packets bigger than %d will fail.", - ptv->iface, mtu, - ptv->out_iface, out_mtu, - (out_mtu > mtu) ? mtu : out_mtu); - } - peerslist.peered += 2; - break; - } - } - - AFPPeerUpdate(ptv); - - SCReturnInt(TM_ECODE_OK); -} - -int AFPPeersListWaitTurn(AFPPeer *peer) -{ - /* If turn is zero, we already have started threads once */ - if (peerslist.turn == 0) - return 0; - - if (peer->turn == SC_ATOMIC_GET(peerslist.reached)) - return 0; - return 1; -} - -void AFPPeersListReachedInc() -{ - if (peerslist.turn == 0) - return; - - if (SC_ATOMIC_ADD(peerslist.reached, 1) == peerslist.turn) { - SCLogInfo("All AFP capture threads are running."); - (void)SC_ATOMIC_SET(peerslist.reached, 0); - /* Set turn to 0 to skip syncrhonization when ReceiveAFPLoop is - * restarted. - */ - peerslist.turn = 0; - } -} - -static int AFPPeersListStarted() -{ - return !peerslist.turn; -} - -/** - * \brief Clean the global peers list. - */ -void AFPPeersListClean() -{ - AFPPeer *pitem; - - while ((pitem = TAILQ_FIRST(&peerslist.peers))) { - TAILQ_REMOVE(&peerslist.peers, pitem, next); - AFPPeerClean(pitem); - } -} - -/** - * @} - */ - -/** - * \brief Registration Function for DecodeAFP. - * \todo Unit tests are needed for this module. - */ -void TmModuleDecodeAFPRegister (void) -{ - tmm_modules[TMM_DECODEAFP].name = "DecodeAFP"; - tmm_modules[TMM_DECODEAFP].ThreadInit = DecodeAFPThreadInit; - tmm_modules[TMM_DECODEAFP].Func = DecodeAFP; - tmm_modules[TMM_DECODEAFP].ThreadExitPrintStats = NULL; - tmm_modules[TMM_DECODEAFP].ThreadDeinit = DecodeAFPThreadDeinit; - tmm_modules[TMM_DECODEAFP].RegisterTests = NULL; - tmm_modules[TMM_DECODEAFP].cap_flags = 0; - tmm_modules[TMM_DECODEAFP].flags = TM_FLAG_DECODE_TM; -} - - -static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose); - -static inline void AFPDumpCounters(AFPThreadVars *ptv) -{ -#ifdef PACKET_STATISTICS - struct tpacket_stats kstats; - socklen_t len = sizeof (struct tpacket_stats); - if (getsockopt(ptv->socket, SOL_PACKET, PACKET_STATISTICS, - &kstats, &len) > -1) { - SCLogDebug("(%s) Kernel: Packets %" PRIu32 ", dropped %" PRIu32 "", - ptv->tv->name, - kstats.tp_packets, kstats.tp_drops); - StatsAddUI64(ptv->tv, ptv->capture_kernel_packets, kstats.tp_packets); - StatsAddUI64(ptv->tv, ptv->capture_kernel_drops, kstats.tp_drops); - (void) SC_ATOMIC_ADD(ptv->livedev->drop, (uint64_t) kstats.tp_drops); - (void) SC_ATOMIC_ADD(ptv->livedev->pkts, (uint64_t) kstats.tp_packets); - } -#endif -} - -/** - * \brief AF packet read function. - * - * This function fills - * From here the packets are picked up by the DecodeAFP thread. - * - * \param user pointer to AFPThreadVars - * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success - */ -int AFPRead(AFPThreadVars *ptv) -{ - Packet *p = NULL; - /* XXX should try to use read that get directly to packet */ - int offset = 0; - int caplen; - struct sockaddr_ll from; - struct iovec iov; - struct msghdr msg; - struct cmsghdr *cmsg; - union { - struct cmsghdr cmsg; - char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; - } cmsg_buf; - unsigned char aux_checksum = 0; - - msg.msg_name = &from; - msg.msg_namelen = sizeof(from); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsg_buf; - msg.msg_controllen = sizeof(cmsg_buf); - msg.msg_flags = 0; - - if (ptv->cooked) - offset = SLL_HEADER_LEN; - else - offset = 0; - iov.iov_len = ptv->datalen - offset; - iov.iov_base = ptv->data + offset; - - caplen = recvmsg(ptv->socket, &msg, MSG_TRUNC); - - if (caplen < 0) { - SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32, - errno); - SCReturnInt(AFP_READ_FAILURE); - } - - p = PacketGetFromQueueOrAlloc(); - if (p == NULL) { - SCReturnInt(AFP_FAILURE); - } - PKT_SET_SRC(p, PKT_SRC_WIRE); - - /* get timestamp of packet via ioctl */ - if (ioctl(ptv->socket, SIOCGSTAMP, &p->ts) == -1) { - SCLogWarning(SC_ERR_AFP_READ, "recvmsg failed with error code %" PRId32, - errno); - TmqhOutputPacketpool(ptv->tv, p); - SCReturnInt(AFP_READ_FAILURE); - } - - ptv->pkts++; - ptv->bytes += caplen + offset; - p->livedev = ptv->livedev; - - /* add forged header */ - if (ptv->cooked) { - SllHdr * hdrp = (SllHdr *)ptv->data; - /* XXX this is minimalist, but this seems enough */ - hdrp->sll_protocol = from.sll_protocol; - } - - p->datalink = ptv->datalink; - SET_PKT_LEN(p, caplen + offset); - if (PacketCopyData(p, ptv->data, GET_PKT_LEN(p)) == -1) { - TmqhOutputPacketpool(ptv->tv, p); - SCReturnInt(AFP_FAILURE); - } - SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", - GET_PKT_LEN(p), p, GET_PKT_DATA(p)); - - /* We only check for checksum disable */ - if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { - p->flags |= PKT_IGNORE_CHECKSUM; - } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { - if (ptv->livedev->ignore_checksum) { - p->flags |= PKT_IGNORE_CHECKSUM; - } else if (ChecksumAutoModeCheck(ptv->pkts, - SC_ATOMIC_GET(ptv->livedev->pkts), - SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { - ptv->livedev->ignore_checksum = 1; - p->flags |= PKT_IGNORE_CHECKSUM; - } - } else { - aux_checksum = 1; - } - - /* List is NULL if we don't have activated auxiliary data */ - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - struct tpacket_auxdata *aux; - - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct tpacket_auxdata)) || - cmsg->cmsg_level != SOL_PACKET || - cmsg->cmsg_type != PACKET_AUXDATA) - continue; - - aux = (struct tpacket_auxdata *)CMSG_DATA(cmsg); - - if (aux_checksum && (aux->tp_status & TP_STATUS_CSUMNOTREADY)) { - p->flags |= PKT_IGNORE_CHECKSUM; - } - break; - } - - if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { - TmqhOutputPacketpool(ptv->tv, p); - SCReturnInt(AFP_FAILURE); - } - SCReturnInt(AFP_READ_OK); -} - -TmEcode AFPWritePacket(Packet *p) -{ - struct sockaddr_ll socket_address; - int socket; - - if (p->afp_v.copy_mode == AFP_COPY_MODE_IPS) { - if (PACKET_TEST_ACTION(p, ACTION_DROP)) { - return TM_ECODE_OK; - } - } - - if (SC_ATOMIC_GET(p->afp_v.peer->state) == AFP_STATE_DOWN) - return TM_ECODE_OK; - - if (p->ethh == NULL) { - SCLogWarning(SC_ERR_INVALID_VALUE, "Should have an Ethernet header"); - return TM_ECODE_FAILED; - } - /* Index of the network device */ - socket_address.sll_ifindex = SC_ATOMIC_GET(p->afp_v.peer->if_idx); - /* Address length*/ - socket_address.sll_halen = ETH_ALEN; - /* Destination MAC */ - memcpy(socket_address.sll_addr, p->ethh, 6); - - /* Send packet, locking the socket if necessary */ - if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) - SCMutexLock(&p->afp_v.peer->sock_protect); - socket = SC_ATOMIC_GET(p->afp_v.peer->socket); - if (sendto(socket, GET_PKT_DATA(p), GET_PKT_LEN(p), 0, - (struct sockaddr*) &socket_address, - sizeof(struct sockaddr_ll)) < 0) { - SCLogWarning(SC_ERR_SOCKET, "Sending packet failed on socket %d: %s", - socket, - strerror(errno)); - if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) - SCMutexUnlock(&p->afp_v.peer->sock_protect); - return TM_ECODE_FAILED; - } - if (p->afp_v.peer->flags & AFP_SOCK_PROTECT) - SCMutexUnlock(&p->afp_v.peer->sock_protect); - - return TM_ECODE_OK; -} - -void AFPReleaseDataFromRing(Packet *p) -{ - /* Need to be in copy mode and need to detect early release - where Ethernet header could not be set (and pseudo packet) */ - if ((p->afp_v.copy_mode != AFP_COPY_MODE_NONE) && !PKT_IS_PSEUDOPKT(p)) { - AFPWritePacket(p); - } - - if (AFPDerefSocket(p->afp_v.mpeer) == 0) - goto cleanup; - - if (p->afp_v.relptr) { - union thdr h; - h.raw = p->afp_v.relptr; - h.h2->tp_status = TP_STATUS_KERNEL; - } - -cleanup: - AFPV_CLEANUP(&p->afp_v); -} - -void AFPReleasePacket(Packet *p) -{ - AFPReleaseDataFromRing(p); - PacketFreeOrRelease(p); -} - -/** - * \brief AF packet read function for ring - * - * This function fills - * From here the packets are picked up by the DecodeAFP thread. - * - * \param user pointer to AFPThreadVars - * \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success - */ -int AFPReadFromRing(AFPThreadVars *ptv) -{ - Packet *p = NULL; - union thdr h; - struct sockaddr_ll *from; - uint8_t emergency_flush = 0; - int read_pkts = 0; - int loop_start = -1; - - - /* Loop till we have packets available */ - while (1) { - if (unlikely(suricata_ctl_flags != 0)) { - break; - } - - /* Read packet from ring */ - h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); - if (h.raw == NULL) { - SCReturnInt(AFP_FAILURE); - } - - if ((! h.h2->tp_status) || (h.h2->tp_status & TP_STATUS_USER_BUSY)) { - if (read_pkts == 0) { - if (loop_start == -1) { - loop_start = ptv->frame_offset; - } else if (unlikely(loop_start == (int)ptv->frame_offset)) { - SCReturnInt(AFP_READ_OK); - } - if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { - ptv->frame_offset = 0; - } - continue; - } - if ((emergency_flush) && (ptv->flags & AFP_EMERGENCY_MODE)) { - SCReturnInt(AFP_KERNEL_DROP); - } else { - SCReturnInt(AFP_READ_OK); - } - } - - read_pkts++; - loop_start = -1; - - /* Our packet is still used by suricata, we exit read loop to - * gain some time */ - if (h.h2->tp_status & TP_STATUS_USER_BUSY) { - SCReturnInt(AFP_READ_OK); - } - - if ((ptv->flags & AFP_EMERGENCY_MODE) && (emergency_flush == 1)) { - h.h2->tp_status = TP_STATUS_KERNEL; - goto next_frame; - } - - p = PacketGetFromQueueOrAlloc(); - if (p == NULL) { - SCReturnInt(AFP_FAILURE); - } - PKT_SET_SRC(p, PKT_SRC_WIRE); - - /* Suricata will treat packet so telling it is busy, this - * status will be reset to 0 (ie TP_STATUS_KERNEL) in the release - * function. */ - h.h2->tp_status |= TP_STATUS_USER_BUSY; - - from = (void *)h.raw + TPACKET_ALIGN(ptv->tp_hdrlen); - - ptv->pkts++; - ptv->bytes += h.h2->tp_len; - p->livedev = ptv->livedev; - - /* add forged header */ - if (ptv->cooked) { - SllHdr * hdrp = (SllHdr *)ptv->data; - /* XXX this is minimalist, but this seems enough */ - hdrp->sll_protocol = from->sll_protocol; - } - - p->datalink = ptv->datalink; - if (h.h2->tp_len > h.h2->tp_snaplen) { - SCLogDebug("Packet length (%d) > snaplen (%d), truncating", - h.h2->tp_len, h.h2->tp_snaplen); - } - - /* get vlan id from header */ - if ((!ptv->vlan_disabled) && - (h.h2->tp_status & TP_STATUS_VLAN_VALID || h.h2->tp_vlan_tci)) { - p->vlan_id[0] = h.h2->tp_vlan_tci; - p->vlan_idx = 1; - p->vlanh[0] = NULL; - } - - if (ptv->flags & AFP_ZERO_COPY) { - if (PacketSetData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) { - TmqhOutputPacketpool(ptv->tv, p); - SCReturnInt(AFP_FAILURE); - } else { - p->afp_v.relptr = h.raw; - p->ReleasePacket = AFPReleasePacket; - p->afp_v.mpeer = ptv->mpeer; - AFPRefSocket(ptv->mpeer); - - p->afp_v.copy_mode = ptv->copy_mode; - if (p->afp_v.copy_mode != AFP_COPY_MODE_NONE) { - p->afp_v.peer = ptv->mpeer->peer; - } else { - p->afp_v.peer = NULL; - } - } - } else { - if (PacketCopyData(p, (unsigned char*)h.raw + h.h2->tp_mac, h.h2->tp_snaplen) == -1) { - TmqhOutputPacketpool(ptv->tv, p); - SCReturnInt(AFP_FAILURE); - } - } - /* Timestamp */ - p->ts.tv_sec = h.h2->tp_sec; - p->ts.tv_usec = h.h2->tp_nsec/1000; - SCLogDebug("pktlen: %" PRIu32 " (pkt %p, pkt data %p)", - GET_PKT_LEN(p), p, GET_PKT_DATA(p)); - - /* We only check for checksum disable */ - if (ptv->checksum_mode == CHECKSUM_VALIDATION_DISABLE) { - p->flags |= PKT_IGNORE_CHECKSUM; - } else if (ptv->checksum_mode == CHECKSUM_VALIDATION_AUTO) { - if (ptv->livedev->ignore_checksum) { - p->flags |= PKT_IGNORE_CHECKSUM; - } else if (ChecksumAutoModeCheck(ptv->pkts, - SC_ATOMIC_GET(ptv->livedev->pkts), - SC_ATOMIC_GET(ptv->livedev->invalid_checksums))) { - ptv->livedev->ignore_checksum = 1; - p->flags |= PKT_IGNORE_CHECKSUM; - } - } else { - if (h.h2->tp_status & TP_STATUS_CSUMNOTREADY) { - p->flags |= PKT_IGNORE_CHECKSUM; - } - } - if (h.h2->tp_status & TP_STATUS_LOSING) { - emergency_flush = 1; - AFPDumpCounters(ptv); - } - - /* release frame if not in zero copy mode */ - if (!(ptv->flags & AFP_ZERO_COPY)) { - h.h2->tp_status = TP_STATUS_KERNEL; - } - - if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) { - h.h2->tp_status = TP_STATUS_KERNEL; - if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { - ptv->frame_offset = 0; - } - TmqhOutputPacketpool(ptv->tv, p); - SCReturnInt(AFP_FAILURE); - } - -next_frame: - if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { - ptv->frame_offset = 0; - /* Get out of loop to be sure we will reach maintenance tasks */ - SCReturnInt(AFP_READ_OK); - } - } - - SCReturnInt(AFP_READ_OK); -} - -/** - * \brief Reference socket - * - * \retval O in case of failure, 1 in case of success - */ -static int AFPRefSocket(AFPPeer* peer) -{ - if (unlikely(peer == NULL)) - return 0; - - (void)SC_ATOMIC_ADD(peer->sock_usage, 1); - return 1; -} - - -/** - * \brief Dereference socket - * - * \retval 1 if socket is still alive, 0 if not - */ -static int AFPDerefSocket(AFPPeer* peer) -{ - if (peer == NULL) - return 1; - - if (SC_ATOMIC_SUB(peer->sock_usage, 1) == 0) { - if (SC_ATOMIC_GET(peer->state) == AFP_STATE_DOWN) { - SCLogInfo("Cleaning socket connected to '%s'", peer->iface); - close(SC_ATOMIC_GET(peer->socket)); - return 0; - } - } - return 1; -} - -void AFPSwitchState(AFPThreadVars *ptv, int state) -{ - ptv->afp_state = state; - ptv->down_count = 0; - - AFPPeerUpdate(ptv); - - /* Do cleaning if switching to down state */ - if (state == AFP_STATE_DOWN) { - if (ptv->frame_buf) { - /* only used in reading phase, we can free it */ - SCFree(ptv->frame_buf); - ptv->frame_buf = NULL; - } - if (ptv->socket != -1) { - /* we need to wait for all packets to return data */ - if (SC_ATOMIC_SUB(ptv->mpeer->sock_usage, 1) == 0) { - SCLogInfo("Cleaning socket connected to '%s'", ptv->iface); - close(ptv->socket); - ptv->socket = -1; - } - } - } - if (state == AFP_STATE_UP) { - (void)SC_ATOMIC_SET(ptv->mpeer->sock_usage, 1); - } -} - -static int AFPReadAndDiscard(AFPThreadVars *ptv, struct timeval *synctv) -{ - struct sockaddr_ll from; - struct iovec iov; - struct msghdr msg; - struct timeval ts; - union { - struct cmsghdr cmsg; - char buf[CMSG_SPACE(sizeof(struct tpacket_auxdata))]; - } cmsg_buf; - - - if (unlikely(suricata_ctl_flags != 0)) { - return 1; - } - - msg.msg_name = &from; - msg.msg_namelen = sizeof(from); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = &cmsg_buf; - msg.msg_controllen = sizeof(cmsg_buf); - msg.msg_flags = 0; - - iov.iov_len = ptv->datalen; - iov.iov_base = ptv->data; - - recvmsg(ptv->socket, &msg, MSG_TRUNC); - - if (ioctl(ptv->socket, SIOCGSTAMP, &ts) == -1) { - /* FIXME */ - return -1; - } - - if ((ts.tv_sec > synctv->tv_sec) || - (ts.tv_sec >= synctv->tv_sec && - ts.tv_usec > synctv->tv_usec)) { - return 1; - } - return 0; -} - -static int AFPReadAndDiscardFromRing(AFPThreadVars *ptv, struct timeval *synctv) -{ - union thdr h; - - if (unlikely(suricata_ctl_flags != 0)) { - return 1; - } - - /* Read packet from ring */ - h.raw = (((union thdr **)ptv->frame_buf)[ptv->frame_offset]); - if (h.raw == NULL) { - return -1; - } - - if (((time_t)h.h2->tp_sec > synctv->tv_sec) || - ((time_t)h.h2->tp_sec == synctv->tv_sec && - (suseconds_t) (h.h2->tp_nsec / 1000) > synctv->tv_usec)) { - return 1; - } - - h.h2->tp_status = TP_STATUS_KERNEL; - if (++ptv->frame_offset >= ptv->req.tp_frame_nr) { - ptv->frame_offset = 0; - } - - - return 0; -} - -/** \brief wait for all afpacket threads to fully init - * - * Discard packets before all threads are ready, as the cluster - * setup is not complete yet. - * - * if AFPPeersListStarted() returns true init is complete - * - * \retval r 1 = happy, otherwise unhappy - */ -static int AFPSynchronizeStart(AFPThreadVars *ptv) -{ - int r; - struct timeval synctv; - struct pollfd fds; - - fds.fd = ptv->socket; - fds.events = POLLIN; - - /* Set timeval to end of the world */ - synctv.tv_sec = 0xffffffff; - synctv.tv_usec = 0xffffffff; - - while (1) { - r = poll(&fds, 1, POLL_TIMEOUT); - if (r > 0 && - (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { - SCLogWarning(SC_ERR_AFP_READ, "poll failed %02x", - fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL)); - return 0; - } else if (r > 0) { - if (AFPPeersListStarted() && synctv.tv_sec == (time_t) 0xffffffff) { - gettimeofday(&synctv, NULL); - } - if (ptv->flags & AFP_RING_MODE) { - r = AFPReadAndDiscardFromRing(ptv, &synctv); - } else { - r = AFPReadAndDiscard(ptv, &synctv); - } - SCLogDebug("Discarding on %s", ptv->tv->name); - switch (r) { - case 1: - SCLogInfo("Starting to read on %s", ptv->tv->name); - return 1; - case -1: - return r; - } - /* no packets */ - } else if (r == 0 && AFPPeersListStarted()) { - SCLogInfo("Starting to read on %s", ptv->tv->name); - return 1; - } else if (r < 0) { /* only exit on error */ - SCLogWarning(SC_ERR_AFP_READ, "poll failed with retval %d", r); - return 0; - } - } - return 1; -} - -/** - * \brief Try to reopen socket - * - * \retval 0 in case of success, negative if error occurs or a condition - * is not met. - */ -static int AFPTryReopen(AFPThreadVars *ptv) -{ - int afp_activate_r; - - ptv->down_count++; - - - /* Don't reconnect till we have packet that did not release data */ - if (SC_ATOMIC_GET(ptv->mpeer->sock_usage) != 0) { - return -1; - } - - afp_activate_r = AFPCreateSocket(ptv, ptv->iface, 0); - if (afp_activate_r != 0) { - if (ptv->down_count % AFP_DOWN_COUNTER_INTERVAL == 0) { - SCLogWarning(SC_ERR_AFP_CREATE, "Can not open iface '%s'", - ptv->iface); - } - return afp_activate_r; - } - - SCLogInfo("Interface '%s' is back", ptv->iface); - return 0; -} - -/** - * \brief Main AF_PACKET reading Loop function - */ -TmEcode ReceiveAFPLoop(ThreadVars *tv, void *data, void *slot) -{ - SCEnter(); - - AFPThreadVars *ptv = (AFPThreadVars *)data; - struct pollfd fds; - int r; - TmSlot *s = (TmSlot *)slot; - time_t last_dump = 0; - struct timeval current_time; - - ptv->slot = s->slot_next; - - if (ptv->afp_state == AFP_STATE_DOWN) { - /* Wait for our turn, threads before us must have opened the socket */ - while (AFPPeersListWaitTurn(ptv->mpeer)) { - usleep(1000); - if (suricata_ctl_flags != 0) { - break; - } - } - r = AFPCreateSocket(ptv, ptv->iface, 1); - if (r < 0) { - switch (-r) { - case AFP_FATAL_ERROR: - SCLogError(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket, fatal error"); - /* fatal is fatal, we want suri to exit */ - EngineKill(); - //tv->aof = THV_ENGINE_EXIT; - SCReturnInt(TM_ECODE_FAILED); - case AFP_RECOVERABLE_ERROR: - SCLogWarning(SC_ERR_AFP_CREATE, "Couldn't init AF_PACKET socket, retrying soon"); - } - } - AFPPeersListReachedInc(); - } - if (ptv->afp_state == AFP_STATE_UP) { - SCLogInfo("Thread %s using socket %d", tv->name, ptv->socket); - AFPSynchronizeStart(ptv); - } - - fds.fd = ptv->socket; - fds.events = POLLIN; - - while (1) { - /* Start by checking the state of our interface */ - if (unlikely(ptv->afp_state == AFP_STATE_DOWN)) { - int dbreak = 0; - - do { - usleep(AFP_RECONNECT_TIMEOUT); - if (suricata_ctl_flags != 0) { - dbreak = 1; - break; - } - r = AFPTryReopen(ptv); - fds.fd = ptv->socket; - } while (r < 0); - if (dbreak == 1) - break; - } - - /* make sure we have at least one packet in the packet pool, to prevent - * us from alloc'ing packets at line rate */ - PacketPoolWait(); - - r = poll(&fds, 1, POLL_TIMEOUT); - - if (suricata_ctl_flags != 0) { - break; - } - - if (r > 0 && - (fds.revents & (POLLHUP|POLLRDHUP|POLLERR|POLLNVAL))) { - if (fds.revents & (POLLHUP | POLLRDHUP)) { - AFPSwitchState(ptv, AFP_STATE_DOWN); - continue; - } else if (fds.revents & POLLERR) { - char c; - /* Do a recv to get errno */ - if (recv(ptv->socket, &c, sizeof c, MSG_PEEK) != -1) - continue; /* what, no error? */ - SCLogError(SC_ERR_AFP_READ, - "Error reading data from iface '%s': (%d" PRIu32 ") %s", - ptv->iface, errno, strerror(errno)); - AFPSwitchState(ptv, AFP_STATE_DOWN); - continue; - } else if (fds.revents & POLLNVAL) { - SCLogError(SC_ERR_AFP_READ, "Invalid polling request"); - AFPSwitchState(ptv, AFP_STATE_DOWN); - continue; - } - } else if (r > 0) { - if (ptv->flags & AFP_RING_MODE) { - r = AFPReadFromRing(ptv); - } else { - /* AFPRead will call TmThreadsSlotProcessPkt on read packets */ - r = AFPRead(ptv); - } - switch (r) { - case AFP_READ_FAILURE: - /* AFPRead in error: best to reset the socket */ - SCLogError(SC_ERR_AFP_READ, - "AFPRead error reading data from iface '%s': (%d" PRIu32 ") %s", - ptv->iface, errno, strerror(errno)); - AFPSwitchState(ptv, AFP_STATE_DOWN); - continue; - case AFP_FAILURE: - AFPSwitchState(ptv, AFP_STATE_DOWN); - SCReturnInt(TM_ECODE_FAILED); - break; - case AFP_READ_OK: - /* Trigger one dump of stats every second */ - TimeGet(¤t_time); - if (current_time.tv_sec != last_dump) { - AFPDumpCounters(ptv); - last_dump = current_time.tv_sec; - } - break; - case AFP_KERNEL_DROP: - AFPDumpCounters(ptv); - break; - } - } else if ((r < 0) && (errno != EINTR)) { - SCLogError(SC_ERR_AFP_READ, "Error reading data from iface '%s': (%d" PRIu32 ") %s", - ptv->iface, - errno, strerror(errno)); - AFPSwitchState(ptv, AFP_STATE_DOWN); - continue; - } - StatsSyncCountersIfSignalled(tv); - } - - AFPDumpCounters(ptv); - StatsSyncCountersIfSignalled(tv); - SCReturnInt(TM_ECODE_OK); -} - -static int AFPGetDevFlags(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { - SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - - return ifr.ifr_flags; -} - - -static int AFPGetIfnumByDev(int fd, const char *ifname, int verbose) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { - if (verbose) - SCLogError(SC_ERR_AFP_CREATE, "Unable to find iface %s: %s", - ifname, strerror(errno)); - return -1; - } - - return ifr.ifr_ifindex; -} - -static int AFPGetDevLinktype(int fd, const char *ifname) -{ - struct ifreq ifr; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - - if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) { - SCLogError(SC_ERR_AFP_CREATE, "Unable to find type for iface \"%s\": %s", - ifname, strerror(errno)); - return -1; - } - - switch (ifr.ifr_hwaddr.sa_family) { - case ARPHRD_LOOPBACK: - return LINKTYPE_ETHERNET; - case ARPHRD_PPP: - return LINKTYPE_RAW; - default: - return ifr.ifr_hwaddr.sa_family; - } -} - -static int AFPComputeRingParams(AFPThreadVars *ptv, int order) -{ - /* Compute structure: - Target is to store all pending packets - with a size equal to MTU + auxdata - And we keep a decent number of block - - To do so: - Compute frame_size (aligned to be able to fit in block - Check which block size we need. Blocksize is a 2^n * pagesize - We then need to get order, big enough to have - frame_size < block size - Find number of frame per block (divide) - Fill in packet_req - - Compute frame size: - described in packet_mmap.txt - dependant on snaplen (need to use a variable ?) -snaplen: MTU ? -tp_hdrlen determine_version in daq_afpacket -in V1: sizeof(struct tpacket_hdr); -in V2: val in getsockopt(instance->fd, SOL_PACKET, PACKET_HDRLEN, &val, &len) -frame size: TPACKET_ALIGN(snaplen + TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); - - */ - int tp_hdrlen = sizeof(struct tpacket_hdr); - int snaplen = default_packet_size; - - if (snaplen == 0) { - snaplen = GetIfaceMaxPacketSize(ptv->iface); - if (snaplen <= 0) { - SCLogWarning(SC_ERR_INVALID_VALUE, - "Unable to get MTU, setting snaplen to sane default of 1514"); - snaplen = 1514; - } - } - - ptv->req.tp_frame_size = TPACKET_ALIGN(snaplen +TPACKET_ALIGN(TPACKET_ALIGN(tp_hdrlen) + sizeof(struct sockaddr_ll) + ETH_HLEN) - ETH_HLEN); - ptv->req.tp_block_size = getpagesize() << order; - int frames_per_block = ptv->req.tp_block_size / ptv->req.tp_frame_size; - if (frames_per_block == 0) { - SCLogInfo("frame size to big"); - return -1; - } - ptv->req.tp_frame_nr = ptv->ring_size; - ptv->req.tp_block_nr = ptv->req.tp_frame_nr / frames_per_block + 1; - /* exact division */ - ptv->req.tp_frame_nr = ptv->req.tp_block_nr * frames_per_block; - SCLogInfo("AF_PACKET RX Ring params: block_size=%d block_nr=%d frame_size=%d frame_nr=%d", - ptv->req.tp_block_size, ptv->req.tp_block_nr, - ptv->req.tp_frame_size, ptv->req.tp_frame_nr); - return 1; -} - -static int AFPCreateSocket(AFPThreadVars *ptv, char *devname, int verbose) -{ - int r; - int ret = AFP_FATAL_ERROR; - struct packet_mreq sock_params; - struct sockaddr_ll bind_address; - int order; - unsigned int i; - int if_idx; - - /* open socket */ - ptv->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (ptv->socket == -1) { - SCLogError(SC_ERR_AFP_CREATE, "Couldn't create a AF_PACKET socket, error %s", strerror(errno)); - goto error; - } - if_idx = AFPGetIfnumByDev(ptv->socket, devname, verbose); - /* bind socket */ - memset(&bind_address, 0, sizeof(bind_address)); - bind_address.sll_family = AF_PACKET; - bind_address.sll_protocol = htons(ETH_P_ALL); - bind_address.sll_ifindex = if_idx; - if (bind_address.sll_ifindex == -1) { - if (verbose) - SCLogError(SC_ERR_AFP_CREATE, "Couldn't find iface %s", devname); - ret = AFP_RECOVERABLE_ERROR; - goto socket_err; - } - - if (ptv->promisc != 0) { - /* Force promiscuous mode */ - memset(&sock_params, 0, sizeof(sock_params)); - sock_params.mr_type = PACKET_MR_PROMISC; - sock_params.mr_ifindex = bind_address.sll_ifindex; - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP,(void *)&sock_params, sizeof(sock_params)); - if (r < 0) { - SCLogError(SC_ERR_AFP_CREATE, - "Couldn't switch iface %s to promiscuous, error %s", - devname, strerror(errno)); - goto frame_err; - } - } - - if (ptv->checksum_mode == CHECKSUM_VALIDATION_KERNEL) { - int val = 1; - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_AUXDATA, &val, - sizeof(val)) == -1 && errno != ENOPROTOOPT) { - SCLogWarning(SC_ERR_NO_AF_PACKET, - "'kernel' checksum mode not supported, failling back to full mode."); - ptv->checksum_mode = CHECKSUM_VALIDATION_ENABLE; - } - } - - /* set socket recv buffer size */ - if (ptv->buffer_size != 0) { - /* - * Set the socket buffer size to the specified value. - */ - SCLogInfo("Setting AF_PACKET socket buffer to %d", ptv->buffer_size); - if (setsockopt(ptv->socket, SOL_SOCKET, SO_RCVBUF, - &ptv->buffer_size, - sizeof(ptv->buffer_size)) == -1) { - SCLogError(SC_ERR_AFP_CREATE, - "Couldn't set buffer size to %d on iface %s, error %s", - ptv->buffer_size, devname, strerror(errno)); - goto frame_err; - } - } - - r = bind(ptv->socket, (struct sockaddr *)&bind_address, sizeof(bind_address)); - if (r < 0) { - if (verbose) { - if (errno == ENETDOWN) { - SCLogError(SC_ERR_AFP_CREATE, - "Couldn't bind AF_PACKET socket, iface %s is down", - devname); - } else { - SCLogError(SC_ERR_AFP_CREATE, - "Couldn't bind AF_PACKET socket to iface %s, error %s", - devname, strerror(errno)); - } - } - ret = AFP_RECOVERABLE_ERROR; - goto frame_err; - } - -#ifdef HAVE_PACKET_FANOUT - /* add binded socket to fanout group */ - if (ptv->threads > 1) { - uint32_t option = 0; - uint16_t mode = ptv->cluster_type; - uint16_t id = ptv->cluster_id; - option = (mode << 16) | (id & 0xffff); - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_FANOUT,(void *)&option, sizeof(option)); - if (r < 0) { - SCLogError(SC_ERR_AFP_CREATE, - "Coudn't set fanout mode, error %s", - strerror(errno)); - goto frame_err; - } - } -#endif - - int if_flags = AFPGetDevFlags(ptv->socket, ptv->iface); - if (if_flags == -1) { - if (verbose) { - SCLogError(SC_ERR_AFP_READ, - "Can not acces to interface '%s'", - ptv->iface); - } - ret = AFP_RECOVERABLE_ERROR; - goto frame_err; - } - if ((if_flags & IFF_UP) == 0) { - if (verbose) { - SCLogError(SC_ERR_AFP_READ, - "Interface '%s' is down", - ptv->iface); - } - ret = AFP_RECOVERABLE_ERROR; - goto frame_err; - } - - if (ptv->flags & AFP_RING_MODE) { - int val = TPACKET_V2; - unsigned int len = sizeof(val); - if (getsockopt(ptv->socket, SOL_PACKET, PACKET_HDRLEN, &val, &len) < 0) { - if (errno == ENOPROTOOPT) { - SCLogError(SC_ERR_AFP_CREATE, - "Too old kernel giving up (need 2.6.27 at least)"); - } - SCLogError(SC_ERR_AFP_CREATE, "Error when retrieving packet header len"); - goto socket_err; - } - ptv->tp_hdrlen = val; - - val = TPACKET_V2; - if (setsockopt(ptv->socket, SOL_PACKET, PACKET_VERSION, &val, - sizeof(val)) < 0) { - SCLogError(SC_ERR_AFP_CREATE, - "Can't activate TPACKET_V2 on packet socket: %s", - strerror(errno)); - goto socket_err; - } - - /* Allocate RX ring */ -#define DEFAULT_ORDER 3 - for (order = DEFAULT_ORDER; order >= 0; order--) { - if (AFPComputeRingParams(ptv, order) != 1) { - SCLogInfo("Ring parameter are incorrect. Please correct the devel"); - } - - r = setsockopt(ptv->socket, SOL_PACKET, PACKET_RX_RING, (void *) &ptv->req, sizeof(ptv->req)); - if (r < 0) { - if (errno == ENOMEM) { - SCLogInfo("Memory issue with ring parameters. Retrying."); - continue; - } - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s: (%d) %s", - devname, - errno, - strerror(errno)); - goto socket_err; - } else { - break; - } - } - - if (order < 0) { - SCLogError(SC_ERR_MEM_ALLOC, - "Unable to allocate RX Ring for iface %s (order 0 failed)", - devname); - goto socket_err; - } - - /* Allocate the Ring */ - ptv->ring_buflen = ptv->req.tp_block_nr * ptv->req.tp_block_size; - ptv->ring_buf = mmap(0, ptv->ring_buflen, PROT_READ|PROT_WRITE, - MAP_SHARED, ptv->socket, 0); - if (ptv->ring_buf == MAP_FAILED) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to mmap"); - goto socket_err; - } - /* allocate a ring for each frame header pointer*/ - ptv->frame_buf = SCMalloc(ptv->req.tp_frame_nr * sizeof (union thdr *)); - if (ptv->frame_buf == NULL) { - SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate frame buf"); - goto mmap_err; - } - memset(ptv->frame_buf, 0, ptv->req.tp_frame_nr * sizeof (union thdr *)); - /* fill the header ring with proper frame ptr*/ - ptv->frame_offset = 0; - for (i = 0; i < ptv->req.tp_block_nr; ++i) { - void *base = &ptv->ring_buf[i * ptv->req.tp_block_size]; - unsigned int j; - for (j = 0; j < ptv->req.tp_block_size / ptv->req.tp_frame_size; ++j, ++ptv->frame_offset) { - (((union thdr **)ptv->frame_buf)[ptv->frame_offset]) = base; - base += ptv->req.tp_frame_size; - } - } - ptv->frame_offset = 0; - } - - SCLogInfo("Using interface '%s' via socket %d", (char *)devname, ptv->socket); - - - ptv->datalink = AFPGetDevLinktype(ptv->socket, ptv->iface); - switch (ptv->datalink) { - case ARPHRD_PPP: - case ARPHRD_ATM: - ptv->cooked = 1; - break; - } - - TmEcode rc; - rc = AFPSetBPFFilter(ptv); - if (rc == TM_ECODE_FAILED) { - SCLogError(SC_ERR_AFP_CREATE, "Set AF_PACKET bpf filter \"%s\" failed.", ptv->bpf_filter); - goto frame_err; - } - - /* Init is ok */ - AFPSwitchState(ptv, AFP_STATE_UP); - return 0; - -frame_err: - if (ptv->frame_buf) - SCFree(ptv->frame_buf); -mmap_err: - /* Packet mmap does the cleaning when socket is closed */ -socket_err: - close(ptv->socket); - ptv->socket = -1; -error: - return -ret; -} - -TmEcode AFPSetBPFFilter(AFPThreadVars *ptv) -{ - struct bpf_program filter; - struct sock_fprog fcode; - int rc; - - if (!ptv->bpf_filter) - return TM_ECODE_OK; - - SCMutexLock(&afpacket_bpf_set_filter_lock); - - SCLogInfo("Using BPF '%s' on iface '%s'", - ptv->bpf_filter, - ptv->iface); - if (pcap_compile_nopcap(default_packet_size, /* snaplen_arg */ - ptv->datalink, /* linktype_arg */ - &filter, /* program */ - ptv->bpf_filter, /* const char *buf */ - 0, /* optimize */ - 0 /* mask */ - ) == -1) { - SCLogError(SC_ERR_AFP_CREATE, "Filter compilation failed."); - SCMutexUnlock(&afpacket_bpf_set_filter_lock); - return TM_ECODE_FAILED; - } - SCMutexUnlock(&afpacket_bpf_set_filter_lock); - - if (filter.bf_insns == NULL) { - SCLogError(SC_ERR_AFP_CREATE, "Filter badly setup."); - return TM_ECODE_FAILED; - } - - fcode.len = filter.bf_len; - fcode.filter = (struct sock_filter*)filter.bf_insns; - - rc = setsockopt(ptv->socket, SOL_SOCKET, SO_ATTACH_FILTER, &fcode, sizeof(fcode)); - - if(rc == -1) { - SCLogError(SC_ERR_AFP_CREATE, "Failed to attach filter: %s", strerror(errno)); - return TM_ECODE_FAILED; - } - - return TM_ECODE_OK; -} - - -/** - * \brief Init function for ReceiveAFP. - * - * \param tv pointer to ThreadVars - * \param initdata pointer to the interface passed from the user - * \param data pointer gets populated with AFPThreadVars - * - * \todo Create a general AFP setup function. - */ -TmEcode ReceiveAFPThreadInit(ThreadVars *tv, void *initdata, void **data) -{ - SCEnter(); - AFPIfaceConfig *afpconfig = initdata; - - if (initdata == NULL) { - SCLogError(SC_ERR_INVALID_ARGUMENT, "initdata == NULL"); - SCReturnInt(TM_ECODE_FAILED); - } - - AFPThreadVars *ptv = SCMalloc(sizeof(AFPThreadVars)); - if (unlikely(ptv == NULL)) { - afpconfig->DerefFunc(afpconfig); - SCReturnInt(TM_ECODE_FAILED); - } - memset(ptv, 0, sizeof(AFPThreadVars)); - - ptv->tv = tv; - ptv->cooked = 0; - - strlcpy(ptv->iface, afpconfig->iface, AFP_IFACE_NAME_LENGTH); - ptv->iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; - - ptv->livedev = LiveGetDevice(ptv->iface); - if (ptv->livedev == NULL) { - SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device"); - SCFree(ptv); - SCReturnInt(TM_ECODE_FAILED); - } - - ptv->buffer_size = afpconfig->buffer_size; - ptv->ring_size = afpconfig->ring_size; - - ptv->promisc = afpconfig->promisc; - ptv->checksum_mode = afpconfig->checksum_mode; - ptv->bpf_filter = NULL; - - ptv->threads = 1; -#ifdef HAVE_PACKET_FANOUT - ptv->cluster_type = PACKET_FANOUT_LB; - ptv->cluster_id = 1; - /* We only set cluster info if the number of reader threads is greater than 1 */ - if (afpconfig->threads > 1) { - ptv->cluster_id = afpconfig->cluster_id; - ptv->cluster_type = afpconfig->cluster_type; - ptv->threads = afpconfig->threads; - } -#endif - ptv->flags = afpconfig->flags; - - if (afpconfig->bpf_filter) { - ptv->bpf_filter = afpconfig->bpf_filter; - } - -#ifdef PACKET_STATISTICS - ptv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets", - ptv->tv); - ptv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops", - ptv->tv); -#endif - - char *active_runmode = RunmodeGetActive(); - - if (active_runmode && !strcmp("workers", active_runmode)) { - ptv->flags |= AFP_ZERO_COPY; - SCLogInfo("Enabling zero copy mode"); - } else { - /* If we are using copy mode we need a lock */ - ptv->flags |= AFP_SOCK_PROTECT; - } - - /* If we are in RING mode, then we can use ZERO copy - * by using the data release mechanism */ - if (ptv->flags & AFP_RING_MODE) { - ptv->flags |= AFP_ZERO_COPY; - SCLogInfo("Enabling zero copy mode by using data release call"); - } - - ptv->copy_mode = afpconfig->copy_mode; - if (ptv->copy_mode != AFP_COPY_MODE_NONE) { - strlcpy(ptv->out_iface, afpconfig->out_iface, AFP_IFACE_NAME_LENGTH); - ptv->out_iface[AFP_IFACE_NAME_LENGTH - 1]= '\0'; - /* Warn about BPF filter consequence */ - if (ptv->bpf_filter) { - SCLogWarning(SC_WARN_UNCOMMON, "Enabling a BPF filter in IPS mode result" - " in dropping all non matching packets."); - } - } - - - if (AFPPeersListAdd(ptv) == TM_ECODE_FAILED) { - SCFree(ptv); - afpconfig->DerefFunc(afpconfig); - SCReturnInt(TM_ECODE_FAILED); - } - -#define T_DATA_SIZE 70000 - ptv->data = SCMalloc(T_DATA_SIZE); - if (ptv->data == NULL) { - afpconfig->DerefFunc(afpconfig); - SCFree(ptv); - SCReturnInt(TM_ECODE_FAILED); - } - ptv->datalen = T_DATA_SIZE; -#undef T_DATA_SIZE - - *data = (void *)ptv; - - afpconfig->DerefFunc(afpconfig); - - /* A bit strange to have this here but we only have vlan information - * during reading so we need to know if we want to keep vlan during - * the capture phase */ - int vlanbool = 0; - if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) { - ptv->vlan_disabled = 1; - } - - /* If kernel is older than 3.0, VLAN is not stripped so we don't - * get the info from packet extended header but we will use a standard - * parsing of packet data (See Linux commit bcc6d47903612c3861201cc3a866fb604f26b8b2) */ - if (! SCKernelVersionIsAtLeast(3, 0)) { - ptv->vlan_disabled = 1; - } - - 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 AFPThreadVars for ptv - */ -void ReceiveAFPThreadExitStats(ThreadVars *tv, void *data) -{ - SCEnter(); - AFPThreadVars *ptv = (AFPThreadVars *)data; - -#ifdef PACKET_STATISTICS - AFPDumpCounters(ptv); - SCLogInfo("(%s) Kernel: Packets %" PRIu64 ", dropped %" PRIu64 "", - tv->name, - StatsGetLocalCounterValue(tv, ptv->capture_kernel_packets), - StatsGetLocalCounterValue(tv, ptv->capture_kernel_drops)); -#endif - - SCLogInfo("(%s) Packets %" PRIu64 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes); -} - -/** - * \brief DeInit function closes af packet socket at exit. - * \param tv pointer to ThreadVars - * \param data pointer that gets cast into AFPThreadVars for ptv - */ -TmEcode ReceiveAFPThreadDeinit(ThreadVars *tv, void *data) -{ - AFPThreadVars *ptv = (AFPThreadVars *)data; - - AFPSwitchState(ptv, AFP_STATE_DOWN); - - if (ptv->data != NULL) { - SCFree(ptv->data); - ptv->data = NULL; - } - ptv->datalen = 0; - - ptv->bpf_filter = NULL; - - SCReturnInt(TM_ECODE_OK); -} - -/** - * \brief This function passes off to link type decoders. - * - * DecodeAFP reads packets from the PacketQueue and passes - * them off to the proper link type decoder. - * - * \param t pointer to ThreadVars - * \param p pointer to the current packet - * \param data pointer that gets cast into AFPThreadVars for ptv - * \param pq pointer to the current PacketQueue - */ -TmEcode DecodeAFP(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq) -{ - SCEnter(); - DecodeThreadVars *dtv = (DecodeThreadVars *)data; - - /* XXX HACK: flow timeout can call us for injected pseudo packets - * see bug: https://redmine.openinfosecfoundation.org/issues/1107 */ - if (p->flags & PKT_PSEUDO_STREAM_END) - return TM_ECODE_OK; - - /* update counters */ - DecodeUpdatePacketCounters(tv, dtv, p); - - /* If suri has set vlan during reading, we increase vlan counter */ - if (p->vlan_idx) { - StatsIncr(tv, dtv->counter_vlan); - } - - /* call the decoder */ - switch(p->datalink) { - case LINKTYPE_LINUX_SLL: - DecodeSll(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - break; - case LINKTYPE_ETHERNET: - DecodeEthernet(tv, dtv, p,GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - break; - case LINKTYPE_PPP: - DecodePPP(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - break; - case LINKTYPE_RAW: - DecodeRaw(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq); - break; - default: - SCLogError(SC_ERR_DATALINK_UNIMPLEMENTED, "Error: datalink type %" PRId32 " not yet supported in module DecodeAFP", p->datalink); - break; - } - - PacketDecodeFinalize(tv, dtv, p); - - SCReturnInt(TM_ECODE_OK); -} - -TmEcode DecodeAFPThreadInit(ThreadVars *tv, void *initdata, void **data) -{ - SCEnter(); - DecodeThreadVars *dtv = NULL; - - dtv = DecodeThreadVarsAlloc(tv); - - if (dtv == NULL) - SCReturnInt(TM_ECODE_FAILED); - - DecodeRegisterPerfCounters(dtv, tv); - - *data = (void *)dtv; - -#ifdef __SC_CUDA_SUPPORT__ - if (CudaThreadVarsInit(&dtv->cuda_vars) < 0) - SCReturnInt(TM_ECODE_FAILED); -#endif - - SCReturnInt(TM_ECODE_OK); -} - -TmEcode DecodeAFPThreadDeinit(ThreadVars *tv, void *data) -{ - if (data != NULL) - DecodeThreadVarsFree(tv, data); - SCReturnInt(TM_ECODE_OK); -} - -#endif /* HAVE_AF_PACKET */ -/* eof */ -/** - * @} - */ -- cgit 1.2.3-korg