]> git.ipfire.org Git - people/ms/suricata.git/blame - src/source-pcap-file.c
Custom logging feature for log-httplog
[people/ms/suricata.git] / src / source-pcap-file.c
CommitLineData
2eef905c 1/* Copyright (C) 2007-2010 Open Information Security Foundation
ce019275
WM
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.
9c7f5afa 11 *
ce019275
WM
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
9c7f5afa 20 *
ce019275 21 * \author Victor Julien <victor@inliniac.net>
9c7f5afa 22 *
ce019275 23 * File based pcap packet acquisition support
9c7f5afa
VJ
24 */
25
af992242 26#if LIBPCAP_VERSION_MAJOR == 1
9c7f5afa 27#include <pcap/pcap.h>
af992242
WM
28#else
29#include <pcap.h>
ba46c16a 30#endif /* LIBPCAP_VERSION_MAJOR */
9c7f5afa 31
ecf86f9c
VJ
32#include "suricata-common.h"
33#include "suricata.h"
9c7f5afa
VJ
34#include "decode.h"
35#include "packet-queue.h"
36#include "threads.h"
37#include "threadvars.h"
38#include "tm-queuehandlers.h"
9c7f5afa
VJ
39#include "source-pcap-file.h"
40#include "util-time.h"
9ececacd 41#include "util-debug.h"
ba46c16a 42#include "conf.h"
29d51a61 43#include "util-error.h"
070ed778 44#include "util-privs.h"
6519a86e 45#include "tmqh-packetpool.h"
b753ecce
VJ
46#include "tm-threads.h"
47#include "util-optimize.h"
5133098b 48#include "flow-manager.h"
41e9dba2 49#include "util-profiling.h"
ba46c16a 50
b657705d 51extern uint8_t suricata_ctl_flags;
7142fdb7 52extern int max_pending_packets;
53acf089 53
b753ecce 54//static int pcap_max_read_packets = 0;
9c7f5afa
VJ
55
56typedef struct PcapFileGlobalVars_ {
57 pcap_t *pcap_handle;
57f71f7e 58 void (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, u_int8_t *, u_int16_t, PacketQueue *);
a4fe9718 59 int datalink;
ba46c16a 60 struct bpf_program filter;
b90ebc1c 61 uint64_t cnt; /** packet counter */
9c7f5afa
VJ
62} PcapFileGlobalVars;
63
4e7df60b 64/** max packets < 65536 */
b753ecce 65//#define PCAP_FILE_MAX_PKTS 256
4e7df60b 66
9c7f5afa
VJ
67typedef struct PcapFileThreadVars_
68{
69 /* counters */
fa5939ca
BR
70 uint32_t pkts;
71 uint64_t bytes;
9c7f5afa
VJ
72
73 ThreadVars *tv;
b753ecce 74 TmSlot *slot;
4e7df60b 75
67cea099
VJ
76 /** callback result -- set if one of the thread module failed. */
77 int cb_result;
78
4e7df60b 79 uint8_t done;
b753ecce 80 uint32_t errs;
9c7f5afa
VJ
81} PcapFileThreadVars;
82
e0aacac4 83static PcapFileGlobalVars pcap_g;
9c7f5afa 84
b753ecce
VJ
85TmEcode ReceivePcapFileLoop(ThreadVars *, void *, void *);
86
40b8afdd 87TmEcode ReceivePcapFileThreadInit(ThreadVars *, void *, void **);
9c7f5afa 88void ReceivePcapFileThreadExitStats(ThreadVars *, void *);
40b8afdd 89TmEcode ReceivePcapFileThreadDeinit(ThreadVars *, void *);
9c7f5afa 90
4e7df60b 91TmEcode DecodePcapFile(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
40b8afdd 92TmEcode DecodePcapFileThreadInit(ThreadVars *, void *, void **);
9c7f5afa
VJ
93
94void TmModuleReceivePcapFileRegister (void) {
e0aacac4
VJ
95 memset(&pcap_g, 0x00, sizeof(pcap_g));
96
9c7f5afa 97 tmm_modules[TMM_RECEIVEPCAPFILE].name = "ReceivePcapFile";
a3910884 98 tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit;
b753ecce
VJ
99 tmm_modules[TMM_RECEIVEPCAPFILE].Func = NULL;
100 tmm_modules[TMM_RECEIVEPCAPFILE].PktAcqLoop = ReceivePcapFileLoop;
a3910884
VJ
101 tmm_modules[TMM_RECEIVEPCAPFILE].ThreadExitPrintStats = ReceivePcapFileThreadExitStats;
102 tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit = NULL;
9c7f5afa 103 tmm_modules[TMM_RECEIVEPCAPFILE].RegisterTests = NULL;
070ed778 104 tmm_modules[TMM_RECEIVEPCAPFILE].cap_flags = 0;
3f1c4efc 105 tmm_modules[TMM_RECEIVEPCAPFILE].flags = TM_FLAG_RECEIVE_TM;
9c7f5afa
VJ
106}
107
108void TmModuleDecodePcapFileRegister (void) {
109 tmm_modules[TMM_DECODEPCAPFILE].name = "DecodePcapFile";
a3910884 110 tmm_modules[TMM_DECODEPCAPFILE].ThreadInit = DecodePcapFileThreadInit;
9c7f5afa 111 tmm_modules[TMM_DECODEPCAPFILE].Func = DecodePcapFile;
a3910884
VJ
112 tmm_modules[TMM_DECODEPCAPFILE].ThreadExitPrintStats = NULL;
113 tmm_modules[TMM_DECODEPCAPFILE].ThreadDeinit = NULL;
9c7f5afa 114 tmm_modules[TMM_DECODEPCAPFILE].RegisterTests = NULL;
070ed778 115 tmm_modules[TMM_DECODEPCAPFILE].cap_flags = 0;
bc6cf438 116 tmm_modules[TMM_DECODEPCAPFILE].flags = TM_FLAG_DECODE_TM;
9c7f5afa
VJ
117}
118
b753ecce 119void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt) {
29d51a61 120 SCEnter();
c5e15213 121
9c7f5afa 122 PcapFileThreadVars *ptv = (PcapFileThreadVars *)user;
b753ecce 123 Packet *p = PacketGetFromQueueOrAlloc();
9c7f5afa 124
b753ecce 125 if (unlikely(p == NULL)) {
e3fc53ec 126 SCReturn;
4e7df60b 127 }
41e9dba2 128 PACKET_PROFILING_TMM_START(p, TMM_RECEIVEPCAPFILE);
9c7f5afa
VJ
129
130 p->ts.tv_sec = h->ts.tv_sec;
131 p->ts.tv_usec = h->ts.tv_usec;
9ececacd 132 SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec);
a4fe9718 133 p->datalink = pcap_g.datalink;
820b0ded 134 p->pcap_cnt = ++pcap_g.cnt;
9c7f5afa
VJ
135
136 ptv->pkts++;
137 ptv->bytes += h->caplen;
138
88559901
EL
139 if (unlikely(PacketCopyData(p, pkt, h->caplen))) {
140 TmqhOutputPacketpool(ptv->tv, p);
41e9dba2 141 PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE);
dd038c19 142 SCReturn;
88559901 143 }
41e9dba2 144 PACKET_PROFILING_TMM_END(p, TMM_RECEIVEPCAPFILE);
c5e15213 145
67cea099
VJ
146 if (TmThreadsSlotProcessPkt(ptv->tv, ptv->slot, p) != TM_ECODE_OK) {
147 pcap_breakloop(pcap_g.pcap_handle);
148 ptv->cb_result = TM_ECODE_FAILED;
149 }
4e7df60b 150
c5e15213 151 SCReturn;
9c7f5afa
VJ
152}
153
c5e15213 154/**
b753ecce 155 * \brief Main PCAP file reading Loop function
c5e15213 156 */
b753ecce 157TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot) {
53acf089 158 uint16_t packet_q_len = 0;
c5e15213 159 PcapFileThreadVars *ptv = (PcapFileThreadVars *)data;
b753ecce
VJ
160 TmSlot *s = (TmSlot *)slot;
161 ptv->slot = s->slot_next;
67cea099 162 ptv->cb_result = TM_ECODE_OK;
b753ecce 163 int r;
4e7df60b 164
b753ecce 165 SCEnter();
1d74797b 166
b753ecce
VJ
167 while (1) {
168 if (suricata_ctl_flags & SURICATA_STOP ||
169 suricata_ctl_flags & SURICATA_KILL)
170 {
de1d002e 171 SCReturnInt(TM_ECODE_OK);
e3fc53ec 172 }
1d74797b 173
b753ecce
VJ
174 /* make sure we have at least one packet in the packet pool, to prevent
175 * us from alloc'ing packets at line rate */
176 do {
177 packet_q_len = PacketPoolSize();
178 if (unlikely(packet_q_len == 0)) {
179 PacketPoolWait();
180 }
181 } while (packet_q_len == 0);
182
183 /* Right now we just support reading packets one at a time. */
184 r = pcap_dispatch(pcap_g.pcap_handle, (int)packet_q_len,
185 (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv);
67cea099 186 if (unlikely(r == -1)) {
b753ecce
VJ
187 SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
188 r, pcap_geterr(pcap_g.pcap_handle));
189
190 /* in the error state we just kill the engine */
191 EngineKill();
192 SCReturnInt(TM_ECODE_FAILED);
193 } else if (unlikely(r == 0)) {
194 SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r);
195
196 EngineStop();
197 break;
67cea099
VJ
198 } else if (ptv->cb_result == TM_ECODE_FAILED) {
199 SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed");
200 EngineKill();
201 SCReturnInt(TM_ECODE_FAILED);
4e7df60b 202 }
d68f182e 203 SCPerfSyncCountersIfSignalled(tv, 0);
4e7df60b
VJ
204 }
205
29d51a61 206 SCReturnInt(TM_ECODE_OK);
9c7f5afa
VJ
207}
208
40b8afdd 209TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) {
29d51a61 210 SCEnter();
e0aacac4 211 char *tmpbpfstring = NULL;
9c7f5afa 212 if (initdata == NULL) {
29d51a61
PR
213 SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL");
214 SCReturnInt(TM_ECODE_FAILED);
9c7f5afa
VJ
215 }
216
e0aacac4
VJ
217 SCLogInfo("reading pcap file %s", (char *)initdata);
218
25a3a5c6 219 PcapFileThreadVars *ptv = SCMalloc(sizeof(PcapFileThreadVars));
9f4fae5b 220 if (ptv == NULL)
29d51a61 221 SCReturnInt(TM_ECODE_FAILED);
9c7f5afa
VJ
222 memset(ptv, 0, sizeof(PcapFileThreadVars));
223
8c3d0c05 224 char errbuf[PCAP_ERRBUF_SIZE] = "";
9c7f5afa
VJ
225 pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf);
226 if (pcap_g.pcap_handle == NULL) {
52936818 227 SCLogError(SC_ERR_FOPEN, "%s\n", errbuf);
25a3a5c6 228 SCFree(ptv);
52936818 229 exit(EXIT_FAILURE);
9c7f5afa
VJ
230 }
231
ba46c16a 232 if (ConfGet("bpf-filter", &tmpbpfstring) != 1) {
e0aacac4 233 SCLogDebug("could not get bpf or none specified");
ba46c16a 234 } else {
e0aacac4 235 SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring);
ba46c16a
WM
236
237 if(pcap_compile(pcap_g.pcap_handle,&pcap_g.filter,tmpbpfstring,1,0) < 0) {
238 SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(pcap_g.pcap_handle));
25a3a5c6 239 SCFree(ptv);
e0aacac4 240 return TM_ECODE_FAILED;
ba46c16a
WM
241 }
242
243 if(pcap_setfilter(pcap_g.pcap_handle,&pcap_g.filter) < 0) {
244 SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(pcap_g.pcap_handle));
25a3a5c6 245 SCFree(ptv);
e0aacac4 246 return TM_ECODE_FAILED;
ba46c16a
WM
247 }
248 }
249
a4fe9718 250 pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle);
e0aacac4
VJ
251 SCLogDebug("datalink %" PRId32 "", pcap_g.datalink);
252
a4fe9718 253 switch(pcap_g.datalink) {
dec11038
BS
254 case LINKTYPE_LINUX_SLL:
255 pcap_g.Decoder = DecodeSll;
256 break;
257 case LINKTYPE_ETHERNET:
258 pcap_g.Decoder = DecodeEthernet;
259 break;
260 case LINKTYPE_PPP:
261 pcap_g.Decoder = DecodePPP;
262 break;
8a643213
WM
263 case LINKTYPE_RAW:
264 pcap_g.Decoder = DecodeRaw;
265 break;
266
dec11038 267 default:
25a3a5c6
PR
268 SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not "
269 "(yet) supported in module PcapFile.\n", pcap_g.datalink);
270 SCFree(ptv);
29d51a61 271 SCReturnInt(TM_ECODE_FAILED);
9c7f5afa
VJ
272 }
273
274 ptv->tv = tv;
275 *data = (void *)ptv;
29d51a61 276 SCReturnInt(TM_ECODE_OK);
9c7f5afa
VJ
277}
278
279void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) {
29d51a61 280 SCEnter();
9c7f5afa
VJ
281 PcapFileThreadVars *ptv = (PcapFileThreadVars *)data;
282
28e15be5 283 SCLogInfo("Pcap-file module read %" PRIu32 " packets, %" PRIu64 " bytes", ptv->pkts, ptv->bytes);
9c7f5afa
VJ
284 return;
285}
286
40b8afdd 287TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data) {
29d51a61
PR
288 SCEnter();
289 SCReturnInt(TM_ECODE_OK);
9c7f5afa
VJ
290}
291
5133098b
AS
292double prev_signaled_ts = 0;
293
4e7df60b 294TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
d0e70309 295{
29d51a61 296 SCEnter();
244f5d54
AS
297 DecodeThreadVars *dtv = (DecodeThreadVars *)data;
298
57f71f7e 299 /* update counters */
ceb7e495 300 SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca);
8beef4a9
AS
301 SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca);
302
dd038c19 303 SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, GET_PKT_LEN(p));
4cacb1e9 304#if 0
dd038c19 305 SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, GET_PKT_LEN(p));
8beef4a9 306 SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca,
dd038c19 307 (GET_PKT_LEN(p) * 8)/1000000.0 );
4cacb1e9 308#endif
dd038c19
EL
309 SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p));
310 SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, GET_PKT_LEN(p));
d0e70309 311
5133098b 312 double curr_ts = p->ts.tv_sec + p->ts.tv_usec / 1000.0;
0150e66e 313 if (curr_ts < prev_signaled_ts || (curr_ts - prev_signaled_ts) > 60.0) {
5133098b
AS
314 prev_signaled_ts = curr_ts;
315 FlowWakeupFlowManagerThread();
316 }
317
6943a7eb
VJ
318 /* update the engine time representation based on the timestamp
319 * of the packet. */
320 TimeSet(&p->ts);
321
9c7f5afa 322 /* call the decoder */
dd038c19 323 pcap_g.Decoder(tv, dtv, p, GET_PKT_DATA(p), GET_PKT_LEN(p), pq);
244f5d54 324
29d51a61 325 SCReturnInt(TM_ECODE_OK);
9c7f5afa
VJ
326}
327
40b8afdd 328TmEcode DecodePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data)
d0e70309 329{
29d51a61 330 SCEnter();
244f5d54 331 DecodeThreadVars *dtv = NULL;
8cc525c9 332 dtv = DecodeThreadVarsAlloc();
244f5d54 333
8cc525c9 334 if (dtv == NULL)
29d51a61 335 SCReturnInt(TM_ECODE_FAILED);
244f5d54 336
8beef4a9 337 DecodeRegisterPerfCounters(dtv, tv);
244f5d54
AS
338
339 *data = (void *)dtv;
ceb7e495 340
29d51a61 341 SCReturnInt(TM_ECODE_OK);
d0e70309
AS
342}
343
9c7f5afa
VJ
344/* eof */
345