Intial IPFW support FreeBSD and OSX

remotes/origin/master-1.0.x
Nick Rogness 15 years ago committed by Victor Julien
parent fbf03a927d
commit 2b7b78f1bf

@ -364,6 +364,15 @@ AC_INIT(configure.in)
fi
fi
#enable support for IPFW
AC_ARG_ENABLE(ipfw,
[ --enable-ipfw Enable FreeBSD IPFW support for inline IDP],
[ enable_ipfw=yes
])
if test "$enable_ipfw" = "yes"; then
CFLAGS="$CFLAGS -DIPFW"
fi
#libnet
AC_ARG_WITH(libnet_includes,
[ --with-libnet-includes=DIR libnet include directory],

@ -256,8 +256,20 @@ For FreeBSD 8 Users
sysctl net.bpf.zerocopy_enable=1
#if you would like to build suricata on FreeBSD with IPS capabilities with IPFW via --enable-ipfw.
You must do the following to enable ipfw and divert socket support before starting the engine
with -d.
#edit /etc/rc.conf and add or modify the following lines
firewall_enable="YES"
firewall_type="open"
#edit /boot/loader.conf and add or modify the following lines
ipfw_load="YES"
ipfw_nat_load="YES"
ipdivert_load="YES"
dummynet_load="YES"
libalias_load="YES"
Basic Installation

@ -11,6 +11,7 @@ source-nfq.c source-nfq.h \
source-pcap.c source-pcap.h \
source-pcap-file.c source-pcap-file.h \
source-pfring.c source-pfring.h \
source-ipfw.c source-ipfw.h \
decode.c decode.h \
decode-ethernet.c decode-ethernet.h \
decode-sll.c decode-sll.h \

@ -109,7 +109,7 @@ int RejectSendLibnet11L3IPv4TCP(ThreadVars *tv, Packet *p, void *data, int dir)
lpacket.sp, /* source port */
lpacket.dp, /* dst port */
lpacket.seq, /* seq number */
lpacket.ack, /* ack number */
lpacket.ack+1, /* ack number */
TH_RST|TH_ACK, /* flags */
lpacket.window, /* window size */
0, /* checksum */

@ -1411,6 +1411,142 @@ int RunModeIdsPfring3(DetectEngineCtx *de_ctx, char *iface) {
return 0;
}
int RunModeIpsIPFW(DetectEngineCtx *de_ctx) {
TimeModeSetLive();
/* create the threads */
ThreadVars *tv_receiveipfw = TmThreadCreatePacketHandler("ReceiveIPFW","packetpool","packetpool","pickup-queue","simple","1slot_noinout");
if (tv_receiveipfw == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
exit(EXIT_FAILURE);
}
TmModule *tm_module = TmModuleGetByName("ReceiveIPFW");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName failed for ReceiveIPFW\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_receiveipfw,tm_module,NULL);
if (TmThreadSpawn(tv_receiveipfw) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_decode1 = TmThreadCreatePacketHandler("Decode1","pickup-queue","simple","decode-queue1","simple","1slot");
if (tv_decode1 == NULL) {
printf("ERROR: TmThreadsCreate failed for Decode1\n");
exit(EXIT_FAILURE);
}
tm_module = TmModuleGetByName("DecodeIPFW");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName DecodeIPFW failed\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_decode1,tm_module,NULL);
if (TmThreadSpawn(tv_decode1) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_stream1 = TmThreadCreatePacketHandler("Stream1","decode-queue1","simple","stream-queue1","simple","1slot");
if (tv_stream1 == NULL) {
printf("ERROR: TmThreadsCreate failed for Stream1\n");
exit(EXIT_FAILURE);
}
tm_module = TmModuleGetByName("StreamTcp");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName StreamTcp failed\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_stream1,tm_module,NULL);
if (TmThreadSpawn(tv_stream1) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_detect1 = TmThreadCreatePacketHandler("Detect1","stream-queue1","simple","verdict-queue","simple","1slot");
if (tv_detect1 == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
exit(EXIT_FAILURE);
}
tm_module = TmModuleGetByName("Detect");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName Detect failed\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_detect1,tm_module,(void *)de_ctx);
if (TmThreadSpawn(tv_detect1) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_detect2 = TmThreadCreatePacketHandler("Detect2","stream-queue1","simple","verdict-queue","simple","1slot");
if (tv_detect2 == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
exit(EXIT_FAILURE);
}
tm_module = TmModuleGetByName("Detect");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName Detect failed\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_detect2,tm_module,(void *)de_ctx);
if (TmThreadSpawn(tv_detect2) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_verdict = TmThreadCreatePacketHandler("Verdict","verdict-queue","simple","respond-queue","simple","1slot");
if (tv_verdict == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
exit(EXIT_FAILURE);
}
tm_module = TmModuleGetByName("VerdictIPFW");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName VerdictIPFW failed\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_verdict,tm_module,NULL);
if (TmThreadSpawn(tv_verdict) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_rreject = TmThreadCreatePacketHandler("RespondReject","respond-queue","simple","alert-queue1","simple","1slot");
if (tv_rreject == NULL) {
printf("ERROR: TmThreadsCreate failed\n");
exit(EXIT_FAILURE);
}
tm_module = TmModuleGetByName("RespondReject");
if (tm_module == NULL) {
printf("ERROR: TmModuleGetByName for RespondReject failed\n");
exit(EXIT_FAILURE);
}
Tm1SlotSetFunc(tv_rreject,tm_module,NULL);
if (TmThreadSpawn(tv_rreject) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
ThreadVars *tv_outputs = TmThreadCreatePacketHandler("Outputs",
"alert-queue1", "simple", "packetpool", "packetpool", "varslot");
SetupOutputs(tv_outputs);
if (TmThreadSpawn(tv_outputs) != TM_ECODE_OK) {
printf("ERROR: TmThreadSpawn failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
/** RunmodeIdsPfring4 simple 4 pfring, decode, stream, and detect threads */
int RunModeIdsPfring4(DetectEngineCtx *de_ctx, char *iface) {
TimeModeSetLive();

@ -17,6 +17,7 @@ int RunModeIdsPfring2(DetectEngineCtx *, char *);
int RunModeIdsPfring3(DetectEngineCtx *, char *);
int RunModeIdsPfring4(DetectEngineCtx *, char *);
int RunModeIpsIPFW(DetectEngineCtx *);
void RunModeShutDown(void);
#endif /* __RUNMODES_H__ */

@ -0,0 +1,631 @@
/* Copyright (c) 2009 Open Information Security Foundation */
/** \file
* \author Nick Rogness <nick@rogness.net>
*/
#include <poll.h>
#include <signal.h>
#include "suricata-common.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 "source-ipfw.h"
#include "util-debug.h"
#include "conf.h"
#define IPFW_ACCEPT 0
#define IPFW_DROP 1
#define IPFW_SOCKET_POLL_MSEC 300
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif
#ifndef IPFW
/* Handle the case if --enable-ipfw was not used
*
*/
TmEcode NoIPFWSupportExit(ThreadVars *, void *, void **);
void TmModuleReceiveIPFWRegister (void) {
tmm_modules[TMM_RECEIVEIPFW].name = "ReceiveIPFW";
tmm_modules[TMM_RECEIVEIPFW].ThreadInit = NoIPFWSupportExit;
tmm_modules[TMM_RECEIVEIPFW].Func = NULL;
tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = NULL;
tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = NULL;
tmm_modules[TMM_RECEIVEIPFW].RegisterTests = NULL;
}
void TmModuleVerdictIPFWRegister (void) {
tmm_modules[TMM_VERDICTIPFW].name = "VerdictIPFW";
tmm_modules[TMM_VERDICTIPFW].ThreadInit = NoIPFWSupportExit;
tmm_modules[TMM_VERDICTIPFW].Func = NULL;
tmm_modules[TMM_VERDICTIPFW].ThreadExitPrintStats = NULL;
tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = NULL;
tmm_modules[TMM_VERDICTIPFW].RegisterTests = NULL;
}
void TmModuleDecodeIPFWRegister (void) {
tmm_modules[TMM_DECODEIPFW].name = "DecodeIPFW";
tmm_modules[TMM_DECODEIPFW].ThreadInit = NoIPFWSupportExit;
tmm_modules[TMM_DECODEIPFW].Func = NULL;
tmm_modules[TMM_DECODEIPFW].ThreadExitPrintStats = NULL;
tmm_modules[TMM_DECODEIPFW].ThreadDeinit = NULL;
tmm_modules[TMM_DECODEIPFW].RegisterTests = NULL;
}
TmEcode NoIPFWSupportExit(ThreadVars *tv, void *initdata, void **data) {
SCLogError(SC_ERR_IPFW_NOSUPPORT,"Error creating thread %s: you do not have support for ipfw "
"enabled please recompile with --enable-ipfw", tv->name);
exit(EXIT_FAILURE);
}
#else /* We have IPFW compiled in */
/**
* \brief Structure to hold thread specific variables.
*/
typedef struct IPFWThreadVars_
{
/* data link type for the thread, probably not needed */
int datalink;
/* counters */
uint32_t pkts;
uint64_t bytes;
uint32_t errs;
uint32_t accepted;
uint32_t dropped;
} IPFWThreadVars;
/* Global socket handler for the divert socket */
struct sockaddr_in ipfw_sin;
socklen_t ipfw_sinlen;
int ipfw_sock;
static SCMutex ipfw_socket_lock;
/* IPFW Prototypes */
TmEcode ReceiveIPFWThreadInit(ThreadVars *, void *, void **);
TmEcode ReceiveIPFW(ThreadVars *, Packet *, void *, PacketQueue *);
void ReceiveIPFWThreadExitStats(ThreadVars *, void *);
TmEcode ReceiveIPFWThreadDeinit(ThreadVars *, void *);
TmEcode IPFWSetVerdict(ThreadVars *, IPFWThreadVars *, Packet *);
TmEcode VerdictIPFW(ThreadVars *, Packet *, void *, PacketQueue *);
TmEcode VerdictIPFWThreadInit(ThreadVars *, void *, void **);
void VerdictIPFWThreadExitStats(ThreadVars *, void *);
TmEcode VerdictIPFWThreadDeinit(ThreadVars *, void *);
TmEcode DecodeIPFWThreadInit(ThreadVars *, void *, void **);
TmEcode DecodeIPFW(ThreadVars *, Packet *, void *, PacketQueue *);
/**
* \brief Registration Function for RecieveIPFW.
* \todo Unit tests are needed for this module.
*/
void TmModuleReceiveIPFWRegister (void) {
tmm_modules[TMM_RECEIVEIPFW].name = "ReceiveIPFW";
tmm_modules[TMM_RECEIVEIPFW].ThreadInit = ReceiveIPFWThreadInit;
tmm_modules[TMM_RECEIVEIPFW].Func = ReceiveIPFW;
tmm_modules[TMM_RECEIVEIPFW].ThreadExitPrintStats = ReceiveIPFWThreadExitStats;
tmm_modules[TMM_RECEIVEIPFW].ThreadDeinit = ReceiveIPFWThreadDeinit;
tmm_modules[TMM_RECEIVEIPFW].RegisterTests = NULL;
}
/**
* \brief Registration Function for VerdictIPFW.
* \todo Unit tests are needed for this module.
*/
void TmModuleVerdictIPFWRegister (void) {
tmm_modules[TMM_VERDICTIPFW].name = "VerdictIPFW";
tmm_modules[TMM_VERDICTIPFW].ThreadInit = VerdictIPFWThreadInit;
tmm_modules[TMM_VERDICTIPFW].Func = VerdictIPFW;
tmm_modules[TMM_VERDICTIPFW].ThreadExitPrintStats = VerdictIPFWThreadExitStats;
tmm_modules[TMM_VERDICTIPFW].ThreadDeinit = VerdictIPFWThreadDeinit;
tmm_modules[TMM_VERDICTIPFW].RegisterTests = NULL;
}
/**
* \brief Registration Function for DecodeIPFW.
* \todo Unit tests are needed for this module.
*/
void TmModuleDecodeIPFWRegister (void) {
tmm_modules[TMM_DECODEIPFW].name = "DecodeIPFW";
tmm_modules[TMM_DECODEIPFW].ThreadInit = DecodeIPFWThreadInit;
tmm_modules[TMM_DECODEIPFW].Func = DecodeIPFW;
tmm_modules[TMM_DECODEIPFW].ThreadExitPrintStats = NULL;
tmm_modules[TMM_DECODEIPFW].ThreadDeinit = NULL;
tmm_modules[TMM_DECODEIPFW].RegisterTests = NULL;
}
/**
* \brief Recieves packets from an interface via ipfw divert socket.
* \todo Unit tests are needed for this module.
*
* This function recieves packets from an ipfw divert socket and passes
* the packet on to the queue
*
* \param tv pointer to ThreadVars
* \param p pointer to Packet
* \param data pointer that gets cast into IPFWThreadVars for ptv
* \param pq pointer to the PacketQueue (not used here but part of the api)
* \retval TM_ECODE_FAILED on failure and TM_ECODE_OK on success
*/
TmEcode ReceiveIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) {
IPFWThreadVars *ptv = (IPFWThreadVars *)data;
char pkt[IP_MAXPACKET];
int pktlen=0;
int r = 0;
struct pollfd IPFWpoll;
struct timeval IPFWts;
SCEnter();
//printf("Entering RecieveIPFW\n");
IPFWpoll.fd=ipfw_sock;
IPFWpoll.events= POLLRDNORM;
/* Read packets from divert socket */
while (r == 0) {
/* Did we receive a signal to shutdown */
if ( TmThreadsCheckFlag(tv, THV_KILL) || TmThreadsCheckFlag(tv, THV_PAUSE)) {
SCLogInfo("Received ThreadShutdown: IPFW divert socket polling interrupted");
SCReturnInt(TM_ECODE_OK);
}
/* Poll the socket for status */
if ( (poll(&IPFWpoll,1,IPFW_SOCKET_POLL_MSEC)) > 0) {
if ( IPFWpoll.revents & (POLLRDNORM | POLLERR) )
r++;
}
} /* end while */
SCMutexLock(&ipfw_socket_lock);
if ((pktlen = recvfrom(ipfw_sock, pkt, sizeof(pkt), 0,(struct sockaddr *)&ipfw_sin, &ipfw_sinlen)) == -1) {
/* We received an error on socket read */
if (errno == EINTR || errno == EWOULDBLOCK) {
/* Nothing for us to process */
SCMutexUnlock(&ipfw_socket_lock);
SCReturnInt(TM_ECODE_OK);
} else {
SCLogWarning(SC_WARN_IPFW_RECV,"Read from IPFW divert socket failed: %s",strerror(errno));
SCMutexUnlock(&ipfw_socket_lock);
SCReturnInt(TM_ECODE_FAILED);
}
} else {
/* We have a packet to process */
memset (&IPFWts, 0, sizeof(struct timeval));
gettimeofday(&IPFWts, NULL);
r++;
}
SCMutexUnlock(&ipfw_socket_lock);
SCLogDebug("Received Packet Len: %d",pktlen);
/* Is the packet queue full, wait if so */
SCMutexLock(&mutex_pending);
if (pending > MAX_PENDING) {
pthread_cond_wait(&cond_pending, &mutex_pending);
}
SCMutexUnlock(&mutex_pending);
/* Setup packet */
p = tv->tmqh_in(tv);
p->ts.tv_sec = IPFWts.tv_sec;
p->ts.tv_usec = IPFWts.tv_usec;
ptv->pkts++;
ptv->bytes += pktlen;
p->datalink = ptv->datalink;
p->pktlen = pktlen;
memcpy(p->pkt, pkt, p->pktlen);
SCLogDebug("Packet info: p->pktlen: %" PRIu32 " (pkt %02x, p->pkt %02x)", p->pktlen, *pkt, *p->pkt);
/* pass on... */
tv->tmqh_out(tv, p);
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief Init function for RecieveIPFW.
*
* This is a setup function for recieving packets
* via ipfw divert, binds a socket, and prepares to
* to read from it.
*
* \param tv pointer to ThreadVars
* \param initdata pointer to the divert port passed from the user
* \param data pointer gets populated with IPFWThreadVars
*
*/
TmEcode ReceiveIPFWThreadInit(ThreadVars *tv, void *initdata, void **data) {
struct timeval timev;
uint16_t divert_port=0;
char *tmpdivertport;
sigset_t sigs;
sigfillset(&sigs);
pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
SCEnter();
/* divert socket port to listen/send on */
if ( (ConfGet("ipfw-divert-port", &tmpdivertport)) != 1 ) {
SCLogError(SC_ERR_IPFW_NOPORT,"Please supply an IPFW divert port");
SCReturnInt(TM_ECODE_FAILED);
} else {
if (atoi(tmpdivertport) > 0 && atoi(tmpdivertport) <= 65535) {
divert_port = (uint16_t)atoi(tmpdivertport);
SCLogInfo("Using IPFW divert port %u",divert_port);
} else {
SCLogError(SC_ERR_IPFW_BIND,"Divert port: %s is invalid",tmpdivertport);
SCReturnInt(TM_ECODE_FAILED);
}
}
/* Setup Threadvars */
IPFWThreadVars *ptv = malloc(sizeof(IPFWThreadVars));
if (ptv == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,"Error Allocating memory for IPFW Receive PTV: %s",strerror(errno));
SCReturnInt(TM_ECODE_FAILED);
}
memset(ptv, 0, sizeof(IPFWThreadVars));
SCMutexInit(&ipfw_socket_lock, NULL);
/* We need a divert socket to play with */
if ((ipfw_sock = socket(PF_INET, SOCK_RAW, IPPROTO_DIVERT)) == -1) {
SCLogError(SC_ERR_IPFW_SOCK,"Can't create divert socket: %s", strerror(errno));
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. */
timev.tv_sec = 1;
timev.tv_usec = 0;
if(setsockopt(ipfw_sock, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)) == -1) {
SCLogWarning(SC_WARN_IPFW_SETSOCKOPT,"Can't set IPFW divert socket timeout: %s", strerror(errno));
SCReturnInt(TM_ECODE_FAILED);
}
ipfw_sinlen=sizeof(ipfw_sin);
memset(&ipfw_sin, 0, ipfw_sinlen);
ipfw_sin.sin_family = PF_INET;
ipfw_sin.sin_addr.s_addr = INADDR_ANY;
ipfw_sin.sin_port = htons(divert_port);
/* Bind that SOB */
if (bind(ipfw_sock, (struct sockaddr *)&ipfw_sin, ipfw_sinlen) == -1) {
SCLogError(SC_ERR_IPFW_BIND,"Can't bind divert socket on port %d: %s",divert_port,strerror(errno));
SCReturnInt(TM_ECODE_FAILED);
}
ptv->datalink = DLT_RAW;
*data = (void *)ptv;
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function prints stats to the screen at exit.
* \todo Unit tests are needed for this module.
* \param tv pointer to ThreadVars
* \param data pointer that gets cast into IPFWThreadVars for ptv
*/
void ReceiveIPFWThreadExitStats(ThreadVars *tv, void *data) {
IPFWThreadVars *ptv = (IPFWThreadVars *)data;
SCEnter();
SCLogInfo("(%s) Packets %" PRIu32 ", bytes %" PRIu64 "", tv->name, ptv->pkts, ptv->bytes);
SCReturn;
}
/**
* \brief DeInit function closes divert socket at exit.
* \todo Unit tests are needed for this module.
* \param tv pointer to ThreadVars
* \param data pointer that gets cast into IPFWThreadVars for ptv
*/
TmEcode ReceiveIPFWThreadDeinit(ThreadVars *tv, void *data) {
IPFWThreadVars *ptv = (IPFWThreadVars *)data;
SCEnter();
/* Attempt to shut the socket down...close instead? */
if ( (shutdown(ipfw_sock,SHUT_RD)) < 0 ) {
SCLogWarning(SC_WARN_IPFW_UNBIND,"Unable to disable ipfw socket: %s",strerror(errno));
SCReturnInt(TM_ECODE_FAILED);
}
data = (void *)ptv;
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function passes off to link type decoders.
* \todo Unit tests are needed for this module.
*
* DecodeIPFW reads packets from the PacketQueue and passes
* them off to the proper link type decoder.
*
* \param tv pointer to ThreadVars
* \param p pointer to the current packet
* \param data pointer that gets cast into IPFWThreadVars for ptv
* \param pq pointer to the PacketQueue
*/
TmEcode DecodeIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq)
{
IPV4Hdr *ip4h = (IPV4Hdr *)p->pkt;
IPV6Hdr *ip6h = (IPV6Hdr *)p->pkt;
DecodeThreadVars *dtv = (DecodeThreadVars *)data;
SCEnter();
/* update counters */
SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca);
SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, p->pktlen);
SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, p->pktlen);
SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, p->pktlen);
/* Process IP packets */
if (IPV4_GET_RAW_VER(ip4h) == 4) {
SCLogDebug("DecodeIPFW ip4 processing");
DecodeIPV4(tv, dtv, p, p->pkt, p->pktlen, pq);
} else if(IPV6_GET_RAW_VER(ip6h) == 6) {
SCLogDebug("DecodeIPFW ip6 processing");
DecodeIPV6(tv, dtv, p, p->pkt, p->pktlen, pq);
} else {
/* We don't support anything besides IP packets for now, bridged packets? */
SCLogInfo("IPFW unknown protocol support %02x", *p->pkt);
SCReturnInt(TM_ECODE_FAILED);
}
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function initializes the DecodeThreadVariables
*
*
* \param tv pointer to ThreadVars
* \param initdata pointer for passing in args
* \param data pointer that gets cast into IPFWThreadVars for ptv
*/
TmEcode DecodeIPFWThreadInit(ThreadVars *tv, void *initdata, void **data)
{
DecodeThreadVars *dtv = NULL;
if ( (dtv = malloc(sizeof(DecodeThreadVars))) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,"Error Allocating memory for IPFW Decode DTV: %s",strerror(errno));
SCReturnInt(TM_ECODE_FAILED);
}
memset(dtv, 0, sizeof(DecodeThreadVars));
DecodeRegisterPerfCounters(dtv, tv);
*data = (void *)dtv;
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function sets the Verdict and processes the packet
*
*
* \param tv pointer to ThreadVars
* \param p pointer to the Packet
*/
TmEcode IPFWSetVerdict(ThreadVars *tv, IPFWThreadVars *ptv, Packet *p) {
uint32_t verdict;
struct pollfd IPFWpoll;
SCEnter();
IPFWpoll.fd=ipfw_sock;
IPFWpoll.events= POLLWRNORM;
/* What to do with the packet? */
switch (p->action) {
case ACTION_ALERT:
case ACTION_PASS:
verdict = IPFW_ACCEPT;
break;
case ACTION_REJECT:
case ACTION_REJECT_DST:
case ACTION_REJECT_BOTH:
case ACTION_DROP:
default:
/* a verdict we don't know about, drop to be sure */
verdict = IPFW_DROP;
}
if (verdict == IPFW_ACCEPT) {
SCLogDebug("IPFW Verdict is to Accept");
ptv->accepted++;
/* For divert sockets, accepting means writing the
* packet back to the socket for ipfw to pick up
*/
SCLogDebug("IPFWSetVerdict writing to socket %d, %p, %u", ipfw_sock,p->pkt,p->pktlen);
while ( (poll(&IPFWpoll,1,IPFW_SOCKET_POLL_MSEC)) < 1) {
/* Did we receive a signal to shutdown */
if (TmThreadsCheckFlag(tv, THV_KILL) || TmThreadsCheckFlag(tv, THV_PAUSE)) {
SCLogInfo("Received ThreadShutdown: IPFW divert socket writing interrupted");
SCReturnInt(TM_ECODE_OK);
}
}
SCMutexLock(&ipfw_socket_lock);
if (sendto(ipfw_sock, p->pkt, p->pktlen, 0,(struct sockaddr *)&ipfw_sin, ipfw_sinlen) == -1) {
SCLogWarning(SC_WARN_IPFW_XMIT,"Write to ipfw divert socket failed: %s",strerror(errno));
SCMutexUnlock(&ipfw_socket_lock);
SCReturnInt(TM_ECODE_FAILED);
}
SCMutexUnlock(&ipfw_socket_lock);
SCLogDebug("Sent Packet back into IPFW Len: %d",p->pktlen);
} /* end IPFW_ACCEPT */
if (verdict == IPFW_DROP) {
SCLogDebug("IPFW SetVerdict is to DROP");
ptv->dropped++;
/* For divert sockets, dropping means not writing the packet back to the socket.
* Need to see if there is some better way to free the packet from the queue */
} /* end IPFW_DROP */
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function handles the Verdict processing
* \todo Unit tests are needed for this module.
*
*
* \param tv pointer to ThreadVars
* \param p pointer to the Packet
* \param data pointer that gets cast into IPFWThreadVars for ptv
* \param pq pointer for the Packet Queue access (Not used)
*/
TmEcode VerdictIPFW(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) {
IPFWThreadVars *ptv = (IPFWThreadVars *)data;
TmEcode retval = TM_ECODE_OK;
SCEnter();
/* This came from NFQ.
* if this is a tunnel packet we check if we are ready to verdict
* already. */
if (IS_TUNNEL_PKT(p)) {
char verdict = 1;
pthread_mutex_t *m = p->root ? &p->root->mutex_rtv_cnt : &p->mutex_rtv_cnt;
SCMutexLock(m);
/* if there are more tunnel packets than ready to verdict packets,
* we won't verdict this one
*/
if (TUNNEL_PKT_TPR(p) > TUNNEL_PKT_RTV(p)) {
SCLogDebug("VerdictIPFW: not ready to verdict yet: TUNNEL_PKT_TPR(p) > TUNNEL_PKT_RTV(p) = %" PRId32 " > %" PRId32 "", TUNNEL_PKT_TPR(p), TUNNEL_PKT_RTV(p));
verdict = 0;
}
SCMutexUnlock(m);
/* don't verdict if we are not ready */
if (verdict == 1) {
SCLogDebug("Setting verdict on tunnel");
retval=IPFWSetVerdict(tv, ptv, p->root ? p->root : p);
} else
TUNNEL_INCR_PKT_RTV(p);
} else {
/* no tunnel, verdict normally */
SCLogDebug("Setting verdict on non-tunnel");
retval=IPFWSetVerdict(tv, ptv, p);
} /* IS_TUNNEL_PKT end */
SCReturnInt(retval);
}
/**
* \brief This function initializes the VerdictThread
*
*
* \param t pointer to ThreadVars
* \param initdata pointer for passing in args
* \param data pointer that gets cast into IPFWThreadVars for ptv
*/
TmEcode VerdictIPFWThreadInit(ThreadVars *tv, void *initdata, void **data) {
IPFWThreadVars *ptv = NULL;
SCEnter();
/* Setup Thread vars */
if ( (ptv = malloc(sizeof(IPFWThreadVars))) == NULL) {
SCLogError(SC_ERR_MEM_ALLOC,"Error Allocating memory for IPFW Verdict PTV: %s", strerror(errno));
SCReturnInt(TM_ECODE_FAILED);
}
memset(ptv, 0, sizeof(IPFWThreadVars));
*data = (void *)ptv;
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function deinitializes the VerdictThread
*
*
* \param tv pointer to ThreadVars
* \param data pointer that gets cast into IPFWThreadVars for ptv
*/
TmEcode VerdictIPFWThreadDeinit(ThreadVars *tv, void *data) {
SCEnter();
/* We don't need to do anything...not sure quite yet */
SCReturnInt(TM_ECODE_OK);
}
/**
* \brief This function prints stats for the VerdictThread
*
*
* \param tv pointer to ThreadVars
* \param data pointer that gets cast into IPFWThreadVars for ptv
*/
void VerdictIPFWThreadExitStats(ThreadVars *tv, void *data) {
IPFWThreadVars *ptv = (IPFWThreadVars *)data;
SCLogInfo("IPFW Processing: - (%s) Pkts accepted %" PRIu32 ", dropped %" PRIu32 "", tv->name, ptv->accepted, ptv->dropped);
}
#endif /* End ifdef IPFW */
/* eof */

@ -0,0 +1,22 @@
/* Copyright (c) 2009 Open Information Security Foundation */
/** \file
* \author Nick Rogness <nick@rogness.net>
*/
#ifndef __SOURCE_IPFW_H__
#define __SOURCE_IPFW_H__
#include <pthread.h>
/* per packet IPFW vars (Not used) */
typedef struct IPFWPacketVars_
{
} IPFWPacketVars;
void TmModuleReceiveIPFWRegister (void);
void TmModuleVerdictIPFWRegister (void);
void TmModuleDecodeIPFWRegister (void);
#endif /* __SOURCE_IPFW_H__ */

@ -50,6 +50,8 @@
#include "source-nfq.h"
#include "source-nfq-prototypes.h"
#include "source-ipfw.h"
#include "source-pcap.h"
#include "source-pcap-file.h"
@ -283,6 +285,7 @@ void usage(const char *progname)
printf("\t-i <dev> : run in pcap live mode\n");
printf("\t-r <path> : run in pcap file/offline mode\n");
printf("\t-q <qid> : run in inline nfqueue mode\n");
printf("\t-d <divert port> : run in inline ipfw divert mode\n");
printf("\t-s <path> : path to signature file (optional)\n");
printf("\t-l <dir> : default log directory\n");
printf("\t-D : run as daemon\n");
@ -339,7 +342,7 @@ int main(int argc, char **argv)
/* getopt_long stores the option index here. */
int option_index = 0;
char short_opts[] = "c:Dhi:l:q:r:us:U:V";
char short_opts[] = "c:Dhi:l:q:d:r:us:U:V";
while ((opt = getopt_long(argc, argv, short_opts, long_opts, &option_index)) != -1) {
switch (opt) {
@ -415,6 +418,13 @@ int main(int argc, char **argv)
run_mode = MODE_NFQ;
nfq_id = atoi(optarg); /* strtol? */
break;
case 'd':
run_mode = MODE_IPFW;
if (ConfSet("ipfw-divert-port", optarg, 0) != 1) {
fprintf(stderr, "ERROR: Failed to set ipfw_divert_port\n");
exit(EXIT_FAILURE);
}
break;
case 'r':
run_mode = MODE_PCAP_FILE;
pcap_file = optarg;
@ -523,6 +533,9 @@ int main(int argc, char **argv)
TmModuleReceiveNFQRegister();
TmModuleVerdictNFQRegister();
TmModuleDecodeNFQRegister();
TmModuleReceiveIPFWRegister();
TmModuleVerdictIPFWRegister();
TmModuleDecodeIPFWRegister();
TmModuleReceivePcapRegister();
TmModuleDecodePcapRegister();
TmModuleReceivePfringRegister();
@ -674,6 +687,9 @@ int main(int argc, char **argv)
else if (run_mode == MODE_NFQ) {
RunModeIpsNFQ(de_ctx);
}
else if (run_mode == MODE_IPFW) {
RunModeIpsIPFW(de_ctx);
}
else {
SCLogError(SC_ERR_UNKNOWN_RUN_MODE, "Unknown runtime mode. Aborting");
exit(EXIT_FAILURE);

@ -39,6 +39,7 @@ enum {
MODE_PCAP_FILE,
MODE_PFRING,
MODE_NFQ,
MODE_IPFW,
MODE_UNITTEST
};

@ -8,6 +8,10 @@
#ifndef __THREADS_H__
#define __THREADS_H__
#ifdef OS_FREEBSD
#include <sys/thr.h>
#endif /* OS_FREEBSD */
#include <pthread.h>
/** The mutex/spinlock/condition definitions and functions are used
@ -24,6 +28,23 @@
#define SCMutexAttr pthread_mutexattr_t
#define SCMutexDestroy pthread_mutex_destroy
/** Get the Current Thread Id */
#ifdef OS_FREEBSD
#define SCGetThreadIdLong(...) ({ \
long tmpthid; \
thr_self(&tmpthid); \
u_long tid = (u_long)tmpthid; \
tid; \
})
#else
#define SCGetThreadIdLong(...) ({ \
pid_t tmpthid; \
tmpthid = syscall(SYS_gettid); \
u_long tid = (u_long)tmpthid; \
tid; \
})
#endif /* OS FREEBSD */
/** Mutex Functions */
#ifdef DBG_THREADS
/** When dbg threads is defined, if a mutex fail to lock, it's

@ -46,6 +46,9 @@ enum {
TMM_LOGHTTPLOG4,
TMM_LOGHTTPLOG6,
TMM_STREAMTCP,
TMM_DECODEIPFW,
TMM_VERDICTIPFW,
TMM_RECEIVEIPFW,
TMM_SIZE,
};

@ -20,6 +20,7 @@
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/cpuset.h>
#include <sys/thr.h>
#define cpu_set_t cpuset_t
#elif OS_DARWIN
#include <mach/mach.h>
@ -576,20 +577,20 @@ void TmVarSlotSetFuncAppend(ThreadVars *tv, TmModule *tm, void *data) {
/* called from the thread */
static int SetCPUAffinity(int cpu) {
//pthread_t tid = pthread_self();
pid_t tid = syscall(SYS_gettid);
cpu_set_t cs;
printf("Setting CPU Affinity for thread %" PRIu32 " to CPU %" PRId32 "\n", tid, cpu);
printf("Setting CPU Affinity for thread %lu to CPU %" PRId32 "\n", SCGetThreadIdLong(), cpu);
cpu_set_t cs;
CPU_ZERO(&cs);
CPU_SET(cpu,&cs);
#ifdef OS_FREEBSD
int r = cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_TID,tid,sizeof(cpu_set_t),&cs);
int r = cpuset_setaffinity(CPU_LEVEL_WHICH,CPU_WHICH_TID,SCGetThreadIdLong(),sizeof(cpu_set_t),&cs);
#elif OS_DARWIN
int r = thread_policy_set(mach_thread_self(), THREAD_AFFINITY_POLICY, (void*)&cs, THREAD_AFFINITY_POLICY_COUNT);
#else
pid_t tid = syscall(SYS_gettid);
int r = sched_setaffinity(tid,sizeof(cpu_set_t),&cs);
#endif /* OS_FREEBSD */

@ -8,19 +8,6 @@
#include <pthread.h>
#include "threads.h"
/**
* \brief extra defines needed for FreeBSD
*/
#ifdef OS_FREEBSD
#ifndef SYS_gettid
#if __i386__
#define SYS_gettid 224
#elif __amd64__
#define SYS_gettid 186
#endif /* cpu arch */
#endif /* SYS_gettid */
#endif /* OS_FREEBSD */
/**
* \brief Enum that holds the different kinds of filters available
*/

@ -11,7 +11,7 @@
#include <sys/time.h>
#include <sys/syscall.h>
#include <syslog.h>
#include "threads.h"
#include "util-debug.h"
#include "util-error.h"
#include "util-enum.h"
@ -334,7 +334,7 @@ SCError SCLogMessage(SCLogLevel log_level, char **msg, const char *file,
case SC_LOG_FMT_TID:
temp_fmt[0] = '\0';
cw = snprintf(temp, SC_LOG_MAX_LOG_MSG_LEN - (temp - *msg),
"%s%lu", substr, syscall(SYS_gettid));
"%s%lu", substr, SCGetThreadIdLong());
if (cw < 0)
goto error;
temp += cw;

@ -77,6 +77,14 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_ERR_MISSING_QUOTE);
CASE_CODE (SC_ERR_UNKNOWN_PROTOCOL);
CASE_CODE (SC_ERR_UNKNOWN_RUN_MODE);
CASE_CODE (SC_ERR_IPFW_NOSUPPORT);
CASE_CODE (SC_ERR_IPFW_BIND);
CASE_CODE (SC_ERR_IPFW_SOCK);
CASE_CODE (SC_ERR_IPFW_NOPORT);
CASE_CODE (SC_WARN_IPFW_RECV);
CASE_CODE (SC_WARN_IPFW_XMIT);
CASE_CODE (SC_WARN_IPFW_SETSOCKOPT);
CASE_CODE (SC_WARN_IPFW_UNBIND);
default:
return "UNKNOWN_ERROR";

@ -67,6 +67,14 @@ typedef enum {
SC_NFQ_HANDLE_PKT,
SC_NFQ_SET_VERDICT,
SC_NFQ_THREAD_INIT,
SC_ERR_IPFW_NOSUPPORT,
SC_ERR_IPFW_BIND,
SC_ERR_IPFW_SOCK,
SC_ERR_IPFW_NOPORT,
SC_WARN_IPFW_RECV,
SC_WARN_IPFW_XMIT,
SC_WARN_IPFW_SETSOCKOPT,
SC_WARN_IPFW_UNBIND,
SC_ERR_DAEMON,
SC_UNIMPLEMENTED,
SC_ERR_ADDRESS_ENGINE_GENERIC_ERROR,

@ -149,8 +149,34 @@ pfring:
# clusterid.
clusterid: 99
#Set the default rule path here to search for the files.
#if not set, it will look at the current working dir
# For FreeBSD ipfw(8) divert(4) support.
# Please make sure you have ipfw_load="YES" and ipdivert_load="YES"
# in /etc/loader.conf or kldload'ing the appropriate kernel modules.
# Additionally, you need to have an ipfw rule for the engine to see
# the packets from ipfw. For Example:
#
# ipfw add 100 divert 8000 ip from any to any
#
# The 8000 above should be the same number you passed on the command
# line, i.e. -d 8000
#
ipfw:
# Reinject packets at the specified ipfw rule number. This config
# option is the ipfw rule number AT WHICH rule processing continues
# in the ipfw processing system after the engine has finished
# inspecting the packet for acceptance. If no rule number is specified,
# accepted packets are reinjected at the divert rule which they entered
# and IPFW rule processing continues. No check is done to verify
# this will rule makes sense so care must be taken to avoid loops in ipfw.
#
## The following example tells the engine to reinject packets
# back into the ipfw firewall AT rule number 5500:
#
# ipfw-reinjection-rule-number: 5500
# Set the default rule path here to search for the files.
# if not set, it will look at the current working dir
default-rule-path: /etc/suricata/rules/
rule-files:
- attack-responses.rules

Loading…
Cancel
Save