diff --git a/src/RuleCondition.cc b/src/RuleCondition.cc index 0650ea309b..789c94cd88 100644 --- a/src/RuleCondition.cc +++ b/src/RuleCondition.cc @@ -54,6 +54,31 @@ void RuleConditionTCPState::PrintDebug() fprintf(stderr, " RuleConditionTCPState: 0x%x\n", tcpstates); } +bool RuleConditionUDPState::DoMatch(Rule* rule, RuleEndpointState* state, + const u_char* data, int len) + { + analyzer::Analyzer* root = state->GetAnalyzer()->Conn()->GetRootAnalyzer(); + + if ( ! root || ! root->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); diff --git a/src/RuleCondition.h b/src/RuleCondition.h index 5951b86eaf..6e73da4d1d 100644 --- a/src/RuleCondition.h +++ b/src/RuleCondition.h @@ -46,6 +46,20 @@ private: int tcpstates; }; +// Implements the "udp-state" keyword. +class RuleConditionUDPState : public RuleCondition { +public: + explicit RuleConditionUDPState(int arg_states) + { states = arg_states; } + + bool DoMatch(Rule* rule, RuleEndpointState* state, const u_char* data, + int len) override; + + void PrintDebug() override; + +private: + int states; +}; // Implements "ip-options". class RuleConditionIPOptions : public RuleCondition { diff --git a/src/rule-parse.y b/src/rule-parse.y index c99104e0e3..cb555c0c6d 100644 --- a/src/rule-parse.y +++ b/src/rule-parse.y @@ -58,6 +58,7 @@ static uint8_t ip4_mask_to_len(uint32_t mask) %token TOK_SRC_IP %token TOK_SRC_PORT %token TOK_TCP_STATE +%token TOK_UDP_STATE %token TOK_STRING %token TOK_STATE_SYM %token TOK_ACTIVE @@ -251,6 +252,14 @@ rule_attr: current_rule->AddCondition(new zeek::detail::RuleConditionTCPState($2)); } + | TOK_UDP_STATE state_list + { + if ( $2 & zeek::detail::RULE_STATE_ESTABLISHED ) + rules_error("'established' is not a valid 'udp-state'"); + + current_rule->AddCondition(new zeek::detail::RuleConditionUDPState($2)); + } + | TOK_ACTIVE TOK_BOOL { current_rule->SetActiveStatus($2); } ; diff --git a/src/rule-scan.l b/src/rule-scan.l index 0660105513..8cf698563e 100644 --- a/src/rule-scan.l +++ b/src/rule-scan.l @@ -132,6 +132,7 @@ same-ip return TOK_SAME_IP; src-ip return TOK_SRC_IP; src-port return TOK_SRC_PORT; tcp-state return TOK_TCP_STATE; +udp-state return TOK_UDP_STATE; active return TOK_ACTIVE; file-magic { rules_lval.val = zeek::detail::Rule::FILE_MAGIC; return TOK_PATTERN_TYPE; } diff --git a/testing/btest/Baseline/signatures.udp-state/out b/testing/btest/Baseline/signatures.udp-state/out new file mode 100644 index 0000000000..eb4d4bc78a --- /dev/null +++ b/testing/btest/Baseline/signatures.udp-state/out @@ -0,0 +1,10 @@ +signature_match [orig_h=192.168.17.58, orig_p=58755/udp, resp_h=8.8.8.8, resp_p=53/udp] - my_sig_udp_orig +0000 35 5e 01 00 00 01 00 00 00 00 00 00 06 67 6f 6f 5^...... .....goo +0010 67 6c 65 03 63 6f 6d 00 01 01 00 01 gle.com. .... + +signature_match [orig_h=192.168.17.58, orig_p=58755/udp, resp_h=8.8.8.8, resp_p=53/udp] - my_sig_udp_resp +0000 35 5e 81 80 00 01 00 01 00 00 00 00 06 67 6f 6f 5^...... .....goo +0010 67 6c 65 03 63 6f 6d 00 01 01 00 01 c0 0c 01 01 gle.com. ........ +0020 00 01 00 00 54 49 00 13 00 05 69 73 73 75 65 73 ....TI.. ..issues +0030 79 6d 61 6e 74 65 63 2e 63 6f 6d ymantec. com + diff --git a/testing/btest/Baseline/signatures.udp-state/reject b/testing/btest/Baseline/signatures.udp-state/reject new file mode 100644 index 0000000000..b495e79aa4 --- /dev/null +++ b/testing/btest/Baseline/signatures.udp-state/reject @@ -0,0 +1,2 @@ +error: Error in signature (udp-established.sig:5): 'established' is not a valid 'udp-state' + diff --git a/testing/btest/signatures/udp-state.zeek b/testing/btest/signatures/udp-state.zeek new file mode 100644 index 0000000000..13cb3d1b8a --- /dev/null +++ b/testing/btest/signatures/udp-state.zeek @@ -0,0 +1,36 @@ +# @TEST-EXEC: zeek -b -s udp-states.sig -r $TRACES/dns-caa.pcap %INPUT >out +# @TEST-EXEC-FAIL: zeek -b -s udp-established.sig -r $TRACES/dns-caa.pcap %INPUT >reject 2>&1 +# @TEST-EXEC: btest-diff out +# @TEST-EXEC: btest-diff reject + +@TEST-START-FILE udp-states.sig +signature my_sig_udp_orig { + ip-proto == udp + payload /.+/ + udp-state originator + event "my_sig_udp_orig" +} + +signature my_sig_udp_resp { + ip-proto == udp + payload /.+/ + udp-state responder + event "my_sig_udp_resp" +} +@TEST-END-FILE + +@TEST-START-FILE udp-established.sig +signature my_sig_udp_est { + ip-proto == udp + payload /.+/ + udp-state established + event "my_sig_udp_est" +} +@TEST-END-FILE + +event signature_match(state: signature_state, msg: string, data: string) + { + print fmt("signature_match %s - %s", state$conn$id, msg); + local s = split_string(hexdump(data), /\n/); + for ( i in s ) print s[i]; + }