mod_dtor
},
IT_PASSIVE,
- (uint16_t)PktType::NONE,
+ PROTO_BIT__NONE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
mod_dtor
},
IT_NETWORK,
- (uint16_t)PktType::UDP,
+ PROTO_BIT__UDP,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
mod_dtor
},
IT_PACKET,
- (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::PDU,
+ PROTO_BIT__ANY_PDU,
nullptr, // buffers
s_name, // service
reg_test_init, // pinit
IpsOption::EvalStatus PktNumOption::eval(Cursor&, Packet*)
{
- ProfileContext profile(pkt_num_perf_stats);
+ Profile profile(pkt_num_perf_stats);
if ( config.eval(get_packet_number()) )
return MATCH;
const uint8_t* const end,
const int expected_len);
- void DecodeTCPOptions(const uint8_t*, uint32_t, CodecData&);
+ void DecodeTCPOptions(const uint8_t*, uint32_t, CodecData&, DecodeData&);
void TCPMiscTests(const tcp::TCPHdr* const tcph,
const DecodeData& snort,
const CodecData& codec);
uint16_t tcp_opt_len = (uint16_t)(tcph->hlen() - tcp::TCP_MIN_HEADER_LEN);
if (tcp_opt_len > 0)
- DecodeTCPOptions((const uint8_t*)(raw.data + tcp::TCP_MIN_HEADER_LEN), tcp_opt_len, codec);
-
+ {
+ const uint8_t* opts = (const uint8_t*)(raw.data + tcp::TCP_MIN_HEADER_LEN);
+ DecodeTCPOptions(opts, tcp_opt_len, codec, snort);
+ }
int dsize = raw.len - tcph->hlen();
if (dsize < 0)
dsize = 0;
*
* Returns: void function
*/
-void TcpCodec::DecodeTCPOptions(const uint8_t* start, uint32_t o_len, CodecData& codec)
+void TcpCodec::DecodeTCPOptions(
+ const uint8_t* start, uint32_t o_len, CodecData& codec, DecodeData& snort)
{
const uint8_t* const end_ptr = start + o_len; /* points to byte after last option */
const tcp::TcpOption* opt = reinterpret_cast<const tcp::TcpOption*>(start);
/* LOG INVALID WINDOWSCALE alert */
codec_event(codec, DECODE_TCPOPT_WSCALE_INVALID);
}
+ snort.decode_flags |= DECODE_WSCALE;
}
break;
void get_protocol_ids(std::vector<ProtocolId>& v) override;
bool decode(const RawData&, CodecData&, DecodeData&) override;
- void format(bool reverse, uint8_t* raw_pkt, DecodeData& snort) override;
};
} // anonymous namespace
v.push_back(ProtocolId::ETHERTYPE_REVARP);
}
-bool ArpCodec::decode(const RawData& raw, CodecData& codec, DecodeData& snort)
+bool ArpCodec::decode(const RawData& raw, CodecData& codec, DecodeData&)
{
if (raw.len < arp::ETHERARP_HDR_LEN)
{
codec.proto_bits |= PROTO_BIT__ARP;
codec.lyr_len = arp::ETHERARP_HDR_LEN;
- snort.set_pkt_type(PktType::ARP);
return true;
}
-void ArpCodec::format(bool /*reverse*/, uint8_t* /*raw_pkt*/, DecodeData& snort)
-{
- snort.set_pkt_type(PktType::ARP);
-}
-
//-------------------------------------------------------------------------
// api
//-------------------------------------------------------------------------
#include "file_decomp_pdf.h"
+#include <cassert>
+
#include "main/thread.h"
#include "utils/util.h"
return( File_Decomp_Error );
}
}
+ // fallthrough
case ( P_OBJ_EOL ):
{
} // switch()
} // while()
- return( File_Decomp_OK );
+ // can not reach this point
+ assert(false);
}
//--------------------------------------------------------------------------
{
ContextSwitcher* sw = Snort::get_switcher();
- if ( p->type() != PktType::PDU or (p->dsize < SnortConfig::get_conf()->offload_limit) or !sw->can_hold() )
+ if ( p->type() != PktType::PDU or (p->dsize < SnortConfig::get_conf()->offload_limit) or
+ !sw->can_hold() )
{
fp_local(p);
return false;
mod_dtor
},
IT_PASSIVE,
- (uint16_t)PktType::NONE,
+ PROTO_BIT__NONE,
nullptr,
"file",
file_init,
mod_dtor
},
IT_PASSIVE,
- (uint16_t)PktType::NONE,
+ PROTO_BIT__NONE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
{
if (ip_api->get_src()->fast_eq4(client_ip))
{
- if ( !(p->proto_bits & (PROTO_BIT__TCP | PROTO_BIT__UDP)) )
+ if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
p->packet_flags |= PKT_FROM_CLIENT;
else if (p->ptrs.sp == client_port)
}
else if (ip_api->get_dst()->fast_eq4(client_ip))
{
- if ( !(p->proto_bits & (PROTO_BIT__TCP | PROTO_BIT__UDP)) )
+ if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
p->packet_flags |= PKT_FROM_SERVER;
else if (p->ptrs.dp == client_port)
{
if (ip_api->get_src()->fast_eq6(client_ip))
{
- if ( !(p->proto_bits & (PROTO_BIT__TCP | PROTO_BIT__UDP)) )
+ if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
p->packet_flags |= PKT_FROM_CLIENT;
else if (p->ptrs.sp == client_port)
}
else if (ip_api->get_dst()->fast_eq6(client_ip))
{
- if ( !(p->proto_bits & (PROTO_BIT__TCP | PROTO_BIT__UDP)) )
+ if ( p->type() != PktType::TCP and p->type() != PktType::UDP )
p->packet_flags |= PKT_FROM_SERVER;
else if (p->ptrs.dp == client_port)
{ return (ssn_state.session_flags & SSNFLAG_PROXIED) != 0; }
bool is_stream()
- { return (to_utype(pkt_type) & to_utype(PktType::STREAM)) != 0; }
+ { return pkt_type == PktType::TCP or pkt_type == PktType::PDU; }
void block()
{ ssn_state.session_flags |= SSNFLAG_BLOCK; }
BitOp* bitop;
FlowHAState* ha_state;
- uint8_t ip_proto; // FIXIT-M do we need both of these?
+ uint8_t ip_proto;
PktType pkt_type; // ^^
// these fields are always set; not zeroed
{
DetectionEngine de;
- delete ip_cache;
- delete icmp_cache;
- delete tcp_cache;
- delete udp_cache;
- delete user_cache;
- delete file_cache;
+ for ( int i = 0; i < to_utype(PktType::MAX); ++i )
+ {
+ delete proto[i].cache;
+ snort_free(proto[i].mem);
+ }
delete exp_cache;
-
- snort_free(ip_mem);
- snort_free(icmp_mem);
- snort_free(tcp_mem);
- snort_free(udp_mem);
- snort_free(user_mem);
- snort_free(file_mem);
}
//-------------------------------------------------------------------------
// count foo
//-------------------------------------------------------------------------
-static THREAD_LOCAL PegCount ip_count = 0;
-static THREAD_LOCAL PegCount icmp_count = 0;
-static THREAD_LOCAL PegCount tcp_count = 0;
-static THREAD_LOCAL PegCount udp_count = 0;
-static THREAD_LOCAL PegCount user_count = 0;
-static THREAD_LOCAL PegCount file_count = 0;
-
-PegCount FlowControl::get_flows(PktType type)
-{
- switch ( type )
- {
- case PktType::IP: return ip_count;
- case PktType::ICMP: return icmp_count;
- case PktType::TCP: return tcp_count;
- case PktType::UDP: return udp_count;
- case PktType::PDU: return user_count;
- case PktType::FILE: return file_count;
- default: return 0;
- }
-}
-
PegCount FlowControl::get_total_prunes(PktType type) const
{
auto cache = get_cache(type);
void FlowControl::clear_counts()
{
- ip_count = icmp_count = 0;
- tcp_count = udp_count = 0;
- user_count = file_count = 0;
-
- FlowCache* cache;
-
- if ( (cache = get_cache(PktType::IP)) )
- cache->reset_stats();
-
- if ( (cache = get_cache(PktType::ICMP)) )
- cache->reset_stats();
-
- if ( (cache = get_cache(PktType::TCP)) )
- cache->reset_stats();
-
- if ( (cache = get_cache(PktType::UDP)) )
- cache->reset_stats();
-
- if ( (cache = get_cache(PktType::PDU)) )
- cache->reset_stats();
+ for ( int i = 0; i < to_utype(PktType::MAX); ++i )
+ {
+ if ( proto[i].cache )
+ proto[i].cache->reset_stats();
- if ( (cache = get_cache(PktType::FILE)) )
- cache->reset_stats();
+ proto[i].num_flows = 0;
+ }
}
//-------------------------------------------------------------------------
// cache foo
//-------------------------------------------------------------------------
-inline FlowCache* FlowControl::get_cache (PktType type)
-{
- switch ( type )
- {
- case PktType::IP: return ip_cache;
- case PktType::ICMP: return icmp_cache;
- case PktType::TCP: return tcp_cache;
- case PktType::UDP: return udp_cache;
- case PktType::PDU: return user_cache;
- case PktType::FILE: return file_cache;
- default: return nullptr;
- }
-}
-
-// FIXIT-L duplication of non-const method above
-inline const FlowCache* FlowControl::get_cache (PktType type) const
-{
- switch ( type )
- {
- case PktType::IP: return ip_cache;
- case PktType::ICMP: return icmp_cache;
- case PktType::TCP: return tcp_cache;
- case PktType::UDP: return udp_cache;
- case PktType::PDU: return user_cache;
- case PktType::FILE: return file_cache;
- default: return nullptr;
- }
-}
-
Flow* FlowControl::find_flow(const FlowKey* key)
{
- FlowCache* cache = get_cache(key->pkt_type);
-
- if ( cache )
+ if ( auto cache = get_cache(key->pkt_type) )
return cache->find(key);
return nullptr;
Flow* FlowControl::new_flow(const FlowKey* key)
{
- FlowCache* cache = get_cache(key->pkt_type);
-
- if ( !cache )
- return nullptr;
+ if ( auto cache = get_cache(key->pkt_type) )
+ return cache->get(key);
- return cache->get(key);
+ return nullptr;
}
// FIXIT-L cache* can be put in flow so that lookups by
if ( !cache )
return;
- Flow* flow = cache->find(key);
-
- if ( flow )
+ if ( auto flow = cache->find(key) )
cache->release(flow, PruneReason::HA);
}
void FlowControl::delete_flow(Flow* flow, PruneReason reason)
{
- FlowCache* cache = get_cache(flow->pkt_type);
-
- if ( cache )
+ if ( auto cache = get_cache(flow->pkt_type) )
cache->release(flow, reason);
}
void FlowControl::purge_flows (PktType type)
{
- FlowCache* cache = get_cache(type);
-
- if ( cache )
+ if ( auto cache = get_cache(type) )
cache->purge();
}
default:
break;
}
+ if ( flow->ssn_state.direction == FROM_CLIENT )
+ p->packet_flags |= PKT_FROM_CLIENT;
+ else
+ p->packet_flags |= PKT_FROM_SERVER;
+}
+
+//-------------------------------------------------------------------------
+// proto
+//-------------------------------------------------------------------------
+
+void FlowControl::init_proto(
+ PktType type, const FlowConfig& fc, InspectSsnFunc get_ssn)
+{
+ if ( !fc.max_sessions || !get_ssn )
+ return;
+
+ auto& con = proto[to_utype(type)];
+
+ con.cache = new FlowCache(fc);
+ con.mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
+
+ for ( unsigned i = 0; i < fc.max_sessions; ++i )
+ con.cache->push(con.mem + i);
+
+ con.get_ssn = get_ssn;
+ types.push_back(type);
+}
+
+// FIXIT-P apply more filtering logic here, eg require_3whs
+// delegate to stream inspectors but that requires binding
+// can't use session because goal is to avoid instantiation
+static bool want_flow(PktType type, Packet* p)
+{
+ if ( type != PktType::TCP )
+ return true;
+
+ if ( p->ptrs.tcph->is_rst() )
+ // guessing direction based on ports is misleading
+ return false;
+
+ if ( !p->ptrs.tcph->is_syn_only() or SnortConfig::get_conf()->track_on_syn() or
+ (p->ptrs.decode_flags & DECODE_WSCALE) )
+ return true;
+
+ p->packet_flags |= PKT_FROM_CLIENT;
+ return false;
+}
+
+bool FlowControl::process(PktType type, Packet* p)
+{
+ auto& con = proto[to_utype(type)];
+
+ if ( !con.cache )
+ return false;
+
+ FlowKey key;
+ set_key(&key, p);
+ Flow* flow = con.cache->find(&key);
+
+ if ( !flow )
+ {
+ if ( !want_flow(type, p) )
+ return true;
+
+ flow = con.cache->get(&key);
+
+ if ( !flow )
+ return true;
+ }
+ if ( !flow->session )
+ {
+ flow->init(type);
+ flow->session = con.get_ssn(flow);
+ }
+
+ con.num_flows += process(flow, p);
+
+ // FIXIT-M refactor to unlink_uni immediately after session
+ // is processed by inspector manager (all flows)
+ if ( flow->next && is_bidirectional(flow) )
+ con.cache->unlink_uni(flow);
+
+ return true;
}
unsigned FlowControl::process(Flow* flow, Packet* p)
{
unsigned news = 0;
- assert ( flow );
flow->previous_ssn_state = flow->ssn_state;
p->flow = flow;
last_pkt_type = p->type();
preemptive_cleanup();
+
flow->set_direction(p);
flow->session->precheck(p);
++news;
}
- flow->set_direction(p);
-
// This requires the packet direction to be set
if ( p->proto_bits & PROTO_BIT__MPLS )
flow->set_mpls_layer_per_dir(p);
return news;
}
-//-------------------------------------------------------------------------
-// ip
-//-------------------------------------------------------------------------
-
-void FlowControl::init_ip(
- const FlowConfig& fc, InspectSsnFunc get_ssn)
-{
- if ( !fc.max_sessions || !get_ssn )
- return;
-
- ip_cache = new FlowCache(fc);
- ip_mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
-
- for ( unsigned i = 0; i < fc.max_sessions; ++i )
- ip_cache->push(ip_mem + i);
-
- get_ip = get_ssn;
- types.push_back(PktType::IP);
-}
-
-void FlowControl::process_ip(Packet* p)
-{
- if ( !ip_cache )
- return;
-
- FlowKey key;
- set_key(&key, p);
- Flow* flow = ip_cache->get(&key);
-
- if ( !flow )
- return;
-
- if ( !flow->session )
- {
- flow->init(PktType::IP);
- flow->session = get_ip(flow);
- }
-
- ip_count += process(flow, p);
-
- if ( flow->next && is_bidirectional(flow) )
- ip_cache->unlink_uni(flow);
-}
-
-//-------------------------------------------------------------------------
-// icmp
-//-------------------------------------------------------------------------
-
-void FlowControl::init_icmp(
- const FlowConfig& fc, InspectSsnFunc get_ssn)
-{
- if ( !fc.max_sessions || !get_ssn )
- return;
-
- icmp_cache = new FlowCache(fc);
- icmp_mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
-
- for ( unsigned i = 0; i < fc.max_sessions; ++i )
- icmp_cache->push(icmp_mem + i);
-
- get_icmp = get_ssn;
- types.push_back(PktType::ICMP);
-}
-
-void FlowControl::process_icmp(Packet* p)
-{
- if ( !icmp_cache )
- {
- process_ip(p);
- return;
- }
-
- FlowKey key;
- set_key(&key, p);
- Flow* flow = icmp_cache->get(&key);
-
- if ( !flow )
- return;
-
- if ( !flow->session )
- {
- flow->init(PktType::ICMP);
- flow->session = get_icmp(flow);
- }
-
- icmp_count += process(flow, p);
-
- if ( flow->next && is_bidirectional(flow) )
- icmp_cache->unlink_uni(flow);
-}
-
-//-------------------------------------------------------------------------
-// tcp
-//-------------------------------------------------------------------------
-
-void FlowControl::init_tcp(
- const FlowConfig& fc, InspectSsnFunc get_ssn)
-{
- if ( !fc.max_sessions || !get_ssn )
- return;
-
- tcp_cache = new FlowCache(fc);
- tcp_mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
-
- for ( unsigned i = 0; i < fc.max_sessions; ++i )
- tcp_cache->push(tcp_mem + i);
-
- get_tcp = get_ssn;
- types.push_back(PktType::TCP);
-}
-
-void FlowControl::process_tcp(Packet* p)
-{
- if ( !tcp_cache )
- return;
-
- FlowKey key;
- set_key(&key, p);
- Flow* flow = tcp_cache->get(&key);
-
- if ( !flow )
- return;
-
- if ( !flow->session )
- {
- flow->init(PktType::TCP);
- flow->session = get_tcp(flow);
- }
-
- tcp_count += process(flow, p);
-
- // FIXIT-M refactor to unlink_uni immediately after session
- // is processed by inspector manager (all flows)
- if ( flow->next && is_bidirectional(flow) )
- tcp_cache->unlink_uni(flow);
-}
-
-//-------------------------------------------------------------------------
-// udp
-//-------------------------------------------------------------------------
-
-void FlowControl::init_udp(
- const FlowConfig& fc, InspectSsnFunc get_ssn)
-{
- if ( !fc.max_sessions || !get_ssn )
- return;
-
- udp_cache = new FlowCache(fc);
- udp_mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
-
- for ( unsigned i = 0; i < fc.max_sessions; ++i )
- udp_cache->push(udp_mem + i);
-
- get_udp = get_ssn;
- types.push_back(PktType::UDP);
-}
-
-void FlowControl::process_udp(Packet* p)
-{
- if ( !udp_cache )
- return;
-
- FlowKey key;
- set_key(&key, p);
- Flow* flow = udp_cache->get(&key);
-
- if ( !flow )
- return;
-
- if ( !flow->session )
- {
- flow->init(PktType::UDP);
- flow->session = get_udp(flow);
- }
-
- udp_count += process(flow, p);
-
- if ( flow->next && is_bidirectional(flow) )
- udp_cache->unlink_uni(flow);
-}
-
-//-------------------------------------------------------------------------
-// user
-//-------------------------------------------------------------------------
-
-void FlowControl::init_user(
- const FlowConfig& fc, InspectSsnFunc get_ssn)
-{
- if ( !fc.max_sessions || !get_ssn )
- return;
-
- user_cache = new FlowCache(fc);
- user_mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
-
- for ( unsigned i = 0; i < fc.max_sessions; ++i )
- user_cache->push(user_mem + i);
-
- get_user = get_ssn;
- types.push_back(PktType::PDU);
-}
-
-void FlowControl::process_user(Packet* p)
-{
- if ( !user_cache )
- return;
-
- FlowKey key;
- set_key(&key, p);
- Flow* flow = user_cache->get(&key);
-
- if ( !flow )
- return;
-
- if ( !flow->session )
- {
- flow->init(PktType::PDU);
- flow->session = get_user(flow);
- }
-
- user_count += process(flow, p);
-
- if ( flow->next && is_bidirectional(flow) )
- user_cache->unlink_uni(flow);
-}
-
-//-------------------------------------------------------------------------
-// file
-//-------------------------------------------------------------------------
-
-void FlowControl::init_file(
- const FlowConfig& fc, InspectSsnFunc get_ssn)
-{
- if ( !fc.max_sessions || !get_ssn )
- return;
-
- file_cache = new FlowCache(fc);
- file_mem = (Flow*)snort_calloc(fc.max_sessions, sizeof(Flow));
-
- for ( unsigned i = 0; i < fc.max_sessions; ++i )
- file_cache->push(file_mem + i);
-
- get_file = get_ssn;
- types.push_back(PktType::FILE);
-}
-
-void FlowControl::process_file(Packet* p)
-{
- if ( !file_cache )
- return;
-
- FlowKey key;
- set_key(&key, p);
- Flow* flow = file_cache->get(&key);
-
- if ( !flow )
- return;
-
- if ( !flow->session )
- {
- flow->init(PktType::FILE);
- flow->session = get_file(flow);
- }
-
- file_count += process(flow, p);
-}
-
//-------------------------------------------------------------------------
// expected
//-------------------------------------------------------------------------
~FlowControl();
public:
- void process_ip(snort::Packet*);
- void process_icmp(snort::Packet*);
- void process_tcp(snort::Packet*);
- void process_udp(snort::Packet*);
- void process_user(snort::Packet*);
- void process_file(snort::Packet*);
+ bool process(PktType, snort::Packet*);
snort::Flow* find_flow(const snort::FlowKey*);
snort::Flow* new_flow(const snort::FlowKey*);
- void init_ip(const FlowConfig&, snort::InspectSsnFunc);
- void init_icmp(const FlowConfig&, snort::InspectSsnFunc);
- void init_tcp(const FlowConfig&, snort::InspectSsnFunc);
- void init_udp(const FlowConfig&, snort::InspectSsnFunc);
- void init_user(const FlowConfig&, snort::InspectSsnFunc);
- void init_file(const FlowConfig&, snort::InspectSsnFunc);
+ void init_proto(PktType, const FlowConfig&, snort::InspectSsnFunc);
void init_exp(uint32_t max);
void delete_flow(const snort::FlowKey*);
const snort::SfIp *dstIP, uint16_t dstPort,
SnortProtocolId snort_protocol_id, snort::FlowData*);
- PegCount get_flows(PktType);
+ PegCount get_flows(PktType pt)
+ { return proto[to_utype(pt)].num_flows; }
+
PegCount get_total_prunes(PktType) const;
PegCount get_prunes(PktType, PruneReason) const;
void clear_counts();
private:
- FlowCache* get_cache(PktType);
- const FlowCache* get_cache(PktType) const;
+ FlowCache* get_cache(PktType pt)
+ { return proto[to_utype(pt)].cache; }
+
+ const FlowCache* get_cache(PktType pt) const
+ { return proto[to_utype(pt)].cache; }
void set_key(snort::FlowKey*, snort::Packet*);
void preemptive_cleanup();
private:
- FlowCache* ip_cache = nullptr;
- FlowCache* icmp_cache = nullptr;
- FlowCache* tcp_cache = nullptr;
- FlowCache* udp_cache = nullptr;
- FlowCache* user_cache = nullptr;
- FlowCache* file_cache = nullptr;
-
- // preallocated arrays
- snort::Flow* ip_mem = nullptr;
- snort::Flow* icmp_mem = nullptr;
- snort::Flow* tcp_mem = nullptr;
- snort::Flow* udp_mem = nullptr;
- snort::Flow* user_mem = nullptr;
- snort::Flow* file_mem = nullptr;
-
- snort::InspectSsnFunc get_ip = nullptr;
- snort::InspectSsnFunc get_icmp = nullptr;
- snort::InspectSsnFunc get_tcp = nullptr;
- snort::InspectSsnFunc get_udp = nullptr;
- snort::InspectSsnFunc get_user = nullptr;
- snort::InspectSsnFunc get_file = nullptr;
+ struct
+ {
+ FlowCache* cache = nullptr;
+ snort::Flow* mem = nullptr;
+ snort::InspectSsnFunc get_ssn = nullptr;
+ PegCount num_flows = 0;
+ } proto[to_utype(PktType::MAX)];
class ExpectCache* exp_cache = nullptr;
PktType last_pkt_type = PktType::NONE;
// Session is an abstract base class for the various protocol subclasses.
// the subclasses do the actual work of tracking, reassembly, etc.
+#include <cassert>
#include "stream/stream.h"
namespace snort
virtual void flush_talker(snort::Packet*, bool /*final_flush */ = false) { }
virtual void flush_listener(snort::Packet*, bool /*final_flush */ = false) { }
- virtual void set_splitter(bool /*c2s*/, snort::StreamSplitter*) { }
+ virtual void set_splitter(bool /*c2s*/, snort::StreamSplitter*) { assert(false); }
virtual snort::StreamSplitter* get_splitter(bool /*c2s*/) { return nullptr; }
virtual void set_extra_data(snort::Packet*, uint32_t /*flag*/) { }
/* Reset before each decode of packet begins */
/* Codec specific fields. These fields are only relevant to codecs. */
- uint16_t proto_bits; /* protocols contained within this packet
+ uint32_t proto_bits; /* protocols contained within this packet
-- will be propogated to Snort++ Packet struct*/
uint16_t codec_flags; /* flags used while decoding */
uint8_t ip_layer_cnt;
/* NOTE: if A protocol is added, update DecodeFlags! */
enum class PktType : std::uint8_t
{
- NONE= 0x00,
- IP = 0x01,
- TCP = 0x02,
- UDP = 0x04,
- ICMP = 0x08,
- ARP = 0x10,
- PDU = 0x20,
- FILE = 0x40,
- STREAM = 0x22,
- ANY_IP = 0x0F,
- ANY_SSN = 0x6F,
- ANY = 0x7F,
-// FREE = 0x80,
+ NONE, IP, TCP, UDP, ICMP, PDU, FILE, MAX
};
+// the first several of these bits must map to PktType
+// eg PROTO_BIT__IP == BIT(PktType::IP), etc.
+#define PROTO_BIT__NONE 0x00000
+#define PROTO_BIT__IP 0x00001
+#define PROTO_BIT__TCP 0x00002
+#define PROTO_BIT__UDP 0x00004
+#define PROTO_BIT__ICMP 0x00008
+#define PROTO_BIT__PDU 0x00010
+#define PROTO_BIT__FILE 0x00020
+#define PROTO_BIT__ARP 0x00040
+#define PROTO_BIT__TEREDO 0x00080
+#define PROTO_BIT__GTP 0x00100
+#define PROTO_BIT__MPLS 0x00200
+#define PROTO_BIT__VLAN 0x00400
+#define PROTO_BIT__ETH 0x00800
+#define PROTO_BIT__TCP_EMBED_ICMP 0x01000
+#define PROTO_BIT__UDP_EMBED_ICMP 0x02000
+#define PROTO_BIT__ICMP_EMBED_ICMP 0x04000
+#define PROTO_BIT__ICMP_EMBED_OTHER 0x08000
+#define PROTO_BIT__IP6_EXT 0x10000
+#define PROTO_BIT__OTHER 0x20000
+#define PROTO_BIT__ALL 0x3FFFF
+
+#define PROTO_BIT__ICMP_EMBED \
+ (PROTO_BIT__TCP_EMBED_ICMP | PROTO_BIT__UDP_EMBED_ICMP | \
+ PROTO_BIT__ICMP_EMBED_ICMP | PROTO_BIT__ICMP_EMBED_OTHER)
+
+#define PROTO_BIT__ANY_IP (PROTO_BIT__IP | PROTO_BIT__TCP | PROTO_BIT__UDP | PROTO_BIT__ICMP)
+#define PROTO_BIT__ANY_PDU (PROTO_BIT__TCP | PROTO_BIT__UDP | PROTO_BIT__PDU)
+#define PROTO_BIT__ANY_SSN (PROTO_BIT__ANY_IP | PROTO_BIT__PDU | PROTO_BIT__FILE)
+#define PROTO_BIT__ANY_TYPE (PROTO_BIT__ANY_SSN | PROTO_BIT__ARP)
+
enum DecodeFlags : std::uint16_t
{
DECODE_ERR_CKSUM_IP = 0x0001, // error flags
DECODE_C2S = 0x0100, // user - client to server
DECODE_SOF = 0x0200, // user - start of flow
DECODE_EOF = 0x0400, // user - end of flow
- DECODE_GTP = 0x0800, // gtp encap
-};
+ DECODE_GTP = 0x0800,
-// FIXIT-L make this an enum!!
-#define PROTO_BIT__NONE 0x0000
-#define PROTO_BIT__IP 0x0001
-#define PROTO_BIT__ARP 0x0002
-#define PROTO_BIT__TCP 0x0004
-#define PROTO_BIT__UDP 0x0008
-#define PROTO_BIT__ICMP 0x0010
-#define PROTO_BIT__TEREDO 0x0020
-#define PROTO_BIT__GTP 0x0040
-#define PROTO_BIT__MPLS 0x0080
-#define PROTO_BIT__VLAN 0x0100
-#define PROTO_BIT__ETH 0x0200
-#define PROTO_BIT__TCP_EMBED_ICMP 0x0400
-#define PROTO_BIT__UDP_EMBED_ICMP 0x0800
-#define PROTO_BIT__ICMP_EMBED_ICMP 0x1000
-#define PROTO_BIT__ICMP_EMBED_OTHER 0x2000
-#define PROTO_BIT__ICMP_EMBED \
- (PROTO_BIT__TCP_EMBED_ICMP | PROTO_BIT__UDP_EMBED_ICMP | \
- PROTO_BIT__ICMP_EMBED_ICMP | PROTO_BIT__ICMP_EMBED_OTHER)
-#define PROTO_BIT__IP6_EXT 0x4000
-#define PROTO_BIT__FREE 0x0000 /* No proto bits free */
-#define PROTO_BIT__OTHER 0x8000 // FIXIT-L delete this after porting is still unused
-#define PROTO_BIT__ALL 0xffff
+ DECODE_WSCALE = 0x1000,
+};
struct DecodeData
{
bool Inspector::likes(Packet* p)
{
- if ( !((uint16_t)p->type() & api->proto_bits) )
+ if ( !(BIT((uint16_t)p->type()) & api->proto_bits) )
return false;
if ( p->is_tcp() && api->type == IT_SERVICE )
{
BaseApi base;
InspectorType type;
- uint16_t proto_bits;
+ uint32_t proto_bits;
const char** buffers; // null terminated list of exported buffers
const char* service; // nullptr when type != IT_SERVICE
}
}
-ZHashNode* ZHash::find_node_row(const void* key, int* rindex)
+ZHashNode* ZHash::find_node_row(const void* key, int& row)
{
unsigned hashkey = hashfcn->hash_fcn(
hashfcn, (const unsigned char*)key, keysize);
// Modulus is slow; use a table size that is a power of 2.
int index = hashkey & (nrows - 1);
-
- *rindex = index;
+ row = index;
for ( ZHashNode* node=table[index]; node; node=node->next ) // UNINITUSE
{
void* ZHash::get(const void* key, bool *new_node)
{
- int index = 0;
- ZHashNode* node = find_node_row(key, &index);
+ int row;
+ ZHashNode* node = find_node_row(key, row);
if ( node )
return node->data;
if ( !node )
return nullptr;
- memcpy(node->key,key,keysize);
+ memcpy(node->key, key, keysize);
- node->rindex = index;
+ node->rindex = row;
link_node (node);
glink_node(node);
void* ZHash::find(const void* key)
{
- int rindex = 0;
- ZHashNode* node = find_node_row(key, &rindex);
+ int row;
+ ZHashNode* node = find_node_row(key, row);
if ( node )
return node->data;
bool ZHash::remove(const void* key)
{
- int row = 0;
- ZHashNode* node = find_node_row(key, &row);
+ int row;
+ ZHashNode* node = find_node_row(key, row);
return remove(node);
}
private:
ZHashNode* get_free_node();
- ZHashNode* find_node_row(const void*, int*);
+ ZHashNode* find_node_row(const void*, int&);
void glink_node(ZHashNode*);
void gunlink_node(ZHashNode*);
BitOp* bitop = get_flow_bitop(p);
if (!bitop)
- {
- assert(false);
return IpsOption::NO_MATCH;
- }
switch (type)
{
{ "max_queue_events", Parameter::PT_INT, "2:100", "5", // upper bound is MAX_EVENT_MATCH
"maximum number of matching fast pattern states to queue per packet" },
- { "detect_raw_tcp", Parameter::PT_BOOL, nullptr, "true",
+ { "detect_raw_tcp", Parameter::PT_BOOL, nullptr, "false",
"detect on TCP payload before reassembly" },
{ "search_method", Parameter::PT_DYNAMIC, (void*)&get_search_methods, "ac_bnfa",
RUN_FLAG__PIGLET = 0x01000000,
#endif
RUN_FLAG__MEM_CHECK = 0x02000000,
+ RUN_FLAG__TRACK_ON_SYN = 0x04000000,
};
enum OutputFlag
return get_conf()->enable_packet_trace;
}
+ bool track_on_syn() const
+ { return (run_flags & RUN_FLAG__TRACK_ON_SYN) != 0; }
+
// Use this to access current thread's conf from other units
static void set_conf(SnortConfig*);
{
for ( auto* p : s_handlers )
{
- if ( p->api.type == IT_STREAM && p->api.proto_bits == proto && !p->init )
+ if ( p->api.type == IT_STREAM and p->api.proto_bits == proto and !p->init )
return p->api.ssn;
}
return nullptr;
const char* t = api.base.name;
m->add(s, t);
- tcp = tcp || (api.proto_bits & (unsigned)PktType::TCP);
- udp = udp || (api.proto_bits & (unsigned)PktType::UDP);
- pdu = pdu || (api.proto_bits & (unsigned)PktType::PDU);
+ tcp = tcp or (api.proto_bits & PROTO_BIT__TCP);
+ udp = udp or (api.proto_bits & PROTO_BIT__UDP);
+ pdu = pdu or (api.proto_bits & PROTO_BIT__PDU);
}
if ( tcp or pdu )
- m->add((unsigned)PktType::TCP, wiz_id);
+ m->add(PROTO_BIT__TCP, wiz_id);
if ( udp )
- m->add((unsigned)PktType::UDP, wiz_id);
+ m->add(PROTO_BIT__UDP, wiz_id);
if ( tcp or udp or pdu )
- m->add((unsigned)PktType::PDU, wiz_id);
+ m->add(PROTO_BIT__PDU, wiz_id);
const InspectApi* api = get_plugin(bind_id);
InspectorManager::instantiate(api, m, sc);
if ( !p->flow && (ppc.api.type == IT_SERVICE) )
break;
- if ( (unsigned)p->type() & ppc.api.proto_bits )
+ // FIXIT-L ideally we could eliminate PktType and just use
+ // proto_bits but things like teredo need to be fixed up.
+ if ( p->type() == PktType::NONE )
+ {
+ if ( p->proto_bits & ppc.api.proto_bits )
+ (*prep)->handler->eval(p);
+ }
+ else if ( BIT((unsigned)p->type()) & ppc.api.proto_bits )
(*prep)->handler->eval(p);
}
}
// these don't have to be visible to operate as replacements
+#ifndef NO_MEM_MGR
void* operator new(size_t n)
{
auto p = memory::Interface<>::allocate(n);
void operator delete[](void* p, size_t) noexcept;
SO_PUBLIC void operator delete[](void* p, size_t) noexcept
{ ::operator delete[](p); }
+#endif
// -----------------------------------------------------------------------------
// unit tests
CHECK( CapSpy::update_deallocations_arg == memory::Metadata::calculate_total_size(n) );
}
}
+ AllocatorSpy::pool = nullptr;
+ AllocatorSpy::deallocate_arg = nullptr;
}
#endif
mod_dtor
},
IT_CONTROL,
- (uint16_t)PktType::ANY_IP,
+ PROTO_BIT__ANY_IP,
nullptr, // buffers
nullptr, // service
appid_inspector_pinit,
{
AppId app_ids[NUM_ID_TYPES];
- assert(p->flow);
+ if ( !p->flow )
+ return NO_MATCH;
+
Profile profile(appidRuleOptionPerfStats);
if ( !opt_data.ids_mapped )
hsession->update_host((const uint8_t*)attribute_data->spdyRequestHost,
strlen(attribute_data->spdyRequestHost));
- // FIXIT-M do we need to free this memeory and set to null
+ // FIXIT-M do we need to free this memory and set to null
// attribute_data->spdyRequestHost = nullptr;
hsession->set_field_offset(REQ_HOST_FID, attribute_data->spdyRequestHostOffset);
hsession->set_field_end_offset(REQ_HOST_FID,
hsession->update_uri((const uint8_t*)attribute_data->spdyRequestPath,
strlen(attribute_data->spdyRequestPath));
- // FIXIT-M do we need to free this memeory and set to null
+ // FIXIT-M do we need to free this memory and set to null
//attribute_data->spdyRequestPath = nullptr;
hsession->set_field_offset(REQ_URI_FID, attribute_data->spdyRequestPathOffset);
hsession->set_field_end_offset(REQ_URI_FID, attribute_data->spdyRequestPathEndOffset);
attribute_data->httpRequestHostLen);
hsession->set_field_offset(REQ_HOST_FID, attribute_data->httpRequestHostOffset);
hsession->set_field_end_offset(REQ_HOST_FID, attribute_data->httpRequestHostEndOffset);
- // FIXIT-M do we need to free this memeory and set to null
+ // FIXIT-M do we need to free this memory and set to null
//attribute_data->httpRequestHost = nullptr;
if (appidDebug->is_active())
LogMessage("AppIdDbg %s HTTP host (%u-%u) is %s\n",
Profile profile(arpPerfStats);
// precondition - what we registered for
- assert(p->type() == PktType::ARP);
+ assert(p->proto_bits & PROTO_BIT__ARP);
+
const uint8_t* dst_mac_addr;
const uint8_t* src_mac_addr;
mod_dtor
},
IT_NETWORK,
- (uint16_t)PktType::ARP,
+ PROTO_BIT__ARP,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
else if ( v.is("proto") )
{
- const PktType mask[] =
+ const unsigned mask[] =
{
- PktType::ANY, PktType::IP, PktType::ICMP, PktType::TCP, PktType::UDP,
- PktType::PDU, PktType::FILE
+ PROTO_BIT__ANY_TYPE, PROTO_BIT__IP, PROTO_BIT__ICMP,
+ PROTO_BIT__TCP, PROTO_BIT__UDP, PROTO_BIT__PDU, PROTO_BIT__FILE
};
- work->when.protos = (unsigned)mask[v.get_long()];
+ work->when.protos = mask[v.get_long()];
}
else if ( v.is("ports") )
{
when.src_ports.set();
when.dst_ports.set();
- when.protos = (unsigned)PktType::ANY;
+ when.protos = PROTO_BIT__ANY_TYPE;
when.vlans.set();
when.ifaces.reset();
inline bool Binding::check_proto(const Flow* flow) const
{
- if ( when.protos & (unsigned)flow->pkt_type )
+ if ( when.protos & BIT((unsigned)flow->pkt_type) )
return true;
return false;
mod_dtor
},
IT_BINDER,
- (uint16_t)PktType::ANY,
+ PROTO_BIT__ANY_TYPE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
mod_dtor
},
IT_PACKET,
- (uint16_t)PktType::ANY_IP,
+ PROTO_BIT__ANY_IP,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
mod_dtor
},
IT_PROBE,
- (uint16_t)PktType::ANY,
+ PROTO_BIT__ANY_TYPE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
struct ModuleConfig
{
- // state optimized for run time using indicies
+ // state optimized for run time using indices
// can't be determined until all modules have loaded (PerfMonitor::configure)
snort::Module* ptr;
IndexVec pegs;
mod_dtor
},
IT_PROBE,
- (uint16_t)PktType::ANY,
+ PROTO_BIT__ANY_TYPE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
char a1[INET6_ADDRSTRLEN];
ip1->ntop(a1, sizeof(a1));
- buf.len = safe_snprintf((char*)buf.data, sizeof(buf.data),
+ buf.len += safe_snprintf((char*)buf.data+buf.len, sizeof(buf.data)-buf.len,
"Scanned IP: %s\n"
"Port Count: %d\n"
- "Ports:",
+ "Open Ports:",
a1,
proto->open_ports_cnt);
buf.len += safe_snprintf((char*)buf.data + buf.len, sizeof(buf.data) - buf.len, "\n");
}
+#if 0
+// FIXIT-L add open port for port sweeps
static void make_open_port_info(Packet* p, uint16_t port)
{
DataBuffer& buf = DetectionEngine::get_alt_buffer(p);
"Open Port: %hu\n",
p->ptrs.ip_api.get_src()->ntop(ip_str), port);
}
+#endif
static void PortscanAlertTcp(Packet* p, PS_PROTO* proto)
{
assert(proto);
- bool portsweep = false;
+ if ( proto->open_ports_cnt and proto->alerts != PS_ALERT_PORTSWEEP and
+ proto->alerts != PS_ALERT_PORTSWEEP_FILTERED )
+ {
+ make_open_port_info(p, proto);
+ }
switch (proto->alerts)
{
case PS_ALERT_ONE_TO_ONE:
case PS_ALERT_PORTSWEEP:
DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_PORTSWEEP);
- portsweep = true;
break;
case PS_ALERT_DISTRIBUTED:
case PS_ALERT_PORTSWEEP_FILTERED:
DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_TCP_PORTSWEEP_FILTERED);
- portsweep = true;
break;
case PS_ALERT_DISTRIBUTED_FILTERED:
default:
return;
}
-
- // Only log open ports for portsweeps after the alert has been generated.
- if (proto->open_ports_cnt and !portsweep)
- {
- make_open_port_info(p, proto);
- DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_OPEN_PORT);
- }
}
static void PortscanAlertUdp(Packet*, PS_PROTO* proto)
static void PortscanAlert(PS_PKT* ps_pkt, PS_PROTO* proto, int proto_type)
{
Packet* p = ps_pkt->pkt;
+ make_port_scan_info(p, proto);
- if (proto->alerts == PS_ALERT_OPEN_PORT)
+ switch (proto_type)
{
- make_open_port_info(p, p->ptrs.sp);
- DetectionEngine::queue_event(GID_PORT_SCAN, PSNG_OPEN_PORT);
- }
- else
- {
- make_port_scan_info(p, proto);
-
- switch (proto_type)
- {
- case PS_PROTO_TCP:
- PortscanAlertTcp(p, proto);
- break;
+ case PS_PROTO_TCP:
+ PortscanAlertTcp(p, proto);
+ break;
- case PS_PROTO_UDP:
- PortscanAlertUdp(p, proto);
- break;
+ case PS_PROTO_UDP:
+ PortscanAlertUdp(p, proto);
+ break;
- case PS_PROTO_ICMP:
- PortscanAlertIcmp(p, proto);
- break;
+ case PS_PROTO_ICMP:
+ PortscanAlertIcmp(p, proto);
+ break;
- case PS_PROTO_IP:
- PortscanAlertIp(p, proto);
- break;
- }
+ case PS_PROTO_IP:
+ PortscanAlertIp(p, proto);
+ break;
}
}
mod_dtor
},
IT_PROBE,
- (uint16_t)PktType::ANY_IP,
+ PROTO_BIT__ANY_IP,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
{
proto->open_ports[iCtr] = port;
proto->open_ports_cnt++;
-
- if (proto->alerts == PS_ALERT_GENERATED)
- {
- proto->alerts = PS_ALERT_OPEN_PORT;
- }
}
return 0;
!(p->packet_flags & PKT_STREAM_EST))
{
if (scanned)
- {
ps_update_open_ports(&scanned->proto, p->ptrs.sp);
- }
-
- if (scanner)
- {
- if (scanner->proto.alerts == PS_ALERT_GENERATED)
- scanner->proto.alerts = PS_ALERT_OPEN_PORT;
- }
}
}
/*
** Stream didn't create a session on the SYN packet,
** so check specifically for SYN here.
*/
- else if (p->ptrs.tcph && (p->ptrs.tcph->th_flags == TH_SYN))
+ else if ( p->ptrs.tcph and p->ptrs.tcph->is_syn_only() )
{
/* No session established, packet only has SYN. SYN only
** packet always from client, so use dp.
** so check specifically for SYN & ACK here. Clear based
** on the 'completion' of three-way handshake.
*/
- else if (p->ptrs.tcph && (p->ptrs.tcph->th_flags == (TH_SYN|TH_ACK)))
+ else if ( p->ptrs.tcph and p->ptrs.tcph->is_syn_ack() )
{
if (scanned)
{
#define PS_ALERT_ONE_TO_ONE_DECOY_FILTERED 6
#define PS_ALERT_DISTRIBUTED_FILTERED 7
#define PS_ALERT_PORTSWEEP_FILTERED 8
-#define PS_ALERT_OPEN_PORT 9
#define PS_ALERT_GENERATED 255
mod_dtor
},
IT_NETWORK,
- (uint16_t)PktType::ANY_IP,
+ PROTO_BIT__ANY_IP,
nullptr, // buffers
nullptr, // service
reputation_init, // pinit
MemoryContext memory;
};
-class SO_PUBLIC ProfileExclude
+class ProfileExclude
{
public:
ProfileExclude(ProfileStats& stats) : ProfileExclude(stats.time, stats.memory) { }
using get_profile_stats_fn = ProfileStats* (*)(const char*);
+class NoMemContext
+{
+public:
+ NoMemContext(ProfileStats& stats) :
+ time(stats.time) { }
+
+private:
+ TimeContext time;
+};
+
+class NoMemExclude
+{
+public:
+ NoMemExclude(ProfileStats& stats) : NoMemExclude(stats.time, stats.memory) { }
+ NoMemExclude(TimeProfilerStats& time, MemoryTracker&) : time(time) { }
+
+private:
+ TimeExclude time;
+};
+
+class ProfileDisabled
+{
+public:
+ ProfileDisabled(ProfileStats&) { }
+ ProfileDisabled(TimeProfilerStats&, MemoryTracker&) { }
+};
+
+#ifdef NO_PROFILER
+using Profile = ProfileDisabled;
+using NoProfile = ProfileDisabled;
+#else
+#ifdef NO_MEM_MGR
+using Profile = NoMemContext;
+using NoProfile = NoMemExclude;
+#else
using Profile = ProfileContext;
+using NoProfile = ProfileExclude;
+#endif
+#endif
+
}
#endif
case PktType::UDP:
return "UDP";
- case PktType::ARP:
- return "ARP";
-
case PktType::PDU:
case PktType::FILE:
if ( proto_bits & PROTO_BIT__TCP )
return "Error";
case PktType::NONE:
+ if ( proto_bits & PROTO_BIT__ARP )
+ return "ARP";
+
if ( num_layers > 0 )
return PacketManager::get_proto_name(layers[num_layers-1].prot_id);
uint32_t packet_flags; /* special flags for the packet */
uint32_t xtradata_mask;
+ uint32_t proto_bits; /* protocols contained within this packet */
- uint16_t proto_bits; /* protocols contained within this packet */
uint16_t alt_dsize; /* size for detection (iff PKT_DETECT_LIMIT) */
uint8_t num_layers; /* index into layers for next encap */
inline bool is_syn() const
{ return (th_flags & TH_SYN); }
- // FIXIT-L should other flags (e.g. RST, FIN) be included in check for syn only?
inline bool is_syn_only() const
{ return (th_flags & (TH_SYN | TH_ACK)) == TH_SYN; }
mod_dtor
},
IT_NETWORK,
- (uint16_t)PktType::UDP,
+ PROTO_BIT__UDP,
nullptr, // buffers
nullptr, // service
bo_init,
mod_proxy_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"dce_http_proxy",
nullptr, // pinit
mod_server_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"dce_http_server",
nullptr, // pinit
mod_dtor
},
snort::IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"netbios-ssn",
dce2_smb_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
DCE_RPC_SERVICE_NAME,
dce2_tcp_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::UDP,
+ PROTO_BIT__UDP,
nullptr, // buffers
DCE_RPC_SERVICE_NAME,
dce2_udp_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU | (uint16_t)PktType::UDP,
+ PROTO_BIT__UDP | PROTO_BIT__PDU,
nullptr, // buffers
"dnp3",
dnp3_init,
if ((ret == true) && (packet->is_udp()))
{
{
- ProfileExclude profile_exclude(dnp3_perf_stats);
+ NoProfile exclude(dnp3_perf_stats);
DetectionEngine::detect(packet);
}
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::PDU,
+ PROTO_BIT__ANY_PDU,
nullptr, // buffers
"dns",
dns_init,
ret = check_ftp(FTPsession, p, iInspectMode);
if ( ret == FTPP_SUCCESS )
{
- ProfileExclude exclude(ftpPerfStats);
+ NoProfile exclude(ftpPerfStats);
// FIXIT-L ideally do_detection will look at the cmd & param buffers
// or the rsp & msg buffers. We should call it from inside check_ftp
mod_dtor
},
IT_PASSIVE,
- (uint16_t)PktType::NONE,
+ PROTO_BIT__NONE,
nullptr, // buffers
"ftp",
nullptr, // init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"ftp",
fs_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
fd_svc_name,
fd_init,
if ( ret == FTPP_SUCCESS || ret == FTPP_NORMALIZED )
{
- ProfileExclude exclude(telnetPerfStats);
+ NoProfile exclude(telnetPerfStats);
do_detection(p);
}
}
else
{
- ProfileExclude exclude(telnetPerfStats);
+ NoProfile exclude(telnetPerfStats);
do_detection(p);
}
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"telnet",
tn_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::UDP,
+ PROTO_BIT__UDP,
nullptr,
"gtp",
gtp_init,
Http2Api::http2_mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
classic_buffer_names,
"http2",
Http2Api::http2_init,
HttpApi::http_mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
classic_buffer_names,
"http",
HttpApi::http_init,
else
{
#ifdef REG_TEST
+ // FIXIT-M: known case: if session clears w/o a flush point,
+ // stream_tcp will flush to paf max which could be well below what
+ // has been scanned so far. since no flush point was specified,
+ // NHI should just deal with what it gets.
assert(false);
#endif
return http_buf;
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"imap",
imap_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr,
"modbus",
modbus_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"pop3",
pop_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"sunrpc",
rd_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU | (uint16_t)PktType::UDP,
+ PROTO_BIT__UDP | PROTO_BIT__PDU,
nullptr, // buffers
"sip",
sip_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"smtp",
smtp_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"ssh",
ssh_init,
mod_dtor
},
IT_SERVICE,
- (uint16_t)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
"ssl",
ssl_init,
mod_dtor
},
IT_WIZARD,
- (uint16_t)PktType::TCP | (uint16_t)PktType::UDP | (uint16_t)PktType::PDU,
+ PROTO_BIT__ANY_PDU,
nullptr, // buffers
nullptr, // service
nullptr, // init
#include "config.h"
#endif
+#include <functional>
+
#include "flow/flow_control.h"
#include "flow/prune_stats.h"
+#include "main/snort_config.h"
#include "managers/inspector_manager.h"
#include "profiler/profiler_defs.h"
#include "protocols/packet.h"
+#include "protocols/tcp.h"
#include "stream/flush_bucket.h"
#include "stream_ha.h"
public:
StreamBase(const StreamModuleConfig*);
+ bool configure(SnortConfig*) override;
void show(SnortConfig*) override;
void tinit() override;
if ( config.ip_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::IP)) )
- flow_con->init_ip(config.ip_cfg, f);
+ if ( (f = InspectorManager::get_session(PROTO_BIT__IP)) )
+ flow_con->init_proto(PktType::IP, config.ip_cfg, f);
}
if ( config.icmp_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::ICMP)) )
- flow_con->init_icmp(config.icmp_cfg, f);
+ if ( (f = InspectorManager::get_session(PROTO_BIT__ICMP)) )
+ flow_con->init_proto(PktType::ICMP, config.icmp_cfg, f);
}
if ( config.tcp_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::TCP)) )
- flow_con->init_tcp(config.tcp_cfg, f);
+ if ( (f = InspectorManager::get_session(PROTO_BIT__TCP)) )
+ flow_con->init_proto(PktType::TCP, config.tcp_cfg, f);
}
if ( config.udp_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::UDP)) )
- flow_con->init_udp(config.udp_cfg, f);
+ if ( (f = InspectorManager::get_session(PROTO_BIT__UDP)) )
+ flow_con->init_proto(PktType::UDP, config.udp_cfg, f);
}
if ( config.user_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::PDU)) )
- flow_con->init_user(config.user_cfg, f);
+ if ( (f = InspectorManager::get_session(PROTO_BIT__PDU)) )
+ flow_con->init_proto(PktType::PDU, config.user_cfg, f);
}
if ( config.file_cfg.max_sessions )
{
- if ( (f = InspectorManager::get_session((uint16_t)PktType::FILE)) )
- flow_con->init_file(config.file_cfg, f);
+ if ( (f = InspectorManager::get_session(PROTO_BIT__FILE)) )
+ flow_con->init_proto(PktType::FILE, config.file_cfg, f);
}
uint32_t max = config.tcp_cfg.max_sessions + config.udp_cfg.max_sessions
+ config.user_cfg.max_sessions;
FlushBucket::clear();
}
+bool StreamBase::configure(SnortConfig* sc)
+{
+ config.track_on_syn = sc->track_on_syn();
+ return true;
+}
+
void StreamBase::show(SnortConfig*)
{
// FIXIT-L SSN print
switch ( p->type() )
{
- case PktType::IP:
- if ( p->has_ip() and
- ((p->ptrs.decode_flags & DECODE_FRAG) or !config.ip_frags_only) )
- flow_con->process_ip(p);
+ case PktType::NONE:
break;
- case PktType::ICMP:
- if ( p->ptrs.icmph )
- flow_con->process_icmp(p);
+ case PktType::IP:
+ if ( p->has_ip() and ((p->ptrs.decode_flags & DECODE_FRAG) or !config.ip_frags_only) )
+ flow_con->process(PktType::IP, p);
break;
case PktType::TCP:
if ( p->ptrs.tcph )
- flow_con->process_tcp(p);
+ flow_con->process(PktType::TCP, p);
break;
case PktType::UDP:
if ( p->ptrs.decode_flags & DECODE_FRAG )
- flow_con->process_ip(p);
+ flow_con->process(PktType::IP, p);
if ( p->ptrs.udph )
- flow_con->process_udp(p);
+ flow_con->process(PktType::UDP, p);
+ break;
+
+ case PktType::ICMP:
+ if ( p->ptrs.icmph )
+ {
+ if ( !flow_con->process(PktType::ICMP, p) )
+ flow_con->process(PktType::IP, p);
+ }
break;
case PktType::PDU:
- flow_con->process_user(p);
+ flow_con->process(PktType::PDU, p);
break;
case PktType::FILE:
- flow_con->process_file(p);
+ flow_con->process(PktType::FILE, p);
break;
- default:
+ case PktType::MAX:
break;
- }
+ };
}
#if 0
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::ANY_SSN,
+ PROTO_BIT__ANY_SSN,
nullptr, // buffers
nullptr, // service
nullptr, // init
int footprint;
bool ip_frags_only;
+ bool track_on_syn;
};
class StreamModule : public snort::Module
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::FILE,
+ PROTO_BIT__FILE,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::ICMP,
+ PROTO_BIT__ICMP,
nullptr, // buffers
nullptr, // service
nullptr, // init
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::IP,
+ PROTO_BIT__IP,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
DebugMessage(DEBUG_STREAM_STATE, "Checking for wscale...\n");
+ if ( !(pkt->ptrs.decode_flags & DECODE_WSCALE) )
+ return false;
+
return ( init_wscale(&wscale) & TF_WSCALE ) != TF_NONE;
}
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::TCP,
+ PROTO_BIT__TCP,
nullptr, // buffers
nullptr, // service
nullptr, // init
#include "tcp_module.h"
+#include "main/snort_config.h"
#include "profiler/profiler_defs.h"
using namespace snort;
{ "flush_factor", Parameter::PT_INT, "0:", "0",
"flush upon seeing a drop in segment size after given number of non-decreasing segments" },
- { "ignore_any_rules", Parameter::PT_BOOL, nullptr, "false",
- "process TCP content rules w/o ports only if rules with ports are present" },
-
{ "max_window", Parameter::PT_INT, "0:1073725440", "0",
"maximum allowed TCP window" },
else if ( v.is("flush_factor") )
config->flush_factor = v.get_long();
- else if ( v.is("ignore_any_rules") )
- config->flags |= STREAM_CONFIG_IGNORE_ANY;
-
else if ( v.is("max_bytes") )
config->max_queued_bytes = v.get_long();
return true;
}
-bool StreamTcpModule::end(const char*, int, SnortConfig*)
+bool StreamTcpModule::end(const char*, int, SnortConfig* sc)
{
+ if ( config->hs_timeout >= 0 )
+ sc->run_flags |= RUN_FLAG__TRACK_ON_SYN;
return true;
}
return ( get_pending_segment_count(trs, 2) > 1 ); // FIXIT-L return false?
}
+bool TcpReassembler::next_no_gap(TcpSegmentNode& tsn)
+{
+ return tsn.next and (tsn.next->seq == tsn.seq + tsn.payload_size);
+}
+
+void TcpReassembler::update_next(TcpReassemblerState& trs, TcpSegmentNode& tsn)
+{
+ trs.sos.seglist.next = next_no_gap(tsn) ? tsn.next : nullptr;
+}
+
int TcpReassembler::delete_reassembly_segment(TcpReassemblerState& trs, TcpSegmentNode* tsn)
{
int ret;
}
if (trs.sos.seglist.next == tsn)
- trs.sos.seglist.next = nullptr;
+ update_next(trs, *tsn);
tsn->term( );
trs.sos.seg_count--;
trs.flush_count++;
segs++;
- trs.sos.seglist.next = tsn->next;
+ update_next(trs, *tsn);
if ( SEQ_EQ(tsn->seq + bytes_to_copy, to_seq) )
break;
tcpStats.rebuilt_packets++;
tcpStats.rebuilt_bytes += flushed_bytes;
- ProfileExclude profile_exclude(s5TcpFlushPerfStats);
+ NoProfile exclude(s5TcpFlushPerfStats);
Snort::inspect(pdu);
}
else
trs.flush_count++;
show_rebuilt_packet(trs, pdu);
- ProfileExclude profile_exclude(s5TcpFlushPerfStats);
+ NoProfile profile_exclude(s5TcpFlushPerfStats);
Snort::inspect(pdu);
if ( trs.tracker->splitter )
if ( !trs.tracker )
return 0;
- trs.sos.seglist.next = trs.sos.seglist.head;
footprint = trs.tracker->r_win_base - trs.sos.seglist_base_seq;
if ( footprint )
{
sequenced = get_q_sequenced(trs);
+
if ( trs.tracker->fin_seq_status == TcpStreamTracker::FIN_WITH_SEQ_ACKED )
--footprint;
}
uint32_t TcpReassembler::get_q_sequenced(TcpReassemblerState& trs)
{
- TcpSegmentNode* tsn = trs.tracker ? trs.sos.seglist.head : nullptr;
- TcpSegmentNode* base = nullptr;
-
- if ( !tsn || ( trs.sos.session->flow->two_way_traffic() &&
- SEQ_LT(trs.tracker->r_win_base, tsn->seq) ) )
- return 0;
+ TcpSegmentNode* tsn;
- while ( tsn->next && ( tsn->next->seq == tsn->seq + tsn->payload_size ) )
+ if ( trs.sos.seglist.next )
+ tsn = trs.sos.seglist.next;
+ else
{
- if ( !tsn->buffered && !base )
- base = tsn;
- tsn = tsn->next;
- }
+ trs.sos.seglist.next = trs.sos.seglist.head;
+ tsn = trs.tracker ? trs.sos.seglist.next : nullptr; // FIXIT-H why check tracker here?
- if ( !tsn->buffered && !base )
- base = tsn;
+ if ( !tsn or (trs.sos.session->flow->two_way_traffic() and
+ SEQ_LT(trs.tracker->r_win_base, tsn->seq)) )
+ {
+ if ( trs.sos.seglist.next )
+ trs.sos.seglist.next = trs.sos.seglist.next->prev;
+ return 0;
+ }
+ }
- int32_t len = 0;
+ uint32_t len = 0;
+ const uint32_t limit = trs.tracker->splitter->get_max_pdu();
- if ( base )
+ while ( len < limit and next_no_gap(*tsn) )
{
- trs.sos.seglist.next = base;
- trs.sos.seglist_base_seq = base->seq;
- len = tsn->seq + tsn->payload_size - base->seq;
+ if ( tsn->buffered )
+ trs.sos.seglist.next = tsn->next;
+ else
+ len += tsn->payload_size;
+
+ tsn = tsn->next;
}
+ if ( !tsn->buffered )
+ len += tsn->payload_size;
+
+ trs.sos.seglist_base_seq = trs.sos.seglist.next->seq;
- return ( len > 0 ) ? len : 0;
+ return len;
}
// FIXIT-L flush_stream() calls should be replaced with calls to
void fallback(TcpReassemblerState&);
int32_t flush_pdu_ackd(TcpReassemblerState&, uint32_t* flags);
int purge_to_seq(TcpReassemblerState&, uint32_t flush_seq);
+
+ bool next_no_gap(TcpSegmentNode&);
+ void update_next(TcpReassemblerState&, TcpSegmentNode&);
};
#endif
TcpSession::~TcpSession()
{
- if (tcp_init)
- clear_session(true, false, false);
+ clear_session(true, false, false);
}
bool TcpSession::setup(Packet* p)
void TcpSession::clear_session(bool free_flow_data, bool flush_segments, bool restart, Packet* p)
{
+ if ( !tcp_init )
+ return;
+
assert(!p or p->flow == flow);
DetectionEngine::onload(flow);
if ( config->flags )
{
LogMessage(" Options:\n");
- if (config->flags & STREAM_CONFIG_IGNORE_ANY)
- LogMessage(" Ignore Any -> Any Rules: YES\n");
-
if (config->flags & STREAM_CONFIG_NO_ASYNC_REASSEMBLY)
LogMessage(" Don't queue packets on one-sided sessions: YES\n");
}
#include "stream/tcp/tcp_defs.h"
#include "time/packet_time.h"
-#define STREAM_CONFIG_STATEFUL_INSPECTION 0x00000001
-#define STREAM_CONFIG_LOG_STREAMS 0x00000004
-#define STREAM_CONFIG_REASS_CLIENT 0x00000008
-#define STREAM_CONFIG_REASS_SERVER 0x00000010
-#define STREAM_CONFIG_ASYNC 0x00000020
-#define STREAM_CONFIG_SHOW_PACKETS 0x00000040
-#define STREAM_CONFIG_MIDSTREAM_DROP_NOALERT 0x00000080
-#define STREAM_CONFIG_IGNORE_ANY 0x00000100
-#define STREAM_CONFIG_STATIC_FLUSHPOINTS 0x00000200
-#define STREAM_CONFIG_IPS 0x00000400
-#define STREAM_CONFIG_NO_ASYNC_REASSEMBLY 0x00000800
+#define STREAM_CONFIG_SHOW_PACKETS 0x00000001
+#define STREAM_CONFIG_NO_ASYNC_REASSEMBLY 0x00000002
#define STREAM_DEFAULT_SSN_TIMEOUT 30
StreamUdpConfig::StreamUdpConfig()
{
session_timeout = 30;
- ignore_any = false;
}
static void udp_show(StreamUdpConfig* pc)
LogMessage("Stream UDP config:\n");
LogMessage(" Timeout: %d seconds\n", pc->session_timeout);
- const char* opt = (pc->ignore_any) ? "YES" : "NO";
- LogMessage(" Ignore Any -> Any Rules: %s\n", opt);
-
#ifdef REG_TEST
LogMessage(" UDP Session Size: %zu\n", sizeof(UdpSession));
#endif
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::UDP,
+ PROTO_BIT__UDP,
nullptr, // buffers
nullptr, // service
nullptr, // init
struct StreamUdpConfig
{
uint32_t session_timeout;
- bool ignore_any;
StreamUdpConfig();
};
{ "session_timeout", Parameter::PT_INT, "1:86400", "30",
"session tracking timeout" },
- { "ignore_any_rules", Parameter::PT_BOOL, nullptr, "false",
- "process UDP content rules w/o ports only if rules with ports are present" },
-
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
if ( v.is("session_timeout") )
config->session_timeout = v.get_long();
- else if ( v.is("ignore_any_rules") )
- config->ignore_any = v.get_bool();
-
else
return false;
mod_dtor
},
IT_STREAM,
- (unsigned)PktType::PDU,
+ PROTO_BIT__PDU,
nullptr, // buffers
nullptr, // service
nullptr, // pinit
return new DeadCode(c);
}
+#if 0
+// currently unused - for future reference
template<const std::string* snort_option,
const std::string* lua_table>
static ConversionState* config_false_no_opt_ctor(Converter& c)
c.get_table_api().close_table();
return new DeadCode(c);
}
+#endif
} // namespace
/*************************************************
tmpval = parse_small_segments(arg_stream);
else if (keyword == "ignore_any_rules")
- tmpval = table_api.add_option("ignore_any_rules", true);
+ table_api.add_deleted_comment("ignore_any_rules");
else if (keyword == "ports")
tmpval = parse_ports(arg_stream);
continue;
if (keyword == "ignore_any_rules")
- tmpval = table_api.add_option("ignore_any_rules", true);
+ table_api.add_deleted_comment("ignore_any_rules");
else if (keyword == "timeout")
{