suricata
source-pcap-file-helper.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2020 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 Danny Browning <danny.browning@protectwise.com>
22 *
23 * File based pcap packet acquisition support
24 */
25
27#include "suricata.h"
28#include "util-datalink.h"
29#include "util-checksum.h"
30#include "util-profiling.h"
31#include "source-pcap-file.h"
33
34extern uint32_t max_pending_packets;
36
37static void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt);
38
40{
41 if (pfv != NULL) {
42 if (pfv->pcap_handle != NULL) {
43 pcap_close(pfv->pcap_handle);
44 pfv->pcap_handle = NULL;
45 }
46 if (pfv->filename != NULL) {
47 if (pfv->shared != NULL && pfv->shared->should_delete) {
48 SCLogDebug("Deleting pcap file %s", pfv->filename);
49 if (unlink(pfv->filename) != 0) {
50 SCLogWarning("Failed to delete %s: %s", pfv->filename, strerror(errno));
51 }
52 }
53 SCFree(pfv->filename);
54 pfv->filename = NULL;
55 }
56 pfv->shared = NULL;
57 SCFree(pfv);
58 }
59}
60
61void PcapFileCallbackLoop(char *user, struct pcap_pkthdr *h, u_char *pkt)
62{
63 SCEnter();
64#ifdef DEBUG
65 if (unlikely((pcap_g.cnt + 1ULL) == g_eps_pcap_packet_loss)) {
66 SCLogNotice("skipping packet %" PRIu64, g_eps_pcap_packet_loss);
67 pcap_g.cnt++;
69 }
70#endif
73
74 if (unlikely(p == NULL)) {
76 }
78
81 SCLogDebug("p->ts.tv_sec %" PRIuMAX "", (uintmax_t)SCTIME_SECS(p->ts));
82 p->datalink = ptv->datalink;
83 p->pcap_cnt = ++pcap_g.cnt;
84
86 ptv->shared->pkts++;
87 ptv->shared->bytes += h->caplen;
88
89 if (unlikely(PacketCopyData(p, pkt, h->caplen))) {
93 }
94
95 /* We only check for checksum disable */
100 SC_ATOMIC_GET(pcap_g.invalid_checksums))) {
103 }
104 }
105
107
108 if (TmThreadsSlotProcessPkt(ptv->shared->tv, ptv->shared->slot, p) != TM_ECODE_OK) {
109 pcap_breakloop(ptv->pcap_handle);
111 }
112
113 SCReturn;
114}
115
116char pcap_filename[PATH_MAX] = "unknown";
117
118const char *PcapFileGetFilename(void)
119{
120 return pcap_filename;
121}
122
123/**
124 * \brief Main PCAP file reading Loop function
125 */
127{
128 SCEnter();
129
130 /* initialize all the thread's initial timestamp */
131 if (likely(ptv->first_pkt_hdr != NULL)) {
133 PcapFileCallbackLoop((char *)ptv, ptv->first_pkt_hdr,
134 (u_char *)ptv->first_pkt_data);
135 ptv->first_pkt_hdr = NULL;
136 ptv->first_pkt_data = NULL;
137 }
138
139 int packet_q_len = 64;
140 TmEcode loop_result = TM_ECODE_OK;
142
143 while (loop_result == TM_ECODE_OK) {
146 }
147
148 /* make sure we have at least one packet in the packet pool, to prevent
149 * us from alloc'ing packets at line rate */
151
152 /* Right now we just support reading packets one at a time. */
153 int r = pcap_dispatch(ptv->pcap_handle, packet_q_len,
154 (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv);
155 if (unlikely(r == -1)) {
156 SCLogError("error code %" PRId32 " %s for %s", r, pcap_geterr(ptv->pcap_handle),
157 ptv->filename);
158 if (ptv->shared->cb_result == TM_ECODE_FAILED) {
160 }
161 loop_result = TM_ECODE_DONE;
162 } else if (unlikely(r == 0)) {
163 SCLogInfo("pcap file %s end of file reached (pcap err code %" PRId32 ")",
164 ptv->filename, r);
165 ptv->shared->files++;
166 loop_result = TM_ECODE_DONE;
167 } else if (ptv->shared->cb_result == TM_ECODE_FAILED) {
168 SCLogError("Pcap callback PcapFileCallbackLoop failed for %s", ptv->filename);
169 loop_result = TM_ECODE_FAILED;
170 }
171 StatsSyncCountersIfSignalled(ptv->shared->tv);
172 }
173
174 SCReturnInt(loop_result);
175}
176
177/** \internal
178 * \brief get the timestamp of the first packet and rewind
179 * \param pfv pcap file variables for storing the timestamp
180 * \retval bool true on success, false on error
181 */
182static bool PeekFirstPacketTimestamp(PcapFileFileVars *pfv)
183{
184 int r = pcap_next_ex(pfv->pcap_handle, &pfv->first_pkt_hdr, &pfv->first_pkt_data);
185 if (r <= 0 || pfv->first_pkt_hdr == NULL) {
186 SCLogError("failed to get first packet timestamp. pcap_next_ex(): %d", r);
187 return false;
188 }
189 /* timestamp in pfv->first_pkt_hdr may not be 'struct timeval' so
190 * do a manual copy of the members. */
191 pfv->first_pkt_ts.tv_sec = pfv->first_pkt_hdr->ts.tv_sec;
192 pfv->first_pkt_ts.tv_usec = pfv->first_pkt_hdr->ts.tv_usec;
193 return true;
194}
195
197{
198 char errbuf[PCAP_ERRBUF_SIZE] = "";
199
200 if(unlikely(pfv->filename == NULL)) {
201 SCLogError("Filename was null");
203 }
204
205 pfv->pcap_handle = pcap_open_offline(pfv->filename, errbuf);
206 if (pfv->pcap_handle == NULL) {
207 SCLogError("%s", errbuf);
209 }
210
211#if defined(HAVE_SETVBUF) && defined(OS_LINUX)
212 if (pcap_g.read_buffer_size > 0) {
213 errno = 0;
214 if (setvbuf(pcap_file(pfv->pcap_handle), pfv->buffer, _IOFBF, pcap_g.read_buffer_size) <
215 0) {
216 SCLogWarning("Failed to setvbuf on PCAP file handle: %s", strerror(errno));
217 }
218 }
219#endif
220
221 if (pfv->shared != NULL && pfv->shared->bpf_string != NULL) {
222 SCLogInfo("using bpf-filter \"%s\"", pfv->shared->bpf_string);
223
224 if (pcap_compile(pfv->pcap_handle, &pfv->filter, pfv->shared->bpf_string, 1, 0) < 0) {
225 SCLogError("bpf compilation error %s for %s", pcap_geterr(pfv->pcap_handle),
226 pfv->filename);
228 }
229
230 if (pcap_setfilter(pfv->pcap_handle, &pfv->filter) < 0) {
231 SCLogError("could not set bpf filter %s for %s", pcap_geterr(pfv->pcap_handle),
232 pfv->filename);
233 pcap_freecode(&pfv->filter);
235 }
236 pcap_freecode(&pfv->filter);
237 }
238
239 pfv->datalink = pcap_datalink(pfv->pcap_handle);
240 SCLogDebug("datalink %" PRId32 "", pfv->datalink);
242
243 if (!PeekFirstPacketTimestamp(pfv))
245
246 DecoderFunc UnusedFnPtr;
247 TmEcode validated = ValidateLinkType(pfv->datalink, &UnusedFnPtr);
248 SCReturnInt(validated);
249}
250
251TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
252{
253 switch (datalink) {
255 *DecoderFn = DecodeSll2;
256 break;
258 *DecoderFn = DecodeSll;
259 break;
261 *DecoderFn = DecodeEthernet;
262 break;
263 case LINKTYPE_PPP:
264 *DecoderFn = DecodePPP;
265 break;
266 case LINKTYPE_IPV4:
267 case LINKTYPE_IPV6:
268 case LINKTYPE_RAW:
269 case LINKTYPE_RAW2:
271 *DecoderFn = DecodeRaw;
272 break;
273 case LINKTYPE_NULL:
274 *DecoderFn = DecodeNull;
275 break;
277 *DecoderFn = DecodeCHDLC;
278 break;
279
280 default:
282 "datalink type %" PRId32 " not (yet) supported in module PcapFile.", datalink);
284 }
285
287}
void StatsSyncCountersIfSignalled(ThreadVars *tv)
Definition counters.c:450
int DecodeCHDLC(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-null.c:51
int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-ppp.c:174
int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-raw.c:42
int DecodeSll2(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-sll2.c:40
int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode-sll.c:41
@ CHECKSUM_VALIDATION_AUTO
Definition decode.h:45
@ CHECKSUM_VALIDATION_DISABLE
Definition decode.h:43
#define PKT_SET_SRC(p, src_val)
Definition decode.h:1325
int(* DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition decode.h:1180
@ PKT_SRC_WIRE
Definition decode.h:52
#define PKT_IGNORE_CHECKSUM
Definition decode.h:1282
uint32_t max_pending_packets
Definition suricata.c:183
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
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition decode.c:377
TmEcode InitPcapFile(PcapFileFileVars *pfv)
const char * PcapFileGetFilename(void)
TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
TmEcode PcapFileDispatch(PcapFileFileVars *ptv)
Main PCAP file reading Loop function.
void CleanupPcapFileFileVars(PcapFileFileVars *pfv)
PcapFileGlobalVars pcap_g
char pcap_filename[PATH_MAX]
uint64_t pcap_cnt
Definition decode.h:626
SCTime_t ts
Definition decode.h:555
int datalink
Definition decode.h:639
PcapPacketVars pcap_v
Definition decode.h:587
uint32_t flags
Definition decode.h:544
PcapFileSharedVars * shared
struct pcap_pkthdr * first_pkt_hdr
struct bpf_program filter
ChecksumValidationMode checksum_mode
uint32_t tenant_id
Definition source-pcap.h:37
size_t strlcpy(char *dst, const char *src, size_t siz)
volatile uint8_t suricata_ctl_flags
Definition suricata.c:172
#define SURICATA_STOP
Definition suricata.h:94
@ TMM_RECEIVEPCAPFILE
@ TM_ECODE_FAILED
@ TM_ECODE_OK
@ TM_ECODE_DONE
void TmThreadsInitThreadsTimestamp(const SCTime_t ts)
void PacketPoolWait(void)
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
int ChecksumAutoModeCheck(uint64_t thread_count, uint64_t iface_count, uint64_t iface_fail)
Check if the number of invalid checksums indicate checksum offloading in place.
#define SCEnter(...)
Definition util-debug.h:277
#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 SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition util-debug.h:225
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCReturn
Definition util-debug.h:279
#define SCFree(p)
Definition util-mem.h:61
#define likely(expr)
#define unlikely(expr)
#define PACKET_PROFILING_TMM_END(p, id)
#define PACKET_PROFILING_TMM_START(p, id)
#define SCTIME_SECS(t)
Definition util-time.h:57
#define SCTIME_FROM_TIMEVAL_UNTRUSTED(tv)
variant to deal with potentially bad timestamps, like from pcap files
Definition util-time.h:85
#define SCTIME_FROM_TIMEVAL(tv)
Definition util-time.h:79