mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
184 lines
5.7 KiB
C++
184 lines
5.7 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
#include "zeek/RuleCondition.h"
|
|
|
|
#include "zeek/Func.h"
|
|
#include "zeek/ID.h"
|
|
#include "zeek/Reporter.h"
|
|
#include "zeek/RuleMatcher.h"
|
|
#include "zeek/Scope.h"
|
|
#include "zeek/Val.h"
|
|
#include "zeek/analyzer/protocol/tcp/TCP.h"
|
|
|
|
static inline bool is_established(const zeek::analyzer::tcp::TCP_Endpoint* e) {
|
|
// We more or less follow Snort here: an established session
|
|
// is one for which the initial handshake has succeeded (but we
|
|
// add partial connections). The connection tear-down is part
|
|
// of the connection.
|
|
return e->state != zeek::analyzer::tcp::TCP_ENDPOINT_INACTIVE &&
|
|
e->state != zeek::analyzer::tcp::TCP_ENDPOINT_SYN_SENT &&
|
|
e->state != zeek::analyzer::tcp::TCP_ENDPOINT_SYN_ACK_SENT;
|
|
}
|
|
|
|
namespace zeek::detail {
|
|
|
|
bool RuleConditionTCPState::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) {
|
|
auto* adapter = state->GetAnalyzer()->Conn()->GetSessionAdapter();
|
|
|
|
if ( ! adapter || ! adapter->IsAnalyzer("TCP") )
|
|
return false;
|
|
|
|
auto* ta = static_cast<packet_analysis::TCP::TCPSessionAdapter*>(adapter);
|
|
|
|
if ( tcpstates & RULE_STATE_STATELESS )
|
|
return true;
|
|
|
|
if ( (tcpstates & RULE_STATE_ORIG) && ! state->IsOrig() )
|
|
return false;
|
|
|
|
if ( (tcpstates & RULE_STATE_RESP) && state->IsOrig() )
|
|
return false;
|
|
|
|
if ( (tcpstates & RULE_STATE_ESTABLISHED) && ! (is_established(ta->Orig()) && is_established(ta->Resp())) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void RuleConditionTCPState::PrintDebug() { fprintf(stderr, " RuleConditionTCPState: 0x%x\n", tcpstates); }
|
|
|
|
bool RuleConditionUDPState::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) {
|
|
auto* adapter = state->GetAnalyzer()->Conn()->GetSessionAdapter();
|
|
|
|
if ( ! adapter || ! adapter->IsAnalyzer("UDP") )
|
|
return false;
|
|
|
|
if ( states & RULE_STATE_STATELESS )
|
|
return true;
|
|
|
|
if ( (states & RULE_STATE_ORIG) && ! state->IsOrig() )
|
|
return false;
|
|
|
|
if ( (states & RULE_STATE_RESP) && state->IsOrig() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void RuleConditionUDPState::PrintDebug() { fprintf(stderr, " RuleConditionUDPState: 0x%x\n", states); }
|
|
|
|
void RuleConditionIPOptions::PrintDebug() { fprintf(stderr, " RuleConditionIPOptions: 0x%x\n", options); }
|
|
|
|
bool RuleConditionIPOptions::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) {
|
|
// FIXME: Not implemented yet
|
|
return false;
|
|
}
|
|
|
|
void RuleConditionSameIP::PrintDebug() { fprintf(stderr, " RuleConditionSameIP\n"); }
|
|
|
|
bool RuleConditionSameIP::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) {
|
|
return state->GetAnalyzer()->Conn()->OrigAddr() == state->GetAnalyzer()->Conn()->RespAddr();
|
|
}
|
|
|
|
void RuleConditionPayloadSize::PrintDebug() { fprintf(stderr, " RuleConditionPayloadSize %d\n", val); }
|
|
|
|
bool RuleConditionPayloadSize::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) {
|
|
#ifdef MATCHER_PRINT_DEBUG
|
|
fprintf(stderr, "%.06f PayloadSize check: val = %d, payload_size = %d\n", network_time, val, state->PayloadSize());
|
|
#endif
|
|
|
|
if ( state->PayloadSize() < 0 )
|
|
// The size has not been set yet, i.e. we're matching
|
|
// on the pure rules now.
|
|
return false;
|
|
|
|
if ( state->PayloadSize() == 0 )
|
|
// We are interested in the first non-empty chunk.
|
|
return false;
|
|
|
|
uint32_t payload_size = uint32_t(state->PayloadSize());
|
|
|
|
switch ( comp ) {
|
|
case RULE_EQ: return payload_size == val;
|
|
|
|
case RULE_NE: return payload_size != val;
|
|
|
|
case RULE_LT: return payload_size < val;
|
|
|
|
case RULE_GT: return payload_size > val;
|
|
|
|
case RULE_LE: return payload_size <= val;
|
|
|
|
case RULE_GE: return payload_size >= val;
|
|
|
|
default: reporter->InternalError("unknown comparison type");
|
|
}
|
|
|
|
// Should not be reached
|
|
return false;
|
|
}
|
|
|
|
RuleConditionEval::RuleConditionEval(const char* func) {
|
|
id = global_scope()->Find(func).get();
|
|
if ( ! id ) {
|
|
rules_error("unknown identifier", func);
|
|
return;
|
|
}
|
|
|
|
if ( id->GetType()->Tag() == TYPE_FUNC ) {
|
|
// Validate argument quantity and type.
|
|
FuncType* f = id->GetType()->AsFuncType();
|
|
|
|
if ( f->Yield()->Tag() != TYPE_BOOL )
|
|
rules_error("eval function type must yield a 'bool'", func);
|
|
|
|
static auto signature_state = id::find_type<RecordType>("signature_state");
|
|
TypeList tl;
|
|
tl.Append(signature_state);
|
|
tl.Append(base_type(TYPE_STRING));
|
|
|
|
if ( ! f->CheckArgs(tl.GetTypes()) )
|
|
rules_error(
|
|
"eval function parameters must be a 'signature_state' "
|
|
"and a 'string' type",
|
|
func);
|
|
|
|
id->AddAttr(make_intrusive<Attr>(ATTR_IS_USED));
|
|
}
|
|
}
|
|
|
|
bool RuleConditionEval::DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, int len) {
|
|
if ( ! id->HasVal() ) {
|
|
reporter->Error("undefined value");
|
|
return false;
|
|
}
|
|
|
|
if ( id->GetType()->Tag() != TYPE_FUNC )
|
|
return id->GetVal()->AsBool();
|
|
|
|
// Call function with a signature_state value as argument.
|
|
Args args;
|
|
args.reserve(2);
|
|
args.emplace_back(AdoptRef{}, rule_matcher->BuildRuleStateValue(rule, state));
|
|
|
|
if ( data )
|
|
args.emplace_back(make_intrusive<StringVal>(len, (const char*)data));
|
|
else
|
|
args.emplace_back(val_mgr->EmptyString());
|
|
|
|
bool result = false;
|
|
|
|
try {
|
|
auto val = id->GetVal()->AsFunc()->Invoke(&args);
|
|
result = val && val->AsBool();
|
|
}
|
|
|
|
catch ( InterpreterException& e ) {
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void RuleConditionEval::PrintDebug() { fprintf(stderr, " RuleConditionEval: %s\n", id->Name()); }
|
|
|
|
} // namespace zeek::detail
|