* This module is primarily for development and test.
-=== User Module
+=== Hext Module
-The user module generates packets suitable for processing with Snort's
-stream_user from simple text input. The first character of the line
-determines it's purpose:
+The hext module generates packets suitable for processing by Snort from
+hex/plain text. Raw packets include full headers and are processed
+normally. Otherwise the packets contain only payload and are accompanied
+with flow information (4-tuple) suitable for processing by stream_user.
+
+The first character of the line determines it's purpose:
'$' command
'#' comment
\\ = 0x5C = \
Format your input carefully; there is minimal error checking and little
-tolerance for arbitrary whitespace. You can use Snort's -L user option to
-generate user input from a pcap.
+tolerance for arbitrary whitespace. You can use Snort's -L hext option to
+generate hext input from a pcap.
* This module only supports ip4 traffic.
* This module is primarily for development and test.
+The hext DAQ also supports a raw mode which is activated by setting the
+data link type. For example, you can input full ethernet packets with
+--daq-var dlt=1 (Data link types are defined in the DAQ include
+sfbpf_dlt.h.) Combine that with the hext logger in raw mode for a quick
+(and dirty) way to edit pcaps. With --lua "log_hext = { raw = true }", the
+hext logger will dump the full packet in a way that can be read by the hext
+DAQ in raw mode. Here is an example:
+
+ # 3 [96]
+
+ x02 09 08 07 06 05 02 01 02 03 04 05 08 00 45 00 00 52 00 03 # ..............E..R..
+ x00 00 40 06 5C 90 0A 01 02 03 0A 09 08 07 BD EC 00 50 00 00 # ..@.\............P..
+ x00 02 00 00 00 02 50 10 20 00 8A E1 00 00 47 45 54 20 2F 74 # ......P. .....GET /t
+ x72 69 67 67 65 72 2F 31 20 48 54 54 50 2F 31 2E 31 0D 0A 48 # rigger/1 HTTP/1.1..H
+ x6F 73 74 3A 20 6C 6F 63 61 6C 68 6F 73 74 0D 0A # ost: localhost..
+
+A comment indicating packet number and size precedes each packet dump.
+Note that the commands are not applicable in raw mode and have no effect.
+
snort.decode_flags |= DECODE_SOF;
if ( pci->flags & DAQ_SKT_FLAG_END_FLOW )
- {
snort.decode_flags |= DECODE_EOF;
- codec.lyr_len = 1; // eat pseudo-octet
- }
- else
- codec.lyr_len = 0;
+
+ codec.lyr_len = 0;
}
bool SocketCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
add_example_library(daq_socket daqs daq_socket.c daq_socket.h)
add_example_library(daq_file daqs daq_file.c daq_socket.h)
-add_example_library(daq_user daqs daq_user.c daq_socket.h)
+add_example_library(daq_hext daqs daq_hext.c daq_socket.h)
daq_file_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
daq_file_la_SOURCES = daq_file.c daq_socket.h
-daqlib_LTLIBRARIES += daq_user.la
-daq_user_la_CFLAGS = -DBUILDING_SO
-daq_user_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
-daq_user_la_SOURCES = daq_user.c daq_socket.h
+daqlib_LTLIBRARIES += daq_hext.la
+daq_hext_la_CFLAGS = -DBUILDING_SO
+daq_hext_la_LDFLAGS = -module -export-dynamic -avoid-version -shared
+daq_hext_la_SOURCES = daq_hext.c daq_socket.h
AM_CFLAGS = @AM_CFLAGS@
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
*/
-/* daq_user.c author Russ Combs <rucombs@cisco.com> */
+/* daq_hext.c author Russ Combs <rucombs@cisco.com> */
#include "daq_socket.h"
#include <sfbpf_dlt.h>
#define DAQ_MOD_VERSION 0
-#define DAQ_NAME "user"
+#define DAQ_NAME "hext"
#define DAQ_TYPE (DAQ_TYPE_FILE_CAPABLE|DAQ_TYPE_INTF_CAPABLE|DAQ_TYPE_MULTI_INSTANCE)
#define DEF_BUF_SZ 16384
int start;
int stop;
int eof;
- int fsm;
+ int dlt;
unsigned snaplen;
unsigned idx;
// file functions
//-------------------------------------------------------------------------
-static int user_setup(FileImpl* impl)
+static int hext_setup(FileImpl* impl)
{
if ( !strcmp(impl->name, "tty") )
{
DAQ_NAME, strerror(errno));
return -1;
}
- parse_host("192.168.1.1 12345", &impl->cfg.src_addr, &impl->cfg.src_port);
+ parse_host("192.168.1.2 12345", &impl->cfg.src_addr, &impl->cfg.src_port);
parse_host("10.1.2.3 80", &impl->cfg.dst_addr, &impl->cfg.dst_port);
impl->cfg.ip_proto = impl->pci.ip_proto = IPPROTO_TCP;
return 0;
}
-static void user_cleanup(FileImpl* impl)
+static void hext_cleanup(FileImpl* impl)
{
if ( impl->fyle != stdin )
fclose(impl->fyle);
impl->fyle = NULL;
}
-static int user_read(FileImpl* impl)
+static int hext_read(FileImpl* impl)
{
int n = 0;
if ( !n )
{
- if ( !impl->eof )
+ if ( (impl->dlt == DLT_SOCKET) && !impl->eof )
{
impl->eof = 1;
return 1; // <= zero won't make it :(
// daq utilities
//-------------------------------------------------------------------------
+static int get_vars (
+ FileImpl* impl, const DAQ_Config_t* cfg, char* errBuf, size_t errMax
+) {
+ const char* s = NULL;
+ DAQ_Dict* entry;
+
+ for ( entry = cfg->values; entry; entry = entry->next)
+ {
+ if ( !strcmp(entry->key, "dlt") )
+ s = entry->value;
+
+ else
+ {
+ snprintf(errBuf, errMax, "unknown var (%s)", s);
+ return 0;
+ }
+ }
+ if ( s )
+ impl->dlt = atoi(s);
+
+ return 1;
+}
+
static void set_pkt_hdr(FileImpl* impl, DAQ_PktHdr_t* phdr, ssize_t len)
{
struct timeval t;
phdr->address_space_id = 0;
phdr->opaque = 0;
+ if ( impl->dlt != DLT_SOCKET )
+ {
+ phdr->priv_ptr = NULL;
+ return;
+ }
impl->pci.flags &= ~(DAQ_SKT_FLAG_START_FLOW|DAQ_SKT_FLAG_END_FLOW);
if ( impl->start )
// forward all but drops, retries and blacklists:
static const int s_fwd[MAX_DAQ_VERDICT] = { 1, 0, 1, 1, 0, 1, 0 };
-static int user_daq_process(
+static int hext_daq_process(
FileImpl* impl, DAQ_Analysis_Func_t cb, void* user)
{
DAQ_PktHdr_t hdr;
- int n = user_read(impl);
+ int n = hext_read(impl);
if ( n < 1 )
return n;
// daq
//-------------------------------------------------------------------------
-static void user_daq_shutdown (void* handle)
+static void hext_daq_shutdown (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
//-------------------------------------------------------------------------
-static int user_daq_initialize (
+static int hext_daq_initialize (
const DAQ_Config_t* cfg, void** handle, char* errBuf, size_t errMax)
{
FileImpl* impl = calloc(1, sizeof(*impl));
return DAQ_ERROR_NOMEM;
}
- impl->fyle = NULL;
- impl->start = impl->stop = 0;
impl->snaplen = cfg->snaplen ? cfg->snaplen : DEF_BUF_SZ;
+ impl->dlt = DLT_SOCKET;
- impl->idx = 0;
- impl->fsm = 0;
- impl->line[0] = '\0';
+ if ( !get_vars(impl, cfg, errBuf, errMax) )
+ {
+ free(impl);
+ return DAQ_ERROR;
+ }
if ( cfg->name )
{
if ( !(impl->buf = malloc(impl->snaplen)) )
{
snprintf(errBuf, errMax, "%s: failed to allocate the ipfw buffer", DAQ_NAME);
- user_daq_shutdown(impl);
+ hext_daq_shutdown(impl);
return DAQ_ERROR_NOMEM;
}
//-------------------------------------------------------------------------
-static int user_daq_start (void* handle)
+static int hext_daq_start (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
- if ( user_setup(impl) )
+ if ( hext_setup(impl) )
return DAQ_ERROR;
impl->state = DAQ_STATE_STARTED;
return DAQ_SUCCESS;
}
-static int user_daq_stop (void* handle)
+static int hext_daq_stop (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
- user_cleanup(impl);
+ hext_cleanup(impl);
impl->state = DAQ_STATE_STOPPED;
return DAQ_SUCCESS;
}
//-------------------------------------------------------------------------
-static int user_daq_inject (
+static int hext_daq_inject (
void* handle, const DAQ_PktHdr_t* hdr, const uint8_t* buf, uint32_t len, int rev)
{
(void)handle;
//-------------------------------------------------------------------------
-static int user_daq_acquire (
+static int hext_daq_acquire (
void* handle, int cnt, DAQ_Analysis_Func_t callback, DAQ_Meta_Func_t meta, void* user)
{
(void)meta;
while ( hit < cnt || cnt <= 0 )
{
- int status = user_daq_process(impl, callback, user);
+ int status = hext_daq_process(impl, callback, user);
if ( status > 0 )
{
//-------------------------------------------------------------------------
-static int user_daq_breakloop (void* handle)
+static int hext_daq_breakloop (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
impl->stop = 1;
return DAQ_SUCCESS;
}
-static DAQ_State user_daq_check_status (void* handle)
+static DAQ_State hext_daq_check_status (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
return impl->state;
}
-static int user_daq_get_stats (void* handle, DAQ_Stats_t* stats)
+static int hext_daq_get_stats (void* handle, DAQ_Stats_t* stats)
{
FileImpl* impl = (FileImpl*)handle;
*stats = impl->stats;
return DAQ_SUCCESS;
}
-static void user_daq_reset_stats (void* handle)
+static void hext_daq_reset_stats (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
memset(&impl->stats, 0, sizeof(impl->stats));
}
-static int user_daq_get_snaplen (void* handle)
+static int hext_daq_get_snaplen (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
return impl->snaplen;
}
-static uint32_t user_daq_get_capabilities (void* handle)
+static uint32_t hext_daq_get_capabilities (void* handle)
{
(void)handle;
return DAQ_CAPA_BLOCK | DAQ_CAPA_REPLACE | DAQ_CAPA_INJECT | DAQ_CAPA_INJECT_RAW
| DAQ_CAPA_BREAKLOOP | DAQ_CAPA_UNPRIV_START;
}
-static int user_daq_get_datalink_type(void *handle)
+static int hext_daq_get_datalink_type(void *handle)
{
- (void)handle;
- return DLT_SOCKET;
+ FileImpl* impl = (FileImpl*)handle;
+ return impl->dlt;
}
-static const char* user_daq_get_errbuf (void* handle)
+static const char* hext_daq_get_errbuf (void* handle)
{
FileImpl* impl = (FileImpl*)handle;
return impl->error;
}
-static void user_daq_set_errbuf (void* handle, const char* s)
+static void hext_daq_set_errbuf (void* handle, const char* s)
{
FileImpl* impl = (FileImpl*)handle;
DPE(impl->error, "%s", s ? s : "");
}
-static int user_daq_get_device_index(void* handle, const char* device)
+static int hext_daq_get_device_index(void* handle, const char* device)
{
(void)handle;
(void)device;
return DAQ_ERROR_NOTSUP;
}
-static int user_daq_set_filter (void* handle, const char* filter)
+static int hext_daq_set_filter (void* handle, const char* filter)
{
(void)handle;
(void)filter;
#ifdef BUILDING_SO
DAQ_SO_PUBLIC DAQ_Module_t DAQ_MODULE_DATA =
#else
-DAQ_Module_t user_daq_module_data =
+DAQ_Module_t hext_daq_module_data =
#endif
{
.api_version = DAQ_API_VERSION,
.module_version = DAQ_MOD_VERSION,
.name = DAQ_NAME,
.type = DAQ_TYPE,
- .initialize = user_daq_initialize,
- .set_filter = user_daq_set_filter,
- .start = user_daq_start,
- .acquire = user_daq_acquire,
- .inject = user_daq_inject,
- .breakloop = user_daq_breakloop,
- .stop = user_daq_stop,
- .shutdown = user_daq_shutdown,
- .check_status = user_daq_check_status,
- .get_stats = user_daq_get_stats,
- .reset_stats = user_daq_reset_stats,
- .get_snaplen = user_daq_get_snaplen,
- .get_capabilities = user_daq_get_capabilities,
- .get_datalink_type = user_daq_get_datalink_type,
- .get_errbuf = user_daq_get_errbuf,
- .set_errbuf = user_daq_set_errbuf,
- .get_device_index = user_daq_get_device_index,
+ .initialize = hext_daq_initialize,
+ .set_filter = hext_daq_set_filter,
+ .start = hext_daq_start,
+ .acquire = hext_daq_acquire,
+ .inject = hext_daq_inject,
+ .breakloop = hext_daq_breakloop,
+ .stop = hext_daq_stop,
+ .shutdown = hext_daq_shutdown,
+ .check_status = hext_daq_check_status,
+ .get_stats = hext_daq_get_stats,
+ .reset_stats = hext_daq_reset_stats,
+ .get_snaplen = hext_daq_get_snaplen,
+ .get_capabilities = hext_daq_get_capabilities,
+ .get_datalink_type = hext_daq_get_datalink_type,
+ .get_errbuf = hext_daq_get_errbuf,
+ .set_errbuf = hext_daq_set_errbuf,
+ .get_device_index = hext_daq_get_device_index,
.modify_flow = NULL,
.hup_prep = NULL,
.hup_apply = NULL,
add_example_library(alert_ex loggers alert_ex.cc)
-add_example_library(log_user loggers log_user.cc)
+add_example_library(log_hext loggers log_hext.cc)
install (
FILES alert.lua
libalert_ex_la_LDFLAGS = -export-dynamic -shared
libalert_ex_la_SOURCES = alert_ex.cc
-loglib_LTLIBRARIES += liblog_user.la
-liblog_user_la_CXXFLAGS = $(AM_CXXFLAGS)
-liblog_user_la_LDFLAGS = -export-dynamic -shared
-liblog_user_la_SOURCES = log_user.cc
+loglib_LTLIBRARIES += liblog_hext.la
+liblog_hext_la_CXXFLAGS = $(AM_CXXFLAGS)
+liblog_hext_la_LDFLAGS = -export-dynamic -shared
+liblog_hext_la_SOURCES = log_hext.cc
dist_loglib_SCRIPTS = alert.lua
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
-// log_user.cc author Russ Combs <rucombs@cisco.com>
+// log_hext.cc author Russ Combs <rucombs@cisco.com>
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "log/text_log.h"
#include "sfip/sf_ip.h"
-#define S_NAME "log_user"
+#define S_NAME "log_hext"
#define F_NAME S_NAME ".txt"
-static const char* s_help = "output payload suitable for daq user";
+static const char* s_help = "output payload suitable for daq hext";
-static THREAD_LOCAL TextLog* user_log = nullptr;
+static THREAD_LOCAL TextLog* hext_log = nullptr;
+static THREAD_LOCAL unsigned s_pkt_num = 0;
//-------------------------------------------------------------------------
// impl stuff
#define LOG_CHARS 20
+static void log_raw(const Packet* p)
+{
+ TextLog_Print(hext_log, "\n# %u [%u]\n",
+ s_pkt_num++, p->pkth->caplen);
+}
+
static void log_header(const Packet* p)
{
char src[INET6_ADDRSTRLEN];
addr = p->ptrs.ip_api.get_dst();
sfip_ntop(addr, dst, sizeof(dst));
- TextLog_Print(user_log, "\n$packet %s %d -> %s %d\n",
+ TextLog_Print(hext_log, "\n$packet %s %d -> %s %d\n",
src, p->ptrs.sp, dst, p->ptrs.dp);
}
char txt[LOG_CHARS+1];
unsigned odx = 0, idx = 0;
- TextLog_NewLine(user_log);
+ TextLog_NewLine(hext_log);
for ( idx = 0; idx < n; idx++)
{
if ( odx == LOG_CHARS )
{
txt[odx] = hex[3*odx] = '\0';
- TextLog_Print(user_log, "x%s # %s\n", hex, txt);
+ TextLog_Print(hext_log, "x%s # %s\n", hex, txt);
odx = 0;
}
}
if ( odx )
{
txt[odx] = hex[3*odx] = '\0';
- TextLog_Print(user_log, "x%s", hex);
+ TextLog_Print(hext_log, "x%s", hex);
while ( odx++ < LOG_CHARS )
- TextLog_Print(user_log, " ");
+ TextLog_Print(hext_log, " ");
- TextLog_Print(user_log, " # %s\n", txt);
+ TextLog_Print(hext_log, " # %s\n", txt);
}
}
{ "file", Parameter::PT_BOOL, nullptr, "false",
"output to " F_NAME " instead of stdout" },
+ { "raw", Parameter::PT_BOOL, nullptr, "false",
+ "output all full packets if true, else just TCP payload" },
+
{ "limit", Parameter::PT_INT, "0:", "0",
"set limit (0 is unlimited)" },
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
-class UserModule : public Module
+class HextModule : public Module
{
public:
- UserModule() : Module(S_NAME, s_help, s_params) { }
+ HextModule() : Module(S_NAME, s_help, s_params) { }
bool set(const char*, Value&, SnortConfig*) override;
bool begin(const char*, int, SnortConfig*) override;
public:
bool file;
+ bool raw;
unsigned long limit;
unsigned units;
};
-bool UserModule::set(const char*, Value& v, SnortConfig*)
+bool HextModule::set(const char*, Value& v, SnortConfig*)
{
if ( v.is("file") )
file = v.get_bool();
+ else if ( v.is("raw") )
+ raw = v.get_bool();
+
else if ( v.is("limit") )
limit = v.get_long();
return true;
}
-bool UserModule::begin(const char*, int, SnortConfig*)
+bool HextModule::begin(const char*, int, SnortConfig*)
{
file = false;
+ raw = false;
limit = 0;
units = 0;
return true;
}
-bool UserModule::end(const char*, int, SnortConfig*)
+bool HextModule::end(const char*, int, SnortConfig*)
{
while ( units-- )
limit *= 1024;
// logger stuff
//-------------------------------------------------------------------------
-class UserLogger : public Logger
+class HextLogger : public Logger
{
public:
- UserLogger(UserModule*);
+ HextLogger(HextModule*);
void open() override;
void close() override;
private:
string file;
unsigned long limit;
+ bool raw;
};
-UserLogger::UserLogger(UserModule* m)
+HextLogger::HextLogger(HextModule* m)
{
file = m->file ? F_NAME : "stdout";
limit = m->limit;
+ raw = m->raw;
}
-void UserLogger::open()
+void HextLogger::open()
{
const unsigned buf_sz = 65536;
- user_log = TextLog_Init(file.c_str(), buf_sz, limit);
+ hext_log = TextLog_Init(file.c_str(), buf_sz, limit);
}
-void UserLogger::close()
+void HextLogger::close()
{
- if ( user_log )
- TextLog_Term(user_log);
+ if ( hext_log )
+ TextLog_Term(hext_log);
}
-void UserLogger::log(Packet* p, const char*, Event*)
+void HextLogger::log(Packet* p, const char*, Event*)
{
- if ( p->data and p->dsize )
+ if ( raw )
+ {
+ log_raw(p);
+ log_data(p->pkt, p->pkth->caplen);
+ }
+ else if ( p->is_tcp() and p->dsize )
{
log_header(p);
log_data(p->data, p->dsize);
//-------------------------------------------------------------------------
static Module* mod_ctor()
-{ return new UserModule; }
+{ return new HextModule; }
static void mod_dtor(Module* m)
{ delete m; }
-static Logger* user_ctor(SnortConfig*, Module* mod)
+static Logger* hext_ctor(SnortConfig*, Module* mod)
{
- return new UserLogger((UserModule*)mod);
+ return new HextLogger((HextModule*)mod);
}
-static void user_dtor(Logger* p)
+static void hext_dtor(Logger* p)
{ delete p; }
-static const LogApi user_api =
+static const LogApi hext_api =
{
{
PT_LOGGER,
mod_dtor
},
OUTPUT_TYPE_FLAG__ALERT,
- user_ctor,
- user_dtor
+ hext_ctor,
+ hext_dtor
};
SO_PUBLIC const BaseApi* snort_plugins[] =
{
- &user_api.base,
+ &hext_api.base,
nullptr
};
#include "config.h"
#endif
+#include <arpa/inet.h>
#include <array>
+
#include "utils/dnet_header.h"
#include "main/snort_config.h"
#include "fpdetect.h"
src.addr32 = ip4h->get_src();
dst.addr32 = ip4h->get_dst();
- TextLog_Print(text_log, "%d.%d.%d.%d -> %d.%d.%d.%d",
- (int)src.addr8[0], (int)src.addr8[1],
- (int)src.addr8[2], (int)src.addr8[3],
- (int)dst.addr8[0], (int)dst.addr8[1],
- (int)dst.addr8[2], (int)dst.addr8[3]);
+ char src_buf[INET_ADDRSTRLEN];
+ char dst_buf[INET_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, &src, src_buf, sizeof(src_buf));
+ inet_ntop(AF_INET, &dst, dst_buf, sizeof(dst_buf));
+
+ TextLog_Print(text_log, "%s -> %s", src_buf, dst_buf);
}
TextLog_NewLine(text_log);
#include "config.h"
#endif
+#include <arpa/inet.h>
#include <limits>
-#include "detection/fpdetect.h"
+#include "detection/fpdetect.h"
#include "protocols/ipv6.h"
#include "codecs/codec_module.h"
#include "framework/codec.h"
const ip::snort_in6_addr* const src = ip6h->get_src();
const ip::snort_in6_addr* const dst = ip6h->get_dst();
- TextLog_Print(text_log, "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:"
- "%02X%02X:%02X%02X:%02X%02X -> %02X%02X:%02X%02X:"
- "%02X%02X:%02X%02X:%02X%02X:%02X%02X",
- (int)src->u6_addr8[0], (int)src->u6_addr8[1], (int)src->u6_addr8[2],
- (int)src->u6_addr8[3], (int)src->u6_addr8[4], (int)src->u6_addr8[5],
- (int)src->u6_addr8[6], (int)src->u6_addr8[7], (int)src->u6_addr8[8],
- (int)src->u6_addr8[9], (int)src->u6_addr8[10], (int)src->u6_addr8[11],
- (int)src->u6_addr8[12], (int)src->u6_addr8[13], (int)src->u6_addr8[14],
- (int)src->u6_addr8[15], (int)dst->u6_addr8[0], (int)dst->u6_addr8[1],
- (int)dst->u6_addr8[2], (int)dst->u6_addr8[3], (int)dst->u6_addr8[4],
- (int)dst->u6_addr8[5], (int)dst->u6_addr8[6], (int)dst->u6_addr8[7],
- (int)dst->u6_addr8[8], (int)dst->u6_addr8[9], (int)dst->u6_addr8[10],
- (int)dst->u6_addr8[11], (int)dst->u6_addr8[12], (int)dst->u6_addr8[13],
- (int)dst->u6_addr8[14], (int)dst->u6_addr8[15]);
+ char src_buf[INET6_ADDRSTRLEN];
+ char dst_buf[INET6_ADDRSTRLEN];
+
+ inet_ntop(AF_INET6, src, src_buf, sizeof(src_buf));
+ inet_ntop(AF_INET6, dst, dst_buf, sizeof(dst_buf));
+
+ TextLog_Print(text_log, "%s -> %s", src_buf, dst_buf);
}
TextLog_NewLine(text_log);
#define EventIsInternal(gid) (gid == GENERATOR_INTERNAL)
-/* D A T A S T R U C T U R E S *********************************************/
-
struct OutputSet;
struct ListHead
{
// FIXIT-L this loops forever if 1 flow in cache
if (flow == save_me)
+ {
+ if ( hash_table->get_count() == 1 )
+ break;
+
hash_table->touch();
+ }
else if ((flow->last_data_seen + timeoutAggressive) < thetime)
{
virtual void set_extra_data(Packet*, uint32_t /*flag*/) { }
virtual void clear_extra_data(Packet*, uint32_t /*flag*/) { }
- virtual int get_rebuilt_packets(Packet*, PacketIterator, void* /*userdata*/) { return 0; }
- virtual int get_segments(Packet*, StreamSegmentIterator, void* /*userdata*/) { return -1; }
-
virtual bool is_sequenced(uint8_t /*dir*/) { return true; }
virtual bool are_packets_missing(uint8_t /*dir*/) { return true; }
public:
virtual ~Codec() { }
- // PKT_MAX = ETHERNET_HEADER_LEN () + VLAN_HEADER (4) + ETHERNET_MTU () + IP_MAXPACKET()
+ // PKT_MAX = ETHERNET_HEADER_LEN + VLAN_HEADER + ETHERNET_MTU + IP_MAXPACKET
/* PKT_MAX is sized to ensure that any reassembled packet
* can accommodate a full datagram at innermost layer
* ETHERNET_HEADER_LEN == 14
* VLAN_HEADER == 4
* ETHERNET_MTU == 1500
- * IP_MAXPACKET == 65535
+ * IP_MAXPACKET == 65535 FIXIT-L use Packet::max_dsize
*/
static const uint32_t PKT_MAX = 14 + 4 + 1500 + 65535;
PktType type;
ip::IpApi ip_api;
- mpls::MplsHdr mplsHdr;
+ mpls::MplsHdr mplsHdr; // FIXIT-L need to zero this?
inline void reset()
{
- memset((char*)&tcph, '\0', offsetof(DecodeData, ip_api));
+ memset(this, 0, offsetof(DecodeData, ip_api));
ip_api.reset();
}
return nullptr;
}
+int Parameter::index(const char* r, const char* s)
+{
+ const char* t = ::find(r, s);
+
+ if ( !t )
+ return -1;
+
+ unsigned idx = get_index(r, t);
+ return (int)idx;
+}
+
const char* get_string() const;
static const Parameter* find(const Parameter*, const char*);
+
+ // 0-based; -1 if not found; list is | delimited
+ static int index(const char* list, const char* key);
};
#endif
int CvsOption::eval(Cursor&, Packet* p)
{
- int ret;
int rval = DETECTION_OPTION_NO_MATCH;
CvsRuleOption* cvs_rule_option = &config;
- if (p == NULL)
- {
- return rval;
- }
-
- if ((p->ptrs.tcph == NULL) || (p->data == NULL) || (p->dsize == 0))
- {
- return rval;
- }
-
- if (cvs_rule_option == NULL)
+ if ( !p->has_tcp_data() )
{
return rval;
}
DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "CVS begin detection\n"); );
- ret = CvsDecode(p->data, p->dsize, cvs_rule_option);
+ int ret = CvsDecode(p->data, p->dsize, cvs_rule_option);
if (ret == CVS_ALERT)
{
void LogIPPkt(Packet* p)
{
log_mutex.lock();
+ TextLog_NewLine(text_log);
+ LogTimeStamp(text_log, p);
LogIPPkt(text_log, p);
TextLog_Flush(text_log);
log_mutex.unlock();
}
-void snort_print(Packet* p)
+void LogFlow(Packet* p)
{
- if (p->ptrs.ip_api.is_ip())
- {
- LogIPPkt(text_log, p);
- }
-#if 0
- // FIXIT-L ARP logging not impelemted
- else if (p->proto_bits & PROTO_BIT__ARP)
- {
- log_mutex.lock();
- LogArpHeader(text_log, p);
- TextLog_Flush(text_log);
- log_mutex.unlock();
- }
-#endif
-#if 0
- else if (p->eplh != NULL)
- {
- LogEapolPkt(text_log, p);
- }
- else if (p->wifih && SnortConfig::output_wifi_mgmt())
- {
- LogWifiPkt(text_log, p);
- }
-#endif
+ log_mutex.lock();
+ TextLog_NewLine(text_log);
+ LogTimeStamp(text_log, p);
+ TextLog_Print(text_log, " %s ", p->get_type());
+ LogIpAddrs(text_log, p);
+ TextLog_NewLine(text_log);
+ log_mutex.unlock();
}
void LogNetData(const uint8_t* data, const int len, Packet* p)
void OpenLogger();
void CloseLogger();
void LogIPPkt(Packet*);
-void snort_print(Packet*);
-void LogNetData(const uint8_t* data, const int len, Packet* p = NULL);
+void LogFlow(Packet*);
+void LogNetData(const uint8_t* data, const int len, Packet*);
#endif
//--------------------------------------------------------------------------
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2002-2013 Sourcefire, Inc.
-// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+// Copyright (C) 2007-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
*/
void LogIpAddrs(TextLog* log, Packet* p)
{
- if ( p->is_fragment() || ( !p->is_tcp() && !p->is_udp()))
+ if ( p->is_fragment() || (!p->is_tcp() && !p->is_udp() && !p->is_data()) )
{
const char* ip_fmt = "%s -> %s";
/* print fragment info if necessary */
if ( p->is_fragment() )
{
-#ifdef REG_TEST
- frag_off >>= 3;
-#endif
-
TextLog_Print(log, "Frag Offset: 0x%04X Frag Size: 0x%04X\n",
frag_off, p->ptrs.ip_api.pay_len());
}
}
}
}
-
-#ifdef REG_TEST
- TextLog_Putc(log, ' ');
-#endif
-
- TextLog_NewLine(log);
}
void LogTcpOptions(TextLog* log, const tcp::TCPHdr* tcph, uint16_t valid_tcp_len)
}
/* dump the TCP options */
-#ifdef REG_TEST
- // emulate snort bug
- if ( !p->is_cooked() || (p->pseudo_type == PSEUDO_PKT_IP) )
-#endif
if (tcph->has_options())
{
LogTcpOptions(log, p);
+ TextLog_NewLine(log);
}
}
}
/*
- * Function: LogNetData(TextLog*, uint8_t *,int, Packet *)
+ * Function: LogNetData(TextLog*, uint8_t*,int, Packet*)
*
* Purpose: Do a side by side dump of a buffer, hex on
* the left, decoded ASCII on the right.
*
* Returns: void function
*/
-#define BYTES_PER_FRAME 16
-/* middle of packet:"41 02 43 04 45 06 47 08 49 0A 4B 0C 4D 0E 4F 0F A.C.E.G.I.K.M.O."
- at end of packet:"41 02 43 04 45 06 47 08 A.C.E.G."*/
-const char pad3[] = " ";
+#define SEPARATOR \
+ "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
+
+#define BYTES_PER_FRAME 20
+/* middle:"41 02 43 04 45 06 47 08 49 0A 4B 0C 4D 0E 4F 0F 01 02 03 04 A.C.E.G.I.K.M.O....."
+ at end:"41 02 43 04 45 06 47 08 A.C.E.G."*/
+
+static const char pad3[] =
+ " ";
void LogNetData(TextLog* log, const uint8_t* data, const int len, Packet* p)
{
int i;
byte_pos = char_pos = 0;
-
ip_ob_start = ip_ob_end = -1;
if ( !len )
- {
- TextLog_NewLine(log);
return;
- }
- if ( !data )
- {
- TextLog_Print(log, "Got NULL ptr in LogNetData()\n");
- return;
- }
-
- if ( len > IP_MAXPACKET )
- {
- if (SnortConfig::log_verbose())
- {
- TextLog_Print(
- log, "Got bogus buffer length (%d) for LogNetData, "
- "defaulting to %d bytes\n", len, BYTES_PER_FRAME
- );
- }
- end = data + BYTES_PER_FRAME;
- }
if (p && SnortConfig::obfuscate() )
{
ip_ob_end = ip_ob_start + 2 + 2*(sizeof(struct in6_addr));
}
}
+#if 0
+ TextLog_Print(log, "%s[%d]\n", p->get_pseudo_type(), p->dsize);
+ LogDiv(log);
+#else
+ char div[64];
+ snprintf(div, sizeof(div), "- - - %s[%d]", p->get_pseudo_type(), p->dsize);
+ div[sizeof(div)-1] = '\0';
+ TextLog_Print(log, "%s%s\n", div, SEPARATOR+strlen(div));
+#endif
/* loop thru the whole buffer */
while ( pb < end )
pb += BYTES_PER_FRAME;
TextLog_NewLine(log);
}
-#ifndef REG_TEST
- TextLog_NewLine(log);
-#endif
+ LogDiv(log);
}
-#ifdef REG_TEST
-#define SEPARATOR \
- "=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+"
-#else
-#define SEPARATOR \
- "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
-#endif
+void LogDiv(TextLog* log)
+{
+ TextLog_Print(log, "%s\n", SEPARATOR);
+}
static int LogObfuscatedData(TextLog* log, Packet* p)
{
uint8_t* payload = NULL;
uint16_t payload_len = 0;
- TextLog_Print(log, "%s\n", SEPARATOR);
-
if (obApi->getObfuscatedPayload(p, &payload,
(uint16_t*)&payload_len) != OB_RET_SUCCESS)
{
return -1;
}
+ LogDiv(log);
+
/* dump the application layer data */
if (SnortConfig::output_app_data() && !SnortConfig::verbose_byte_dump())
{
if (SnortConfig::output_char_data())
LogCharData(log, (char*)payload, payload_len);
else
- LogNetData(log, payload, payload_len, NULL);
+ LogNetData(log, payload, payload_len, p);
}
else if (SnortConfig::verbose_byte_dump())
{
SafeMemcpy(buf + dlen, payload, payload_len,
buf, buf + sizeof(buf));
- LogNetData(log, buf, dlen + payload_len, NULL);
+ LogNetData(log, buf, dlen + payload_len, p);
}
free(payload);
return 0;
}
-#ifndef REG_TEST
-static void LogPacketType(TextLog* log, Packet* p)
-{
- TextLog_NewLine(log);
-
- if ( !p->dsize || !p->is_cooked() )
- return;
-
- switch ( p->pseudo_type )
- {
- case PSEUDO_PKT_SMB_SEG:
- TextLog_Print(log, "%s", "SMB desegmented packet");
- break;
- case PSEUDO_PKT_DCE_SEG:
- TextLog_Print(log, "%s", "DCE/RPC desegmented packet");
- break;
- case PSEUDO_PKT_DCE_FRAG:
- TextLog_Print(log, "%s", "DCE/RPC defragmented packet");
- break;
- case PSEUDO_PKT_SMB_TRANS:
- TextLog_Print(log, "%s", "SMB Transact reassembled packet");
- break;
- case PSEUDO_PKT_DCE_RPKT:
- TextLog_Print(log, "%s", "DCE/RPC reassembled packet");
- break;
- case PSEUDO_PKT_TCP:
- TextLog_Print(log, "%s", "Stream reassembled packet");
- break;
- case PSEUDO_PKT_IP:
- TextLog_Print(log, "%s", "Frag reassembled packet");
- break;
- default:
- // FIXIT-L do we get here for portscan or sdf?
- TextLog_Print(log, "%s", "Cooked packet");
- break;
- } /* switch */
- TextLog_NewLine(log);
-}
-
-#endif
-
/*--------------------------------------------------------------------
* Function: LogIPPkt(TextLog*, int, Packet *)
*
*--------------------------------------------------------------------
*/
-#define DATA_LEN(p) \
- (p->ptrs.ip_api.actual_ip_len() - (p->ptrs.ip_api.hlen()))
-
void LogIPPkt(TextLog* log, Packet* p)
{
-#ifndef REG_TEST
- LogPacketType(log, p);
- TextLog_Print(log, "%s\n", SEPARATOR);
-#endif
-
- /* dump the timestamp */
- LogTimeStamp(log, p);
-
- /* dump the ethernet header if we're doing that sort of thing */
if ( SnortConfig::output_datalink() )
{
Log2ndHeader(log, p);
if ( p->proto_bits & PROTO_BIT__MPLS )
LogMPLSHeader(log, p);
- // FIXIT-J --> log everything in order!!
+ // FIXIT-L --> log everything in order!!
ip::IpApi tmp_api = p->ptrs.ip_api;
int8_t num_layer = 0;
uint8_t tmp_next = p->get_ip_proto_next();
while (layer::set_outer_ip_api(p, p->ptrs.ip_api, p->ip_proto_next, num_layer) &&
tmp_api != p->ptrs.ip_api)
{
-#ifdef REG_TEST
- // In Snort, cooked packets should not print an outer IP Header
- if (p->is_cooked() && (p->pseudo_type != PSEUDO_PKT_IP))
- break;
-#endif
LogOuterIPHeader(log, p);
if (first)
LogGREHeader(log, p); // checks for valid gre layer before logging
first = false;
}
-
-#ifdef REG_TEST
- break;
-#endif
}
p->ip_proto_next = tmp_next;
if ( p->ptrs.tcph != NULL )
LogTCPHeader(log, p);
else
- LogNetData(log, p->ptrs.ip_api.ip_data(), p->ptrs.ip_api.pay_len(), NULL);
+ LogNetData(log, p->ptrs.ip_api.ip_data(), p->ptrs.ip_api.pay_len(), p);
break;
case PktType::UDP:
if ( p->ptrs.udph != NULL )
{
-#ifdef REG_TEST
// for consistency, nothing to log (tcp doesn't log paylen)
LogUDPHeader(log, p);
-#endif
}
else
{
- LogNetData(log, p->ptrs.ip_api.ip_data(), p->ptrs.ip_api.pay_len(), NULL);
+ LogNetData(log, p->ptrs.ip_api.ip_data(), p->ptrs.ip_api.pay_len(), p);
}
break;
if ( p->ptrs.icmph != NULL )
LogICMPHeader(log, p);
else
- LogNetData(log, p->ptrs.ip_api.ip_data(), p->ptrs.ip_api.pay_len(), NULL);
+ LogNetData(log, p->ptrs.ip_api.ip_data(), p->ptrs.ip_api.pay_len(), p);
break;
default:
/* dump the application layer data */
if (SnortConfig::output_app_data() && !SnortConfig::verbose_byte_dump())
{
-#ifdef REG_TEST
- const uint8_t* tmp_data = 0;
- uint16_t tmp_dsize = 0;
-
- if ( p->proto_bits & PROTO_BIT__ICMP_EMBED )
- {
- tmp_data = p->data;
- tmp_dsize = p->dsize;
- p->data = p->layers[p->num_layers - 1].start;
-
- // layer.length may be layer's length, not the actual length
- p->dsize = (uint16_t)((tmp_data - p->data) + tmp_dsize);
- }
-#endif
if (SnortConfig::output_char_data())
{
LogCharData(log, (char*)p->data, p->dsize);
}
else
{
- LogNetData(log, p->data, p->dsize, NULL);
+ LogNetData(log, p->data, p->dsize, p);
if (!IsJSNormData(p->flow))
{
TextLog_Print(log, "%s\n", "Normalized JavaScript for this packet");
- LogNetData(log, g_file_data.data, g_file_data.len, NULL);
+ LogNetData(log, g_file_data.data, g_file_data.len, p);
}
else if (!IsGzipData(p->flow))
{
TextLog_Print(log, "%s\n", "Decompressed Data for this packet");
- LogNetData(log, g_file_data.data, g_file_data.len, NULL);
+ LogNetData(log, g_file_data.data, g_file_data.len, p);
}
}
-
-#ifdef REG_TEST
- if ( p->proto_bits & PROTO_BIT__ICMP_EMBED )
- {
- p->data = tmp_data;
- p->dsize = tmp_dsize;
- }
-#endif
}
else if (SnortConfig::verbose_byte_dump())
{
LogNetData(log, p->pkt, p->pkth->caplen, p);
}
-#ifdef REG_TEST
- TextLog_Print(log, "\n%s\n\n", SEPARATOR);
-#endif
}
/*--------------------------------------------------------------------
* ARP stuff cloned from log.c
+ * FIXIT-L these must be converted to use TextLog (or just deleted)
*--------------------------------------------------------------------
*/
#if 0
-// these must be converted to use TextLog
-// (or just deleted)
/****************************************************************************
*
* Function: PrintEapolKey(FILE *)
void LogPayload(TextLog*, Packet*);
void LogNetData(TextLog*, const uint8_t* data, const int len, Packet*);
+void LogDiv(TextLog*);
void LogTimeStamp(TextLog*, Packet*);
+
void LogTrHeader(TextLog*, Packet*);
void Log2ndHeader(TextLog*, Packet*);
void LogIpAddrs(TextLog*, Packet*);
-SO_PUBLIC void LogIpOptions(TextLog*, const IP4Hdr*, uint16_t valid_ip4_len);
-SO_PUBLIC void LogTcpOptions(TextLog*, const tcp::TCPHdr*, uint16_t valid_tcp_len);
+
void LogIPHeader(TextLog*, Packet*);
void LogTCPHeader(TextLog*, Packet*);
void LogUDPHeader(TextLog*, Packet*);
void LogICMPHeader(TextLog*, Packet*);
+SO_PUBLIC void LogIpOptions(TextLog*, const IP4Hdr*, uint16_t valid_ip4_len);
+SO_PUBLIC void LogTcpOptions(TextLog*, const tcp::TCPHdr*, uint16_t valid_tcp_len);
+
#endif
# ifndef OBFUSCATION_TEST
# define OBFUSCATION_TEST
# endif
-# define TraverseReassembled stream.traverse_stream_segments
static int TraverseReassembled(
-Packet*,
-int (*)(DAQ_PktHdr_t*, uint8_t*, uint8_t*, uint32_t, void*),
-void*
+ Packet*,
+ int (*)(DAQ_PktHdr_t*, uint8_t*, uint8_t*, uint32_t, void*),
+ void*
);
#endif
static inline int NumObfuscateSliceEntries(void);
static inline ObRet ObfuscationEntryOverflow(ob_size_t);
static inline int PayloadObfuscationRequired(Packet*);
+
static inline void SetObfuscationEntry(ObfuscationEntry*, Packet*,
-ob_size_t, ob_size_t, ob_char_t);
+ ob_size_t, ob_size_t, ob_char_t);
+
static inline void SortObfuscationEntries(void);
+
static inline void SetObfuscationCallbackData(
-ObfuscationCallbackData*, Packet*, ObfuscationCallback, void*);
+ ObfuscationCallbackData*, Packet*, ObfuscationCallback, void*);
+
static inline void SetObfuscationStreamCallbackData(
-ObfuscationStreamCallbackData*, ObfuscationCallbackData*,
-Packet*, ObfuscationCallback, void*);
+ ObfuscationStreamCallbackData*, ObfuscationCallbackData*,
+ Packet*, ObfuscationCallback, void*);
static ObRet AddObfuscationEntry(Packet*, ob_size_t, ob_size_t, ob_char_t);
static int ObfuscationEntrySort(const void*, const void*);
+
static ObRet TraverseObfuscationList(ObfuscationCallbackData*,
-const DAQ_PktHdr_t*, const uint8_t*, ob_size_t);
-static int ObfuscateStreamSegmentsCallback(DAQ_PktHdr_t*,
-uint8_t*, uint8_t*, uint32_t, void*);
+ const DAQ_PktHdr_t*, const uint8_t*, ob_size_t);
+
static ObRet GetObfuscatedPayloadCallback(const DAQ_PktHdr_t*,
const uint8_t*, ob_size_t, ob_char_t, void*);
static void PrintObfuscationEntry(const ObfuscationEntry*, int);
}
// obfuscatePacketStreamSegments
-static ObRet OB_API_ObfuscatePacketStreamSegments(Packet* p,
- ObfuscationCallback user_callback, void* user_data)
+// FIXIT-L traverse_reassembled() deleted
+// this should also be deleted if it is no longer needed
+static ObRet OB_API_ObfuscatePacketStreamSegments(Packet*,
+ ObfuscationCallback, void*)
{
- ObfuscationStreamCallbackData stream_callback_data;
- ObfuscationCallbackData callback_data;
-
- if (!PayloadObfuscationRequired(p))
- return OB_RET_ERROR;
-
- SortObfuscationEntries();
- SetObfuscationStreamCallbackData(&stream_callback_data, &callback_data,
- p, user_callback, user_data);
-
- if (stream.traverse_stream_segments(p, ObfuscateStreamSegmentsCallback,
- (void*)&stream_callback_data) == -1)
- {
- return OB_RET_ERROR;
- }
-
- return OB_RET_SUCCESS;
+ return OB_RET_ERROR;
}
// getObfuscatedPayload
return OB_RET_SUCCESS;
}
-/*******************************************************************************
- * Function: ObfuscateStreamSegmentsCallback()
- *
- * Stream API callback for traverse_stream_segments.
- *
- * Arguments
- * DAQ_PktHdr_t *pkth
- * The pcap header information associated with the segment packet.
- * uint8_t *pkt
- * Pointer to the segment packet data starting at packet headers
- * uint8_t *payload
- * Pointer to the segment payload data to be obfuscated
- * uint32_t
- * The sequence number of this segment
- * void *data
- * The ObfuscationCallBack data
- *
- * Returns
- * Per stream api traverse_reassembled:
- * 0 if obfuscation was successful.
- * -1 if we had to bail on the obfuscation due to the user callback
- * telling us to - this should tell traverse_stream_segments to stop
- * traversing and not call this anymore.
- *
- ******************************************************************************/
-static int ObfuscateStreamSegmentsCallback(DAQ_PktHdr_t* pkth,
- uint8_t* pkt, uint8_t* payload, uint32_t seq_num, void* data)
-{
- ObfuscationStreamCallbackData* callback_data =
- (ObfuscationStreamCallbackData*)data;
- ob_size_t payload_size = (uint16_t)(pkth->caplen - (payload - pkt));
-
- if ((pkt >= payload) || ((ob_size_t)(payload - pkt) > pkth->caplen))
- return -1;
-
- if (callback_data->data->user_callback(pkth, pkt, (ob_size_t)(payload - pkt),
- 0, callback_data->data->user_data) != OB_RET_SUCCESS)
- {
- return -1;
- }
-
- /* If we get an overlap set the entry index to where the last packet
- * started, else set the last entry index to the end of the one for
- * the last segment */
- if (callback_data->next_seq > seq_num)
- {
- callback_data->data->entry_index = callback_data->last_entry_index;
- callback_data->data->total_offset -=
- (ob_size_t)(callback_data->next_seq - seq_num);
- }
- else
- {
- callback_data->last_entry_index = callback_data->data->entry_index;
- }
-
- if (TraverseObfuscationList(callback_data->data, NULL,
- payload, payload_size) != OB_RET_SUCCESS)
- {
- return -1;
- }
-
- /* Update next expected sequence number */
- callback_data->next_seq = seq_num + payload_size;
-
- return 0;
-}
-
/*******************************************************************************
* Function: GetObfuscationPayloadCallback()
*
packet.reset();
packet.pseudo_type = 0;
- packet.max_dsize = 0;
packet.user_policy_id = 0;
packet.iplist_id = 0;
packeet.ps_proto = 0;
pkthtmp->caplen = payload_bytes;
pkthtmp->ts.tv_sec = 0;
pkthtmp->ts.tv_usec = 0;
+
packet.packet_flags |= PKT_PAYLOAD_OBFUSCATE;
packet.data = payload;
packet.dsize = payload_bytes;
//--------------------------------------------------------------------------
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2003-2013 Sourcefire, Inc.
+// Copyright (C) 2007-2013 Sourcefire, Inc.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
alert_fast.cc
alert_full.cc
alert_syslog.cc
- alert_test.cc
alert_unixsock.cc
log_null.cc
log_pcap.cc
add_shared_library(alert_fast loggers alert_fast.cc)
add_shared_library(alert_full loggers alert_full.cc)
add_shared_library(alert_syslog loggers alert_syslog.cc)
- add_shared_library(alert_test loggers alert_test.cc)
add_shared_library(alert_unixsock loggers alert_unixsock.cc)
add_shared_library(log_null loggers log_null.cc)
add_shared_library(log_pcap loggers log_pcap.cc)
alert_fast.cc \
alert_full.cc \
alert_syslog.cc \
-alert_test.cc \
alert_unixsock.cc \
log_null.cc \
log_pcap.cc \
libalert_syslog_la_LDFLAGS = -export-dynamic -shared
libalert_syslog_la_SOURCES = alert_syslog.cc
-ehlib_LTLIBRARIES += libalert_test.la
-libalert_test_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
-libalert_test_la_LDFLAGS = -export-dynamic -shared
-libalert_test_la_SOURCES = alert_test.cc
-
ehlib_LTLIBRARIES += libalert_unixsock.la
libalert_unixsock_la_CXXFLAGS = $(AM_CXXFLAGS) -DBUILDING_SO
libalert_unixsock_la_LDFLAGS = -export-dynamic -shared
//--------------------------------------------------------------------------
// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2002-2013 Sourcefire, Inc.
-// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
-// Copyright (C) 2001 Brian Caswell <bmc@mitre.org>
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License Version 2 as published
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//--------------------------------------------------------------------------
+// alert_csv.cc author Russ Combs <rucombs@cisco.com>
+//
+// this a complete rewrite of the work originally done by:
+//
+// 1998-2002 Martin Roesch <roesch@sourcefire.com>
+// 2001-2001 Brian Caswell <bmc@mitre.org>
+// 2002-2013 Sourcefire, Inc.
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string>
+#include <vector>
#include "framework/logger.h"
#include "framework/module.h"
#include "protocols/packet.h"
-#include "parser.h"
-#include "snort_debug.h"
-#include "mstring.h"
-#include "util.h"
-#include "log.h"
+#include "detection/signature.h"
+#include "main/snort_debug.h"
+#include "utils/util.h"
+#include "utils/stats.h"
+#include "log/log.h"
#include "log/text_log.h"
#include "log/log_text.h"
#include "protocols/tcp.h"
#include "protocols/icmp4.h"
#include "protocols/icmp6.h"
#include "protocols/eth.h"
+#include "packet_io/active.h"
#define LOG_BUFFER (4*K_BYTES)
using namespace std;
+//-------------------------------------------------------------------------
+// field formatting functions
+//-------------------------------------------------------------------------
+
+struct Args
+{
+ Packet* pkt;
+ const char* msg;
+ Event* event;
+};
+
+static void ff_action(Args&)
+{
+ TextLog_Puts(csv_log, Active_GetDispositionString());
+}
+
+static void ff_dir(Args& a)
+{
+ const char* dir;
+
+ if ( a.pkt->packet_flags & PKT_FROM_CLIENT )
+ dir = "C2S";
+ else if ( a.pkt->packet_flags & PKT_FROM_SERVER )
+ dir = "S2C";
+ else
+ dir = "UNK";
+
+ TextLog_Puts(csv_log, dir);
+}
+
+static void ff_dgm_len(Args& a)
+{
+ if (a.pkt->has_ip())
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.ip_api.dgram_len());
+ else
+ TextLog_Print(csv_log, "%d", a.pkt->dsize);
+}
+
+static void ff_dst_addr(Args& a)
+{
+ if ( a.pkt->has_ip() or a.pkt->is_data() )
+ TextLog_Puts(csv_log, inet_ntoa(a.pkt->ptrs.ip_api.get_dst()));
+}
+
+static void ff_dst_ap(Args& a)
+{
+ const char* addr = "";
+ unsigned port = 0;
+
+ if ( a.pkt->has_ip() or a.pkt->is_data() )
+ addr = sfip_to_str(a.pkt->ptrs.ip_api.get_dst());
+
+ if ( a.pkt->proto_bits & (PROTO_BIT__TCP|PROTO_BIT__UDP) )
+ port = a.pkt->ptrs.dp;
+
+ TextLog_Print(csv_log, "%s:%d", addr, port);
+}
+
+static void ff_dst_port(Args& a)
+{
+ if ( a.pkt->proto_bits & (PROTO_BIT__TCP|PROTO_BIT__UDP) )
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.dp);
+}
+
+static void ff_eth_dst(Args& a)
+{
+ if ( !(a.pkt->proto_bits & PROTO_BIT__ETH) )
+ return;
+
+ const eth::EtherHdr* eh = layer::get_eth_layer(a.pkt);
+
+ TextLog_Print(csv_log, "%02X:%02X:%02X:%02X:%02X:%02X", eh->ether_dst[0],
+ eh->ether_dst[1], eh->ether_dst[2], eh->ether_dst[3],
+ eh->ether_dst[4], eh->ether_dst[5]);
+}
+
+static void ff_eth_len(Args& a)
+{
+ if ( !(a.pkt->proto_bits & PROTO_BIT__ETH) )
+ return;
+
+ TextLog_Print(csv_log, "0x%X", a.pkt->pkth->pktlen);
+}
+
+static void ff_eth_src(Args& a)
+{
+ if ( !(a.pkt->proto_bits & PROTO_BIT__ETH) )
+ return;
+
+ const eth::EtherHdr* eh = layer::get_eth_layer(a.pkt);
+
+ TextLog_Print(csv_log, "%02X:%02X:%02X:%02X:%02X:%02X", eh->ether_src[0],
+ eh->ether_src[1], eh->ether_src[2], eh->ether_src[3],
+ eh->ether_src[4], eh->ether_src[5]);
+}
+
+static void ff_eth_type(Args& a)
+{
+ if ( !(a.pkt->proto_bits & PROTO_BIT__ETH) )
+ return;
+
+ const eth::EtherHdr* eh = layer::get_eth_layer(a.pkt);
+ TextLog_Print(csv_log, "0x%X", ntohs(eh->ether_type));
+}
+
+static void ff_gid(Args& a)
+{
+ if (a.event )
+ TextLog_Print(csv_log, "%u", a.event->sig_info->generator);
+}
+
+static void ff_icmp_code(Args& a)
+{
+ if (a.pkt->ptrs.icmph )
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.icmph->code);
+}
+
+static void ff_icmp_id(Args& a)
+{
+ if (a.pkt->ptrs.icmph )
+ TextLog_Print(csv_log, "%d", ntohs(a.pkt->ptrs.icmph->s_icmp_id));
+}
+
+static void ff_icmp_seq(Args& a)
+{
+ if (a.pkt->ptrs.icmph )
+ TextLog_Print(csv_log, "%d", ntohs(a.pkt->ptrs.icmph->s_icmp_seq));
+}
+
+static void ff_icmp_type(Args& a)
+{
+ if (a.pkt->ptrs.icmph )
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.icmph->type);
+}
+
+static void ff_ip_id(Args& a)
+{
+ if (a.pkt->has_ip())
+ TextLog_Print(csv_log, "%u", a.pkt->ptrs.ip_api.id());
+}
+
+static void ff_ip_len(Args& a)
+{
+ if (a.pkt->has_ip())
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.ip_api.pay_len());
+}
+
+static void ff_msg(Args& a)
+{
+ TextLog_Quote(csv_log, a.msg);
+}
+
+static void ff_pkt_gen(Args& a)
+{
+ TextLog_Puts(csv_log, a.pkt->get_pseudo_type());
+}
+
+static void ff_pkt_num(Args&)
+{
+ TextLog_Print(csv_log, STDu64, pc.total_from_daq);
+}
+
+static void ff_proto(Args& a)
+{
+ TextLog_Puts(csv_log, a.pkt->get_type());
+}
+
+static void ff_rev(Args& a)
+{
+ if (a.event )
+ TextLog_Print(csv_log, "%u", a.event->sig_info->rev);
+}
+
+static void ff_rule(Args& a)
+{
+ TextLog_Print(csv_log, "%u:%u:%u",
+ a.event->sig_info->generator, a.event->sig_info->id, a.event->sig_info->rev);
+}
+
+static void ff_sid(Args& a)
+{
+ if (a.event )
+ TextLog_Print(csv_log, "%u", a.event->sig_info->id);
+}
+
+static void ff_src_addr(Args& a)
+{
+ if ( a.pkt->has_ip() or a.pkt->is_data() )
+ TextLog_Puts(csv_log, inet_ntoa(a.pkt->ptrs.ip_api.get_src()));
+}
+
+static void ff_src_ap(Args& a)
+{
+ const char* addr = "";
+ unsigned port = 0;
+
+ if ( a.pkt->has_ip() or a.pkt->is_data() )
+ addr = sfip_to_str(a.pkt->ptrs.ip_api.get_src());
+
+ if ( a.pkt->proto_bits & (PROTO_BIT__TCP|PROTO_BIT__UDP) )
+ port = a.pkt->ptrs.sp;
+
+ TextLog_Print(csv_log, "%s:%d", addr, port);
+}
+
+static void ff_src_port(Args& a)
+{
+ if ( a.pkt->proto_bits & (PROTO_BIT__TCP|PROTO_BIT__UDP) )
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.sp);
+}
+
+static void ff_tcp_ack(Args& a)
+{
+ if (a.pkt->ptrs.tcph )
+ TextLog_Print(csv_log, "0x%lX", (u_long)ntohl(a.pkt->ptrs.tcph->th_ack));
+}
+
+static void ff_tcp_flags(Args& a)
+{
+ if (a.pkt->ptrs.tcph )
+ {
+ char tcpFlags[9];
+ CreateTCPFlagString(a.pkt->ptrs.tcph, tcpFlags);
+ TextLog_Print(csv_log, "%s", tcpFlags);
+ }
+}
+
+static void ff_tcp_len(Args& a)
+{
+ if (a.pkt->ptrs.tcph )
+ TextLog_Print(csv_log, "%d", (a.pkt->ptrs.tcph->off()));
+}
+
+static void ff_tcp_seq(Args& a)
+{
+ if (a.pkt->ptrs.tcph )
+ TextLog_Print(csv_log, "0x%lX", (u_long)ntohl(a.pkt->ptrs.tcph->th_seq));
+}
+
+static void ff_tcp_win(Args& a)
+{
+ if (a.pkt->ptrs.tcph )
+ TextLog_Print(csv_log, "0x%X", ntohs(a.pkt->ptrs.tcph->th_win));
+}
+
+static void ff_tos(Args& a)
+{
+ if (a.pkt->has_ip())
+ TextLog_Print(csv_log, "%d", a.pkt->ptrs.ip_api.tos());
+}
+
+static void ff_ttl(Args& a)
+{
+ if (a.pkt->has_ip())
+ TextLog_Print(csv_log, "%d",a.pkt->ptrs.ip_api.ttl());
+}
+
+static void ff_timestamp(Args& a)
+{
+ LogTimeStamp(csv_log, a.pkt);
+}
+
+static void ff_udp_len(Args& a)
+{
+ if (a.pkt->ptrs.udph )
+ TextLog_Print(csv_log, "%d", ntohs(a.pkt->ptrs.udph->uh_len));
+}
+
//-------------------------------------------------------------------------
// module stuff
//-------------------------------------------------------------------------
+typedef void (*CsvFunc)(Args&);
+
+static const CsvFunc csv_func[] =
+{
+ ff_action, ff_dir, ff_dgm_len, ff_dst_addr, ff_dst_ap, ff_dst_port,
+ ff_eth_dst, ff_eth_len, ff_eth_src, ff_eth_type, ff_gid,
+ ff_icmp_code, ff_icmp_id, ff_icmp_seq, ff_icmp_type,
+ ff_ip_id, ff_ip_len, ff_msg, ff_pkt_gen, ff_pkt_num, ff_proto,
+ ff_rev, ff_rule, ff_sid, ff_src_addr, ff_src_ap, ff_src_port,
+ ff_tcp_ack, ff_tcp_flags, ff_tcp_len, ff_tcp_seq, ff_tcp_win,
+ ff_timestamp, ff_tos, ff_ttl, ff_udp_len
+};
+
#define csv_range \
- "timestamp | gid | sid | rev | msg | proto | " \
- "src_addr | dst_addr | src_port | dst_port | " \
- "eth_src | eth_dst | eth_type | eth_len | " \
- "ttl | tos | id | ip_len | dgm_len | " \
- "icmp_type | icmp_code | icmp_id | icmp_seq | " \
- "tcp_flags | tcp_seq | tcp_ack | tcp_len | tcp_win | " \
- "udp_len"
+ "action | dir | dgm_len | dst_addr | dst_ap | dst_port | " \
+ "eth_dst | eth_len | eth_src | eth_type | gid | " \
+ "icmp_code | icmp_id | icmp_seq | icmp_type | " \
+ "ip_id | ip_len | msg | pkt_gen | pkt_num | proto | " \
+ "rev | rule | sid | src_addr | src_ap | src_port | " \
+ "tcp_ack | tcp_flags | tcp_len | tcp_seq | tcp_win | " \
+ "timestamp | tos | ttl | udp_len"
#define csv_deflt \
- "timestamp gid sid rev src_addr src_port dst_addr dst_port"
+ "timestamp pkt_num proto pkt_gen dgm_len dir src_ap dst_ap rule action"
static const Parameter s_params[] =
{
{ "file", Parameter::PT_BOOL, nullptr, "false",
"output to " F_NAME " instead of stdout" },
- { "csv", Parameter::PT_MULTI, csv_range, csv_deflt,
+ { "fields", Parameter::PT_MULTI, csv_range, csv_deflt,
"selected fields will be output in given order left to right" },
{ "limit", Parameter::PT_INT, "0:", "0",
"set limit (0 is unlimited)" },
+ { "separator", Parameter::PT_STRING, nullptr, ", ",
+ "separate fields with this character sequence" },
+
// FIXIT-M provide PT_UNITS that converts to multiplier automatically
{ "units", Parameter::PT_ENUM, "B | K | M | G", "B",
"bytes | KB | MB | GB" },
public:
bool file;
- string csvargs;
+ string sep;
unsigned long limit;
unsigned units;
+ vector<CsvFunc> fields;
};
bool CsvModule::set(const char*, Value& v, SnortConfig*)
if ( v.is("file") )
file = v.get_bool();
- else if ( v.is("csv") )
- csvargs = SnortStrdup(v.get_string());
+ else if ( v.is("fields") )
+ {
+ string tok;
+ v.set_first_token();
+ fields.clear();
+
+ while ( v.get_next_token(tok) )
+ fields.push_back(csv_func[Parameter::index(csv_range, tok.c_str())]);
+ }
else if ( v.is("limit") )
limit = v.get_long();
+ else if ( v.is("separator") )
+ sep = v.get_string();
+
else if ( v.is("units") )
units = v.get_long();
file = false;
limit = 0;
units = 0;
- csvargs = csv_deflt;
+ sep = ", ";
+
+ if ( fields.empty() )
+ {
+ Value v(csv_deflt);
+ string tok;
+ v.set_first_token();
+
+ while ( v.get_next_token(tok) )
+ fields.push_back(csv_func[Parameter::index(csv_range, tok.c_str())]);
+ }
return true;
}
{
public:
CsvLogger(CsvModule*);
- ~CsvLogger();
void open() override;
void close() override;
public:
string file;
unsigned long limit;
- char** args;
- int numargs;
+ vector<CsvFunc> fields;
+ string sep;
};
CsvLogger::CsvLogger(CsvModule* m)
{
file = m->file ? F_NAME : "stdout";
limit = m->limit;
- args = mSplit(m->csvargs.c_str(), " \n\t", 0, &numargs, 0);
-}
-
-CsvLogger::~CsvLogger()
-{
- mSplitFree(&args, numargs);
+ sep = m->sep;
+ fields = std::move(m->fields);
}
void CsvLogger::open()
void CsvLogger::alert(Packet* p, const char* msg, Event* event)
{
- int num;
- char* type;
- char tcpFlags[9];
- const eth::EtherHdr* eh = nullptr;
-
- assert(p);
+ Args a = { p, msg, event };
+ bool first = true;
- if (p->proto_bits & PROTO_BIT__ETH)
- eh = layer::get_eth_layer(p);
-
- // TBD an enum would be an improvement here
- for (num = 0; num < numargs; num++)
+ for ( CsvFunc f : fields )
{
- type = args[num];
-
- if (!strcasecmp("timestamp", type))
- {
- LogTimeStamp(csv_log, p);
- }
- else if (!strcasecmp("gid", type))
- {
- if (event != NULL)
- TextLog_Print(csv_log, "%lu", (unsigned long)event->sig_info->generator);
- }
- else if (!strcasecmp("sid", type))
- {
- if (event != NULL)
- TextLog_Print(csv_log, "%lu", (unsigned long)event->sig_info->id);
- }
- else if (!strcasecmp("rev", type))
- {
- if (event != NULL)
- TextLog_Print(csv_log, "%lu", (unsigned long)event->sig_info->rev);
- }
- else if (!strcasecmp("msg", type))
- {
- TextLog_Quote(csv_log, msg); /* Don't fatal */
- }
- else if (!strcasecmp("proto", type))
- {
- // api returns zero if invalid
- switch (p->type())
- {
- case PktType::UDP:
- TextLog_Puts(csv_log, "UDP");
- break;
- case PktType::TCP:
- TextLog_Puts(csv_log, "TCP");
- break;
- case PktType::ICMP:
- TextLog_Puts(csv_log, "ICMP");
- break;
- default:
- break;
- }
- }
- else if (!strcasecmp("eth_src", type))
- {
- if (eh)
- {
- TextLog_Print(csv_log, "%02X:%02X:%02X:%02X:%02X:%02X", eh->ether_src[0],
- eh->ether_src[1], eh->ether_src[2], eh->ether_src[3],
- eh->ether_src[4], eh->ether_src[5]);
- }
- }
- else if (!strcasecmp("eth_dst", type))
- {
- if (eh)
- {
- TextLog_Print(csv_log, "%02X:%02X:%02X:%02X:%02X:%02X", eh->ether_dst[0],
- eh->ether_dst[1], eh->ether_dst[2], eh->ether_dst[3],
- eh->ether_dst[4], eh->ether_dst[5]);
- }
- }
- else if (!strcasecmp("eth_type", type))
- {
- if (eh != NULL)
- TextLog_Print(csv_log, "0x%X", ntohs(eh->ether_type));
- }
- else if (!strcasecmp("eth_len", type))
- {
- if (eh != NULL)
- TextLog_Print(csv_log, "0x%X", p->pkth->pktlen);
- }
- else if (!strcasecmp("udp_len", type))
- {
- if (p->ptrs.udph != NULL)
- TextLog_Print(csv_log, "%d", ntohs(p->ptrs.udph->uh_len));
- }
- else if (!strcasecmp("src_port", type))
- {
- // api return 0 if invalid
- switch (p->type())
- {
- case PktType::UDP:
- case PktType::TCP:
- TextLog_Print(csv_log, "%d", p->ptrs.sp);
- break;
- default:
- break;
- }
- }
- else if (!strcasecmp("dst_port", type))
- {
- switch (p->type())
- {
- case PktType::UDP:
- case PktType::TCP:
- TextLog_Print(csv_log, "%d", p->ptrs.dp);
- break;
- default:
- break;
- }
- }
- else if (!strcasecmp("src_addr", type))
- {
- if (p->has_ip())
- TextLog_Puts(csv_log, inet_ntoa(p->ptrs.ip_api.get_src()));
- }
- else if (!strcasecmp("dst_addr", type))
- {
- if (p->has_ip())
- TextLog_Puts(csv_log, inet_ntoa(p->ptrs.ip_api.get_dst()));
- }
- else if (!strcasecmp("icmp_type", type))
- {
- if (p->ptrs.icmph != NULL)
- TextLog_Print(csv_log, "%d", p->ptrs.icmph->type);
- }
- else if (!strcasecmp("icmp_code", type))
- {
- if (p->ptrs.icmph != NULL)
- TextLog_Print(csv_log, "%d", p->ptrs.icmph->code);
- }
- else if (!strcasecmp("icmp_id", type))
- {
- if (p->ptrs.icmph != NULL)
- TextLog_Print(csv_log, "%d", ntohs(p->ptrs.icmph->s_icmp_id));
- }
- else if (!strcasecmp("icmp_seq", type))
- {
- if (p->ptrs.icmph != NULL)
- TextLog_Print(csv_log, "%d", ntohs(p->ptrs.icmph->s_icmp_seq));
- }
- else if (!strcasecmp("ttl", type))
- {
- if (p->has_ip())
- TextLog_Print(csv_log, "%d",p->ptrs.ip_api.ttl());
- }
- else if (!strcasecmp("tos", type))
- {
- if (p->has_ip())
- TextLog_Print(csv_log, "%d", p->ptrs.ip_api.tos());
- }
- else if (!strcasecmp("id", type))
- {
- if (p->has_ip())
- TextLog_Print(csv_log, "%u", p->ptrs.ip_api.id());
- }
- else if (!strcasecmp("ip_len", type))
- {
- if (p->has_ip())
- TextLog_Print(csv_log, "%d", p->ptrs.ip_api.pay_len());
- }
- else if (!strcasecmp("dgm_len", type))
- {
- if (p->has_ip())
- {
- // XXX might cause a bug when IPv6 is printed?
- TextLog_Print(csv_log, "%d", p->ptrs.ip_api.dgram_len());
- }
- }
- else if (!strcasecmp("tcp_seq", type))
- {
- if (p->ptrs.tcph != NULL)
- TextLog_Print(csv_log, "0x%lX", (u_long)ntohl(p->ptrs.tcph->th_seq));
- }
- else if (!strcasecmp("tcp_ack", type))
- {
- if (p->ptrs.tcph != NULL)
- TextLog_Print(csv_log, "0x%lX", (u_long)ntohl(p->ptrs.tcph->th_ack));
- }
- else if (!strcasecmp("tcp_len", type))
- {
- if (p->ptrs.tcph != NULL)
- TextLog_Print(csv_log, "%d", (p->ptrs.tcph->off()));
- }
- else if (!strcasecmp("tcp_win", type))
- {
- if (p->ptrs.tcph != NULL)
- TextLog_Print(csv_log, "0x%X", ntohs(p->ptrs.tcph->th_win));
- }
- else if (!strcasecmp("tcp_flags",type))
- {
- if (p->ptrs.tcph != NULL)
- {
- CreateTCPFlagString(p->ptrs.tcph, tcpFlags);
- TextLog_Print(csv_log, "%s", tcpFlags);
- }
- }
-
- if (num < numargs - 1)
- TextLog_Putc(csv_log, ',');
+ if ( first )
+ first = false;
+ else
+ TextLog_Puts(csv_log, sep.c_str());
+
+ f(a);
}
TextLog_NewLine(csv_log);
//-------------------------------------------------------------------------
// logger stuff
//-------------------------------------------------------------------------
-static const char* s_dispos[] = { " [Allow]", " [CDrop]", " [WDrop]", " [Drop]", " [FDrop]" };
+
+static const char* s_dispos[] =
+{ " [Allow]", " [CDrop]", " [WDrop]", " [Drop]", " [FDrop]" };
class FastLogger : public Logger
{
TextLog_Term(fast_log);
}
-#ifdef REG_TEST
-static void LogReassembly(const Packet* p)
-{
- /* Log whether or not this is reassembled data - only indicate
- * if we're actually going to show any of the payload */
- if ( !SnortConfig::output_app_data() || !p->dsize || !p->is_cooked() )
- return;
-
- switch ( p->pseudo_type )
- {
- case PSEUDO_PKT_SMB_SEG:
- TextLog_Print(fast_log, "%s\n", "SMB desegmented packet");
- break;
- case PSEUDO_PKT_DCE_SEG:
- TextLog_Print(fast_log, "%s\n", "DCE/RPC desegmented packet");
- break;
- case PSEUDO_PKT_DCE_FRAG:
- TextLog_Print(fast_log, "%s\n", "DCE/RPC defragmented packet");
- break;
- case PSEUDO_PKT_SMB_TRANS:
- TextLog_Print(fast_log, "%s\n", "SMB Transact reassembled packet");
- break;
- case PSEUDO_PKT_DCE_RPKT:
- TextLog_Print(fast_log, "%s\n", "DCE/RPC reassembled packet");
- break;
- case PSEUDO_PKT_TCP:
- TextLog_Print(fast_log, "%s\n", "Stream reassembled packet");
- break;
- case PSEUDO_PKT_IP:
- TextLog_Print(fast_log, "%s\n", "Frag reassembled packet");
- break;
- default:
- // FIXIT do we get here for portscan or sdf?
- break;
- }
-}
-
-#endif
-
-#ifndef REG_TEST
-static const char* get_pkt_type(Packet* p)
-{
- switch ( p->ptrs.get_pkt_type() )
- {
- case PktType::IP: return "IP";
- case PktType::ICMP: return "ICMP";
- case PktType::TCP: return "TCP";
- case PktType::UDP: return "UDP";
- default: break;
- }
- return "error";
-}
-#endif
-
void FastLogger::alert(Packet* p, const char* msg, Event* event)
{
- tActiveDrop dispos = Active_GetDisposition();
LogTimeStamp(fast_log, p);
+ tActiveDrop dispos = Active_GetDisposition();
if ( dispos > ACTIVE_ALLOW )
{
if ( dispos > ACTIVE_DROP )
dispos = ACTIVE_DROP;
- TextLog_Puts(fast_log, s_dispos[dispos]);
+ TextLog_Print(fast_log, " %s", s_dispos[dispos]);
}
{
}
if (msg != NULL)
- {
-#ifdef REG_TEST
- string tmp = msg + 1;
- tmp.pop_back();
- TextLog_Puts(fast_log, tmp.c_str());
-#else
TextLog_Puts(fast_log, msg);
-#endif
- }
+
TextLog_Puts(fast_log, " [**] ");
}
/* print the packet header to the alert file */
{
LogPriorityData(fast_log, event, 0);
-#ifndef REG_TEST
- TextLog_Print(fast_log, "{%s} ", get_pkt_type(p));
-#else
- TextLog_Print(fast_log, "{%s} ", protocol_names[p->get_ip_proto_next()]);
-#endif
+ TextLog_Print(fast_log, "{%s} ", p->get_type());
LogIpAddrs(fast_log, p);
}
if ( packet || SnortConfig::output_app_data() )
{
TextLog_NewLine(fast_log);
-#ifdef REG_TEST
- LogReassembly(p);
-#endif
if (p->has_ip())
LogIPPkt(fast_log, p);
else
- LogPayload(fast_log, p);
+ LogNetData(fast_log, p->data, p->dsize, p);
#if 0
- // FIXIT-L -J LogArpHeader unimplemented
+ // FIXIT-L LogArpHeader unimplemented
else if (p->proto_bits & PROTO_BIT__ARP)
LogArpHeader(fast_log, p);
#endif
DEBUG_WRAP(DebugMessage(DEBUG_LOG, "Logging Alert data!\n"); );
LogTimeStamp(full_log, p);
+ TextLog_Putc(full_log, ' ');
if (p && p->has_ip())
{
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2007-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation. You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-//--------------------------------------------------------------------------
-
-/* alert_test_
- *
- * Output is tab delimited in the following order:
- * packet count, gid, sid, rev, msg, session, rebuilt
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "snort_types.h"
-#include "framework/logger.h"
-#include "framework/module.h"
-#include "event.h"
-#include "protocols/packet.h"
-#include "snort_debug.h"
-#include "parser.h"
-#include "util.h"
-#include "log/log_text.h"
-#include "log/text_log.h"
-#include "utils/stats.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <string>
-
-#define TEST_FLAG_MSG 0x01
-#define TEST_FLAG_SESSION 0x02
-#define TEST_FLAG_REBUILT 0x04
-#define TEST_FLAG_FILE 0x08
-
-static THREAD_LOCAL TextLog* test_file = nullptr;
-
-using namespace std;
-
-#define S_NAME "alert_test"
-#define F_NAME S_NAME ".txt"
-
-//-------------------------------------------------------------------------
-// alert_test module
-//-------------------------------------------------------------------------
-
-static const Parameter s_params[] =
-{
- { "file", Parameter::PT_BOOL, nullptr, "false",
- "output to " F_NAME " instead of stdout" },
-
- { "rebuilt", Parameter::PT_BOOL, nullptr, "false",
- "include type:count where type is S for stream and F for frag" },
-
- { "session", Parameter::PT_BOOL, nullptr, "false",
- "include src-dst each of form -addr:port" },
-
- { "msg", Parameter::PT_BOOL, nullptr, "false",
- "include alert msg" },
-
- { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
-};
-
-#define s_help \
- "output event in custom tsv format"
-
-class TestModule : public Module
-{
-public:
- TestModule() : Module(S_NAME, s_help, s_params) { }
-
- bool set(const char*, Value&, SnortConfig*) override;
- bool begin(const char*, int, SnortConfig*) override;
-
-public:
- unsigned flags;
-};
-
-bool TestModule::set(const char*, Value& v, SnortConfig*)
-{
- if ( v.is("file") )
- {
- if ( v.get_bool() )
- flags |= TEST_FLAG_FILE;
- }
- else if ( v.is("rebuilt") )
- {
- if ( v.get_bool() )
- flags |= TEST_FLAG_REBUILT;
- }
- else if ( v.is("session") )
- {
- if ( v.get_bool() )
- flags |= TEST_FLAG_SESSION;
- }
- else if ( v.is("msg") )
- {
- if ( v.get_bool() )
- flags |= TEST_FLAG_MSG;
- }
- else
- return false;
-
- return true;
-}
-
-bool TestModule::begin(const char*, int, SnortConfig*)
-{
- flags = 0;
- return true;
-}
-
-//-------------------------------------------------------------------------
-
-class TestLogger : public Logger
-{
-public:
- TestLogger(TestModule*);
-
- void open() override;
- void close() override;
-
- void alert(Packet*, const char* msg, Event*) override;
-
-private:
- unsigned flags;
-};
-
-TestLogger::TestLogger(TestModule* m)
-{
- flags = m->flags;
-}
-
-void TestLogger::open()
-{
- const char* f = (flags & TEST_FLAG_FILE) ? F_NAME : "stdout";
- test_file = TextLog_Init(f);
-}
-
-void TestLogger::close()
-{
- TextLog_Term(test_file);
-}
-
-void TestLogger::alert(Packet* p, const char* msg, Event* event)
-{
- TextLog_Print(test_file, "" STDu64 "\t", pc.total_from_daq);
-
- if (event != NULL)
- {
- TextLog_Print(test_file, "%lu\t%lu\t%lu\t",
- (unsigned long)event->sig_info->generator,
- (unsigned long)event->sig_info->id,
- (unsigned long)event->sig_info->rev);
- }
-
- if (flags & TEST_FLAG_MSG)
- {
- if (msg != NULL)
- TextLog_Print(test_file, "%s\t", msg);
- }
-
- if (flags & TEST_FLAG_SESSION)
- LogIpAddrs(test_file, p);
-
- if ( (flags & TEST_FLAG_REBUILT) && (p->packet_flags & PKT_PSEUDO) )
- {
- const char* s;
- switch ( p->pseudo_type )
- {
- case PSEUDO_PKT_IP: s = "ip-defrag"; break;
- case PSEUDO_PKT_TCP: s = "tcp-deseg"; break;
- case PSEUDO_PKT_DCE_RPKT: s = "dce-pkt"; break;
- case PSEUDO_PKT_DCE_SEG: s = "dce-deseg"; break;
- case PSEUDO_PKT_DCE_FRAG: s = "dec-defrag"; break;
- case PSEUDO_PKT_SMB_SEG: s = "smb-deseg"; break;
- case PSEUDO_PKT_SMB_TRANS: s = "smb-trans"; break;
- case PSEUDO_PKT_PS: s = "port_scan"; break;
- case PSEUDO_PKT_SDF: s = "sdf"; break;
- default: s = "pseudo pkt"; break;
- }
- TextLog_Print(test_file, "%s", s);
- }
- TextLog_Print(test_file, "\n");
- TextLog_Flush(test_file);
-}
-
-//-------------------------------------------------------------------------
-
-static Module* mod_ctor()
-{ return new TestModule; }
-
-static void mod_dtor(Module* m)
-{ delete m; }
-
-static Logger* test_ctor(SnortConfig*, Module* mod)
-{ return new TestLogger((TestModule*)mod); }
-
-static void test_dtor(Logger* p)
-{ delete p; }
-
-static LogApi test_api
-{
- {
- PT_LOGGER,
- sizeof(LogApi),
- LOGAPI_VERSION,
- 0,
- API_RESERVED,
- API_OPTIONS,
- S_NAME,
- s_help,
- mod_ctor,
- mod_dtor
- },
- OUTPUT_TYPE_FLAG__ALERT,
- test_ctor,
- test_dtor
-};
-
-#ifdef BUILDING_SO
-SO_PUBLIC const BaseApi* snort_plugins[] =
-{
- &test_api.base,
- nullptr
-};
-#else
-const BaseApi* alert_test = &test_api.base;
-#endif
-
#include <iostream>
#include "main/snort_types.h"
+#include "main/snort_config.h"
#include "framework/logger.h"
#include "framework/module.h"
#include "protocols/packet.h"
#include "protocols/packet_manager.h"
#include "detection/signature.h"
#include "log/text_log.h"
+#include "log/log_text.h"
#include "utils/stats.h"
static THREAD_LOCAL TextLog* test_file = nullptr;
void CodecLogger::log(Packet* p, const char* msg, Event* e)
{
- std::string s = std::string(msg);
-
TextLog_Print(test_file, "pkt:" STDu64 "\t", pc.total_from_daq);
if (e != NULL)
TextLog_NewLine(test_file);
PacketManager::log_protocols(test_file, p);
TextLog_NewLine(test_file);
+
+ if ( p->dsize and SnortConfig::output_app_data() )
+ LogNetData(test_file, p->data, p->dsize, p);
+
TextLog_NewLine(test_file);
}
return PCAP_PKT_HDR_SZ + pkth->caplen;
}
-static int SizeOfCallback(
- DAQ_PktHdr_t* pkth, uint8_t*, void* userdata)
-{
- size_t* pSize = (size_t*)userdata;
- (*pSize) += SizeOf(pkth);
-
- return 0;
-}
-
static void LogTcpdumpSingle(
LtdConfig* data, Packet* p, const char*, Event*)
{
}
}
-static int LogTcpdumpStreamCallback(
- DAQ_PktHdr_t* pkth, uint8_t* packet_data, void*)
-{
- pcap_dump((u_char*)context.dumpd,
- (struct pcap_pkthdr*)pkth,
- (u_char*)packet_data);
-
- return 0;
-}
-
static void LogTcpdumpStream(
- LtdConfig* data, Packet* p, const char*, Event*)
+ LtdConfig*, Packet*, const char*, Event*)
{
- size_t dumpSize = 0;
-
- stream.traverse_reassembled(p, SizeOfCallback, &dumpSize);
-
- if ( data->limit && (context.size + dumpSize > data->limit) )
- TcpdumpRollLogFile(data);
-
- stream.traverse_reassembled(p, LogTcpdumpStreamCallback, data);
-
- context.size += dumpSize;
-
- if (!SnortConfig::line_buffered_logging())
- {
- /* we happen to know that pcap_dumper_t* is really just a FILE* */
- fflush( (FILE*)context.dumpd);
- }
+// FIXIT-L log reassembled stream data with original packet?
+// (take original packet headers and append reassembled data)
}
static void TcpdumpInitLogFile(LtdConfig*, int /*nostamps?*/)
extern const BaseApi* alert_fast;
extern const BaseApi* alert_full;
extern const BaseApi* alert_syslog;
-extern const BaseApi* alert_test;
extern const BaseApi* alert_unix_sock;
extern const BaseApi* log_null;
extern const BaseApi* log_pcap;
alert_fast,
alert_full,
alert_syslog,
- alert_test,
alert_unix_sock,
// loggers
log_null,
static void Unified2InitFile(Unified2Config*);
static inline void Unified2RotateFile(Unified2Config*);
static void _Unified2LogPacketAlert(Packet*, const char*, Unified2Config*, Event*);
-static void _Unified2LogStreamAlert(Packet*, const char*, Unified2Config*, Event*);
-static int Unified2LogStreamCallback(DAQ_PktHdr_t*, uint8_t*, void*);
static void Unified2Write(uint8_t*, uint32_t, Unified2Config*);
static void _AlertIP4_v2(Packet*, const char*, Unified2Config*, Event*);
Unified2Write(write_pkt_buffer, write_len, config);
}
-/**
- * Callback for the Stream reassembler to log packets
- *
- */
-static int Unified2LogStreamCallback(DAQ_PktHdr_t* pkth,
- uint8_t* packet_data, void* userdata)
-{
- Unified2LogCallbackData* unifiedData = (Unified2LogCallbackData*)userdata;
- Serial_Unified2_Header hdr;
- uint32_t write_len = sizeof(Serial_Unified2_Header) + sizeof(Serial_Unified2Packet) - 4;
-
- if (!userdata || !pkth || !packet_data)
- return -1;
-
- write_len += pkth->caplen;
-
- if ( unifiedData->config->limit &&
- (u2.current + write_len) > unifiedData->config->limit )
- Unified2RotateFile(unifiedData->config);
-
- hdr.type = htonl(UNIFIED2_PACKET);
- hdr.length = htonl(sizeof(Serial_Unified2Packet) - 4 + pkth->caplen);
-
- /* Event data will already be set */
-
- unifiedData->logheader->packet_second = htonl((uint32_t)pkth->ts.tv_sec);
- unifiedData->logheader->packet_microsecond = htonl((uint32_t)pkth->ts.tv_usec);
- unifiedData->logheader->packet_length = htonl(pkth->caplen);
-
- if (SafeMemcpy(write_pkt_buffer, &hdr, sizeof(Serial_Unified2_Header),
- write_pkt_buffer, write_pkt_end) != SAFEMEM_SUCCESS)
- {
- ErrorMessage("%s(%d) Failed to copy Serial_Unified2_Header. "
- "Not writing unified2 event.\n", __FILE__, __LINE__);
- return -1;
- }
-
- if (SafeMemcpy(write_pkt_buffer + sizeof(Serial_Unified2_Header),
- unifiedData->logheader, sizeof(Serial_Unified2Packet) - 4,
- write_pkt_buffer, write_pkt_end) != SAFEMEM_SUCCESS)
- {
- ErrorMessage("%s(%d) Failed to copy Serial_Unified2Packet. "
- "Not writing unified2 event.\n", __FILE__, __LINE__);
- return -1;
- }
-
- if (SafeMemcpy(write_pkt_buffer + sizeof(Serial_Unified2_Header) +
- sizeof(Serial_Unified2Packet) - 4,
- packet_data, pkth->caplen,
- write_pkt_buffer, write_pkt_end) != SAFEMEM_SUCCESS)
- {
- ErrorMessage("%s(%d) Failed to copy packet data. "
- "Not writing unified2 event.\n", __FILE__, __LINE__);
- return -1;
- }
-
- Unified2Write(write_pkt_buffer, write_len, unifiedData->config);
-
- return 0;
-}
-
static ObRet Unified2LogObfuscationCallback(const DAQ_PktHdr_t* pkth,
const uint8_t* packet_data, ob_size_t length,
ob_char_t ob_char, void* userdata)
return OB_RET_SUCCESS;
}
-/**
- * Log a set of packets stored in the stream reassembler
- *
- */
-static void _Unified2LogStreamAlert(
- Packet* p, const char*, Unified2Config* config, Event* event)
-{
- Unified2LogCallbackData unifiedData;
- Serial_Unified2Packet logheader;
-
- logheader.sensor_id = 0;
- logheader.linktype = u2.base_proto;
-
- /* setup the event header */
- if (event != NULL)
- {
- logheader.event_id = htonl(event->event_reference);
- logheader.event_second = htonl(event->ref_time.tv_sec);
- }
- else
- {
- logheader.event_id = 0;
- logheader.event_second = 0;
- }
-
- /* queue up the stream for logging */
- unifiedData.logheader = &logheader;
- unifiedData.config = config;
- unifiedData.event = event;
- unifiedData.num_bytes = 0;
-
- if ((p != NULL) && (p->pkt != NULL) && (p->pkth != NULL)
- && obApi->payloadObfuscationRequired(p))
- {
- if (obApi->obfuscatePacketStreamSegments(p, Unified2LogObfuscationCallback,
- (void*)&unifiedData) == OB_RET_SUCCESS)
- {
- /* Write the last record */
- if (unifiedData.num_bytes != 0)
- Unified2Write(write_pkt_buffer, unifiedData.num_bytes, config);
- return;
- }
-
- /* Reset since we failed */
- unifiedData.num_bytes = 0;
- }
-
- if (!p)
- return;
-
- stream.traverse_reassembled(p, Unified2LogStreamCallback, &unifiedData);
-}
-
/******************************************************************************
* Function: Unified2Write()
*
{
DEBUG_WRAP(DebugMessage(DEBUG_LOG,
"[*] Reassembled packet, dumping stream packets\n"); );
- _Unified2LogStreamAlert(p, msg, &config, event);
+ // FIXIT-L replace with reassembled stream data and
+ // optionally the first captured packet
+ //_Unified2LogStreamAlert(p, msg, &config, event);
}
else
{
{ "logdir", Parameter::PT_STRING, nullptr, ".",
"where to put log files (same as -l)" },
- { "nolog", Parameter::PT_BOOL, nullptr, "false",
- "turn off logging (alerts still work, same as -N)" },
-
{ "obfuscate", Parameter::PT_BOOL, nullptr, "false",
"obfuscate the logged IP addresses (same as -O)" },
else if ( v.is("max_data") )
sc->event_trace_max = v.get_long();
- else if ( v.is("nolog") )
- v.update_mask(sc->output_flags, OUTPUT_FLAG__NO_LOG);
-
else if ( v.is("obfuscate") )
v.update_mask(sc->output_flags, OUTPUT_FLAG__OBFUSCATE);
return false;
}
- if ( (snort_conf->output_flags & OUTPUT_FLAG__NO_LOG) !=
- (output_flags & OUTPUT_FLAG__NO_LOG) )
- {
- ErrorMessage("Snort Reload: Changing from log to no log or vice "
- "versa requires a restart.\n");
- return false;
- }
-
if ((snort_conf->run_flags & RUN_FLAG__NO_PROMISCUOUS) !=
(run_flags & RUN_FLAG__NO_PROMISCUOUS))
{
OUTPUT_FLAG__OBFUSCATE = 0x00000100, /* -B */
OUTPUT_FLAG__ALERT_IFACE = 0x00000200, /* -I */
OUTPUT_FLAG__NO_TIMESTAMP = 0x00000400, /* --nostamps */
-
- OUTPUT_FLAG__NO_ALERT = 0x00001000, /* -A none */
- OUTPUT_FLAG__NO_LOG = 0x00002000, /* -K none */
- OUTPUT_FLAG__ALERTS = 0x00004000, /* -A != none */
+ OUTPUT_FLAG__ALERTS = 0x00000800, /* -A */
};
enum LoggingFlag
// parameters
//-------------------------------------------------------------------------
-#ifdef REG_TEST
-#define REG_TEST_IGNORE " -N --pcap-reset "
-#endif
-
static const Parameter s_params[] =
{
{ "-?", Parameter::PT_STRING, "(optional)", nullptr,
"<mode> checksum mode (all,noip,notcp,noudp,noicmp,none)" },
{ "-L", Parameter::PT_STRING, nullptr, nullptr,
- "<mode> logging mode (none, text, pcap, or log_*)" },
+ "<mode> logging mode (none, dump, pcap, or log_*)" },
{ "-l", Parameter::PT_STRING, nullptr, nullptr,
"<logdir> log to this directory instead of current directory" },
{ "-m", Parameter::PT_INT, "0:", nullptr,
"<umask> set umask = <umask>" },
-#ifdef REG_TEST
- { "-N", Parameter::PT_IMPLIED, nullptr, nullptr,
- "ignored - for REG_TEST only" },
-#endif
-
{ "-n", Parameter::PT_INT, "0:", nullptr,
"<count> stop after count packets" },
{ "--pcap-reload", Parameter::PT_IMPLIED, nullptr, nullptr,
"if reading multiple pcaps, reload snort config between pcaps" },
-#ifdef REG_TEST
- { "--pcap-reset", Parameter::PT_IMPLIED, nullptr, nullptr,
- "ignored - for REG_TEST only" },
-#endif
-
{ "--pcap-show", Parameter::PT_IMPLIED, nullptr, nullptr,
"print a line saying what pcap is currently being read" },
else if ( v.is("--x2c") )
x2c(v.get_long());
-#ifdef REG_TEST
- else if ( !strstr(REG_TEST_IGNORE, v.get_name()) )
- return false;
-#endif
-
return true;
}
uint64_t Active_GetInjects(void) { return s_injects; }
+const char* Active_GetDispositionString()
+{
+ switch ( active_drop_pkt )
+ {
+ case ACTIVE_ALLOW: return "allow";
+ case ACTIVE_CANT_DROP: return "cant_drop";
+ case ACTIVE_WOULD_DROP: return "would_drop";
+ case ACTIVE_DROP: return "drop";
+ case ACTIVE_FORCE_DROP: return "force_drop";
+ default: break;
+ }
+ return "error";
+}
+
SO_PUBLIC const char* Active_GetDispositionString();
-#endif // ACTIVE_H
+#endif
#define DAQ_DEFAULT "pcap"
#endif
-#ifdef REG_TEST
#ifndef DAQ_CAPA_INJECT_RAW
#define DAQ_CAPA_INJECT_RAW 0x200
#endif
-#endif
// common for all daq threads / instances
static const DAQ_Module_t* daq_mod = NULL;
#include "sfip/sf_ip.h"
#define LOG_NONE "none"
-#define LOG_TEXT "text"
-#define LOG_PCAP "pcap"
+#define LOG_DUMP "dump"
+#define LOG_CODECS "codecs"
#define ALERT_NONE "none"
#define ALERT_CMG "cmg"
#define ALERT_DJR "djr"
#define ALERT_U2 "u2"
#define ALERT_AJK "ajk"
-#ifdef REG_TEST
-#define ALERT_CON "console"
-#endif
#define OUTPUT_U2 "unified2"
#define OUTPUT_FAST "alert_fast"
-#define OUTPUT_PCAP "log_pcap"
static std::string lua_conf;
static std::string snort_conf_dir;
sc->dirty_pig = 1;
}
-void ConfigNoLog(SnortConfig* sc, const char*)
-{
- sc->output_flags |= OUTPUT_FLAG__NO_LOG;
-}
-
void ConfigObfuscate(SnortConfig* sc, const char*)
{
sc->output_flags |= OUTPUT_FLAG__OBFUSCATE;
void config_alert_mode(SnortConfig* sc, const char* val)
{
if (strcasecmp(val, ALERT_NONE) == 0)
- {
- sc->output_flags |= OUTPUT_FLAG__NO_ALERT;
EventManager::enable_alerts(false);
- }
+
else if ( !strcasecmp(val, ALERT_CMG) or !strcasecmp(val, ALERT_JH) or
!strcasecmp(val, ALERT_DJR) )
{
else if ( !strcasecmp(val, ALERT_U2) or !strcasecmp(val, ALERT_AJK) )
sc->output = OUTPUT_U2;
-#ifdef REG_TEST
- else if (strcasecmp(val, ALERT_CON) == 0)
- sc->output = OUTPUT_FAST;
-#endif
else
sc->output = val;
{
if (strcasecmp(val, LOG_NONE) == 0)
{
- sc->output_flags |= OUTPUT_FLAG__NO_LOG;
Snort::set_main_hook(snort_ignore);
EventManager::enable_logs(false);
}
- else if (strcasecmp(val, LOG_TEXT) == 0)
- {
- Snort::set_main_hook(snort_print);
- }
- else if (strcasecmp(val, LOG_PCAP) == 0)
- {
- sc->output = OUTPUT_PCAP;
- Snort::set_main_hook(snort_log);
- }
else
{
+ if ( !strcmp(val, LOG_DUMP) )
+ val = LOG_CODECS;
sc->output = val;
Snort::set_main_hook(snort_log);
}
void ConfigDaqVar(SnortConfig*, const char*);
void ConfigDaqDir(SnortConfig*, const char*);
void ConfigDirtyPig(SnortConfig*, const char*);
-void ConfigNoLog(SnortConfig*, const char*);
void ConfigNoLoggingTimestamps(SnortConfig*, const char*);
void ConfigObfuscate(SnortConfig*, const char*);
void ConfigObfuscationMask(SnortConfig*, const char*);
std::memcpy(&(dst.ip8), &(h6->ip6_dst), 16);
}
-void IpApi::set(sfip_t& sip, sfip_t& dip)
+void IpApi::set(const sfip_t& sip, const sfip_t& dip)
{
type = IAT_DATA;
sfip_set_ip(&src, &sip);
void set(const IP4Hdr* h4);
void set(const IP6Hdr* h6);
- void set(sfip_t& src, sfip_t& dst);
+ void set(const sfip_t& src, const sfip_t& dst);
bool set(const uint8_t* raw_ip_data);
void reset();
return false;
}
+const char* Packet::get_type() const
+{
+ switch ( ptrs.get_pkt_type() )
+ {
+ case PktType::IP:
+ return "IP";
+
+ case PktType::ICMP:
+ return "ICMP";
+
+ case PktType::TCP:
+ return "TCP";
+
+ case PktType::UDP:
+ return "UDP";
+
+ case PktType::USER:
+ case PktType::FILE:
+ if ( proto_bits & PROTO_BIT__TCP )
+ return "TCP";
+ if ( proto_bits & PROTO_BIT__UDP )
+ return "UDP";
+ break;
+
+ default:
+ break;
+ }
+ return "error";
+}
+
+const char* Packet::get_pseudo_type() const
+{
+ if ( !(packet_flags & PKT_PSEUDO) )
+ return "raw";
+
+ switch ( pseudo_type )
+ {
+ case PSEUDO_PKT_IP:
+ return "stream_ip";
+
+ case PSEUDO_PKT_TCP:
+ return "stream_tcp";
+
+ case PSEUDO_PKT_DCE_RPKT:
+ return "dce2_rpc_reass";
+
+ case PSEUDO_PKT_DCE_SEG:
+ return "dce2_rpc_deseg";
+
+ case PSEUDO_PKT_DCE_FRAG:
+ return "dce2_rpc_defrag";
+
+ case PSEUDO_PKT_SMB_SEG:
+ return "dce2_smb_deseg";
+
+ case PSEUDO_PKT_SMB_TRANS:
+ return "dce2_smb_transact";
+
+ case PSEUDO_PKT_PS:
+ return "port_scan";
+
+ case PSEUDO_PKT_SDF:
+ return "sdf";
+
+ default: break;
+ }
+ return "other";
+}
+
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
-#else /* !WIN32 */
+#else
#include <netinet/in_systm.h>
#ifndef IFNAMSIZ
#define IFNAMESIZ MAX_ADAPTER_NAME
-#endif /* !IFNAMSIZ */
-#endif /* !WIN32 */
+#endif
+#endif
extern "C" {
#include <daq.h>
constexpr uint8_t TCP_OPTLENMAX = 40; /* (((2^4) - 1) * 4 - TCP_HEADER_LEN) */
constexpr uint8_t DEFAULT_LAYERMAX = 40;
-/* D A T A S T R U C T U R E S *********************************************/
-class Flow;
-
+// Packet is an abstraction describing a unit of work. it may define a
+// wire packet or it may define a cooked packet. the latter contains
+// payload data only, no headers.
struct SO_PUBLIC Packet
{
- Flow* flow; /* for session tracking */
+ class Flow* flow; /* for session tracking */
uint32_t packet_flags; /* special flags for the packet */
uint32_t xtradata_mask;
PseudoPacketType pseudo_type; // valid only when PKT_PSEUDO is set
uint32_t iplist_id;
- uint16_t max_dsize;
- /**policyId provided in configuration file. Used for correlating configuration
- * with event output
- */
+ // for correlating configuration with event output
uint16_t user_policy_id;
uint8_t ps_proto; // Used for portscan and unified2 logging
+ // IP_MAXPACKET is the minimum allowable max_dsize
+ // there is no requirement that all data fit into an IP datagram
+ // but we do require that an IP datagram fit into Packet space
+ // we can increase beyond this if needed
+ static const uint32_t max_dsize = IP_MAXPACKET;
+
/* Boolean functions - general information about this packet */
inline bool has_ip() const
{ return ptrs.ip_api.is_ip(); }
inline bool is_fragment() const
{ return ptrs.decode_flags & DECODE_FRAG; }
+ inline bool has_tcp_data() const
+ { return (proto_bits & PROTO_BIT__TCP) and data and dsize; }
+
/* Get general, non-boolean information */
inline PktType type() const
{ return ptrs.get_pkt_type(); } // defined in codec.h
+ const char* get_type() const;
+ const char* get_pseudo_type() const;
+
/* the ip_api return the protocol_ID of the protocol directly after the
* innermost IP layer. However, especially in IPv6, the next protocol
* can frequently be an IP extension. Therefore, this function
inline void reset()
{
- memset(&flow, '\0', offsetof(Packet, pkth));
+ memset(this, 0, offsetof(Packet, pkth));
ptrs.reset();
}
bool from_client()
{ return (packet_flags & (PKT_REBUILT_STREAM|PKT_REBUILT_FRAG)) != 0; }
};
-#define PKT_ZERO_LEN offsetof(Packet, pkth)
-
/* Macros to deal with sequence numbers - p810 TCP Illustrated vol 2 */
#define SEQ_LT(a,b) ((int)((a) - (b)) < 0)
#define SEQ_LEQ(a,b) ((int)((a) - (b)) <= 0)
codec_data.codec_flags |= CODEC_STREAM_REBUILT;
// initialize all Packet information
- memset(p, 0, PKT_ZERO_LEN);
+ p->reset();
p->pkth = pkthdr;
p->pkt = pkt;
p->ptrs.reset();
}
}
+static void set_hdr(
+ const Packet* p, Packet* c, const DAQ_PktHdr_t* phdr, uint32_t opaque)
+{
+ c->reset();
+ DAQ_PktHdr_t* pkth = (DAQ_PktHdr_t*)c->pkth;
+
+#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
+ if ( !phdr )
+ phdr = p->pkth;
+
+ pkth->ingress_index = phdr->ingress_index;
+ pkth->ingress_group = phdr->ingress_group;
+ pkth->egress_index = phdr->egress_index;
+ pkth->egress_group = phdr->egress_group;
+ pkth->flags = phdr->flags & (~DAQ_PKT_FLAG_HW_TCP_CS_GOOD);
+ pkth->address_space_id = phdr->address_space_id;
+ pkth->opaque = opaque;
+ UNUSED(p);
+#else
+#ifdef HAVE_DAQ_ACQUIRE_WITH_META
+ pkth->opaque = p->pkth->opaque;
+#endif
+ UNUSED(p);
+ UNUSED(phdr);
+ UNUSED(opaque);
+#endif
+}
+
//-------------------------------------------------------------------------
// formatters:
// - these packets undergo detection
// - inner layer header is very similar but payload differs
// - original ttl is always used
//-------------------------------------------------------------------------
-int PacketManager::encode_format_with_daq_info(
+
+int PacketManager::format_tcp(
+ EncodeFlags, const Packet* p, Packet* c, PseudoPacketType type,
+ const DAQ_PktHdr_t* phdr, uint32_t opaque)
+{
+ c->reset();
+ DAQ_PktHdr_t* pkth = (DAQ_PktHdr_t*)c->pkth;
+ set_hdr(p, c, phdr, opaque);
+
+ c->packet_flags |= PKT_PSEUDO;
+ c->pseudo_type = type;
+ c->user_policy_id = p->user_policy_id; // cooked packet gets same policy as raw
+
+ // setup pkt capture header
+ pkth->caplen = 0;
+ pkth->pktlen = 0;
+ pkth->ts = p->pkth->ts;
+
+ total_rebuilt_pkts++; // update local counter
+ return 0;
+}
+
+int PacketManager::encode_format(
EncodeFlags f, const Packet* p, Packet* c, PseudoPacketType type,
const DAQ_PktHdr_t* phdr, uint32_t opaque)
{
if ( num_layers <= 0 )
return -1;
- memset(c, 0, PKT_ZERO_LEN);
-
-#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
- pkth->ingress_index = phdr->ingress_index;
- pkth->ingress_group = phdr->ingress_group;
- pkth->egress_index = phdr->egress_index;
- pkth->egress_group = phdr->egress_group;
- pkth->flags = phdr->flags & (~DAQ_PKT_FLAG_HW_TCP_CS_GOOD);
- pkth->address_space_id = phdr->address_space_id;
- pkth->opaque = opaque;
-#elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
- pkth->opaque = opaque;
- UNUSED(phdr);
-#else
- UNUSED(phdr);
- UNUSED(opaque);
-#endif /* HAVE_DAQ_ADDRESS_SPACE_ID */
+ c->reset();
+ set_hdr(p, c, phdr, opaque);
if ( f & ENC_FLAG_NET )
{
len = c->data - c->pkt;
// len < ETHERNET_HEADER_LEN + VLAN_HEADER + ETHERNET_MTU
- assert((unsigned)len < Codec::PKT_MAX - IP_MAXPACKET);
+ assert((unsigned)len < Codec::PKT_MAX - c->max_dsize);
- c->max_dsize = IP_MAXPACKET - len;
c->proto_bits = p->proto_bits;
c->ip_proto_next = p->ip_proto_next;
c->packet_flags |= PKT_PSEUDO;
return 0;
}
-#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
-int PacketManager::encode_format(EncodeFlags f, const Packet* p, Packet* c, PseudoPacketType type)
-{
- return encode_format_with_daq_info(f, p, c, type, p->pkth, p->pkth->opaque);
-}
-
-#elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
-int PacketManager::encode_format(EncodeFlags f, const Packet* p, Packet* c, PseudoPacketType type)
-{
- return encode_format_with_daq_info(f, p, c, type, nullptr, p->pkth->opaque);
-}
-
-#else
-int PacketManager::encode_format(EncodeFlags f, const Packet* p, Packet* c, PseudoPacketType type)
-{
- return encode_format_with_daq_info(f, p, c, type, nullptr, 0);
-}
-
-#endif
-
//-------------------------------------------------------------------------
// updaters: these functions set length and checksum fields, only needed
// when a packet is modified. some packets only have replacements so only
class SO_PUBLIC PacketManager
{
public:
-
// decode this packet and set all relevent packet fields.
static void decode(Packet*, const struct _daq_pkthdr*, const uint8_t*, bool cooked = false);
// allocate a Packet for later formatting (cloning)
static Packet* encode_new(bool allocate_packet_data = true);
+
// release the allocated Packet
static void encode_delete(Packet*);
// when encoding, rather than copy the destination MAC address from the
// inbound packet, manually set the MAC address.
static void encode_set_dst_mac(uint8_t*);
+
// get the MAC address which has been set using encode_set_dst_mac().
// Useful for root decoders setting the MAC address
static uint8_t* encode_get_dst_mac();
+
// update the packet's checksums and length variables. Call this function
// after Snort has changed any data in this packet
static void encode_update(Packet*);
- // format packet for detection. Original ttl is always used.
- static int encode_format(
- EncodeFlags f, const Packet* orig, Packet* clone, PseudoPacketType type);
- // encode the packet with pre-set daq info.
- static int encode_format_with_daq_info(
- EncodeFlags f, const Packet* p, Packet* c, PseudoPacketType type,
- const DAQ_PktHdr_t*, uint32_t opaque);
- // orig is the wire pkt; clone was obtained with New()
+
+ //--------------------------------------------------------------------
+ // FIXIT-L encode_format() should be replaced with a function that
+ // does format and update in one step for packets cooked for internal
+ // use only like stream_tcp and port_scan. stream_ip packets should
+ // just be decoded from last layer on. at that point all the
+ // Codec::format methods can be deleted too. the new function should
+ // be some super set of format_tcp().
+ //--------------------------------------------------------------------
+
+ // format packet for detection. Original ttl is always used. orig is
+ // the wire pkt; clone was obtained with New()
+ static int encode_format( EncodeFlags f, const Packet* orig, Packet*
+ clone, PseudoPacketType type, const DAQ_PktHdr_t* = nullptr,
+ uint32_t opaque = 0);
+
+ static int format_tcp(
+ EncodeFlags f, const Packet* orig, Packet* clone, PseudoPacketType type,
+ const DAQ_PktHdr_t* = nullptr, uint32_t opaque = 0);
// Send a TCP response. TcpResponse params determined the type
// of response. Len will be set to the response's length.
// payload && payload_len are optional.
static const uint8_t* encode_response(
- TcpResponse, EncodeFlags, const Packet* orig, uint32_t& len,
- const uint8_t* const payload = nullptr, uint32_t payload_len = 0);
+ TcpResponse, EncodeFlags, const Packet* orig, uint32_t& len,
+ const uint8_t* const payload = nullptr, uint32_t payload_len = 0);
+
// Send an ICMP unreachable response!
static const uint8_t* encode_reject(UnreachResponse type,
EncodeFlags flags, const Packet* p, uint32_t& len);
- // for backwards compatability and convenience.
- static inline int encode_format_with_daq_info(
- EncodeFlags f, const Packet* orig, Packet* clone,
- PseudoPacketType type, uint32_t opaque)
- { return encode_format_with_daq_info(f, orig, clone, type, nullptr, opaque); }
-
/* codec support and statistics */
// get the number of packets which have been rebuilt by this thread
static PegCount get_rebuilt_packet_count(void);
+
// set the packet to be encoded.
static void encode_set_pkt(Packet* p);
+
// get the max payload for the current packet
static uint16_t encode_get_max_payload(const Packet*);
+
// reset the current 'clone' packet
static inline void encode_reset(void)
{ encode_set_pkt(NULL); }
// print codec information. MUST be called after thread_term.
static void dump_stats();
+
// Get the name of the given protocol
static const char* get_proto_name(uint16_t protocol);
+
// Get the name of the given protocol
static const char* get_proto_name(uint8_t protocol);
+
// print this packets information, layer by layer
static void log_protocols(TextLog* const, const Packet* const);
{ return CodecManager::s_proto_map[proto]; }
private:
- // STATISTICS!!
-
// The only time we should accumulate is when CodecManager tells us too
friend void CodecManager::thread_term();
static void accumulate();
static void pop_teredo(Packet*, RawData&);
+
static bool encode(const Packet* p, EncodeFlags,
- uint8_t lyr_start, uint8_t next_prot, Buffer& buf);
+ uint8_t lyr_start, uint8_t next_prot, Buffer& buf);
// constant offsets into the s_stats array. Notice the stat_offset
// constant which is used when adding a protocol specific codec
static std::array<PegCount, s_stats.size()> g_stats;
static const std::array<const char*, stat_offset> stat_names;
};
-
#endif
PROFILE_VARS;
/* For TCP, do a few extra checks... */
- if (p->is_udp())
+ if ( p->has_tcp_data() )
{
/* If session picked up mid-stream, do not process further.
* Would be almost impossible to tell where we are in the
void Dns::eval(Packet* p)
{
// precondition - what we registered for
- assert((p->is_udp() || p->is_tcp()) && p->dsize && p->data);
+ assert((p->is_udp() and p->dsize and p->data) or p->has_tcp_data());
++dnsstats.total_packets;
snort_dns(p);
void FtpServer::eval(Packet* p)
{
// precondition - what we registered for
- assert(p->is_tcp() && p->data && p->dsize);
+ assert(p->has_tcp_data());
++ftstats.total_packets;
snort_ftp(p);
void FtpData::eval(Packet* p)
{
// precondition - what we registered for
- assert(p->is_tcp());
+ assert(p->has_tcp_data());
if ( file_api->get_max_file_depth() < 0 )
return;
void Telnet::eval(Packet* p)
{
// precondition - what we registered for
- assert(p->is_tcp() && p->dsize && p->data);
+ assert(p->has_tcp_data());
++tnstats.total_packets;
snort_telnet(config, p);
return HI_INVALID_ARG;
}
- seq_num = GET_PKT_SEQ(p);
+ seq_num = sd ? sd->resp_state.next_seq : 0;
/*
** Let's set up the data pointers.
clearHttpRespBuffer(Server);
- seq_num = GET_PKT_SEQ(p);
+ seq_num = sd ? sd->resp_state.next_seq : 0;
{
expected_pkt = !p->is_pdu_start();
PROFILE_VARS;
// preconditions - what we registered for
- // FIXIT remove proto check? check for tcp or user?
- //assert(p->is_tcp() && p->dsize && p->data);
- assert(p->dsize && p->data);
+ assert(p->has_tcp_data());
MODULE_PROFILE_START(hiPerfStats);
hi_clear_events();
{
PROFILE_VARS;
// precondition - what we registered for
- assert(p->is_tcp() && p->dsize && p->data);
+ assert(p->has_tcp_data());
++imapstats.total_packets;
header_line = new Field[session_data->num_head_lines[source_id]];
while (bytes_used < msg_text.length)
{
+ assert(num_headers < session_data->num_head_lines[source_id]);
header_line[num_headers].start = msg_text.start + bytes_used;
header_line[num_headers].length = find_header_end(header_line[num_headers].start,
msg_text.length - bytes_used, num_seps);
- assert(num_headers < session_data->num_head_lines[source_id]);
if (header_line[num_headers].length > MAX_HEADER_LENGTH)
{
infractions += INF_TOO_LONG_HEADER;
{
PROFILE_VARS;
// precondition - what we registered for
- assert(p->is_tcp() && p->dsize && p->data);
+ assert(p->has_tcp_data());
++popstats.total_packets;
DEBUG_WRAP(DebugMessage(DEBUG_RPC, "New size: %d\n", decoded_len);
DebugMessage(DEBUG_RPC, "converted data:\n");
- //LogNetData(data, decoded_len, NULL);
+ //LogNetData(data, decoded_len, p);
);
set_alt_data(DecodeBuffer.data, decoded_len);
PROFILE_VARS;
// preconditions - what we registered for
- assert(p->is_tcp() && p->dsize);
+ assert(p->has_tcp_data());
/* If we're stateful that means stream has been configured.
* In this case we don't look at server packets.
{
PROFILE_VARS;
// precondition - what we registered for
- assert(p->is_tcp() && p->dsize && p->data);
+ assert(p->has_tcp_data());
++smtpstats.total_packets;
void Ssh::eval(Packet* p)
{
// precondition - what we registered for
- assert(p->is_tcp() && p->dsize && p->data);
+ assert(p->has_tcp_data());
++sshstats.total_packets;
snort_ssh(config, p);
// such as exceeding s5_pkt->max_dsize. the actual amount
// flushed would ideally be applied to ps->fpt later. for
// now we try to circumvent such cases so we track correctly.
+ // FIXIT-L max_dsize should no longer be exceeded since it excludes
+ // headers.
case FT_MAX:
at = s5_len;
if ( ps->fpt > s5_len )
//--------------------------------------------------------------------
-uint32_t paf_check (
+int32_t paf_check (
StreamSplitter* ss, PAF_State* ps, Flow* ssn,
const uint8_t* data, uint32_t len, uint32_t total,
uint32_t seq, uint32_t* flags)
}
// called on each in order segment
-uint32_t paf_check(
+int32_t paf_check(
StreamSplitter* paf_config, PAF_State*, Flow* ssn,
const uint8_t* data, uint32_t len, uint32_t total,
uint32_t seq, uint32_t* flags);
unsigned use;
};
-/* D A T A S T R U C T U R E S **********************************/
// FIXIT-L some of this stuff can be better encapsulated
struct StreamGlobalConfig
flow->session->clear_extra_data(p, flag);
}
-int Stream::traverse_reassembled(
- Packet* p, PacketIterator callback, void* userdata)
-{
- Flow* flow = p->flow;
- assert(flow && flow->session);
- return flow->session->get_rebuilt_packets(p, callback, userdata);
-}
-
-int Stream::traverse_stream_segments(
- Packet* p, StreamSegmentIterator callback, void* userdata)
-{
- Flow* flow = p->flow;
- assert(flow && flow->session);
- return flow->session->get_segments(p, callback, userdata);
-}
-
char Stream::get_reassembly_direction(Flow* flow)
{
assert(flow && flow->session);
static void flush_request(Packet*); // flush listener
static void flush_response(Packet*); // flush talker
- /* Calls user-provided callback function for each packet of
- * a reassembled stream. If the callback function returns non-zero,
- * iteration ends.
- *
- * Returns number of packets
- */
- static int traverse_reassembled(Packet*, PacketIterator, void* userdata); // PKT
-
- /* Calls user-provided callback function for each segment of
- * a reassembled stream. If the callback function returns non-zero,
- * iteration ends.
- *
- * Returns number of packets
- */
- static int traverse_stream_segments(Packet*, StreamSegmentIterator, void* userdata); // PKT
-
/* Add session alert - true if added
*/
static bool add_session_alert(Flow*, Packet*, uint32_t gid, uint32_t sid);
}
/* P R O T O T Y P E S ********************************************/
-static void StreamPrintTcpConfig(StreamTcpConfig*);
-static inline void SetupTcpDataBlock(TcpDataBlock*, Packet*);
-static int ProcessTcp(Flow*, Packet*, TcpDataBlock*,
- StreamTcpConfig*);
+static int ProcessTcp(Flow*, Packet*, TcpDataBlock*, StreamTcpConfig*);
+
static inline int CheckFlushPolicyOnData(
TcpSession *, TcpTracker *, TcpTracker *, Packet *);
+
static inline int CheckFlushPolicyOnAck(
TcpSession *, TcpTracker *, TcpTracker *, Packet *);
-static void StreamSeglistAddNode(TcpTracker *, TcpSegment *,
- TcpSegment *);
+
+static void StreamSeglistAddNode(TcpTracker *, TcpSegment *, TcpSegment *);
static int StreamSeglistDeleteNode(TcpTracker*, TcpSegment*);
static int StreamSeglistDeleteNodeTrim(TcpTracker*, TcpSegment*, uint32_t flush_seq);
-static int AddStreamNode(
- TcpTracker*, Packet*, TcpDataBlock*,
- int16_t len, uint32_t slide, uint32_t trunc,
- uint32_t seq, TcpSegment *left, TcpSegment **retSeg);
+
static int DupStreamNode(
- Packet*,
- TcpTracker*,
- TcpSegment* left,
- TcpSegment** retSeg);
-
-static uint32_t StreamGetWscale(Packet*, uint16_t*);
-static uint32_t StreamPacketHasWscale(Packet*);
-static uint32_t StreamGetMss(Packet*, uint16_t*);
-static uint32_t StreamGetTcpTimestamp(Packet*, uint32_t*, int strip);
+ Packet*, TcpTracker*, TcpSegment* left, TcpSegment** retSeg);
-int s5TcpStreamSizeInit(SnortConfig* sc, char* name, char* parameters, void** dataPtr);
-int s5TcpStreamSizeEval(Packet*, const uint8_t** cursor, void* dataPtr);
-void s5TcpStreamSizeCleanup(void* dataPtr);
-int s5TcpStreamReassembleRuleOptionInit(
- SnortConfig* sc, char* name, char* parameters, void** dataPtr);
-int s5TcpStreamReassembleRuleOptionEval(Packet*, const uint8_t** cursor, void* dataPtr);
-void s5TcpStreamReassembleRuleOptionCleanup(void* dataPtr);
+static uint32_t StreamGetTcpTimestamp(Packet*, uint32_t*, int strip);
/* G L O B A L S **************************************************/
#endif
static THREAD_LOCAL Packet* s5_pkt = nullptr;
-static THREAD_LOCAL Packet* cleanup_pkt = nullptr;
-/* F U N C T I O N S **********************************************/
+//-------------------------------------------------------------------------
+// TcpSegment stuff
+//-------------------------------------------------------------------------
+
+TcpSegment* TcpSegment::init(
+ Packet* p, const struct timeval& tv, const uint8_t* data, unsigned dsize)
+{
+ TcpSegment* ss;
+ unsigned size = sizeof(*ss);
+
+ if ( dsize > 0 )
+ size += dsize - 1; // ss contains 1st byte
+
+ tcp_memcap->alloc(size);
+
+ if ( tcp_memcap->at_max() )
+ {
+ sfBase.iStreamFaults++;
+
+ // FIXIT eliminate the packet dependency?
+ if ( p )
+ flow_con->prune_flows(PktType::TCP, p);
+ }
+
+ ss = (TcpSegment*)malloc(size);
+
+ if ( !ss )
+ return nullptr;
+
+ ss->tv = tv;
+ memcpy(ss->data, data, dsize);
+ ss->orig_dsize = dsize;
+
+ ss->payload = ss->data;
+ ss->prev = ss->next = nullptr;
+ ss->ts = ss->seq = 0;
+ ss->size = ss->orig_dsize;
+ ss->urg_offset = 0;
+ ss->buffered = 0;
+
+ return ss;
+}
+
+void TcpSegment::term(TcpSegment* seg)
+{
+ unsigned dropped = sizeof(TcpSegment);
+
+ if ( seg->size > 0 )
+ dropped += seg->size - 1; // seg contains 1st byte
+
+ tcp_memcap->dealloc(dropped);
+ free(seg);
+ tcpStats.segs_released++;
+}
+
+bool TcpSegment::is_retransmit(const uint8_t* rdata, uint16_t rsize, uint32_t rseq)
+{
+ // retransmit must have same payload at same place
+ if ( !SEQ_EQ(seq, rseq) )
+ return false;
+
+ if ( ((size <= rsize) and !memcmp(data, rdata, size)) or
+ ((size > rsize) and !memcmp(data, rdata, rsize)) )
+ return true;
+
+ return false;
+}
+
+//-------------------------------------------------------------------------
+// flush policy stuff
+//-------------------------------------------------------------------------
+
static inline void init_flush_policy(Flow*, TcpTracker* trk)
{
if ( !trk->splitter )
}
//-------------------------------------------------------------------------
-// FIXIT-L directionality must be fixed per 297 bug fixes
-//
// when client ports are configured, that means c2s and is stored on the
// client side; when the session starts, the server policy is obtained from
// the client side because segments are stored on the receiving side.
//
-// this could be improved further beyond the 297 bug fixes by storing the
-// c2s policy on the server side and then obtaining server policy from the
-// server on session startup.
+// this could be improved further by storing the c2s policy on the server
+// side and then obtaining server policy from the server on session
+// startup.
//
// either way, this client / server distinction must be kept in mind to
// make sense of the code in this file.
void tcp_sinit()
{
s5_pkt = PacketManager::encode_new();
- cleanup_pkt = PacketManager::encode_new();
tcp_memcap = new Memcap(26214400); // FIXIT-M replace with session memcap
//AtomSplitter::init(); // FIXIT-L PAF implement
}
s5_pkt = nullptr;
}
- if (cleanup_pkt)
- {
- PacketManager::encode_delete(cleanup_pkt);
- cleanup_pkt = nullptr;
- }
delete tcp_memcap;
tcp_memcap = nullptr;
}
#endif
}
-static void SegmentFree (TcpSegment *seg)
-{
- unsigned dropped = sizeof(TcpSegment);
-
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Dumping segment at seq %X, size %d, caplen %d\n",
- seg->seq, seg->size, seg->caplen); );
-
- if ( seg->caplen > 0 )
- dropped += seg->caplen - 1; // seg contains 1st byte
-
- tcp_memcap->dealloc(dropped);
- free(seg);
- tcpStats.segs_released++;
-
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "SegmentFree dropped %d bytes\n", dropped); );
-}
-
static void DeleteSeglist(TcpSegment *listhead)
{
TcpSegment *idx = listhead;
i++;
dump_me = idx;
idx = idx->next;
- SegmentFree(dump_me);
+ TcpSegment::term(dump_me);
}
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
}
static inline int purge_alerts(
- TcpTracker *st, uint32_t flush_seq, Flow* flow)
+ TcpTracker *st, uint32_t /*flush_seq*/, Flow* flow)
{
int i;
int new_count = 0;
{
StreamAlertInfo* ai = st->alerts + i;
- if (SEQ_LT(ai->seq, flush_seq) )
+ //if (SEQ_LT(ai->seq, flush_seq) )
{
stream.log_extra_data(
flow, st->xtradata_mask, ai->event_id, ai->event_second);
memset(ai, 0, sizeof(*ai));
}
+#if 0
else
{
if (new_count != i)
}
new_count++;
}
+#endif
}
st->alert_count = new_count;
return 0;
}
+#define SEPARATOR \
+ "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
+
static void ShowRebuiltPacket(TcpSession* ssn, Packet* pkt)
{
if ( (ssn->client.config->flags & STREAM_CONFIG_SHOW_PACKETS) ||
(ssn->server.config->flags & STREAM_CONFIG_SHOW_PACKETS) )
{
-#ifdef REG_TEST
- printf("+++++++++++++++++++Stream Packet+++++++++++++++++++++\n");
-#endif
- LogIPPkt(pkt);
-#ifdef REG_TEST
- printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
-#endif
+ LogFlow(pkt);
+ LogNetData(pkt->data, pkt->dsize, pkt);
}
}
{
s5_pkt->data = sb->data;
s5_pkt->dsize = sb->length;
- assert(sb->length < 65536); // FIXIT-M should be < s5_pkt->max_dsize);
+ assert(sb->length <= s5_pkt->max_dsize);
// FIXIT-M flushbuf should be eliminated from this function
// since we are actually using the stream splitter buffer
ss->size = bytes_to_copy;
sr->seq += bytes_to_copy;
sr->size -= bytes_to_copy;
- sr->payload += bytes_to_copy + (ss->payload - ss->data);
+ sr->payload += bytes_to_copy;
}
ss->buffered = SL_BUF_FLUSHED;
st->flush_count++;
return bytes_flushed;
}
+// FIXIT-L consolidate encode format, update, and this into new function?
+static void prep_s5_pkt(Flow* flow, Packet* p, uint32_t pkt_flags)
+{
+ s5_pkt->ptrs.set_pkt_type(PktType::USER);
+ s5_pkt->proto_bits |= PROTO_BIT__TCP;
+ s5_pkt->packet_flags |= (pkt_flags & PKT_PDU_FULL);
+ s5_pkt->flow = flow;
+
+ if ( p == s5_pkt )
+ {
+ // final
+ if ( pkt_flags & PKT_FROM_SERVER )
+ {
+ s5_pkt->packet_flags |= PKT_FROM_SERVER;
+ s5_pkt->ptrs.ip_api.set(flow->server_ip, flow->client_ip);
+ s5_pkt->ptrs.sp = flow->server_port;
+ s5_pkt->ptrs.dp = flow->client_port;
+ }
+ else
+ {
+ s5_pkt->packet_flags |= PKT_FROM_CLIENT;
+ s5_pkt->ptrs.ip_api.set(flow->client_ip, flow->server_ip);
+ s5_pkt->ptrs.sp = flow->client_port;
+ s5_pkt->ptrs.dp = flow->server_port;
+ }
+ }
+ else if ( !p->packet_flags || (pkt_flags & p->packet_flags) )
+ {
+ // forward
+ s5_pkt->packet_flags |= (p->packet_flags & (PKT_FROM_CLIENT|PKT_FROM_SERVER));
+ s5_pkt->ptrs.ip_api.set(*p->ptrs.ip_api.get_src(), *p->ptrs.ip_api.get_dst());
+ s5_pkt->ptrs.sp = p->ptrs.sp;
+ s5_pkt->ptrs.dp = p->ptrs.dp;
+ }
+ else
+ {
+ // reverse
+ if ( p->packet_flags & PKT_FROM_CLIENT )
+ s5_pkt->packet_flags |= PKT_FROM_SERVER;
+ else
+ s5_pkt->packet_flags |= PKT_FROM_CLIENT;
+
+ s5_pkt->ptrs.ip_api.set(*p->ptrs.ip_api.get_dst(), *p->ptrs.ip_api.get_src());
+ s5_pkt->ptrs.dp = p->ptrs.sp;
+ s5_pkt->ptrs.sp = p->ptrs.dp;
+ }
+}
+
static inline int _flush_to_seq(
- TcpSession *tcpssn, TcpTracker *st, uint32_t bytes, Packet *p, uint32_t dir)
+ TcpSession *tcpssn, TcpTracker *st, uint32_t bytes, Packet *p, uint32_t pkt_flags)
{
uint32_t stop_seq;
uint32_t footprint;
uint32_t bytes_processed = 0;
int32_t flushed_bytes;
-#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
- DAQ_PktHdr_t pkth;
-#endif
EncodeFlags enc_flags = 0;
PROFILE_VARS;
MODULE_PROFILE_START(s5TcpFlushPerfStats);
- if ( !p->packet_flags || (dir & p->packet_flags) )
- enc_flags = ENC_FLAG_FWD;
-
#ifdef HAVE_DAQ_ADDRESS_SPACE_ID
- GetPacketHeaderFoo(tcpssn, &pkth, dir);
- PacketManager::encode_format_with_daq_info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, 0);
-#elif defined(HAVE_DAQ_ACQUIRE_WITH_META)
- PacketManager::encode_format_with_daq_info(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, 0);
+ DAQ_PktHdr_t pkth;
+ GetPacketHeaderFoo(tcpssn, &pkth, pkt_flags);
+ PacketManager::format_tcp(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP, &pkth, pkth.opaque);
#else
- PacketManager::encode_format(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP);
+ PacketManager::format_tcp(enc_flags, p, s5_pkt, PSEUDO_PKT_TCP);
#endif
- // TBD in ips mode, these should be coming from current packet (tdb)
- ((TCPHdr*)s5_pkt->ptrs.tcph)->th_ack = htonl(st->l_unackd);
- ((TCPHdr*)s5_pkt->ptrs.tcph)->th_win = htons((uint16_t)st->l_window);
+ prep_s5_pkt(tcpssn->flow, p, pkt_flags);
// if not specified, set bytes to flush to what was acked
if ( !bytes && SEQ_GT(st->r_win_base, st->seglist_base_seq) )
((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_sec = st->seglist_next->tv.tv_sec;
((DAQ_PktHdr_t*)s5_pkt->pkth)->ts.tv_usec = st->seglist_next->tv.tv_usec;
- ((TCPHdr*)s5_pkt->ptrs.tcph)->th_seq = htonl(st->seglist_next->seq);
/* setup the pseudopacket payload */
s5_pkt->dsize = 0;
if ((p->packet_flags & PKT_PDU_TAIL))
s5_pkt->packet_flags |= PKT_PDU_TAIL;
- PacketManager::encode_update(s5_pkt);
-
sfBase.iStreamFlushes++;
bytes_processed += flushed_bytes;
- s5_pkt->packet_flags |= dir;
- s5_pkt->flow = tcpssn->flow;
s5_pkt->application_protocol_ordinal = p->application_protocol_ordinal;
ShowRebuiltPacket(tcpssn, s5_pkt);
st->flags &= ~TF_MISSING_PREV_PKT;
}
}
- while ( DataToFlush(st) );
+ while ( st->seglist_next and DataToFlush(st) );
/* tell them how many bytes we processed */
MODULE_PROFILE_END(s5TcpFlushPerfStats);
* and fire it thru the system.
*/
static inline int flush_to_seq(
- TcpSession *tcpssn, TcpTracker *st, uint32_t bytes, Packet *p, uint32_t dir)
+ TcpSession *tcpssn, TcpTracker *st, uint32_t bytes, Packet *p, uint32_t pkt_flags)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
"In flush_to_seq()\n"); );
}
st->flags &= ~TF_FIRST_PKT_MISSING;
- return _flush_to_seq(tcpssn, st, bytes, p, dir);
+ return _flush_to_seq(tcpssn, st, bytes, p, pkt_flags);
}
/*
return ( len > 0 ) ? len : 0;
}
-static inline int flush_ackd(
- TcpSession *tcpssn, TcpTracker *st, Packet *p, uint32_t dir)
-{
- uint32_t bytes = get_q_footprint(st);
- return flush_to_seq(tcpssn, st, bytes, p, dir);
-}
-
// FIXIT-L flush_stream() calls should be replaced with calls to
// CheckFlushPolicyOn*() with the exception that for the *OnAck() case,
// any available ackd data must be flushed in both directions.
if ( !st->flush_policy )
return 0;
+ uint32_t bytes;
+
if ( Normalize_IsEnabled(NORM_TCP_IPS) )
- {
- uint32_t bytes = get_q_sequenced(st);
- return flush_to_seq(tcpssn, st, bytes, p, dir);
- }
+ bytes = get_q_sequenced(st);
+ else
+ bytes = get_q_footprint(st);
- return flush_ackd(tcpssn, st, p, dir);
+ return flush_to_seq(tcpssn, st, bytes, p, dir);
}
static void TcpSessionClear (Flow* lwssn, TcpSession* tcpssn, int freeApplicationData)
}
static void final_flush(
- Flow* lwssn, TcpSession* tcpssn, TcpTracker& trk, Packet* p,
- PegCount& peg, uint32_t flag)
+ TcpSession* tcpssn, TcpTracker& trk, Packet* p,
+ PegCount& peg, uint32_t dir)
{
if ( !p )
{
- DAQ_PktHdr_t* const tmp_pcap_hdr = const_cast<DAQ_PktHdr_t*>(cleanup_pkt->pkth);
+ p = s5_pkt;
+
+ DAQ_PktHdr_t* const tmp_pcap_hdr = const_cast<DAQ_PktHdr_t*>(p->pkth);
peg++;
/* Do each field individually because of size differences on 64bit OS */
tmp_pcap_hdr->ts.tv_sec = trk.seglist->tv.tv_sec;
tmp_pcap_hdr->ts.tv_usec = trk.seglist->tv.tv_usec;
- tmp_pcap_hdr->caplen = trk.seglist->caplen;
- tmp_pcap_hdr->pktlen = trk.seglist->pktlen;
-
- Snort::decode_rebuilt_packet(cleanup_pkt, tmp_pcap_hdr, trk.seglist->pkt, lwssn);
- p = cleanup_pkt;
}
- if ( p->ptrs.tcph )
- {
- trk.flags |= TF_FORCE_FLUSH;
+ trk.flags |= TF_FORCE_FLUSH;
- if ( flush_stream(tcpssn, &trk, p, flag) )
- purge_flushed_ackd(tcpssn, &trk);
+ if ( flush_stream(tcpssn, &trk, p, dir) )
+ purge_flushed_ackd(tcpssn, &trk);
- trk.flags &= ~TF_FORCE_FLUSH;
- }
+ trk.flags &= ~TF_FORCE_FLUSH;
}
// flush data on both sides as necessary
if ( (pending and (p or tcpssn->client.seglist) and
!(lwssn->ssn_state.ignore_direction & SSN_DIR_FROM_SERVER)) )
{
- final_flush(lwssn, tcpssn, tcpssn->client, p, tcpStats.s5tcp1, PKT_FROM_SERVER);
+ final_flush(tcpssn, tcpssn->client, p, tcpStats.s5tcp1, PKT_FROM_SERVER);
}
// flush the server (data from client)
if ( (pending and (p or tcpssn->server.seglist) and
!(lwssn->ssn_state.ignore_direction & SSN_DIR_FROM_CLIENT)) )
{
- final_flush(lwssn, tcpssn, tcpssn->server, p, tcpStats.s5tcp2, PKT_FROM_CLIENT);
+ final_flush(tcpssn, tcpssn->server, p, tcpStats.s5tcp2, PKT_FROM_CLIENT);
}
}
#endif
-#ifdef REG_TEST
+#ifndef REG_TEST
+#define S5TraceTCP(pkt, flow, tdb, evt)
+#else
#define LCL(p, x) (p->x - p->isn)
#define RMT(p, x, q) (p->x - (q ? q->isn : 0))
}
TraceTCP(p, lws, tdb, event);
}
-
-#else
-#define S5TraceTCP(pkt, flow, tdb, evt)
-#endif // REG_TEST
+#endif
static uint32_t StreamGetTcpTimestamp(Packet* p, uint32_t* ts, int strip)
{
#endif
}
-static void NewQueue(
- TcpTracker *st, Packet *p, TcpDataBlock *tdb)
-{
- TcpSegment *ss = NULL;
- uint32_t overlap = 0;
- PROFILE_VARS;
-
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "In NewQueue\n"); );
-
- MODULE_PROFILE_START(s5TcpInsertPerfStats);
-
- if (st->flush_policy != STREAM_FLPOLICY_IGNORE)
- {
- uint32_t seq = tdb->seq;
-
- if ( p->ptrs.tcph->th_flags & TH_SYN )
- seq++;
-
- /* new packet seq is below the last ack... */
- if ( SEQ_GT(st->r_win_base, seq) )
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "segment overlaps ack'd data...\n"); );
- overlap = st->r_win_base - tdb->seq;
- if (overlap >= p->dsize)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "full overlap on ack'd data, dropping segment\n"); );
- MODULE_PROFILE_END(s5TcpInsertPerfStats);
- return;
- }
- }
-
- AddStreamNode(st, p, tdb, p->dsize, overlap, 0, tdb->seq+overlap, NULL, &ss);
-
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Attached new queue to seglist, %d bytes queued, "
- "base_seq 0x%X\n",
- ss->size, st->seglist_base_seq); );
- }
-
- MODULE_PROFILE_END(s5TcpInsertPerfStats);
-}
-
static inline int SegmentFastTrack(TcpSegment *tail, TcpDataBlock *tdb)
{
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
return 0;
}
-static inline TcpSegment* SegmentAlloc(
- Packet* p, const struct timeval* tv, uint32_t caplen, uint32_t pktlen, const uint8_t* pkt)
-{
- TcpSegment* ss;
- unsigned size = sizeof(*ss);
-
- if ( caplen > 0 )
- size += caplen - 1; // ss contains 1st byte
-
- tcp_memcap->alloc(size);
-
- if ( tcp_memcap->at_max() )
- {
- sfBase.iStreamFaults++;
-
- if ( !p )
- {
- tcp_memcap->dealloc(size);
- return NULL;
- }
- flow_con->prune_flows(PktType::TCP, p);
- }
-
- ss = (TcpSegment*)SnortAlloc(size);
-
- ss->tv.tv_sec = tv->tv_sec;
- ss->tv.tv_usec = tv->tv_usec;
- ss->caplen = caplen;
- ss->pktlen = pktlen;
-
- memcpy(ss->pkt, pkt, caplen);
-
- return ss;
-}
-
static int AddStreamNode(
TcpTracker *st, Packet *p,
TcpDataBlock* tdb,
uint32_t slide,
uint32_t trunc,
uint32_t seq,
- TcpSegment *left,
- TcpSegment **retSeg)
+ TcpSegment *left)
{
TcpSegment *ss = NULL;
int32_t newSize = len - slide - trunc;
return STREAM_INSERT_ANOMALY;
}
- ss = SegmentAlloc(p, &p->pkth->ts, p->pkth->caplen, p->pkth->pktlen, p->pkt);
+ // FIXIT-L don't allocate overlapped part
+ ss = TcpSegment::init(p, p->pkth->ts, p->data, p->dsize);
- ss->data = ss->pkt + (p->data - p->pkt);
- ss->orig_dsize = p->dsize;
+ if ( !ss )
+ return STREAM_INSERT_FAILED;
ss->payload = ss->data + slide;
ss->size = (uint16_t)newSize;
StreamSeglistAddNode(st, left, ss);
st->seg_bytes_logical += ss->size;
- st->seg_bytes_total += ss->caplen; /* Includes protocol headers and payload */
- st->total_segs_queued++;
st->total_bytes_queued += ss->size;
p->packet_flags |= PKT_STREAM_INSERT;
"%d segments queued\n", ss->size, ss->seq,
st->seg_bytes_logical, SegsToFlush(st, 0)); );
- *retSeg = ss;
#ifdef SEG_TEST
CheckSegments(st);
#endif
static int DupStreamNode(
Packet *p, TcpTracker *st, TcpSegment *left, TcpSegment **retSeg)
{
- TcpSegment* ss = SegmentAlloc(p, &left->tv, left->caplen, left->pktlen, left->pkt);
+ TcpSegment* ss = TcpSegment::init(p, left->tv, left->payload, left->size);
if ( !ss )
return STREAM_INSERT_FAILED;
tcpStats.segs_split++;
- ss->data = ss->pkt + (left->data - left->pkt);
- ss->orig_dsize = left->orig_dsize;
/* twiddle the values for overlaps */
ss->payload = ss->data;
ss->seq = left->seq;
StreamSeglistAddNode(st, left, ss);
- st->seg_bytes_total += ss->caplen;
- st->total_segs_queued++;
//st->total_bytes_queued += ss->size;
STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
return STREAM_INSERT_OK;
}
-static inline bool IsRetransmit(
- TcpSegment *seg, const uint8_t *rdata, uint16_t rsize, uint32_t rseq)
-{
- // If seg->orig_size == seg->size, then it's sequence number wasn't adjusted
- // so can just do a straight compare of the sequence numbers.
- // Don't want to count as a retransmit if segment's size/sequence number
- // has been adjusted.
- if (SEQ_EQ(seg->seq, rseq) && (seg->orig_dsize == seg->size))
- {
- if (((seg->size <= rsize) && (memcmp(seg->data, rdata, seg->size) == 0))
- || ((seg->size > rsize) && (memcmp(seg->data, rdata, rsize) == 0)))
- return true;
- }
-
- return false;
-}
-
static inline void RetransmitProcess(Packet* p, TcpSession*)
{
// Data has already been analyzed so don't bother looking at it again.
return Normalize_GetMode(NORM_TCP_IPS);
}
+static void NewQueue(
+ TcpTracker *st, Packet *p, TcpDataBlock *tdb)
+{
+ PROFILE_VARS;
+ MODULE_PROFILE_START(s5TcpInsertPerfStats);
+
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE, "In NewQueue\n"); );
+
+ uint32_t overlap = 0;
+ uint32_t seq = tdb->seq;
+
+ if ( p->ptrs.tcph->th_flags & TH_SYN )
+ seq++;
+
+ /* new packet seq is below the last ack... */
+ if ( SEQ_GT(st->r_win_base, seq) )
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "segment overlaps ack'd data...\n"); );
+ overlap = st->r_win_base - tdb->seq;
+
+ if (overlap >= p->dsize)
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "full overlap on ack'd data, dropping segment\n"); );
+ MODULE_PROFILE_END(s5TcpInsertPerfStats);
+ return;
+ }
+ }
+
+ // BLOCK add new block to seglist containing data
+ AddStreamNode(st, p, tdb, p->dsize, overlap, 0, tdb->seq+overlap, NULL);
+
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "Attached new queue to seglist, %d bytes queued, "
+ "base_seq 0x%X\n",
+ p->dsize-overlap, st->seglist_base_seq); );
+
+ MODULE_PROFILE_END(s5TcpInsertPerfStats);
+}
+
static int StreamQueue(TcpTracker *st, Packet *p, TcpDataBlock *tdb,
TcpSession *tcpssn)
{
- TcpSegment *ss = NULL;
TcpSegment *left = NULL;
TcpSegment *right = NULL;
TcpSegment *dump_me = NULL;
"Fast tracking segment! (tail_seq %X size %d)\n",
st->seglist_tail->seq, st->seglist_tail->size); );
+ // BLOCK add to existing block and/or allocate new block
ret = AddStreamNode(st, p, tdb, len,
- slide /* 0 */, trunc /* 0 */, seq, left /* tail */,
- &ss);
+ slide /* 0 */, trunc /* 0 */, seq, left /* tail */);
MODULE_PROFILE_END(s5TcpInsertPerfStats);
return ret;
if (SEQ_LEQ(dist_head, dist_tail))
{
+ TcpSegment* ss;
+
/* Start iterating at the head (left) */
for (ss = st->seglist; ss; ss = ss->next)
{
}
else
{
+ TcpSegment* ss;
+
/* Start iterating at the tail (right) */
for (ss = st->seglist_tail; ss; ss = ss->prev)
{
ret = DupStreamNode(p, st, left, &right);
if (ret != STREAM_INSERT_OK)
{
- /* No warning,
- * its done in StreamSeglistAddNode */
+ /* No warning, its done in StreamSeglistAddNode */
MODULE_PROFILE_END(s5TcpInsertPerfStats);
return ret;
}
st->seg_bytes_logical -= overlap;
right->seq = seq + len;
- right->size -= (int16_t)(seq + len - left->seq);
- right->payload += (seq + len - left->seq);
- st->seg_bytes_logical -= (seq + len - left->seq);
+ uint16_t delta = (int16_t)(right->seq - left->seq);
+ right->size -= delta;
+ right->payload += delta;
+ st->seg_bytes_logical -= delta;
}
else
{
if (overlap < right->size)
{
- if (IsRetransmit(right, rdata, rsize, rseq))
+ if ( right->is_retransmit(rdata, rsize, rseq) )
{
// All data was retransmitted
RetransmitProcess(p, tcpssn);
// Don't want to count retransmits as overlaps or do anything
// else with them. Account for retransmits of multiple PDUs
// in one segment.
- if (IsRetransmit(right, rdata, rsize, rseq))
+ if ( right->is_retransmit(rdata, rsize, rseq) )
{
rdata += right->size;
rsize -= right->size;
/* insert this one, and see if we need to chunk it up
Adjust slide so that is correct relative to orig seq */
slide = seq - tdb->seq;
- ret = AddStreamNode(st, p, tdb, len, slide, trunc, seq, left, &ss);
+ ret = AddStreamNode(st, p, tdb, len, slide, trunc, seq, left);
if (ret != STREAM_INSERT_OK)
{
/* no warning, already done above */
/* Adjust slide so that is correct relative to orig seq */
slide = seq - tdb->seq;
ret = AddStreamNode(
- st, p, tdb, len, slide, trunc, seq, left, &ss);
+ st, p, tdb, len, slide, trunc, seq, left);
}
else
{
SetPacketHeaderFoo(tcpssn, p);
#endif
+ if (rcv->flush_policy == STREAM_FLPOLICY_IGNORE)
+ {
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "Ignoring segment due to IGNORE flush_policy\n"); );
+ return;
+ }
+
if ((config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY) &&
!tcpssn->flow->two_way_traffic())
{
return;
}
- if (rcv->seg_count != 0)
- {
- if (rcv->flush_policy == STREAM_FLPOLICY_IGNORE)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Ignoring segment due to IGNORE flush_policy\n"); );
- return;
- }
- else
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "queuing segment\n"); );
-
- if ( SEQ_GT(rcv->r_win_base, tdb->seq) )
- {
- uint32_t offset = rcv->r_win_base - tdb->seq;
+ STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
+ "queuing segment\n"); );
- if ( offset < p->dsize )
- {
- tdb->seq += offset;
- p->data += offset;
- p->dsize -= (uint16_t)offset;
+ if ( !rcv->seg_count )
+ {
+ NewQueue(rcv, p, tdb);
+ return;
+ }
+ if ( SEQ_GT(rcv->r_win_base, tdb->seq) )
+ {
+ uint32_t offset = rcv->r_win_base - tdb->seq;
- StreamQueue(rcv, p, tdb, tcpssn);
+ if ( offset < p->dsize )
+ {
+ tdb->seq += offset;
+ p->data += offset;
+ p->dsize -= (uint16_t)offset;
- p->dsize += (uint16_t)offset;
- p->data -= offset;
- tdb->seq -= offset;
- }
- }
- else
- StreamQueue(rcv, p, tdb, tcpssn);
+ StreamQueue(rcv, p, tdb, tcpssn);
- if ((rcv->config->overlap_limit) &&
- (rcv->overlap_count > rcv->config->overlap_limit))
- {
- /* Alert on overlap limit and reset counter */
- EventExcessiveOverlap();
- rcv->overlap_count = 0;
- }
+ p->dsize += (uint16_t)offset;
+ p->data -= offset;
+ tdb->seq -= offset;
}
}
else
+ StreamQueue(rcv, p, tdb, tcpssn);
+
+ if ((rcv->config->overlap_limit) &&
+ (rcv->overlap_count > rcv->config->overlap_limit))
{
- if (rcv->flush_policy == STREAM_FLPOLICY_IGNORE)
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "Ignoring segment due to IGNORE flush_policy\n"); );
- return;
- }
- else
- {
- STREAM_DEBUG_WRAP(DebugMessage(DEBUG_STREAM_STATE,
- "queuing segment\n"); );
- NewQueue(rcv, p, tdb);
- }
+ /* Alert on overlap limit and reset counter */
+ EventExcessiveOverlap();
+ rcv->overlap_count = 0;
}
}
static void StreamSeglistAddNode(
TcpTracker *st, TcpSegment *prev, TcpSegment *ss)
{
- tcpStats.segs_queued++;
-
if (prev)
{
ss->next = prev->next;
st->seglist = ss;
}
st->seg_count++;
+ st->seg_bytes_total += ss->orig_dsize;
+ st->total_segs_queued++;
+ tcpStats.segs_queued++;
}
static int StreamSeglistDeleteNode (TcpTracker* st, TcpSegment* seg)
st->seglist_tail = seg->prev;
st->seg_bytes_logical -= seg->size;
- st->seg_bytes_total -= seg->caplen;
+ st->seg_bytes_total -= seg->orig_dsize;
- ret = seg->caplen;
+ ret = seg->orig_dsize;
if (seg->buffered)
{
if ( st->seglist_next == seg )
st->seglist_next = NULL;
- SegmentFree(seg);
+ TcpSegment::term(seg);
st->seg_count--;
return ret;
void TcpSession::flush_listener(Packet* p)
{
TcpTracker *listener = NULL;
- int dir = 0;
+ uint32_t dir = 0;
int flushed = 0;
/* figure out direction of this packet -- we should've already
void TcpSession::flush_talker(Packet* p)
{
TcpTracker *talker = NULL;
- int dir = 0;
+ uint32_t dir = 0;
int flushed = 0;
/* figure out direction of this packet -- we should've already
}
}
-/* Iterates through the packets that were reassembled for
- * logging of tagged packets.
- */
-int TcpSession::get_rebuilt_packets(
- Packet* p, PacketIterator callback, void *userdata)
+// FIXIT add alert and check alerted go away when we finish
+// packet / PDU split because PDU rules won't run on raw packets
+bool TcpSession::add_alert(Packet* p, uint32_t gid, uint32_t sid)
{
- int packets = 0;
TcpTracker *st;
- TcpSegment *ss;
- uint32_t start_seq = ntohl(p->ptrs.tcph->th_seq);
- uint32_t end_seq = start_seq + p->dsize;
+ StreamAlertInfo* ai;
- /* TcpTracker is the opposite of the ip of the reassembled
- * packet --> it came out the queue for the other side */
- if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
+ if (sfip_equals(p->ptrs.ip_api.get_src(),&flow->client_ip))
st = &server;
else
st = &client;
- // skip over segments not covered by this reassembled packet
- for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next);
+ if (st->alert_count >= MAX_SESSION_ALERTS)
+ return false;
+
+ ai = st->alerts + st->alert_count;
+ ai->gid = gid;
+ ai->sid = sid;
+ ai->seq = 0;
- // return flushed segments only
- for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next)
- {
- if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
- {
- DAQ_PktHdr_t pkth;
- pkth.ts.tv_sec = ss->tv.tv_sec;
- pkth.ts.tv_usec = ss->tv.tv_usec;
- pkth.caplen = ss->caplen;
- pkth.pktlen = ss->pktlen;
-
- callback(&pkth, ss->pkt, userdata);
- packets++;
- }
- else
- break;
- }
+ st->alert_count++;
- return packets;
+ return true;
}
-/* Iterates through the packets that were reassembled for
- * logging of tagged packets.
- */
-int TcpSession::get_segments(
- Packet* p, StreamSegmentIterator callback, void *userdata)
+bool TcpSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid)
{
- int packets = 0;
+ /* If this is not a rebuilt packet, no need to check further */
+ if ( !(p->packet_flags & PKT_REBUILT_STREAM) )
+ return false;
+
TcpTracker *st;
- TcpSegment *ss;
- uint32_t start_seq = ntohl(p->ptrs.tcph->th_seq);
- uint32_t end_seq = start_seq + p->dsize;
- /* TcpTracker is the opposite of the ip of the reassembled
- * packet --> it came out the queue for the other side */
if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
st = &server;
else
st = &client;
- // skip over segments not covered by this reassembled packet
- for (ss = st->seglist; ss && SEQ_LT(ss->seq, start_seq); ss = ss->next);
-
- // return flushed segments only
- for (; ss && ss->buffered == SL_BUF_FLUSHED; ss = ss->next)
+ for ( int i = 0; i < st->alert_count; i++ )
{
- if (SEQ_GEQ(ss->seq,start_seq) && SEQ_LT(ss->seq, end_seq))
+ /* This is a rebuilt packet and if we've seen this alert before,
+ * return that we have previously alerted on original packet.
+ */
+ if ( st->alerts[i].gid == gid &&
+ st->alerts[i].sid == sid )
{
- DAQ_PktHdr_t pkth;
- pkth.ts.tv_sec = ss->tv.tv_sec;
- pkth.ts.tv_usec = ss->tv.tv_usec;
- pkth.caplen = ss->caplen;
- pkth.pktlen = ss->pktlen;
-
- if (callback(&pkth, ss->pkt, ss->data, ss->seq, userdata) != 0)
- return -1;
-
- packets++;
+ return true;
}
- else
- break;
}
- return packets;
+ return false;
}
int TcpSession::update_alert(
else
st = &client;
- seq_num = GET_PKT_SEQ(p);
-
- if ( p->ptrs.tcph->th_flags & TH_FIN )
- seq_num--;
+ seq_num = 0;
for (i=0; i<st->alert_count; i++)
{
return 0;
}
-bool TcpSession::add_alert(Packet* p, uint32_t gid, uint32_t sid)
-{
- TcpTracker *st;
- StreamAlertInfo* ai;
-
- if (sfip_equals(p->ptrs.ip_api.get_src(),&flow->client_ip))
- st = &server;
- else
- st = &client;
-
- if (st->alert_count >= MAX_SESSION_ALERTS)
- return false;
-
- ai = st->alerts + st->alert_count;
- ai->gid = gid;
- ai->sid = sid;
- ai->seq = GET_PKT_SEQ(p);
-
- if ( p->ptrs.tcph->th_flags & TH_FIN )
- ai->seq--;
-
- st->alert_count++;
-
- return true;
-}
-
-bool TcpSession::check_alerted(Packet* p, uint32_t gid, uint32_t sid)
-{
- /* If this is not a rebuilt packet, no need to check further */
- if ( !(p->packet_flags & PKT_REBUILT_STREAM) )
- return false;
-
- TcpTracker *st;
-
- if (sfip_equals(p->ptrs.ip_api.get_src(), &flow->client_ip))
- st = &server;
- else
- st = &client;
-
- for ( int i = 0; i < st->alert_count; i++ )
- {
- /* This is a rebuilt packet and if we've seen this alert before,
- * return that we have previously alerted on original packet.
- */
- if ( st->alerts[i].gid == gid &&
- st->alerts[i].sid == sid )
- {
- return true;
- }
- }
-
- return false;
-}
-
void TcpSession::flush()
{
if ( (SegsToFlush(&server, 1) > 0) || (SegsToFlush(&client, 1) > 0) )
struct TcpSegment
{
- uint8_t* data;
+ static TcpSegment* init(struct Packet*, const struct timeval&, const uint8_t*, unsigned);
+ static void term(TcpSegment*);
+ bool is_retransmit(const uint8_t*, uint16_t size, uint32_t);
+
uint8_t* payload;
TcpSegment *prev;
TcpSegment *next;
struct timeval tv;
- uint32_t caplen;
- uint32_t pktlen;
uint32_t ts;
uint32_t seq;
uint16_t urg_offset;
uint8_t buffered;
- // this sequence ensures 4-byte alignment of iph in pkt
- // (only significant if we call the grinder)
- uint8_t pad1;
- uint16_t pad2;
- uint8_t pkt[1]; // variable length
+ uint8_t data[1]; // variable length
};
enum FlushPolicy
void set_extra_data(Packet*, uint32_t /*flag*/) override;
void clear_extra_data(Packet*, uint32_t /*flag*/) override;
- int get_rebuilt_packets(Packet*, PacketIterator, void* /*userdata*/) override;
- int get_segments(Packet*, StreamSegmentIterator, void* /*userdata*/) override;
-
bool is_sequenced(uint8_t /*dir*/) override;
bool are_packets_missing(uint8_t /*dir*/) override;
{
unsigned bucket = (n > BUCKET) ? n : BUCKET;
UserSegment* us = (UserSegment*)malloc(sizeof(*us)+bucket-1);
+
+ if ( !us )
+ return nullptr;
+
us->len = 0;
us->offset = 0;
us->used = 0;
us->copy(p, n);
+
return us;
}
if ( avail < p->dsize )
{
UserSegment* us = UserSegment::init(p->data+avail, p->dsize-avail);
+
+ if ( !us )
+ return;
+
seg_list.push_back(us);
}
total += p->dsize;
UserTracker& ut = p->from_client() ? server : client;
- if ( p->ptrs.decode_flags & DECODE_SOF )
+ if ( p->ptrs.decode_flags & DECODE_SOF or !ut.splitter )
start(p, flow);
if ( p->data && p->dsize )
void UserSession::set_extra_data(Packet*, uint32_t /*flag*/) { }
void UserSession::clear_extra_data(Packet*, uint32_t /*flag*/) { }
-int UserSession::get_rebuilt_packets(Packet*, PacketIterator, void* /*userdata*/)
-{ return 0; }
-
-int UserSession::get_segments(Packet*, StreamSegmentIterator, void* /*userdata*/)
-{ return 0; }
-
uint8_t UserSession::get_reassembly_direction()
{ return SSN_DIR_NONE; }
void set_extra_data(Packet*, uint32_t flag) override;
void clear_extra_data(Packet*, uint32_t flag) override;
- int get_rebuilt_packets(Packet*, PacketIterator, void* userdata) override;
- int get_segments(Packet*, StreamSegmentIterator, void* userdata) override;
-
uint8_t get_reassembly_direction() override;
public:
PegCount verdicts[MAX_SFDAQ_VERDICT];
PegCount internal_blacklist;
PegCount internal_whitelist;
-#ifdef REG_TEST
PegCount skipped;
-#endif
PegCount fail_open;
PegCount idle;
};
// FIXIT-L these are not exactly DAQ counts - but they are related
{ "internal blacklist", "packets blacklisted internally due to lack of DAQ support" },
{ "internal whitelist", "packets whitelisted internally due to lack of DAQ support" },
-#ifdef REG_TEST
{ "skipped", "packets skipped at startup" },
-#endif
{ "fail open", "packets passed during initialization" },
{ "idle", "attempts to acquire from DAQ without available packets" },
{ nullptr, nullptr }
daq_stats.internal_blacklist = gaux.internal_blacklist;
daq_stats.internal_whitelist = gaux.internal_whitelist;
-#ifdef REG_TEST
daq_stats.skipped = snort_conf->pkt_skip;
-#endif
daq_stats.fail_open = gaux.total_fail_open;
daq_stats.idle = gaux.idle;
}
int year = (lt->tm_year >= 100) ? (lt->tm_year - 100) : lt->tm_year;
(void)SnortSnprintf(timebuf, TIMEBUF_SIZE,
- "%02d/%02d/%02d-%02d:%02d:%02d.%06u ",
+ "%02d/%02d/%02d-%02d:%02d:%02d.%06u",
lt->tm_mon + 1, lt->tm_mday, year,
s / 3600, (s % 3600) / 60, s % 60,
(u_int)tvp->tv_usec);
else
{
(void)SnortSnprintf(timebuf, TIMEBUF_SIZE,
- "%02d/%02d-%02d:%02d:%02d.%06u ", lt->tm_mon + 1,
+ "%02d/%02d-%02d:%02d:%02d.%06u", lt->tm_mon + 1,
lt->tm_mday, s / 3600, (s % 3600) / 60, s % 60,
(u_int)tvp->tv_usec);
}