return 0;
}
-static inline int search_data(
+static inline int batch_search(
Mpse* so, OtnxMatchData* omd, const uint8_t* buf, unsigned len, PegCount& cnt)
{
assert(so->get_pattern_count() > 0);
- int start_state = 0;
cnt++;
- omd->data = buf; omd->size = len;
- MpseStash* stash = omd->p->context->stash;
- stash->init();
+
+ //FIXIT-P Batch outer UDP payload searches for teredo set and the outer header
+ //during any signature evaluation
+ if ( omd->p->ptrs.udph && (omd->p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
+ {
+ int start_state = 0;
+ MpseStash* stash = omd->p->context->stash;
+ stash->init();
+ so->search(buf, len, rule_tree_queue, omd, &start_state);
+ stash->process(rule_tree_match, omd);
+ }
+ else
+ {
+ MpseBatchKey<> key = MpseBatchKey<>(buf, len);
+ omd->p->context->searches.items[key].so.push_back(so);
+ }
+
dump_buffer(buf, len, omd->p);
- so->search(buf, len, rule_tree_queue, omd, &start_state);
- stash->process(rule_tree_match, omd);
+
if ( PacketLatency::fastpath() )
return 1;
return 0;
trace_logf(detection, TRACE_FP_SEARCH, "%" PRIu64 " fp %s.%s[%d]\n",
omd->p->context->packet_number, gadget->get_name(), pm_type_strings[pmt], buf.len);
- search_data(so, omd, buf.data, buf.len, cnt);
+ batch_search(so, omd, buf.data, buf.len, cnt);
}
}
return 0;
trace_logf(detection, TRACE_FP_SEARCH, "%" PRIu64 " fp %s[%u]\n",
p->context->packet_number, pm_type_strings[PM_TYPE_PKT], pattern_match_size);
- search_data(so, omd, p->data, pattern_match_size, pc.pkt_searches);
+ batch_search(so, omd, p->data, pattern_match_size, pc.pkt_searches);
p->is_cooked() ? pc.cooked_searches++ : pc.raw_searches++;
}
}
trace_logf(detection, TRACE_FP_SEARCH, "%" PRIu64 " fp search %s[%d]\n",
p->context->packet_number, pm_type_strings[PM_TYPE_FILE], file_data.len);
- search_data(so, omd, file_data.data, file_data.len, pc.file_searches);
+ batch_search(so, omd, file_data.data, file_data.len, pc.file_searches);
}
}
}
stash->enable_process();
stash->init();
init_match_info(c->otnx);
+
+ c->searches.mf = rule_tree_queue;
+ c->searches.context = c->otnx;
fpEvalPacket(p, FPTask::BOTH);
+
+ if (c->searches.items.size() > 0) {
+ c->searches.search(c->searches);
+ while (c->searches.items.size() > 0)
+ c->searches.receive_responses(c->searches);
+ stash->process(rule_tree_match, c->otnx);
+ }
+
fpFinalSelectEvent(c->otnx, p);
}
stash->init();
stash->disable_process();
init_match_info(c->otnx);
+ c->searches.mf = rule_tree_queue;
+ c->searches.context = c->otnx;
fpEvalPacket(p, FPTask::FP);
+
+ if (c->searches.items.size() > 0) {
+ Mpse* so = c->searches.items.begin()->second.so[0];
+ so->search(c->searches);
+ }
}
void fp_complete(Packet* p)
IpsContext* c = p->context;
MpseStash* stash = c->stash;
stash->enable_process();
+ while (c->searches.items.size() > 0)
+ c->searches.items.begin()->second.so[0]->receive_responses(c->searches);
stash->process(rule_tree_match, c->otnx);
fpEvalPacket(p, FPTask::NON_FP);
fpFinalSelectEvent(c->otnx, p);
// MPSE = Multi-Pattern Search Engine - ie fast pattern matching. The key
// methods of an MPSE are the ability to add patterns, compile a state
-// machine from the patterns, and search a buffer for patterns.
+// machine from the patterns, and search either a single buffer or a set
+// of (related) buffers for patterns.
#include <string>
+#include <unordered_map>
+#include <vector>
#include "framework/base_api.h"
#include "main/snort_types.h"
#define SEAPI_VERSION ((BASE_API_VERSION << 16) | 0)
struct SnortConfig;
+class Mpse;
struct MpseApi;
+struct MpseBatch;
struct ProfileStats;
+template<typename BUF = const uint8_t*, typename LEN = unsigned>
+struct MpseBatchKey
+{
+ BUF buf;
+ LEN len;
+ MpseBatchKey(BUF b, LEN n)
+ {
+ this->buf = b;
+ this->len = n;
+ }
+
+ bool operator==(const MpseBatchKey &k) const
+ {
+ return buf == k.buf && len == k.len;
+ }
+};
+
+struct MpseBatchKeyHash
+{
+ template <class BUF, class LEN>
+ std::size_t operator()(const MpseBatchKey<BUF, LEN> &k) const
+ {
+ std::size_t h1 = std::hash<BUF>()(k.buf);
+ std::size_t h2 = std::hash<LEN>()(k.len);
+
+ return h1 ^ h2;
+ }
+};
+
+class MpseBatchItem
+{
+public:
+ std::vector<Mpse*> so;
+ bool done;
+
+ MpseBatchItem(Mpse* s = nullptr)
+ { if (s) so.push_back(s); done = false; }
+};
+
class SO_PUBLIC Mpse
{
public:
virtual int search_all(
const uint8_t* T, int n, MpseMatch, void* context, int* current_state);
+ virtual void search(MpseBatch& batch);
+
+ virtual bool receive_responses(MpseBatch&) { return true; }
+
virtual void set_opt(int) { }
virtual int print_info() { return 0; }
virtual int get_pattern_count() const { return 0; }
const MpseApi* api;
};
+struct MpseBatch
+{
+ MpseMatch mf;
+ void* context;
+ std::unordered_map<MpseBatchKey<>, MpseBatchItem, MpseBatchKeyHash> items;
+
+ void search(MpseBatch& batch)
+ { items.begin()->second.so[0]->search(batch); }
+
+ bool receive_responses(MpseBatch& batch)
+ { return items.begin()->second.so[0]->receive_responses(batch); }
+};
+
extern THREAD_LOCAL ProfileStats mpsePerfStats;
typedef void (* MpseOptFunc)(SnortConfig*);