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"
32 #include "util-exception-policy.h"
33 
34 extern uint16_t max_pending_packets;
36 
37 static 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 
61 void 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++;
68  SCReturn;
69  }
70 #endif
71  PcapFileFileVars *ptv = (PcapFileFileVars *)user;
73 
74  if (unlikely(p == NULL)) {
75  SCReturn;
76  }
78 
80  p->ts = SCTIME_FROM_TIMEVAL_UNTRUSTED(&h->ts);
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 
85  p->pcap_v.tenant_id = ptv->shared->tenant_id;
86  ptv->shared->pkts++;
87  ptv->shared->bytes += h->caplen;
88 
89  if (unlikely(PacketCopyData(p, pkt, h->caplen))) {
90  TmqhOutputPacketpool(ptv->shared->tv, p);
92  SCReturn;
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 
116 char pcap_filename[PATH_MAX] = "unknown";
117 
118 const 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 */
150  PacketPoolWait();
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  */
182 static 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 (pfv->shared != NULL && pfv->shared->bpf_string != NULL) {
212  SCLogInfo("using bpf-filter \"%s\"", pfv->shared->bpf_string);
213 
214  if (pcap_compile(pfv->pcap_handle, &pfv->filter, pfv->shared->bpf_string, 1, 0) < 0) {
215  SCLogError("bpf compilation error %s for %s", pcap_geterr(pfv->pcap_handle),
216  pfv->filename);
218  }
219 
220  if (pcap_setfilter(pfv->pcap_handle, &pfv->filter) < 0) {
221  SCLogError("could not set bpf filter %s for %s", pcap_geterr(pfv->pcap_handle),
222  pfv->filename);
223  pcap_freecode(&pfv->filter);
225  }
226  pcap_freecode(&pfv->filter);
227  }
228 
229  pfv->datalink = pcap_datalink(pfv->pcap_handle);
230  SCLogDebug("datalink %" PRId32 "", pfv->datalink);
232 
233  if (!PeekFirstPacketTimestamp(pfv))
235 
236  DecoderFunc UnusedFnPtr;
237  TmEcode validated = ValidateLinkType(pfv->datalink, &UnusedFnPtr);
238  SCReturnInt(validated);
239 }
240 
241 TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
242 {
243  switch (datalink) {
244  case LINKTYPE_LINUX_SLL:
245  *DecoderFn = DecodeSll;
246  break;
247  case LINKTYPE_ETHERNET:
248  *DecoderFn = DecodeEthernet;
249  break;
250  case LINKTYPE_PPP:
251  *DecoderFn = DecodePPP;
252  break;
253  case LINKTYPE_IPV4:
254  case LINKTYPE_IPV6:
255  case LINKTYPE_RAW:
256  case LINKTYPE_RAW2:
258  *DecoderFn = DecodeRaw;
259  break;
260  case LINKTYPE_NULL:
261  *DecoderFn = DecodeNull;
262  break;
263  case LINKTYPE_CISCO_HDLC:
264  *DecoderFn = DecodeCHDLC;
265  break;
266 
267  default:
268  SCLogError(
269  "datalink type %" PRId32 " not (yet) supported in module PcapFile.", datalink);
271  }
272 
274 }
PcapFileSharedVars_::slot
TmSlot * slot
Definition: source-pcap-file-helper.h:51
max_pending_packets
uint16_t max_pending_packets
Definition: suricata.c:182
PcapFileDispatch
TmEcode PcapFileDispatch(PcapFileFileVars *ptv)
Main PCAP file reading Loop function.
Definition: source-pcap-file-helper.c:126
PcapFileFileVars_::filename
char * filename
Definition: source-pcap-file-helper.h:70
PcapFileGlobalVars_
Definition: source-pcap-file-helper.h:30
PcapFileFileVars_::first_pkt_data
const u_char * first_pkt_data
Definition: source-pcap-file-helper.h:80
PcapFileFileVars_::datalink
int datalink
Definition: source-pcap-file-helper.h:73
DecodePPP
int DecodePPP(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ppp.c:174
PacketCopyData
int PacketCopyData(Packet *p, const uint8_t *pktdata, uint32_t pktlen)
Copy data to Packet payload and set packet length.
Definition: decode.c:351
source-pcap-file.h
ValidateLinkType
TmEcode ValidateLinkType(int datalink, DecoderFunc *DecoderFn)
Definition: source-pcap-file-helper.c:241
PcapFileFileVars_::shared
PcapFileSharedVars * shared
Definition: source-pcap-file-helper.h:76
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:609
util-checksum.h
TM_ECODE_DONE
@ TM_ECODE_DONE
Definition: tm-threads-common.h:86
Packet_::flags
uint32_t flags
Definition: decode.h:519
PcapFileSharedVars_::should_delete
bool should_delete
Definition: source-pcap-file-helper.h:48
DecoderFunc
int(* DecoderFunc)(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode.h:1157
LINKTYPE_LINUX_SLL
#define LINKTYPE_LINUX_SLL
Definition: decode.h:1249
SURICATA_STOP
#define SURICATA_STOP
Definition: suricata.h:89
PcapFileSharedVars_::cb_result
int cb_result
Definition: source-pcap-file-helper.h:62
DecodeCHDLC
int DecodeCHDLC(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-chdlc.c:42
CHECKSUM_VALIDATION_DISABLE
@ CHECKSUM_VALIDATION_DISABLE
Definition: decode.h:46
TmqhOutputPacketpool
void TmqhOutputPacketpool(ThreadVars *t, Packet *p)
Definition: tmqh-packetpool.c:315
TM_ECODE_FAILED
@ TM_ECODE_FAILED
Definition: tm-threads-common.h:85
ChecksumAutoModeCheck
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.
Definition: util-checksum.c:69
TM_ECODE_OK
@ TM_ECODE_OK
Definition: tm-threads-common.h:84
LINKTYPE_NULL
#define LINKTYPE_NULL
Definition: decode.h:1247
strlcpy
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: util-strlcpyu.c:43
SCTIME_FROM_TIMEVAL_UNTRUSTED
#define SCTIME_FROM_TIMEVAL_UNTRUSTED(tv)
variant to deal with potentially bad timestamps, like from pcap files
Definition: util-time.h:85
Packet_::datalink
int datalink
Definition: decode.h:622
PKT_SET_SRC
#define PKT_SET_SRC(p, src_val)
Definition: decode.h:1337
DecodeNull
int DecodeNull(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-null.c:51
CHECKSUM_VALIDATION_AUTO
@ CHECKSUM_VALIDATION_AUTO
Definition: decode.h:48
PcapFileGlobalVars_::cnt
uint64_t cnt
Definition: source-pcap-file-helper.h:31
PKT_SRC_WIRE
@ PKT_SRC_WIRE
Definition: decode.h:55
Packet_::ts
SCTime_t ts
Definition: decode.h:530
LINKTYPE_IPV4
#define LINKTYPE_IPV4
Definition: decode.h:1255
util-exception-policy.h
TMM_RECEIVEPCAPFILE
@ TMM_RECEIVEPCAPFILE
Definition: tm-threads-common.h:39
PcapFileGlobalVars_::checksum_mode
ChecksumValidationMode checksum_mode
Definition: source-pcap-file-helper.h:33
Packet_::pcap_v
PcapPacketVars pcap_v
Definition: decode.h:570
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
SCTIME_FROM_TIMEVAL
#define SCTIME_FROM_TIMEVAL(tv)
Definition: util-time.h:79
InitPcapFile
TmEcode InitPcapFile(PcapFileFileVars *pfv)
Definition: source-pcap-file-helper.c:196
LINKTYPE_GRE_OVER_IP
#define LINKTYPE_GRE_OVER_IP
Definition: decode.h:1257
LINKTYPE_PPP
#define LINKTYPE_PPP
Definition: decode.h:1250
SCLogWarning
#define SCLogWarning(...)
Macro used to log WARNING messages.
Definition: util-debug.h:249
util-profiling.h
PacketPoolWait
void PacketPoolWait(void)
Definition: tmqh-packetpool.c:80
SCReturn
#define SCReturn
Definition: util-debug.h:273
PACKET_PROFILING_TMM_END
#define PACKET_PROFILING_TMM_END(p, id)
Definition: util-profiling.h:139
source-pcap-file-helper.h
Packet_
Definition: decode.h:482
PcapPacketVars_::tenant_id
uint32_t tenant_id
Definition: source-pcap.h:37
PKT_IGNORE_CHECKSUM
#define PKT_IGNORE_CHECKSUM
Definition: decode.h:1297
PcapFileFileVars_
Definition: source-pcap-file-helper.h:69
TmEcode
TmEcode
Definition: tm-threads-common.h:83
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
TmThreadsInitThreadsTimestamp
void TmThreadsInitThreadsTimestamp(const SCTime_t ts)
Definition: tm-threads.c:2231
LINKTYPE_RAW
#define LINKTYPE_RAW
Definition: decode.h:1251
PcapFileSharedVars_::bpf_string
char * bpf_string
Definition: source-pcap-file-helper.h:42
pcap_filename
char pcap_filename[PATH_MAX]
Definition: source-pcap-file-helper.c:116
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
LINKTYPE_IPV6
#define LINKTYPE_IPV6
Definition: decode.h:1256
DecodeSll
int DecodeSll(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-sll.c:41
PcapFileSharedVars_::tenant_id
uint32_t tenant_id
Definition: source-pcap-file-helper.h:44
PcapFileFileVars_::first_pkt_ts
struct timeval first_pkt_ts
Definition: source-pcap-file-helper.h:82
PACKET_PROFILING_TMM_START
#define PACKET_PROFILING_TMM_START(p, id)
Definition: util-profiling.h:131
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
PcapFileFileVars_::pcap_handle
pcap_t * pcap_handle
Definition: source-pcap-file-helper.h:71
LINKTYPE_RAW2
#define LINKTYPE_RAW2
Definition: decode.h:1254
LINKTYPE_CISCO_HDLC
#define LINKTYPE_CISCO_HDLC
Definition: decode.h:1258
PcapFileGetFilename
const char * PcapFileGetFilename(void)
Definition: source-pcap-file-helper.c:118
suricata.h
DecodeRaw
int DecodeRaw(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-raw.c:42
PcapFileFileVars_::first_pkt_hdr
struct pcap_pkthdr * first_pkt_hdr
Definition: source-pcap-file-helper.h:81
pcap_g
PcapFileGlobalVars pcap_g
Definition: source-pcap-file.c:37
PcapFileFileVars_::filter
struct bpf_program filter
Definition: source-pcap-file-helper.h:74
likely
#define likely(expr)
Definition: util-optimize.h:32
PcapFileSharedVars_::bytes
uint64_t bytes
Definition: source-pcap-file-helper.h:55
StatsSyncCountersIfSignalled
void StatsSyncCountersIfSignalled(ThreadVars *tv)
Definition: counters.c:454
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:375
CleanupPcapFileFileVars
void CleanupPcapFileFileVars(PcapFileFileVars *pfv)
Definition: source-pcap-file-helper.c:39
PcapFileSharedVars_::tv
ThreadVars * tv
Definition: source-pcap-file-helper.h:50
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
SCReturnInt
#define SCReturnInt(x)
Definition: util-debug.h:275
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:267
DecodeEthernet
int DecodeEthernet(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t *pkt, uint32_t len)
Definition: decode-ethernet.c:42
PcapFileSharedVars_::pkts
uint64_t pkts
Definition: source-pcap-file-helper.h:54
LINKTYPE_ETHERNET
#define LINKTYPE_ETHERNET
Definition: decode.h:1248
suricata_ctl_flags
volatile uint8_t suricata_ctl_flags
Definition: suricata.c:171