Feature #7785 ยป pcap-log-context.patch
src/flow.h | ||
---|---|---|
/* per flow flags */
|
||
/** At least one packet from the source address was seen */
|
||
#define FLOW_TO_SRC_SEEN BIT_U32(0)
|
||
#define FLOW_TO_SRC_SEEN BIT_U32(0)
|
||
/** At least one packet from the destination address was seen */
|
||
#define FLOW_TO_DST_SEEN BIT_U32(1)
|
||
#define FLOW_TO_DST_SEEN BIT_U32(1)
|
||
// vacancy
|
||
/** Flow was inspected against IP-Only sigs in the toserver direction */
|
||
#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3)
|
||
#define FLOW_TOSERVER_IPONLY_SET BIT_U32(3)
|
||
/** Flow was inspected against IP-Only sigs in the toclient direction */
|
||
#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4)
|
||
#define FLOW_TOCLIENT_IPONLY_SET BIT_U32(4)
|
||
/** Packet belonging to this flow should not be inspected at all */
|
||
#define FLOW_NOPACKET_INSPECTION BIT_U32(5)
|
||
#define FLOW_NOPACKET_INSPECTION BIT_U32(5)
|
||
/** Packet payloads belonging to this flow should not be inspected */
|
||
#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6)
|
||
#define FLOW_NOPAYLOAD_INSPECTION BIT_U32(6)
|
||
/** All packets in this flow should be dropped */
|
||
#define FLOW_ACTION_DROP BIT_U32(7)
|
||
#define FLOW_ACTION_DROP BIT_U32(7)
|
||
/** Sgh for toserver direction set (even if it's NULL) */
|
||
#define FLOW_SGH_TOSERVER BIT_U32(8)
|
||
#define FLOW_SGH_TOSERVER BIT_U32(8)
|
||
/** Sgh for toclient direction set (even if it's NULL) */
|
||
#define FLOW_SGH_TOCLIENT BIT_U32(9)
|
||
#define FLOW_SGH_TOCLIENT BIT_U32(9)
|
||
/** packet to server direction has been logged in drop file (only in IPS mode) */
|
||
#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10)
|
||
#define FLOW_TOSERVER_DROP_LOGGED BIT_U32(10)
|
||
/** packet to client direction has been logged in drop file (only in IPS mode) */
|
||
#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11)
|
||
#define FLOW_TOCLIENT_DROP_LOGGED BIT_U32(11)
|
||
/** flow has alerts */
|
||
#define FLOW_HAS_ALERTS BIT_U32(12)
|
||
#define FLOW_HAS_ALERTS BIT_U32(12)
|
||
/** Pattern matcher alproto detection done */
|
||
#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13)
|
||
#define FLOW_TS_PM_ALPROTO_DETECT_DONE BIT_U32(13)
|
||
/** Probing parser alproto detection done */
|
||
#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14)
|
||
#define FLOW_TS_PP_ALPROTO_DETECT_DONE BIT_U32(14)
|
||
/** Expectation alproto detection done */
|
||
#define FLOW_TS_PE_ALPROTO_DETECT_DONE BIT_U32(15)
|
||
#define FLOW_TS_PE_ALPROTO_DETECT_DONE BIT_U32(15)
|
||
/** Pattern matcher alproto detection done */
|
||
#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(16)
|
||
#define FLOW_TC_PM_ALPROTO_DETECT_DONE BIT_U32(16)
|
||
/** Probing parser alproto detection done */
|
||
#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(17)
|
||
#define FLOW_TC_PP_ALPROTO_DETECT_DONE BIT_U32(17)
|
||
/** Expectation alproto detection done */
|
||
#define FLOW_TC_PE_ALPROTO_DETECT_DONE BIT_U32(18)
|
||
#define FLOW_TIMEOUT_REASSEMBLY_DONE BIT_U32(19)
|
||
#define FLOW_TC_PE_ALPROTO_DETECT_DONE BIT_U32(18)
|
||
#define FLOW_TIMEOUT_REASSEMBLY_DONE BIT_U32(19)
|
||
/** flow is ipv4 */
|
||
#define FLOW_IPV4 BIT_U32(20)
|
||
#define FLOW_IPV4 BIT_U32(20)
|
||
/** flow is ipv6 */
|
||
#define FLOW_IPV6 BIT_U32(21)
|
||
#define FLOW_IPV6 BIT_U32(21)
|
||
#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(22)
|
||
#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(23)
|
||
#define FLOW_PROTO_DETECT_TS_DONE BIT_U32(22)
|
||
#define FLOW_PROTO_DETECT_TC_DONE BIT_U32(23)
|
||
/** Indicate that alproto detection for flow should be done again */
|
||
#define FLOW_CHANGE_PROTO BIT_U32(24)
|
||
#define FLOW_CHANGE_PROTO BIT_U32(24)
|
||
#define FLOW_WRONG_THREAD BIT_U32(25)
|
||
#define FLOW_WRONG_THREAD BIT_U32(25)
|
||
/** Protocol detection told us flow is picked up in wrong direction (midstream) */
|
||
#define FLOW_DIR_REVERSED BIT_U32(26)
|
||
#define FLOW_DIR_REVERSED BIT_U32(26)
|
||
/** Indicate that the flow did trigger an expectation creation */
|
||
#define FLOW_HAS_EXPECTATION BIT_U32(27)
|
||
#define FLOW_HAS_EXPECTATION BIT_U32(27)
|
||
/** All packets in this flow should be passed */
|
||
#define FLOW_ACTION_PASS BIT_U32(28)
|
||
... | ... | |
/* File flags */
|
||
#define FLOWFILE_INIT 0
|
||
#define FLOWFILE_INIT 0
|
||
/** no magic on files in this flow */
|
||
#define FLOWFILE_NO_MAGIC_TS BIT_U16(0)
|
||
#define FLOWFILE_NO_MAGIC_TC BIT_U16(1)
|
||
#define FLOWFILE_NO_MAGIC_TS BIT_U16(0)
|
||
#define FLOWFILE_NO_MAGIC_TC BIT_U16(1)
|
||
/** even if the flow has files, don't store 'm */
|
||
#define FLOWFILE_NO_STORE_TS BIT_U16(2)
|
||
#define FLOWFILE_NO_STORE_TC BIT_U16(3)
|
||
#define FLOWFILE_NO_STORE_TS BIT_U16(2)
|
||
#define FLOWFILE_NO_STORE_TC BIT_U16(3)
|
||
/** no md5 on files in this flow */
|
||
#define FLOWFILE_NO_MD5_TS BIT_U16(4)
|
||
#define FLOWFILE_NO_MD5_TC BIT_U16(5)
|
||
#define FLOWFILE_NO_MD5_TS BIT_U16(4)
|
||
#define FLOWFILE_NO_MD5_TC BIT_U16(5)
|
||
/** no sha1 on files in this flow */
|
||
#define FLOWFILE_NO_SHA1_TS BIT_U16(6)
|
||
#define FLOWFILE_NO_SHA1_TC BIT_U16(7)
|
||
#define FLOWFILE_NO_SHA1_TS BIT_U16(6)
|
||
#define FLOWFILE_NO_SHA1_TC BIT_U16(7)
|
||
/** no sha256 on files in this flow */
|
||
#define FLOWFILE_NO_SHA256_TS BIT_U16(8)
|
||
#define FLOWFILE_NO_SHA256_TC BIT_U16(9)
|
||
#define FLOWFILE_NO_SHA256_TS BIT_U16(8)
|
||
#define FLOWFILE_NO_SHA256_TC BIT_U16(9)
|
||
/** no size tracking of files in this flow */
|
||
#define FLOWFILE_NO_SIZE_TS BIT_U16(10)
|
||
#define FLOWFILE_NO_SIZE_TC BIT_U16(11)
|
||
#define FLOWFILE_NO_SIZE_TS BIT_U16(10)
|
||
#define FLOWFILE_NO_SIZE_TC BIT_U16(11)
|
||
/** store files in the flow */
|
||
#define FLOWFILE_STORE_TS BIT_U16(12)
|
||
#define FLOWFILE_STORE_TC BIT_U16(13)
|
||
#define FLOWFILE_NONE_TS (FLOWFILE_NO_MAGIC_TS | \
|
||
FLOWFILE_NO_STORE_TS | \
|
||
FLOWFILE_NO_MD5_TS | \
|
||
FLOWFILE_NO_SHA1_TS | \
|
||
FLOWFILE_NO_SHA256_TS| \
|
||
FLOWFILE_NO_SIZE_TS)
|
||
#define FLOWFILE_NONE_TC (FLOWFILE_NO_MAGIC_TC | \
|
||
FLOWFILE_NO_STORE_TC | \
|
||
FLOWFILE_NO_MD5_TC | \
|
||
FLOWFILE_NO_SHA1_TC | \
|
||
FLOWFILE_NO_SHA256_TC| \
|
||
FLOWFILE_NO_SIZE_TC)
|
||
#define FLOWFILE_NONE (FLOWFILE_NONE_TS|FLOWFILE_NONE_TC)
|
||
#define FLOW_IS_IPV4(f) \
|
||
(((f)->flags & FLOW_IPV4) == FLOW_IPV4)
|
||
#define FLOW_IS_IPV6(f) \
|
||
(((f)->flags & FLOW_IPV6) == FLOW_IPV6)
|
||
#define FLOW_GET_SP(f) \
|
||
((f)->flags & FLOW_DIR_REVERSED) ? (f)->dp : (f)->sp;
|
||
#define FLOW_GET_DP(f) \
|
||
((f)->flags & FLOW_DIR_REVERSED) ? (f)->sp : (f)->dp;
|
||
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) do { \
|
||
(pa)->family = AF_INET; \
|
||
(pa)->addr_data32[0] = (fa)->addr_data32[0]; \
|
||
#define FLOWFILE_NONE_TS \
|
||
(FLOWFILE_NO_MAGIC_TS | FLOWFILE_NO_STORE_TS | FLOWFILE_NO_MD5_TS | FLOWFILE_NO_SHA1_TS | \
|
||
FLOWFILE_NO_SHA256_TS | FLOWFILE_NO_SIZE_TS)
|
||
#define FLOWFILE_NONE_TC \
|
||
(FLOWFILE_NO_MAGIC_TC | FLOWFILE_NO_STORE_TC | FLOWFILE_NO_MD5_TC | FLOWFILE_NO_SHA1_TC | \
|
||
FLOWFILE_NO_SHA256_TC | FLOWFILE_NO_SIZE_TC)
|
||
#define FLOWFILE_NONE (FLOWFILE_NONE_TS | FLOWFILE_NONE_TC)
|
||
#define FLOW_IS_IPV4(f) (((f)->flags & FLOW_IPV4) == FLOW_IPV4)
|
||
#define FLOW_IS_IPV6(f) (((f)->flags & FLOW_IPV6) == FLOW_IPV6)
|
||
#define FLOW_GET_SP(f) ((f)->flags & FLOW_DIR_REVERSED) ? (f)->dp : (f)->sp;
|
||
#define FLOW_GET_DP(f) ((f)->flags & FLOW_DIR_REVERSED) ? (f)->sp : (f)->dp;
|
||
#define FLOW_COPY_IPV4_ADDR_TO_PACKET(fa, pa) \
|
||
do { \
|
||
(pa)->family = AF_INET; \
|
||
(pa)->addr_data32[0] = (fa)->addr_data32[0]; \
|
||
} while (0)
|
||
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) do { \
|
||
(pa)->family = AF_INET6; \
|
||
(pa)->addr_data32[0] = (fa)->addr_data32[0]; \
|
||
(pa)->addr_data32[1] = (fa)->addr_data32[1]; \
|
||
(pa)->addr_data32[2] = (fa)->addr_data32[2]; \
|
||
(pa)->addr_data32[3] = (fa)->addr_data32[3]; \
|
||
#define FLOW_COPY_IPV6_ADDR_TO_PACKET(fa, pa) \
|
||
do { \
|
||
(pa)->family = AF_INET6; \
|
||
(pa)->addr_data32[0] = (fa)->addr_data32[0]; \
|
||
(pa)->addr_data32[1] = (fa)->addr_data32[1]; \
|
||
(pa)->addr_data32[2] = (fa)->addr_data32[2]; \
|
||
(pa)->addr_data32[3] = (fa)->addr_data32[3]; \
|
||
} while (0)
|
||
/* Set the IPv4 addressesinto the Addrs of the Packet.
|
||
... | ... | |
*
|
||
* We set the rest of the struct to 0 so we can
|
||
* prevent using memset. */
|
||
#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) do { \
|
||
(a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \
|
||
(a)->addr_data32[1] = 0; \
|
||
(a)->addr_data32[2] = 0; \
|
||
(a)->addr_data32[3] = 0; \
|
||
#define FLOW_SET_IPV4_SRC_ADDR_FROM_PACKET(p, a) \
|
||
do { \
|
||
(a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_src.s_addr; \
|
||
(a)->addr_data32[1] = 0; \
|
||
(a)->addr_data32[2] = 0; \
|
||
(a)->addr_data32[3] = 0; \
|
||
} while (0)
|
||
#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) do { \
|
||
(a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \
|
||
(a)->addr_data32[1] = 0; \
|
||
(a)->addr_data32[2] = 0; \
|
||
(a)->addr_data32[3] = 0; \
|
||
#define FLOW_SET_IPV4_DST_ADDR_FROM_PACKET(p, a) \
|
||
do { \
|
||
(a)->addr_data32[0] = (uint32_t)(p)->ip4h->s_ip_dst.s_addr; \
|
||
(a)->addr_data32[1] = 0; \
|
||
(a)->addr_data32[2] = 0; \
|
||
(a)->addr_data32[3] = 0; \
|
||
} while (0)
|
||
/* Set the IPv6 addressesinto the Addrs of the Packet.
|
||
* Make sure p->ip6h is initialized and validated. */
|
||
#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) do { \
|
||
(a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \
|
||
(a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \
|
||
(a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \
|
||
(a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \
|
||
#define FLOW_SET_IPV6_SRC_ADDR_FROM_PACKET(p, a) \
|
||
do { \
|
||
(a)->addr_data32[0] = (p)->ip6h->s_ip6_src[0]; \
|
||
(a)->addr_data32[1] = (p)->ip6h->s_ip6_src[1]; \
|
||
(a)->addr_data32[2] = (p)->ip6h->s_ip6_src[2]; \
|
||
(a)->addr_data32[3] = (p)->ip6h->s_ip6_src[3]; \
|
||
} while (0)
|
||
#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) do { \
|
||
(a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \
|
||
(a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \
|
||
(a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \
|
||
(a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \
|
||
#define FLOW_SET_IPV6_DST_ADDR_FROM_PACKET(p, a) \
|
||
do { \
|
||
(a)->addr_data32[0] = (p)->ip6h->s_ip6_dst[0]; \
|
||
(a)->addr_data32[1] = (p)->ip6h->s_ip6_dst[1]; \
|
||
(a)->addr_data32[2] = (p)->ip6h->s_ip6_dst[2]; \
|
||
(a)->addr_data32[3] = (p)->ip6h->s_ip6_dst[3]; \
|
||
} while (0)
|
||
/* pkt flow flags */
|
||
#define FLOW_PKT_TOSERVER 0x01
|
||
#define FLOW_PKT_TOCLIENT 0x02
|
||
#define FLOW_PKT_ESTABLISHED 0x04
|
||
#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08
|
||
#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10
|
||
#define FLOW_PKT_TOSERVER_FIRST 0x20
|
||
#define FLOW_PKT_TOCLIENT_FIRST 0x40
|
||
#define FLOW_PKT_TOSERVER 0x01
|
||
#define FLOW_PKT_TOCLIENT 0x02
|
||
#define FLOW_PKT_ESTABLISHED 0x04
|
||
#define FLOW_PKT_TOSERVER_IPONLY_SET 0x08
|
||
#define FLOW_PKT_TOCLIENT_IPONLY_SET 0x10
|
||
#define FLOW_PKT_TOSERVER_FIRST 0x20
|
||
#define FLOW_PKT_TOCLIENT_FIRST 0x40
|
||
/** last pseudo packet in the flow. Can be used to trigger final clean,
|
||
* logging, etc. */
|
||
#define FLOW_PKT_LAST_PSEUDO 0x80
|
||
#define FLOW_PKT_LAST_PSEUDO 0x80
|
||
#define FLOW_END_FLAG_STATE_NEW 0x01
|
||
#define FLOW_END_FLAG_STATE_ESTABLISHED 0x02
|
||
... | ... | |
#define FLOW_END_FLAG_STATE_BYPASSED 0x80
|
||
/** Mutex or RWLocks for the flow. */
|
||
//#define FLOWLOCK_RWLOCK
|
||
// #define FLOWLOCK_RWLOCK
|
||
#define FLOWLOCK_MUTEX
|
||
#ifdef FLOWLOCK_RWLOCK
|
||
#ifdef FLOWLOCK_MUTEX
|
||
#error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX
|
||
#endif
|
||
#ifdef FLOWLOCK_MUTEX
|
||
#error Cannot enable both FLOWLOCK_RWLOCK and FLOWLOCK_MUTEX
|
||
#endif
|
||
#endif
|
||
#ifdef FLOWLOCK_RWLOCK
|
||
#define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL)
|
||
#define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r)
|
||
#define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r)
|
||
#define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r)
|
||
#define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r)
|
||
#define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r)
|
||
#define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r)
|
||
#define FLOWLOCK_INIT(fb) SCRWLockInit(&(fb)->r, NULL)
|
||
#define FLOWLOCK_DESTROY(fb) SCRWLockDestroy(&(fb)->r)
|
||
#define FLOWLOCK_RDLOCK(fb) SCRWLockRDLock(&(fb)->r)
|
||
#define FLOWLOCK_WRLOCK(fb) SCRWLockWRLock(&(fb)->r)
|
||
#define FLOWLOCK_TRYRDLOCK(fb) SCRWLockTryRDLock(&(fb)->r)
|
||
#define FLOWLOCK_TRYWRLOCK(fb) SCRWLockTryWRLock(&(fb)->r)
|
||
#define FLOWLOCK_UNLOCK(fb) SCRWLockUnlock(&(fb)->r)
|
||
#elif defined FLOWLOCK_MUTEX
|
||
#define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL)
|
||
#define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m)
|
||
#define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m)
|
||
#define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m)
|
||
#define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m)
|
||
#define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m)
|
||
#define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m)
|
||
#define FLOWLOCK_INIT(fb) SCMutexInit(&(fb)->m, NULL)
|
||
#define FLOWLOCK_DESTROY(fb) SCMutexDestroy(&(fb)->m)
|
||
#define FLOWLOCK_RDLOCK(fb) SCMutexLock(&(fb)->m)
|
||
#define FLOWLOCK_WRLOCK(fb) SCMutexLock(&(fb)->m)
|
||
#define FLOWLOCK_TRYRDLOCK(fb) SCMutexTrylock(&(fb)->m)
|
||
#define FLOWLOCK_TRYWRLOCK(fb) SCMutexTrylock(&(fb)->m)
|
||
#define FLOWLOCK_UNLOCK(fb) SCMutexUnlock(&(fb)->m)
|
||
#else
|
||
#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
|
||
#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
|
||
#endif
|
||
#define FLOW_IS_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE))
|
||
#define FLOW_IS_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE))
|
||
#define FLOW_IS_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags & FLOW_TC_PE_ALPROTO_DETECT_DONE))
|
||
#define FLOW_SET_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE))
|
||
#define FLOW_SET_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE))
|
||
#define FLOW_SET_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags |= FLOW_TC_PE_ALPROTO_DETECT_DONE))
|
||
#define FLOW_RESET_PM_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PM_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PM_ALPROTO_DETECT_DONE))
|
||
#define FLOW_RESET_PP_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PP_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PP_ALPROTO_DETECT_DONE))
|
||
#define FLOW_RESET_PE_DONE(f, dir) (((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PE_ALPROTO_DETECT_DONE) : ((f)->flags &= ~FLOW_TC_PE_ALPROTO_DETECT_DONE))
|
||
#define FLOW_IS_PM_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PM_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags & FLOW_TC_PM_ALPROTO_DETECT_DONE))
|
||
#define FLOW_IS_PP_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PP_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags & FLOW_TC_PP_ALPROTO_DETECT_DONE))
|
||
#define FLOW_IS_PE_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags & FLOW_TS_PE_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags & FLOW_TC_PE_ALPROTO_DETECT_DONE))
|
||
#define FLOW_SET_PM_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PM_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags |= FLOW_TC_PM_ALPROTO_DETECT_DONE))
|
||
#define FLOW_SET_PP_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PP_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags |= FLOW_TC_PP_ALPROTO_DETECT_DONE))
|
||
#define FLOW_SET_PE_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags |= FLOW_TS_PE_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags |= FLOW_TC_PE_ALPROTO_DETECT_DONE))
|
||
#define FLOW_RESET_PM_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PM_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags &= ~FLOW_TC_PM_ALPROTO_DETECT_DONE))
|
||
#define FLOW_RESET_PP_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PP_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags &= ~FLOW_TC_PP_ALPROTO_DETECT_DONE))
|
||
#define FLOW_RESET_PE_DONE(f, dir) \
|
||
(((dir) & STREAM_TOSERVER) ? ((f)->flags &= ~FLOW_TS_PE_ALPROTO_DETECT_DONE) \
|
||
: ((f)->flags &= ~FLOW_TC_PE_ALPROTO_DETECT_DONE))
|
||
/* global flow config */
|
||
typedef struct FlowCnf_
|
||
{
|
||
typedef struct FlowCnf_ {
|
||
uint32_t hash_rand;
|
||
uint32_t hash_size;
|
||
uint32_t prealloc;
|
||
... | ... | |
} FlowConfig;
|
||
/* Hash key for the flow hash */
|
||
typedef struct FlowKey_
|
||
{
|
||
typedef struct FlowKey_ {
|
||
Address src, dst;
|
||
Port sp, dp;
|
||
uint8_t proto;
|
||
... | ... | |
typedef struct FlowAddress_ {
|
||
union {
|
||
uint32_t address_un_data32[4]; /* type-specific field */
|
||
uint16_t address_un_data16[8]; /* type-specific field */
|
||
uint8_t address_un_data8[16]; /* type-specific field */
|
||
uint32_t address_un_data32[4]; /* type-specific field */
|
||
uint16_t address_un_data16[8]; /* type-specific field */
|
||
uint8_t address_un_data8[16]; /* type-specific field */
|
||
} address;
|
||
} FlowAddress;
|
||
... | ... | |
* of a flow. This is why we can access those without protection of the lock.
|
||
*/
|
||
typedef struct Flow_
|
||
{
|
||
typedef struct Flow_ {
|
||
/* flow "header", used for hashing and flow lookup. Static after init,
|
||
* so safe to look at without lock */
|
||
FlowAddress src, dst;
|
||
union {
|
||
Port sp; /**< tcp/udp source port */
|
||
Port sp; /**< tcp/udp source port */
|
||
struct {
|
||
uint8_t type; /**< icmp type */
|
||
uint8_t code; /**< icmp code */
|
||
uint8_t type; /**< icmp type */
|
||
uint8_t code; /**< icmp code */
|
||
} icmp_s;
|
||
struct {
|
||
... | ... | |
} esp;
|
||
};
|
||
union {
|
||
Port dp; /**< tcp/udp destination port */
|
||
Port dp; /**< tcp/udp destination port */
|
||
struct {
|
||
uint8_t type; /**< icmp type */
|
||
uint8_t code; /**< icmp code */
|
||
uint8_t type; /**< icmp type */
|
||
uint8_t code; /**< icmp code */
|
||
} icmp_d;
|
||
};
|
||
uint8_t proto;
|
||
... | ... | |
/* track toserver/toclient flow timeout needs */
|
||
union {
|
||
struct {
|
||
uint8_t ffr_ts:4;
|
||
uint8_t ffr_tc:4;
|
||
uint8_t ffr_ts : 4;
|
||
uint8_t ffr_tc : 4;
|
||
};
|
||
uint8_t ffr;
|
||
};
|
||
... | ... | |
uint32_t probing_parser_toserver_alproto_masks;
|
||
uint32_t probing_parser_toclient_alproto_masks;
|
||
uint32_t flags; /**< generic flags */
|
||
uint32_t flags; /**< generic flags */
|
||
uint16_t file_flags; /**< file tracking/extraction flags */
|
||
uint16_t file_flags; /**< file tracking/extraction flags */
|
||
/** destination port to be used in protocol detection. This is meant
|
||
* for use with STARTTLS and HTTP CONNECT detection */
|
||
... | ... | |
#elif defined FLOWLOCK_MUTEX
|
||
SCMutex m;
|
||
#else
|
||
#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
|
||
#error Enable FLOWLOCK_RWLOCK or FLOWLOCK_MUTEX
|
||
#endif
|
||
/** protocol specific data pointer, e.g. for TcpSession */
|
||
... | ... | |
/** application level storage ptrs.
|
||
*
|
||
*/
|
||
AppLayerParserState *alparser; /**< parser internal state */
|
||
void *alstate; /**< application layer state */
|
||
AppLayerParserState *alparser; /**< parser internal state */
|
||
void *alstate; /**< application layer state */
|
||
/** toclient sgh for this flow. Only use when FLOW_SGH_TOCLIENT flow flag
|
||
* has been set. */
|
||
... | ... | |
uint32_t tosrcpktcnt;
|
||
uint64_t todstbytecnt;
|
||
uint64_t tosrcbytecnt;
|
||
/** Remaining packets that should be logged by the pcap-log "context-packets-after"
|
||
* feature once an alert has fired for this flow. This field is **only** used by
|
||
* the pcap-log output module and is otherwise ignored by the rest of the engine.
|
||
* It is initialised to 0 and set to `context_packets_after` when the first alert
|
||
* for this flow is encountered. It is then decremented for each subsequent packet
|
||
* the module logs until it reaches 0. */
|
||
uint32_t pcap_after_remaining;
|
||
} Flow;
|
||
enum FlowState {
|
||
... | ... | |
} FlowProtoFreeFunc;
|
||
typedef struct FlowBypassInfo_ {
|
||
bool (* BypassUpdate)(Flow *f, void *data, time_t tsec);
|
||
void (* BypassFree)(void *data);
|
||
bool (*BypassUpdate)(Flow *f, void *data, time_t tsec);
|
||
void (*BypassFree)(void *data);
|
||
void *bypass_data;
|
||
uint64_t tosrcpktcnt;
|
||
uint64_t tosrcbytecnt;
|
||
... | ... | |
* and calc the hash value to be used in the lookup and autofp flow
|
||
* balancing. */
|
||
void FlowSetupPacket(Packet *p);
|
||
void FlowHandlePacket (ThreadVars *, FlowLookupStruct *, Packet *);
|
||
void FlowHandlePacket(ThreadVars *, FlowLookupStruct *, Packet *);
|
||
void FlowInitConfig(bool);
|
||
void FlowReset(void);
|
||
void FlowShutdown(void);
|
||
... | ... | |
*
|
||
* \param f Flow to set the flag in
|
||
*/
|
||
static inline void FlowSetNoPacketInspectionFlag(Flow *f)
|
||
static inline void FlowSetNoPacketInspectionFlag(Flow *f)
|
||
{
|
||
SCEnter();
|
||
... | ... | |
return false;
|
||
}
|
||
int FlowClearMemory(Flow *,uint8_t );
|
||
int FlowClearMemory(Flow *, uint8_t);
|
||
AppProto FlowGetAppProtocol(const Flow *f);
|
||
void *FlowGetAppState(const Flow *f);
|
src/log-pcap.c | ||
---|---|---|
*/
|
||
#include "suricata-common.h"
|
||
#include <errno.h>
|
||
#include <pcap.h>
|
||
#include <string.h>
|
||
#include <sys/stat.h>
|
||
#ifdef HAVE_LIBLZ4
|
||
#include <lz4frame.h>
|
||
#include "util-fmemopen.h"
|
||
... | ... | |
#define INIT_RING_BUFFER
|
||
#include <dirent.h>
|
||
#include <fnmatch.h>
|
||
#include <pcre2.h>
|
||
#endif
|
||
#include "log-pcap.h"
|
||
... | ... | |
#include "util-profiling.h"
|
||
#include "util-time.h"
|
||
#define DEFAULT_LOG_FILENAME "pcaplog"
|
||
#define MODULE_NAME "PcapLog"
|
||
#define MIN_LIMIT 4 * 1024 * 1024
|
||
#define DEFAULT_LIMIT 100 * 1024 * 1024
|
||
#define DEFAULT_FILE_LIMIT 0
|
||
#include "util-unittest.h"
|
||
#include "util-unittest-helper.h"
|
||
#include "conf-yaml-loader.h"
|
||
#define LOGMODE_NORMAL 0
|
||
#define LOGMODE_SGUIL 1
|
||
#define LOGMODE_MULTI 2
|
||
#define DEFAULT_LOG_FILENAME "pcaplog"
|
||
#define MODULE_NAME "PcapLog"
|
||
#define MIN_LIMIT 4 * 1024 * 1024
|
||
#define DEFAULT_LIMIT 100 * 1024 * 1024
|
||
#define DEFAULT_FILE_LIMIT 0
|
||
#define LOGMODE_NORMAL 0
|
||
#define LOGMODE_SGUIL 1
|
||
#define LOGMODE_MULTI 2
|
||
typedef enum LogModeConditionalType_ {
|
||
LOGMODE_COND_ALL,
|
||
... | ... | |
LOGMODE_COND_TAG
|
||
} LogModeConditionalType;
|
||
#define RING_BUFFER_MODE_DISABLED 0
|
||
#define RING_BUFFER_MODE_ENABLED 1
|
||
#define RING_BUFFER_MODE_DISABLED 0
|
||
#define RING_BUFFER_MODE_ENABLED 1
|
||
#define TS_FORMAT_SEC 0
|
||
#define TS_FORMAT_USEC 1
|
||
#define TS_FORMAT_SEC 0
|
||
#define TS_FORMAT_USEC 1
|
||
#define USE_STREAM_DEPTH_DISABLED 0
|
||
#define USE_STREAM_DEPTH_ENABLED 1
|
||
#define USE_STREAM_DEPTH_DISABLED 0
|
||
#define USE_STREAM_DEPTH_ENABLED 1
|
||
#define HONOR_PASS_RULES_DISABLED 0
|
||
#define HONOR_PASS_RULES_ENABLED 1
|
||
#define HONOR_PASS_RULES_DISABLED 0
|
||
#define HONOR_PASS_RULES_ENABLED 1
|
||
#define PCAP_SNAPLEN 262144
|
||
#define PCAP_BUFFER_TIMEOUT 1000000 // microseconds
|
||
#define PCAP_PKTHDR_SIZE 16
|
||
#define PCAP_SNAPLEN 262144
|
||
#define PCAP_BUFFER_TIMEOUT 1000000 // microseconds
|
||
#define PCAP_PKTHDR_SIZE 16
|
||
SC_ATOMIC_DECLARE(uint32_t, thread_cnt);
|
||
... | ... | |
uint64_t cnt;
|
||
} PcapLogProfileData;
|
||
#define MAX_TOKS 9
|
||
#define MAX_TOKS 9
|
||
#define MAX_FILENAMELEN 513
|
||
enum PcapLogCompressionFormat {
|
||
... | ... | |
* Used for storing file options.
|
||
*/
|
||
typedef struct PcapLogData_ {
|
||
int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */
|
||
int honor_pass_rules; /**< don't log if pass rules have matched */
|
||
int is_private; /**< TRUE if ctx is thread local */
|
||
int use_stream_depth; /**< use stream depth i.e. ignore packets that reach limit */
|
||
int honor_pass_rules; /**< don't log if pass rules have matched */
|
||
int is_private; /**< TRUE if ctx is thread local */
|
||
SCMutex plog_lock;
|
||
uint64_t pkt_cnt; /**< total number of packets */
|
||
uint64_t pkt_cnt; /**< total number of packets */
|
||
struct pcap_pkthdr *h; /**< pcap header struct */
|
||
char *filename; /**< current filename */
|
||
int mode; /**< normal or sguil */
|
||
... | ... | |
TAILQ_HEAD(, PcapFileName_) pcap_file_list;
|
||
uint32_t thread_number; /**< thread number, first thread is 1, second 2, etc */
|
||
int use_ringbuffer; /**< ring buffer mode enabled or disabled */
|
||
int timestamp_format; /**< timestamp format sec or usec */
|
||
char *prefix; /**< filename prefix */
|
||
const char *suffix; /**< filename suffix */
|
||
char dir[PATH_MAX]; /**< pcap log directory */
|
||
uint32_t thread_number; /**< thread number, first thread is 1, second 2, etc */
|
||
int use_ringbuffer; /**< ring buffer mode enabled or disabled */
|
||
int timestamp_format; /**< timestamp format sec or usec */
|
||
char *prefix; /**< filename prefix */
|
||
const char *suffix; /**< filename suffix */
|
||
char dir[PATH_MAX]; /**< pcap log directory */
|
||
int reported;
|
||
int threads; /**< number of threads (only set in the global) */
|
||
int threads; /**< number of threads (only set in the global) */
|
||
char *filename_parts[MAX_TOKS];
|
||
int filename_part_cnt;
|
||
struct timeval last_pcap_dump;
|
||
int fopen_err; /**< set to the last fopen error */
|
||
bool pcap_open_err; /**< true if the last pcap open errored */
|
||
uint32_t context_packets_before; /**< packets to capture before alert */
|
||
uint32_t context_packets_after; /**< packets to capture after alert */
|
||
uint8_t **context_buffer; /**< circular buffer for context packets */
|
||
struct pcap_pkthdr *context_headers; /**< headers for context packets */
|
||
uint32_t context_buffer_size; /**< size of context buffer */
|
||
uint32_t context_buffer_pos; /**< current position in buffer */
|
||
uint32_t context_buffer_count; /**< packets stored in buffer */
|
||
PcapLogCompressionData compression;
|
||
} PcapLogData;
|
||
... | ... | |
static void PcapLogProfilingDump(PcapLogData *);
|
||
static int PcapLogCondition(ThreadVars *, void *, const Packet *);
|
||
#ifdef UNITTESTS
|
||
static void PcapLogRegisterTests(void);
|
||
#endif
|
||
void PcapLogRegister(void)
|
||
{
|
||
OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log",
|
||
PcapLogInitCtx, PcapLog, PcapLogCondition, PcapLogDataInit,
|
||
PcapLogDataDeinit, NULL);
|
||
OutputRegisterPacketModule(LOGGER_PCAP, MODULE_NAME, "pcap-log", PcapLogInitCtx, PcapLog,
|
||
PcapLogCondition, PcapLogDataInit, PcapLogDataDeinit, NULL);
|
||
PcapLogProfileSetup();
|
||
SC_ATOMIC_INIT(thread_cnt);
|
||
SC_ATOMIC_SET(thread_cnt, 1); /* first id is 1 */
|
||
#ifdef UNITTESTS
|
||
PcapLogRegisterTests();
|
||
#endif
|
||
return;
|
||
}
|
||
#define PCAPLOG_PROFILE_START \
|
||
uint64_t pcaplog_profile_ticks = UtilCpuGetTicks()
|
||
#define PCAPLOG_PROFILE_START uint64_t pcaplog_profile_ticks = UtilCpuGetTicks()
|
||
#define PCAPLOG_PROFILE_END(prof) \
|
||
(prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \
|
||
#define PCAPLOG_PROFILE_END(prof) \
|
||
(prof).total += (UtilCpuGetTicks() - pcaplog_profile_ticks); \
|
||
(prof).cnt++
|
||
static int PcapLogCondition(ThreadVars *tv, void *thread_data, const Packet *p)
|
||
{
|
||
PcapLogThreadData *ptd = (PcapLogThreadData *)thread_data;
|
||
/* Log alerted flow or tagged flow */
|
||
/* If context packets are enabled, we need to process all packets to fill the context buffer */
|
||
if ((ptd->pcap_log->context_packets_before > 0 || ptd->pcap_log->context_packets_after > 0) &&
|
||
ptd->pcap_log->conditional == LOGMODE_COND_ALERTS) {
|
||
/* Always process packets when context is enabled, but let PcapLog decide what to write */
|
||
if (p->flags & PKT_PSEUDO_STREAM_END) {
|
||
return FALSE;
|
||
}
|
||
if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
/* Original conditional logic for when context is not enabled */
|
||
switch (ptd->pcap_log->conditional) {
|
||
case LOGMODE_COND_ALL:
|
||
break;
|
||
... | ... | |
/* pcap_dump_close() has closed its output ``file'',
|
||
* so we need to call fmemopen again. */
|
||
comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf,
|
||
comp->pcap_buf_size, "w");
|
||
comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, comp->pcap_buf_size, "w");
|
||
if (comp->pcap_buf_wrapper == NULL) {
|
||
SCLogError("SCFmemopen failed: %s", strerror(errno));
|
||
return TM_ECODE_FAILED;
|
||
... | ... | |
/* pcap_dump_close did not write any data because we call
|
||
* pcap_dump_flush() after every write when writing
|
||
* compressed output. */
|
||
uint64_t bytes_written = LZ4F_compressEnd(comp->lz4f_context,
|
||
comp->buffer, comp->buffer_size, NULL);
|
||
uint64_t bytes_written =
|
||
LZ4F_compressEnd(comp->lz4f_context, comp->buffer, comp->buffer_size, NULL);
|
||
if (LZ4F_isError(bytes_written)) {
|
||
SCLogError("LZ4F_compressEnd: %s", LZ4F_getErrorName(bytes_written));
|
||
return TM_ECODE_FAILED;
|
||
... | ... | |
PCAPLOG_PROFILE_START;
|
||
if (PcapLogCloseFile(t,pl) < 0) {
|
||
/* Ensure all data is flushed before rotation */
|
||
if (pl->pcap_dumper != NULL) {
|
||
pcap_dump_flush(pl->pcap_dumper);
|
||
}
|
||
if (PcapLogCloseFile(t, pl) < 0) {
|
||
SCLogDebug("PcapLogCloseFile failed");
|
||
return -1;
|
||
}
|
||
... | ... | |
/* Remove directory if Sguil mode and no files left in sguil dir */
|
||
if (pl->mode == LOGMODE_SGUIL) {
|
||
pfnext = TAILQ_NEXT(pf,next);
|
||
pfnext = TAILQ_NEXT(pf, next);
|
||
if (strcmp(pf->dirname, pfnext->dirname) == 0) {
|
||
SCLogDebug("Current entry dir %s and next entry %s "
|
||
"are equal: not removing dir",
|
||
"are equal: not removing dir",
|
||
pf->dirname, pfnext->dirname);
|
||
} else {
|
||
SCLogDebug("current entry %s and %s are "
|
||
"not equal: removing dir",
|
||
"not equal: removing dir",
|
||
pf->dirname, pfnext->dirname);
|
||
if (remove(pf->dirname) != 0) {
|
||
... | ... | |
if (pl->pcap_dumper == NULL) {
|
||
if (pl->compression.format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
|
||
if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle,
|
||
pl->filename)) == NULL) {
|
||
if ((pl->pcap_dumper = pcap_dump_open(pl->pcap_dead_handle, pl->filename)) == NULL) {
|
||
if (!pl->pcap_open_err) {
|
||
SCLogError("Error opening dump file %s", pcap_geterr(pl->pcap_dead_handle));
|
||
pl->pcap_open_err = true;
|
||
... | ... | |
pl->pcap_open_err = false;
|
||
}
|
||
uint64_t bytes_written = LZ4F_compressBegin(comp->lz4f_context,
|
||
comp->buffer, comp->buffer_size, NULL);
|
||
uint64_t bytes_written =
|
||
LZ4F_compressBegin(comp->lz4f_context, comp->buffer, comp->buffer_size, NULL);
|
||
if (LZ4F_isError(bytes_written)) {
|
||
SCLogError("LZ4F_compressBegin: %s", LZ4F_getErrorName(bytes_written));
|
||
return TM_ECODE_FAILED;
|
||
... | ... | |
}
|
||
}
|
||
/**
|
||
* \brief Force a flush of the pcap log file
|
||
*
|
||
* \param pl PcapLog thread variable.
|
||
*
|
||
* \retval TM_ECODE_OK on success
|
||
* \retval TM_ECODE_FAILED on failure
|
||
*/
|
||
static int PcapLogFlush(PcapLogData *pl)
|
||
{
|
||
if (pl == NULL || pl->pcap_dumper == NULL)
|
||
return TM_ECODE_OK;
|
||
SCLogDebug("Flushing pcap file %s", pl->filename ? pl->filename : "(unknown)");
|
||
pcap_dump_flush(pl->pcap_dumper);
|
||
return TM_ECODE_OK;
|
||
}
|
||
/** \internal
|
||
* \brief Write a packet to pcap file
|
||
* \param pl PcapLog thread variable
|
||
* \param p Packet
|
||
*/
|
||
static inline int PcapWrite(
|
||
PcapLogData *pl, PcapLogCompressionData *comp, uint8_t *data, size_t len)
|
||
PcapLogData *pl, PcapLogCompressionData *comp, uint8_t *data, size_t len, bool force_flush)
|
||
{
|
||
struct timeval current_dump;
|
||
gettimeofday(¤t_dump, NULL);
|
||
... | ... | |
}
|
||
}
|
||
#endif /* HAVE_LIBLZ4 */
|
||
if (TimeDifferenceMicros(pl->last_pcap_dump, current_dump) >= PCAP_BUFFER_TIMEOUT) {
|
||
// Flush in strategic cases:
|
||
// 1. When explicitly forced (flow end, last after-packet, etc.)
|
||
// 2. When the time interval has passed
|
||
// 3. For alert packets and context packets (after packets)
|
||
if (force_flush ||
|
||
TimeDifferenceMicros(pl->last_pcap_dump, current_dump) >= PCAP_BUFFER_TIMEOUT) {
|
||
pcap_dump_flush(pl->pcap_dumper);
|
||
SCLogDebug("PCAP-FLUSH: %s", force_flush ? "forced" : "time-based");
|
||
}
|
||
pl->last_pcap_dump = current_dump;
|
||
return TM_ECODE_OK;
|
||
... | ... | |
MemBufferWriteRaw(pctx->buf, seg->pcap_hdr_storage->pkt_hdr, seg->pcap_hdr_storage->pktlen);
|
||
MemBufferWriteRaw(pctx->buf, buf, buflen);
|
||
PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len);
|
||
// Only flush at true flow endpoints
|
||
PcapWrite(pctx->pl, pctx->connp, (uint8_t *)pctx->buf->buffer, pctx->pl->h->len, false);
|
||
}
|
||
return 1;
|
||
}
|
||
... | ... | |
* \retval TM_ECODE_OK on succes
|
||
* \retval TM_ECODE_FAILED on serious error
|
||
*/
|
||
static int PcapLog (ThreadVars *t, void *thread_data, const Packet *p)
|
||
static int PcapLog(ThreadVars *t, void *thread_data, const Packet *p)
|
||
{
|
||
size_t len;
|
||
int rotate = 0;
|
||
int ret = 0;
|
||
bool do_write = false; /* set to true when this packet must be written */
|
||
Packet *rp = NULL;
|
||
PcapLogThreadData *td = (PcapLogThreadData *)thread_data;
|
||
... | ... | |
PcapLogCompressionData *comp = &pl->compression;
|
||
if (comp->format == PCAP_LOG_COMPRESSION_FORMAT_NONE) {
|
||
if ((pl->size_current + len) > pl->size_limit || rotate) {
|
||
if (PcapLogRotateFile(t,pl) < 0) {
|
||
if (PcapLogRotateFile(t, pl) < 0) {
|
||
PcapLogUnlock(pl);
|
||
SCLogDebug("rotation of pcap failed");
|
||
return TM_ECODE_FAILED;
|
||
... | ... | |
* bytes that have been fed into lz4 since the last write, and
|
||
* act as if they would be written uncompressed. */
|
||
if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit ||
|
||
rotate) {
|
||
if (PcapLogRotateFile(t,pl) < 0) {
|
||
if ((pl->size_current + comp->bytes_in_block + len) > pl->size_limit || rotate) {
|
||
if (PcapLogRotateFile(t, pl) < 0) {
|
||
PcapLogUnlock(pl);
|
||
SCLogDebug("rotation of pcap failed");
|
||
return TM_ECODE_FAILED;
|
||
... | ... | |
PCAPLOG_PROFILE_START;
|
||
// NEW: determine if this packet itself should always be written in
|
||
// conditional modes (alerts or tag based packets).
|
||
// This has to be done before we possibly early-return based on
|
||
// the `do_write` flag later on.
|
||
if (pl->conditional == LOGMODE_COND_ALERTS) {
|
||
/* Alert packets */
|
||
if (p->alerts.cnt > 0) {
|
||
do_write = true;
|
||
}
|
||
}
|
||
/* if we are using alerted logging and if packet is first one with alert in flow
|
||
* then we need to dump in the pcap the stream acked by the packet */
|
||
if ((p->flags & PKT_FIRST_ALERTS) && (td->pcap_log->conditional != LOGMODE_COND_ALL)) {
|
||
... | ... | |
}
|
||
}
|
||
/* First, handle context packets before writing alert packets */
|
||
if (p->alerts.cnt > 0 && pl->context_packets_before > 0 && pl->context_buffer != NULL) {
|
||
/* Calculate how many "before" packets to dump */
|
||
uint32_t packets_to_dump = (pl->context_buffer_count < pl->context_packets_before)
|
||
? pl->context_buffer_count
|
||
: pl->context_packets_before;
|
||
/* Calculate start position in circular buffer for oldest packets */
|
||
uint32_t start_pos;
|
||
if (pl->context_buffer_count < pl->context_buffer_size) {
|
||
/* Buffer not full yet, start from beginning */
|
||
start_pos = 0;
|
||
} else {
|
||
/* Buffer is full, start from oldest packet */
|
||
start_pos = pl->context_buffer_pos;
|
||
}
|
||
/* Write context packets */
|
||
for (uint32_t i = 0; i < packets_to_dump; i++) {
|
||
uint32_t pos = (start_pos + i) % pl->context_buffer_size;
|
||
struct pcap_pkthdr *ctx_hdr = &pl->context_headers[pos];
|
||
uint8_t *ctx_data = pl->context_buffer[pos];
|
||
/* Write context packet directly using pcap_dump */
|
||
if (pl->pcap_dumper != NULL) {
|
||
pcap_dump((u_char *)pl->pcap_dumper, ctx_hdr, ctx_data);
|
||
pl->size_current += PCAP_PKTHDR_SIZE + ctx_hdr->caplen;
|
||
}
|
||
}
|
||
}
|
||
/* Store packet in context buffer for future "before" packets (except alert packets in
|
||
* conditional mode) */
|
||
/* Store ALL packets in context buffer for future "before" packets, but do this AFTER dumping
|
||
* "before" packets for alerts */
|
||
if ((pl->context_packets_before > 0 || pl->context_packets_after > 0) &&
|
||
pl->context_buffer != NULL) {
|
||
/* Store packets in the context buffer when context is enabled */
|
||
uint32_t pkt_len =
|
||
IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p) ? GET_PKT_LEN(p->root) : GET_PKT_LEN(p);
|
||
if (pkt_len > PCAP_SNAPLEN)
|
||
pkt_len = PCAP_SNAPLEN;
|
||
/* Store pcap header */
|
||
pl->context_headers[pl->context_buffer_pos].ts.tv_sec = SCTIME_SECS(p->ts);
|
||
pl->context_headers[pl->context_buffer_pos].ts.tv_usec = SCTIME_USECS(p->ts);
|
||
pl->context_headers[pl->context_buffer_pos].caplen = pkt_len;
|
||
pl->context_headers[pl->context_buffer_pos].len = pkt_len;
|
||
/* Store packet data */
|
||
const uint8_t *pkt_data = IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p) ? GET_PKT_DATA(p->root)
|
||
: GET_PKT_DATA(p);
|
||
memcpy(pl->context_buffer[pl->context_buffer_pos], pkt_data, pkt_len);
|
||
/* Update circular buffer position */
|
||
pl->context_buffer_pos = (pl->context_buffer_pos + 1) % pl->context_buffer_size;
|
||
if (pl->context_buffer_count < pl->context_buffer_size) {
|
||
pl->context_buffer_count++;
|
||
}
|
||
}
|
||
/* Handle "after" packets by checking flow state */
|
||
if (pl->context_packets_after > 0 && p->flow != NULL) {
|
||
/* Use the dedicated pcap_after_remaining field */
|
||
if (p->alerts.cnt > 0) {
|
||
/* Set "after" packet counter in flow */
|
||
p->flow->pcap_after_remaining = pl->context_packets_after;
|
||
SCLogNotice("PCAP-AFTER: alert resets counter to %u (flow %p)",
|
||
pl->context_packets_after, (void *)p->flow);
|
||
} else if (p->flow->pcap_after_remaining > 0) {
|
||
/* This is an "after" packet - decrement counter */
|
||
p->flow->pcap_after_remaining--;
|
||
do_write = true; /* after-packet */
|
||
SCLogNotice("PCAP-AFTER: wrote after-pkt, remaining=%u (flow %p)",
|
||
p->flow->pcap_after_remaining, (void *)p->flow);
|
||
}
|
||
}
|
||
/* For conditional modes ensure we only write if required */
|
||
if (!do_write && pl->conditional != LOGMODE_COND_ALL) {
|
||
SCLogNotice("PCAP-AFTER: skipped ordinary pkt, remaining=%u (flow %p)",
|
||
p->flow ? p->flow->pcap_after_remaining : 0, (void *)p->flow);
|
||
PCAPLOG_PROFILE_END(pl->profile_write);
|
||
PcapLogUnlock(pl);
|
||
return TM_ECODE_OK;
|
||
}
|
||
// Strategic flush points:
|
||
// 1. On flow end (natural termination)
|
||
// 2. On ALL "after" packets (to ensure context is captured)
|
||
// 3. On alert packets (since they trigger context tracking)
|
||
bool should_flush = (p->flags & PKT_PSEUDO_STREAM_END) || (p->alerts.cnt > 0) ||
|
||
(p->flow && pl->context_packets_after > 0 &&
|
||
p->flow->pcap_after_remaining >= 0 && do_write);
|
||
if (IS_TUNNEL_PKT(p) && !IS_TUNNEL_ROOT_PKT(p)) {
|
||
rp = p->root;
|
||
#ifdef HAVE_LIBLZ4
|
||
ret = PcapWrite(pl, comp, GET_PKT_DATA(rp), len);
|
||
ret = PcapWrite(pl, comp, GET_PKT_DATA(rp), len, should_flush);
|
||
#else
|
||
ret = PcapWrite(pl, NULL, GET_PKT_DATA(rp), len);
|
||
ret = PcapWrite(pl, NULL, GET_PKT_DATA(rp), len, should_flush);
|
||
#endif
|
||
} else {
|
||
#ifdef HAVE_LIBLZ4
|
||
ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len);
|
||
ret = PcapWrite(pl, comp, GET_PKT_DATA(p), len, should_flush);
|
||
#else
|
||
ret = PcapWrite(pl, NULL, GET_PKT_DATA(p), len);
|
||
ret = PcapWrite(pl, NULL, GET_PKT_DATA(p), len, should_flush);
|
||
#endif
|
||
}
|
||
if (ret != TM_ECODE_OK) {
|
||
... | ... | |
PCAPLOG_PROFILE_END(pl->profile_write);
|
||
pl->profile_data_size += len;
|
||
SCLogDebug("pl->size_current %"PRIu64", pl->size_limit %"PRIu64,
|
||
pl->size_current, pl->size_limit);
|
||
SCLogDebug("pl->size_current %" PRIu64 ", pl->size_limit %" PRIu64, pl->size_current,
|
||
pl->size_limit);
|
||
PcapLogUnlock(pl);
|
||
return TM_ECODE_OK;
|
||
... | ... | |
copy->size_limit = pl->size_limit;
|
||
copy->conditional = pl->conditional;
|
||
/* Copy context settings */
|
||
copy->context_packets_before = pl->context_packets_before;
|
||
copy->context_packets_after = pl->context_packets_after;
|
||
copy->context_buffer_size = pl->context_buffer_size;
|
||
copy->context_buffer_pos = 0;
|
||
copy->context_buffer_count = 0;
|
||
/* Allocate context buffers if needed */
|
||
if (pl->context_buffer_size > 0) {
|
||
copy->context_buffer = SCCalloc(copy->context_buffer_size, sizeof(uint8_t *));
|
||
if (copy->context_buffer == NULL) {
|
||
SCLogError("Failed to allocate context buffer array");
|
||
goto fail_copy;
|
||
}
|
||
for (uint32_t i = 0; i < copy->context_buffer_size; i++) {
|
||
copy->context_buffer[i] = SCMalloc(PCAP_SNAPLEN);
|
||
if (copy->context_buffer[i] == NULL) {
|
||
SCLogError("Failed to allocate context buffer slot %u", i);
|
||
goto fail_copy;
|
||
}
|
||
}
|
||
copy->context_headers = SCCalloc(copy->context_buffer_size, sizeof(struct pcap_pkthdr));
|
||
if (copy->context_headers == NULL) {
|
||
SCLogError("Failed to allocate context headers");
|
||
goto fail_copy;
|
||
}
|
||
} else {
|
||
copy->context_buffer = NULL;
|
||
copy->context_headers = NULL;
|
||
}
|
||
const PcapLogCompressionData *comp = &pl->compression;
|
||
PcapLogCompressionData *copy_comp = ©->compression;
|
||
copy_comp->format = comp->format;
|
||
... | ... | |
copy_comp->buffer = SCMalloc(copy_comp->buffer_size);
|
||
if (copy_comp->buffer == NULL) {
|
||
SCLogError("SCMalloc failed: %s", strerror(errno));
|
||
SCFree(copy->h);
|
||
SCFree(copy);
|
||
return NULL;
|
||
goto fail_copy;
|
||
}
|
||
copy_comp->pcap_buf = SCMalloc(copy_comp->pcap_buf_size);
|
||
if (copy_comp->pcap_buf == NULL) {
|
||
SCLogError("SCMalloc failed: %s", strerror(errno));
|
||
SCFree(copy_comp->buffer);
|
||
SCFree(copy->h);
|
||
SCFree(copy);
|
||
return NULL;
|
||
goto fail_copy;
|
||
}
|
||
copy_comp->pcap_buf_wrapper = SCFmemopen(copy_comp->pcap_buf,
|
||
copy_comp->pcap_buf_size, "w");
|
||
copy_comp->pcap_buf_wrapper =
|
||
SCFmemopen(copy_comp->pcap_buf, copy_comp->pcap_buf_size, "w");
|
||
if (copy_comp->pcap_buf_wrapper == NULL) {
|
||
SCLogError("SCFmemopen failed: %s", strerror(errno));
|
||
SCFree(copy_comp->buffer);
|
||
SCFree(copy_comp->pcap_buf);
|
||
SCFree(copy->h);
|
||
SCFree(copy);
|
||
return NULL;
|
||
goto fail_copy;
|
||
}
|
||
/* Initialize a new compression context. */
|
||
LZ4F_errorCode_t errcode =
|
||
LZ4F_createCompressionContext(©_comp->lz4f_context, 1);
|
||
LZ4F_errorCode_t errcode = LZ4F_createCompressionContext(©_comp->lz4f_context, 1);
|
||
if (LZ4F_isError(errcode)) {
|
||
SCLogError("LZ4F_createCompressionContext failed: %s", LZ4F_getErrorName(errcode));
|
||
fclose(copy_comp->pcap_buf_wrapper);
|
||
SCFree(copy_comp->buffer);
|
||
SCFree(copy_comp->pcap_buf);
|
||
SCFree(copy->h);
|
||
SCFree(copy);
|
||
return NULL;
|
||
goto fail_copy;
|
||
}
|
||
/* Initialize the rest. */
|
||
... | ... | |
SCLogDebug("copied, returning %p", copy);
|
||
return copy;
|
||
fail_copy:
|
||
if (copy) {
|
||
if (copy->context_buffer) {
|
||
for (uint32_t i = 0; i < copy->context_buffer_size; i++) {
|
||
SCFree(copy->context_buffer[i]);
|
||
}
|
||
SCFree(copy->context_buffer);
|
||
}
|
||
SCFree(copy->context_headers);
|
||
#ifdef HAVE_LIBLZ4
|
||
if (copy->compression.format == PCAP_LOG_COMPRESSION_FORMAT_LZ4) {
|
||
if (copy->compression.pcap_buf_wrapper) {
|
||
fclose(copy->compression.pcap_buf_wrapper);
|
||
}
|
||
SCFree(copy->compression.buffer);
|
||
SCFree(copy->compression.pcap_buf);
|
||
if (copy->compression.lz4f_context) {
|
||
LZ4F_freeCompressionContext(copy->compression.lz4f_context);
|
||
}
|
||
}
|
||
#endif
|
||
SCFree(copy->prefix);
|
||
SCFree(copy->h);
|
||
SCFree(copy);
|
||
}
|
||
return NULL;
|
||
}
|
||
#ifdef INIT_RING_BUFFER
|
||
static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs,
|
||
uint32_t *usecs)
|
||
static int PcapLogGetTimeOfFile(const char *filename, uint64_t *secs, uint32_t *usecs)
|
||
{
|
||
char buf[PATH_MAX];
|
||
size_t copylen;
|
||
... | ... | |
{
|
||
char pattern[PATH_MAX];
|
||
SCLogInfo("Initializing PCAP ring buffer for %s/%s.",
|
||
pl->dir, pl->prefix);
|
||
SCLogInfo("Initializing PCAP ring buffer for %s/%s.", pl->dir, pl->prefix);
|
||
strlcpy(pattern, pl->dir, PATH_MAX);
|
||
if (pattern[strlen(pattern) - 1] != '/') {
|
||
... | ... | |
return TM_ECODE_FAILED;
|
||
case 'n': {
|
||
char tmp[PATH_MAX];
|
||
snprintf(tmp, PATH_MAX, "%"PRIu32, pl->thread_number);
|
||
snprintf(tmp, PATH_MAX, "%" PRIu32, pl->thread_number);
|
||
strlcat(pattern, tmp, PATH_MAX);
|
||
break;
|
||
}
|
||
... | ... | |
} else {
|
||
/* Ordered insert. */
|
||
PcapFileName *it = NULL;
|
||
TAILQ_FOREACH(it, &pl->pcap_file_list, next) {
|
||
TAILQ_FOREACH (it, &pl->pcap_file_list, next) {
|
||
if (pf->secs < it->secs) {
|
||
break;
|
||
} else if (pf->secs == it->secs && pf->usecs < it->usecs) {
|
||
... | ... | |
SCFree(pl->compression.buffer);
|
||
fclose(pl->compression.pcap_buf_wrapper);
|
||
SCFree(pl->compression.pcap_buf);
|
||
LZ4F_errorCode_t errcode =
|
||
LZ4F_freeCompressionContext(pl->compression.lz4f_context);
|
||
LZ4F_errorCode_t errcode = LZ4F_freeCompressionContext(pl->compression.lz4f_context);
|
||
if (LZ4F_isError(errcode)) {
|
||
SCLogWarning("Error freeing lz4 context.");
|
||
}
|
||
}
|
||
#endif /* HAVE_LIBLZ4 */
|
||
if (pl->context_buffer) {
|
||
for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
|
||
SCFree(pl->context_buffer[i]);
|
||
}
|
||
SCFree(pl->context_buffer);
|
||
}
|
||
SCFree(pl->context_headers);
|
||
SCFree(pl);
|
||
}
|
||
... | ... | |
PcapLogData *pl = td->pcap_log;
|
||
if (pl->pcap_dumper != NULL) {
|
||
if (PcapLogCloseFile(t,pl) < 0) {
|
||
PcapLogFlush(pl);
|
||
SCLogNotice("PCAP: flushing at thread cleanup for end of processing");
|
||
if (PcapLogCloseFile(t, pl) < 0) {
|
||
SCLogDebug("PcapLogCloseFile failed");
|
||
}
|
||
}
|
||
... | ... | |
return TM_ECODE_OK;
|
||
}
|
||
static int ParseFilename(PcapLogData *pl, const char *filename)
|
||
{
|
||
char *toks[MAX_TOKS] = { NULL };
|
||
... | ... | |
if (filename) {
|
||
filename_len = strlen(filename);
|
||
if (filename_len > (MAX_FILENAMELEN-1)) {
|
||
if (filename_len > (MAX_FILENAMELEN - 1)) {
|
||
SCLogError("invalid filename option. Max filename-length: %d", MAX_FILENAMELEN - 1);
|
||
goto error;
|
||
}
|
||
... | ... | |
str[s++] = filename[i];
|
||
if (filename[i] == '%') {
|
||
str[s-1] = '\0';
|
||
str[s - 1] = '\0';
|
||
SCLogDebug("filename with %%-sign: %s", str);
|
||
p = SCStrdup(str);
|
||
... | ... | |
s = 0;
|
||
if (i+1 < (int)strlen(filename)) {
|
||
if (i + 1 < (int)strlen(filename)) {
|
||
if (tok >= MAX_TOKS) {
|
||
SCLogError("invalid filename option. Max 2 %%-sign options");
|
||
goto error;
|
||
}
|
||
if (filename[i+1] != 'n' && filename[i+1] != 't' && filename[i+1] != 'i') {
|
||
if (filename[i + 1] != 'n' && filename[i + 1] != 't' &&
|
||
filename[i + 1] != 'i') {
|
||
SCLogError(
|
||
"invalid filename option. Valid %%-sign options: %%n, %%i and %%t");
|
||
goto error;
|
||
}
|
||
str[0] = '%';
|
||
str[1] = filename[i+1];
|
||
str[1] = filename[i + 1];
|
||
str[2] = '\0';
|
||
p = SCStrdup(str);
|
||
if (p == NULL)
|
||
... | ... | |
if (tok >= MAX_TOKS) {
|
||
SCLogError("invalid filename option. Max 3 %%-sign options");
|
||
goto error;
|
||
}
|
||
str[s++] = '\0';
|
||
p = SCStrdup(str);
|
||
... | ... | |
exit(EXIT_FAILURE);
|
||
}
|
||
if (pl->size_limit < 4096) {
|
||
SCLogInfo("pcap-log \"limit\" value of %"PRIu64" assumed to be pre-1.2 "
|
||
"style: setting limit to %"PRIu64"mb", pl->size_limit, pl->size_limit);
|
||
SCLogInfo("pcap-log \"limit\" value of %" PRIu64 " assumed to be pre-1.2 "
|
||
"style: setting limit to %" PRIu64 "mb",
|
||
pl->size_limit, pl->size_limit);
|
||
uint64_t size = pl->size_limit * 1024 * 1024;
|
||
pl->size_limit = size;
|
||
} else if (pl->size_limit < MIN_LIMIT) {
|
||
... | ... | |
const char *log_dir = NULL;
|
||
log_dir = ConfigGetLogDirectory();
|
||
strlcpy(pl->dir,
|
||
log_dir, sizeof(pl->dir));
|
||
SCLogInfo("Using log dir %s", pl->dir);
|
||
strlcpy(pl->dir, log_dir, sizeof(pl->dir));
|
||
SCLogInfo("Using log dir %s", pl->dir);
|
||
}
|
||
} else {
|
||
if (PathIsAbsolute(s_dir)) {
|
||
strlcpy(pl->dir,
|
||
s_dir, sizeof(pl->dir));
|
||
strlcpy(pl->dir, s_dir, sizeof(pl->dir));
|
||
} else {
|
||
const char *log_dir = NULL;
|
||
log_dir = ConfigGetLogDirectory();
|
||
snprintf(pl->dir, sizeof(pl->dir), "%s/%s",
|
||
log_dir, s_dir);
|
||
snprintf(pl->dir, sizeof(pl->dir), "%s/%s", log_dir, s_dir);
|
||
}
|
||
struct stat stat_buf;
|
||
... | ... | |
SCLogInfo("Using log dir %s", pl->dir);
|
||
}
|
||
const char *compression_str = ConfNodeLookupChildValue(conf,
|
||
"compression");
|
||
const char *compression_str = ConfNodeLookupChildValue(conf, "compression");
|
||
PcapLogCompressionData *comp = &pl->compression;
|
||
if (compression_str == NULL || strcmp(compression_str, "none") == 0) {
|
||
... | ... | |
/* Use SCFmemopen so we can make pcap_dump write to a buffer. */
|
||
comp->pcap_buf_size = sizeof(struct pcap_file_header) +
|
||
sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN;
|
||
comp->pcap_buf_size =
|
||
sizeof(struct pcap_file_header) + sizeof(struct pcap_pkthdr) + PCAP_SNAPLEN;
|
||
comp->pcap_buf = SCMalloc(comp->pcap_buf_size);
|
||
if (comp->pcap_buf == NULL) {
|
||
SCLogError("SCMalloc failed: %s", strerror(errno));
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf,
|
||
comp->pcap_buf_size, "w");
|
||
comp->pcap_buf_wrapper = SCFmemopen(comp->pcap_buf, comp->pcap_buf_size, "w");
|
||
if (comp->pcap_buf_wrapper == NULL) {
|
||
SCLogError("SCFmemopen failed: %s", strerror(errno));
|
||
exit(EXIT_FAILURE);
|
||
... | ... | |
comp->lz4f_prefs.frameInfo.blockMode = LZ4F_blockLinked;
|
||
if (ConfNodeChildValueIsTrue(conf, "lz4-checksum")) {
|
||
comp->lz4f_prefs.frameInfo.contentChecksumFlag = 1;
|
||
}
|
||
else {
|
||
} else {
|
||
comp->lz4f_prefs.frameInfo.contentChecksumFlag = 0;
|
||
}
|
||
intmax_t lvl = 0;
|
||
... | ... | |
/* Allocate resources for lz4. */
|
||
LZ4F_errorCode_t errcode =
|
||
LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1);
|
||
LZ4F_createCompressionContext(&pl->compression.lz4f_context, 1);
|
||
if (LZ4F_isError(errcode)) {
|
||
SCLogError("LZ4F_createCompressionContext failed: %s", LZ4F_getErrorName(errcode));
|
||
... | ... | |
/* Calculate the size of the lz4 output buffer. */
|
||
comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size,
|
||
&comp->lz4f_prefs);
|
||
comp->buffer_size = LZ4F_compressBound(comp->pcap_buf_size, &comp->lz4f_prefs);
|
||
comp->buffer = SCMalloc(comp->buffer_size);
|
||
if (unlikely(comp->buffer == NULL)) {
|
||
... | ... | |
PcapLogDataFree(pl);
|
||
return result;
|
||
#endif /* HAVE_LIBLZ4 */
|
||
}
|
||
else {
|
||
} else {
|
||
SCLogError("Unsupported pcap-log "
|
||
"compression format: %s",
|
||
compression_str);
|
||
... | ... | |
"Selected pcap-log conditional logging: %s", s_conditional ? s_conditional : "all");
|
||
}
|
||
const char *context_before = ConfNodeLookupChildValue(conf, "context-packets-before");
|
||
if (context_before != NULL) {
|
||
if (StringParseUint32(&pl->context_packets_before, 10, 0, context_before) < 0) {
|
||
SCLogError("Invalid context-packets-before value: %s", context_before);
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
if (pl->context_packets_before > 0) {
|
||
pl->context_buffer_size = pl->context_packets_before;
|
||
pl->context_buffer = SCCalloc(pl->context_buffer_size, sizeof(uint8_t *));
|
||
pl->context_headers = SCCalloc(pl->context_buffer_size, sizeof(struct pcap_pkthdr));
|
||
if (!pl->context_buffer || !pl->context_headers) {
|
||
SCLogError("Failed to allocate context buffer");
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
for (uint32_t i = 0; i < pl->context_buffer_size; i++) {
|
||
pl->context_buffer[i] = SCMalloc(PCAP_SNAPLEN);
|
||
if (!pl->context_buffer[i]) {
|
||
SCLogError("Failed to allocate context packet buffer");
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
const char *context_after = ConfNodeLookupChildValue(conf, "context-packets-after");
|
||
if (context_after != NULL) {
|
||
if (StringParseUint32(&pl->context_packets_after, 10, 0, context_after) < 0) {
|
||
SCLogError("Invalid context-packets-after value: %s", context_after);
|
||
exit(EXIT_FAILURE);
|
||
}
|
||
}
|
||
if (ParseFilename(pl, filename) != 0)
|
||
exit(EXIT_FAILURE);
|
||
SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL ?
|
||
"Sguil compatible" : (pl->mode == LOGMODE_MULTI ? "multi" : "normal"));
|
||
SCLogInfo("using %s logging", pl->mode == LOGMODE_SGUIL
|
||
? "Sguil compatible"
|
||
: (pl->mode == LOGMODE_MULTI ? "multi" : "normal"));
|
||
uint32_t max_file_limit = DEFAULT_FILE_LIMIT;
|
||
if (conf != NULL) {
|
||
const char *max_number_of_files_s = NULL;
|
||
max_number_of_files_s = ConfNodeLookupChildValue(conf, "max-files");
|
||
if (max_number_of_files_s != NULL) {
|
||
if (StringParseUint32(&max_file_limit, 10, 0,
|
||
max_number_of_files_s) == -1) {
|
||
if (StringParseUint32(&max_file_limit, 10, 0, max_number_of_files_s) == -1) {
|
||
SCLogError("Failed to initialize "
|
||
"pcap-log output, invalid number of files limit: %s",
|
||
max_number_of_files_s);
|
||
... | ... | |
PcapLogData *pl = output_ctx->data;
|
||
PcapFileName *pf = NULL;
|
||
TAILQ_FOREACH(pf, &pl->pcap_file_list, next) {
|
||
TAILQ_FOREACH (pf, &pl->pcap_file_list, next) {
|
||
SCLogDebug("PCAP files left at exit: %s\n", pf->filename);
|
||
}
|
||
PcapLogDataFree(pl);
|
||
... | ... | |
char dirname[32], dirfull[PATH_MAX] = "";
|
||
snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d",
|
||
tms->tm_year + 1900, tms->tm_mon + 1, tms->tm_mday);
|
||
snprintf(dirname, sizeof(dirname), "%04d-%02d-%02d", tms->tm_year + 1900, tms->tm_mon + 1,
|
||
tms->tm_mday);
|
||
/* create the filename to use */
|
||
int ret = snprintf(dirfull, sizeof(dirfull), "%s/%s", pl->dir, dirname);
|
||
... | ... | |
int i;
|
||
for (i = 0; i < pl->filename_part_cnt; i++) {
|
||
if (pl->filename_parts[i] == NULL ||strlen(pl->filename_parts[i]) == 0)
|
||
if (pl->filename_parts[i] == NULL || strlen(pl->filename_parts[i]) == 0)
|
||
continue;
|