wizard.cc (snort3-3.1.29.0) | : | wizard.cc (snort3-3.1.30.0) | ||
---|---|---|---|---|
skipping to change at line 142 | skipping to change at line 142 | |||
{ | { | |||
public: | public: | |||
Wizard(WizardModule*); | Wizard(WizardModule*); | |||
~Wizard() override; | ~Wizard() override; | |||
void eval(Packet*) override; | void eval(Packet*) override; | |||
StreamSplitter* get_splitter(bool) override; | StreamSplitter* get_splitter(bool) override; | |||
inline bool finished(Wand& w) | inline bool finished(Wand& w) | |||
{ return !w.hex && !w.spell && w.curse_tracker.empty(); } | { return !w.hex and !w.spell and w.curse_tracker.empty(); } | |||
void reset(Wand&, bool tcp, bool c2s); | ||||
void reset(Wand&, bool, bool); | ||||
bool cast_spell(Wand&, Flow*, const uint8_t*, unsigned, uint16_t&); | bool cast_spell(Wand&, Flow*, const uint8_t*, unsigned, uint16_t&); | |||
bool spellbind(const MagicPage*&, Flow*, const uint8_t*, unsigned, const Mag icPage*&); | bool spellbind(const MagicPage*&, Flow*, const uint8_t*, unsigned, const Mag icPage*&); | |||
bool cursebind(const vector<CurseServiceTracker>&, Flow*, const uint8_t*, un signed); | bool cursebind(const vector<CurseServiceTracker>&, Flow*, const uint8_t*, un signed); | |||
public: | public: | |||
MagicBook* c2s_hexes; | MagicBook* c2s_hexes; | |||
MagicBook* s2c_hexes; | MagicBook* s2c_hexes; | |||
MagicBook* c2s_spells; | MagicBook* c2s_spells; | |||
MagicBook* s2c_spells; | MagicBook* s2c_spells; | |||
skipping to change at line 179 | skipping to change at line 181 | |||
wizard = w; | wizard = w; | |||
w->add_ref(); | w->add_ref(); | |||
w->reset(wand, true, c2s); | w->reset(wand, true, c2s); | |||
} | } | |||
MagicSplitter::~MagicSplitter() | MagicSplitter::~MagicSplitter() | |||
{ | { | |||
wizard->rem_ref(); | wizard->rem_ref(); | |||
// release trackers | // release trackers | |||
for (unsigned i = 0; i < wand.curse_tracker.size(); i++) | for ( unsigned i = 0; i < wand.curse_tracker.size(); i++ ) | |||
delete wand.curse_tracker[i].tracker; | delete wand.curse_tracker[i].tracker; | |||
} | } | |||
StreamSplitter::Status MagicSplitter::scan( | StreamSplitter::Status MagicSplitter::scan( | |||
Packet* pkt, const uint8_t* data, uint32_t len, | Packet* pkt, const uint8_t* data, uint32_t len, | |||
uint32_t, uint32_t*) | uint32_t, uint32_t*) | |||
{ | { | |||
Profile profile(wizPerfStats); | Profile profile(wizPerfStats); | |||
count_scan(pkt->flow); | count_scan(pkt->flow); | |||
bytes_scanned += len; | bytes_scanned += len; | |||
if ( wizard->cast_spell(wand, pkt->flow, data, len, wizard_processed_bytes) ) | if ( wizard->cast_spell(wand, pkt->flow, data, len, wizard_processed_bytes) ) | |||
{ | { | |||
trace_logf(wizard_trace, pkt, "%s streaming search found service %s\n", | trace_logf(wizard_trace, pkt, "%s streaming search found service %s\n", | |||
to_server() ? "c2s" : "s2c", pkt->flow->service); | to_server() ? "c2s" : "s2c", pkt->flow->service); | |||
count_hit(pkt->flow); | count_hit(pkt->flow); | |||
wizard_processed_bytes = 0; | wizard_processed_bytes = 0; | |||
return STOP; | return STOP; | |||
} | } | |||
else if ( wizard->finished(wand) || bytes_scanned >= max(pkt->flow) ) | else if ( wizard->finished(wand) or bytes_scanned >= max(pkt->flow) ) | |||
{ | { | |||
count_miss(pkt->flow); | count_miss(pkt->flow); | |||
trace_logf(wizard_trace, pkt, "%s streaming search abandoned\n", to_serv er() ? "c2s" : "s2c"); | trace_logf(wizard_trace, pkt, "%s streaming search abandoned\n", to_serv er() ? "c2s" : "s2c"); | |||
wizard_processed_bytes = 0; | wizard_processed_bytes = 0; | |||
if (!pkt->flow->flags.svc_event_generated) | ||||
if ( !pkt->flow->flags.svc_event_generated ) | ||||
{ | { | |||
DataBus::publish(FLOW_NO_SERVICE_EVENT, pkt); | DataBus::publish(FLOW_NO_SERVICE_EVENT, pkt); | |||
pkt->flow->flags.svc_event_generated = true; | pkt->flow->flags.svc_event_generated = true; | |||
} | } | |||
return ABORT; | return ABORT; | |||
} | } | |||
// FIXIT-L Ideally, this event should be raised after wizard aborts its sear ch. However, this | // FIXIT-L Ideally, this event should be raised after wizard aborts its sear ch. However, this | |||
// could take multiple packets because wizard needs wizard.max_search_depth payload bytes before | // could take multiple packets because wizard needs wizard.max_search_depth payload bytes before | |||
// it aborts. This is an issue for AppId which consumes this event. AppId is required to declare | // it aborts. This is an issue for AppId which consumes this event. AppId is required to declare | |||
// unknown service as soon as it can so that the flow actions (such as IPS b lock, etc) don't get | // unknown service as soon as it can so that the flow actions (such as IPS b lock, etc) don't get | |||
// delayed. Because AppId depends on wizard only for SSH detection and SSH i nspector can be | // delayed. Because AppId depends on wizard only for SSH detection and SSH i nspector can be | |||
// attached very early, event is raised here after first scan. In the future , wizard should be | // attached very early, event is raised here after first scan. In the future , wizard should be | |||
// enhanced to abort sooner if it can't detect service. | // enhanced to abort sooner if it can't detect service. | |||
if (!pkt->flow->service && !pkt->flow->flags.svc_event_generated) | if ( !pkt->flow->service and !pkt->flow->flags.svc_event_generated ) | |||
{ | { | |||
DataBus::publish(FLOW_NO_SERVICE_EVENT, pkt); | DataBus::publish(FLOW_NO_SERVICE_EVENT, pkt); | |||
pkt->flow->flags.svc_event_generated = true; | pkt->flow->flags.svc_event_generated = true; | |||
} | } | |||
// ostensibly continue but splitter will be swapped out upon hit | // ostensibly continue but splitter will be swapped out upon hit | |||
return SEARCH; | return SEARCH; | |||
} | } | |||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | |||
skipping to change at line 272 | skipping to change at line 277 | |||
{ | { | |||
w.hex = c2s_hexes->page1(); | w.hex = c2s_hexes->page1(); | |||
w.spell = c2s_spells->page1(); | w.spell = c2s_spells->page1(); | |||
} | } | |||
else | else | |||
{ | { | |||
w.hex = s2c_hexes->page1(); | w.hex = s2c_hexes->page1(); | |||
w.spell = s2c_spells->page1(); | w.spell = s2c_spells->page1(); | |||
} | } | |||
if (w.curse_tracker.empty()) | if ( w.curse_tracker.empty() ) | |||
{ | { | |||
vector<const CurseDetails*> pages = curses->get_curses(tcp); | vector<const CurseDetails*> pages = curses->get_curses(tcp); | |||
for ( const CurseDetails* curse : pages ) | for ( const CurseDetails* curse : pages ) | |||
{ | { | |||
if (tcp) | if ( tcp ) | |||
w.curse_tracker.emplace_back( CurseServiceTracker{ curse, new Cu rseTracker } ); | w.curse_tracker.emplace_back( CurseServiceTracker{ curse, new Cu rseTracker } ); | |||
else | else | |||
w.curse_tracker.emplace_back( CurseServiceTracker{ curse, nullpt r } ); | w.curse_tracker.emplace_back( CurseServiceTracker{ curse, nullpt r } ); | |||
} | } | |||
} | } | |||
} | } | |||
void Wizard::eval(Packet* p) | void Wizard::eval(Packet* p) | |||
{ | { | |||
Profile profile(wizPerfStats); | Profile profile(wizPerfStats); | |||
if ( !p->is_udp() ) | if ( !p->is_udp() ) | |||
return; | return; | |||
if ( !p->data || !p->dsize ) | if ( !p->data or !p->dsize ) | |||
return; | return; | |||
bool c2s = p->is_from_client(); | bool c2s = p->is_from_client(); | |||
Wand wand; | Wand wand; | |||
reset(wand, false, c2s); | reset(wand, false, c2s); | |||
uint16_t udp_processed_bytes = 0; | uint16_t udp_processed_bytes = 0; | |||
++tstats.udp_scans; | ++tstats.udp_scans; | |||
if ( cast_spell(wand, p->flow, p->data, p->dsize, udp_processed_bytes) ) | if ( cast_spell(wand, p->flow, p->data, p->dsize, udp_processed_bytes) ) | |||
{ | { | |||
trace_logf(wizard_trace, p, "%s datagram search found service %s\n", | trace_logf(wizard_trace, p, "%s datagram search found service %s\n", | |||
c2s ? "c2s" : "s2c", p->flow->service); | c2s ? "c2s" : "s2c", p->flow->service); | |||
++tstats.udp_hits; | ++tstats.udp_hits; | |||
} | } | |||
else | else | |||
{ | { | |||
p->flow->clear_clouseau(); | p->flow->clear_clouseau(); | |||
trace_logf(wizard_trace, p, "%s datagram search abandoned\n", c2s ? "c2s " : "s2c"); | trace_logf(wizard_trace, p, "%s datagram search abandoned\n", c2s ? "c2s " : "s2c"); | |||
skipping to change at line 324 | skipping to change at line 331 | |||
StreamSplitter* Wizard::get_splitter(bool c2s) | StreamSplitter* Wizard::get_splitter(bool c2s) | |||
{ | { | |||
return new MagicSplitter(c2s, this); | return new MagicSplitter(c2s, this); | |||
} | } | |||
bool Wizard::spellbind( | bool Wizard::spellbind( | |||
const MagicPage*& m, Flow* f, const uint8_t* data, unsigned len, const Magic Page*& bookmark) | const MagicPage*& m, Flow* f, const uint8_t* data, unsigned len, const Magic Page*& bookmark) | |||
{ | { | |||
f->service = m->book.find_spell(data, len, m, bookmark); | f->service = m->book.find_spell(data, len, m, bookmark); | |||
return f->service != nullptr; | return f->service != nullptr; | |||
} | } | |||
bool Wizard::cursebind(const vector<CurseServiceTracker>& curse_tracker, Flow* f , | bool Wizard::cursebind(const vector<CurseServiceTracker>& curse_tracker, Flow* f , | |||
const uint8_t* data, unsigned len) | const uint8_t* data, unsigned len) | |||
{ | { | |||
for (const CurseServiceTracker& cst : curse_tracker) | for ( const CurseServiceTracker& cst : curse_tracker ) | |||
{ | { | |||
if (cst.curse->alg(data, len, cst.tracker)) | if ( cst.curse->alg(data, len, cst.tracker) ) | |||
{ | { | |||
f->service = cst.curse->service; | f->service = cst.curse->service; | |||
if ( f->service ) | if ( f->service ) | |||
return true; | return true; | |||
} | } | |||
} | } | |||
return false; | return false; | |||
} | } | |||
bool Wizard::cast_spell( | bool Wizard::cast_spell( | |||
Wand& w, Flow* f, const uint8_t* data, unsigned len, uint16_t& wizard_proces sed_bytes) | Wand& w, Flow* f, const uint8_t* data, unsigned len, uint16_t& wizard_proces sed_bytes) | |||
{ | { | |||
auto curse_len = len; | auto curse_len = len; | |||
len = std::min(len, static_cast<unsigned>(max_search_depth - wizard_processe d_bytes)); | len = std::min(len, static_cast<unsigned>(max_search_depth - wizard_processe d_bytes)); | |||
wizard_processed_bytes += len; | wizard_processed_bytes += len; | |||
if ( w.hex && spellbind(w.hex, f, data, len, w.bookmark) ) | if ( w.hex and spellbind(w.hex, f, data, len, w.bookmark) ) | |||
return true; | return true; | |||
if ( w.spell && spellbind(w.spell, f, data, len, w.bookmark) ) | if ( w.spell and spellbind(w.spell, f, data, len, w.bookmark) ) | |||
return true; | return true; | |||
if (cursebind(w.curse_tracker, f, data, curse_len)) | if ( cursebind(w.curse_tracker, f, data, curse_len) ) | |||
return true; | return true; | |||
// If we reach max value of wizard_processed_bytes, | // If we reach max value of wizard_processed_bytes, | |||
// but not assign any inspector - raise tcp_miss and stop | // but not assign any inspector - raise tcp_miss and stop | |||
if ( !f->service && wizard_processed_bytes >= max_search_depth ) | if ( !f->service and wizard_processed_bytes >= max_search_depth ) | |||
{ | { | |||
w.spell = nullptr; | w.spell = nullptr; | |||
w.hex = nullptr; | w.hex = nullptr; | |||
for ( const CurseServiceTracker& cst : w.curse_tracker ) | for ( const CurseServiceTracker& cst : w.curse_tracker ) | |||
delete cst.tracker; | delete cst.tracker; | |||
w.curse_tracker.clear(); | w.curse_tracker.clear(); | |||
} | } | |||
End of changes. 22 change blocks. | ||||
17 lines changed or deleted | 24 lines changed or added |