suricata
source-nflog.c
Go to the documentation of this file.
1/* Copyright (C) 2014 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18/**
19 * \file
20 *
21 * \author Giuseppe Longo <giuseppelng@gmail.com>
22 *
23 * Netfilter's netfilter_log support
24 */
25#include "suricata-common.h"
26#include "suricata.h"
27#include "decode.h"
28#include "packet-queue.h"
29
30#include "threads.h"
31#include "threadvars.h"
32#include "tm-threads.h"
33#include "tm-modules.h"
34#include "tm-queuehandlers.h"
35#include "tmqh-packetpool.h"
36
37#include "runmodes.h"
38#include "util-error.h"
39#include "util-device-private.h"
40#include "util-datalink.h"
41
42#ifndef HAVE_NFLOG
43/** Handle the case where no NFLOG support is compiled in.
44 *
45 */
46
47TmEcode NoNFLOGSupportExit(ThreadVars *, const void *, void **);
48
54
60
61TmEcode NoNFLOGSupportExit(ThreadVars *tv, const void *initdata, void **data)
62{
63 SCLogError("Error creating thread %s: you do not have support for nflog "
64 "enabled please recompile with --enable-nflog",
65 tv->name);
66 exit(EXIT_FAILURE);
67}
68
69#else /* implied we do have NFLOG support */
70
71#include "source-nflog.h"
72
73TmEcode ReceiveNFLOGThreadInit(ThreadVars *, const void *, void **);
74TmEcode ReceiveNFLOGThreadDeinit(ThreadVars *, void *);
75TmEcode ReceiveNFLOGLoop(ThreadVars *, void *, void *);
76void ReceiveNFLOGThreadExitStats(ThreadVars *, void *);
77
78TmEcode DecodeNFLOGThreadInit(ThreadVars *, const void *, void **);
79TmEcode DecodeNFLOGThreadDeinit(ThreadVars *tv, void *data);
80TmEcode DecodeNFLOG(ThreadVars *, Packet *, void *);
81
82static int runmode_workers;
83
84/* Structure to hold thread specific variables */
85typedef struct NFLOGThreadVars_ {
87 TmSlot *slot;
88
89 char *data;
90 int datalen;
91
92 uint16_t group;
93 uint32_t nlbufsiz;
94 uint32_t nlbufsiz_max;
95 uint32_t qthreshold;
96 uint32_t qtimeout;
97
98 struct nflog_handle *h;
99 struct nflog_g_handle *gh;
100
101 LiveDevice *livedev;
102 int nful_overrun_warned;
103
104 /* counters */
105 uint32_t pkts;
106 uint64_t bytes;
107 uint32_t errs;
108
109 uint16_t capture_kernel_packets;
110 uint16_t capture_kernel_drops;
111} NFLOGThreadVars;
112
113/**
114 * \brief Registration function for ReceiveNFLOG
115 */
117{
118 tmm_modules[TMM_RECEIVENFLOG].name = "ReceiveNFLOG";
119 tmm_modules[TMM_RECEIVENFLOG].ThreadInit = ReceiveNFLOGThreadInit;
121 tmm_modules[TMM_RECEIVENFLOG].PktAcqLoop = ReceiveNFLOGLoop;
123 tmm_modules[TMM_RECEIVENFLOG].ThreadExitPrintStats = ReceiveNFLOGThreadExitStats;
124 tmm_modules[TMM_RECEIVENFLOG].ThreadDeinit = ReceiveNFLOGThreadDeinit;
126}
127
128/**
129 * \brief Registration function for DecodeNFLOG
130 */
132{
133 tmm_modules[TMM_DECODENFLOG].name = "DecodeNFLOG";
134 tmm_modules[TMM_DECODENFLOG].ThreadInit = DecodeNFLOGThreadInit;
135 tmm_modules[TMM_DECODENFLOG].Func = DecodeNFLOG;
137 tmm_modules[TMM_DECODENFLOG].ThreadDeinit = DecodeNFLOGThreadDeinit;
139}
140
141/**
142 * \brief NFLOG callback function
143 * This function setup a packet from a nflog message
144 */
145static int NFLOGCallback(struct nflog_g_handle *gh, struct nfgenmsg *msg,
146 struct nflog_data *nfa, void *data)
147{
148 NFLOGThreadVars *ntv = (NFLOGThreadVars *) data;
149 struct nfulnl_msg_packet_hdr *ph;
150 char *payload;
151 int ret;
152
153 /* grab a packet*/
155 if (p == NULL)
156 return -1;
157
159
160 ph = nflog_get_msg_packet_hdr(nfa);
161 if (ph != NULL) {
162 p->nflog_v.hw_protocol = ph->hw_protocol;
163 }
164
165 p->nflog_v.ifi = nflog_get_indev(nfa);
166 p->nflog_v.ifo = nflog_get_outdev(nfa);
167
168 ret = nflog_get_payload(nfa, &payload);
169
170 if (ret > 0) {
171 if (ret > 65536) {
172 SCLogWarning("NFLOG sent too big packet");
173 SET_PKT_LEN(p, 0);
174 } else if (runmode_workers)
175 PacketSetData(p, (uint8_t *)payload, ret);
176 else
177 PacketCopyData(p, (uint8_t *)payload, ret);
178 } else if (ret == -1)
179 SET_PKT_LEN(p, 0);
180
181 struct timeval tv;
182 ret = nflog_get_timestamp(nfa, &tv);
183 if (ret != 0) {
184 memset(&tv, 0, sizeof(tv));
185 gettimeofday(&tv, NULL);
186 }
188
189 p->datalink = DLT_RAW;
190
191#ifdef COUNTERS
192 ntv->pkts++;
193 ntv->bytes += GET_PKT_LEN(p);
194#endif
195 (void) SC_ATOMIC_ADD(ntv->livedev->pkts, 1);
196
197 if (TmThreadsSlotProcessPkt(ntv->tv, ntv->slot, p) != TM_ECODE_OK) {
198 return -1;
199 }
200
201 return 0;
202}
203
204/**
205 * \brief Receives packet from a nflog group via libnetfilter_log
206 * This is a setup function for receiving packets via libnetfilter_log.
207 * \param tv pointer to ThreadVars
208 * \param initdata pointer to the group passed from the user
209 * \param data pointer gets populated with NFLOGThreadVars
210 * \retvalTM_ECODE_OK on success
211 * \retval TM_ECODE_FAILED on error
212 */
213TmEcode ReceiveNFLOGThreadInit(ThreadVars *tv, const void *initdata, void **data)
214{
215 NflogGroupConfig *nflconfig = (NflogGroupConfig *)initdata;
216
217 if (initdata == NULL) {
218 SCLogError("initdata == NULL");
220 }
221
222 NFLOGThreadVars *ntv = SCCalloc(1, sizeof(NFLOGThreadVars));
223 if (unlikely(ntv == NULL)) {
224 nflconfig->DerefFunc(nflconfig);
226 }
227
228 ntv->tv = tv;
229 ntv->group = nflconfig->group;
230 ntv->nlbufsiz = nflconfig->nlbufsiz;
231 ntv->nlbufsiz_max = nflconfig->nlbufsiz_max;
232 ntv->qthreshold = nflconfig->qthreshold;
233 ntv->qtimeout = nflconfig->qtimeout;
234 ntv->nful_overrun_warned = nflconfig->nful_overrun_warned;
235
236 ntv->h = nflog_open();
237 if (ntv->h == NULL) {
238 SCLogError("nflog_open() failed");
239 SCFree(ntv);
240 return TM_ECODE_FAILED;
241 }
242
243 SCLogDebug("binding netfilter_log as nflog handler for AF_INET and AF_INET6");
244
245 if (nflog_bind_pf(ntv->h, AF_INET) < 0) {
246 FatalError("nflog_bind_pf() for AF_INET failed");
247 }
248 if (nflog_bind_pf(ntv->h, AF_INET6) < 0) {
249 FatalError("nflog_bind_pf() for AF_INET6 failed");
250 }
251
252 ntv->gh = nflog_bind_group(ntv->h, ntv->group);
253 if (!ntv->gh) {
254 SCLogError("nflog_bind_group() failed");
255 SCFree(ntv);
256 return TM_ECODE_FAILED;
257 }
258
259 if (nflog_set_mode(ntv->gh, NFULNL_COPY_PACKET, 0xFFFF) < 0) {
260 SCLogError("can't set packet_copy mode");
261 SCFree(ntv);
262 return TM_ECODE_FAILED;
263 }
264
265 nflog_callback_register(ntv->gh, &NFLOGCallback, (void *)ntv);
266
267 if (ntv->nlbufsiz < ntv->nlbufsiz_max)
268 ntv->nlbufsiz = nfnl_rcvbufsiz(nflog_nfnlh(ntv->h), ntv->nlbufsiz);
269 else {
270 SCLogError("Maximum buffer size (%d) in NFLOG "
271 "has been reached",
272 ntv->nlbufsiz);
273 return TM_ECODE_FAILED;
274 }
275
276 if (nflog_set_qthresh(ntv->gh, ntv->qthreshold) >= 0)
277 SCLogDebug("NFLOG netlink queue threshold has been set to %d",
278 ntv->qthreshold);
279 else
280 SCLogDebug("NFLOG netlink queue threshold can't be set to %d",
281 ntv->qthreshold);
282
283 if (nflog_set_timeout(ntv->gh, ntv->qtimeout) >= 0)
284 SCLogDebug("NFLOG netlink queue timeout has been set to %d",
285 ntv->qtimeout);
286 else
287 SCLogDebug("NFLOG netlink queue timeout can't be set to %d",
288 ntv->qtimeout);
289
290 ntv->livedev = LiveGetDevice(nflconfig->numgroup);
291 if (ntv->livedev == NULL) {
292 SCLogError("Unable to find Live device");
293 SCFree(ntv);
295 }
296
297 /* set a timeout to the socket so we can check for a signal
298 * in case we don't get packets for a longer period. */
299 struct timeval timev;
300 timev.tv_sec = 1;
301 timev.tv_usec = 0;
302
303 int fd = nflog_fd(ntv->h);
304 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)) == -1) {
305 SCLogWarning("can't set socket "
306 "timeout: %s",
307 strerror(errno));
308 }
309
310#ifdef PACKET_STATISTICS
311 ntv->capture_kernel_packets = StatsRegisterCounter("capture.kernel_packets",
312 ntv->tv);
313 ntv->capture_kernel_drops = StatsRegisterCounter("capture.kernel_drops",
314 ntv->tv);
315#endif
316
317 char *active_runmode = RunmodeGetActive();
318 if (active_runmode && !strcmp("workers", active_runmode))
319 runmode_workers = 1;
320 else
321 runmode_workers = 0;
322
323#define T_DATA_SIZE 70000
324 ntv->data = SCMalloc(T_DATA_SIZE);
325 if (ntv->data == NULL) {
326 nflconfig->DerefFunc(nflconfig);
327 SCFree(ntv);
329 }
330
331 ntv->datalen = T_DATA_SIZE;
332#undef T_DATA_SIZE
333
335
336 *data = (void *)ntv;
337
338 nflconfig->DerefFunc(nflconfig);
340}
341
342/**
343 * \brief DeInit function unbind group and close nflog's handle
344 * \param tv pointer to ThreadVars
345 * \param data pointer that gets cast into NFLogThreadVars
346 * \retval TM_ECODE_OK is always returned
347 */
348TmEcode ReceiveNFLOGThreadDeinit(ThreadVars *tv, void *data)
349{
350 NFLOGThreadVars *ntv = (NFLOGThreadVars *)data;
351
352 SCLogDebug("closing nflog group %d", ntv->group);
353 if (nflog_unbind_pf(ntv->h, AF_INET) < 0) {
354 FatalError("nflog_unbind_pf() for AF_INET failed");
355 }
356
357 if (nflog_unbind_pf(ntv->h, AF_INET6) < 0) {
358 FatalError("nflog_unbind_pf() for AF_INET6 failed");
359 }
360
361 if (ntv->gh) {
362 nflog_unbind_group(ntv->gh);
363 ntv->gh = NULL;
364 }
365
366 if (ntv->h) {
367 nflog_close(ntv->h);
368 ntv->h = NULL;
369 }
370
371 if (ntv->data != NULL) {
372 SCFree(ntv->data);
373 ntv->data = NULL;
374 }
375 ntv->datalen = 0;
376
377 SCFree(ntv);
378
380}
381
382/**
383 * \brief Increases netlink buffer size
384 *
385 * This function netlink's buffer size until
386 * the max buffer size is reached
387 *
388 * \param data pointer that gets cast into NFLOGThreadVars
389 * \param size netlink buffer size
390 */
391static int NFLOGSetnlbufsiz(void *data, unsigned int size)
392{
393 SCEnter();
394 NFLOGThreadVars *ntv = (NFLOGThreadVars *)data;
395
396 if (size < ntv->nlbufsiz_max) {
397 ntv->nlbufsiz = nfnl_rcvbufsiz(nflog_nfnlh(ntv->h), ntv->nlbufsiz);
398 return 1;
399 }
400
401 SCLogWarning("Maximum buffer size (%d) in NFLOG has been "
402 "reached. Please, consider raising "
403 "`buffer-size` and `max-size` in nflog configuration",
404 ntv->nlbufsiz);
405 return 0;
406
407}
408
409/**
410 * \brief Recieves packets from a group via libnetfilter_log.
411 *
412 * This function receives packets from a group and passes
413 * the packet on to the nflog callback function.
414 *
415 * \param tv pointer to ThreadVars
416 * \param data pointer that gets cast into NFLOGThreadVars
417 * \param slot slot containing task information
418 * \retval TM_ECODE_OK on success
419 * \retval TM_ECODE_FAILED on failure
420 */
421TmEcode ReceiveNFLOGLoop(ThreadVars *tv, void *data, void *slot)
422{
423 SCEnter();
424 NFLOGThreadVars *ntv = (NFLOGThreadVars *)data;
425 int rv, fd;
426 int ret = -1;
427
428 ntv->slot = ((TmSlot *) slot)->slot_next;
429
430 fd = nflog_fd(ntv->h);
431 if (fd < 0) {
432 SCLogError("Can't obtain a file descriptor");
434 }
435
436 // Indicate that the thread is actually running its application level code (i.e., it can poll
437 // packets)
439
440 while (1) {
441 if (suricata_ctl_flags != 0)
442 break;
443
444 rv = recv(fd, ntv->data, ntv->datalen, 0);
445 if (rv < 0) {
446 /*We received an error on socket read */
447 if (errno == EINTR || errno == EWOULDBLOCK) {
448 /*Nothing for us to process */
449 continue;
450 } else if (errno == ENOBUFS) {
451 if (!ntv->nful_overrun_warned) {
452 int s = ntv->nlbufsiz * 2;
453 if (NFLOGSetnlbufsiz((void *)ntv, s)) {
454 SCLogWarning("We are losing events, "
455 "increasing buffer size "
456 "to %d",
457 ntv->nlbufsiz);
458 } else {
459 ntv->nful_overrun_warned = 1;
460 }
461 }
462 continue;
463 } else {
464 SCLogWarning("Read from NFLOG fd failed: %s", strerror(errno));
466 }
467 }
468
469 ret = nflog_handle_packet(ntv->h, ntv->data, rv);
470 if (ret != 0)
471 SCLogWarning("nflog_handle_packet error %" PRId32 "", ret);
472
474 }
475
477}
478
479/**
480 * \brief This function prints stats to the screen at exit
481 * \param tv pointer to ThreadVars
482 * \param data pointer that gets cast into NFLOGThreadVars
483 */
484void ReceiveNFLOGThreadExitStats(ThreadVars *tv, void *data)
485{
486 SCEnter();
487 NFLOGThreadVars *ntv = (NFLOGThreadVars *)data;
488
489 SCLogNotice("(%s) Pkts %" PRIu32 ", Bytes %" PRIu64 "",
490 tv->name, ntv->pkts, ntv->bytes);
491}
492
493
494/**
495 * \brief Decode IPv4/v6 packets.
496 *
497 * \param tv pointer to ThreadVars
498 * \param p pointer to the current packet
499 * \param data pointer that gets cast into NFLOGThreadVars for ptv
500 *
501 * \retval TM_ECODE_OK is always returned
502 */
503TmEcode DecodeNFLOG(ThreadVars *tv, Packet *p, void *data)
504{
505 SCEnter();
506 IPV4Hdr *ip4h = (IPV4Hdr *)GET_PKT_DATA(p);
507 IPV6Hdr *ip6h = (IPV6Hdr *)GET_PKT_DATA(p);
509
511
512 if (IPV4_GET_RAW_VER(ip4h) == 4) {
513 if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) {
514 return TM_ECODE_FAILED;
515 }
516 SCLogDebug("IPv4 packet");
518 } else if(IPV6_GET_RAW_VER(ip6h) == 6) {
519 if (unlikely(GET_PKT_LEN(p) > USHRT_MAX)) {
520 return TM_ECODE_FAILED;
521 }
522 SCLogDebug("IPv6 packet");
524 } else {
525 SCLogDebug("packet unsupported by NFLOG, first byte: %02x", *GET_PKT_DATA(p));
526 }
527
529
531}
532
533/**
534 * \brief This an Init function for DecodeNFLOG
535 *
536 * \param tv pointer to ThreadVars
537 * \param initdata pointer to initialization data.
538 * \param data pointer that gets cast into NFLOGThreadVars
539 * \retval TM_ECODE_OK is returned on success
540 * \retval TM_ECODE_FAILED is returned on error
541 */
542TmEcode DecodeNFLOGThreadInit(ThreadVars *tv, const void *initdata, void **data)
543{
544 DecodeThreadVars *dtv = NULL;
546
547 if (dtv == NULL)
549
551
552 *data = (void *)dtv;
553
555}
556
557TmEcode DecodeNFLOGThreadDeinit(ThreadVars *tv, void *data)
558{
559 if (data != NULL)
562}
563
564#endif /* NFLOG */
uint8_t group
uint16_t StatsRegisterCounter(const char *name, struct ThreadVars_ *tv)
Registers a normal, unqualified counter.
Definition counters.c:952
void StatsSyncCountersIfSignalled(ThreadVars *tv)
Definition counters.c:450
int DecodeIPV4(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define IPV4_GET_RAW_VER(ip4h)
Definition decode-ipv4.h:95
int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint16_t len)
#define IPV6_GET_RAW_VER(ip6h)
Definition decode-ipv6.h:62
#define SET_PKT_LEN(p, len)
Definition decode.h:213
#define PKT_SET_SRC(p, src_val)
Definition decode.h:1325
#define GET_PKT_DATA(p)
Definition decode.h:209
#define GET_PKT_LEN(p)
Definition decode.h:208
@ PKT_SRC_WIRE
Definition decode.h:52
DecodeThreadVars * dtv
ThreadVars * tv
Packet * PacketGetFromQueueOrAlloc(void)
Get a packet. We try to get a packet from the packetpool first, but if that is empty we alloc a packe...
Definition decode.c:293
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
Definition decode.c:628
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
Definition decode.c:232
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
Definition decode.c:804
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
Definition decode.c:822
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition decode.c:377
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
Definition decode.c:770
int PacketSetData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Set data for Packet and set length when zero copy is used.
Definition decode.c:842
char * RunmodeGetActive(void)
Definition runmodes.c:199
void TmModuleDecodeNFLOGRegister(void)
TmEcode NoNFLOGSupportExit(ThreadVars *, const void *, void **)
void TmModuleReceiveNFLOGRegister(void)
#define T_DATA_SIZE
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
void(* DerefFunc)(void *)
uint32_t nlbufsiz_max
char numgroup[NFLOG_GROUP_NAME_LENGTH]
SCTime_t ts
Definition decode.h:555
int datalink
Definition decode.h:639
Per thread variable structure.
Definition threadvars.h:58
char name[16]
Definition threadvars.h:65
const char * name
Definition tm-modules.h:48
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition tm-modules.h:53
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition tm-modules.h:52
TmEcode(* PktAcqBreakLoop)(ThreadVars *, void *)
Definition tm-modules.h:61
TmEcode(* Func)(ThreadVars *, Packet *, void *)
Definition tm-modules.h:56
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition tm-modules.h:58
uint8_t flags
Definition tm-modules.h:80
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition tm-modules.h:51
volatile uint8_t suricata_ctl_flags
Definition suricata.c:172
#define THV_RUNNING
Definition threadvars.h:55
TmModule tmm_modules[TMM_SIZE]
Definition tm-modules.c:29
#define TM_FLAG_RECEIVE_TM
Definition tm-modules.h:32
#define TM_FLAG_DECODE_TM
Definition tm-modules.h:33
@ TMM_DECODENFLOG
@ TMM_RECEIVENFLOG
@ TM_ECODE_FAILED
@ TM_ECODE_OK
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition tm-threads.c:101
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SCEnter(...)
Definition util-debug.h:277
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCReturnInt(x)
Definition util-debug.h:281
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition util-debug.h:255
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
LiveDevice * LiveGetDevice(const char *name)
Get a pointer to the device at idx.
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
#define unlikely(expr)
#define SCTIME_FROM_TIMEVAL(tv)
Definition util-time.h:79