]>
Commit | Line | Data |
---|---|---|
9c7f5afa VJ |
1 | /* Copyright (c) 2009 Victor Julien <victor@inliniac.net> */ |
2 | ||
3 | /* TODO | |
4 | * | |
5 | * | |
6 | * | |
7 | */ | |
8 | ||
af992242 | 9 | #if LIBPCAP_VERSION_MAJOR == 1 |
9c7f5afa | 10 | #include <pcap/pcap.h> |
af992242 WM |
11 | #else |
12 | #include <pcap.h> | |
ba46c16a | 13 | #endif /* LIBPCAP_VERSION_MAJOR */ |
9c7f5afa | 14 | |
ecf86f9c VJ |
15 | #include "suricata-common.h" |
16 | #include "suricata.h" | |
9c7f5afa VJ |
17 | #include "decode.h" |
18 | #include "packet-queue.h" | |
19 | #include "threads.h" | |
20 | #include "threadvars.h" | |
21 | #include "tm-queuehandlers.h" | |
22 | #include "tm-modules.h" | |
23 | #include "source-pcap-file.h" | |
24 | #include "util-time.h" | |
9ececacd | 25 | #include "util-debug.h" |
ba46c16a | 26 | #include "conf.h" |
29d51a61 | 27 | #include "util-error.h" |
070ed778 | 28 | #include "util-privs.h" |
ba46c16a | 29 | |
7142fdb7 | 30 | extern int max_pending_packets; |
9c7f5afa VJ |
31 | |
32 | typedef struct PcapFileGlobalVars_ { | |
33 | pcap_t *pcap_handle; | |
57f71f7e | 34 | void (*Decoder)(ThreadVars *, DecodeThreadVars *, Packet *, u_int8_t *, u_int16_t, PacketQueue *); |
a4fe9718 | 35 | int datalink; |
ba46c16a | 36 | struct bpf_program filter; |
9c7f5afa VJ |
37 | } PcapFileGlobalVars; |
38 | ||
39 | typedef struct PcapFileThreadVars_ | |
40 | { | |
41 | /* counters */ | |
fa5939ca BR |
42 | uint32_t pkts; |
43 | uint64_t bytes; | |
44 | uint32_t errs; | |
9c7f5afa VJ |
45 | |
46 | ThreadVars *tv; | |
c53dfea3 VJ |
47 | |
48 | Packet *in_p; | |
9c7f5afa VJ |
49 | } PcapFileThreadVars; |
50 | ||
e0aacac4 | 51 | static PcapFileGlobalVars pcap_g; |
9c7f5afa | 52 | |
40b8afdd GS |
53 | TmEcode ReceivePcapFile(ThreadVars *, Packet *, void *, PacketQueue *); |
54 | TmEcode ReceivePcapFileThreadInit(ThreadVars *, void *, void **); | |
9c7f5afa | 55 | void ReceivePcapFileThreadExitStats(ThreadVars *, void *); |
40b8afdd | 56 | TmEcode ReceivePcapFileThreadDeinit(ThreadVars *, void *); |
9c7f5afa | 57 | |
40b8afdd GS |
58 | TmEcode DecodePcapFile(ThreadVars *, Packet *, void *, PacketQueue *); |
59 | TmEcode DecodePcapFileThreadInit(ThreadVars *, void *, void **); | |
9c7f5afa VJ |
60 | |
61 | void TmModuleReceivePcapFileRegister (void) { | |
e0aacac4 VJ |
62 | memset(&pcap_g, 0x00, sizeof(pcap_g)); |
63 | ||
9c7f5afa | 64 | tmm_modules[TMM_RECEIVEPCAPFILE].name = "ReceivePcapFile"; |
a3910884 | 65 | tmm_modules[TMM_RECEIVEPCAPFILE].ThreadInit = ReceivePcapFileThreadInit; |
9c7f5afa | 66 | tmm_modules[TMM_RECEIVEPCAPFILE].Func = ReceivePcapFile; |
a3910884 VJ |
67 | tmm_modules[TMM_RECEIVEPCAPFILE].ThreadExitPrintStats = ReceivePcapFileThreadExitStats; |
68 | tmm_modules[TMM_RECEIVEPCAPFILE].ThreadDeinit = NULL; | |
9c7f5afa | 69 | tmm_modules[TMM_RECEIVEPCAPFILE].RegisterTests = NULL; |
070ed778 | 70 | tmm_modules[TMM_RECEIVEPCAPFILE].cap_flags = 0; |
9c7f5afa VJ |
71 | } |
72 | ||
73 | void TmModuleDecodePcapFileRegister (void) { | |
74 | tmm_modules[TMM_DECODEPCAPFILE].name = "DecodePcapFile"; | |
a3910884 | 75 | tmm_modules[TMM_DECODEPCAPFILE].ThreadInit = DecodePcapFileThreadInit; |
9c7f5afa | 76 | tmm_modules[TMM_DECODEPCAPFILE].Func = DecodePcapFile; |
a3910884 VJ |
77 | tmm_modules[TMM_DECODEPCAPFILE].ThreadExitPrintStats = NULL; |
78 | tmm_modules[TMM_DECODEPCAPFILE].ThreadDeinit = NULL; | |
9c7f5afa | 79 | tmm_modules[TMM_DECODEPCAPFILE].RegisterTests = NULL; |
070ed778 | 80 | tmm_modules[TMM_DECODEPCAPFILE].cap_flags = 0; |
9c7f5afa VJ |
81 | } |
82 | ||
83 | void PcapFileCallback(char *user, struct pcap_pkthdr *h, u_char *pkt) { | |
29d51a61 | 84 | SCEnter(); |
c5e15213 | 85 | |
9c7f5afa | 86 | PcapFileThreadVars *ptv = (PcapFileThreadVars *)user; |
9c7f5afa | 87 | |
e26833be | 88 | SCMutexLock(&mutex_pending); |
7142fdb7 | 89 | if (pending > max_pending_packets) { |
e26833be | 90 | SCondWait(&cond_pending, &mutex_pending); |
9c7f5afa | 91 | } |
e26833be | 92 | SCMutexUnlock(&mutex_pending); |
9c7f5afa | 93 | |
c53dfea3 | 94 | Packet *p = ptv->in_p; |
9c7f5afa VJ |
95 | |
96 | p->ts.tv_sec = h->ts.tv_sec; | |
97 | p->ts.tv_usec = h->ts.tv_usec; | |
9ececacd | 98 | SCLogDebug("p->ts.tv_sec %"PRIuMAX"", (uintmax_t)p->ts.tv_sec); |
9c7f5afa | 99 | TimeSet(&p->ts); |
a4fe9718 | 100 | p->datalink = pcap_g.datalink; |
9c7f5afa VJ |
101 | |
102 | ptv->pkts++; | |
103 | ptv->bytes += h->caplen; | |
104 | ||
105 | p->pktlen = h->caplen; | |
106 | memcpy(p->pkt, pkt, p->pktlen); | |
fa5939ca | 107 | //printf("PcapFileCallback: p->pktlen: %" PRIu32 " (pkt %02x, p->pkt %02x)\n", p->pktlen, *pkt, *p->pkt); |
c5e15213 VJ |
108 | |
109 | SCReturn; | |
9c7f5afa VJ |
110 | } |
111 | ||
c5e15213 VJ |
112 | /** |
113 | * \brief Main PCAP file reading function | |
114 | */ | |
40b8afdd | 115 | TmEcode ReceivePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) { |
29d51a61 | 116 | SCEnter(); |
9c7f5afa | 117 | |
c5e15213 | 118 | PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; |
c53dfea3 VJ |
119 | ptv->in_p = p; |
120 | ||
53c9276d | 121 | /* Right now we just support reading packets one at a time. */ |
c5e15213 VJ |
122 | int r = pcap_dispatch(pcap_g.pcap_handle, 1, |
123 | (pcap_handler)PcapFileCallback, (u_char *)ptv); | |
53c9276d | 124 | if (r < 0) { |
c5e15213 VJ |
125 | SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s", |
126 | r, pcap_geterr(pcap_g.pcap_handle)); | |
127 | ||
53c9276d | 128 | EngineStop(); |
c5e15213 | 129 | SCReturnInt(TM_ECODE_FAILED); |
53c9276d | 130 | } else if (r == 0) { |
7dcc1daa | 131 | SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r); |
c5e15213 | 132 | |
9c7f5afa | 133 | EngineStop(); |
29d51a61 | 134 | SCReturnInt(TM_ECODE_FAILED); |
9c7f5afa VJ |
135 | } |
136 | ||
29d51a61 | 137 | SCReturnInt(TM_ECODE_OK); |
9c7f5afa VJ |
138 | } |
139 | ||
40b8afdd | 140 | TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) { |
29d51a61 | 141 | SCEnter(); |
e0aacac4 | 142 | char *tmpbpfstring = NULL; |
9c7f5afa | 143 | if (initdata == NULL) { |
29d51a61 PR |
144 | SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL"); |
145 | SCReturnInt(TM_ECODE_FAILED); | |
9c7f5afa VJ |
146 | } |
147 | ||
e0aacac4 VJ |
148 | SCLogInfo("reading pcap file %s", (char *)initdata); |
149 | ||
25a3a5c6 | 150 | PcapFileThreadVars *ptv = SCMalloc(sizeof(PcapFileThreadVars)); |
9c7f5afa | 151 | if (ptv == NULL) { |
29d51a61 PR |
152 | SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory for PcapFileThreadVars"); |
153 | SCReturnInt(TM_ECODE_FAILED); | |
9c7f5afa VJ |
154 | } |
155 | memset(ptv, 0, sizeof(PcapFileThreadVars)); | |
156 | ||
8c3d0c05 | 157 | char errbuf[PCAP_ERRBUF_SIZE] = ""; |
9c7f5afa VJ |
158 | pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf); |
159 | if (pcap_g.pcap_handle == NULL) { | |
52936818 | 160 | SCLogError(SC_ERR_FOPEN, "%s\n", errbuf); |
25a3a5c6 | 161 | SCFree(ptv); |
52936818 | 162 | exit(EXIT_FAILURE); |
9c7f5afa VJ |
163 | } |
164 | ||
ba46c16a | 165 | if (ConfGet("bpf-filter", &tmpbpfstring) != 1) { |
e0aacac4 | 166 | SCLogDebug("could not get bpf or none specified"); |
ba46c16a | 167 | } else { |
e0aacac4 | 168 | SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring); |
ba46c16a WM |
169 | |
170 | if(pcap_compile(pcap_g.pcap_handle,&pcap_g.filter,tmpbpfstring,1,0) < 0) { | |
171 | SCLogError(SC_ERR_BPF,"bpf compilation error %s",pcap_geterr(pcap_g.pcap_handle)); | |
25a3a5c6 | 172 | SCFree(ptv); |
e0aacac4 | 173 | return TM_ECODE_FAILED; |
ba46c16a WM |
174 | } |
175 | ||
176 | if(pcap_setfilter(pcap_g.pcap_handle,&pcap_g.filter) < 0) { | |
177 | SCLogError(SC_ERR_BPF,"could not set bpf filter %s",pcap_geterr(pcap_g.pcap_handle)); | |
25a3a5c6 | 178 | SCFree(ptv); |
e0aacac4 | 179 | return TM_ECODE_FAILED; |
ba46c16a WM |
180 | } |
181 | } | |
182 | ||
a4fe9718 | 183 | pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle); |
e0aacac4 VJ |
184 | SCLogDebug("datalink %" PRId32 "", pcap_g.datalink); |
185 | ||
a4fe9718 | 186 | switch(pcap_g.datalink) { |
dec11038 BS |
187 | case LINKTYPE_LINUX_SLL: |
188 | pcap_g.Decoder = DecodeSll; | |
189 | break; | |
190 | case LINKTYPE_ETHERNET: | |
191 | pcap_g.Decoder = DecodeEthernet; | |
192 | break; | |
193 | case LINKTYPE_PPP: | |
194 | pcap_g.Decoder = DecodePPP; | |
195 | break; | |
8a643213 WM |
196 | case LINKTYPE_RAW: |
197 | pcap_g.Decoder = DecodeRaw; | |
198 | break; | |
199 | ||
dec11038 | 200 | default: |
25a3a5c6 PR |
201 | SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not " |
202 | "(yet) supported in module PcapFile.\n", pcap_g.datalink); | |
203 | SCFree(ptv); | |
29d51a61 | 204 | SCReturnInt(TM_ECODE_FAILED); |
9c7f5afa VJ |
205 | } |
206 | ||
207 | ptv->tv = tv; | |
208 | *data = (void *)ptv; | |
29d51a61 | 209 | SCReturnInt(TM_ECODE_OK); |
9c7f5afa VJ |
210 | } |
211 | ||
212 | void ReceivePcapFileThreadExitStats(ThreadVars *tv, void *data) { | |
29d51a61 | 213 | SCEnter(); |
9c7f5afa VJ |
214 | PcapFileThreadVars *ptv = (PcapFileThreadVars *)data; |
215 | ||
53c9276d | 216 | SCLogInfo(" - (%s) Packets %" PRIu32 ", bytes %" PRIu64 ".", tv->name, ptv->pkts, ptv->bytes); |
9c7f5afa VJ |
217 | return; |
218 | } | |
219 | ||
40b8afdd | 220 | TmEcode ReceivePcapFileThreadDeinit(ThreadVars *tv, void *data) { |
29d51a61 PR |
221 | SCEnter(); |
222 | SCReturnInt(TM_ECODE_OK); | |
9c7f5afa VJ |
223 | } |
224 | ||
40b8afdd | 225 | TmEcode DecodePcapFile(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq) |
d0e70309 | 226 | { |
29d51a61 | 227 | SCEnter(); |
244f5d54 AS |
228 | DecodeThreadVars *dtv = (DecodeThreadVars *)data; |
229 | ||
57f71f7e | 230 | /* update counters */ |
ceb7e495 | 231 | SCPerfCounterIncr(dtv->counter_pkts, tv->sc_perf_pca); |
8beef4a9 AS |
232 | SCPerfCounterIncr(dtv->counter_pkts_per_sec, tv->sc_perf_pca); |
233 | ||
ceb7e495 | 234 | SCPerfCounterAddUI64(dtv->counter_bytes, tv->sc_perf_pca, p->pktlen); |
8beef4a9 AS |
235 | SCPerfCounterAddDouble(dtv->counter_bytes_per_sec, tv->sc_perf_pca, p->pktlen); |
236 | SCPerfCounterAddDouble(dtv->counter_mbit_per_sec, tv->sc_perf_pca, | |
237 | (p->pktlen * 8)/1000000.0 ); | |
238 | ||
ceb7e495 AS |
239 | SCPerfCounterAddUI64(dtv->counter_avg_pkt_size, tv->sc_perf_pca, p->pktlen); |
240 | SCPerfCounterSetUI64(dtv->counter_max_pkt_size, tv->sc_perf_pca, p->pktlen); | |
d0e70309 | 241 | |
9c7f5afa | 242 | /* call the decoder */ |
57f71f7e | 243 | pcap_g.Decoder(tv, dtv, p, p->pkt, p->pktlen, pq); |
244f5d54 | 244 | |
29d51a61 | 245 | SCReturnInt(TM_ECODE_OK); |
9c7f5afa VJ |
246 | } |
247 | ||
40b8afdd | 248 | TmEcode DecodePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data) |
d0e70309 | 249 | { |
29d51a61 | 250 | SCEnter(); |
244f5d54 AS |
251 | DecodeThreadVars *dtv = NULL; |
252 | ||
25a3a5c6 | 253 | if ( (dtv = SCMalloc(sizeof(DecodeThreadVars))) == NULL) { |
29d51a61 PR |
254 | SCLogError(SC_ERR_MEM_ALLOC, "Error Allocating memory for DecodeThreadVars"); |
255 | SCReturnInt(TM_ECODE_FAILED); | |
244f5d54 AS |
256 | } |
257 | memset(dtv, 0, sizeof(DecodeThreadVars)); | |
258 | ||
8beef4a9 | 259 | DecodeRegisterPerfCounters(dtv, tv); |
244f5d54 AS |
260 | |
261 | *data = (void *)dtv; | |
ceb7e495 | 262 | |
29d51a61 | 263 | SCReturnInt(TM_ECODE_OK); |
d0e70309 AS |
264 | } |
265 | ||
9c7f5afa VJ |
266 | /* eof */ |
267 |