suricata
source-erf-file.c
Go to the documentation of this file.
1 /* Copyright (C) 2010-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 Endace Technology Limited.
22  *
23  * Support for reading ERF files.
24  *
25  * Only ethernet supported at this time.
26  */
27 
28 #include "suricata-common.h"
29 #include "suricata.h"
30 #include "tm-threads.h"
31 #include "source-erf-file.h"
32 #include "util-datalink.h"
33 
34 #define ERF_HEADER_LEN 16
35 #define ERF_EXT_LEN 8
36 #define ERF_ETH_PAD_LEN 2
37 
38 #ifndef HAVE_DAG
39 #define ERF_TYPE_MASK 0x7f
40 #define ERF_TYPE_MORE_EXT 0x80
41 #define ERF_TYPE_ETH 2
42 #define ERF_TYPE_COLOR_ETH 11
43 #define ERF_TYPE_DSM_COLOR_ETH 16
44 #define ERF_TYPE_COLOR_HASH_ETH 20
45 
46 #else /* Implied we do have DAG support */
47 #include <dagapi.h>
48 #endif
49 
50 typedef struct DagFlags_ {
51  uint8_t iface:2;
52  uint8_t vlen:1;
53  uint8_t trunc:1;
54  uint8_t rxerror:1;
55  uint8_t dserror:1;
56  uint8_t reserved:1;
57  uint8_t direction:1;
59 
60 typedef struct DagRecord_ {
61  uint64_t ts;
62  uint8_t type;
64  uint16_t rlen;
65  uint16_t lctr;
66  uint16_t wlen;
67 } __attribute__((packed)) DagRecord;
68 
69 typedef struct ErfFileThreadVars_ {
71  TmSlot *slot;
72 
73  FILE *erf;
74 
75  uint32_t pkts;
76  uint64_t bytes;
77 
78  uint8_t buffer[MAX_PAYLOAD_SIZE];
80 
81 static inline TmEcode ReadErfRecord(ThreadVars *, Packet *, void *);
82 TmEcode ReceiveErfFileLoop(ThreadVars *, void *, void *);
83 TmEcode ReceiveErfFileThreadInit(ThreadVars *, const void *, void **);
86 
87 static TmEcode DecodeErfFileThreadInit(ThreadVars *, const void *, void **);
88 static TmEcode DecodeErfFileThreadDeinit(ThreadVars *tv, void *data);
89 static TmEcode DecodeErfFile(ThreadVars *, Packet *, void *);
90 
91 /**
92  * \brief Register the ERF file receiver (reader) module.
93  */
94 void
96 {
97  tmm_modules[TMM_RECEIVEERFFILE].name = "ReceiveErfFile";
107 }
108 
109 /**
110  * \brief Register the ERF file decoder module.
111  */
112 void
114 {
115  tmm_modules[TMM_DECODEERFFILE].name = "DecodeErfFile";
116  tmm_modules[TMM_DECODEERFFILE].ThreadInit = DecodeErfFileThreadInit;
117  tmm_modules[TMM_DECODEERFFILE].Func = DecodeErfFile;
119  tmm_modules[TMM_DECODEERFFILE].ThreadDeinit = DecodeErfFileThreadDeinit;
122 }
123 
124 /**
125  * \brief ERF file reading loop.
126  */
127 TmEcode ReceiveErfFileLoop(ThreadVars *tv, void *data, void *slot)
128 {
129  Packet *p = NULL;
130  ErfFileThreadVars *etv = (ErfFileThreadVars *)data;
131 
132  etv->slot = ((TmSlot *)slot)->slot_next;
133 
134  // Indicate that the thread is actually running its application level code (i.e., it can poll
135  // packets)
137 
138  while (1) {
141  }
142 
143  /* Make sure we have at least one packet in the packet pool,
144  * to prevent us from alloc'ing packets at line rate. */
145  PacketPoolWait();
146 
147  if (p == NULL) {
149  }
150  if (unlikely(p == NULL)) {
151  SCLogError("Failed to allocate a packet.");
152  EngineStop();
154  }
156 
157  if (ReadErfRecord(tv, p, data) != TM_ECODE_OK) {
158  TmqhOutputPacketpool(etv->tv, p);
159  EngineStop();
161  }
162  if (GET_PKT_LEN(p) == 0) {
163  continue;
164  }
165 
166  if (TmThreadsSlotProcessPkt(etv->tv, etv->slot, p) != TM_ECODE_OK) {
167  EngineStop();
169  }
170  p = NULL;
171  }
173 }
174 
175 static inline TmEcode ReadErfRecord(ThreadVars *tv, Packet *p, void *data)
176 {
177  SCEnter();
178 
179  ErfFileThreadVars *etv = (ErfFileThreadVars *)data;
180  DagRecord dr;
181  unsigned int hdr_num = 0;
182  char ext_hdr[ERF_EXT_LEN];
183 
184  size_t r = fread(&dr, sizeof(DagRecord), 1, etv->erf);
185  if (r < 1) {
186  if (feof(etv->erf)) {
187  SCLogInfo("End of ERF file reached");
188  }
189  else {
190  SCLogInfo("Error reading ERF record");
191  }
193  }
194  uint8_t hdr_type = dr.type;
195  uint16_t rlen = SCNtohs(dr.rlen);
196  if (rlen < ERF_HEADER_LEN) {
197  SCLogError("Bad ERF record, "
198  "record length less than size of header");
200  }
201 
202  /* count extension headers */
203  while (hdr_type & ERF_TYPE_MORE_EXT) {
204  if (rlen < (ERF_HEADER_LEN + ((hdr_num + 1) * 8))) {
205  SCLogError("Insufficient captured packet length.");
207  }
208  r = fread(ext_hdr, ERF_EXT_LEN, 1, etv->erf);
209  if (r < 1) {
210  if (feof(etv->erf)) {
211  SCLogInfo("End of ERF file reached");
212  } else {
213  SCLogInfo("Error reading ERF record");
214  }
216  }
217  hdr_type = ext_hdr[0];
218  hdr_num++;
219  }
220 
221  /* read and discard ERF Ethernet pad */
222  if (rlen < (ERF_HEADER_LEN + (hdr_num * ERF_EXT_LEN) + ERF_ETH_PAD_LEN)) {
223  SCLogError("Insufficient captured packet length.");
225  }
226  r = fread(ext_hdr, ERF_ETH_PAD_LEN, 1, etv->erf);
227  if (r < 1) {
228  if (feof(etv->erf)) {
229  SCLogInfo("End of ERF file reached");
230  } else {
231  SCLogInfo("Error reading ERF record");
232  }
234  }
235 
236  uint32_t caplen = rlen - (hdr_num * ERF_EXT_LEN) - ERF_HEADER_LEN - ERF_ETH_PAD_LEN;
237  if (caplen > MAX_PACKET_SIZE) {
238  SCLogError("Bad ERF record, capture length %u exceeds max %d", caplen, MAX_PACKET_SIZE);
240  }
241 
242  r = fread(etv->buffer, caplen, 1, etv->erf);
243  if (r < 1) {
244  if (feof(etv->erf)) {
245  SCLogInfo("End of ERF file reached");
246  }
247  else {
248  SCLogInfo("Error reading ERF record");
249  }
251  }
252 
253  /* Only support ethernet at this time. Return TM_ECODE_OK with pkt len = 0 to indicate skipped
254  * record */
255  switch (dr.type & ERF_TYPE_MASK) {
256  case ERF_TYPE_DSM_COLOR_ETH:
257  case ERF_TYPE_COLOR_ETH:
258  case ERF_TYPE_COLOR_HASH_ETH:
259  case ERF_TYPE_ETH:
260  break;
261  default:
263  }
264 
265  if (PacketCopyData(p, etv->buffer, caplen) != 0) {
267  }
268 
270 
271  /* Convert ERF time to SCTime_t */
272  uint64_t ts = dr.ts;
273  p->ts = SCTIME_FROM_SECS(ts >> 32);
274  ts = (ts & 0xffffffffULL) * 1000000;
275  ts += 0x80000000; /* rounding */
276  uint64_t usecs = (ts >> 32);
277  p->ts = SCTIME_ADD_USECS(p->ts, usecs);
278 
279  etv->pkts++;
280  etv->bytes += caplen;
281 
283 }
284 
285 /**
286  * \brief Initialize the ERF receiver thread.
287  */
288 TmEcode
289 ReceiveErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data)
290 {
291  SCEnter();
292 
293  if (initdata == NULL) {
294  SCLogError("Error: No filename provided.");
296  }
297 
298  FILE *erf = fopen((const char *)initdata, "r");
299  if (erf == NULL) {
300  SCLogError("Failed to open %s: %s", (char *)initdata, strerror(errno));
301  exit(EXIT_FAILURE);
302  }
303 
304  ErfFileThreadVars *etv = SCCalloc(1, sizeof(ErfFileThreadVars));
305  if (unlikely(etv == NULL)) {
306  SCLogError("Failed to allocate memory for ERF file thread vars.");
307  fclose(erf);
309  }
310  etv->erf = erf;
311  etv->tv = tv;
312  *data = (void *)etv;
313 
314  SCLogInfo("Processing ERF file %s", (char *)initdata);
315 
317 
319 }
320 
321 /**
322  * \brief Initialize the ERF decoder thread.
323  */
324 TmEcode
325 DecodeErfFileThreadInit(ThreadVars *tv, const void *initdata, void **data)
326 {
327  SCEnter();
328  DecodeThreadVars *dtv = NULL;
330 
331  if (dtv == NULL)
333 
335 
336  *data = (void *)dtv;
337 
339 }
340 
341 TmEcode DecodeErfFileThreadDeinit(ThreadVars *tv, void *data)
342 {
343  if (data != NULL)
344  DecodeThreadVarsFree(tv, data);
346 }
347 
348 /**
349  * \brief Decode the ERF file.
350  *
351  * This function ups the decoder counters and then passes the packet
352  * off to the ethernet decoder.
353  */
354 TmEcode
355 DecodeErfFile(ThreadVars *tv, Packet *p, void *data)
356 {
357  SCEnter();
359 
361 
362  /* Update counters. */
364 
366 
368 
370 }
371 
372 /**
373  * \brief Print some stats to the log at program exit.
374  *
375  * \param tv Pointer to ThreadVars.
376  * \param data Pointer to data, ErfFileThreadVars.
377  */
378 void
380 {
381  ErfFileThreadVars *etv = (ErfFileThreadVars *)data;
382 
383  SCLogInfo("Packets: %"PRIu32"; Bytes: %"PRIu64, etv->pkts, etv->bytes);
384 }
TmModule_::cap_flags
uint8_t cap_flags
Definition: tm-modules.h:77
TMM_RECEIVEERFFILE
@ TMM_RECEIVEERFFILE
Definition: tm-threads-common.h:48
tm-threads.h
DagRecord_::type
uint8_t type
Definition: source-erf-file.c:62
ts
uint64_t ts
Definition: source-erf-file.c:68
ERF_HEADER_LEN
#define ERF_HEADER_LEN
Definition: source-erf-file.c:34
DagRecord_::lctr
uint16_t lctr
Definition: source-erf-file.c:65
PacketCopyData
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:383
PKT_IS_PSEUDOPKT
#define PKT_IS_PSEUDOPKT(p)
return 1 if the packet is a pseudo packet
Definition: decode.h:1364
DagRecord_::ts
uint64_t ts
Definition: source-erf-file.c:61
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
TmThreadsSetFlag
void TmThreadsSetFlag(ThreadVars *tv, uint32_t flag)
Set a thread flag.
Definition: tm-threads.c:103
DagFlags_::trunc
uint8_t trunc
Definition: source-erf-file.c:53
ReceiveErfFileThreadExitStats
void ReceiveErfFileThreadExitStats(ThreadVars *, void *)
Print some stats to the log at program exit.
Definition: source-erf-file.c:379
DagRecord_::flags
DagFlags flags
Definition: source-erf-file.c:63
TmModuleDecodeErfFileRegister
void TmModuleDecodeErfFileRegister(void)
Register the ERF file decoder module.
Definition: source-erf-file.c:113
THV_RUNNING
#define THV_RUNNING
Definition: threadvars.h:55
SURICATA_STOP
#define SURICATA_STOP
Definition: suricata.h:94
PacketDecodeFinalize
void PacketDecodeFinalize(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Finalize decoding of a packet.
Definition: decode.c:235
p
Packet * p
Definition: fuzz_iprep.c:21
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:305
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:82
TmModule_::PktAcqLoop
TmEcode(* PktAcqLoop)(ThreadVars *, void *, void *)
Definition: tm-modules.h:58
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:81
TmModule_::ThreadDeinit
TmEcode(* ThreadDeinit)(ThreadVars *, void *)
Definition: tm-modules.h:53
Packet_::datalink
int datalink
Definition: decode.h:652
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1366
DecodeRegisterPerfCounters
void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv)
Definition: decode.c:634
SCTIME_FROM_SECS
#define SCTIME_FROM_SECS(s)
Definition: util-time.h:69
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:52
DagFlags_::rxerror
uint8_t rxerror
Definition: source-erf-file.c:54
SCTIME_ADD_USECS
#define SCTIME_ADD_USECS(ts, us)
Definition: util-time.h:59
DagFlags_::direction
uint8_t direction
Definition: source-erf-file.c:57
TmModule_::PktAcqBreakLoop
TmEcode(* PktAcqBreakLoop)(ThreadVars *, void *)
Definition: tm-modules.h:61
Packet_::ts
SCTime_t ts
Definition: decode.h:570
SCEnter
#define SCEnter(...)
Definition: util-debug.h:284
GET_PKT_DATA
#define GET_PKT_DATA(p)
Definition: decode.h:210
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
ERF_ETH_PAD_LEN
#define ERF_ETH_PAD_LEN
Definition: source-erf-file.c:36
TmModule_::Func
TmEcode(* Func)(ThreadVars *, Packet *, void *)
Definition: tm-modules.h:56
DagRecord_::rlen
uint16_t rlen
Definition: source-erf-file.c:64
DagFlags_
Definition: source-erf-file.c:50
ErfFileThreadVars
ErfFileThreadVars
Definition: source-erf-file.c:79
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:325
PacketPoolWait
void PacketPoolWait(void)
Definition: tmqh-packetpool.c:71
Packet_
Definition: decode.h:516
TM_FLAG_DECODE_TM
#define TM_FLAG_DECODE_TM
Definition: tm-modules.h:33
tmm_modules
TmModule tmm_modules[TMM_SIZE]
Definition: tm-modules.c:29
GET_PKT_LEN
#define GET_PKT_LEN(p)
Definition: decode.h:209
TmSlot_
Definition: tm-threads.h:53
DagFlags
struct DagFlags_ DagFlags
TmEcode
TmEcode
Definition: tm-threads-common.h:80
TMM_DECODEERFFILE
@ TMM_DECODEERFFILE
Definition: tm-threads-common.h:49
TmModule_::name
const char * name
Definition: tm-modules.h:48
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:232
TM_FLAG_RECEIVE_TM
#define TM_FLAG_RECEIVE_TM
Definition: tm-modules.h:32
TmModuleReceiveErfFileRegister
void TmModuleReceiveErfFileRegister(void)
Register the ERF file receiver (reader) module.
Definition: source-erf-file.c:95
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:34
ReceiveErfFileThreadDeinit
TmEcode ReceiveErfFileThreadDeinit(ThreadVars *, void *)
__attribute__
struct DagRecord_ __attribute__((packed))
DNP3 application object header.
Definition: source-erf-file.c:67
ERF_EXT_LEN
#define ERF_EXT_LEN
Definition: source-erf-file.c:35
DecodeThreadVarsFree
void DecodeThreadVarsFree(ThreadVars *tv, DecodeThreadVars *dtv)
Definition: decode.c:848
SCNtohs
#define SCNtohs(x)
Definition: suricata-common.h:439
suricata-common.h
DagFlags_::dserror
uint8_t dserror
Definition: source-erf-file.c:55
TmModule_::ThreadInit
TmEcode(* ThreadInit)(ThreadVars *, const void *, void **)
Definition: tm-modules.h:51
EngineStop
void EngineStop(void)
make sure threads can stop the engine by calling this function. Purpose: pcap file mode needs to be a...
Definition: suricata.c:492
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:33
TmModule_::ThreadExitPrintStats
void(* ThreadExitPrintStats)(ThreadVars *, void *)
Definition: tm-modules.h:52
MAX_PACKET_SIZE
#define MAX_PACKET_SIZE
Definition: source-af-packet.h:81
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:274
DagFlags_::vlen
uint8_t vlen
Definition: source-erf-file.c:52
DagRecord_::wlen
uint16_t wlen
Definition: source-erf-file.c:66
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:995
MAX_PAYLOAD_SIZE
#define MAX_PAYLOAD_SIZE
Definition: decode.h:714
DagFlags_::reserved
uint8_t reserved
Definition: source-erf-file.c:56
source-erf-file.h
DecodeThreadVarsAlloc
DecodeThreadVars * DecodeThreadVarsAlloc(ThreadVars *tv)
Alloc and setup DecodeThreadVars.
Definition: decode.c:830
DagFlags_::iface
uint8_t iface
Definition: source-erf-file.c:51
DagRecord_
Definition: source-erf-file.c:60
suricata.h
ReceiveErfFileThreadInit
TmEcode ReceiveErfFileThreadInit(ThreadVars *, const void *, void **)
Initialize the ERF receiver thread.
Definition: source-erf-file.c:289
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:288
ReceiveErfFileLoop
TmEcode ReceiveErfFileLoop(ThreadVars *, void *, void *)
ERF file reading loop.
Definition: source-erf-file.c:127
PacketGetFromQueueOrAlloc
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:299
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
TmModule_::flags
uint8_t flags
Definition: tm-modules.h:80
DecodeUpdatePacketCounters
void DecodeUpdatePacketCounters(ThreadVars *tv, const DecodeThreadVars *dtv, const Packet *p)
Definition: decode.c:798
suricata_ctl_flags
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:176
rlen
uint16_t rlen
Definition: source-erf-file.c:71