diff --git a/aux/btest b/aux/btest index a9aeb2e1a8..acf25f34ab 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit a9aeb2e1a8434c583c75f5941b58dc69a7517444 +Subproject commit acf25f34ab48568f5db919c9e3505ed319daa4e5 diff --git a/policy.old/brolite-backdoor.bro b/policy.old/brolite-backdoor.bro index 496ee4e075..c2a378f907 100644 --- a/policy.old/brolite-backdoor.bro +++ b/policy.old/brolite-backdoor.bro @@ -14,7 +14,6 @@ @load site @load backdoor -@load alarm @load weird # By default, do backdoor detection on everything except standard HTTP diff --git a/policy.old/brolite-sigs.bro b/policy.old/brolite-sigs.bro index 82cc3f63bc..33b5be7730 100644 --- a/policy.old/brolite-sigs.bro +++ b/policy.old/brolite-sigs.bro @@ -4,7 +4,6 @@ # General policy - these scripts are more infrastructural than service # oriented, so in general avoid changing anything here. -@load alarm # open logging file for alarm events # Set global constant. This can be used in ifdef statements to determine # if signatures are enabled. diff --git a/policy.old/brolite.bro b/policy.old/brolite.bro index 79492143c1..36d9ad3653 100644 --- a/policy.old/brolite.bro +++ b/policy.old/brolite.bro @@ -190,6 +190,6 @@ redef notice_policy += { }; @endif -# Use tagged log files for alarms and notices. +# Use tagged log files for notices. redef use_tagging = T; diff --git a/policy.old/hand-over.bro b/policy.old/hand-over.bro index 0b3cf2f195..5c017c66b5 100644 --- a/policy.old/hand-over.bro +++ b/policy.old/hand-over.bro @@ -46,7 +46,7 @@ event bro_init() { # Disable packet processing. install_src_net_filter(0.0.0.0/0, 0, 100); - alarm "waiting for hand-over - packet processing disabled."; + # Reporter::message("waiting for hand-over - packet processing disabled."); } event remote_connection_error(p: event_peer, reason: string) @@ -55,7 +55,7 @@ event remote_connection_error(p: event_peer, reason: string) return; # Seems that the other side in not running. - alarm "can't connect for hand-over - starting processing ..."; + # Reporter::error("can't connect for hand-over - starting processing ..."); handover_start_processing(); } @@ -72,7 +72,7 @@ event remote_connection_established(p: event_peer) if ( ! is_handover_peer(p) ) return; - alarm fmt("requesting hand-over from %s:%d", p$host, p$p); + # Reporter::message(fmt("requesting hand-over from %s:%d", p$host, p$p)); request_remote_events(p, /handover_.*|finished_send_state/); @@ -85,7 +85,7 @@ event remote_connection_established(p: event_peer) # if the remote host is defined as a hand-over host in remote_peers. if ( is_handover_peer(p) ) { - alarm fmt("allowing hand-over from %s:%d", p$host, p$p); + # Reporter::message(fmt("allowing hand-over from %s:%d", p$host, p$p)); request_remote_events(p, /handover_.*|finished_send_state/); } } @@ -99,7 +99,7 @@ event handover_send_state(p: event_peer) # we will have to try again. if ( ! send_state(p) ) { - alarm "can't send state; serialization in progress"; + # Reporter::message("can't send state; serialization in progress"); schedule 5 secs { handover_send_state(p$host, p$p) }; } } @@ -124,8 +124,8 @@ event finished_send_state(p: event_peer) if ( ! is_handover_peer(p) ) return; - alarm fmt("full state received from %s:%d - starting processing ...", - p$host, p$p); + #Reporter::message(fmt("full state received from %s:%d - starting processing ...", + # p$host, p$p)); event handover_got_state(p); @@ -139,6 +139,6 @@ event handover_got_state(p: event_peer) if ( ! (is_remote_event() && is_it_us(p$host, p$p)) ) return; - alarm fmt("%s:%d received our state - terminating", p$host, p$p); + # Reporter::message(fmt("%s:%d received our state - terminating", p$host, p$p)); terminate(); } diff --git a/policy.old/hot.bro b/policy.old/hot.bro index c3434e3a3b..5c4fd6a395 100644 --- a/policy.old/hot.bro +++ b/policy.old/hot.bro @@ -85,7 +85,7 @@ function check_spoof(c: connection): bool service !in allow_spoof_services ) { if ( c$id$orig_p == service && orig == resp ) - event conn_weird("Land_attack", c); + event conn_weird("Land_attack", c, ""); if ( same_local_net_is_spoof ) ++c$hot; diff --git a/policy.old/http-body.bro b/policy.old/http-body.bro index 77c1c30680..4990a37341 100644 --- a/policy.old/http-body.bro +++ b/policy.old/http-body.bro @@ -53,8 +53,8 @@ event http_message_done(c: connection, is_orig: bool, stat: http_message_stat) # This can happen for multipart messages with a # 'content-length' header, which is not required for multipart # messages. - alarm fmt("length mismatch: %s %d %d %d", - id_string(c$id), stat$body_length, msg$data_length, - stat$content_gap_length); + # Log::warning(fmt("length mismatch: %s %d %d %d", + # id_string(c$id), stat$body_length, msg$data_length, + # stat$content_gap_length)); } } diff --git a/policy.old/mt.bro b/policy.old/mt.bro index 456708c4ea..1a39bc1025 100644 --- a/policy.old/mt.bro +++ b/policy.old/mt.bro @@ -1,6 +1,5 @@ # $Id: mt.bro 340 2004-09-09 06:38:27Z vern $ -@load alarm @load dns-lookup @load hot @load frag diff --git a/policy.old/remote-report-notices.bro b/policy.old/remote-report-notices.bro index 9b43ad865f..b70baf59c4 100644 --- a/policy.old/remote-report-notices.bro +++ b/policy.old/remote-report-notices.bro @@ -1,6 +1,6 @@ # $Id:$ # -# Forward remote alarms to our local system. +# Forward remote notices to our local system. event notice_action(n: notice_info, action: NoticeAction) { diff --git a/policy.old/ssl-worm.bro b/policy.old/ssl-worm.bro index a8db78eed3..40c9ce432e 100644 --- a/policy.old/ssl-worm.bro +++ b/policy.old/ssl-worm.bro @@ -2,7 +2,6 @@ @load signatures @load software -@load alarm redef signature_files += "ssl-worm.sig"; diff --git a/policy.old/stepping.bro b/policy.old/stepping.bro index e9aed914e1..9b7fe23031 100644 --- a/policy.old/stepping.bro +++ b/policy.old/stepping.bro @@ -4,7 +4,6 @@ @load port-name @load demux @load login -@load alarm module Stepping; diff --git a/policy.old/trw-impl.bro b/policy.old/trw-impl.bro index fc3fcd837a..a93782d11c 100644 --- a/policy.old/trw-impl.bro +++ b/policy.old/trw-impl.bro @@ -147,7 +147,7 @@ function check_TRW_scan(c: connection, state: string, reverse: bool): bool theta_one >= 1 || theta_one >= theta_zero ) { # Error: theta_zero should be between 0 and 1. - alarm "bad theta_zero/theta_one in check_TRW_scan"; + # Log::error("bad theta_zero/theta_one in check_TRW_scan"); use_TRW_algorithm = F; return F; } @@ -169,7 +169,7 @@ function check_TRW_scan(c: connection, state: string, reverse: bool): bool target_false_positive_prob >= 1 ) { # Error: target probabilities should be between 0 and 1 - alarm "bad target probabilities in check_TRW_scan"; + # Log::error("bad target probabilities in check_TRW_scan"); use_TRW_algorithm = F; return F; } diff --git a/policy/all.bro b/policy/all.bro index c6c4dac83c..ea9c591563 100644 --- a/policy/all.bro +++ b/policy/all.bro @@ -19,4 +19,4 @@ @load detectors/http-MHR -@load tuning/defaults \ No newline at end of file +@load tuning/defaults diff --git a/policy/bro.init b/policy/bro.init index 18f3c09cc1..3e71b7dfd9 100644 --- a/policy/bro.init +++ b/policy/bro.init @@ -291,11 +291,10 @@ type entropy_test_result: record { # Prototypes of Bro built-in functions. @load strings.bif.bro @load bro.bif.bro +@load reporter.bif.bro @load logging # sic! Not logging.bif. -global bro_alarm_file: file &redef; -global alarm_hook: function(msg: string): bool &redef; global log_file_name: function(tag: string): string &redef; global open_log_file: function(tag: string): file &redef; @@ -1482,3 +1481,20 @@ const parse_udp_tunnels = F &redef; #@load site #@load dpd + +# TODO: These need to go somewhere else with real implementations. +# +# event reporter_message(t: time, msg: string, location: string) +# { +# print fmt("[script] reporter_message: %s [%s] [%.6f]", msg, location, t); +# } +# +# event reporter_warning(t: time, msg: string, location: string) +# { +# print fmt("[script] reporter_warning: %s [%s] [%.6f]", msg, location, t); +# } +# +# event reporter_error(t: time, msg: string, location: string) +# { +# print fmt("[script] reporter_error: %s [%s] [%.6f]", msg, location, t); +# } diff --git a/policy/frameworks/logging/base.bro b/policy/frameworks/logging/base.bro index 410bc20da8..cdb7cbc575 100644 --- a/policy/frameworks/logging/base.bro +++ b/policy/frameworks/logging/base.bro @@ -206,4 +206,3 @@ function remove_default_filter(id: ID) : bool { return remove_filter(id, "default"); } - diff --git a/policy/frameworks/notice/weird.bro b/policy/frameworks/notice/weird.bro index 9a95c85374..9c2197d2f8 100644 --- a/policy/frameworks/notice/weird.bro +++ b/policy/frameworks/notice/weird.bro @@ -379,12 +379,7 @@ function report_weird_orig(t: time, name: string, id: string, orig: addr) report_weird(t, name, id, F, "", action, no_log); } -event conn_weird(name: string, c: connection) - { - report_weird_conn(network_time(), name, id_string(c$id), "", c); - } - -event conn_weird_addl(name: string, c: connection, addl: string) +event conn_weird(name: string, c: connection, addl: string) { report_weird_conn(network_time(), name, id_string(c$id), addl, c); } diff --git a/policy/protocols/dns/base.bro b/policy/protocols/dns/base.bro index 713964dc0d..47a0b893db 100644 --- a/policy/protocols/dns/base.bro +++ b/policy/protocols/dns/base.bro @@ -118,7 +118,7 @@ function set_session(c: connection, msg: dns_msg, is_query: bool) if ( c$dns?$total_replies && c$dns$total_replies != msg$num_answers + msg$num_addl + msg$num_auth ) { - event conn_weird_addl("dns_changed_number_of_responses", c, + event conn_weird("dns_changed_number_of_responses", c, fmt("The declared number of responses changed from %d to %d", c$dns$total_replies, msg$num_answers + msg$num_addl + msg$num_auth)); @@ -142,7 +142,7 @@ event do_reply(c: connection, msg: dns_msg, ans: dns_answer, reply: string) &pri if ( ans$answer_type == DNS_ANS ) { if ( msg$id in c$dns_state$finished_answers ) - event conn_weird("dns_reply_seen_after_done", c); + event conn_weird("dns_reply_seen_after_done", c, ""); if ( reply != "" ) { diff --git a/src/ARP.cc b/src/ARP.cc index 42b9d0e6f8..cdf0baa170 100644 --- a/src/ARP.cc +++ b/src/ARP.cc @@ -5,6 +5,7 @@ #include "ARP.h" #include "Event.h" +#include "Reporter.h" ARP_Analyzer::ARP_Analyzer() @@ -218,12 +219,7 @@ void ARP_Analyzer::BadARP(const struct arp_pkthdr* hdr, const char* msg) void ARP_Analyzer::Corrupted(const char* msg) { - if ( ! net_weird ) - return; - - val_list* vl = new val_list; - vl->append(new StringVal(msg)); - mgr.QueueEvent(net_weird, vl); + reporter->Weird(msg); } void ARP_Analyzer::RREvent(EventHandlerPtr e, diff --git a/src/Analyzer.cc b/src/Analyzer.cc index da81e54478..c0a29077af 100644 --- a/src/Analyzer.cc +++ b/src/Analyzer.cc @@ -916,12 +916,12 @@ void TransportLayerAnalyzer::Done() void TransportLayerAnalyzer::SetContentsFile(unsigned int /* direction */, BroFile* /* f */) { - run_time("analyzer type does not support writing to a contents file"); + reporter->Error("analyzer type does not support writing to a contents file"); } BroFile* TransportLayerAnalyzer::GetContentsFile(unsigned int /* direction */) const { - run_time("analyzer type does not support writing to a contents file"); + reporter->Error("analyzer type does not support writing to a contents file"); return 0; } diff --git a/src/Analyzer.h b/src/Analyzer.h index c889dc6b2f..3d29620a65 100644 --- a/src/Analyzer.h +++ b/src/Analyzer.h @@ -245,11 +245,8 @@ public: { conn->Event(f, this, v1, v2); } void ConnectionEvent(EventHandlerPtr f, val_list* vl) { conn->ConnectionEvent(f, this, vl); } - void Weird(const char* name) { conn->Weird(name); } - void Weird(const char* name, const char* addl) + void Weird(const char* name, const char* addl = "") { conn->Weird(name, addl); } - void Weird(const char* name, int addl_len, const char* addl) - { conn->Weird(name, addl_len, addl); }; // Factory function to instantiate new analyzers. static Analyzer* InstantiateAnalyzer(AnalyzerTag::Tag tag, Connection* c); diff --git a/src/Anon.cc b/src/Anon.cc index 2f44a6cddc..bd29b3cfe9 100644 --- a/src/Anon.cc +++ b/src/Anon.cc @@ -102,9 +102,9 @@ ipaddr32_t AnonymizeIPAddr_RandomMD5::anonymize(ipaddr32_t input) } -// This code is from "On the Design and Performance of Prefix-Preserving +// This code is from "On the Design and Performance of Prefix-Preserving // IP Traffic Trace Anonymization", by Xu et al (IMW 2001) -// +// // http://www.imconf.net/imw-2001/proceedings.html ipaddr32_t AnonymizeIPAddr_PrefixMD5::anonymize(ipaddr32_t input) @@ -159,7 +159,7 @@ int AnonymizeIPAddr_A50::PreservePrefix(ipaddr32_t input, int num_bits) if ( ! before_anonymization ) { - run_time("prefix perservation specified after anonymization begun"); + reporter->Error("prefix perservation specified after anonymization begun"); return 0; } @@ -206,7 +206,7 @@ AnonymizeIPAddr_A50::Node* AnonymizeIPAddr_A50::new_node_block() int block_size = 1024; Node* block = new Node[block_size]; if ( ! block ) - internal_error("out of memory!"); + reporter->InternalError("out of memory!"); blocks.push_back(block); @@ -258,7 +258,7 @@ ipaddr32_t AnonymizeIPAddr_A50::make_output(ipaddr32_t old_output, int swivel) c AnonymizeIPAddr_A50::Node* AnonymizeIPAddr_A50::make_peer(ipaddr32_t a, Node* n) { if ( a == 0 || a == 0xFFFFFFFFU ) - internal_error("0.0.0.0 and 255.255.255.255 should never get into the tree"); + reporter->InternalError("0.0.0.0 and 255.255.255.255 should never get into the tree"); // Become a peer. // Algorithm: create two nodes, the two peers. Leave orig node as @@ -341,7 +341,7 @@ AnonymizeIPAddr_A50::Node* AnonymizeIPAddr_A50::find_node(ipaddr32_t a) } } - internal_error("out of memory!"); + reporter->InternalError("out of memory!"); return 0; } @@ -379,24 +379,24 @@ ipaddr32_t anonymize_ip(ipaddr32_t ip, enum ip_addr_anonymization_class_t cl) } ipaddr32_t new_ip = 0; - + if ( preserve_addr && preserve_addr->Lookup(&addr) ) new_ip = ip; else if ( method >= 0 && method < NUM_ADDR_ANONYMIZATION_METHODS ) { - if ( method == KEEP_ORIG_ADDR ) + if ( method == KEEP_ORIG_ADDR ) new_ip = ip; else if ( ! ip_anonymizer[method] ) - internal_error("IP anonymizer not initialized"); + reporter->InternalError("IP anonymizer not initialized"); else new_ip = ip_anonymizer[method]->Anonymize(ip); } else - internal_error("invalid IP anonymization method"); + reporter->InternalError("invalid IP anonymization method"); #ifdef LOG_ANONYMIZATION_MAPPING log_anonymization_mapping(ip, new_ip); diff --git a/src/Anon.h b/src/Anon.h index 3368ce16da..2f138c36d7 100644 --- a/src/Anon.h +++ b/src/Anon.h @@ -18,6 +18,7 @@ #include using namespace std; +#include "Reporter.h" #include "net_util.h" // TODO: Anon.h may not be the right place to put these functions ... @@ -52,7 +53,7 @@ public: // Keep the specified prefix unchanged. virtual int PreservePrefix(ipaddr32_t /* input */, int /* num_bits */) { - internal_error("prefix preserving is not supported for the anonymizer"); + reporter->InternalError("prefix preserving is not supported for the anonymizer"); return 0; } diff --git a/src/Attr.cc b/src/Attr.cc index 73685ec8fa..22b4337405 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -19,7 +19,7 @@ const char* attr_name(attr_tag t) "&persistent", "&synchronized", "&postprocessor", "&encrypt", "&match", "&disable_print_hook", "&raw_output", "&mergeable", "&priority", - "&group", "&log", "(&tracked)", + "&group", "&log", "&error_handler", "(&tracked)", }; return attr_names[int(t)]; @@ -408,6 +408,12 @@ void Attributes::CheckAttr(Attr* a) Error("&group only applicable to events"); break; + case ATTR_ERROR_HANDLER: + if ( type->Tag() != TYPE_FUNC || + ! type->AsFuncType()->IsEvent() ) + Error("&error_handler only applicable to events"); + break; + case ATTR_LOG: if ( ! LogVal::IsCompatibleType(type) ) Error("&log applied to a type that cannot be logged"); diff --git a/src/Attr.h b/src/Attr.h index bdde98b4a7..89a81428e5 100644 --- a/src/Attr.h +++ b/src/Attr.h @@ -36,6 +36,7 @@ typedef enum { ATTR_PRIORITY, ATTR_GROUP, ATTR_LOG, + ATTR_ERROR_HANDLER, ATTR_TRACKED, // hidden attribute, tracked by NotifierRegistry #define NUM_ATTRS (int(ATTR_TRACKED) + 1) } attr_tag; diff --git a/src/Base64.cc b/src/Base64.cc index a82b2ee24a..2585debf5e 100644 --- a/src/Base64.cc +++ b/src/Base64.cc @@ -46,7 +46,7 @@ int Base64Decoder::Decode(int len, const char* data, int* pblen, char** pbuf) char* buf; if ( ! pbuf ) - internal_error("nil pointer to decoding result buffer"); + reporter->InternalError("nil pointer to decoding result buffer"); if ( *pbuf ) { diff --git a/src/Base64.h b/src/Base64.h index a8e7c01667..5bf5d4e2bc 100644 --- a/src/Base64.h +++ b/src/Base64.h @@ -46,7 +46,7 @@ public: if ( analyzer ) analyzer->Weird("base64_illegal_encoding", msg); else - run_time(msg); + reporter->Error(msg); } protected: diff --git a/src/BroString.cc b/src/BroString.cc index 1bbe0099f2..8677cd9533 100644 --- a/src/BroString.cc +++ b/src/BroString.cc @@ -11,6 +11,7 @@ #include "BroString.h" #include "Var.h" +#include "Reporter.h" #ifdef DEBUG #define DEBUG_STR(msg) DBG_LOG(DBG_STRING, msg) @@ -175,9 +176,9 @@ const char* BroString::CheckString() const // Either an embedded NUL, or no final NUL. char* exp_s = Render(); if ( b[n-1] != '\0' ) - run_time("string without NUL terminator: \"%s\"", exp_s); + reporter->Error("string without NUL terminator: \"%s\"", exp_s); else - run_time("string with embedded NUL: \"%s\"", exp_s); + reporter->Error("string with embedded NUL: \"%s\"", exp_s); delete [] exp_s; return ""; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 316a9cdf33..1a5f096f70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,6 +137,7 @@ set(BIF_SRCS const.bif types.bif strings.bif + reporter.bif ) foreach (bift ${BIF_SRCS}) @@ -326,7 +327,7 @@ set(bro_SRCS IOSource.cc IRC.cc List.cc - Logger.cc + Reporter.cc LogMgr.cc LogWriter.cc LogWriterAscii.cc diff --git a/src/ChunkedIO.cc b/src/ChunkedIO.cc index 9ca8f23508..d2eff510ce 100644 --- a/src/ChunkedIO.cc +++ b/src/ChunkedIO.cc @@ -195,7 +195,7 @@ bool ChunkedIOFd::WriteChunk(Chunk* chunk, bool partial) assert(chunk->len <= BUFFER_SIZE - sizeof(uint32) ); if ( chunk->len == 0 ) - internal_error( "attempt to write 0 bytes chunk"); + reporter->InternalError("attempt to write 0 bytes chunk"); if ( partial ) chunk->len |= FLAG_PARTIAL; @@ -285,7 +285,7 @@ bool ChunkedIOFd::FlushWriteBuffer() } if ( written == 0 ) - internal_error("written==0"); + reporter->InternalError("written==0"); // Short write. write_pos += written; @@ -906,7 +906,7 @@ bool ChunkedIOSSL::WriteData(char* p, uint32 len, bool* error) return false; } - internal_error("can't be reached"); + reporter->InternalError("can't be reached"); return false; } @@ -1026,7 +1026,7 @@ bool ChunkedIOSSL::ReadData(char* p, uint32 len, bool* error) } // Can't be reached. - internal_error("can't be reached"); + reporter->InternalError("can't be reached"); return false; } diff --git a/src/CompHash.cc b/src/CompHash.cc index 69b3d9c38d..605949b81c 100644 --- a/src/CompHash.cc +++ b/src/CompHash.cc @@ -6,6 +6,7 @@ #include "CompHash.h" #include "Val.h" +#include "Reporter.h" CompositeHash::CompositeHash(TypeList* composite_type) { @@ -191,7 +192,7 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0, } else { - internal_error("bad index type in CompositeHash::SingleValHash"); + reporter->InternalError("bad index type in CompositeHash::SingleValHash"); return 0; } } @@ -314,7 +315,7 @@ HashKey* CompositeHash::ComputeSingletonHash(const Val* v, int type_check) const if ( v->Type()->Tag() == TYPE_FUNC ) return new HashKey(v); - internal_error("bad index type in CompositeHash::ComputeSingletonHash"); + reporter->InternalError("bad index type in CompositeHash::ComputeSingletonHash"); return 0; case TYPE_INTERNAL_STRING: @@ -324,7 +325,7 @@ HashKey* CompositeHash::ComputeSingletonHash(const Val* v, int type_check) const return 0; default: - internal_error("bad internal type in CompositeHash::ComputeSingletonHash"); + reporter->InternalError("bad internal type in CompositeHash::ComputeSingletonHash"); return 0; } } @@ -399,7 +400,7 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v, } else { - internal_error("bad index type in CompositeHash::CompositeHash"); + reporter->InternalError("bad index type in CompositeHash::CompositeHash"); return 0; } } @@ -522,7 +523,7 @@ ListVal* CompositeHash::RecoverVals(const HashKey* k) const } if ( kp != k_end ) - internal_error("under-ran key in CompositeHash::DescribeKey %ld", k_end - kp); + reporter->InternalError("under-ran key in CompositeHash::DescribeKey %ld", k_end - kp); return l; } @@ -533,7 +534,7 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, { // k->Size() == 0 for a single empty string. if ( kp0 >= k_end && k->Size() > 0 ) - internal_error("over-ran key in CompositeHash::RecoverVals"); + reporter->InternalError("over-ran key in CompositeHash::RecoverVals"); TypeTag tag = t->Tag(); InternalTypeTag it = t->InternalType(); @@ -580,7 +581,7 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, break; default: - internal_error("bad internal unsigned int in CompositeHash::RecoverOneVal()"); + reporter->InternalError("bad internal unsigned int in CompositeHash::RecoverOneVal()"); pval = 0; break; } @@ -619,7 +620,7 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, break; default: - internal_error("bad internal address in CompositeHash::RecoverOneVal()"); + reporter->InternalError("bad internal address in CompositeHash::RecoverOneVal()"); pval = 0; break; } @@ -648,21 +649,21 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, Val* v = *kp; if ( ! v || ! v->Type() ) - internal_error("bad aggregate Val in CompositeHash::RecoverOneVal()"); + reporter->InternalError("bad aggregate Val in CompositeHash::RecoverOneVal()"); if ( t->Tag() != TYPE_FUNC && // ### Maybe fix later, but may be fundamentally // un-checkable --US ! same_type(v->Type(), t) ) { - internal_error("inconsistent aggregate Val in CompositeHash::RecoverOneVal()"); + reporter->InternalError("inconsistent aggregate Val in CompositeHash::RecoverOneVal()"); } // ### A crude approximation for now. if ( t->Tag() == TYPE_FUNC && v->Type()->Tag() != TYPE_FUNC ) { - internal_error("inconsistent aggregate Val in CompositeHash::RecoverOneVal()"); + reporter->InternalError("inconsistent aggregate Val in CompositeHash::RecoverOneVal()"); } pval = v->Ref(); @@ -687,7 +688,7 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, rt->FieldType(i), v, optional); if ( ! (v || optional) ) { - internal_error("didn't recover expected number of fields from HashKey"); + reporter->InternalError("didn't recover expected number of fields from HashKey"); pval = 0; break; } @@ -707,7 +708,7 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, } else { - internal_error("bad index type in CompositeHash::DescribeKey"); + reporter->InternalError("bad index type in CompositeHash::DescribeKey"); } } break; diff --git a/src/CompHash.h b/src/CompHash.h index d3bde770b8..e2f87d240b 100644 --- a/src/CompHash.h +++ b/src/CompHash.h @@ -34,7 +34,7 @@ protected: // Recovers just one Val of possibly many; called from RecoverVals. // Upon return, pval will point to the recovered Val of type t. - // Returns and updated kp for the next Val. Calls internal_error() + // Returns and updated kp for the next Val. Calls reporter->InternalError() // upon errors, so there is no return value for invalid input. const char* RecoverOneVal(const HashKey* k, const char* kp, const char* const k_end, diff --git a/src/Conn.cc b/src/Conn.cc index fbc53a9d9a..f777a12f57 100644 --- a/src/Conn.cc +++ b/src/Conn.cc @@ -11,7 +11,7 @@ #include "Conn.h" #include "Event.h" #include "Sessions.h" -#include "Logger.h" +#include "Reporter.h" #include "Timer.h" #include "PIA.h" #include "binpac.h" @@ -54,7 +54,7 @@ void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer, ConnectionTimer::~ConnectionTimer() { if ( conn->RefCnt() < 1 ) - internal_error("reference count inconsistency in ~ConnectionTimer"); + reporter->InternalError("reference count inconsistency in ~ConnectionTimer"); conn->RemoveTimer(this); Unref(conn); @@ -72,7 +72,7 @@ void ConnectionTimer::Dispatch(double t, int is_expire) (conn->*timer)(t); if ( conn->RefCnt() < 1 ) - internal_error("reference count inconsistency in ConnectionTimer::Dispatch"); + reporter->InternalError("reference count inconsistency in ConnectionTimer::Dispatch"); } IMPLEMENT_SERIAL(ConnectionTimer, SER_CONNECTION_TIMER); @@ -94,7 +94,7 @@ bool ConnectionTimer::DoSerialize(SerialInfo* info) const else if ( timer == timer_func(&Connection::RemoveConnectionTimer) ) type = 4; else - internal_error("unknown function in ConnectionTimer::DoSerialize()"); + reporter->InternalError("unknown function in ConnectionTimer::DoSerialize()"); return conn->Serialize(info) && SERIALIZE(type) && SERIALIZE(do_expire); } @@ -197,7 +197,7 @@ Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id) Connection::~Connection() { if ( ! finished ) - internal_error("Done() not called before destruction of Connection"); + reporter->InternalError("Done() not called before destruction of Connection"); CancelTimers(); @@ -636,54 +636,10 @@ void Connection::ConnectionEvent(EventHandlerPtr f, Analyzer* a, val_list* vl) a ? a->GetID() : 0, GetTimerMgr(), this); } -void Connection::Weird(const char* name) - { - weird = 1; - if ( conn_weird ) - Event(conn_weird, 0, name); - else - fprintf(stderr, "%.06f weird: %s\n", network_time, name); - } - void Connection::Weird(const char* name, const char* addl) { weird = 1; - if ( conn_weird_addl ) - { - val_list* vl = new val_list(3); - - vl->append(new StringVal(name)); - vl->append(BuildConnVal()); - vl->append(new StringVal(addl)); - - ConnectionEvent(conn_weird_addl, 0, vl); - } - - else - fprintf(stderr, "%.06f weird: %s (%s)\n", network_time, name, addl); - } - -void Connection::Weird(const char* name, int addl_len, const char* addl) - { - weird = 1; - if ( conn_weird_addl ) - { - val_list* vl = new val_list(3); - - vl->append(new StringVal(name)); - vl->append(BuildConnVal()); - vl->append(new StringVal(addl_len, addl)); - - ConnectionEvent(conn_weird_addl, 0, vl); - } - - else - { - fprintf(stderr, "%.06f weird: %s (", network_time, name); - for ( int i = 0; i < addl_len; ++i ) - fputc(addl[i], stderr); - fprintf(stderr, ")\n"); - } + reporter->Weird(this, name, addl ? addl : ""); } void Connection::AddTimer(timer_func timer, double t, int do_expire, @@ -794,7 +750,7 @@ void Connection::Describe(ODesc* d) const break; case TRANSPORT_UNKNOWN: - internal_error("unknown transport in Connction::Describe()"); + reporter->InternalError("unknown transport in Connction::Describe()"); break; } diff --git a/src/Conn.h b/src/Conn.h index 8c962b9bb7..8f817fd003 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -193,15 +193,13 @@ public: // Raises a software_unparsed_version_found event. int UnparsedVersionFoundEvent(const uint32* addr, const char* full_descr, int len, Analyzer* analyzer); - + void Event(EventHandlerPtr f, Analyzer* analyzer, const char* name = 0); void Event(EventHandlerPtr f, Analyzer* analyzer, Val* v1, Val* v2 = 0); void ConnectionEvent(EventHandlerPtr f, Analyzer* analyzer, val_list* vl); - void Weird(const char* name); - void Weird(const char* name, const char* addl); - void Weird(const char* name, int addl_len, const char* addl); + void Weird(const char* name, const char* addl = ""); bool DidWeird() const { return weird != 0; } // Cancel all associated timers. diff --git a/src/ConnCompressor.cc b/src/ConnCompressor.cc index 7c82b12af0..e173463205 100644 --- a/src/ConnCompressor.cc +++ b/src/ConnCompressor.cc @@ -663,7 +663,7 @@ const IP_Hdr* ConnCompressor::PendingConnToPacket(const PendingConn* c) // only an IPv4 address. #ifdef BROv6 if ( ! is_v4_addr(c->key.ip1) || ! is_v4_addr(c->key.ip2) ) - internal_error("IPv6 snuck into connection compressor"); + reporter->InternalError("IPv6 snuck into connection compressor"); #endif *(uint32*) &ip->ip_src = to_v4_addr(c->ip1_is_src ? c->key.ip1 : c->key.ip2); @@ -929,6 +929,14 @@ void ConnCompressor::Event(const PendingConn* pending, double t, conn_val->SetOrigin(0); } + if ( event == conn_weird ) + { + // Special case to go through the logger. + const char* msg = arg->AsString()->CheckString(); + reporter->Weird(conn_val->Ref(), msg); + return; + } + val_list* vl = new val_list; if ( arg ) vl->append(arg); diff --git a/src/ConnCompressor.h b/src/ConnCompressor.h index 040a120ba9..e2140526d0 100644 --- a/src/ConnCompressor.h +++ b/src/ConnCompressor.h @@ -165,11 +165,10 @@ private: void Weird(const PendingConn* pending, double t, const char* msg) { - if ( conn_weird ) - Event(pending, t, conn_weird, TCP_ENDPOINT_INACTIVE, 0, - TCP_ENDPOINT_INACTIVE, new StringVal(msg)); - else - fprintf(stderr, "%.06f weird: %s\n", t, msg); + // This will actually go through the Reporter; Event() takes + // care of that. + Event(pending, t, conn_weird, TCP_ENDPOINT_INACTIVE, 0, + TCP_ENDPOINT_INACTIVE, new StringVal(msg)); } static const int BLOCK_SIZE = 16 * 1024; diff --git a/src/ContentLine.cc b/src/ContentLine.cc index 5f58fa1f0c..e9f0856462 100644 --- a/src/ContentLine.cc +++ b/src/ContentLine.cc @@ -103,7 +103,7 @@ void ContentLine_Analyzer::DeliverStream(int len, const u_char* data, buf = tmp; if ( ! buf ) - internal_error("out of memory delivering endpoint line"); + reporter->InternalError("out of memory delivering endpoint line"); } DoDeliver(len, data); @@ -125,7 +125,7 @@ void ContentLine_Analyzer::EndpointEOF(bool is_orig) void ContentLine_Analyzer::SetPlainDelivery(int64_t length) { if ( length < 0 ) - internal_error("negative length for plain delivery"); + reporter->InternalError("negative length for plain delivery"); plain_delivery_length = length; } diff --git a/src/DCE_RPC.cc b/src/DCE_RPC.cc index c44b100aa5..4e21ecd545 100644 --- a/src/DCE_RPC.cc +++ b/src/DCE_RPC.cc @@ -60,7 +60,7 @@ UUID::UUID(const u_char d[16]) UUID::UUID(const binpac::bytestring& uuid) { if ( uuid.length() != 16 ) - internal_error("UUID length error"); + reporter->InternalError("UUID length error"); memcpy(data, uuid.begin(), 16); s = uuid_to_string(data); } @@ -82,7 +82,7 @@ UUID::UUID(const char* str) } if ( i != 16 ) - internal_error("invalid UUID string: %s", str); + reporter->InternalError("invalid UUID string: %s", str); } typedef map uuid_map_t; diff --git a/src/DNS_Mgr.cc b/src/DNS_Mgr.cc index 3c800e1f30..8776f69d55 100644 --- a/src/DNS_Mgr.cc +++ b/src/DNS_Mgr.cc @@ -35,6 +35,7 @@ #include "Event.h" #include "Net.h" #include "Var.h" +#include "Reporter.h" extern "C" { extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); @@ -359,7 +360,7 @@ DNS_Mgr::DNS_Mgr(DNS_MgrMode arg_mode) nb_dns = nb_dns_init(err); if ( ! nb_dns ) - warn(fmt("problem initializing NB-DNS: %s", err)); + reporter->Warning(fmt("problem initializing NB-DNS: %s", err)); dns_mapping_valid = dns_mapping_unverified = dns_mapping_new_name = dns_mapping_lost_name = dns_mapping_name_changed = @@ -446,7 +447,7 @@ TableVal* DNS_Mgr::LookupHost(const char* name) return d->Addrs()->ConvertToSet(); else { - warn("no such host:", name); + reporter->Warning("no such host:", name); return empty_addr_set(); } } @@ -459,7 +460,7 @@ TableVal* DNS_Mgr::LookupHost(const char* name) return empty_addr_set(); case DNS_FORCE: - internal_error("can't find DNS entry for %s in cache", name); + reporter->InternalError("can't find DNS entry for %s in cache", name); return 0; case DNS_DEFAULT: @@ -468,7 +469,7 @@ TableVal* DNS_Mgr::LookupHost(const char* name) return LookupHost(name); default: - internal_error("bad mode in DNS_Mgr::LookupHost"); + reporter->InternalError("bad mode in DNS_Mgr::LookupHost"); return 0; } } @@ -489,7 +490,7 @@ Val* DNS_Mgr::LookupAddr(uint32 addr) return d->Host(); else { - warn("can't resolve IP address:", dotted_addr(addr)); + reporter->Warning("can't resolve IP address:", dotted_addr(addr)); return new StringVal(dotted_addr(addr)); } } @@ -502,7 +503,7 @@ Val* DNS_Mgr::LookupAddr(uint32 addr) return new StringVal(""); case DNS_FORCE: - internal_error("can't find DNS entry for %s in cache", + reporter->InternalError("can't find DNS entry for %s in cache", dotted_addr(addr)); return 0; @@ -512,7 +513,7 @@ Val* DNS_Mgr::LookupAddr(uint32 addr) return LookupAddr(addr); default: - internal_error("bad mode in DNS_Mgr::LookupHost"); + reporter->InternalError("bad mode in DNS_Mgr::LookupHost"); return 0; } } @@ -573,7 +574,7 @@ void DNS_Mgr::Resolve() struct nb_dns_result r; status = nb_dns_activity(nb_dns, &r, err); if ( status < 0 ) - internal_error( + reporter->InternalError( "NB-DNS error in DNS_Mgr::WaitForReplies (%s)", err); else if ( status > 0 ) @@ -752,7 +753,7 @@ void DNS_Mgr::CompareMappings(DNS_Mapping* prev_dm, DNS_Mapping* new_dm) ListVal* new_a = new_dm->Addrs(); if ( ! prev_a || ! new_a ) - internal_error("confused in DNS_Mgr::CompareMappings"); + reporter->InternalError("confused in DNS_Mgr::CompareMappings"); ListVal* prev_delta = AddrListDelta(prev_a, new_a); ListVal* new_delta = AddrListDelta(new_a, prev_a); @@ -822,7 +823,7 @@ void DNS_Mgr::LoadCache(FILE* f) } if ( ! m->NoMapping() ) - internal_error("DNS cache corrupted"); + reporter->InternalError("DNS cache corrupted"); delete m; fclose(f); @@ -957,7 +958,7 @@ void DNS_Mgr::IssueAsyncRequests() if ( ! dr->MakeRequest(nb_dns) ) { - run_time("can't issue DNS request"); + reporter->Error("can't issue DNS request"); req->Timeout(); continue; } @@ -1070,7 +1071,7 @@ void DNS_Mgr::Process() int status = nb_dns_activity(nb_dns, &r, err); if ( status < 0 ) - internal_error("NB-DNS error in DNS_Mgr::Process (%s)", err); + reporter->InternalError("NB-DNS error in DNS_Mgr::Process (%s)", err); else if ( status > 0 ) { @@ -1094,7 +1095,7 @@ int DNS_Mgr::AnswerAvailable(int timeout) { int fd = nb_dns_fd(nb_dns); if ( fd < 0 ) - internal_error("nb_dns_fd() failed in DNS_Mgr::WaitForReplies"); + reporter->InternalError("nb_dns_fd() failed in DNS_Mgr::WaitForReplies"); fd_set read_fds; @@ -1111,11 +1112,11 @@ int DNS_Mgr::AnswerAvailable(int timeout) { if ( errno == EINTR ) return -1; - internal_error("problem with DNS select"); + reporter->InternalError("problem with DNS select"); } if ( status > 1 ) - internal_error("strange return from DNS select"); + reporter->InternalError("strange return from DNS select"); return status; } diff --git a/src/DPM.cc b/src/DPM.cc index 95c219182e..69b859a9e1 100644 --- a/src/DPM.cc +++ b/src/DPM.cc @@ -262,7 +262,7 @@ bool DPM::BuildInitialAnalyzerTree(TransportProto proto, Connection* conn, } default: - internal_error("unknown protocol"); + reporter->InternalError("unknown protocol"); } if ( ! root ) diff --git a/src/DbgBreakpoint.cc b/src/DbgBreakpoint.cc index a71a6fc186..7205a78521 100644 --- a/src/DbgBreakpoint.cc +++ b/src/DbgBreakpoint.cc @@ -204,7 +204,10 @@ bool DbgBreakpoint::Reset() break; } - internal_error("DbgBreakpoint::Reset function incomplete."); + reporter->InternalError("DbgBreakpoint::Reset function incomplete."); + + // Cannot be reached. + return false; } bool DbgBreakpoint::SetCondition(const string& new_condition) @@ -292,7 +295,7 @@ BreakCode DbgBreakpoint::ShouldBreak(Stmt* s) assert(false); default: - internal_error("Invalid breakpoint type in DbgBreakpoint::ShouldBreak"); + reporter->InternalError("Invalid breakpoint type in DbgBreakpoint::ShouldBreak"); } // If we got here, that means that the breakpoint could hit, @@ -309,7 +312,7 @@ BreakCode DbgBreakpoint::ShouldBreak(Stmt* s) BreakCode DbgBreakpoint::ShouldBreak(double t) { if ( kind != BP_TIME ) - internal_error("Calling ShouldBreak(time) on a non-time breakpoint"); + reporter->InternalError("Calling ShouldBreak(time) on a non-time breakpoint"); if ( t < at_time ) return bcNoHit; @@ -350,6 +353,6 @@ void DbgBreakpoint::PrintHitMsg() assert(false); default: - internal_error("Missed a case in DbgBreakpoint::PrintHitMsg\n"); + reporter->InternalError("Missed a case in DbgBreakpoint::PrintHitMsg\n"); } } diff --git a/src/DbgWatch.cc b/src/DbgWatch.cc index 75f9b9c4af..74ac26cb73 100644 --- a/src/DbgWatch.cc +++ b/src/DbgWatch.cc @@ -4,16 +4,17 @@ #include "Debug.h" #include "DbgWatch.h" +#include "Reporter.h" // Support classes DbgWatch::DbgWatch(BroObj* var_to_watch) { - internal_error("DbgWatch unimplemented"); + reporter->InternalError("DbgWatch unimplemented"); } DbgWatch::DbgWatch(Expr* expr_to_watch) { - internal_error("DbgWatch unimplemented"); + reporter->InternalError("DbgWatch unimplemented"); } DbgWatch::~DbgWatch() diff --git a/src/Debug.cc b/src/Debug.cc index 6a0bbfdbb7..7b6dcfdb68 100644 --- a/src/Debug.cc +++ b/src/Debug.cc @@ -54,7 +54,7 @@ DebuggerState::~DebuggerState() bool StmtLocMapping::StartsAfter(const StmtLocMapping* m2) { if ( ! m2 ) - internal_error("Assertion failed: %s", "m2 != 0"); + reporter->InternalError("Assertion failed: %s", "m2 != 0"); return loc.first_line > m2->loc.first_line || (loc.first_line == m2->loc.first_line && @@ -362,7 +362,7 @@ vector parse_location_string(const string& s) { Filemap* map = g_dbgfilemaps.Lookup(loc_filename); if ( ! map ) - internal_error("Policy file %s should have been loaded\n", + reporter->InternalError("Policy file %s should have been loaded\n", loc_filename); if ( plr.line > how_many_lines_in(loc_filename) ) @@ -603,7 +603,7 @@ int dbg_execute_command(const char* cmd) #endif if ( int(cmd_code) >= num_debug_cmds() ) - internal_error("Assertion failed: %s", "int(cmd_code) < num_debug_cmds()"); + reporter->InternalError("Assertion failed: %s", "int(cmd_code) < num_debug_cmds()"); // Dispatch to the op-specific handler (with args). int retcode = dbg_dispatch_cmd(cmd_code, arguments); @@ -612,7 +612,7 @@ int dbg_execute_command(const char* cmd) const DebugCmdInfo* info = get_debug_cmd_info(cmd_code); if ( ! info ) - internal_error("Assertion failed: %s", "info"); + reporter->InternalError("Assertion failed: %s", "info"); if ( ! info ) return -2; // ### yuck, why -2? @@ -766,7 +766,7 @@ int dbg_handle_debug_input() const Stmt* stmt = curr_frame->GetNextStmt(); if ( ! stmt ) - internal_error("Assertion failed: %s", "stmt != 0"); + reporter->InternalError("Assertion failed: %s", "stmt != 0"); const Location loc = *stmt->GetLocationInfo(); @@ -872,7 +872,7 @@ bool pre_execute_stmt(Stmt* stmt, Frame* f) p = g_debugger_state.breakpoint_map.equal_range(stmt); if ( p.first == p.second ) - internal_error("Breakpoint count nonzero, but no matching breakpoints"); + reporter->InternalError("Breakpoint count nonzero, but no matching breakpoints"); for ( BPMapType::iterator i = p.first; i != p.second; ++i ) { @@ -943,11 +943,11 @@ Val* dbg_eval_expr(const char* expr) (g_frame_stack.size() - 1) - g_debugger_state.curr_frame_idx; if ( ! (frame_idx >= 0 && (unsigned) frame_idx < g_frame_stack.size()) ) - internal_error("Assertion failed: %s", "frame_idx >= 0 && (unsigned) frame_idx < g_frame_stack.size()"); + reporter->InternalError("Assertion failed: %s", "frame_idx >= 0 && (unsigned) frame_idx < g_frame_stack.size()"); Frame* frame = g_frame_stack[frame_idx]; if ( ! (frame) ) - internal_error("Assertion failed: %s", "frame"); + reporter->InternalError("Assertion failed: %s", "frame"); const BroFunc* func = frame->GetFunction(); if ( func ) diff --git a/src/DebugCmds.cc b/src/DebugCmds.cc index a26e6a9567..1d3b9dd220 100644 --- a/src/DebugCmds.cc +++ b/src/DebugCmds.cc @@ -194,7 +194,7 @@ static int dbg_backtrace_internal(int start, int end) if ( start < 0 || end < 0 || (unsigned) start >= g_frame_stack.size() || (unsigned) end >= g_frame_stack.size() ) - internal_error("Invalid stack frame index in DbgBacktraceInternal\n"); + reporter->InternalError("Invalid stack frame index in DbgBacktraceInternal\n"); if ( start < end ) { @@ -325,7 +325,7 @@ int dbg_cmd_frame(DebugCmd cmd, const vector& args) // for 'list', 'break', etc. const Stmt* stmt = g_frame_stack[user_frame_number]->GetNextStmt(); if ( ! stmt ) - internal_error("Assertion failed: %s", "stmt != 0"); + reporter->InternalError("Assertion failed: %s", "stmt != 0"); const Location loc = *stmt->GetLocationInfo(); g_debugger_state.last_loc = loc; @@ -365,7 +365,7 @@ int dbg_cmd_break(DebugCmd cmd, const vector& args) Stmt* stmt = g_frame_stack[user_frame_number]->GetNextStmt(); if ( ! stmt ) - internal_error("Assertion failed: %s", "stmt != 0"); + reporter->InternalError("Assertion failed: %s", "stmt != 0"); DbgBreakpoint* bp = new DbgBreakpoint(); bp->SetID(g_debugger_state.NextBPID()); @@ -530,7 +530,7 @@ int dbg_cmd_break_set_state(DebugCmd cmd, const vector& args) break; default: - internal_error("Invalid command in DbgCmdBreakSetState\n"); + reporter->InternalError("Invalid command in DbgCmdBreakSetState\n"); } } diff --git a/src/DebugLogger.cc b/src/DebugLogger.cc index 3c9dbad363..326371d981 100644 --- a/src/DebugLogger.cc +++ b/src/DebugLogger.cc @@ -28,10 +28,7 @@ DebugLogger::DebugLogger(const char* filename) file = fopen(filename, "w"); if ( ! file ) - { - fprintf(stderr, "Can't open '%s' for debugging output.", filename); - exit(1); - } + reporter->FatalError("can't open '%s' for debugging output.", filename); setvbuf(file, NULL, _IOLBF, 0); } @@ -68,7 +65,7 @@ void DebugLogger::EnableStreams(const char* s) if ( strcasecmp("verbose", tok) == 0 ) verbose = true; else - internal_error("unknown debug stream %s\n", tok); + reporter->InternalError("unknown debug stream %s\n", tok); } tok = strtok(0, ","); diff --git a/src/Desc.cc b/src/Desc.cc index c15a461bb2..e49ec31a2f 100644 --- a/src/Desc.cc +++ b/src/Desc.cc @@ -9,6 +9,7 @@ #include "Desc.h" #include "File.h" +#include "Reporter.h" #define DEFAULT_SIZE 128 #define SLOP 10 @@ -72,14 +73,14 @@ void ODesc::PushIndent() void ODesc::PopIndent() { if ( --indent_level < 0 ) - internal_error("ODesc::PopIndent underflow"); + reporter->InternalError("ODesc::PopIndent underflow"); NL(); } void ODesc::PopIndentNoNL() { if ( --indent_level < 0 ) - internal_error("ODesc::PopIndent underflow"); + reporter->InternalError("ODesc::PopIndent underflow"); } void ODesc::Add(const char* s, int do_indent) @@ -288,7 +289,7 @@ void ODesc::AddBytesRaw(const void* bytes, unsigned int n) if ( ! write_failed ) // Most likely it's a "disk full" so report // subsequent failures only once. - run_time(fmt("error writing to %s: %s", f->Name(), strerror(errno))); + reporter->Error(fmt("error writing to %s: %s", f->Name(), strerror(errno))); write_failed = true; return; @@ -324,5 +325,5 @@ void ODesc::Grow(unsigned int n) void ODesc::OutOfMemory() { - internal_error("out of memory"); + reporter->InternalError("out of memory"); } diff --git a/src/Dict.cc b/src/Dict.cc index 642ceabbb4..6bef17ad3e 100644 --- a/src/Dict.cc +++ b/src/Dict.cc @@ -9,6 +9,7 @@ #endif #include "Dict.h" +#include "Reporter.h" // If the mean bucket length exceeds the following then Insert() will // increase the size of the hash table. @@ -474,7 +475,7 @@ void Dictionary::StartChangeSize(int new_size) return; if ( tbl2 ) - internal_error("Dictionary::StartChangeSize() tbl2 not NULL"); + reporter->InternalError("Dictionary::StartChangeSize() tbl2 not NULL"); Init2(new_size); @@ -521,7 +522,7 @@ void Dictionary::FinishChangeSize() { // Cheap safety check. if ( num_entries != 0 ) - internal_error( + reporter->InternalError( "Dictionary::FinishChangeSize: num_entries is %d\n", num_entries); diff --git a/src/Event.cc b/src/Event.cc index f761cc4d08..0ba5b68a21 100644 --- a/src/Event.cc +++ b/src/Event.cc @@ -93,7 +93,7 @@ void EventMgr::QueueEvent(Event* event) void EventMgr::Dispatch() { if ( ! head ) - internal_error("EventMgr underflow"); + reporter->InternalError("EventMgr underflow"); Event* current = head; diff --git a/src/Event.h b/src/Event.h index 9028ca5fab..ce498ae9cc 100644 --- a/src/Event.h +++ b/src/Event.h @@ -40,10 +40,16 @@ protected: event_serializer->Serialize(&info, handler->Name(), args); } + if ( handler->ErrorHandler() ) + reporter->BeginErrorHandler(); + handler->Call(args, no_remote); if ( obj ) // obj->EventDone(); Unref(obj); + + if ( handler->ErrorHandler() ) + reporter->EndErrorHandler(); } EventHandlerPtr handler; diff --git a/src/EventHandler.cc b/src/EventHandler.cc index 9cc5306c9c..9a06763bc0 100644 --- a/src/EventHandler.cc +++ b/src/EventHandler.cc @@ -13,6 +13,7 @@ EventHandler::EventHandler(const char* arg_name) local = 0; type = 0; group = 0; + error_handler = false; enabled = true; } diff --git a/src/EventHandler.h b/src/EventHandler.h index 4320134d50..6a9438fd4c 100644 --- a/src/EventHandler.h +++ b/src/EventHandler.h @@ -36,8 +36,13 @@ public: // Returns true if there is at least one local or remote handler. operator bool() const; - void SetUsed() { used = true; } - bool Used() { return used; } + void SetUsed() { used = true; } + bool Used() { return used; } + + // Handlers marked as error handlers will not be called recursively to + // avoid infinite loops if they trigger a similar error themselves. + void SetErrorHandler() { error_handler = true; } + bool ErrorHandler() { return error_handler; } const char* Group() { return group; } void SetGroup(const char* arg_group) @@ -57,6 +62,7 @@ private: FuncType* type; bool used; // this handler is indeed used somewhere bool enabled; + bool error_handler; // this handler reports error messages. declare(List, SourceID); typedef List(SourceID) receiver_list; @@ -74,6 +80,9 @@ public: const EventHandlerPtr& operator=(const EventHandlerPtr& h) { handler = h.handler; return *this; } + bool operator==(const EventHandlerPtr& h) const + { return handler == h.handler; } + EventHandler* Ptr() { return handler; } operator bool() const { return handler && *handler; } diff --git a/src/EventRegistry.cc b/src/EventRegistry.cc index d7f672c2e5..f5691ab448 100644 --- a/src/EventRegistry.cc +++ b/src/EventRegistry.cc @@ -91,11 +91,20 @@ void EventRegistry::SetGroup(const char* name, const char* group) { EventHandler* eh = Lookup(name); if ( ! eh ) - internal_error("unknown event handler in SetGroup()"); + reporter->InternalError("unknown event handler in SetGroup()"); eh->SetGroup(group); } +void EventRegistry::SetErrorHandler(const char* name) + { + EventHandler* eh = Lookup(name); + if ( ! eh ) + reporter->InternalError("unknown event handler in SetErrorHandler()"); + + eh->SetErrorHandler(); + } + void EventRegistry::EnableGroup(const char* group, bool enable) { IterCookie* c = handlers.InitForIteration(); diff --git a/src/EventRegistry.h b/src/EventRegistry.h index 980b8ea83f..bd9e0cd185 100644 --- a/src/EventRegistry.h +++ b/src/EventRegistry.h @@ -31,6 +31,11 @@ public: // Associates a group with the given event. void SetGroup(const char* name, const char* group); + // Marks a handler as handling errors. Error handler will not be called + // recursively to avoid infinite loops in case they trigger an error + // themselves. + void SetErrorHandler(const char* name); + // Enable/disable all members of the group. void EnableGroup(const char* group, bool enable); diff --git a/src/Expr.cc b/src/Expr.cc index c3589facca..d748808041 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -300,7 +300,7 @@ Val* NameExpr::Eval(Frame* f) const return v->Ref(); else { - RunTime("value used but not set"); + Error("value used but not set"); return 0; } } @@ -383,7 +383,7 @@ bool NameExpr::DoUnserialize(UnserialInfo* info) if ( id ) ::Ref(id); else - run_time("unserialized unknown global name"); + reporter->Warning("unserialized unknown global name"); delete [] name; } @@ -626,7 +626,7 @@ Val* BinaryExpr::Eval(Frame* f) const if ( v_op1->Size() != v_op2->Size() ) { - RunTime("vector operands are of different sizes"); + Error("vector operands are of different sizes"); return 0; } @@ -1040,7 +1040,7 @@ Val* IncrExpr::DoSingleEval(Frame* f, Val* v) const if ( k < 0 && v->Type()->InternalType() == TYPE_INTERNAL_UNSIGNED ) - RunTime("count underflow"); + Error("count underflow"); } BroType* ret_type = Type(); @@ -1959,7 +1959,7 @@ Val* BoolExpr::Eval(Frame* f) const if ( vec_v1->Size() != vec_v2->Size() ) { - RunTime("vector operands have different sizes"); + Error("vector operands have different sizes"); return 0; } @@ -2341,7 +2341,7 @@ Val* CondExpr::Eval(Frame* f) const if ( cond->Size() != a->Size() || a->Size() != b->Size() ) { - RunTime("vectors in conditional expression have different sizes"); + Error("vectors in conditional expression have different sizes"); return 0; } @@ -2942,7 +2942,7 @@ Val* IndexExpr::Eval(Frame* f) const { if ( v_v1->Size() != v_v2->Size() ) { - RunTime("size mismatch, boolean index and vector"); + Error("size mismatch, boolean index and vector"); return 0; } @@ -2989,7 +2989,7 @@ Val* IndexExpr::Fold(Val* v1, Val* v2) const if ( v ) return v->Ref(); - RunTime("no such index"); + Error("no such index"); return 0; } @@ -4894,7 +4894,7 @@ Val* ListExpr::Eval(Frame* f) const Val* ev = exprs[i]->Eval(f); if ( ! ev ) { - RunTime("uninitialized list value"); + Error("uninitialized list value"); return 0; } @@ -5623,7 +5623,7 @@ int same_expr(const Expr* e1, const Expr* e2) } default: - internal_error("bad tag in same_expr()"); + reporter->InternalError("bad tag in same_expr()"); } return 0; @@ -5643,7 +5643,7 @@ static Expr* make_constant(BroType* t, double d) case TYPE_INTERNAL_DOUBLE: v = new Val(double(d), t->Tag()); break; default: - internal_error("bad type in make_constant()"); + reporter->InternalError("bad type in make_constant()"); } return new ConstExpr(v); diff --git a/src/File.cc b/src/File.cc index 2e6929fc89..c8390c9bb5 100644 --- a/src/File.cc +++ b/src/File.cc @@ -30,6 +30,7 @@ #include "Net.h" #include "Serializer.h" #include "Event.h" +#include "Reporter.h" // Timer which on dispatching rotates the file. class RotateTimer : public Timer { @@ -93,7 +94,7 @@ static int maximize_num_fds() #else struct rlimit rl; if ( getrlimit(RLIMIT_NOFILE, &rl) < 0 ) - internal_error("maximize_num_fds(): getrlimit failed"); + reporter->InternalError("maximize_num_fds(): getrlimit failed"); if ( rl.rlim_max == RLIM_INFINITY ) { @@ -109,7 +110,7 @@ static int maximize_num_fds() rl.rlim_cur = rl.rlim_max; if ( setrlimit(RLIMIT_NOFILE, &rl) < 0 ) - internal_error("maximize_num_fds(): setrlimit failed"); + reporter->InternalError("maximize_num_fds(): setrlimit failed"); return rl.rlim_cur / 2; #endif @@ -150,7 +151,7 @@ BroFile::BroFile(const char* arg_name, const char* arg_access, BroType* arg_t) t = arg_t ? arg_t : base_type(TYPE_STRING); if ( ! Open() ) { - error(fmt("cannot open %s: %s", name, strerror(errno))); + reporter->Error(fmt("cannot open %s: %s", name, strerror(errno))); is_open = 0; okay_to_manage = 0; } @@ -272,7 +273,7 @@ FILE* BroFile::File() FILE* BroFile::BringIntoCache() { if ( f ) - internal_error("BroFile non-nil non-open file"); + reporter->InternalError("BroFile non-nil non-open file"); if ( num_files_in_cache >= max_files_in_cache ) PurgeCache(); @@ -286,12 +287,12 @@ FILE* BroFile::BringIntoCache() if ( ! f ) { - run_time("can't open %s", this); + reporter->Error("can't open %s", this); f = fopen("/dev/null", "w"); if ( ! f ) - internal_error("out of file descriptors"); + reporter->InternalError("out of file descriptors"); okay_to_manage = 0; return f; @@ -301,7 +302,7 @@ FILE* BroFile::BringIntoCache() UpdateFileSize(); if ( fseek(f, position, SEEK_SET) < 0 ) - run_time("reopen seek failed", this); + reporter->Error("reopen seek failed", this); InsertAtBeginning(); @@ -314,7 +315,7 @@ FILE* BroFile::Seek(long new_position) return 0; if ( fseek(f, new_position, SEEK_SET) < 0 ) - run_time("seek failed", this); + reporter->Error("seek failed", this); return f; } @@ -325,7 +326,7 @@ void BroFile::SetBuf(bool arg_buffered) return; if ( setvbuf(f, NULL, arg_buffered ? _IOFBF : _IOLBF, 0) != 0 ) - run_time("setvbuf failed", this); + reporter->Error("setvbuf failed", this); buffered = arg_buffered; } @@ -376,18 +377,18 @@ int BroFile::Close() void BroFile::Suspend() { if ( ! is_in_cache ) - internal_error("BroFile::Suspend() called for non-cached file"); + reporter->InternalError("BroFile::Suspend() called for non-cached file"); if ( ! is_open ) - internal_error("BroFile::Suspend() called for non-open file"); + reporter->InternalError("BroFile::Suspend() called for non-open file"); Unlink(); if ( ! f ) - internal_error("BroFile::Suspend() called for nil file"); + reporter->InternalError("BroFile::Suspend() called for nil file"); if ( (position = ftell(f)) < 0 ) { - run_time("ftell failed", this); + reporter->Error("ftell failed", this); position = 0; } @@ -398,7 +399,7 @@ void BroFile::Suspend() void BroFile::PurgeCache() { if ( ! tail ) - internal_error("BroFile purge of empty cache"); + reporter->InternalError("BroFile purge of empty cache"); tail->Suspend(); } @@ -418,13 +419,13 @@ void BroFile::Unlink() Next()->SetPrev(prev); if ( (head || tail) && ! (head && tail) ) - internal_error("BroFile link list botch"); + reporter->InternalError("BroFile link list botch"); is_in_cache = 0; prev = next = 0; if ( --num_files_in_cache < 0 ) - internal_error("BroFile underflow of file cache"); + reporter->InternalError("BroFile underflow of file cache"); } } @@ -444,7 +445,7 @@ void BroFile::InsertAtBeginning() } if ( ++num_files_in_cache > max_files_in_cache ) - internal_error("BroFile overflow of file cache"); + reporter->InternalError("BroFile overflow of file cache"); is_in_cache = 1; } @@ -455,7 +456,7 @@ void BroFile::MoveToBeginning() return; // already at the beginning if ( ! is_in_cache || ! prev ) - internal_error("BroFile inconsistency in MoveToBeginning()"); + reporter->InternalError("BroFile inconsistency in MoveToBeginning()"); Unlink(); InsertAtBeginning(); @@ -642,7 +643,7 @@ void BroFile::InitEncrypt(const char* keyfile) if ( ! key ) { - error(fmt("can't open key file %s: %s", keyfile, strerror(errno))); + reporter->Error(fmt("can't open key file %s: %s", keyfile, strerror(errno))); Close(); return; } @@ -650,7 +651,7 @@ void BroFile::InitEncrypt(const char* keyfile) pub_key = PEM_read_PUBKEY(key, 0, 0, 0); if ( ! pub_key ) { - error(fmt("can't read key from %s: %s", keyfile, + reporter->Error(fmt("can't read key from %s: %s", keyfile, ERR_error_string(ERR_get_error(), 0))); Close(); return; @@ -672,7 +673,7 @@ void BroFile::InitEncrypt(const char* keyfile) if ( ! EVP_SealInit(cipher_ctx, cipher_type, &psecret, (int*) &secret_len, iv, &pub_key, 1) ) { - error(fmt("can't init cipher context for %s: %s", keyfile, + reporter->Error(fmt("can't init cipher context for %s: %s", keyfile, ERR_error_string(ERR_get_error(), 0))); Close(); return; @@ -685,7 +686,7 @@ void BroFile::InitEncrypt(const char* keyfile) fwrite(secret, ntohl(secret_len), 1, f) && fwrite(iv, iv_len, 1, f)) ) { - error(fmt("can't write header to log file %s: %s", + reporter->Error(fmt("can't write header to log file %s: %s", name, strerror(errno))); Close(); return; @@ -710,7 +711,7 @@ void BroFile::FinishEncrypt() if ( outl && ! fwrite(cipher_buffer, outl, 1, f) ) { - run_time(fmt("write error for %s: %s", + reporter->Error(fmt("write error for %s: %s", name, strerror(errno))); return; } @@ -742,7 +743,7 @@ int BroFile::Write(const char* data, int len) if ( ! EVP_SealUpdate(cipher_ctx, cipher_buffer, &outl, (unsigned char*)data, inl) ) { - run_time(fmt("encryption error for %s: %s", + reporter->Error(fmt("encryption error for %s: %s", name, ERR_error_string(ERR_get_error(), 0))); Close(); @@ -751,7 +752,7 @@ int BroFile::Write(const char* data, int len) if ( outl && ! fwrite(cipher_buffer, outl, 1, f) ) { - run_time(fmt("write error for %s: %s", + reporter->Error(fmt("write error for %s: %s", name, strerror(errno))); Close(); return 0; @@ -799,7 +800,7 @@ void BroFile::UpdateFileSize() struct stat s; if ( fstat(fileno(f), &s) < 0 ) { - run_time(fmt("can't stat fd for %s: %s", name, strerror(errno))); + reporter->Error(fmt("can't stat fd for %s: %s", name, strerror(errno))); current_size = 0; return; } diff --git a/src/FileAnalyzer.cc b/src/FileAnalyzer.cc index 17d3ad1dbc..16bf003775 100644 --- a/src/FileAnalyzer.cc +++ b/src/FileAnalyzer.cc @@ -3,6 +3,7 @@ #include #include "FileAnalyzer.h" +#include "Reporter.h" #ifdef HAVE_LIBMAGIC magic_t File_Analyzer::magic = 0; @@ -75,11 +76,11 @@ void File_Analyzer::InitMagic(magic_t* magic, int flags) *magic = magic_open(flags); if ( ! *magic ) - error(fmt("can't init libmagic: %s", magic_error(*magic))); + reporter->Error(fmt("can't init libmagic: %s", magic_error(*magic))); else if ( magic_load(*magic, 0) < 0 ) { - error(fmt("can't load magic file: %s", magic_error(*magic))); + reporter->Error(fmt("can't load magic file: %s", magic_error(*magic))); magic_close(*magic); *magic = 0; } diff --git a/src/FlowSrc.cc b/src/FlowSrc.cc index 4f94d7e4a8..6f31cf2c3e 100644 --- a/src/FlowSrc.cc +++ b/src/FlowSrc.cc @@ -77,7 +77,7 @@ int FlowSocketSrc::ExtractNextPDU() (struct sockaddr*) &from, &fromlen); if ( pdu_len < 0 ) { - run_time("problem reading NetFlow data from socket"); + reporter->Error("problem reading NetFlow data from socket"); data = 0; next_timestamp = -1.0; closed = 1; @@ -86,7 +86,7 @@ int FlowSocketSrc::ExtractNextPDU() if ( fromlen != sizeof(from) ) { - run_time("malformed NetFlow PDU"); + reporter->Error("malformed NetFlow PDU"); return 0; } @@ -171,7 +171,7 @@ int FlowFileSrc::ExtractNextPDU() if ( pdu_header.pdu_length > NF_MAX_PKT_SIZE ) { - run_time("NetFlow packet too long"); + reporter->Error("NetFlow packet too long"); // Safely skip over the too-long PDU. if ( lseek(selectable_fd, pdu_header.pdu_length, SEEK_CUR) < 0 ) diff --git a/src/Frag.cc b/src/Frag.cc index b8cc5b5776..abf68baa14 100644 --- a/src/Frag.cc +++ b/src/Frag.cc @@ -24,7 +24,7 @@ void FragTimer::Dispatch(double t, int /* is_expire */) if ( f ) f->Expire(t); else - internal_error("fragment timer dispatched w/o reassembler"); + reporter->InternalError("fragment timer dispatched w/o reassembler"); } FragReassembler::FragReassembler(NetSessions* arg_s, @@ -209,7 +209,7 @@ void FragReassembler::BlockInserted(DataBlock* /* start_block */) break; if ( b->upper > n ) - internal_error("bad fragment reassembly"); + reporter->InternalError("bad fragment reassembly"); memcpy((void*) &pkt[b->seq], (const void*) b->block, b->upper - b->seq); diff --git a/src/Func.cc b/src/Func.cc index 580a363d18..a6e31a0dd7 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -48,6 +48,7 @@ #include "RemoteSerializer.h" #include "Event.h" #include "Traverse.h" +#include "Reporter.h" extern RETSIGTYPE sig_handler(int signo); @@ -333,7 +334,7 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const (flow != FLOW_RETURN /* we fell off the end */ || ! result /* explicit return with no result */) && ! f->HasDelayed() ) - warn("non-void function returns without a value:", id->Name()); + reporter->Warning("non-void function returns without a value:", id->Name()); if ( result && g_trace_state.DoTrace() ) { @@ -425,9 +426,9 @@ BuiltinFunc::BuiltinFunc(built_in_func arg_func, const char* arg_name, id = lookup_ID(name, GLOBAL_MODULE_NAME, false); if ( ! id ) - internal_error("built-in function %s missing", name); + reporter->InternalError("built-in function %s missing", name); if ( id->HasVal() ) - internal_error("built-in function %s multiply defined", name); + reporter->InternalError("built-in function %s multiply defined", name); id->SetVal(new Val(this)); } @@ -499,20 +500,22 @@ bool BuiltinFunc::DoUnserialize(UnserialInfo* info) return UNSERIALIZE_STR(&name, 0); } -void builtin_run_time(const char* msg, BroObj* arg) +void builtin_error(const char* msg, BroObj* arg) { if ( calling_expr ) - calling_expr->RunTime(msg, arg); + calling_expr->Error(msg, arg); else - run_time(msg, arg); + reporter->Error(msg, arg); } #include "bro.bif.func_h" #include "logging.bif.func_h" +#include "reporter.bif.func_h" #include "strings.bif.func_h" #include "bro.bif.func_def" #include "logging.bif.func_def" +#include "reporter.bif.func_def" #include "strings.bif.func_def" void init_builtin_funcs() @@ -526,6 +529,7 @@ void init_builtin_funcs() #include "bro.bif.func_init" #include "logging.bif.func_init" +#include "reporter.bif.func_init" #include "strings.bif.func_init" did_builtin_init = true; diff --git a/src/Func.h b/src/Func.h index b6cfab893b..8ba954db37 100644 --- a/src/Func.h +++ b/src/Func.h @@ -132,7 +132,7 @@ protected: }; -extern void builtin_run_time(const char* msg, BroObj* arg = 0); +extern void builtin_error(const char* msg, BroObj* arg = 0); extern void init_builtin_funcs(); extern bool check_built_in_call(BuiltinFunc* f, CallExpr* call); diff --git a/src/HTTP.cc b/src/HTTP.cc index f5f4bf9673..54613bb9e1 100644 --- a/src/HTTP.cc +++ b/src/HTTP.cc @@ -89,7 +89,7 @@ void HTTP_Entity::Deliver(int len, const char* data, int trailing_CRLF) if ( in_header ) { if ( ! trailing_CRLF ) - http_message->MyHTTP_Analyzer()->Weird("no_http_in_header_list"); + http_message->MyHTTP_Analyzer()->Weird("http_no_crlf_in_header_list"); header_length += len; MIME_Entity::Deliver(len, data, trailing_CRLF); @@ -576,7 +576,7 @@ void HTTP_Message::SubmitData(int len, const char* buf) { if ( buf != (const char*) data_buffer->Bytes() + buffer_offset || buffer_offset + len > buffer_size ) - internal_error("buffer misalignment"); + reporter->InternalError("buffer misalignment"); buffer_offset += len; if ( buffer_offset >= buffer_size ) @@ -624,7 +624,7 @@ void HTTP_Message::SubmitEvent(int event_type, const char* detail) break; default: - internal_error("unrecognized HTTP message event"); + reporter->InternalError("unrecognized HTTP message event"); } MyHTTP_Analyzer()->HTTP_Event(category, detail); @@ -1097,7 +1097,7 @@ int HTTP_Analyzer::HTTP_RequestLine(const char* line, const char* end_of_line) request_method = new StringVal(http_methods[i]); if ( ! ParseRequest(rest, end_of_line) ) - internal_error("HTTP ParseRequest failed"); + reporter->InternalError("HTTP ParseRequest failed"); Conn()->Match(Rule::HTTP_REQUEST, (const u_char*) unescaped_URI->AsString()->Bytes(), diff --git a/src/ID.cc b/src/ID.cc index eac4f4e916..2decef725f 100644 --- a/src/ID.cc +++ b/src/ID.cc @@ -223,6 +223,7 @@ void ID::UpdateValAttrs() if ( Type()->Tag() == TYPE_FUNC ) { Attr* attr = attrs->FindAttr(ATTR_GROUP); + if ( attr ) { Val* group = attr->AttrExpr()->ExprVal(); @@ -234,6 +235,11 @@ void ID::UpdateValAttrs() Error("&group attribute takes string"); } } + + attr = attrs->FindAttr(ATTR_ERROR_HANDLER); + + if ( attr ) + event_registry->SetErrorHandler(Name()); } if ( Type()->Tag() == TYPE_RECORD ) @@ -448,7 +454,7 @@ ID* ID::Unserialize(UnserialInfo* info) break; default: - internal_error("unknown type for UnserialInfo::id_policy"); + reporter->InternalError("unknown type for UnserialInfo::id_policy"); } } @@ -552,7 +558,7 @@ bool ID::DoUnserialize(UnserialInfo* info) } if ( installed_tmp && ! global_scope()->Remove(name) ) - internal_error("tmp id missing"); + reporter->InternalError("tmp id missing"); return true; } diff --git a/src/IRC.cc b/src/IRC.cc index 78cc7b6edc..04a07d17a9 100644 --- a/src/IRC.cc +++ b/src/IRC.cc @@ -1178,7 +1178,7 @@ void IRC_Analyzer::DeliverStream(int length, const u_char* line, bool orig) AddSupportAnalyzer(new ZIP_Analyzer(Conn(), true)); AddSupportAnalyzer(new ZIP_Analyzer(Conn(), false)); #else - run_time("IRC analyzer lacking libz support"); + reporter->Error("IRC analyzer lacking libz support"); Remove(); #endif } diff --git a/src/Ident.cc b/src/Ident.cc index dba42f9ed4..2231c50ae8 100644 --- a/src/Ident.cc +++ b/src/Ident.cc @@ -73,7 +73,10 @@ void Ident_Analyzer::DeliverStream(int length, const u_char* data, bool is_orig) } if ( line != end_of_line ) - Weird("ident_request_addendum", length, orig_line); + { + BroString s((const u_char*)orig_line, length, true); + Weird("ident_request_addendum", s.CheckString()); + } val_list* vl = new val_list; vl->append(BuildConnVal()); @@ -233,14 +236,16 @@ const char* Ident_Analyzer::ParsePort(const char* line, const char* end_of_line, void Ident_Analyzer::BadRequest(int length, const char* line) { - Weird("bad_ident_request", length, line); + BroString s((const u_char*)line, length, true); + Weird("bad_ident_request", s.CheckString()); } void Ident_Analyzer::BadReply(int length, const char* line) { if ( ! did_bad_reply ) { - Weird("bad_ident_reply", length, line); + BroString s((const u_char*)line, length, true); + Weird("bad_ident_reply", s.CheckString()); did_bad_reply = 1; } } diff --git a/src/LogMgr.cc b/src/LogMgr.cc index db35221aff..0925e99534 100644 --- a/src/LogMgr.cc +++ b/src/LogMgr.cc @@ -273,7 +273,7 @@ bool LogVal::Read(SerializationFormat* fmt) } default: - internal_error("unsupported type %s in LogVal::Write", type_name(type)); + reporter->InternalError("unsupported type %s in LogVal::Write", type_name(type)); } return false; @@ -374,7 +374,7 @@ bool LogVal::Write(SerializationFormat* fmt) const } default: - internal_error("unsupported type %s in LogVal::REad", type_name(type)); + reporter->InternalError("unsupported type %s in LogVal::REad", type_name(type)); } return false; @@ -452,7 +452,7 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) if ( ! same_type(rtype, BifType::Record::Log::Stream, 0) ) { - run_time("sval argument not of right type"); + reporter->Error("sval argument not of right type"); return false; } @@ -468,7 +468,7 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) if ( ! LogVal::IsCompatibleType(columns->FieldType(i)) ) { - run_time("type of field '%s' is not support for logging output", + reporter->Error("type of field '%s' is not support for logging output", columns->FieldName(i)); return false; @@ -479,7 +479,7 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) if ( ! log_attr_present ) { - run_time("logged record type does not have any &log attributes"); + reporter->Error("logged record type does not have any &log attributes"); return false; } @@ -493,7 +493,7 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) if ( ! etype->IsEvent() ) { - run_time("stream event is a function, not an event"); + reporter->Error("stream event is a function, not an event"); return false; } @@ -501,13 +501,13 @@ bool LogMgr::CreateStream(EnumVal* id, RecordVal* sval) if ( args->length() != 1 ) { - run_time("stream event must take a single argument"); + reporter->Error("stream event must take a single argument"); return false; } if ( ! same_type((*args)[0], columns) ) { - run_time("stream event's argument type does not match column record type"); + reporter->Error("stream event's argument type does not match column record type"); return new Val(0, TYPE_BOOL); } } @@ -627,7 +627,7 @@ bool LogMgr::TraverseRecord(Stream* stream, Filter* filter, RecordType* rt, else { - run_time("unsupported field type for log column"); + reporter->Error("unsupported field type for log column"); return false; } } @@ -666,7 +666,7 @@ bool LogMgr::TraverseRecord(Stream* stream, Filter* filter, RecordType* rt, if ( ! filter->fields ) { - run_time("out of memory in add_filter"); + reporter->Error("out of memory in add_filter"); return false; } @@ -685,7 +685,7 @@ bool LogMgr::AddFilter(EnumVal* id, RecordVal* fval) if ( ! same_type(rtype, BifType::Record::Log::Filter, 0) ) { - run_time("filter argument not of right type"); + reporter->Error("filter argument not of right type"); return false; } @@ -836,7 +836,7 @@ bool LogMgr::Write(EnumVal* id, RecordVal* columns) if ( ! columns ) { - run_time("incompatible log record type"); + reporter->Error("incompatible log record type"); return false; } @@ -878,7 +878,7 @@ bool LogMgr::Write(EnumVal* id, RecordVal* columns) if ( ! v->Type()->Tag() == TYPE_STRING ) { - run_time("path_func did not return string"); + reporter->Error("path_func did not return string"); Unref(v); return false; } @@ -1062,7 +1062,7 @@ LogVal* LogMgr::ValToLogVal(Val* val, BroType* ty) } default: - internal_error("unsupported type for log_write"); + reporter->InternalError("unsupported type for log_write"); } return lval; @@ -1127,7 +1127,7 @@ LogWriter* LogMgr::CreateWriter(EnumVal* id, EnumVal* writer, string path, { if ( ld->type == BifEnum::Log::WRITER_DEFAULT ) { - run_time("unknow writer when creating writer"); + reporter->Error("unknow writer when creating writer"); return 0; } @@ -1286,7 +1286,7 @@ bool LogMgr::Flush(EnumVal* id) void LogMgr::Error(LogWriter* writer, const char* msg) { - run_time(fmt("error with writer for %s: %s", + reporter->Error(fmt("error with writer for %s: %s", writer->Path().c_str(), msg)); } diff --git a/src/Logger.cc b/src/Logger.cc deleted file mode 100644 index ec1c48194d..0000000000 --- a/src/Logger.cc +++ /dev/null @@ -1,73 +0,0 @@ -// $Id: Logger.cc 6916 2009-09-24 20:48:36Z vern $ -// -// See the file "COPYING" in the main distribution directory for copyright. - -#include -#include -#include -#include - -#include "config.h" -#include "File.h" -#include "Logger.h" - -#ifdef SYSLOG_INT -extern "C" { -int openlog(const char* ident, int logopt, int facility); -int syslog(int priority, const char* message_fmt, ...); -int closelog(); -} -#endif - -Logger::Logger(const char* name, BroFile* arg_f) - { - openlog(name, 0, LOG_LOCAL5); - f = arg_f; - enabled = 1; - } - -Logger::~Logger() - { - closelog(); - Unref(f); - } - -void Logger::Log(const char* msg) - { - int has_timestamp = - (fabs(atof(msg) - network_time) <= 30.0) || - (msg[0] == 't' && msg[1] == '=' && isdigit(msg[2])); - - if ( enabled ) - { - const char* sub_msg = msg; - if ( has_timestamp ) - { - // Don't include the timestamp in the logging, - // as it gets tacked on by syslog anyway. - sub_msg = strchr(sub_msg, ' '); - if ( sub_msg ) - ++sub_msg; // skip over ' ' - else - sub_msg = msg; - } - - syslog(LOG_NOTICE, "%s", sub_msg); - } - - if ( f ) - { - if ( has_timestamp ) - f->Write(fmt("%s\n", msg)); - else - f->Write(fmt("%.6f %s\n", network_time, msg)); - - f->Flush(); - } - } - -void Logger::Describe(ODesc* d) const - { - d->AddSP("logger"); - f->Describe(d); - } diff --git a/src/Logger.h b/src/Logger.h deleted file mode 100644 index 6512776550..0000000000 --- a/src/Logger.h +++ /dev/null @@ -1,31 +0,0 @@ -// See the file "COPYING" in the main distribution directory for copyright. - -#ifndef logger_h -#define logger_h - -#include "util.h" -#include "Obj.h" - -class BroFile; -class Func; - -class Logger : public BroObj { -public: - Logger(const char* name, BroFile* f = 0); - virtual ~Logger(); - - void Log(const char* msg); - - void SetEnabled(int do_enabled) { enabled = do_enabled; } - - void Describe(ODesc* d) const; - -protected: - BroFile* f; // associated file - int enabled; // if true, syslog'ing is done, otherwise just file log -}; - -extern Logger* bro_logger; -extern Func* alarm_hook; - -#endif diff --git a/src/Login.cc b/src/Login.cc index 7ad309458d..0a3849ccd0 100644 --- a/src/Login.cc +++ b/src/Login.cc @@ -115,7 +115,7 @@ void Login_Analyzer::NewLine(bool orig, char* line) } if ( state != LOGIN_STATE_CONFUSED ) - internal_error("bad state in Login_Analyzer::NewLine"); + reporter->InternalError("bad state in Login_Analyzer::NewLine"); // When we're in "confused", we feed each user input line to // login_confused_text, but also scan the text in the @@ -572,7 +572,7 @@ void Login_Analyzer::AddUserText(const char* line) char* Login_Analyzer::PeekUserText() const { if ( num_user_text <= 0 ) - internal_error("underflow in Login_Analyzer::PeekUserText()"); + reporter->InternalError("underflow in Login_Analyzer::PeekUserText()"); return user_text[user_text_first]; } diff --git a/src/MIME.cc b/src/MIME.cc index 44da01a91e..3fe652d4cc 100644 --- a/src/MIME.cc +++ b/src/MIME.cc @@ -5,6 +5,7 @@ #include "NetVar.h" #include "MIME.h" #include "Event.h" +#include "Reporter.h" // Here are a few things to do: // @@ -268,7 +269,7 @@ void MIME_Entity::init() MIME_Entity::~MIME_Entity() { if ( ! end_of_data ) - internal_error("EndOfData must be called before delete a MIME_Entity"); + reporter->InternalError("EndOfData must be called before delete a MIME_Entity"); delete current_header_line; Unref(content_type_str); @@ -653,7 +654,7 @@ int MIME_Entity::CheckBoundaryDelimiter(int len, const char* data) { if ( ! multipart_boundary ) { - warn("boundary delimiter was not specified for a multipart message\n"); + reporter->Warning("boundary delimiter was not specified for a multipart message\n"); DEBUG_MSG("headers of the MIME entity for debug:\n"); DebugPrintHeaders(); return NOT_MULTIPART_BOUNDARY; @@ -799,7 +800,7 @@ void MIME_Entity::DecodeBase64(int len, const char* data) char* prbuf = rbuf; int decoded = base64_decoder->Decode(len, data, &rlen, &prbuf); if ( prbuf != rbuf ) - internal_error("buffer pointer modified in base64 decoding"); + reporter->InternalError("buffer pointer modified in base64 decoding"); DataOctets(rlen, rbuf); len -= decoded; data += decoded; } @@ -808,7 +809,7 @@ void MIME_Entity::DecodeBase64(int len, const char* data) void MIME_Entity::StartDecodeBase64() { if ( base64_decoder ) - internal_error("previous Base64 decoder not released!"); + reporter->InternalError("previous Base64 decoder not released!"); base64_decoder = new Base64Decoder(message->GetAnalyzer()); } @@ -825,7 +826,7 @@ void MIME_Entity::FinishDecodeBase64() if ( base64_decoder->Done(&rlen, &prbuf) ) { // some remaining data if ( prbuf != rbuf ) - internal_error("buffer pointer modified in base64 decoding"); + reporter->InternalError("buffer pointer modified in base64 decoding"); if ( rlen > 0 ) DataOctets(rlen, rbuf); } @@ -839,7 +840,7 @@ int MIME_Entity::GetDataBuffer() int ret = message->RequestBuffer(&data_buf_length, &data_buf_data); if ( ! ret || data_buf_length == 0 || data_buf_data == 0 ) { - // internal_error("cannot get data buffer from MIME_Message", ""); + // reporter->InternalError("cannot get data buffer from MIME_Message", ""); return 0; } @@ -1092,7 +1093,7 @@ void MIME_Mail::SubmitAllHeaders(MIME_HeaderList& hlist) void MIME_Mail::SubmitData(int len, const char* buf) { if ( buf != (char*) data_buffer->Bytes() + buffer_start ) - internal_error("buffer misalignment"); + reporter->InternalError("buffer misalignment"); if ( compute_content_hash ) { @@ -1180,7 +1181,7 @@ void MIME_Mail::SubmitEvent(int event_type, const char* detail) break; default: - internal_error("unrecognized MIME_Mail event"); + reporter->InternalError("unrecognized MIME_Mail event"); } if ( mime_event ) diff --git a/src/MIME.h b/src/MIME.h index c55cdcb42b..b5cdf556ac 100644 --- a/src/MIME.h +++ b/src/MIME.h @@ -193,7 +193,7 @@ public: virtual ~MIME_Message() { if ( ! finished ) - internal_error("Done() must be called before destruction"); + reporter->InternalError("Done() must be called before destruction"); } virtual void Done() { finished = 1; } diff --git a/src/NVT.cc b/src/NVT.cc index 66438a0589..ad5e321595 100644 --- a/src/NVT.cc +++ b/src/NVT.cc @@ -38,7 +38,7 @@ void TelnetOption::RecvOption(unsigned int type) { TelnetOption* peer = endp->FindPeerOption(code); if ( ! peer ) - internal_error("option peer missing in TelnetOption::RecvOption"); + reporter->InternalError("option peer missing in TelnetOption::RecvOption"); // WILL/WONT/DO/DONT are messages we've *received* from our peer. switch ( type ) { @@ -83,7 +83,7 @@ void TelnetOption::RecvOption(unsigned int type) break; default: - internal_error("bad option type in TelnetOption::RecvOption"); + reporter->InternalError("bad option type in TelnetOption::RecvOption"); } } @@ -163,7 +163,7 @@ void TelnetEncryptOption::RecvSubOption(u_char* data, int len) (TelnetEncryptOption*) endp->FindPeerOption(code); if ( ! peer ) - internal_error("option peer missing in TelnetEncryptOption::RecvSubOption"); + reporter->InternalError("option peer missing in TelnetEncryptOption::RecvSubOption"); if ( peer->DidRequest() || peer->DoingEncryption() || peer->Endpoint()->AuthenticationHasBeenAccepted() ) @@ -199,7 +199,7 @@ void TelnetAuthenticateOption::RecvSubOption(u_char* data, int len) (TelnetAuthenticateOption*) endp->FindPeerOption(code); if ( ! peer ) - internal_error("option peer missing in TelnetAuthenticateOption::RecvSubOption"); + reporter->InternalError("option peer missing in TelnetAuthenticateOption::RecvSubOption"); if ( ! peer->DidRequestAuthentication() ) InconsistentOption(0); diff --git a/src/Net.cc b/src/Net.cc index d9171d2ce1..e2c9854785 100644 --- a/src/Net.cc +++ b/src/Net.cc @@ -26,7 +26,7 @@ #include "Event.h" #include "Timer.h" #include "Var.h" -#include "Logger.h" +#include "Reporter.h" #include "Net.h" #include "Anon.h" #include "PacketSort.h" @@ -108,15 +108,6 @@ RETSIGTYPE watchdog(int /* signo */) int frac_pst = int((processing_start_time - int_pst) * 1e6); - char msg[512]; - safe_snprintf(msg, sizeof(msg), - "**watchdog timer expired, t = %d.%06d, start = %d.%06d, dispatched = %d", - int_ct, frac_ct, int_pst, frac_pst, - current_dispatched); - - bro_logger->Log(msg); - run_time("watchdog timer expired"); - if ( current_hdr ) { if ( ! pkt_dumper ) @@ -128,7 +119,7 @@ RETSIGTYPE watchdog(int /* signo */) pkt_dumper = new PktDumper("watchdog-pkt.pcap"); if ( pkt_dumper->IsError() ) { - fprintf(stderr, "watchdog: can't open watchdog-pkt.pcap for writing\n"); + reporter->Error("watchdog: can't open watchdog-pkt.pcap for writing\n"); pkt_dumper = 0; } } @@ -140,8 +131,10 @@ RETSIGTYPE watchdog(int /* signo */) net_get_final_stats(); net_finish(0); - abort(); - exit(1); + reporter->FatalErrorWithCore( + "**watchdog timer expired, t = %d.%06d, start = %d.%06d, dispatched = %d", + int_ct, frac_ct, int_pst, frac_pst, + current_dispatched); } } @@ -168,11 +161,8 @@ void net_init(name_list& interfaces, name_list& readfiles, PktFileSrc* ps = new PktFileSrc(readfiles[i], filter); if ( ! ps->IsOpen() ) - { - fprintf(stderr, "%s: problem with trace file %s - %s\n", + reporter->FatalError("%s: problem with trace file %s - %s\n", prog, readfiles[i], ps->ErrorMsg()); - exit(1); - } else { pkt_srcs.append(ps); @@ -188,12 +178,9 @@ void net_init(name_list& interfaces, name_list& readfiles, TYPE_FILTER_SECONDARY); if ( ! ps->IsOpen() ) - { - fprintf(stderr, "%s: problem with trace file %s - %s\n", + reporter->FatalError("%s: problem with trace file %s - %s\n", prog, readfiles[i], ps->ErrorMsg()); - exit(1); - } else { pkt_srcs.append(ps); @@ -209,11 +196,8 @@ void net_init(name_list& interfaces, name_list& readfiles, FlowFileSrc* fs = new FlowFileSrc(flowfiles[i]); if ( ! fs->IsOpen() ) - { - fprintf(stderr, "%s: problem with netflow file %s - %s\n", + reporter->FatalError("%s: problem with netflow file %s - %s\n", prog, flowfiles[i], fs->ErrorMsg()); - exit(1); - } else { io_sources.Register(fs); @@ -232,11 +216,8 @@ void net_init(name_list& interfaces, name_list& readfiles, ps = new PktInterfaceSrc(interfaces[i], filter); if ( ! ps->IsOpen() ) - { - fprintf(stderr, "%s: problem with interface %s - %s\n", + reporter->FatalError("%s: problem with interface %s - %s\n", prog, interfaces[i], ps->ErrorMsg()); - exit(1); - } else { pkt_srcs.append(ps); @@ -250,12 +231,9 @@ void net_init(name_list& interfaces, name_list& readfiles, filter, TYPE_FILTER_SECONDARY); if ( ! ps->IsOpen() ) - { - fprintf(stderr, "%s: problem with interface %s - %s\n", + reporter->Error("%s: problem with interface %s - %s\n", prog, interfaces[i], ps->ErrorMsg()); - exit(1); - } else { pkt_srcs.append(ps); @@ -271,11 +249,8 @@ void net_init(name_list& interfaces, name_list& readfiles, FlowSocketSrc* fs = new FlowSocketSrc(netflows[i]); if ( ! fs->IsOpen() ) - { - fprintf(stderr, "%s: problem with netflow socket %s - %s\n", + reporter->Error("%s: problem with netflow socket %s - %s\n", prog, netflows[i], fs->ErrorMsg()); - exit(1); - } else { io_sources.Register(fs); @@ -297,15 +272,12 @@ void net_init(name_list& interfaces, name_list& readfiles, // interfaces with different-lengthed media. pkt_dumper = new PktDumper(writefile); if ( pkt_dumper->IsError() ) - { - fprintf(stderr, "%s: can't open write file \"%s\" - %s\n", + reporter->FatalError("%s: can't open write file \"%s\" - %s\n", prog, writefile, pkt_dumper->ErrorMsg()); - exit(1); - } ID* id = global_scope()->Lookup("trace_output_file"); if ( ! id ) - run_time("trace_output_file not defined in bro.init"); + reporter->Error("trace_output_file not defined in bro.init"); else id->SetVal(new StringVal(writefile)); } @@ -565,7 +537,7 @@ void net_get_final_stats() { struct PktSrc::Stats s; ps->Statistics(&s); - fprintf(stderr, "%d packets received on interface %s, %d dropped\n", + reporter->Message("%d packets received on interface %s, %d dropped\n", s.received, ps->Interface(), s.dropped); } } @@ -588,8 +560,6 @@ void net_finish(int drain_events) delete pkt_dumper; - // fprintf(stderr, "uhash: %d/%d\n", hash_cnt_uhash, hash_cnt_all); - #ifdef DEBUG extern int reassem_seen_bytes, reassem_copied_bytes; // DEBUG_MSG("Reassembly (TCP and IP/Frag): %d bytes seen, %d bytes copied\n", @@ -641,7 +611,7 @@ static double suspend_start = 0; void net_suspend_processing() { if ( _processing_suspended == 0 ) - bro_logger->Log("processing suspended"); + reporter->Message("processing suspended"); ++_processing_suspended; } @@ -650,7 +620,7 @@ void net_continue_processing() { if ( _processing_suspended == 1 ) { - bro_logger->Log("processing continued"); + reporter->Message("processing continued"); loop_over_list(pkt_srcs, i) pkt_srcs[i]->ContinueAfterSuspend(); } diff --git a/src/NetVar.cc b/src/NetVar.cc index 2ca71a030e..b8ea954c45 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -255,6 +255,7 @@ StringVal* cmd_line_bpf_filter; #include "types.bif.netvar_def" #include "event.bif.netvar_def" #include "logging.bif.netvar_def" +#include "reporter.bif.netvar_def" void init_event_handlers() { @@ -314,6 +315,7 @@ void init_net_var() #include "const.bif.netvar_init" #include "types.bif.netvar_init" #include "logging.bif.netvar_init" +#include "reporter.bif.netvar_init" conn_id = internal_type("conn_id")->AsRecordType(); endpoint = internal_type("endpoint")->AsRecordType(); diff --git a/src/NetVar.h b/src/NetVar.h index 69502d334f..50b558a69b 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -264,5 +264,6 @@ extern void init_net_var(); #include "types.bif.netvar_h" #include "event.bif.netvar_h" #include "logging.bif.netvar_h" +#include "reporter.bif.netvar_h" #endif diff --git a/src/OSFinger.cc b/src/OSFinger.cc index 0f0e5b9d57..e8fd929885 100644 --- a/src/OSFinger.cc +++ b/src/OSFinger.cc @@ -87,7 +87,7 @@ void OSFingerprint::collide(uint32 id) if (sig[id].ttl % 32 && sig[id].ttl != 255 && sig[id].ttl % 30) { problems=1; - warn(fmt("OS fingerprinting: [!] Unusual TTL (%d) for signature '%s %s' (line %d).", + reporter->Warning(fmt("OS fingerprinting: [!] Unusual TTL (%d) for signature '%s %s' (line %d).", sig[id].ttl,sig[id].os,sig[id].desc,sig[id].line)); } @@ -96,7 +96,7 @@ void OSFingerprint::collide(uint32 id) if (!strcmp(sig[i].os,sig[id].os) && !strcmp(sig[i].desc,sig[id].desc)) { problems=1; - warn(fmt("OS fingerprinting: [!] Duplicate signature name: '%s %s' (line %d and %d).", + reporter->Warning(fmt("OS fingerprinting: [!] Duplicate signature name: '%s %s' (line %d and %d).", sig[i].os,sig[i].desc,sig[i].line,sig[id].line)); } @@ -279,7 +279,7 @@ do_const: if (sig[id].opt[j] ^ sig[i].opt[j]) goto reloop; problems=1; - warn(fmt("OS fingerprinting: [!] Signature '%s %s' (line %d)\n" + reporter->Warning(fmt("OS fingerprinting: [!] Signature '%s %s' (line %d)\n" " is already covered by '%s %s' (line %d).", sig[id].os,sig[id].desc,sig[id].line,sig[i].os,sig[i].desc, sig[i].line)); diff --git a/src/OSFinger.h b/src/OSFinger.h index ca040f609a..f1f9e492f2 100644 --- a/src/OSFinger.h +++ b/src/OSFinger.h @@ -15,7 +15,7 @@ #include "util.h" #include "Dict.h" - +#include "Reporter.h" // Size limit for size wildcards. #define PACKET_BIG 100 @@ -105,19 +105,19 @@ protected: void Error(const char* msg) { - error(msg); + reporter->Error(msg); err = true; } void Error(const char* msg, int n) { - error(msg, n); + reporter->Error(msg, n); err = true; } void Error(const char* msg, const char* s) { - error(msg, s); + reporter->Error(msg, s); err = true; } diff --git a/src/Obj.cc b/src/Obj.cc index d649b77b61..666a57ac93 100644 --- a/src/Obj.cc +++ b/src/Obj.cc @@ -52,6 +52,32 @@ bool Location::DoUnserialize(UnserialInfo* info) && UNSERIALIZE(&last_column); } +void Location::Describe(ODesc* d) const + { + if ( filename ) + { + d->Add(filename); + + if ( first_line == 0 ) + return; + + d->AddSP(","); + } + + if ( last_line != first_line ) + { + d->Add("lines "); + d->Add(first_line); + d->Add("-"); + d->Add(last_line); + } + else + { + d->Add("line "); + d->Add(first_line); + } + } + bool Location::operator==(const Location& l) const { if ( filename == l.filename || @@ -61,7 +87,7 @@ bool Location::operator==(const Location& l) const return false; } -int BroObj::suppress_runtime = 0; +int BroObj::suppress_errors = 0; BroObj::~BroObj() { @@ -70,23 +96,21 @@ BroObj::~BroObj() void BroObj::Warn(const char* msg, const BroObj* obj2, int pinpoint_only) const { - DoMsg("warning,", msg, obj2, pinpoint_only); - ++nwarn; + ODesc d; + DoMsg(&d, msg, obj2, pinpoint_only); + reporter->Warning("%s", d.Description()); + reporter->PopLocation(); } void BroObj::Error(const char* msg, const BroObj* obj2, int pinpoint_only) const { - DoMsg("error,", msg, obj2, pinpoint_only); - ++nerr; - } + if ( suppress_errors ) + return; -void BroObj::RunTime(const char* msg, const BroObj* obj2, int pinpoint_only) const - { - if ( ! suppress_runtime ) - { - DoMsg("run-time error,", msg, obj2, pinpoint_only); - ++nruntime; - } + ODesc d; + DoMsg(&d, msg, obj2, pinpoint_only); + reporter->Error("%s", d.Description()); + reporter->PopLocation(); } void BroObj::BadTag(const char* msg, const char* t1, const char* t2) const @@ -100,19 +124,23 @@ void BroObj::BadTag(const char* msg, const char* t1, const char* t2) const else snprintf(out, sizeof(out), "%s", msg); - DoMsg("bad tag in", out); - Fatal(); + ODesc d; + DoMsg(&d, out); + reporter->FatalError("%s", d.Description()); } void BroObj::Internal(const char* msg) const { - DoMsg("internal error:", msg); - Fatal(); + ODesc d; + DoMsg(&d, msg); + reporter->InternalError("%s", d.Description()); } void BroObj::InternalWarning(const char* msg) const { - DoMsg("internal warning:", msg); + ODesc d; + DoMsg(&d, msg); + reporter->InternalWarning("%s", d.Description()); } void BroObj::AddLocation(ODesc* d) const @@ -123,28 +151,7 @@ void BroObj::AddLocation(ODesc* d) const return; } - if ( location->filename ) - { - d->Add(location->filename); - - if ( location->first_line == 0 ) - return; - - d->AddSP(","); - } - - if ( location->last_line != location->first_line ) - { - d->Add("lines "); - d->Add(location->first_line); - d->Add("-"); - d->Add(location->last_line); - } - else - { - d->Add("line "); - d->Add(location->first_line); - } + location->Describe(d); } bool BroObj::SetLocationInfo(const Location* start, const Location* end) @@ -177,39 +184,24 @@ void BroObj::UpdateLocationEndInfo(const Location& end) location->last_column = end.last_column; } -void BroObj::DoMsg(const char s1[], const char s2[], const BroObj* obj2, +void BroObj::DoMsg(ODesc* d, const char s1[], const BroObj* obj2, int pinpoint_only) const { - ODesc d; - d.SetShort(); + d->SetShort(); - PinPoint(&d, obj2, pinpoint_only); - d.SP(); - d.Add(s1); - d.SP(); - d.Add(s2); - fprintf(stderr, "%s\n", d.Description()); + d->Add(s1); + PinPoint(d, obj2, pinpoint_only); + + const Location* loc2 = 0; + if ( obj2 && obj2->GetLocationInfo() != &no_location && + *obj2->GetLocationInfo() != *GetLocationInfo() ) + loc2 = obj2->GetLocationInfo(); + + reporter->PushLocation(GetLocationInfo(), loc2); } void BroObj::PinPoint(ODesc* d, const BroObj* obj2, int pinpoint_only) const { - if ( network_time > 0.0 ) - { - char time[256]; - safe_snprintf(time, sizeof(time), "%.6f", network_time); - d->Add(time); - d->SP(); - } - - AddLocation(d); - if ( obj2 && obj2->GetLocationInfo() != &no_location && - *obj2->GetLocationInfo() != *GetLocationInfo() ) - { - d->Add(" and "); - obj2->AddLocation(d); - d->Add("\n "); - } - d->Add(" ("); Describe(d); if ( obj2 && ! pinpoint_only ) @@ -218,15 +210,7 @@ void BroObj::PinPoint(ODesc* d, const BroObj* obj2, int pinpoint_only) const obj2->Describe(d); } - d->Add("):"); - } - -void BroObj::Fatal() const - { -#ifdef DEBUG_BRO - internal_error("BroObj::Fatal()"); -#endif - exit(1); + d->Add(")"); } bool BroObj::DoSerialize(SerialInfo* info) const @@ -260,7 +244,7 @@ void print(const BroObj* obj) void bad_ref(int type) { - internal_error("bad reference count [%d]", type); + reporter->InternalError("bad reference count [%d]", type); abort(); } diff --git a/src/Obj.h b/src/Obj.h index 7bfec745ba..d5a60aa972 100644 --- a/src/Obj.h +++ b/src/Obj.h @@ -44,6 +44,8 @@ public: delete [] filename; } + void Describe(ODesc* d) const; + bool Serialize(SerialInfo* info) const; static Location* Unserialize(UnserialInfo* info); @@ -120,8 +122,6 @@ public: int pinpoint_only = 0) const; void Error(const char* msg, const BroObj* obj2 = 0, int pinpoint_only = 0) const; - void RunTime(const char* msg, const BroObj* obj2 = 0, - int pinpoint_only = 0) const; // Report internal errors. void BadTag(const char* msg, const char* t1 = 0, @@ -155,12 +155,12 @@ public: int RefCnt() const { return ref_cnt; } - // Helper class to temporarily suppress run-time errors + // Helper class to temporarily suppress errors // as long as there exist any instances. - class SuppressRunTimeErrors { + class SuppressErrors { public: - SuppressRunTimeErrors() { ++BroObj::suppress_runtime; } - ~SuppressRunTimeErrors() { --BroObj::suppress_runtime; } + SuppressErrors() { ++BroObj::suppress_errors; } + ~SuppressErrors() { --BroObj::suppress_errors; } }; bool in_ser_cache; @@ -173,13 +173,12 @@ protected: Location* location; // all that matters in real estate private: - friend class SuppressRunTimeErrors; + friend class SuppressErrors; - void DoMsg(const char s1[], const char s2[], const BroObj* obj2 = 0, + void DoMsg(ODesc* d, const char s1[], const BroObj* obj2 = 0, int pinpoint_only = 0) const; void PinPoint(ODesc* d, const BroObj* obj2 = 0, int pinpoint_only = 0) const; - void Fatal() const; friend inline void Ref(BroObj* o); friend inline void Unref(BroObj* o); @@ -188,7 +187,7 @@ private: // If non-zero, do not print runtime errors. Useful for // speculative evaluation. - static int suppress_runtime; + static int suppress_errors; }; // Prints obj to stderr, primarily for debugging. diff --git a/src/PIA.cc b/src/PIA.cc index a38cf608fc..32c0b40fc5 100644 --- a/src/PIA.cc +++ b/src/PIA.cc @@ -153,7 +153,7 @@ void PIA_UDP::ActivateAnalyzer(AnalyzerTag::Tag tag, const Rule* rule) void PIA_UDP::DeactivateAnalyzer(AnalyzerTag::Tag tag) { - internal_error("PIA_UDP::Deact not implemented yet"); + reporter->InternalError("PIA_UDP::Deact not implemented yet"); } //// TCP PIA @@ -375,7 +375,7 @@ void PIA_TCP::ActivateAnalyzer(AnalyzerTag::Tag tag, const Rule* rule) void PIA_TCP::DeactivateAnalyzer(AnalyzerTag::Tag tag) { - internal_error("PIA_TCP::Deact not implemented yet"); + reporter->InternalError("PIA_TCP::Deact not implemented yet"); } void PIA_TCP::ReplayStreamBuffer(Analyzer* analyzer) diff --git a/src/POP3.cc b/src/POP3.cc index 5d38b4c3d1..b364541be1 100644 --- a/src/POP3.cc +++ b/src/POP3.cc @@ -15,6 +15,7 @@ #include "POP3.h" #include "Event.h" #include "NVT.h" +#include "Reporter.h" #undef POP3_CMD_DEF #define POP3_CMD_DEF(cmd) #cmd, @@ -199,7 +200,7 @@ void POP3_Analyzer::ProcessRequest(int length, const char* line) break; default: - internal_error("unexpected authorization state"); + reporter->InternalError("unexpected authorization state"); } delete decoded; @@ -555,7 +556,7 @@ void POP3_Analyzer::ProcessClientCmd() break; default: - internal_error("command not known"); + reporter->InternalError("command not known"); } } @@ -807,7 +808,7 @@ void POP3_Analyzer::BeginData() void POP3_Analyzer::EndData() { if ( ! mail ) - warn("unmatched end of data"); + reporter->Warning("unmatched end of data"); else { mail->Done(); diff --git a/src/PacketDumper.cc b/src/PacketDumper.cc index f11137ff08..d401cd63cb 100644 --- a/src/PacketDumper.cc +++ b/src/PacketDumper.cc @@ -18,7 +18,7 @@ PacketDumper::PacketDumper(pcap_dumper_t* arg_pkt_dump) pkt_dump = arg_pkt_dump; if ( ! pkt_dump ) - internal_error("PacketDumper: nil dump file"); + reporter->InternalError("PacketDumper: nil dump file"); } void PacketDumper::DumpPacket(const struct pcap_pkthdr* hdr, @@ -29,7 +29,7 @@ void PacketDumper::DumpPacket(const struct pcap_pkthdr* hdr, struct pcap_pkthdr h = *hdr; h.caplen = len; if ( h.caplen > hdr->caplen ) - internal_error("bad modified caplen"); + reporter->InternalError("bad modified caplen"); pcap_dump((u_char*) pkt_dump, &h, pkt); } diff --git a/src/PacketSort.cc b/src/PacketSort.cc index e2c18c4a4f..8beaa51474 100644 --- a/src/PacketSort.cc +++ b/src/PacketSort.cc @@ -347,8 +347,8 @@ PacketSortElement* PacketSortGlobalPQ::RemoveMin(double timestamp) PacketSortConnPQ* PacketSortGlobalPQ::FindConnPQ(PacketSortElement* e) { if ( ! e->is_tcp ) - internal_error("cannot find a connection for an invalid id"); - + reporter->InternalError("cannot find a connection for an invalid id"); + PacketSortConnPQ* pq = (PacketSortConnPQ*) conn_pq_table.Lookup(e->key); if ( ! pq ) { diff --git a/src/PersistenceSerializer.cc b/src/PersistenceSerializer.cc index 96e1686e74..3b733986b0 100644 --- a/src/PersistenceSerializer.cc +++ b/src/PersistenceSerializer.cc @@ -13,7 +13,7 @@ #include "RemoteSerializer.h" #include "Conn.h" #include "Event.h" -#include "Logger.h" +#include "Reporter.h" #include "Net.h" class IncrementalWriteTimer : public Timer { @@ -189,7 +189,7 @@ void PersistenceSerializer::RaiseFinishedSendState() vl->append(new PortVal(remote_port)); mgr.QueueEvent(finished_send_state, vl); - bro_logger->Log("Serialization done."); + reporter->Log("Serialization done."); } #endif @@ -213,7 +213,7 @@ void PersistenceSerializer::GotStateAccess(StateAccess* s) void PersistenceSerializer::GotTimer(Timer* s) { - run_time("PersistenceSerializer::GotTimer not implemented"); + reporter->Error("PersistenceSerializer::GotTimer not implemented"); } void PersistenceSerializer::GotConnection(Connection* c) @@ -228,7 +228,7 @@ void PersistenceSerializer::GotID(ID* id, Val* /* val */) void PersistenceSerializer::GotPacket(Packet* p) { - run_time("PersistenceSerializer::GotPacket not implemented"); + reporter->Error("PersistenceSerializer::GotPacket not implemented"); } bool PersistenceSerializer::LogAccess(const StateAccess& s) @@ -286,7 +286,7 @@ bool PersistenceSerializer::SendState(SourceID peer, bool may_suspend) status->conns = &persistent_conns; status->peer = peer; - bro_logger->Log("Sending state..."); + reporter->Message("Sending state..."); return RunSerialization(status); } @@ -301,7 +301,7 @@ bool PersistenceSerializer::SendConfig(SourceID peer, bool may_suspend) status->ids = global_scope()->GetIDs(); status->peer = peer; - bro_logger->Log("Sending config..."); + reporter->Message("Sending config..."); return RunSerialization(status); } @@ -319,8 +319,7 @@ bool PersistenceSerializer::RunSerialization(SerialStatus* status) { if ( running[i]->type == status->type ) { - // ### We don't report this anymore as it would go to stderr. - // Warning(fmt("Serialization of type %d already running.", status->type)); + reporter->Warning("Serialization of type %d already running.", status->type); return false; } } @@ -382,14 +381,14 @@ bool PersistenceSerializer::RunSerialization(SerialStatus* status) } else - internal_error("unknown suspend state"); + reporter->InternalError("unknown suspend state"); } else if ( cont->Resuming() ) cont->Resume(); else - internal_error("unknown continuation state"); + reporter->InternalError("unknown continuation state"); if ( status->id_cookie ) { @@ -505,7 +504,7 @@ bool PersistenceSerializer::DoIDSerialization(SerialStatus* status, ID* id) break; default: - internal_error("unknown serialization type"); + reporter->InternalError("unknown serialization type"); } return success; @@ -536,7 +535,7 @@ bool PersistenceSerializer::DoConnSerialization(SerialStatus* status, break; default: - internal_error("unknown serialization type"); + reporter->InternalError("unknown serialization type"); } return success; @@ -561,7 +560,7 @@ bool PersistenceSerializer::DoAccessSerialization(SerialStatus* status, break; default: - internal_error("unknown serialization type"); + reporter->InternalError("unknown serialization type"); } return success; diff --git a/src/PktSrc.cc b/src/PktSrc.cc index d1f5eafba3..050b58b508 100644 --- a/src/PktSrc.cc +++ b/src/PktSrc.cc @@ -400,7 +400,7 @@ void PktSrc::Statistics(Stats* s) else if ( pcap_stats(pd, &pstat) < 0 ) { - run_time("problem getting packet filter statistics: %s", + reporter->Error("problem getting packet filter statistics: %s", ErrorMsg()); s->received = s->dropped = s->link = 0; } @@ -463,7 +463,7 @@ PktInterfaceSrc::PktInterfaceSrc(const char* arg_interface, const char* filter, // ### This needs autoconf'ing. #ifdef HAVE_PCAP_INT_H - fprintf(stderr, "pcap bufsize = %d\n", ((struct pcap *) pd)->bufsize); + reporter->Message("pcap bufsize = %d\n", ((struct pcap *) pd)->bufsize); #endif #ifdef HAVE_LINUX @@ -486,7 +486,7 @@ PktInterfaceSrc::PktInterfaceSrc(const char* arg_interface, const char* filter, // Couldn't get header size. return; - fprintf(stderr, "listening on %s\n", interface); + reporter->Message("listening on %s\n", interface); } else closed = true; @@ -518,7 +518,7 @@ PktFileSrc::PktFileSrc(const char* arg_readfile, const char* filter, selectable_fd = fileno(pcap_file(pd)); if ( selectable_fd < 0 ) - internal_error("OS does not support selectable pcap fd"); + reporter->InternalError("OS does not support selectable pcap fd"); } else closed = true; diff --git a/src/PolicyFile.cc b/src/PolicyFile.cc index dd1feaf498..22a6a96cb6 100644 --- a/src/PolicyFile.cc +++ b/src/PolicyFile.cc @@ -16,6 +16,7 @@ using namespace std; #include "Debug.h" #include "util.h" #include "PolicyFile.h" +#include "Reporter.h" struct PolicyFile { PolicyFile () { filedata = 0; lmtime = 0; } @@ -32,7 +33,7 @@ static PolicyFileMap policy_files; int how_many_lines_in(const char* policy_filename) { if ( ! policy_filename ) - internal_error("NULL value passed to how_many_lines_in\n"); + reporter->InternalError("NULL value passed to how_many_lines_in\n"); FILE* throwaway = fopen(policy_filename, "r"); if ( ! throwaway ) diff --git a/src/PrefixTable.cc b/src/PrefixTable.cc index b3313c82e5..03e1495957 100644 --- a/src/PrefixTable.cc +++ b/src/PrefixTable.cc @@ -1,6 +1,7 @@ // $Id: PrefixTable.cc 1016 2005-01-31 21:23:50Z vern $ #include "PrefixTable.h" +#include "Reporter.h" // IPv4 version. inline static prefix_t* make_prefix(const uint32 addr, int width) @@ -36,7 +37,7 @@ void* PrefixTable::Insert(const_addr_type addr, int width, void* data) Deref_Prefix(prefix); if ( ! node ) - internal_error("Cannot create node in patricia tree"); + reporter->InternalError("Cannot create node in patricia tree"); void* old = node->data; @@ -65,7 +66,7 @@ void* PrefixTable::Insert(const Val* value, void* data) break; default: - internal_error("Wrong index type for PrefixTable"); + reporter->InternalError("Wrong index type for PrefixTable"); return 0; } } @@ -99,7 +100,7 @@ void* PrefixTable::Lookup(const Val* value, bool exact) const break; default: - internal_error("Wrong index type %d for PrefixTable", + reporter->InternalError("Wrong index type %d for PrefixTable", value->Type()->Tag()); return 0; } @@ -137,7 +138,7 @@ void* PrefixTable::Remove(const Val* value) break; default: - internal_error("Wrong index type for PrefixTable"); + reporter->InternalError("Wrong index type for PrefixTable"); return 0; } } diff --git a/src/PriorityQueue.cc b/src/PriorityQueue.cc index 2ed4d17d93..d94ccba7d6 100644 --- a/src/PriorityQueue.cc +++ b/src/PriorityQueue.cc @@ -8,6 +8,7 @@ #include #include "PriorityQueue.h" +#include "Reporter.h" #include "util.h" PriorityQueue::PriorityQueue(int initial_size) @@ -52,7 +53,7 @@ PQ_Element* PriorityQueue::Remove(PQ_Element* e) PQ_Element* e2 = Remove(); if ( e != e2 ) - internal_error("inconsistency in PriorityQueue::Remove"); + reporter->InternalError("inconsistency in PriorityQueue::Remove"); return e2; } diff --git a/src/RE.cc b/src/RE.cc index 73584c14d1..af72d84519 100644 --- a/src/RE.cc +++ b/src/RE.cc @@ -114,7 +114,7 @@ int Specific_RE_Matcher::Compile(int lazy) RE_set_input(pattern_text); if ( RE_parse() ) { - run_time("error compiling pattern /%s/", pattern_text); + reporter->Error("error compiling pattern /%s/", pattern_text); return 0; } @@ -134,7 +134,7 @@ int Specific_RE_Matcher::Compile(int lazy) int Specific_RE_Matcher::CompileSet(const string_list& set, const int_list& idx) { if ( set.length() != idx.length() ) - internal_error("compileset: lengths of sets differ"); + reporter->InternalError("compileset: lengths of sets differ"); rem = this; @@ -145,7 +145,7 @@ int Specific_RE_Matcher::CompileSet(const string_list& set, const int_list& idx) RE_set_input(set[i]); if ( RE_parse() ) { - run_time("error compiling pattern /%s/", set[i]); + reporter->Error("error compiling pattern /%s/", set[i]); return 0; } diff --git a/src/RPC.cc b/src/RPC.cc index 915f2efe9e..02fb20a436 100644 --- a/src/RPC.cc +++ b/src/RPC.cc @@ -263,7 +263,7 @@ int RPC_Interpreter::DeliverRPC(const u_char* buf, int n, int rpclen, } else if ( n < 0 ) - internal_error("RPC underflow"); + reporter->InternalError("RPC underflow"); return 1; } @@ -473,7 +473,7 @@ bool Contents_RPC::CheckResync(int& len, const u_char*& data, bool orig) if ( resync_toskip != 0 ) // Should never happen. - internal_error("RPC resync: skipping over data failed"); + reporter->InternalError("RPC resync: skipping over data failed"); // Now lets see whether data points to the beginning of a RPC // frame. If the resync processs is successful, we should be @@ -623,9 +623,7 @@ void Contents_RPC::DeliverStream(int len, const u_char* data, bool orig) marker_buf.Init(4,4); if ( ! dummy_p ) - { - internal_error("inconsistent RPC record marker extraction"); - } + reporter->InternalError("inconsistent RPC record marker extraction"); last_frag = (marker & 0x80000000) != 0; marker &= 0x7fffffff; diff --git a/src/RSH.cc b/src/RSH.cc index bfc78d04b7..0b833697fd 100644 --- a/src/RSH.cc +++ b/src/RSH.cc @@ -127,7 +127,7 @@ void Contents_Rsh_Analyzer::DoDeliver(int len, const u_char* data) break; default: - internal_error("bad state in Contents_Rsh_Analyzer::DoDeliver"); + reporter->InternalError("bad state in Contents_Rsh_Analyzer::DoDeliver"); break; } } @@ -179,7 +179,7 @@ void Rsh_Analyzer::DeliverStream(int len, const u_char* data, bool orig) void Rsh_Analyzer::ClientUserName(const char* s) { if ( client_name ) - internal_error("multiple rsh client names"); + reporter->InternalError("multiple rsh client names"); client_name = new StringVal(s); } @@ -187,7 +187,7 @@ void Rsh_Analyzer::ClientUserName(const char* s) void Rsh_Analyzer::ServerUserName(const char* s) { if ( username ) - internal_error("multiple rsh initial client names"); + reporter->InternalError("multiple rsh initial client names"); username = new StringVal(s); } diff --git a/src/Reassem.cc b/src/Reassem.cc index 0153bde178..319fcbff3b 100644 --- a/src/Reassem.cc +++ b/src/Reassem.cc @@ -24,7 +24,7 @@ DataBlock::DataBlock(const u_char* data, int size, int arg_seq, block = new u_char[size]; if ( ! block ) - internal_error("out of memory"); + reporter->InternalError("out of memory"); memcpy((void*) block, (const void*) data, size); diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 6f33a33bca..c4869e4328 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -186,6 +186,7 @@ #include "File.h" #include "Conn.h" #include "LogMgr.h" +#include "Reporter.h" extern "C" { #include "setsignal.h" @@ -393,7 +394,7 @@ static bool sendToIO(ChunkedIO* io, ChunkedIO::Chunk* c) { if ( ! io->Write(c) ) { - warn(fmt("can't send chunk: %s", io->Error())); + reporter->Warning(fmt("can't send chunk: %s", io->Error())); return false; } @@ -405,7 +406,7 @@ static bool sendToIO(ChunkedIO* io, char msg_type, RemoteSerializer::PeerID id, { if ( ! sendCMsg(io, msg_type, id) ) { - warn(fmt("can't send message of type %d: %s", msg_type, io->Error())); + reporter->Warning(fmt("can't send message of type %d: %s", msg_type, io->Error())); return false; } @@ -420,7 +421,7 @@ static bool sendToIO(ChunkedIO* io, char msg_type, RemoteSerializer::PeerID id, { if ( ! sendCMsg(io, msg_type, id) ) { - warn(fmt("can't send message of type %d: %s", msg_type, io->Error())); + reporter->Warning(fmt("can't send message of type %d: %s", msg_type, io->Error())); return false; } @@ -663,7 +664,7 @@ void RemoteSerializer::Fork() setpriority(PRIO_PROCESS, 0, 5); child.Run(); - internal_error("cannot be reached"); + reporter->InternalError("cannot be reached"); } } @@ -674,7 +675,7 @@ RemoteSerializer::PeerID RemoteSerializer::Connect(addr_type ip, uint16 port, return true; if ( ! initialized ) - internal_error("remote serializer not initialized"); + reporter->InternalError("remote serializer not initialized"); #ifdef BROv6 if ( ! is_v4_addr(ip) ) @@ -735,13 +736,13 @@ bool RemoteSerializer::RequestSync(PeerID id, bool auth) Peer* peer = LookupPeer(id, true); if ( ! peer ) { - run_time(fmt("unknown peer id %d for request sync", int(id))); + reporter->Error(fmt("unknown peer id %d for request sync", int(id))); return false; } if ( peer->phase != Peer::HANDSHAKE ) { - run_time(fmt("can't request sync from peer; wrong phase %d", + reporter->Error(fmt("can't request sync from peer; wrong phase %d", peer->phase)); return false; } @@ -762,13 +763,13 @@ bool RemoteSerializer::RequestLogs(PeerID id) Peer* peer = LookupPeer(id, true); if ( ! peer ) { - run_time(fmt("unknown peer id %d for request logs", int(id))); + reporter->Error(fmt("unknown peer id %d for request logs", int(id))); return false; } if ( peer->phase != Peer::HANDSHAKE ) { - run_time(fmt("can't request logs from peer; wrong phase %d", + reporter->Error(fmt("can't request logs from peer; wrong phase %d", peer->phase)); return false; } @@ -787,13 +788,13 @@ bool RemoteSerializer::RequestEvents(PeerID id, RE_Matcher* pattern) Peer* peer = LookupPeer(id, true); if ( ! peer ) { - run_time(fmt("unknown peer id %d for request sync", int(id))); + reporter->Error(fmt("unknown peer id %d for request sync", int(id))); return false; } if ( peer->phase != Peer::HANDSHAKE ) { - run_time(fmt("can't request events from peer; wrong phase %d", + reporter->Error(fmt("can't request events from peer; wrong phase %d", peer->phase)); return false; } @@ -854,7 +855,7 @@ bool RemoteSerializer::CompleteHandshake(PeerID id) if ( p->phase != Peer::HANDSHAKE ) { - run_time(fmt("can't complete handshake; wrong phase %d", + reporter->Error(fmt("can't complete handshake; wrong phase %d", p->phase)); return false; } @@ -1123,7 +1124,7 @@ bool RemoteSerializer::SendCaptureFilter(PeerID id, const char* filter) if ( peer->phase != Peer::HANDSHAKE ) { - run_time(fmt("can't sent capture filter to peer; wrong phase %d", peer->phase)); + reporter->Error(fmt("can't sent capture filter to peer; wrong phase %d", peer->phase)); return false; } @@ -1200,7 +1201,7 @@ bool RemoteSerializer::SendCapabilities(Peer* peer) { if ( peer->phase != Peer::HANDSHAKE ) { - run_time(fmt("can't sent capabilties to peer; wrong phase %d", + reporter->Error(fmt("can't sent capabilties to peer; wrong phase %d", peer->phase)); return false; } @@ -1223,7 +1224,7 @@ bool RemoteSerializer::Listen(addr_type ip, uint16 port, bool expect_ssl) return true; if ( ! initialized ) - internal_error("remote serializer not initialized"); + reporter->InternalError("remote serializer not initialized"); #ifdef BROv6 if ( ! is_v4_addr(ip) ) @@ -1545,10 +1546,11 @@ bool RemoteSerializer::Poll(bool may_block) } default: - internal_error("unknown msgstate"); + reporter->InternalError("unknown msgstate"); } - internal_error("cannot be reached"); + reporter->InternalError("cannot be reached"); + return false; } bool RemoteSerializer::DoMessage() @@ -1662,7 +1664,7 @@ bool RemoteSerializer::DoMessage() return true; // keep going } - internal_error("cannot be reached"); + reporter->InternalError("cannot be reached"); return false; } @@ -1953,7 +1955,7 @@ bool RemoteSerializer::ProcessConnected() ID* descr = global_scope()->Lookup("peer_description"); if ( ! descr ) - internal_error("peer_description not defined"); + reporter->InternalError("peer_description not defined"); SerialInfo info(this); SendID(&info, current_peer, *descr); @@ -2136,7 +2138,7 @@ bool RemoteSerializer::HandshakeDone(Peer* peer) else if ( peer->sync_requested & Peer::WE ) peer->send_state = false; else - internal_error("illegal sync_requested value"); + reporter->InternalError("illegal sync_requested value"); } else { @@ -2834,7 +2836,7 @@ void RemoteSerializer::GotStateAccess(StateAccess* s) void RemoteSerializer::GotTimer(Timer* s) { - run_time("RemoteSerializer::GotTimer not implemented"); + reporter->Error("RemoteSerializer::GotTimer not implemented"); } void RemoteSerializer::GotPacket(Packet* p) @@ -2938,7 +2940,7 @@ bool RemoteSerializer::SendCMsgToChild(char msg_type, Peer* peer) { if ( ! sendCMsg(io, msg_type, peer ? peer->id : PEER_NONE) ) { - warn(fmt("can't send message of type %d: %s", + reporter->Warning(fmt("can't send message of type %d: %s", msg_type, io->Error())); return false; } @@ -3011,7 +3013,7 @@ void RemoteSerializer::FatalError(const char* msg) { msg = fmt("fatal error, shutting down communication: %s", msg); Log(LogError, msg); - error(msg); + reporter->Error(msg); closed = true; kill(child_pid, SIGQUIT); @@ -3052,7 +3054,7 @@ void RemoteSerializer::InternalCommError(const char* msg) #ifdef DEBUG_COMMUNICATION DumpDebugData(); #else - internal_error("%s", msg); + reporter->InternalError("%s", msg); #endif } @@ -3073,7 +3075,7 @@ static ChunkedIO* openDump(const char* file) if ( fd < 0 ) { - fprintf(stderr, "cannot open %s: %s\n", file, strerror(errno)); + reporter->Error("cannot open %s: %s\n", file, strerror(errno)); return 0; } @@ -3090,7 +3092,7 @@ void RemoteSerializer::ReadDumpAsMessageType(const char* file) if ( ! io->Read(&chunk, true ) ) { - fprintf(stderr, "cannot read %s: %s\n", file, strerror(errno)); + reporter->Error("cannot read %s: %s\n", file, strerror(errno)); return; } @@ -3405,11 +3407,11 @@ bool SocketComm::ProcessParentMessage() } default: - internal_error("unknown msg type %d", parent_msgtype); + reporter->InternalError("unknown msg type %d", parent_msgtype); return true; } - internal_error("cannot be reached"); + reporter->InternalError("cannot be reached"); } case ARGS: @@ -3432,10 +3434,11 @@ bool SocketComm::ProcessParentMessage() } default: - internal_error("unknown msgstate"); + reporter->InternalError("unknown msgstate"); } - internal_error("cannot be reached"); + reporter->InternalError("cannot be reached"); + return false; } bool SocketComm::DoParentMessage() @@ -3493,7 +3496,7 @@ bool SocketComm::DoParentMessage() peers[j]->io->DumpDebugData(fmt("comm-dump.child.peer.%d", id), false); } #else - internal_error("DEBUG_DUMP support not compiled in"); + reporter->InternalError("DEBUG_DUMP support not compiled in"); #endif return true; } @@ -3553,10 +3556,11 @@ bool SocketComm::DoParentMessage() return ForwardChunkToPeer(); default: - internal_error("ProcessParentMessage: unexpected state"); + reporter->InternalError("ProcessParentMessage: unexpected state"); } - internal_error("cannot be reached"); + reporter->InternalError("cannot be reached"); + return false; } bool SocketComm::ForwardChunkToPeer() @@ -3616,7 +3620,7 @@ bool SocketComm::ProcessListen() bool SocketComm::ProcessParentCompress() { #ifndef HAVE_LIBZ - internal_error("supposed to enable compression but don't have zlib"); + reporter->InternalError("supposed to enable compression but don't have zlib"); return false; #else @@ -3736,10 +3740,11 @@ bool SocketComm::ProcessRemoteMessage(SocketComm::Peer* peer) } default: - internal_error("ProcessRemoteMessage: unexpected state"); + reporter->InternalError("ProcessRemoteMessage: unexpected state"); } - return true; + assert(false); // Cannot be reached. + return false; } bool SocketComm::ForwardChunkToParent(Peer* peer, ChunkedIO::Chunk* c) diff --git a/src/Reporter.cc b/src/Reporter.cc new file mode 100644 index 0000000000..6dd3c00d0f --- /dev/null +++ b/src/Reporter.cc @@ -0,0 +1,311 @@ +// +// See the file "COPYING" in the main distribution directory for copyright. +// + +#include + +#include "config.h" +#include "Reporter.h" +#include "Event.h" +#include "NetVar.h" +#include "Net.h" +#include "Conn.h" + +#ifdef SYSLOG_INT +extern "C" { +int openlog(const char* ident, int logopt, int facility); +int syslog(int priority, const char* message_fmt, ...); +int closelog(); +} +#endif + +Reporter* reporter = 0; + +Reporter::Reporter() + { + errors = 0; + via_events = false; + in_error_handler = 0; + + openlog("bro", 0, LOG_LOCAL5); + } + +Reporter::~Reporter() + { + closelog(); + } + +void Reporter::Message(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + DoLog("", reporter_message, stderr, 0, 0, true, true, fmt, ap); + va_end(ap); + } + +void Reporter::Warning(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + DoLog("warning", reporter_warning, stderr, 0, 0, true, true, fmt, ap); + va_end(ap); + } + +void Reporter::Error(const char* fmt, ...) + { + ++errors; + va_list ap; + va_start(ap, fmt); + DoLog("error", reporter_error, stderr, 0, 0, true, true, fmt, ap); + va_end(ap); + } + +void Reporter::FatalError(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + + // Always log to stderr. + DoLog("fatal error", 0, stderr, 0, 0, true, false, fmt, ap); + + va_end(ap); + + set_processing_status("TERMINATED", "fatal_error"); + exit(1); + } + +void Reporter::FatalErrorWithCore(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + + // Always log to stderr. + DoLog("fatal error", 0, stderr, 0, 0, true, false, fmt, ap); + + va_end(ap); + + set_processing_status("TERMINATED", "fatal_error"); + abort(); + } + +void Reporter::InternalError(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + + // Always log to stderr. + DoLog("internal error", 0, stderr, 0, 0, true, false, fmt, ap); + + va_end(ap); + + set_processing_status("TERMINATED", "internal_error"); + abort(); + } + +void Reporter::InternalWarning(const char* fmt, ...) + { + va_list ap; + va_start(ap, fmt); + DoLog("internal warning", reporter_warning, stderr, 0, 0, true, true, fmt, ap); + va_end(ap); + } + +void Reporter::Syslog(const char* fmt, ...) + { + if ( reading_traces ) + return; + + va_list ap; + va_start(ap, fmt); + vsyslog(LOG_NOTICE, fmt, ap); + va_end(ap); + } + +void Reporter::WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* name, const char* addl, ...) + { + val_list* vl = new val_list(1); + + if ( conn_val ) + vl->append(conn_val); + + if ( addl ) + vl->append(new StringVal(addl)); + + va_list ap; + va_start(ap, addl); + DoLog("weird", event, stderr, 0, vl, false, false, name, ap); + va_end(ap); + + delete vl; + } + +void Reporter::WeirdFlowHelper(addr_type orig, addr_type resp, const char* name, ...) + { + val_list* vl = new val_list(2); + vl->append(new AddrVal(orig)); + vl->append(new AddrVal(resp)); + + va_list ap; + va_start(ap, name); + DoLog("weird", flow_weird, stderr, 0, vl, false, false, name, ap); + va_end(ap); + + delete vl; + } + +void Reporter::Weird(const char* name) + { + WeirdHelper(net_weird, 0, name, 0); + } + +void Reporter::Weird(Connection* conn, const char* name, const char* addl) + { + WeirdHelper(conn_weird, conn->BuildConnVal(), name, addl); + } + +void Reporter::Weird(Val* conn_val, const char* name, const char* addl) + { + WeirdHelper(conn_weird, conn_val, name, addl); + } + +void Reporter::Weird(addr_type orig, addr_type resp, const char* name) + { + WeirdFlowHelper(orig, resp, name); + } + +void Reporter::DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Connection* conn, val_list* addl, bool location, bool time, const char* fmt, va_list ap) + { + static char tmp[512]; + + int size = sizeof(tmp); + char* buffer = tmp; + char* alloced = 0; + + string loc_str; + + if ( location ) + { + string loc_file = ""; + int loc_line = 0; + + if ( locations.size() ) + { + ODesc d; + + std::pair locs = locations.back(); + + if ( locs.first ) + { + if ( locs.first != &no_location ) + locs.first->Describe(&d); + + else + d.Add(""); + + if ( locs.second ) + { + d.Add(" and "); + + if ( locs.second != &no_location ) + locs.second->Describe(&d); + + else + d.Add(""); + + } + } + + loc_str = d.Description(); + } + + else if ( filename && *filename ) + { + // Take from globals. + loc_str = filename; + char tmp[32]; + snprintf(tmp, 32, "%d", line_number); + loc_str += string(", line ") + string(tmp); + } + } + + while ( true ) + { + va_list aq; + va_copy(aq, ap); + int n = vsnprintf(buffer, size, fmt, aq); + va_end(aq); + + if ( n > -1 && n < size ) + // We had enough space; + break; + + // Enlarge buffer; + size *= 2; + buffer = alloced = (char *)realloc(alloced, size); + + if ( ! buffer ) + FatalError("out of memory in Reporter"); + } + + if ( event && via_events && ! in_error_handler ) + { + val_list* vl = new val_list; + + if ( time ) + vl->append(new Val((bro_start_network_time != 0.0) ? network_time : 0, TYPE_TIME)); + + vl->append(new StringVal(buffer)); + + if ( location ) + vl->append(new StringVal(loc_str.c_str())); + + if ( conn ) + vl->append(conn->BuildConnVal()); + + if ( addl ) + { + loop_over_list(*addl, i) + vl->append((*addl)[i]); + } + + if ( conn ) + conn->ConnectionEvent(event, 0, vl); + else + mgr.QueueEvent(event, vl); + } + + else + { + string s = ""; + + if ( bro_start_network_time != 0.0 ) + { + char tmp[32]; + snprintf(tmp, 32, "%.6f", network_time); + s += string(tmp) + " "; + } + + if ( prefix && *prefix ) + { + if ( loc_str != "" ) + s += string(prefix) + " in " + loc_str + ": "; + else + s += string(prefix) + ": "; + } + + else + { + if ( loc_str != "" ) + s += loc_str + ": "; + } + + s += buffer; + s += "\n"; + + fprintf(out, s.c_str()); + } + + if ( alloced ) + free(alloced); + } + diff --git a/src/Reporter.h b/src/Reporter.h new file mode 100644 index 0000000000..ff1ceecd61 --- /dev/null +++ b/src/Reporter.h @@ -0,0 +1,104 @@ +// See the file "COPYING" in the main distribution directory for copyright. + +#ifndef REPORTER_H +#define REPORTER_H + +#include + +#include +#include + +#include "util.h" +#include "net_util.h" +#include "EventHandler.h" + +class Connection; +class Location; + +class Reporter { +public: + Reporter(); + ~Reporter(); + + // Report an informational message, nothing that needs specific + // attention. + void Message(const char* fmt, ...); + + // Report a warning that may indicate a problem. + void Warning(const char* fmt, ...); + + // Report a non-fatal error. Processing proceeds normally after the error + // has been reported. + void Error(const char* fmt, ...); + + // Returns the number of errors reported so far. + int Errors() { return errors; } + + // Report a fatal error. Bro will terminate after the message has been + // reported. + void FatalError(const char* fmt, ...); + + // Report a fatal error. Bro will terminate after the message has been + // reported and always generate a core dump. + void FatalErrorWithCore(const char* fmt, ...); + + // Report a traffic weirdness, i.e., an unexpected protocol situation + // that may lead to incorrectly processing a connnection. + void Weird(const char* name); // Raises net_weird(). + void Weird(Connection* conn, const char* name, const char* addl = ""); // Raises conn_weird(). + void Weird(Val* conn_val, const char* name, const char* addl = ""); // Raises conn_weird(). + void Weird(addr_type orig, addr_type resp, const char* name); // Raises flow_weird(). + + // Syslog a message. This methods does nothing if we're running + // offline from a trace. + void Syslog(const char* fmt, ...); + + // Report about a potential internal problem. Bro will continue + // normally. + void InternalWarning(const char* fmt, ...); + + // Report an internal program error. Bro will terminate with a core + // dump after the message has been reported. + void InternalError(const char* fmt, ...); + + // Toggle whether non-fatal messages should be reported through the + // scripting layer rather on standard output. Fatal errors are always + // reported via stderr. + void ReportViaEvents(bool arg_via_events) { via_events = arg_via_events; } + + // Associates the given location with subsequent output. We create a + // stack of location so that the most recent is always the one that + // will be assumed to be the current one. The pointer must remain + // valid until the location is popped. + void PushLocation(const Location* location) + { locations.push_back(std::pair(location, 0)); } + + void PushLocation(const Location* loc1, const Location* loc2) + { locations.push_back(std::pair(loc1, loc2)); } + + // Removes the top-most location information from stack. + void PopLocation() + { locations.pop_back(); } + + // Signals that we're entering processing an error handler event. + void BeginErrorHandler() { ++in_error_handler; } + + // Signals that we're done processing an error handler event. + void EndErrorHandler() { --in_error_handler; } + +private: + void DoLog(const char* prefix, EventHandlerPtr event, FILE* out, Connection* conn, val_list* addl, bool location, bool time, const char* fmt, va_list ap); + + void WeirdHelper(EventHandlerPtr event, Val* conn_val, const char* name, const char* addl, ...); + void WeirdFlowHelper(addr_type orig, addr_type resp, const char* name, ...); + + int errors; + bool via_events; + int in_error_handler; + + std::list > locations; +}; + +extern Reporter* reporter; + +#endif diff --git a/src/Rlogin.cc b/src/Rlogin.cc index 043baade7e..8404eacca7 100644 --- a/src/Rlogin.cc +++ b/src/Rlogin.cc @@ -192,7 +192,7 @@ void Contents_Rlogin_Analyzer::DoDeliver(int len, const u_char* data) break; default: - internal_error("bad state in Contents_Rlogin_Analyzer::DoDeliver"); + reporter->InternalError("bad state in Contents_Rlogin_Analyzer::DoDeliver"); break; } } @@ -223,7 +223,7 @@ Rlogin_Analyzer::Rlogin_Analyzer(Connection* conn) void Rlogin_Analyzer::ClientUserName(const char* s) { if ( client_name ) - internal_error("multiple rlogin client names"); + reporter->InternalError("multiple rlogin client names"); client_name = new StringVal(s); } diff --git a/src/RuleCondition.cc b/src/RuleCondition.cc index 9067b39fb9..78dbee39cd 100644 --- a/src/RuleCondition.cc +++ b/src/RuleCondition.cc @@ -113,7 +113,7 @@ bool RuleConditionPayloadSize::DoMatch(Rule* rule, RuleEndpointState* state, return payload_size >= val; default: - internal_error("unknown comparision type"); + reporter->InternalError("unknown comparision type"); } // Should not be reached @@ -135,7 +135,7 @@ bool RuleConditionEval::DoMatch(Rule* rule, RuleEndpointState* state, { if ( ! id->HasVal() ) { - run_time("undefined value"); + reporter->Error("undefined value"); return false; } diff --git a/src/RuleMatcher.cc b/src/RuleMatcher.cc index 83e13c8737..1ca891883d 100644 --- a/src/RuleMatcher.cc +++ b/src/RuleMatcher.cc @@ -10,6 +10,7 @@ #include "NetVar.h" #include "Scope.h" #include "File.h" +#include "Reporter.h" // FIXME: Things that are not fully implemented/working yet: // @@ -200,7 +201,7 @@ bool RuleMatcher::ReadFiles(const name_list& files) rules_in = search_for_file(files[i], "sig", 0, false, 0); if ( ! rules_in ) { - error("Can't open signature file", files[i]); + reporter->Error("Can't open signature file", files[i]); return false; } @@ -400,7 +401,7 @@ static inline uint32 getval(const u_char* data, int size) return ntohl(*(uint32*) data); default: - internal_error("illegal HdrTest size"); + reporter->InternalError("illegal HdrTest size"); } // Should not be reached. @@ -513,7 +514,7 @@ RuleEndpointState* RuleMatcher::InitEndpoint(Analyzer* analyzer, default: data = 0; - internal_error("unknown protocol"); + reporter->InternalError("unknown protocol"); } // ### data can be nil here if it's an @@ -542,7 +543,7 @@ RuleEndpointState* RuleMatcher::InitEndpoint(Analyzer* analyzer, DO_MATCH_OR(*h->vals, getval(data + h->offset, h->size), >=); default: - internal_error("unknown comparision type"); + reporter->InternalError("unknown comparision type"); } no_match: @@ -569,7 +570,7 @@ void RuleMatcher::Match(RuleEndpointState* state, Rule::PatternType type, { if ( ! state ) { - warn("RuleEndpointState not initialized yet."); + reporter->Warning("RuleEndpointState not initialized yet."); return; } diff --git a/src/SMB.cc b/src/SMB.cc index e33c7ac73a..5b3db68db9 100644 --- a/src/SMB.cc +++ b/src/SMB.cc @@ -6,6 +6,7 @@ #include "SMB.h" #include "smb_pac.h" #include "Val.h" +#include "Reporter.h" namespace { const bool DEBUG_smb_ipc = true; @@ -732,7 +733,7 @@ int SMB_Session::ParseTransaction(int is_orig, int cmd, break; default: - internal_error("command mismatch for ParseTransaction"); + reporter->InternalError("command mismatch for ParseTransaction"); } int ret; @@ -932,7 +933,7 @@ void SMB_Session::Weird(const char* msg) // input can be in Unicode (little endian), and the returned string // will be in ASCII. Note, Unicode strings have NUL characters // at the end of them already. Adding an additional NUL byte at -// the end leads to embedded-NUL warnings (CheckString() run_time error). +// the end leads to embedded-NUL warnings (CheckString() run time error). BroString* SMB_Session::ExtractString(binpac::SMB::SMB_string const* s) { diff --git a/src/SMTP.cc b/src/SMTP.cc index f6396bafa6..5822d9d75f 100644 --- a/src/SMTP.cc +++ b/src/SMTP.cc @@ -10,6 +10,7 @@ #include "SMTP.h" #include "Event.h" #include "ContentLine.h" +#include "Reporter.h" #undef SMTP_CMD_DEF #define SMTP_CMD_DEF(cmd) #cmd, @@ -865,7 +866,7 @@ void SMTP_Analyzer::BeginData() skip_data = 0; // reset the flag at the beginning of the mail if ( mail != 0 ) { - warn("nested mail transaction"); + reporter->Warning("nested mail transaction"); mail->Done(); delete mail; } @@ -876,7 +877,7 @@ void SMTP_Analyzer::BeginData() void SMTP_Analyzer::EndData() { if ( ! mail ) - warn("Unmatched end of data"); + reporter->Warning("Unmatched end of data"); else { mail->Done(); diff --git a/src/SSL-binpac.cc b/src/SSL-binpac.cc index c8077c4e40..ec1fd206f6 100644 --- a/src/SSL-binpac.cc +++ b/src/SSL-binpac.cc @@ -1,5 +1,6 @@ #include "SSL-binpac.h" #include "TCP_Reassembler.h" +#include "Reporter.h" #include "util.h" SSL_Analyzer_binpac::SSL_Analyzer_binpac(Connection* c) diff --git a/src/SSLv2.cc b/src/SSLv2.cc new file mode 100644 index 0000000000..f699b7bfdb --- /dev/null +++ b/src/SSLv2.cc @@ -0,0 +1,946 @@ +// $Id: SSLv2.cc 5988 2008-07-19 07:02:12Z vern $ + +#include "SSLv2.h" +#include "SSLv3.h" + +// --- Initalization of static variables -------------------------------------- + +uint SSLv2_Interpreter::totalConnections = 0; +uint SSLv2_Interpreter::analyzedConnections = 0; +uint SSLv2_Interpreter::openedConnections = 0; +uint SSLv2_Interpreter::failedConnections = 0; +uint SSLv2_Interpreter::weirdConnections = 0; +uint SSLv2_Interpreter::totalRecords = 0; +uint SSLv2_Interpreter::clientHelloRecords = 0; +uint SSLv2_Interpreter::serverHelloRecords = 0; +uint SSLv2_Interpreter::clientMasterKeyRecords = 0; +uint SSLv2_Interpreter::errorRecords = 0; + + +// --- SSLv2_Interpreter ------------------------------------------------------- + +/*! + * The Constructor. + * + * \param proxy Pointer to the SSLProxy_Analyzer who created this instance. + */ +SSLv2_Interpreter::SSLv2_Interpreter(SSLProxy_Analyzer* proxy) +: SSL_Interpreter(proxy) + { + ++totalConnections; + records = 0; + bAnalyzedCounted = false; + connState = START; + + pServerCipherSpecs = 0; + pClientCipherSpecs = 0; + bClientWantsCachedSession = false; + usedCipherSpec = (SSLv2_CipherSpec) 0; + + pConnectionId = 0; + pChallenge = 0; + pSessionId = 0; + pMasterClearKey = 0; + pMasterEncryptedKey = 0; + pClientReadKey = 0; + pServerReadKey = 0; + } + +/*! + * The Destructor. + */ +SSLv2_Interpreter::~SSLv2_Interpreter() + { + if ( connState != CLIENT_MASTERKEY_SEEN && + connState != CACHED_SESSION && + connState != START && // we only complain if we saw some data + connState != ERROR_SEEN ) + ++failedConnections; + + if ( connState != CLIENT_MASTERKEY_SEEN && connState != CACHED_SESSION ) + ++weirdConnections; + + delete pServerCipherSpecs; + delete pClientCipherSpecs; + delete pConnectionId; + delete pChallenge; + delete pSessionId; + delete pMasterClearKey; + delete pMasterEncryptedKey; + delete pClientReadKey; + delete pServerReadKey; + } + +/*! + * This method implements SSL_Interpreter::BuildInterpreterEndpoints() + */ +void SSLv2_Interpreter::BuildInterpreterEndpoints() + { + orig = new SSLv2_Endpoint(this, 1); + resp = new SSLv2_Endpoint(this, 0); + } + +/*! + * This method prints some counters. + */ +void SSLv2_Interpreter::printStats() + { + printf("SSLv2:\n"); + printf("totalConnections = %u\n", totalConnections); + printf("analyzedConnections = %u\n", analyzedConnections); + printf("openedConnections = %u\n", openedConnections); + printf("failedConnections = %u\n", failedConnections); + printf("weirdConnections = %u\n", weirdConnections); + + printf("totalRecords = %u\n", totalRecords); + printf("clientHelloRecords = %u\n", clientHelloRecords); + printf("serverHelloRecords = %u\n", serverHelloRecords); + printf("clientMasterKeyRecords = %u\n", clientMasterKeyRecords); + printf("errorRecords = %u\n", errorRecords); + + printf("SSL_RecordBuilder::maxAllocCount = %u\n", SSL_RecordBuilder::maxAllocCount); + printf("SSL_RecordBuilder::maxFragmentCount = %u\n", SSL_RecordBuilder::maxFragmentCount); + printf("SSL_RecordBuilder::fragmentedHeaders = %u\n", SSL_RecordBuilder::fragmentedHeaders); + } + +/*! + * \return the current state of the ssl connection + */ +SSLv2_States SSLv2_Interpreter::ConnState() + { + return connState; + } + +/*! + * This method is called by SSLv2_Endpoint::Deliver(). It is the main entry + * point of this class. The header of the given SSLV2 record is analyzed and + * its contents are then passed to the corresponding analyzer method. After + * the record has been analyzed, the ssl connection state is updated. + * + * \param s Pointer to the endpoint which sent the record + * \param length length of SSLv2 record + * \param data pointer to SSLv2 record to analyze + */ +void SSLv2_Interpreter::NewSSLRecord(SSL_InterpreterEndpoint* s, + int length, const u_char* data) + { + ++records; + ++totalRecords; + + if ( ! bAnalyzedCounted ) + { + ++analyzedConnections; + bAnalyzedCounted = true; + } + + // We should see a maximum of 4 cleartext records. + if ( records == 5 ) + { // so this should never happen + Weird("SSLv2: Saw more than 4 records, skipping connection..."); + proxy->SetSkip(1); + return; + } + + // SSLv2 record header analysis + uint32 recordLength = 0; // data length of SSLv2 record + bool isEscape = false; + uint8 padding = 0; + const u_char* contents; + + if ( (data[0] & 0x80) > 0 ) + { // we have a two-byte record header + recordLength = ((data[0] & 0x7f) << 8) | data[1]; + contents = data + 2; + if ( recordLength + 2 != uint32(length) ) + { + // This should never happen, otherwise + // we have a bug in the SSL_RecordBuilder. + Weird("SSLv2: FATAL: recordLength doesn't match data block length!"); + connState = ERROR_REQUIRED; + proxy->SetSkip(1); + return; + } + } + else + { // We have a three-byte record header. + recordLength = ((data[0] & 0x3f) << 8) | data[1]; + isEscape = (data[0] & 0x40) != 0; + padding = data[2]; + contents = data + 3; + if ( recordLength + 3 != uint32(length) ) + { + // This should never happen, otherwise + // we have a bug in the SSL_RecordBuilder. + Weird("SSLv2: FATAL: recordLength doesn't match data block length!"); + connState = ERROR_REQUIRED; + proxy->SetSkip(1); + return; + } + + if ( padding == 0 && ! isEscape ) + Weird("SSLv2: 3 Byte record header, but no escape, no padding!"); + } + + if ( recordLength == 0 ) + { + Weird("SSLv2: Record length is zero (no record data)!"); + return; + } + + if ( isEscape ) + Weird("SSLv2: Record has escape bit set (security escape)!"); + + if ( padding > 0 && connState != CACHED_SESSION && + connState != CLIENT_MASTERKEY_SEEN ) + Weird("SSLv2 record with padding > 0 in cleartext!"); + + // MISSING: + // A final consistency check is done when a block cipher is used + // and the protocol is using encryption. The amount of data present + // in a record (RECORD-LENGTH))must be a multiple of the cipher's + // block size. If the received record is not a multiple of the + // cipher's block size then the record is considered damaged, and it + // is to be treated as if an "I/O Error" had occurred (i.e. an + // unrecoverable error is asserted and the connection is closed). + + switch ( connState ) { + case START: + // Only CLIENT-HELLLOs allowed here. + if ( contents[0] != SSLv2_MT_CLIENT_HELLO ) + { + Weird("SSLv2: First packet is not a CLIENT-HELLO!"); + analyzeRecord(s, recordLength, contents); + connState = ERROR_REQUIRED; + } + else + connState = ClientHelloRecord(s, recordLength, contents); + break; + + case CLIENT_HELLO_SEEN: + // Only SERVER-HELLOs or ERRORs allowed here. + if ( contents[0] == SSLv2_MT_SERVER_HELLO ) + connState = ServerHelloRecord(s, recordLength, contents); + else if ( contents[0] == SSLv2_MT_ERROR ) + connState = ErrorRecord(s, recordLength, contents); + else + { + Weird("SSLv2: State violation in CLIENT_HELLO_SEEN!"); + analyzeRecord(s, recordLength, contents); + connState = ERROR_REQUIRED; + } + break; + + case NEW_SESSION: + // We expect a client master key. + if ( contents[0] == SSLv2_MT_CLIENT_MASTER_KEY ) + connState = ClientMasterKeyRecord(s, recordLength, contents); + else if ( contents[0] == SSLv2_MT_ERROR ) + connState = ErrorRecord(s, recordLength, contents); + else + { + Weird("SSLv2: State violation in NEW_SESSION or encrypted record!"); + analyzeRecord(s, recordLength, contents); + connState = ERROR_REQUIRED; + } + + delete pServerCipherSpecs; + pServerCipherSpecs = 0; + break; + + case CACHED_SESSION: + delete pServerCipherSpecs; + pServerCipherSpecs = 0; + // No break here. + + case CLIENT_MASTERKEY_SEEN: + // If no error record, no further analysis. + if ( contents[0] == SSLv2_MT_ERROR && + recordLength == SSLv2_ERROR_RECORD_SIZE ) + connState = ErrorRecord(s, recordLength, contents); + else + { + // So we finished the cleartext handshake. + // Skip all further data. + + proxy->SetSkip(1); + ++openedConnections; + } + break; + + case ERROR_REQUIRED: + if ( contents[0] == SSLv2_MT_ERROR ) + connState = ErrorRecord(s, recordLength, contents); + else + { + // We lost tracking: this should not happen. + Weird("SSLv2: State inconsistency in ERROR_REQUIRED (lost tracking!)!"); + analyzeRecord(s, recordLength, contents); + connState = ERROR_REQUIRED; + } + break; + + case ERROR_SEEN: + // We don't have recoverable errors in cleartext phase, + // so we shouldn't see anymore packets. + Weird("SSLv2: Traffic after error record!"); + analyzeRecord(s, recordLength, contents); + break; + + default: + reporter->InternalError("SSLv2: unknown state"); + break; + } + } + +/*! + * This method is called whenever the connection tracking failed. It calls + * the corresponding analyzer method for the given SSLv2 record, but does not + * update the ssl connection state. + * + * \param s Pointer to the endpoint which sent the record + * \param length length of SSLv2 record + * \param data pointer to SSLv2 record to analyze + */ +void SSLv2_Interpreter::analyzeRecord(SSL_InterpreterEndpoint* s, + int length, const u_char* data) + { + switch ( data[0] ) { + case SSLv2_MT_ERROR: + ErrorRecord(s, length, data); + break; + + case SSLv2_MT_CLIENT_HELLO: + ClientHelloRecord(s, length, data); + break; + + case SSLv2_MT_CLIENT_MASTER_KEY: + ClientMasterKeyRecord(s, length, data); + break; + + case SSLv2_MT_SERVER_HELLO: + ServerHelloRecord(s, length, data); + break; + + case SSLv2_MT_CLIENT_FINISHED: + case SSLv2_MT_SERVER_VERIFY: + case SSLv2_MT_SERVER_FINISHED: + case SSLv2_MT_REQUEST_CERTIFICATE: + case SSLv2_MT_CLIENT_CERTIFICATE: + Weird("SSLv2: Encrypted record type seems to be in cleartext"); + break; + + default: + // Unknown record type. + Weird("SSLv2: Unknown record type or encrypted record"); + break; + } + } + +/*! + * This method analyses a SSLv2 CLIENT-HELLO record. + * + * \param s Pointer to the endpoint which sent the record + * \param length length of SSLv2 CLIENT-HELLO record + * \param data pointer to SSLv2 CLIENT-HELLO record to analyze + * + * \return the updated state of the current ssl connection + */ +SSLv2_States SSLv2_Interpreter::ClientHelloRecord(SSL_InterpreterEndpoint* s, + int recordLength, const u_char* recordData) + { + // This method gets the record's data (without the header). + ++clientHelloRecords; + + if ( s != orig ) + Weird("SSLv2: CLIENT-HELLO record from server!"); + + // There should not be any pending data in the SSLv2 reassembler, + // because the client should wait for a server response. + if ( ((SSLv2_Endpoint*) s)->isDataPending() ) + Weird("SSLv2: Pending data in SSL_RecordBuilder after CLIENT-HELLO!"); + + // Client hello minimum header size check. + if ( recordLength < SSLv2_CLIENT_HELLO_HEADER_SIZE ) + { + Weird("SSLv2: CLIENT-HELLO is too small!"); + return ERROR_REQUIRED; + } + + // Extract the data of the client hello header. + SSLv2_ClientHelloHeader ch; + ch.clientVersion = uint16(recordData[1] << 8) | recordData[2]; + ch.cipherSpecLength = uint16(recordData[3] << 8) | recordData[4]; + ch.sessionIdLength = uint16(recordData[5] << 8) | recordData[6]; + ch.challengeLength = uint16(recordData[7] << 8) | recordData[8]; + + if ( ch.clientVersion != SSLProxy_Analyzer::SSLv20 && + ch.clientVersion != SSLProxy_Analyzer::SSLv30 && + ch.clientVersion != SSLProxy_Analyzer::SSLv31 ) + { + Weird("SSLv2: Unsupported SSL-Version in CLIENT-HELLO"); + return ERROR_REQUIRED; + } + + if ( ch.challengeLength + ch.cipherSpecLength + ch.sessionIdLength + + SSLv2_CLIENT_HELLO_HEADER_SIZE != recordLength ) + { + Weird("SSLv2: Size inconsistency in CLIENT-HELLO"); + return ERROR_REQUIRED; + } + + // The CIPHER-SPECS-LENGTH must be > 0 and a multiple of 3. + if ( ch.cipherSpecLength == 0 || ch.cipherSpecLength % 3 != 0 ) + { + Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in CLIENT-HELLO."); + return ERROR_REQUIRED; + } + + // The SESSION-ID-LENGTH must either be zero or 16. + if ( ch.sessionIdLength != 0 && ch.sessionIdLength != 16 ) + Weird("SSLv2: Nonconform SESSION-ID-LENGTH in CLIENT-HELLO."); + + if ( (ch.challengeLength < 16) || (ch.challengeLength > 32)) + Weird("SSLv2: Nonconform CHALLENGE-LENGTH in CLIENT-HELLO."); + + const u_char* ptr = recordData; + ptr += SSLv2_CLIENT_HELLO_HEADER_SIZE + ch.cipherSpecLength; + + pSessionId = new SSL_DataBlock(ptr, ch.sessionIdLength); + + // If decrypting, store the challenge. + if ( ssl_store_key_material && ch.challengeLength <= 32 ) + pChallenge = new SSL_DataBlock(ptr, ch.challengeLength); + + bClientWantsCachedSession = ch.sessionIdLength != 0; + + TableVal* currentCipherSuites = + analyzeCiphers(s, ch.cipherSpecLength, + recordData + SSLv2_CLIENT_HELLO_HEADER_SIZE); + + fire_ssl_conn_attempt(ch.clientVersion, currentCipherSuites); + + return CLIENT_HELLO_SEEN; + } + +/*! + * This method analyses a SSLv2 SERVER-HELLO record. + * + * \param s Pointer to the endpoint which sent the record + * \param length length of SSLv2 SERVER-HELLO record + * \param data pointer to SSLv2 SERVER-HELLO record to analyze + * + * \return the updated state of the current ssl connection + */ +SSLv2_States SSLv2_Interpreter::ServerHelloRecord(SSL_InterpreterEndpoint* s, + int recordLength, const u_char* recordData) + { + ++serverHelloRecords; + TableVal* currentCipherSuites = NULL; + + if ( s != resp ) + Weird("SSLv2: SERVER-HELLO from client!"); + + if ( recordLength < SSLv2_SERVER_HELLO_HEADER_SIZE ) + { + Weird("SSLv2: SERVER-HELLO is too small!"); + return ERROR_REQUIRED; + } + + // Extract the data of the client hello header. + SSLv2_ServerHelloHeader sh; + sh.sessionIdHit = recordData[1]; + sh.certificateType = recordData[2]; + sh.serverVersion = uint16(recordData[3] << 8) | recordData[4]; + sh.certificateLength = uint16(recordData[5] << 8) | recordData[6]; + sh.cipherSpecLength = uint16(recordData[7] << 8) | recordData[8]; + sh.connectionIdLength = uint16(recordData[9] << 8) | recordData[10]; + + if ( sh.serverVersion != SSLProxy_Analyzer::SSLv20 ) + { + Weird("SSLv2: Unsupported SSL-Version in SERVER-HELLO"); + return ERROR_REQUIRED; + } + + if ( sh.certificateLength + sh.cipherSpecLength + + sh.connectionIdLength + + SSLv2_SERVER_HELLO_HEADER_SIZE != recordLength ) + { + Weird("SSLv2: Size inconsistency in SERVER-HELLO"); + return ERROR_REQUIRED; + } + + // The length of the CONNECTION-ID must be between 16 and 32 bytes. + if ( sh.connectionIdLength < 16 || sh.connectionIdLength > 32 ) + Weird("SSLv2: Nonconform CONNECTION-ID-LENGTH in SERVER-HELLO"); + + // If decrypting, store the connection ID. + if ( ssl_store_key_material && sh.connectionIdLength <= 32 ) + { + const u_char* ptr = recordData; + + ptr += SSLv2_SERVER_HELLO_HEADER_SIZE + sh.cipherSpecLength + + sh.certificateLength; + + pConnectionId = new SSL_DataBlock(ptr, sh.connectionIdLength); + } + + if ( sh.sessionIdHit == 0 ) + { + // Generating reusing-connection event. + EventHandlerPtr event = ssl_session_insertion; + + if ( event ) + { + TableVal* sessionIDTable = + MakeSessionID( + recordData + + SSLv2_SERVER_HELLO_HEADER_SIZE + + sh.certificateLength + + sh.cipherSpecLength, + sh.connectionIdLength); + + val_list* vl = new val_list; + vl->append(proxy->BuildConnVal()); + vl->append(sessionIDTable); + + proxy->ConnectionEvent(ssl_session_insertion, vl); + } + } + + SSLv2_States nextState; + + if ( sh.sessionIdHit != 0 ) + { // we're using a cached session + + // There should not be any pending data in the SSLv2 + // reassembler, because the server should wait for a + // client response. + if ( ((SSLv2_Endpoint*) s)->isDataPending() ) + { + // But turns out some SSL Implementations do this + // when using a cached session. + } + + // Consistency check for SESSION-ID-HIT. + if ( ! bClientWantsCachedSession ) + Weird("SSLv2: SESSION-ID hit in SERVER-HELLO, but no SESSION-ID in CLIENT-HELLO!"); + + // If the SESSION-ID-HIT flag is non-zero then the + // CERTIFICATE-TYPE, CERTIFICATE-LENGTH and + // CIPHER-SPECS-LENGTH fields will be zero. + if ( sh.certificateType != 0 || sh.certificateLength != 0 || + sh.cipherSpecLength != 0 ) + Weird("SSLv2: SESSION-ID-HIT, but session data in SERVER-HELLO"); + + // Generate reusing-connection event. + if ( pSessionId ) + { + fire_ssl_conn_reused(pSessionId); + delete pSessionId; + pSessionId = 0; + } + + nextState = CACHED_SESSION; + } + else + { // we're starting a new session + + // There should not be any pending data in the SSLv2 + // reassembler, because the server should wait for + // a client response. + if ( ((SSLv2_Endpoint*) s)->isDataPending() ) + Weird("SSLv2: Pending data in SSL_RecordBuilder after SERVER-HELLO (new session)!"); + + // TODO: check certificate length ??? + if ( sh.certificateLength == 0 ) + Weird("SSLv2: No certificate in SERVER-HELLO!"); + + // The CIPHER-SPECS-LENGTH must be > zero and a multiple of 3. + if ( sh.cipherSpecLength == 0 ) + Weird("SSLv2: No CIPHER-SPECS in SERVER-HELLO!"); + + if ( sh.cipherSpecLength % 3 != 0 ) + { + Weird("SSLv2: Nonconform CIPHER-SPECS-LENGTH in SERVER-HELLO"); + return ERROR_REQUIRED; + } + + const u_char* ptr = recordData; + ptr += sh.certificateLength + SSLv2_SERVER_HELLO_HEADER_SIZE; + currentCipherSuites = analyzeCiphers(s, sh.cipherSpecLength, ptr); + + nextState = NEW_SESSION; + } + + // Check if at least one cipher is supported by the client. + if ( pClientCipherSpecs && pServerCipherSpecs ) + { + bool bFound = false; + for ( int i = 0; i < pClientCipherSpecs->len; i += 3 ) + { + for ( int j = 0; j < pServerCipherSpecs->len; j += 3 ) + { + if ( memcmp(pClientCipherSpecs + i, + pServerCipherSpecs + j, 3) == 0 ) + { + bFound = true; + i = pClientCipherSpecs->len; + break; + } + } + } + + if ( ! bFound ) + { + Weird("SSLv2: Client's and server's CIPHER-SPECS don't match!"); + nextState = ERROR_REQUIRED; + } + + delete pClientCipherSpecs; + pClientCipherSpecs = 0; + } + + // Certificate analysis. + if ( sh.certificateLength > 0 && ssl_analyze_certificates != 0 ) + { + analyzeCertificate(s, recordData + SSLv2_SERVER_HELLO_HEADER_SIZE, + sh.certificateLength, sh.certificateType, false); + } + + if ( nextState == NEW_SESSION ) + // generate server-reply event + fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites); + + else if ( nextState == CACHED_SESSION ) + { // generate server-reply event + fire_ssl_conn_server_reply(sh.serverVersion, currentCipherSuites); + // Generate a connection-established event with a dummy + // cipher suite, since we can't remember session information + // (yet). + // Note: A new session identifier is sent encrypted in SSLv2! + fire_ssl_conn_established(sh.serverVersion, 0xABCD); + } + else + // Unref, since the table is not delivered to any event. + Unref(currentCipherSuites); + + return nextState; + } + +/*! + * This method analyses a SSLv2 CLIENT-MASTER-KEY record. + * + * \param s Pointer to the endpoint which sent the record + * \param length length of SSLv2 CLIENT-MASTER-KEY record + * \param data pointer to SSLv2 CLIENT-MASTER-KEY record to analyze + * + * \return the updated state of the current ssl connection + */ +SSLv2_States SSLv2_Interpreter:: + ClientMasterKeyRecord(SSL_InterpreterEndpoint* s, int recordLength, + const u_char* recordData) + { + ++clientMasterKeyRecords; + SSLv2_States nextState = CLIENT_MASTERKEY_SEEN; + + if ( s != orig ) + Weird("SSLv2: CLIENT-MASTER-KEY from server!"); + + if ( recordLength < SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE ) + { + Weird("SSLv2: CLIENT-MASTER-KEY is too small!"); + return ERROR_REQUIRED; + } + + // Extract the data of the client master key header. + SSLv2_ClientMasterKeyHeader cmk; + cmk.cipherKind = + ((recordData[1] << 16) | recordData[2] << 8) | recordData[3]; + cmk.clearKeyLength = uint16(recordData[4] << 8) | recordData[5]; + cmk.encryptedKeyLength = uint16(recordData[6] << 8) | recordData[7]; + cmk.keyArgLength = uint16(recordData[8] << 8) | recordData[9]; + + if ( cmk.clearKeyLength + cmk.encryptedKeyLength + cmk.keyArgLength + + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE != recordLength ) + { + Weird("SSLv2: Size inconsistency in CLIENT-MASTER-KEY"); + return ERROR_REQUIRED; + } + + // Check if cipher is supported by the server. + if ( pServerCipherSpecs ) + { + bool bFound = false; + for ( int i = 0; i < pServerCipherSpecs->len; i += 3 ) + { + uint32 cipherSpec = + ((pServerCipherSpecs->data[i] << 16) | + pServerCipherSpecs->data[i+1] << 8) | + pServerCipherSpecs->data[i+2]; + + if ( cmk.cipherKind == cipherSpec ) + { + bFound = true; + break; + } + } + + if ( ! bFound ) + { + Weird("SSLv2: Client chooses unadvertised cipher in CLIENT-MASTER-KEY!"); + nextState = ERROR_REQUIRED; + } + else + nextState = CLIENT_MASTERKEY_SEEN; + + delete pServerCipherSpecs; + pServerCipherSpecs = 0; + } + + // TODO: check if cipher has been advertised before. + + SSL_CipherSpec* pCipherSpecTemp = 0; + + HashKey h(static_cast(cmk.cipherKind)); + pCipherSpecTemp = (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h); + if ( ! pCipherSpecTemp || ! (pCipherSpecTemp->flags & SSL_FLAG_SSLv20) ) + Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-MASTER-KEY!"); + else + { // check for conistency of clearKeyLength + if ( cmk.clearKeyLength * 8 != pCipherSpecTemp->clearKeySize ) + { + Weird("SSLv2: Inconsistency of clearKeyLength in CLIENT-MASTER-KEY!"); + // nextState = ERROR_REQUIRED; + } + + // TODO: check for consistency of encryptedKeyLength. + // TODO: check for consistency of keyArgLength. +// switch ( cmk.cipherKind ) +// { +// case SSL_CK_RC4_128_WITH_MD5: +// case SSL_CK_RC4_128_EXPORT40_WITH_MD5: +// if ( cmk.keyArgLength != 0 ) +// { +// Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!"); +// //nextState = ERROR_REQUIRED; +// } +// break; +// case SSL_CK_DES_64_CBC_WITH_MD5: +// case SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5: +// case SSL_CK_RC2_128_CBC_WITH_MD5: +// case SSL_CK_IDEA_128_CBC_WITH_MD5: +// case SSL_CK_DES_192_EDE3_CBC_WITH_MD5: +// if ( cmk.keyArgLength != 8 ) +// { +// Weird("SSLv2: Inconsistency of keyArgLength in CLIENT-MASTER-KEY!"); +// } +// break; +// } + } + + // Remember the used cipher spec. + usedCipherSpec = SSLv2_CipherSpec(cmk.cipherKind); + + // If decrypting, store the clear key part of the master key. + if ( ssl_store_key_material /* && cmk.clearKeyLength == 11 */ ) + { + pMasterClearKey = + new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE), cmk.clearKeyLength); + + pMasterEncryptedKey = + new SSL_DataBlock((recordData + SSLv2_CLIENT_MASTER_KEY_HEADER_SIZE + cmk.clearKeyLength ), cmk.encryptedKeyLength); + } + + if ( nextState == CLIENT_MASTERKEY_SEEN ) + fire_ssl_conn_established(SSLProxy_Analyzer::SSLv20, + cmk.cipherKind); + + return nextState; + } + + +/*! + * This method analyses a SSLv2 ERROR record. + * + * \param s Pointer to the endpoint which sent the record + * \param length length of SSLv2 ERROR record + * \param data pointer to SSLv2 ERROR record to analyze + * + * \return the updated state of the current ssl connection + */ +SSLv2_States SSLv2_Interpreter::ErrorRecord(SSL_InterpreterEndpoint* s, + int recordLength, const u_char* recordData) + { + ++errorRecords; + + if ( unsigned(recordLength) != SSLv2_ERROR_RECORD_SIZE ) + { + Weird("SSLv2: Size mismatch in Error Record!"); + return ERROR_REQUIRED; + } + + SSLv2_ErrorRecord er; + er.errorCode = (recordData[1] << 8) | recordData[2]; + SSL3x_AlertLevel al = SSL3x_AlertLevel(255); + + switch ( er.errorCode ) { + case SSLv2_PE_NO_CIPHER: + // The client doesn't support a cipher which the server + // supports. Only from client to server and not recoverable! + al = SSL3x_ALERT_LEVEL_FATAL; + break; + + case SSLv2_PE_NO_CERTIFICATE: + if ( s == orig ) + // from client to server: not recoverable + al = SSL3x_ALERT_LEVEL_FATAL; + else + // from server to client: recoverable + al = SSL3x_ALERT_LEVEL_WARNING; + break; + + case SSLv2_PE_BAD_CERTIFICATE: + if ( s == orig ) + // from client to server: not recoverable + al = SSL3x_ALERT_LEVEL_FATAL; + else + // from server to client: recoverable + al = SSL3x_ALERT_LEVEL_WARNING; + break; + + case SSLv2_PE_UNSUPPORTED_CERTIFICATE_TYPE: + if ( s == orig ) + // from client to server: not recoverable + al = SSL3x_ALERT_LEVEL_FATAL; + else + // from server to client: recoverable + al = SSL3x_ALERT_LEVEL_WARNING; + break; + + default: + al = SSL3x_ALERT_LEVEL_FATAL; + break; + } + + fire_ssl_conn_alert(SSLProxy_Analyzer::SSLv20, al, er.errorCode); + + return ERROR_SEEN; + } + +/*! + * This method analyses a set of SSLv2 cipher suites. + * + * \param s Pointer to the endpoint which sent the cipher suites + * \param length length of cipher suites + * \param data pointer to cipher suites to analyze + * + * \return a pointer to a Bro TableVal (of type cipher_suites_list) which contains + * the cipher suites list of the current analyzed record + */ +TableVal* SSLv2_Interpreter::analyzeCiphers(SSL_InterpreterEndpoint* s, + int length, const u_char* data) + { + if ( length > MAX_CIPHERSPEC_SIZE ) + { + if ( s == orig ) + Weird("SSLv2: Client has CipherSpecs > MAX_CIPHERSPEC_SIZE"); + else + Weird("SSLv2: Server has CipherSpecs > MAX_CIPHERSPEC_SIZE"); + } + else + { // cipher specs are not too big + if ( ssl_compare_cipherspecs ) + { // store cipher specs for state analysis + if ( s == resp ) + pServerCipherSpecs = + new SSL_DataBlock(data, length); + else + pClientCipherSpecs = + new SSL_DataBlock(data, length); + } + } + + const u_char* pCipher = data; + bool bExtractCipherSuite = false; + TableVal* pCipherTable = 0; + + // We only extract the cipher suite when the corresponding + // ssl events are defined (otherwise we do work for nothing + // and suffer a memory leak). + // FIXME: This check needs to be done only once! + if ( (s == orig && ssl_conn_attempt) || + (s == resp && ssl_conn_server_reply) ) + { + pCipherTable = new TableVal(cipher_suites_list); + bExtractCipherSuite = true; + } + + for ( int i = 0; i < length; i += 3 ) + { + SSL_CipherSpec* pCurrentCipherSpec; + uint32 cipherSpecID = + ((pCipher[0] << 16) | pCipher[1] << 8) | pCipher[2]; + + // Check for unknown cipher specs. + HashKey h(static_cast(cipherSpecID)); + pCurrentCipherSpec = + (SSL_CipherSpec*) SSL_CipherSpecDict.Lookup(&h); + + if ( ! pCurrentCipherSpec ) + { + if ( s == orig ) + Weird("SSLv2: Unknown CIPHER-SPEC in CLIENT-HELLO!"); + else + Weird("SSLv2: Unknown CIPHER-SPEC in SERVER-HELLO!"); + } + + if ( bExtractCipherSuite ) + { + Val* index = new Val(cipherSpecID, TYPE_COUNT); + pCipherTable->Assign(index, 0); + Unref(index); + } + + pCipher += 3; + } + + return pCipherTable; + } + +// --- SSLv2_EndPoint --------------------------------------------------------- + +/*! + * The constructor. + * + * \param interpreter Pointer to the SSLv2 interpreter to whom this endpoint belongs to + * \param is_orig true if this is the originating endpoint of the ssl connection, + * false otherwise + */ +SSLv2_Endpoint::SSLv2_Endpoint(SSLv2_Interpreter* interpreter, int is_orig) +: SSL_InterpreterEndpoint(interpreter, is_orig) + { + sentRecords = 0; + } + +/*! + * The destructor. + */ +SSLv2_Endpoint::~SSLv2_Endpoint() + { + } + +/*! + * This method is called by the SSLProxy_Analyzer with a complete reassembled + * SSLv2 record. It passes the record to SSLv2_Interpreter::NewSSLRecord(). + * + * \param t reserved (always zero) + * \param seq reserved (always zero) + * \param len length of the data block containing the ssl record + * \param data pointer to the data block containing the ssl record + */ +void SSLv2_Endpoint::Deliver(int len, const u_char* data) + { + ++((SSLv2_Endpoint*)peer)->sentRecords; + + ((SSLv2_Interpreter*)interpreter)->NewSSLRecord(this, len, data); + } diff --git a/src/Scope.cc b/src/Scope.cc index c9b12c356c..196937d984 100644 --- a/src/Scope.cc +++ b/src/Scope.cc @@ -7,6 +7,7 @@ #include "ID.h" #include "Val.h" #include "Scope.h" +#include "Reporter.h" static scope_list scopes; static Scope* top_scope; @@ -27,7 +28,7 @@ Scope::Scope(ID* id) if ( id_type->Tag() == TYPE_ERROR ) return; else if ( id_type->Tag() != TYPE_FUNC ) - internal_error("bad scope id"); + reporter->InternalError("bad scope id"); Ref(id); @@ -128,7 +129,7 @@ ID* lookup_ID(const char* name, const char* curr_module, bool no_global, if ( id ) { if ( need_export && ! id->IsExport() && ! in_debug ) - error("identifier is not exported:", + reporter->Error("identifier is not exported:", fullname.c_str()); Ref(id); @@ -155,7 +156,7 @@ ID* install_ID(const char* name, const char* module_name, bool is_global, bool is_export) { if ( scopes.length() == 0 && ! is_global ) - internal_error("local identifier in global scope"); + reporter->InternalError("local identifier in global scope"); IDScope scope; if ( is_export || ! module_name || @@ -197,7 +198,7 @@ Scope* pop_scope() { int n = scopes.length() - 1; if ( n < 0 ) - internal_error("scope underflow"); + reporter->InternalError("scope underflow"); scopes.remove_nth(n); Scope* old_top = top_scope; diff --git a/src/SerialObj.cc b/src/SerialObj.cc index 02c312c1e7..cddb0b0963 100644 --- a/src/SerialObj.cc +++ b/src/SerialObj.cc @@ -21,7 +21,7 @@ SerialObj* SerialObj::Instantiate(SerialType type) return o; } - run_time(fmt("Unknown object type 0x%08x", type)); + reporter->Error(fmt("Unknown object type 0x%08x", type)); return 0; } @@ -31,7 +31,7 @@ const char* SerialObj::ClassName(SerialType type) if ( f != names->end() ) return f->second; - run_time(fmt("Unknown object type 0x%08x", type)); + reporter->Error(fmt("Unknown object type 0x%08x", type)); return ""; } @@ -47,7 +47,7 @@ void SerialObj::Register(SerialType type, FactoryFunc f, const char* name) FactoryMap::iterator i = factories->find(type); if ( i != factories->end() ) - internal_error("SerialType 0x%08x registered twice", type); + reporter->InternalError("SerialType 0x%08x registered twice", type); (*factories)[type] = f; (*names)[type] = name; @@ -77,7 +77,7 @@ bool SerialObj::Serialize(SerialInfo* info) const const TransientID* tid = GetTID(); if ( ! tid ) - internal_error("no tid - missing DECLARE_SERIAL?"); + reporter->InternalError("no tid - missing DECLARE_SERIAL?"); if ( info->cache ) pid = info->s->Cache()->Lookup(*tid); @@ -211,7 +211,7 @@ SerialObj* SerialObj::Unserialize(UnserialInfo* info, SerialType type) const TransientID* tid = obj->GetTID(); if ( ! tid ) - internal_error("no tid - missing DECLARE_SERIAL?"); + reporter->InternalError("no tid - missing DECLARE_SERIAL?"); if ( info->cache ) info->s->Cache()->Register(obj, pid, info->new_cache_strategy); diff --git a/src/SerialTypes.h b/src/SerialTypes.h index 4f9ab4585b..c2c4123a57 100644 --- a/src/SerialTypes.h +++ b/src/SerialTypes.h @@ -151,7 +151,7 @@ SERIAL_EXPR(VECTOR_COERCE_EXPR, 44) #define SERIAL_STMT(name, val) SERIAL_CONST(name, val, STMT) SERIAL_STMT(STMT, 1) SERIAL_STMT(EXPR_LIST_STMT, 2) -SERIAL_STMT(ALARM_STMT, 3) +// There used to be ALARM_STMT (3) here. SERIAL_STMT(PRINT_STMT, 4) SERIAL_STMT(EXPR_STMT, 5) SERIAL_STMT(IF_STMT, 6) diff --git a/src/SerializationFormat.cc b/src/SerializationFormat.cc index b9b3da5fef..b229cbbc87 100644 --- a/src/SerializationFormat.cc +++ b/src/SerializationFormat.cc @@ -5,6 +5,7 @@ #include "net_util.h" #include "SerializationFormat.h" #include "Serializer.h" +#include "Reporter.h" SerializationFormat::SerializationFormat() { @@ -58,7 +59,7 @@ bool SerializationFormat::ReadData(void* b, size_t count) { if ( input_pos + count > input_len ) { - error("data underflow during read in binary format"); + reporter->Error("data underflow during read in binary format"); abort(); return false; } @@ -204,7 +205,7 @@ bool BinarySerializationFormat::Read(char** str, int* len, const char* tag) for ( int i = 0; i < l; i++ ) if ( ! s[i] ) { - error("binary Format: string contains null; replaced by '_'"); + reporter->Error("binary Format: string contains null; replaced by '_'"); s[i] = '_'; } } @@ -332,61 +333,61 @@ XMLSerializationFormat::~XMLSerializationFormat() bool XMLSerializationFormat::Read(int* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(uint16* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(uint32* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(int64* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(uint64* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(bool* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(double* d, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(char* v, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(char** str, int* len, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } bool XMLSerializationFormat::Read(string* s, const char* tag) { - internal_error("no reading of xml"); + reporter->InternalError("no reading of xml"); return false; } diff --git a/src/Serializer.cc b/src/Serializer.cc index c6a065f28f..96821408a5 100644 --- a/src/Serializer.cc +++ b/src/Serializer.cc @@ -12,7 +12,7 @@ #include "Serializer.h" #include "Scope.h" #include "Stmt.h" -#include "Logger.h" +#include "Reporter.h" #include "Func.h" #include "Event.h" #include "EventRegistry.h" @@ -911,7 +911,7 @@ bool FileSerializer::Read(UnserialInfo* info, const char* file, bool header) void FileSerializer::ReportError(const char* str) { - run_time(str); + reporter->Error(str); } void FileSerializer::GotID(ID* id, Val* val) @@ -971,7 +971,7 @@ ConversionSerializer::~ConversionSerializer() bool ConversionSerializer::Convert(const char* file_in, const char* file_out) { - internal_error("Error: Printing as XML is broken."); + reporter->InternalError("Error: Printing as XML is broken."); if ( ! serout->Open(file_out, true) ) return false; @@ -1004,19 +1004,19 @@ void ConversionSerializer::GotFunctionCall(const char* name, double time, void ConversionSerializer::GotID(ID* id, Val* val) { - warn("ConversionSerializer::GotID not implemented"); + reporter->Warning("ConversionSerializer::GotID not implemented"); Unref(id); } void ConversionSerializer::GotStateAccess(StateAccess* s) { - warn("ConversionSerializer::GotID not implemented"); + reporter->Warning("ConversionSerializer::GotID not implemented"); delete s; } void ConversionSerializer::GotPacket(Packet* p) { - warn("ConversionSerializer::GotPacket not implemented"); + reporter->Warning("ConversionSerializer::GotPacket not implemented"); delete p; } diff --git a/src/Serializer.h b/src/Serializer.h index dde5c564e6..6bdac10f83 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -18,6 +18,7 @@ #include "IP.h" #include "Timer.h" #include "IOSource.h" +#include "Reporter.h" class SerializationCache; class SerialInfo; @@ -262,7 +263,7 @@ public: virtual ~CloneSerializer() { } protected: - virtual void ReportError(const char* msg) { run_time(msg); } + virtual void ReportError(const char* msg) { reporter->Error(msg); } virtual void GotID(ID* id, Val* val) { } virtual void GotEvent(const char* name, double time, EventHandlerPtr event, val_list* args) { } diff --git a/src/Sessions.cc b/src/Sessions.cc index 2cabaf5801..c0ef2d7cab 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -15,6 +15,7 @@ #include "Timer.h" #include "NetVar.h" #include "Sessions.h" +#include "Reporter.h" #include "OSFinger.h" #include "ICMP.h" @@ -547,7 +548,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, HashKey* h = id.BuildConnKey(); if ( ! h ) - internal_error("hash computation failed"); + reporter->InternalError("hash computation failed"); Connection* conn = 0; @@ -736,7 +737,7 @@ FragReassembler* NetSessions::NextFragment(double t, const IP_Hdr* ip, HashKey* h = ch->ComputeHash(key, 1); if ( ! h ) - internal_error("hash computation failed"); + reporter->InternalError("hash computation failed"); FragReassembler* f = fragments.Lookup(h); if ( ! f ) @@ -830,7 +831,7 @@ Connection* NetSessions::FindConnection(Val* v) HashKey* h = id.BuildConnKey(); if ( ! h ) - internal_error("hash computation failed"); + reporter->InternalError("hash computation failed"); Dictionary* d; @@ -908,21 +909,21 @@ void NetSessions::Remove(Connection* c) ; else if ( ! tcp_conns.RemoveEntry(k) ) - internal_error("connection missing"); + reporter->InternalError("connection missing"); break; case TRANSPORT_UDP: if ( ! udp_conns.RemoveEntry(k) ) - internal_error("connection missing"); + reporter->InternalError("connection missing"); break; case TRANSPORT_ICMP: if ( ! icmp_conns.RemoveEntry(k) ) - internal_error("connection missing"); + reporter->InternalError("connection missing"); break; case TRANSPORT_UNKNOWN: - internal_error("unknown transport when removing connection"); + reporter->InternalError("unknown transport when removing connection"); break; } @@ -935,10 +936,10 @@ void NetSessions::Remove(FragReassembler* f) { HashKey* k = f->Key(); if ( ! k ) - internal_error("fragment block not in dictionary"); + reporter->InternalError("fragment block not in dictionary"); if ( ! fragments.RemoveEntry(k) ) - internal_error("fragment block missing"); + reporter->InternalError("fragment block missing"); Unref(f); } @@ -974,7 +975,7 @@ void NetSessions::Insert(Connection* c) break; default: - internal_error("unknown connection type"); + reporter->InternalError("unknown connection type"); } if ( old && old != c ) @@ -1065,7 +1066,7 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id, tproto = TRANSPORT_UDP; break; default: - internal_error("unknown transport protocol"); + reporter->InternalError("unknown transport protocol"); break; }; @@ -1252,7 +1253,7 @@ void NetSessions::DumpPacket(const struct pcap_pkthdr* hdr, struct pcap_pkthdr h = *hdr; h.caplen = len; if ( h.caplen > hdr->caplen ) - internal_error("bad modified caplen"); + reporter->InternalError("bad modified caplen"); pkt_dumper->Dump(&h, pkt); } } @@ -1261,7 +1262,7 @@ void NetSessions::Internal(const char* msg, const struct pcap_pkthdr* hdr, const u_char* pkt) { DumpPacket(hdr, pkt); - internal_error("%s", msg); + reporter->InternalError("%s", msg); } void NetSessions::Weird(const char* name, @@ -1270,28 +1271,12 @@ void NetSessions::Weird(const char* name, if ( hdr ) dump_this_packet = 1; - if ( net_weird ) - { - val_list* vl = new val_list; - vl->append(new StringVal(name)); - mgr.QueueEvent(net_weird, vl); - } - else - fprintf(stderr, "weird: %.06f %s\n", network_time, name); + reporter->Weird(name); } void NetSessions::Weird(const char* name, const IP_Hdr* ip) { - if ( flow_weird ) - { - val_list* vl = new val_list; - vl->append(new StringVal(name)); - vl->append(new AddrVal(ip->SrcAddr4())); - vl->append(new AddrVal(ip->DstAddr4())); - mgr.QueueEvent(flow_weird, vl); - } - else - fprintf(stderr, "weird: %.06f %s\n", network_time, name); + reporter->Weird(ip->SrcAddr4(), ip->DstAddr4(), name); } unsigned int NetSessions::ConnectionMemoryUsage() diff --git a/src/SmithWaterman.cc b/src/SmithWaterman.cc index 34ca4bc87b..3f27018550 100644 --- a/src/SmithWaterman.cc +++ b/src/SmithWaterman.cc @@ -10,6 +10,7 @@ #include "SmithWaterman.h" #include "Var.h" #include "util.h" +#include "Reporter.h" BroSubstring::BroSubstring(const BroSubstring& bst) : BroString((const BroString&) bst), _new(bst._new) @@ -185,7 +186,7 @@ bool BroSubstringCmp::operator()(const BroSubstring* bst1, if ( _index >= bst1->GetNumAlignments() || _index >= bst2->GetNumAlignments() ) { - warn("BroSubstringCmp::operator(): invalid index for input strings.\n"); + reporter->Warning("BroSubstringCmp::operator(): invalid index for input strings.\n"); return false; } diff --git a/src/StateAccess.cc b/src/StateAccess.cc index 74481a155a..ef4c257f6b 100644 --- a/src/StateAccess.cc +++ b/src/StateAccess.cc @@ -235,7 +235,7 @@ bool StateAccess::MergeTables(TableVal* dst, Val* src) { if ( ! src->Type()->Tag() == TYPE_TABLE ) { - run_time("type mismatch while merging tables"); + reporter->Error("type mismatch while merging tables"); return false; } @@ -269,8 +269,8 @@ void StateAccess::Replay() { // FIXME: I think this warrants an internal error, // but let's check that first ... - // internal_error("replay id lacking a value"); - run_time("replay id lacks a value"); + // reporter->InternalError("replay id lacking a value"); + reporter->Error("replay id lacks a value"); return; } @@ -352,7 +352,7 @@ void StateAccess::Replay() v->AsRecordVal()->Assign(idx, op2 ? op2->Ref() : 0); } else - run_time(fmt("access replay: unknown record field %s for assign", field)); + reporter->Error(fmt("access replay: unknown record field %s for assign", field)); } else if ( t == TYPE_VECTOR ) @@ -377,7 +377,7 @@ void StateAccess::Replay() } else - internal_error("unknown type in replaying index assign"); + reporter->InternalError("unknown type in replaying index assign"); break; @@ -413,7 +413,7 @@ void StateAccess::Replay() v->AsRecordVal()->Assign(idx, new_val, OP_INCR); } else - run_time(fmt("access replay: unknown record field %s for assign", field)); + reporter->Error(fmt("access replay: unknown record field %s for assign", field)); } else if ( t == TYPE_VECTOR ) @@ -427,7 +427,7 @@ void StateAccess::Replay() } else - internal_error("unknown type in replaying index increment"); + reporter->InternalError("unknown type in replaying index increment"); break; } @@ -489,7 +489,7 @@ void StateAccess::Replay() case OP_PRINT: assert(op1.val); - internal_error("access replay for print not implemented"); + reporter->InternalError("access replay for print not implemented"); break; case OP_READ_IDX: @@ -518,11 +518,11 @@ void StateAccess::Replay() } } else - run_time("read for non-table"); + reporter->Error("read for non-table"); break; default: - internal_error("access replay: unknown opcode for StateAccess"); + reporter->InternalError("access replay: unknown opcode for StateAccess"); break; } @@ -630,7 +630,7 @@ bool StateAccess::DoSerialize(SerialInfo* info) const break; default: - internal_error("StateAccess::DoSerialize: unknown opcode"); + reporter->InternalError("StateAccess::DoSerialize: unknown opcode"); } } @@ -854,7 +854,7 @@ void StateAccess::Describe(ODesc* d) const break; default: - internal_error("unknown opcode for StateAccess"); + reporter->InternalError("unknown opcode for StateAccess"); break; } diff --git a/src/Stmt.cc b/src/Stmt.cc index 7064e82635..ee7c0784a4 100644 --- a/src/Stmt.cc +++ b/src/Stmt.cc @@ -8,7 +8,7 @@ #include "Event.h" #include "Frame.h" #include "File.h" -#include "Logger.h" +#include "Reporter.h" #include "NetVar.h" #include "Stmt.h" #include "Scope.h" @@ -21,7 +21,8 @@ const char* stmt_name(BroStmtTag t) { static const char* stmt_names[int(NUM_STMTS)] = { - "alarm", "print", "event", "expr", "if", "when", "switch", + "alarm", // Does no longer exist, but kept for keeping enums consistent. + "print", "event", "expr", "if", "when", "switch", "for", "next", "break", "return", "add", "delete", "list", "bodylist", "", @@ -255,47 +256,6 @@ TraversalCode ExprListStmt::Traverse(TraversalCallback* cb) const HANDLE_TC_STMT_POST(tc); } -Val* AlarmStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const - { - ODesc d; - PrintVals(&d, vals, 0); - - if ( alarm_hook ) - { - ListExpr* args = new ListExpr(); - args->Append(new ConstExpr(new StringVal(d.Description()))); - - CallExpr* ce = - new CallExpr(new ConstExpr(new Val(alarm_hook)), args); - - Val* hook_eval = ce->Eval(0); - int do_log = hook_eval->IsOne(); - - Unref(ce); - Unref(hook_eval); - - if ( ! do_log ) - return 0; - } - - bro_logger->Log(d.Description()); - return 0; - } - -IMPLEMENT_SERIAL(AlarmStmt, SER_ALARM_STMT); - -bool AlarmStmt::DoSerialize(SerialInfo* info) const - { - DO_SERIALIZE(SER_ALARM_STMT, ExprListStmt); - return true; - } - -bool AlarmStmt::DoUnserialize(UnserialInfo* info) - { - DO_UNSERIALIZE(ExprListStmt); - return true; - } - static BroFile* print_stdout = 0; Val* PrintStmt::DoExec(val_list* vals, stmt_flow_type& /* flow */) const @@ -1957,7 +1917,6 @@ int same_stmt(const Stmt* s1, const Stmt* s2) return 0; switch ( s1->Tag() ) { - case STMT_ALARM: case STMT_PRINT: { const ListExpr* l1 = ((const ExprListStmt*) s1)->ExprList(); @@ -2101,7 +2060,7 @@ int same_stmt(const Stmt* s1, const Stmt* s2) return 1; default: - error("bad tag in same_stmt()"); + reporter->Error("bad tag in same_stmt()"); } return 0; diff --git a/src/Stmt.h b/src/Stmt.h index 4909ff9da5..bbfdd98bfd 100644 --- a/src/Stmt.h +++ b/src/Stmt.h @@ -10,6 +10,7 @@ #include "BroList.h" #include "Obj.h" #include "Expr.h" +#include "Reporter.h" #include "StmtEnums.h" @@ -62,7 +63,7 @@ public: if ( breakpoint_count ) --breakpoint_count; else - internal_error("breakpoint count decremented below 0"); + reporter->InternalError("breakpoint count decremented below 0"); } virtual unsigned int BPCount() const { return breakpoint_count; } @@ -115,19 +116,6 @@ protected: ListExpr* l; }; -class AlarmStmt : public ExprListStmt { -public: - AlarmStmt(ListExpr* l) : ExprListStmt(STMT_ALARM, l) { } - -protected: - friend class Stmt; - AlarmStmt() {} - - Val* DoExec(val_list* vals, stmt_flow_type& flow) const; - - DECLARE_SERIAL(AlarmStmt); -}; - class PrintStmt : public ExprListStmt { public: PrintStmt(ListExpr* l) : ExprListStmt(STMT_PRINT, l) { } diff --git a/src/StmtEnums.h b/src/StmtEnums.h index 0a7f88e40e..c00b16112f 100644 --- a/src/StmtEnums.h +++ b/src/StmtEnums.h @@ -9,7 +9,8 @@ // These are in a separate file to break circular dependences typedef enum { STMT_ANY = -1, - STMT_ALARM, STMT_PRINT, STMT_EVENT, + STMT_ALARM, // Does no longer exist but kept to create enums consistent. + STMT_PRINT, STMT_EVENT, STMT_EXPR, STMT_IF, STMT_WHEN, STMT_SWITCH, STMT_FOR, STMT_NEXT, STMT_BREAK, diff --git a/src/TCP.cc b/src/TCP.cc index 62039b7fa7..4c56eb7ff9 100644 --- a/src/TCP.cc +++ b/src/TCP.cc @@ -1589,7 +1589,7 @@ BroFile* TCP_Analyzer::GetContentsFile(unsigned int direction) const default: break; } - internal_error("inconsistency in TCP_Analyzer::GetContentsFile"); + reporter->InternalError("inconsistency in TCP_Analyzer::GetContentsFile"); return 0; } diff --git a/src/TCP_Endpoint.cc b/src/TCP_Endpoint.cc index a5d19ad82d..6d74a1d818 100644 --- a/src/TCP_Endpoint.cc +++ b/src/TCP_Endpoint.cc @@ -208,7 +208,7 @@ int TCP_Endpoint::DataSent(double t, int seq, int len, int caplen, if ( fwrite(data, 1, len, f) < unsigned(len) ) // ### this should really generate an event - internal_error("contents write failed"); + reporter->InternalError("contents write failed"); } return status; diff --git a/src/TCP_Reassembler.cc b/src/TCP_Reassembler.cc index e221ab4118..bbde905320 100644 --- a/src/TCP_Reassembler.cc +++ b/src/TCP_Reassembler.cc @@ -104,7 +104,7 @@ void TCP_Reassembler::SetContentsFile(BroFile* f) { if ( ! f->IsOpen() ) { - run_time("no such file \"%s\"", f->Name()); + reporter->Error("no such file \"%s\"", f->Name()); return; } @@ -173,7 +173,7 @@ void TCP_Reassembler::Undelivered(int up_to_seq) if ( seq_delta(up_to_seq, last_reassem_seq) <= 0 ) // This should never happen. - internal_error("Calling Undelivered for data that has already been delivered (or has already been marked as undelivered"); + reporter->InternalError("Calling Undelivered for data that has already been delivered (or has already been marked as undelivered"); if ( last_reassem_seq == 1 && (endpoint->FIN_cnt > 0 || endpoint->RST_cnt > 0 || @@ -323,14 +323,14 @@ void TCP_Reassembler::RecordBlock(DataBlock* b, BroFile* f) unsigned int len = b->Size(); if ( ! f->Write((const char*) b->block, len) ) // ### this should really generate an event - internal_error("contents write failed"); + reporter->InternalError("contents write failed"); } void TCP_Reassembler::RecordGap(int start_seq, int upper_seq, BroFile* f) { if ( ! f->Write(fmt("\n<>\n", seq_delta(upper_seq, start_seq))) ) // ### this should really generate an event - internal_error("contents gap write failed"); + reporter->InternalError("contents gap write failed"); } void TCP_Reassembler::BlockInserted(DataBlock* start_block) @@ -407,12 +407,14 @@ IMPLEMENT_SERIAL(TCP_Reassembler, SER_TCP_REASSEMBLER); bool TCP_Reassembler::DoSerialize(SerialInfo* info) const { - internal_error("TCP_Reassembler::DoSerialize not implemented"); + reporter->InternalError("TCP_Reassembler::DoSerialize not implemented"); + return false; // Cannot be reached. } bool TCP_Reassembler::DoUnserialize(UnserialInfo* info) { - internal_error("TCP_Reassembler::DoUnserialize not implemented"); + reporter->InternalError("TCP_Reassembler::DoUnserialize not implemented"); + return false; // Cannot be reached. } void TCP_Reassembler::Deliver(int seq, int len, const u_char* data) diff --git a/src/Timer.cc b/src/Timer.cc index 1349d1d488..c7feb0bbd8 100644 --- a/src/Timer.cc +++ b/src/Timer.cc @@ -127,7 +127,7 @@ void PQ_TimerMgr::Add(Timer* timer) // multiple already-added timers are added, they'll still // execute in sorted order. if ( ! q->Add(timer) ) - internal_error("out of memory"); + reporter->InternalError("out of memory"); ++current_timers[timer->Type()]; } @@ -173,7 +173,7 @@ int PQ_TimerMgr::DoAdvance(double new_t, int max_expire) void PQ_TimerMgr::Remove(Timer* timer) { if ( ! q->Remove(timer) ) - internal_error("asked to remove a missing timer"); + reporter->InternalError("asked to remove a missing timer"); --current_timers[timer->Type()]; delete timer; @@ -183,7 +183,7 @@ CQ_TimerMgr::CQ_TimerMgr(const Tag& tag) : TimerMgr(tag) { cq = cq_init(60.0, 1.0); if ( ! cq ) - internal_error("could not initialize calendar queue"); + reporter->InternalError("could not initialize calendar queue"); } CQ_TimerMgr::~CQ_TimerMgr() @@ -208,7 +208,7 @@ void CQ_TimerMgr::Add(Timer* timer) t = network_time; if ( cq_enqueue(cq, t, timer) < 0 ) - internal_error("problem queueing timer"); + reporter->InternalError("problem queueing timer"); ++current_timers[timer->Type()]; } diff --git a/src/Trigger.cc b/src/Trigger.cc index e71c19732b..45d1959ee7 100644 --- a/src/Trigger.cc +++ b/src/Trigger.cc @@ -43,7 +43,7 @@ TraversalCode TriggerTraversalCallback::PreExpr(const Expr* expr) case EXPR_INDEX: { const IndexExpr* e = static_cast(expr); - BroObj::SuppressRunTimeErrors no_errors; + BroObj::SuppressErrors no_errors; Val* v = e->Eval(trigger->frame); if ( v ) trigger->Register(v); @@ -119,7 +119,7 @@ Trigger::Trigger(Expr* arg_cond, Stmt* arg_body, Stmt* arg_timeout_stmts, Trigger* parent = frame->GetTrigger(); if ( ! parent ) { - run_time("return trigger in context which does not allow delaying result"); + reporter->Error("return trigger in context which does not allow delaying result"); Unref(this); return; } diff --git a/src/Type.cc b/src/Type.cc index 6e87a1f83a..5da892d87f 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -9,6 +9,7 @@ #include "Expr.h" #include "Scope.h" #include "Serializer.h" +#include "Reporter.h" #include #include @@ -315,7 +316,7 @@ int TypeList::AllMatch(const BroType* t, int is_init) const void TypeList::Append(BroType* t) { if ( pure_type && ! same_type(t, pure_type) ) - internal_error("pure type-list violation"); + reporter->InternalError("pure type-list violation"); types.append(t); } @@ -932,7 +933,7 @@ void RecordType::Init(TypeList* arg_base) if ( fields->Lookup(tdij->id) ) { - error("duplicate field", tdij->id); + reporter->Error("duplicate field", tdij->id); continue; } @@ -1023,7 +1024,7 @@ const TypeDecl* RecordType::FieldDecl(int field) const { RecordField* rf = fields->NthEntry(field); if ( ! rf ) - internal_error("missing field in RecordType::FieldDecl"); + reporter->InternalError("missing field in RecordType::FieldDecl"); BroType* bt = (*base->Types())[rf->base]; RecordType* rbt = bt->AsRecordType(); @@ -1340,7 +1341,7 @@ CommentedEnumType::~CommentedEnumType() } } -// Note, we use error() here (not Error()) to include the current script +// Note, we use reporter->Error() here (not Error()) to include the current script // location in the error message, rather than the one where the type was // originally defined. void EnumType::AddName(const string& module_name, const char* name, bool is_export) @@ -1348,7 +1349,7 @@ void EnumType::AddName(const string& module_name, const char* name, bool is_expo /* implicit, auto-increment */ if ( counter < 0) { - error("cannot mix explicit enumerator assignment and implicit auto-increment"); + reporter->Error("cannot mix explicit enumerator assignment and implicit auto-increment"); SetError(); return; } @@ -1361,7 +1362,7 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va /* explicit value specified */ if ( counter > 0 ) { - error("cannot mix explicit enumerator assignment and implicit auto-increment"); + reporter->Error("cannot mix explicit enumerator assignment and implicit auto-increment"); SetError(); return; } @@ -1394,7 +1395,7 @@ void EnumType::AddNameInternal(const string& module_name, const char* name, bro_ ID *id; if ( Lookup(val) ) { - error("enumerator value in enumerated type definition already exists"); + reporter->Error("enumerator value in enumerated type definition already exists"); SetError(); return; } @@ -1408,7 +1409,7 @@ void EnumType::AddNameInternal(const string& module_name, const char* name, bro_ } else { - error("identifier or enumerator value in enumerated type definition already exists"); + reporter->Error("identifier or enumerator value in enumerated type definition already exists"); SetError(); return; } @@ -1775,7 +1776,7 @@ int same_type(const BroType* t1, const BroType* t2, int is_init) return same_type(t1, t2, is_init); case TYPE_UNION: - error("union type in same_type()"); + reporter->Error("union type in same_type()"); } return 0; } @@ -1820,7 +1821,7 @@ const BroType* flatten_type(const BroType* t) const type_list* types = tl->Types(); if ( types->length() == 0 ) - internal_error("empty type list in flatten_type"); + reporter->InternalError("empty type list in flatten_type"); const BroType* ft = (*types)[0]; if ( types->length() == 1 || tl->AllMatch(ft, 0) ) @@ -1869,7 +1870,7 @@ int is_assignable(BroType* t) return 0; case TYPE_UNION: - error("union type in is_assignable()"); + reporter->Error("union type in is_assignable()"); } return 0; @@ -1898,7 +1899,7 @@ TypeTag max_type(TypeTag t1, TypeTag t2) } else { - internal_error("non-arithmetic tags in max_type()"); + reporter->InternalError("non-arithmetic tags in max_type()"); return TYPE_ERROR; } } @@ -1993,7 +1994,7 @@ BroType* merge_types(const BroType* t1, const BroType* t2) return new TableType(tl3, y3); else { - internal_error("bad tag in merge_types"); + reporter->InternalError("bad tag in merge_types"); return 0; } } @@ -2111,11 +2112,11 @@ BroType* merge_types(const BroType* t1, const BroType* t2) return new FileType(merge_types(t1->YieldType(), t2->YieldType())); case TYPE_UNION: - internal_error("union type in merge_types()"); + reporter->InternalError("union type in merge_types()"); return 0; default: - internal_error("bad type in merge_types()"); + reporter->InternalError("bad type in merge_types()"); return 0; } } @@ -2127,7 +2128,7 @@ BroType* merge_type_list(ListExpr* elements) if ( tl->length() < 1 ) { - error("no type can be inferred for empty list"); + reporter->Error("no type can be inferred for empty list"); return 0; } @@ -2144,7 +2145,7 @@ BroType* merge_type_list(ListExpr* elements) } if ( ! t ) - error("inconsistent types in list"); + reporter->Error("inconsistent types in list"); return t; } diff --git a/src/UDP.cc b/src/UDP.cc index b141a1e9a2..5331560eff 100644 --- a/src/UDP.cc +++ b/src/UDP.cc @@ -9,6 +9,7 @@ #include "Net.h" #include "NetVar.h" #include "UDP.h" +#include "Reporter.h" UDP_Analyzer::UDP_Analyzer(Connection* conn) : TransportLayerAnalyzer(AnalyzerTag::UDP, conn) @@ -135,7 +136,7 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, request_len += ulen; #ifdef DEBUG if ( request_len < 0 ) - warn("wrapping around for UDP request length"); + reporter->Warning("wrapping around for UDP request length"); #endif } @@ -153,7 +154,7 @@ void UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig, reply_len += ulen; #ifdef DEBUG if ( reply_len < 0 ) - warn("wrapping around for UDP reply length"); + reporter->Warning("wrapping around for UDP reply length"); #endif } diff --git a/src/Val.cc b/src/Val.cc index e0ba8df9bf..5ad77b5aef 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -26,7 +26,7 @@ #include "RemoteSerializer.h" #include "PrefixTable.h" #include "Conn.h" -#include "Logger.h" +#include "Reporter.h" Val::Val(Func* f) @@ -253,7 +253,7 @@ bool Val::DoSerialize(SerialInfo* info) const return false; } - internal_error("should not be reached"); + reporter->InternalError("should not be reached"); return false; } @@ -410,7 +410,7 @@ bool Val::DoUnserialize(UnserialInfo* info) return false; } - internal_error("should not be reached"); + reporter->InternalError("should not be reached"); return false; } @@ -616,7 +616,7 @@ void Val::ValDescribe(ODesc* d) const default: // Don't call Internal(), that'll loop! - internal_error("Val description unavailable"); + reporter->InternalError("Val description unavailable"); } } @@ -964,7 +964,7 @@ AddrVal::AddrVal(const char* text) : Val(TYPE_ADDR) #ifdef BROv6 Init(dotted_to_addr6(text)); #else - error("bro wasn't compiled with IPv6 support"); + reporter->Error("bro wasn't compiled with IPv6 support"); Init(uint32(0)); #endif } @@ -998,7 +998,7 @@ Val* AddrVal::SizeVal() const #ifdef BROv6 if ( ! is_v4_addr(val.addr_val) ) { - RunTime("|addr| for IPv6 addresses not supported"); + Error("|addr| for IPv6 addresses not supported"); return new Val(0, TYPE_COUNT); } @@ -1085,13 +1085,13 @@ static uint32 parse_dotted(const char* text, int& dots) } else - internal_error("scanf failed in parse_dotted()"); + reporter->InternalError("scanf failed in parse_dotted()"); for ( int i = 0; i <= dots; ++i ) { if ( addr[i] < 0 || addr[i] > 255 ) { - error("bad dotted address", text); + reporter->Error("bad dotted address", text); break; } } @@ -1105,7 +1105,7 @@ NetVal::NetVal(const char* text) : AddrVal(TYPE_NET) uint32 a = parse_dotted(text, dots); if ( addr_to_net(a) != a ) - error("bad net address", text); + reporter->Error("bad net address", text); Init(uint32(htonl(a))); } @@ -1129,7 +1129,7 @@ Val* NetVal::SizeVal() const #ifdef BROv6 if ( ! is_v4_addr(val.addr_val) ) { - RunTime("|net| for IPv6 addresses not supported"); + Error("|net| for IPv6 addresses not supported"); return new Val(0.0, TYPE_DOUBLE); } @@ -1998,7 +1998,7 @@ int TableVal::ExpandAndInit(Val* index, Val* new_val) if ( iv->BaseTag() != TYPE_ANY ) { if ( table_type->Indices()->Types()->length() != 1 ) - internal_error("bad singleton list index"); + reporter->InternalError("bad singleton list index"); for ( int i = 0; i < iv->Length(); ++i ) if ( ! ExpandAndInit(iv->Index(i), new_val ? new_val->Ref() : 0) ) @@ -2062,7 +2062,7 @@ Val* TableVal::Default(Val* index) if ( ! def_val ) { - RunTime("non-constant default attribute"); + Error("non-constant default attribute"); return 0; } @@ -2087,7 +2087,7 @@ Val* TableVal::Default(Val* index) if ( ! result ) { - RunTime("no value returned from &default function"); + Error("no value returned from &default function"); return 0; } @@ -2193,7 +2193,7 @@ Val* TableVal::Delete(const Val* index) Val* va = v ? (v->Value() ? v->Value() : this->Ref()) : 0; if ( subnets && ! subnets->Remove(index) ) - internal_error( "index not in prefix table" ); + reporter->InternalError( "index not in prefix table" ); if ( LoggingAccess() ) { @@ -2235,7 +2235,7 @@ Val* TableVal::Delete(const HashKey* k) { Val* index = table_hash->RecoverVals(k); if ( ! subnets->Remove(index) ) - internal_error( "index not in prefix table" ); + reporter->InternalError( "index not in prefix table" ); Unref(index); } @@ -2316,7 +2316,7 @@ void TableVal::Describe(ODesc* d) const TableEntryVal* v = tbl->NextEntry(k, c); if ( ! v ) - internal_error("hash table underflow in TableVal::Describe"); + reporter->InternalError("hash table underflow in TableVal::Describe"); ListVal* vl = table_hash->RecoverVals(k); int dim = vl->Length(); @@ -2367,7 +2367,7 @@ void TableVal::Describe(ODesc* d) const } if ( tbl->NextEntry(c) ) - internal_error("hash table overflow in TableVal::Describe"); + reporter->InternalError("hash table overflow in TableVal::Describe"); if ( d->IsPortable() || d->IsReadable() ) { @@ -2489,7 +2489,7 @@ void TableVal::DoExpire(double t) { Val* index = RecoverIndex(k); if ( ! subnets->Remove(index) ) - internal_error( "index not in prefix table" ); + reporter->InternalError( "index not in prefix table" ); Unref(index); } @@ -2610,7 +2610,7 @@ bool TableVal::DoSerialize(SerialInfo* info) const state = (State*) info->cont.RestoreState(); } else - internal_error("unknown continuation state"); + reporter->InternalError("unknown continuation state"); HashKey* k; int count = 0; @@ -2695,7 +2695,7 @@ bool TableVal::DoSerialize(SerialInfo* info) const { info->cont.SaveState(state); info->cont.Suspend(); - bro_logger->Log("TableVals serialization suspended right in the middle."); + reporter->Message("TableVals serialization suspended right in the middle."); return true; } } @@ -3489,7 +3489,7 @@ Val* check_and_promote(Val* v, const BroType* t, int is_init) break; default: - internal_error("bad internal type in check_and_promote()"); + reporter->InternalError("bad internal type in check_and_promote()"); Unref(v); return 0; } @@ -3500,7 +3500,7 @@ Val* check_and_promote(Val* v, const BroType* t, int is_init) int same_val(const Val* /* v1 */, const Val* /* v2 */) { - internal_error("same_val not implemented"); + reporter->InternalError("same_val not implemented"); return 0; } @@ -3551,7 +3551,7 @@ int same_atomic_val(const Val* v1, const Val* v2) return subnet_eq(v1->AsSubNet(), v2->AsSubNet()); default: - internal_error("same_atomic_val called for non-atomic value"); + reporter->InternalError("same_atomic_val called for non-atomic value"); return 0; } diff --git a/src/Var.cc b/src/Var.cc index 00ac734c0a..626f3f7e3c 100644 --- a/src/Var.cc +++ b/src/Var.cc @@ -404,7 +404,7 @@ Val* internal_val(const char* name) { ID* id = lookup_ID(name, GLOBAL_MODULE_NAME); if ( ! id ) - internal_error("internal variable %s missing", name); + reporter->InternalError("internal variable %s missing", name); return id->ID_Val(); } @@ -413,10 +413,10 @@ Val* internal_const_val(const char* name) { ID* id = lookup_ID(name, GLOBAL_MODULE_NAME); if ( ! id ) - internal_error("internal variable %s missing", name); + reporter->InternalError("internal variable %s missing", name); if ( ! id->IsConst() ) - internal_error("internal variable %s is not constant", name); + reporter->InternalError("internal variable %s is not constant", name); return id->ID_Val(); } @@ -477,7 +477,7 @@ ListVal* internal_list_val(const char* name) } else - internal_error("internal variable %s is not a list", name); + reporter->InternalError("internal variable %s is not a list", name); } return 0; @@ -487,7 +487,7 @@ BroType* internal_type(const char* name) { ID* id = lookup_ID(name, GLOBAL_MODULE_NAME); if ( ! id ) - internal_error("internal type %s missing", name); + reporter->InternalError("internal type %s missing", name); return id->Type(); } diff --git a/src/X509.cc b/src/X509.cc new file mode 100644 index 0000000000..783bccdad1 --- /dev/null +++ b/src/X509.cc @@ -0,0 +1,265 @@ +// $Id: X509.cc 6724 2009-06-07 09:23:03Z vern $ + +#include + +#include "X509.h" +#include "config.h" + +// ### NOTE: while d2i_X509 does not take a const u_char** pointer, +// here we assume d2i_X509 does not write to , so it is safe to +// convert data to a non-const pointer. Could some X509 guru verify +// this? + +X509* d2i_X509_(X509** px, const u_char** in, int len) + { +#ifdef OPENSSL_D2I_X509_USES_CONST_CHAR + return d2i_X509(px, in, len); +#else + return d2i_X509(px, (u_char**)in, len); +#endif + } + +X509_STORE* X509_Cert::ctx = 0; +X509_LOOKUP* X509_Cert::lookup = 0; +X509_STORE_CTX X509_Cert::csc; +bool X509_Cert::bInited = false; + +// TODO: Check if Key < 768 Bits => Weakness! +// FIXME: Merge verify and verifyChain. + +void X509_Cert::sslCertificateEvent(Contents_SSL* e, X509* pCert) + { + EventHandlerPtr event = ssl_certificate; + if ( ! event ) + return; + + char tmp[256]; + RecordVal* pX509Cert = new RecordVal(x509_type); + + X509_NAME_oneline(X509_get_issuer_name(pCert), tmp, sizeof tmp); + pX509Cert->Assign(0, new StringVal(tmp)); + X509_NAME_oneline(X509_get_subject_name(pCert), tmp, sizeof tmp); + pX509Cert->Assign(1, new StringVal(tmp)); + pX509Cert->Assign(2, new AddrVal(e->Conn()->OrigAddr())); + + val_list* vl = new val_list; + vl->append(e->BuildConnVal()); + vl->append(pX509Cert); + vl->append(new Val(e->IsOrig(), TYPE_BOOL)); + + e->Conn()->ConnectionEvent(event, e, vl); + } + +void X509_Cert::sslCertificateError(Contents_SSL* e, int error_numbe) + { + Val* err_str = new StringVal(X509_verify_cert_error_string(csc.error)); + val_list* vl = new val_list; + + vl->append(e->BuildConnVal()); + vl->append(new Val(csc.error, TYPE_INT)); + vl->append(err_str); + + e->Conn()->ConnectionEvent(ssl_X509_error, e, vl); + } + +int X509_Cert::init() + { +#if 0 + OpenSSL_add_all_algorithms(); +#endif + + ctx = X509_STORE_new(); + int flag = 0; + int ret = 0; + + if ( x509_trusted_cert_path && + x509_trusted_cert_path->AsString()->Len() > 0 ) + { // add the path(s) for the local CA's certificates + const BroString* pString = x509_trusted_cert_path->AsString(); + + lookup = X509_STORE_add_lookup(ctx, X509_LOOKUP_hash_dir()); + if ( ! lookup ) + { + reporter->Error("X509_Cert::init(): initing lookup failed\n"); + flag = 1; + } + + int i = X509_LOOKUP_add_dir(lookup, + (const char*) pString->Bytes(), + X509_FILETYPE_PEM); + if ( ! i ) + { + reporter->Error("X509_Cert::init(): error adding lookup directory\n"); + ret = 0; + } + } + else + { + printf("X509: Using the default trusted cert path.\n"); + X509_STORE_set_default_paths(ctx); + } + + // Add crl functionality - will only add if defined and + // X509_STORE_add_lookup was successful. + if ( ! flag && x509_crl_file && x509_crl_file->AsString()->Len() > 0 ) + { + const BroString* rString = x509_crl_file->AsString(); + + if ( X509_load_crl_file(lookup, (const char*) rString->Bytes(), + X509_FILETYPE_PEM) != 1 ) + { + reporter->Error("X509_Cert::init(): error reading CRL file\n"); + ret = 1; + } + +#if 0 + // Note, openssl version must be > 0.9.7(a). + X509_STORE_set_flags(ctx, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); +#endif + } + + bInited = true; + return ret; + } + +int X509_Cert::verify(Contents_SSL* e, const u_char* data, uint32 len) + { + if ( ! bInited ) + init(); + + X509* pCert = d2i_X509_(NULL, &data, len); + if ( ! pCert ) + { + // 5 = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY + sslCertificateError(e, 5); + return -1; + } + + sslCertificateEvent(e, pCert); + + X509_STORE_CTX_init(&csc, ctx, pCert, 0); + X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time); + int i = X509_verify_cert(&csc); + X509_STORE_CTX_cleanup(&csc); + int ret = 0; + + int ext = X509_get_ext_count(pCert); + + if ( ext > 0 ) + { + TableVal* x509ex = new TableVal(x509_extension); + val_list* vl = new val_list; + char buf[256]; + + for ( int k = 0; k < ext; ++k ) + { + X509_EXTENSION* ex = X509_get_ext(pCert, k); + ASN1_OBJECT* obj = X509_EXTENSION_get_object(ex); + i2t_ASN1_OBJECT(buf, sizeof(buf), obj); + + Val* index = new Val(k+1, TYPE_COUNT); + Val* value = new StringVal(strlen(buf), buf); + x509ex->Assign(index, value); + Unref(index); + // later we can do critical extensions like: + // X509_EXTENSION_get_critical(ex); + } + + vl->append(e->BuildConnVal()); + vl->append(x509ex); + e->Conn()->ConnectionEvent(process_X509_extensions, e, vl); + } + + if ( ! i ) + { + sslCertificateError(e, csc.error); + ret = csc.error; + } + else + ret = 0; + + delete pCert; + return ret; + } + +int X509_Cert::verifyChain(Contents_SSL* e, const u_char* data, uint32 len) + { + if ( ! bInited ) + init(); + + // Gets an ssl3x cert chain (could be one single cert, too, + // but in chain format). + + // Init the stack. + STACK_OF(X509)* untrustedCerts = sk_X509_new_null(); + if ( ! untrustedCerts ) + { + // Internal error allocating stack of untrusted certs. + // 11 = X509_V_ERR_OUT_OF_MEM + sslCertificateError(e, 11); + return -1; + } + + // NOT AGAIN!!! + // Extract certificates and put them into an OpenSSL Stack. + uint tempLength = 0; + int certCount = 0; + X509* pCert = 0; // base cert, this one is to be verified + + while ( tempLength < len ) + { + ++certCount; + uint32 certLength = + uint32((data[tempLength + 0] << 16) | + data[tempLength + 1] << 8) | + data[tempLength + 2]; + + // Points to current cert. + const u_char* pCurrentCert = &data[tempLength+3]; + + X509* pTemp = d2i_X509_(0, &pCurrentCert, certLength); + if ( ! pTemp ) + { // error is somewhat of a misnomer + // 5 = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY + sslCertificateError(e, 5); + //FIXME: free ptrs + return -1; + } + + if ( certCount == 1 ) + // The first certificate goes directly into the ctx. + pCert = pTemp; + else + // The remaining certificates (if any) are put into + // the list of untrusted certificates + sk_X509_push(untrustedCerts, pTemp); + + tempLength += certLength + 3; + } + + sslCertificateEvent(e, pCert); + + X509_STORE_CTX_init(&csc, ctx, pCert, untrustedCerts); + X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time); + int i = X509_verify_cert(&csc); + X509_STORE_CTX_cleanup(&csc); + //X509_STORE_CTX_free(&csc); + int ret = 0; + + if ( ! i ) + { + sslCertificateError(e, csc.error); + ret = csc.error; + } + else + ret = 0; + + delete pCert; + // Free the stack, incuding. contents. + + // FIXME: could this break Bro's memory tracking? + sk_X509_pop_free(untrustedCerts, X509_free); + + return ret; + } diff --git a/src/bro.bif b/src/bro.bif index fa453ec46a..5ebc6d3288 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -10,6 +10,7 @@ #include #include +#include "Reporter.h" using namespace std; @@ -94,7 +95,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d) if ( field_width > 128 || precision > 128 ) { - builtin_run_time("excessive field width or precision"); + builtin_error("excessive field width or precision"); return; } @@ -125,7 +126,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d) } if ( precision >= 0 && *fmt != 'e' && *fmt != 'f' && *fmt != 'g' ) - builtin_run_time("precision specified for non-floating point"); + builtin_error("precision specified for non-floating point"); switch ( *fmt ) { case 'D': @@ -133,7 +134,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d) { if ( t != TYPE_TIME ) { - builtin_run_time("bad type for Date/Time format", v); + builtin_error("bad type for Date/Time format", v); break; } @@ -207,7 +208,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d) else if ( ! check_fmt_type(t, ok_d_fmt) ) { - builtin_run_time("bad type for %d/%x format", v); + builtin_error("bad type for %d/%x format", v); break; } @@ -250,7 +251,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d) { if ( ! check_fmt_type(t, ok_f_fmt) ) { - builtin_run_time("bad type for floating-point format", v); + builtin_error("bad type for floating-point format", v); break; } @@ -261,7 +262,7 @@ static void do_fmt(const char*& fmt, Val* v, ODesc* d) break; default: - builtin_run_time("bad format"); + builtin_error("bad format"); } // Left-padding with whitespace, if any. @@ -329,7 +330,7 @@ function length%(v: any%): count else { - builtin_run_time("length() requires a table/set/vector argument"); + builtin_error("length() requires a table/set/vector argument"); return new Val(0, TYPE_COUNT); } %} @@ -344,7 +345,7 @@ function clear_table%(v: any%): any if ( v->Type()->Tag() == TYPE_TABLE ) v->AsTableVal()->RemoveAll(); else - builtin_run_time("clear_table() requires a table/set argument"); + builtin_error("clear_table() requires a table/set argument"); return 0; %} @@ -425,10 +426,10 @@ function fmt%(...%): string ; if ( n < @ARGC@ - 1 ) - builtin_run_time("too many arguments for format", fmt_v); + builtin_error("too many arguments for format", fmt_v); else if ( n >= @ARGC@ ) - builtin_run_time("too few arguments for format", fmt_v); + builtin_error("too few arguments for format", fmt_v); BroString* s = new BroString(1, d.TakeBytes(), d.Len()); s->SetUseFreeToDelete(true); @@ -459,7 +460,7 @@ function to_int%(str: string%): int // Not clear we should complain. For example, is " 205 " // a legal conversion? if ( s[0] == '\0' || end_s[0] != '\0' ) - builtin_run_time("bad conversion to integer", @ARG@[0]); + builtin_error("bad conversion to integer", @ARG@[0]); #endif return new Val(i, TYPE_INT); @@ -469,7 +470,7 @@ function int_to_count%(n: int%): count %{ if ( n < 0 ) { - builtin_run_time("bad conversion to count", @ARG@[0]); + builtin_error("bad conversion to count", @ARG@[0]); n = 0; } return new Val(n, TYPE_COUNT); @@ -478,7 +479,7 @@ function int_to_count%(n: int%): count function double_to_count%(d: double%): count %{ if ( d < 0.0 ) - builtin_run_time("bad conversion to count", @ARG@[0]); + builtin_error("bad conversion to count", @ARG@[0]); return new Val(bro_uint_t(rint(d)), TYPE_COUNT); %} @@ -492,7 +493,7 @@ function to_count%(str: string%): count if ( s[0] == '\0' || end_s[0] != '\0' ) { - builtin_run_time("bad conversion to count", @ARG@[0]); + builtin_error("bad conversion to count", @ARG@[0]); u = 0; } @@ -524,7 +525,7 @@ function addr_to_count%(a: addr%): count #ifdef BROv6 if ( ! is_v4_addr(a) ) { - builtin_run_time("conversion of non-IPv4 address to count", @ARG@[0]); + builtin_error("conversion of non-IPv4 address to count", @ARG@[0]); return new Val(0, TYPE_COUNT); } @@ -562,7 +563,7 @@ function count_to_v4_addr%(ip: count%): addr %{ if ( ip > 4294967295 ) { - builtin_run_time("conversion of non-IPv4 count to addr", @ARG@[0]); + builtin_error("conversion of non-IPv4 count to addr", @ARG@[0]); return new AddrVal(uint32(0)); } @@ -575,7 +576,7 @@ function raw_bytes_to_v4_addr%(b: string%): addr uint32 a = 0; if ( b->Len() < 4 ) - builtin_run_time("too short a string as input to raw_bytes_to_v4_addr()"); + builtin_error("too short a string as input to raw_bytes_to_v4_addr()"); else { @@ -591,7 +592,7 @@ function to_net%(a: addr%): net #ifdef BROv6 if ( ! is_v4_addr(a) ) { - builtin_run_time("conversion of non-IPv4 address to net", @ARG@[0]); + builtin_error("conversion of non-IPv4 address to net", @ARG@[0]); return new NetVal(uint32(0)); } @@ -610,7 +611,7 @@ function net_to_subnet%(a: net%): subnet #ifdef BROv6 if ( ! is_v4_addr(a) ) { - builtin_run_time("conversion of non-IPv4 address to subnet", @ARG@[0]); + builtin_error("conversion of non-IPv4 address to subnet", @ARG@[0]); return new SubNetVal(uint32(0), 0); } @@ -652,7 +653,7 @@ function remask_addr%(a1: addr, a2: addr, top_bits_from_a1: count%): addr #ifdef BROv6 if ( ! is_v4_addr(a1) || ! is_v4_addr(a2) ) { - builtin_run_time("cannot use remask_addr on IPv6 addresses"); + builtin_error("cannot use remask_addr on IPv6 addresses"); return new AddrVal(a1); } @@ -737,7 +738,7 @@ function mkdir%(f: string%): bool const char* filename = f->CheckString(); if ( mkdir(filename, 0777) < 0 && errno != EEXIST ) { - builtin_run_time("cannot create directory", @ARG@[0]); + builtin_error("cannot create directory", @ARG@[0]); return new Val(0, TYPE_BOOL); } else @@ -765,7 +766,7 @@ function connection_record%(cid: conn_id%): connection else { // Hard to recover from this until we have union types ... - builtin_run_time("connection ID not a known connection (fatal)", cid); + builtin_error("connection ID not a known connection (fatal)", cid); exit(0); return 0; } @@ -792,8 +793,11 @@ EnumVal* map_conn_type(TransportProto tp) break; default: - internal_error("bad connection type in map_conn_type()"); + reporter->InternalError("bad connection type in map_conn_type()"); } + + // Cannot be reached; + assert(false); } %%} @@ -802,7 +806,7 @@ function get_conn_transport_proto%(cid: conn_id%): transport_proto Connection* c = sessions->FindConnection(cid); if ( ! c ) { - builtin_run_time("unknown connection id in get_conn_transport_proto()", cid); + builtin_error("unknown connection id in get_conn_transport_proto()", cid); return new EnumVal(0, transport_proto); } @@ -836,7 +840,7 @@ function sqrt%(x: double%): double %{ if ( x < 0 ) { - run_time("negative sqrt argument"); + reporter->Error("negative sqrt argument"); return new Val(-1.0, TYPE_DOUBLE); } @@ -891,7 +895,7 @@ static bool prepare_environment(TableVal* tbl, bool set) if ( key->Type()->Tag() != TYPE_STRING || val->Type()->Tag() != TYPE_STRING ) { - builtin_run_time("system_env() needs a table[string] of string"); + builtin_error("system_env() needs a table[string] of string"); return false; } @@ -932,7 +936,7 @@ function system_env%(str: string, env: any%): int %{ if ( env->Type()->Tag() != TYPE_TABLE ) { - builtin_run_time("system_env() requires a table/set argument"); + builtin_error("system_env() requires a table/set argument"); return new Val(-1, TYPE_INT); } @@ -1059,7 +1063,7 @@ function lookup_connection%(cid: conn_id%): connection if ( conn ) return conn->BuildConnVal(); - builtin_run_time("connection ID not a known connection", cid); + builtin_error("connection ID not a known connection", cid); // Return a dummy connection record. RecordVal* c = new RecordVal(connection_type); @@ -1135,9 +1139,9 @@ function get_contents_file%(cid: conn_id, direction: count%): file // Return some sort of error value. if ( ! c ) - builtin_run_time("unknown connection id in get_contents_file()", cid); + builtin_error("unknown connection id in get_contents_file()", cid); else - builtin_run_time("no contents file for given direction"); + builtin_error("no contents file for given direction"); return new Val(new BroFile(stderr, "-", "w")); %} @@ -1212,7 +1216,7 @@ function get_orig_seq%(cid: conn_id%): count TYPE_COUNT); else { - run_time("connection does not have TCP analyzer"); + reporter->Error("connection does not have TCP analyzer"); return new Val(0, TYPE_COUNT); } %} @@ -1232,7 +1236,7 @@ function get_resp_seq%(cid: conn_id%): count TYPE_COUNT); else { - run_time("connection does not have TCP analyzer"); + reporter->Error("connection does not have TCP analyzer"); return new Val(0, TYPE_COUNT); } %} @@ -1247,7 +1251,7 @@ function ptr_name_to_addr%(s: string%): addr "%d.%d.%d.%d.in-addr.arpa", a, a+1, a+2, a+3) != 4 ) { - builtin_run_time("bad PTR name", @ARG@[0]); + builtin_error("bad PTR name", @ARG@[0]); addr = 0; } else @@ -1266,7 +1270,7 @@ function addr_to_ptr_name%(a: addr%): string addr = a[3]; else { - builtin_run_time("conversion of non-IPv4 address to net", @ARG@[0]); + builtin_error("conversion of non-IPv4 address to net", @ARG@[0]); addr = 0; } #else @@ -1332,7 +1336,7 @@ function fmt_ftp_port%(a: addr, p: port%): string %{ #ifdef BROv6 if ( ! is_v4_addr(a) ) - builtin_run_time("conversion of non-IPv4 address to net", @ARG@[0]); + builtin_error("conversion of non-IPv4 address to net", @ARG@[0]); uint32 addr = to_v4_addr(a); #else @@ -1411,14 +1415,14 @@ function skip_http_entity_data%(c: connection, is_orig: bool%): any if ( ha->GetTag() == AnalyzerTag::HTTP ) static_cast(ha)->SkipEntityData(is_orig); else - run_time("non-HTTP analyzer associated with connection record"); + reporter->Error("non-HTTP analyzer associated with connection record"); } else - run_time("could not find analyzer for skip_http_entity_data"); + reporter->Error("could not find analyzer for skip_http_entity_data"); } else - run_time("no analyzer associated with connection record"); + reporter->Error("no analyzer associated with connection record"); return 0; %} @@ -1502,7 +1506,7 @@ function resource_usage%(%): bro_resources struct rusage r; if ( getrusage(RUSAGE_SELF, &r) < 0 ) - internal_error("getrusage() failed in bro_resource_usage()"); + reporter->InternalError("getrusage() failed in bro_resource_usage()"); double elapsed_time = current_time() - bro_start_time; @@ -1665,7 +1669,7 @@ function preserve_prefix%(a: addr, width: count%): any { #ifdef BROv6 if ( ! is_v4_addr(a) ) - builtin_run_time("preserve_prefix() not supported for IPv6 addresses"); + builtin_error("preserve_prefix() not supported for IPv6 addresses"); else ip_anon->PreservePrefix(a[3], width); #else @@ -1685,7 +1689,7 @@ function preserve_subnet%(a: subnet%): any { #ifdef BROv6 if ( ! is_v4_addr(a->AsAddr()) ) - builtin_run_time("preserve_subnet() not supported for IPv6 addresses"); + builtin_error("preserve_subnet() not supported for IPv6 addresses"); else ip_anon->PreservePrefix(a->AsAddr()[3], a->Width()); #else @@ -1699,7 +1703,7 @@ function preserve_subnet%(a: subnet%): any function preserve_net%(a: net%): any %{ #ifdef BROv6 - builtin_run_time("preserve_net() not supported with --enable-BROv6"); + builtin_error("preserve_net() not supported with --enable-BROv6"); #else AnonymizeIPAddr* ip_anon = ip_anonymizer[PREFIX_PRESERVING_A50]; if ( ip_anon ) @@ -1714,12 +1718,12 @@ function anonymize_addr%(a: addr, cl: IPAddrAnonymizationClass%): addr %{ int anon_class = cl->InternalInt(); if ( anon_class < 0 || anon_class >= NUM_ADDR_ANONYMIZATION_CLASSES ) - builtin_run_time("anonymize_addr(): invalid ip addr anonymization class"); + builtin_error("anonymize_addr(): invalid ip addr anonymization class"); #ifdef BROv6 if ( ! is_v4_addr(a) ) { - builtin_run_time("anonymize_addr() not supported for IPv6 addresses"); + builtin_error("anonymize_addr() not supported for IPv6 addresses"); return 0; } else @@ -1861,7 +1865,7 @@ function decode_base64%(s: string%): string return new StringVal(t); else { - run_time("error in decoding string %s", @ARG@[0]); + reporter->Error("error in decoding string %s", @ARG@[0]); return new StringVal(""); } %} @@ -1912,7 +1916,7 @@ function merge_pattern%(p1: pattern, p2: pattern%): pattern %{ if ( bro_start_network_time != 0.0 ) { - builtin_run_time("merge_pattern can only be called at init time"); + builtin_error("merge_pattern can only be called at init time"); return 0; } @@ -1958,7 +1962,7 @@ function string_to_pattern%(s: string, convert: bool%): pattern %{ if ( bro_start_network_time != 0.0 ) { - builtin_run_time("string_to_pattern can only be called at init time"); + builtin_error("string_to_pattern can only be called at init time"); return 0; } @@ -1993,7 +1997,7 @@ function precompile_pcap_filter%(id: PcapFilterID, s: string%): bool if ( ! pkt_srcs[i]->PrecompileFilter(id->ForceAsInt(), s->CheckString()) ) { - run_time( "precompile_pcap_filter: %s", + reporter->Error( "precompile_pcap_filter: %s", pkt_srcs[i]->ErrorMsg() ); success = false; } @@ -2181,7 +2185,7 @@ function send_id%(p: event_peer, id: string%) : bool ID* i = global_scope()->Lookup(id->CheckString()); if ( ! i ) { - run_time(fmt("send_id: no global id %s", id->CheckString())); + reporter->Error(fmt("send_id: no global id %s", id->CheckString())); return new Val(0, TYPE_BOOL); } @@ -2245,12 +2249,12 @@ function get_event_peer%(%) : event_peer } if ( ! remote_serializer ) - internal_error("remote_serializer not initialized"); + reporter->InternalError("remote_serializer not initialized"); Val* v = remote_serializer->GetPeerVal(src); if ( ! v ) { - run_time(fmt("peer %d does not exist anymore", int(src))); + reporter->Error(fmt("peer %d does not exist anymore", int(src))); RecordVal* p = mgr.GetLocalPeerVal(); Ref(p); return p; @@ -2307,7 +2311,7 @@ function is_local_interface%(ip: addr%) : bool #ifdef BROv6 if ( ! is_v4_addr(ip) ) { - builtin_run_time("is_local_interface() only supports IPv4 addresses"); + builtin_error("is_local_interface() only supports IPv4 addresses"); return new Val(0, TYPE_BOOL); } @@ -2393,7 +2397,7 @@ function resize%(aggr: any, newsize: count%) : count %{ if ( aggr->Type()->Tag() != TYPE_VECTOR ) { - builtin_run_time("resize() operates on vectors"); + builtin_error("resize() operates on vectors"); return 0; } @@ -2406,7 +2410,7 @@ function any_set%(v: any%) : bool if ( v->Type()->Tag() != TYPE_VECTOR || v->Type()->YieldType()->Tag() != TYPE_BOOL ) { - builtin_run_time("any_set() requires vector of bool"); + builtin_error("any_set() requires vector of bool"); return new Val(false, TYPE_BOOL); } @@ -2424,7 +2428,7 @@ function all_set%(v: any%) : bool if ( v->Type()->Tag() != TYPE_VECTOR || v->Type()->YieldType()->Tag() != TYPE_BOOL ) { - builtin_run_time("all_set() requires vector of bool"); + builtin_error("all_set() requires vector of bool"); return new Val(false, TYPE_BOOL); } @@ -2495,7 +2499,7 @@ function sort%(v: any, ...%) : any if ( v->Type()->Tag() != TYPE_VECTOR ) { - builtin_run_time("sort() requires vector"); + builtin_error("sort() requires vector"); return v; } @@ -2503,14 +2507,14 @@ function sort%(v: any, ...%) : any Func* comp = 0; if ( @ARG@.length() > 2 ) - builtin_run_time("sort() called with extraneous argument"); + builtin_error("sort() called with extraneous argument"); if ( @ARG@.length() == 2 ) { Val* comp_val = @ARG@[1]; if ( ! IsFunc(comp_val->Type()->Tag()) ) { - builtin_run_time("second argument to sort() needs to be comparison function"); + builtin_error("second argument to sort() needs to be comparison function"); return v; } @@ -2518,7 +2522,7 @@ function sort%(v: any, ...%) : any } if ( ! comp && ! IsIntegral(elt_type->Tag()) ) - builtin_run_time("comparison function required for sort() with non-integral types"); + builtin_error("comparison function required for sort() with non-integral types"); vector& vv = *v->AsVector(); @@ -2528,7 +2532,7 @@ function sort%(v: any, ...%) : any if ( comp_type->YieldType()->Tag() != TYPE_INT || ! comp_type->ArgTypes()->AllMatch(elt_type, 0) ) { - builtin_run_time("invalid comparison function in call to sort()"); + builtin_error("invalid comparison function in call to sort()"); return v; } @@ -2549,7 +2553,7 @@ function order%(v: any, ...%) : index_vec if ( v->Type()->Tag() != TYPE_VECTOR ) { - builtin_run_time("order() requires vector"); + builtin_error("order() requires vector"); return result_v; } @@ -2557,14 +2561,14 @@ function order%(v: any, ...%) : index_vec Func* comp = 0; if ( @ARG@.length() > 2 ) - builtin_run_time("order() called with extraneous argument"); + builtin_error("order() called with extraneous argument"); if ( @ARG@.length() == 2 ) { Val* comp_val = @ARG@[1]; if ( ! IsFunc(comp_val->Type()->Tag()) ) { - builtin_run_time("second argument to order() needs to be comparison function"); + builtin_error("second argument to order() needs to be comparison function"); return v; } @@ -2572,7 +2576,7 @@ function order%(v: any, ...%) : index_vec } if ( ! comp && ! IsIntegral(elt_type->Tag()) ) - builtin_run_time("comparison function required for sort() with non-integral types"); + builtin_error("comparison function required for sort() with non-integral types"); vector& vv = *v->AsVector(); int n = vv.size(); @@ -2594,7 +2598,7 @@ function order%(v: any, ...%) : index_vec if ( comp_type->YieldType()->Tag() != TYPE_INT || ! comp_type->ArgTypes()->AllMatch(elt_type, 0) ) { - builtin_run_time("invalid comparison function in call to sort()"); + builtin_error("invalid comparison function in call to sort()"); return v; } @@ -2673,7 +2677,7 @@ function generate_idmef%(src_ip: addr, src_port: port, printCurrentMessage(stderr); return new Val(1, TYPE_BOOL); #else - builtin_run_time("Bro was not configured for IDMEF support"); + builtin_error("Bro was not configured for IDMEF support"); return new Val(0, TYPE_BOOL); #endif %} @@ -2871,7 +2875,7 @@ function lookup_addr%(host: addr%) : string if ( ! trigger) { - builtin_run_time("lookup_addr() can only be called inside a when-condition"); + builtin_error("lookup_addr() can only be called inside a when-condition"); return new StringVal(""); } @@ -2887,7 +2891,7 @@ function lookup_addr%(host: addr%) : string static bool warned = false; if ( ! warned ) { - warn("lookup_addr() only supports IPv4 addresses currently"); + reporter->Warning("lookup_addr() only supports IPv4 addresses currently"); warned = true; } @@ -2912,7 +2916,7 @@ function lookup_hostname%(host: string%) : addr_set if ( ! trigger) { - builtin_run_time("lookup_hostname() can only be called inside a when-condition"); + builtin_error("lookup_hostname() can only be called inside a when-condition"); return new StringVal(""); } @@ -2958,14 +2962,14 @@ function disable_analyzer%(cid: conn_id, aid: count%) : bool Connection* c = sessions->FindConnection(cid); if ( ! c ) { - run_time("cannot find connection"); + reporter->Error("cannot find connection"); return new Val(0, TYPE_BOOL); } Analyzer* a = c->FindAnalyzer(aid); if ( ! a ) { - run_time("connection does not have analyzer specified to disable"); + reporter->Error("connection does not have analyzer specified to disable"); return new Val(0, TYPE_BOOL); } @@ -3024,7 +3028,7 @@ function getpid%(%) : count function syslog%(s: string%): any %{ - syslog(LOG_NOTICE, "%s", s->CheckString()); + reporter->Syslog("%s", s->CheckString()); return 0; %} @@ -3054,11 +3058,11 @@ function lookup_location%(a: addr%) : geo_location GEOIP_MEMORY_CACHE); if ( ! geoip ) { - builtin_run_time("can't initialize GeoIP City database.. trying Country version"); + builtin_error("can't initialize GeoIP City database.. trying Country version"); geoip = GeoIP_open_type(GEOIP_COUNTRY_EDITION, GEOIP_MEMORY_CACHE); if ( ! geoip ) - builtin_run_time("can't initialize GeoIP Country database"); + builtin_error("can't initialize GeoIP Country database"); } #ifdef BROv6 @@ -3066,7 +3070,7 @@ function lookup_location%(a: addr%) : geo_location geoip_v6 = GeoIP_open_type(GEOIP_COUNTRY_EDITION_V6, GEOIP_MEMORY_CACHE); if ( ! geoip_v6 ) - builtin_run_time("can't initialize the GeoIPv6 Country database"); + builtin_error("can't initialize the GeoIPv6 Country database"); #endif #endif } @@ -3126,7 +3130,7 @@ function lookup_location%(a: addr%) : geo_location if ( ! missing_geoip_reported ) { - builtin_run_time("Bro was not configured for GeoIP support"); + builtin_error("Bro was not configured for GeoIP support"); missing_geoip_reported = 1; } #endif @@ -3156,7 +3160,7 @@ function lookup_asn%(a: addr%) : count geoip_asn = GeoIP_open_type(GEOIP_ASNUM_EDITION, GEOIP_MEMORY_CACHE); if ( ! geoip_asn ) - builtin_run_time("can't initialize GeoIP ASNUM database"); + builtin_error("can't initialize GeoIP ASNUM database"); } if ( geoip_asn ) @@ -3190,7 +3194,7 @@ function lookup_asn%(a: addr%) : count if ( ! missing_geoip_reported ) { - builtin_run_time("Bro was not configured for GeoIP ASN support"); + builtin_error("Bro was not configured for GeoIP ASN support"); missing_geoip_reported = 1; } #endif @@ -3245,13 +3249,13 @@ function identify_data%(data: string, return_mime: bool%): string if ( ! *magic ) { - error(fmt("can't init libmagic: %s", magic_error(*magic))); + reporter->Error(fmt("can't init libmagic: %s", magic_error(*magic))); return new StringVal(""); } if ( magic_load(*magic, 0) < 0 ) { - error(fmt("can't load magic file: %s", magic_error(*magic))); + reporter->Error(fmt("can't load magic file: %s", magic_error(*magic))); magic_close(*magic); *magic = 0; return new StringVal(""); @@ -3422,7 +3426,7 @@ function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: tabl X509* x = d2i_X509_(NULL, &data, sv->Len()); if ( ! x ) { - builtin_run_time(fmt("Root CA error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + builtin_error(fmt("Root CA error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); return new Val((uint64) ERR_get_error(), TYPE_COUNT); } X509_STORE_add_cert(ctx, x); @@ -3435,7 +3439,7 @@ function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: tabl STACK_OF(X509)* untrusted_certs = sk_X509_new_null(); if ( ! untrusted_certs ) { - builtin_run_time(fmt("Untrusted certificate stack initialization error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + builtin_error(fmt("Untrusted certificate stack initialization error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); return new Val((uint64) ERR_get_error(), TYPE_COUNT); } @@ -3447,7 +3451,7 @@ function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: tabl X509* x = d2i_X509_(NULL, &data, sv->Len()); if ( ! x ) { - builtin_run_time(fmt("Untrusted certificate stack creation error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + builtin_error(fmt("Untrusted certificate stack creation error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); return new Val((uint64) ERR_get_error(), TYPE_COUNT); } sk_X509_push(untrusted_certs, x); @@ -3459,7 +3463,7 @@ function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: tabl X509* cert = d2i_X509_(NULL, &cert_data, der_cert->Len()); if ( ! cert ) { - builtin_run_time(fmt("Certificate error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + builtin_error(fmt("Certificate error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); return new Val((uint64) ERR_get_error(), TYPE_COUNT); } diff --git a/src/builtin-func.y b/src/builtin-func.y index 4f97135ab5..fd40613236 100644 --- a/src/builtin-func.y +++ b/src/builtin-func.y @@ -460,7 +460,8 @@ const_def: TOK_CONST opt_ws TOK_ID opt_ws ':' opt_ws TOK_ID opt_ws ';' /* Currently support only boolean and string values */ -opt_attr_init: '=' opt_ws TOK_BOOL opt_ws +opt_attr_init: /* nothing */ + | '=' opt_ws TOK_BOOL opt_ws { fprintf(fp_bro_init, "=%s%c%s", $2, ($3) ? 'T' : 'F', $4); } @@ -635,7 +636,7 @@ body_start: TOK_LPB c_code_begin fprintf(fp_func_def, "\tif ( %s->length() != %d )\n", arg_list_name, argc); fprintf(fp_func_def, "\t\t{\n"); fprintf(fp_func_def, - "\t\trun_time(\"%s() takes exactly %d argument(s)\");\n", + "\t\treporter->Error(\"%s() takes exactly %d argument(s)\");\n", decl.bro_fullname.c_str(), argc); fprintf(fp_func_def, "\t\treturn 0;\n"); fprintf(fp_func_def, "\t\t}\n"); @@ -645,7 +646,7 @@ body_start: TOK_LPB c_code_begin fprintf(fp_func_def, "\tif ( %s->length() < %d )\n", arg_list_name, argc); fprintf(fp_func_def, "\t\t{\n"); fprintf(fp_func_def, - "\t\trun_time(\"%s() takes at least %d argument(s)\");\n", + "\t\treporter->Error(\"%s() takes at least %d argument(s)\");\n", decl.bro_fullname.c_str(), argc); fprintf(fp_func_def, "\t\treturn 0;\n"); fprintf(fp_func_def, "\t\t}\n"); diff --git a/src/event.bif b/src/event.bif index 5b33df4eea..bd949f0854 100644 --- a/src/event.bif +++ b/src/event.bif @@ -51,8 +51,7 @@ event icmp_unreachable%(c: connection, icmp: icmp_conn, code: count, context: ic event icmp_time_exceeded%(c: connection, icmp: icmp_conn, code: count, context: icmp_context%); event icmp_redirect%(c: connection, icmp: icmp_conn, a: addr%); event conn_stats%(c: connection, os: endpoint_stats, rs: endpoint_stats%); -event conn_weird%(name: string, c: connection%); -event conn_weird_addl%(name: string, c: connection, addl: string%); +event conn_weird%(name: string, c: connection, addl: string%); event flow_weird%(name: string, src: addr, dst: addr%); event net_weird%(name: string%); event load_sample%(samples: load_sample_info, CPU: interval, dmem: int%); @@ -475,3 +474,9 @@ event rotate_size%(f: file%); event netflow_v5_header%(h: nf_v5_header%); event netflow_v5_record%(r: nf_v5_record%); + +# Different types of reporter messages. These won't be called +# recursively. +event reporter_message%(t: time, msg: string, location: string%) &error_handler; +event reporter_warning%(t: time, msg: string, location: string%) &error_handler; +event reporter_error%(t: time, msg: string, location: string%) &error_handler; diff --git a/src/input.h b/src/input.h index 5ef64f4a60..8af7a35445 100644 --- a/src/input.h +++ b/src/input.h @@ -49,8 +49,4 @@ extern Stmt* stmts; // global statements extern int optimize; -extern int nwarn; -extern int nerr; -extern int nruntime; - #endif diff --git a/src/main.cc b/src/main.cc index 2de6d07a41..4d40dee9b7 100644 --- a/src/main.cc +++ b/src/main.cc @@ -30,7 +30,7 @@ extern "C" void OPENSSL_add_all_algorithms_conf(void); #include "Scope.h" #include "Event.h" #include "File.h" -#include "Logger.h" +#include "Reporter.h" #include "LogMgr.h" #include "Net.h" #include "NetVar.h" @@ -73,9 +73,7 @@ char* writefile = 0; name_list prefixes; DNS_Mgr* dns_mgr; TimerMgr* timer_mgr; -Logger* bro_logger; LogMgr* log_mgr; -Func* alarm_hook = 0; Stmt* stmts; EventHandlerPtr net_done = 0; RuleMatcher* rule_matcher = 0; @@ -282,7 +280,6 @@ void terminate_bro() remote_serializer->LogStats(); delete timer_mgr; - delete bro_logger; delete dns_mgr; delete persistence_serializer; delete event_player; @@ -294,6 +291,7 @@ void terminate_bro() delete remote_serializer; delete dpm; delete log_mgr; + delete reporter; } void termination_signal() @@ -301,7 +299,7 @@ void termination_signal() set_processing_status("TERMINATING", "termination_signal"); Val sval(signal_val, TYPE_COUNT); - message("received termination signal"); + reporter->Message("received termination signal"); net_get_final_stats(); done_with_network(); net_delete(); @@ -653,8 +651,9 @@ int main(int argc, char** argv) set_processing_status("INITIALIZING", "main"); bro_start_time = current_time(true); + reporter = new Reporter(); - init_random_seed(seed, seed_load_file, seed_save_file); + init_random_seed(seed, (seed_load_file && *seed_load_file ? seed_load_file : 0) , seed_save_file); // DEBUG_MSG("HMAC key: %s\n", md5_digest_print(shared_hmac_md5_key)); init_hash_function(); @@ -753,7 +752,7 @@ int main(int argc, char** argv) return 0; } - if ( nerr > 0 ) + if ( reporter->Errors() > 0 ) { delete dns_mgr; exit(1); @@ -766,7 +765,7 @@ int main(int argc, char** argv) ID* id = global_scope()->Lookup("cmd_line_bpf_filter"); if ( ! id ) - internal_error("global cmd_line_bpf_filter not defined"); + reporter->InternalError("global cmd_line_bpf_filter not defined"); id->SetVal(new StringVal(user_pcap_filter)); } @@ -802,11 +801,6 @@ int main(int argc, char** argv) // ### Add support for debug command file. dbg_init_debugger(0); - Val* bro_alarm_file = internal_val("bro_alarm_file"); - bro_logger = new Logger("bro", - bro_alarm_file ? - bro_alarm_file->AsFile() : new BroFile(stderr)); - if ( (flow_files.length() == 0 || read_files.length() == 0) && (netflows.length() == 0 || interfaces.length() == 0) ) { @@ -831,15 +825,8 @@ int main(int argc, char** argv) writefile, "tcp or udp or icmp", secondary_path->Filter(), do_watchdog); - if ( ! reading_traces ) - // Only enable actual syslog'ing for live input. - bro_logger->SetEnabled(enable_syslog); - else - bro_logger->SetEnabled(0); - BroFile::SetDefaultRotation(log_rotate_interval, log_max_size); - alarm_hook = internal_func("alarm_hook"); net_done = internal_handler("net_done"); if ( ! g_policy_debug ) @@ -859,10 +846,7 @@ int main(int argc, char** argv) dns_mgr->Resolve(); if ( ! dns_mgr->Save() ) - { - bro_logger->Log("**Can't update DNS cache"); - exit(1); - } + reporter->FatalError("can't update DNS cache"); mgr.Drain(); delete dns_mgr; @@ -887,7 +871,7 @@ int main(int argc, char** argv) info.print = stdout; info.install_uniques = true; if ( ! s.Read(&info, bst_file) ) - error("Failed to read events from %s\n", bst_file); + reporter->Error("Failed to read events from %s\n", bst_file); } exit(0); @@ -905,10 +889,7 @@ int main(int argc, char** argv) ID* id = global_scope()->Lookup(id_name); if ( ! id ) - { - fprintf(stderr, "No such ID: %s\n", id_name); - exit(1); - } + reporter->FatalError("No such ID: %s\n", id_name); ODesc desc; desc.SetQuotes(true); @@ -950,9 +931,9 @@ int main(int argc, char** argv) if ( dead_handlers->length() > 0 && check_for_unused_event_handlers ) { - warn("event handlers never invoked:"); + reporter->Warning("event handlers never invoked:"); for ( int i = 0; i < dead_handlers->length(); ++i ) - warn("\t", (*dead_handlers)[i]); + reporter->Warning("\t", (*dead_handlers)[i]); } delete dead_handlers; @@ -962,9 +943,9 @@ int main(int argc, char** argv) if ( alive_handlers->length() > 0 && dump_used_event_handlers ) { - message("invoked event handlers:"); + reporter->Message("invoked event handlers:"); for ( int i = 0; i < alive_handlers->length(); ++i ) - message((*alive_handlers)[i]); + reporter->Message((*alive_handlers)[i]); } delete alive_handlers; @@ -986,6 +967,8 @@ int main(int argc, char** argv) dpm->PostScriptInit(); + reporter->ReportViaEvents(true); + mgr.Drain(); have_pending_timers = ! reading_traces && timer_mgr->Size() > 0; @@ -1006,6 +989,7 @@ int main(int argc, char** argv) } #endif + net_run(); done_with_network(); net_delete(); diff --git a/src/net_util.cc b/src/net_util.cc index f1cd9a335f..d7dc3f4add 100644 --- a/src/net_util.cc +++ b/src/net_util.cc @@ -13,6 +13,7 @@ #include #endif +#include "Reporter.h" #include "net_util.h" // - adapted from tcpdump @@ -229,14 +230,14 @@ uint32 dotted_to_addr(const char* addr_text) if ( sscanf(addr_text, "%d.%d.%d.%d", addr+0, addr+1, addr+2, addr+3) != 4 ) { - error("bad dotted address:", addr_text ); + reporter->Error("bad dotted address:", addr_text ); return 0; } if ( addr[0] < 0 || addr[1] < 0 || addr[2] < 0 || addr[3] < 0 || addr[0] > 255 || addr[1] > 255 || addr[2] > 255 || addr[3] > 255 ) { - error("bad dotted address:", addr_text); + reporter->Error("bad dotted address:", addr_text); return 0; } @@ -253,7 +254,7 @@ uint32* dotted_to_addr6(const char* addr_text) uint32* addr = new uint32[4]; if ( inet_pton(AF_INET6, addr_text, addr) <= 0 ) { - error("bad IPv6 address:", addr_text ); + reporter->Error("bad IPv6 address:", addr_text ); addr[0] = addr[1] = addr[2] = addr[3] = 0; } @@ -273,7 +274,7 @@ uint32 to_v4_addr(const uint32* addr) { #ifdef BROv6 if ( ! is_v4_addr(addr) ) - internal_error("conversion of non-IPv4 address to IPv4 address"); + reporter->InternalError("conversion of non-IPv4 address to IPv4 address"); return addr[3]; #else return addr[0]; @@ -284,7 +285,7 @@ uint32 mask_addr(uint32 a, uint32 top_bits_to_keep) { if ( top_bits_to_keep > 32 ) { - error("bad address mask value", top_bits_to_keep); + reporter->Error("bad address mask value", top_bits_to_keep); return a; } @@ -323,7 +324,7 @@ const uint32* mask_addr(const uint32* a, uint32 top_bits_to_keep) if ( top_bits_to_keep == 0 || top_bits_to_keep > max_bits ) { - error("bad address mask value", top_bits_to_keep); + reporter->Error("bad address mask value", top_bits_to_keep); return addr; } diff --git a/src/parse.y b/src/parse.y index ba7174a338..c3624bfd2d 100644 --- a/src/parse.y +++ b/src/parse.y @@ -3,9 +3,9 @@ // See the file "COPYING" in the main distribution directory for copyright. %} -%expect 85 +%expect 88 -%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ALARM TOK_ANY +%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY %token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF %token TOK_BOOL TOK_BREAK TOK_CASE TOK_CONST %token TOK_CONSTANT TOK_COPY TOK_COUNT TOK_COUNTER TOK_DEFAULT TOK_DELETE @@ -24,7 +24,7 @@ %token TOK_ATTR_EXPIRE_CREATE TOK_ATTR_EXPIRE_READ TOK_ATTR_EXPIRE_WRITE %token TOK_ATTR_PERSISTENT TOK_ATTR_SYNCHRONIZED %token TOK_ATTR_DISABLE_PRINT_HOOK TOK_ATTR_RAW_OUTPUT TOK_ATTR_MERGEABLE -%token TOK_ATTR_PRIORITY TOK_ATTR_GROUP TOK_ATTR_LOG +%token TOK_ATTR_PRIORITY TOK_ATTR_GROUP TOK_ATTR_LOG TOK_ATTR_ERROR_HANDLER %token TOK_DEBUG @@ -78,6 +78,7 @@ #include "DNS.h" #include "RE.h" #include "Scope.h" +#include "Reporter.h" #include "BroDoc.h" #include "BroDocObj.h" @@ -562,7 +563,7 @@ expr: int intval = t->Lookup(id->ModuleName(), id->Name()); if ( intval < 0 ) - internal_error("enum value not found for %s", id->Name()); + reporter->InternalError("enum value not found for %s", id->Name()); $$ = new ConstExpr(new EnumVal(intval, t)); } else @@ -689,7 +690,7 @@ enum_body_elem: assert(cur_enum_type); if ( $4->Type()->Tag() != TYPE_COUNT ) - error("enumerator is not a count constant"); + reporter->Error("enumerator is not a count constant"); else cur_enum_type->AddName(current_module, $2, $4->InternalUnsigned(), is_export); @@ -707,7 +708,7 @@ enum_body_elem: error message if users triy to use a negative integer (will also catch other cases, but that's fine.) */ - error("enumerator is not a count constant"); + reporter->Error("enumerator is not a count constant"); } | opt_doc_list TOK_ID @@ -827,7 +828,7 @@ type: | TOK_UNION '{' type_list '}' { set_location(@1, @4); - error("union type not implemented"); + reporter->Error("union type not implemented"); $$ = 0; } @@ -843,7 +844,7 @@ type: { set_location(@1); // $$ = new TypeList(); - error("list type not implemented"); + reporter->Error("list type not implemented"); $$ = 0; } @@ -851,7 +852,7 @@ type: { set_location(@1); // $$ = new TypeList($3); - error("list type not implemented"); + reporter->Error("list type not implemented"); $$ = 0; } @@ -1320,6 +1321,8 @@ attr: { $$ = new Attr(ATTR_GROUP, $3); } | TOK_ATTR_LOG { $$ = new Attr(ATTR_LOG); } + | TOK_ATTR_ERROR_HANDLER + { $$ = new Attr(ATTR_ERROR_HANDLER); } ; stmt: @@ -1329,12 +1332,6 @@ stmt: $$ = $2; } - | TOK_ALARM expr_list ';' - { - set_location(@1, @3); - $$ = new AlarmStmt($2); - } - | TOK_PRINT expr_list ';' { set_location(@1, @3); @@ -1602,7 +1599,7 @@ resolve_id: $$ = lookup_ID($1, current_module.c_str()); if ( ! $$ ) - error("identifier not defined:", $1); + reporter->Error("identifier not defined:", $1); delete [] $1; } @@ -1659,7 +1656,7 @@ int yyerror(const char msg[]) strcat(msgbuf, "\nDocumentation mode is enabled: " "remember to check syntax of ## style comments\n"); - error(msgbuf); + reporter->Error(msgbuf); return 0; } diff --git a/src/re-parse.y b/src/re-parse.y index f4c0722c51..26c8ab6716 100644 --- a/src/re-parse.y +++ b/src/re-parse.y @@ -8,6 +8,7 @@ #include "CCL.h" #include "NFA.h" #include "EquivClass.h" +#include "Reporter.h" int csize = 256; int syntax_error = 0; @@ -220,7 +221,7 @@ int clower(int sym) void synerr(const char str[]) { syntax_error = true; - run_time("%s (compiling pattern /%s/)", str, RE_parse_input); + reporter->Error("%s (compiling pattern /%s/)", str, RE_parse_input); } void yyerror(const char msg[]) diff --git a/src/reporter.bif b/src/reporter.bif new file mode 100644 index 0000000000..4bbdede145 --- /dev/null +++ b/src/reporter.bif @@ -0,0 +1,30 @@ + +module Reporter; + +%%{ +#include "NetVar.h" +%%} + +function Reporter::message%(msg: string%): bool + %{ + reporter->PushLocation(frame->GetCall()->GetLocationInfo()); + reporter->Message("%s", msg->CheckString()); + reporter->PopLocation(); + return new Val(1, TYPE_BOOL); + %} + +function Reporter::warning%(msg: string%): bool + %{ + reporter->PushLocation(frame->GetCall()->GetLocationInfo()); + reporter->Warning("%s", msg->CheckString()); + reporter->PopLocation(); + return new Val(1, TYPE_BOOL); + %} + +function Reporter::error%(msg: string%): bool + %{ + reporter->PushLocation(frame->GetCall()->GetLocationInfo()); + reporter->Error("%s", msg->CheckString()); + reporter->PopLocation(); + return new Val(1, TYPE_BOOL); + %} diff --git a/src/rule-parse.y b/src/rule-parse.y index da3437d9e8..73c04a72ab 100644 --- a/src/rule-parse.y +++ b/src/rule-parse.y @@ -3,6 +3,7 @@ #include #include "RuleMatcher.h" +#include "Reporter.h" extern void begin_PS(); extern void end_PS(); @@ -169,7 +170,7 @@ rule_attr: | TOK_PATTERN_TYPE '[' rangeopt ']' pattern { if ( $3.offset > 0 ) - warn("Offsets are currently ignored for patterns"); + reporter->Warning("Offsets are currently ignored for patterns"); current_rule->AddPattern($5, $1, 0, $3.len); } @@ -316,14 +317,14 @@ pattern: void rules_error(const char* msg) { - fprintf(stderr, "Error in signature (%s:%d): %s\n", + reporter->Error("Error in signature (%s:%d): %s\n", current_rule_file, rules_line_number+1, msg); rule_matcher->SetParseError(); } void rules_error(const char* msg, const char* addl) { - fprintf(stderr, "Error in signature (%s:%d): %s (%s)\n", + reporter->Error("Error in signature (%s:%d): %s (%s)\n", current_rule_file, rules_line_number+1, msg, addl); rule_matcher->SetParseError(); } @@ -331,7 +332,7 @@ void rules_error(const char* msg, const char* addl) void rules_error(Rule* r, const char* msg) { const Location& l = r->GetLocation(); - fprintf(stderr, "Error in signature %s (%s:%d): %s\n", + reporter->Error("Error in signature %s (%s:%d): %s\n", r->ID(), l.filename, l.first_line, msg); rule_matcher->SetParseError(); } diff --git a/src/scan.l b/src/scan.l index 553260a479..3590cc26fc 100644 --- a/src/scan.l +++ b/src/scan.l @@ -24,15 +24,12 @@ #include "BroDoc.h" #include "Analyzer.h" #include "AnalyzerTags.h" +#include "Reporter.h" extern YYLTYPE yylloc; // holds start line and column of token extern int print_loaded_scripts; extern int generate_documentation; -int nwarn = 0; -int nerr = 0; -int nruntime = 0; - // Track the @if... depth. ptr_compat_int current_depth = 0; @@ -53,7 +50,7 @@ char last_tok[128]; // a read fails. #define YY_INPUT(buf,result,max_size) \ if ( ((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin) ) \ - error(fmt("read failed with \"%s\"", strerror(errno))); + reporter->Error(fmt("read failed with \"%s\"", strerror(errno))); // Files we have already scanned (or are in the process of scanning). They // are tracked by inode number. @@ -92,7 +89,7 @@ static ino_t get_inode_num(FILE* f, const char* filename) if ( fstat(fileno(f), &b) ) { - error("failed to fstat fd of %s\n", filename); + reporter->Error("failed to fstat fd of %s\n", filename); exit(1); } @@ -246,7 +243,6 @@ ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+)) add return TOK_ADD; addr return TOK_ADDR; -alarm return TOK_ALARM; any return TOK_ANY; bool return TOK_BOOL; break return TOK_BREAK; @@ -309,6 +305,7 @@ when return TOK_WHEN; &disable_print_hook return TOK_ATTR_DISABLE_PRINT_HOOK; &raw_output return TOK_ATTR_RAW_OUTPUT; &encrypt return TOK_ATTR_ENCRYPT; +&error_handler return TOK_ATTR_ERROR_HANDLER; &expire_func return TOK_ATTR_EXPIRE_FUNC; &group return TOK_ATTR_GROUP; &log return TOK_ATTR_LOG; @@ -358,7 +355,7 @@ when return TOK_WHEN; files_scanned.push_back(i); } else - error("failed find file associated with @unload %s", new_file); + reporter->Error("failed find file associated with @unload %s", new_file); } @prefixes{WS}("+"?)={WS}{PREFIX} { @@ -414,7 +411,7 @@ F RET_CONST(new Val(false, TYPE_BOOL)) uint32 p = atoi(yytext); if ( p > 65535 ) { - error("bad port number -", yytext); + reporter->Error("bad port number -", yytext); p = 0; } RET_CONST(new PortVal(p, TRANSPORT_TCP)) @@ -423,7 +420,7 @@ F RET_CONST(new Val(false, TYPE_BOOL)) uint32 p = atoi(yytext); if ( p > 65535 ) { - error("bad port number -", yytext); + reporter->Error("bad port number -", yytext); p = 0; } RET_CONST(new PortVal(p, TRANSPORT_UDP)) @@ -432,7 +429,7 @@ F RET_CONST(new Val(false, TYPE_BOOL)) uint32 p = atoi(yytext); if ( p > 255 ) { - error("bad port number -", yytext); + reporter->Error("bad port number -", yytext); p = 0; } RET_CONST(new PortVal(p, TRANSPORT_ICMP)) @@ -441,7 +438,7 @@ F RET_CONST(new Val(false, TYPE_BOOL)) uint32 p = atoi(yytext); if ( p > 255 ) { - error("bad port number -", yytext); + reporter->Error("bad port number -", yytext); p = 0; } RET_CONST(new PortVal(p, TRANSPORT_UNKNOWN)) @@ -487,13 +484,13 @@ F RET_CONST(new Val(false, TYPE_BOOL)) { s[i++] = *text; if ( i >= len ) - internal_error("bad string length computation"); + reporter->InternalError("bad string length computation"); } } // Get rid of trailing quote. if ( s[i-1] != '"' ) - internal_error("string scanning confused"); + reporter->InternalError("string scanning confused"); s[i-1] = '\0'; @@ -507,7 +504,7 @@ F RET_CONST(new Val(false, TYPE_BOOL)) [/\\\n] return yytext[0]; -<*>. error("unrecognized character -", yytext); +<*>. reporter->Error("unrecognized character -", yytext); <> last_tok[0] = '\0'; return EOF; @@ -594,7 +591,7 @@ static int load_files_with_prefix(const char* orig_file) HashKey* key = new HashKey(full_filename); if ( g_dbgfilemaps.Lookup(key) ) { - // warn("Not re-reading policy file; check BRO_PREFIXES:", full_filename); + // reporter->Warning("Not re-reading policy file; check BRO_PREFIXES:", full_filename); fclose(f); delete key; continue; @@ -644,7 +641,7 @@ static int load_files_with_prefix(const char* orig_file) { if ( streq(prefixes[i], "") ) { - error("can't open", full_filename); + reporter->Error("can't open %s", full_filename); exit(1); } } @@ -700,7 +697,7 @@ void do_atifndef(const char *id) void do_atelse() { if ( current_depth == 0 ) - error("@else without @if..."); + reporter->Error("@else without @if..."); if ( if_stack.length() && current_depth > if_stack.last() ) return; @@ -720,7 +717,7 @@ void do_atelse() void do_atendif() { if ( current_depth == 0 ) - error("unbalanced @if... @endif"); + reporter->Error("unbalanced @if... @endif"); if ( current_depth == if_stack.last() ) { @@ -756,7 +753,7 @@ const char* get_current_input_filename() void add_input_file(const char* file) { if ( ! file ) - internal_error("empty filename"); + reporter->InternalError("empty filename"); if ( ! filename ) (void) load_files_with_prefix(file); @@ -783,7 +780,7 @@ void add_to_name_list(char* s, char delim, name_list& nl) int yywrap() { - if ( nerr > 0 ) + if ( reporter->Errors() > 0 ) return 1; --include_level; diff --git a/src/strings.bif b/src/strings.bif index f10dc412f3..d13de8accb 100644 --- a/src/strings.bif +++ b/src/strings.bif @@ -159,7 +159,7 @@ function join_string_vec%(vec: string_vec, sep: string%): string function edit%(arg_s: string, arg_edit_char: string%): string %{ if ( arg_edit_char->Len() != 1 ) - builtin_run_time("not exactly one edit character", @ARG@[1]); + builtin_error("not exactly one edit character", @ARG@[1]); const u_char* s = arg_s->Bytes(); const u_char* edit_s = arg_edit_char->Bytes(); @@ -274,7 +274,7 @@ Val* do_split(StringVal* str_val, RE_Matcher* re, TableVal* other_sep, s += offset + end_of_match;; if ( s > end_of_s ) - internal_error("RegMatch in split goes beyond the string"); + reporter->InternalError("RegMatch in split goes beyond the string"); } if ( other_strings ) diff --git a/src/util.cc b/src/util.cc index 4b4e833ef2..9697285270 100644 --- a/src/util.cc +++ b/src/util.cc @@ -39,6 +39,7 @@ #include "Val.h" #include "NetVar.h" #include "Net.h" +#include "Reporter.h" char* copy_string(const char* s) { @@ -84,7 +85,7 @@ int expand_escape(const char*& s) int result; if ( sscanf(start, "%3o", &result) != 1 ) { - warn("bad octal escape: ", start); + reporter->Warning("bad octal escape: ", start); result = 0; } @@ -103,7 +104,7 @@ int expand_escape(const char*& s) int result; if ( sscanf(start, "%2x", &result) != 1 ) { - warn("bad hexadecimal escape: ", start); + reporter->Warning("bad hexadecimal escape: ", start); result = 0; } @@ -230,7 +231,7 @@ unsigned char encode_hex(int h) if ( h < 0 || h >= 16 ) { - internal_error("illegal value for encode_hex: %d", h); + reporter->InternalError("illegal value for encode_hex: %d", h); return 'X'; } @@ -456,7 +457,7 @@ const char* fmt(const char* format, ...) va_end(al); if ( (unsigned int) n >= buf_len ) - internal_error("confusion reformatting in fmt()"); + reporter->InternalError("confusion reformatting in fmt()"); } return buf; @@ -477,14 +478,14 @@ bool ensure_dir(const char *dirname) { if ( errno != ENOENT ) { - warn(fmt("can't stat directory %s: %s", + reporter->Warning(fmt("can't stat directory %s: %s", dirname, strerror(errno))); return false; } if ( mkdir(dirname, 0700) < 0 ) { - warn(fmt("can't create directory %s: %s", + reporter->Warning(fmt("can't create directory %s: %s", dirname, strerror(errno))); return false; } @@ -492,7 +493,7 @@ bool ensure_dir(const char *dirname) else if ( ! S_ISDIR(st.st_mode) ) { - warn(fmt("%s exists but is not a directory", dirname)); + reporter->Warning(fmt("%s exists but is not a directory", dirname)); return false; } @@ -505,7 +506,7 @@ bool is_dir(const char* path) if ( stat(path, &st) < 0 ) { if ( errno != ENOENT ) - warn(fmt("can't stat %s: %s", path, strerror(errno))); + reporter->Warning(fmt("can't stat %s: %s", path, strerror(errno))); return false; } @@ -537,7 +538,7 @@ uint8 shared_hmac_md5_key[16]; void hmac_md5(size_t size, const unsigned char* bytes, unsigned char digest[16]) { if ( ! hmac_key_set ) - internal_error("HMAC-MD5 invoked before the HMAC key is set"); + reporter->InternalError("HMAC-MD5 invoked before the HMAC key is set"); hash_md5(size, bytes, digest); @@ -555,14 +556,14 @@ static bool read_random_seeds(const char* read_file, uint32* seed, if ( stat(read_file, &st) < 0 ) { - warn(fmt("Seed file '%s' does not exist: %s", + reporter->Warning(fmt("Seed file '%s' does not exist: %s", read_file, strerror(errno))); return false; } if ( ! (f = fopen(read_file, "r")) ) { - warn(fmt("Could not open seed file '%s': %s", + reporter->Warning(fmt("Could not open seed file '%s': %s", read_file, strerror(errno))); return false; } @@ -598,7 +599,7 @@ static bool write_random_seeds(const char* write_file, uint32 seed, if ( ! (f = fopen(write_file, "w+")) ) { - warn(fmt("Could not create seed file '%s': %s", + reporter->Warning(fmt("Could not create seed file '%s': %s", write_file, strerror(errno))); return false; } @@ -633,7 +634,7 @@ void init_random_seed(uint32 seed, const char* read_file, const char* write_file if ( read_file ) { if ( ! read_random_seeds(read_file, &seed, buf, bufsiz) ) - fprintf(stderr, "Could not load seeds from file '%s'.\n", + reporter->Error("Could not load seeds from file '%s'.\n", read_file); else seeds_done = true; @@ -696,7 +697,7 @@ void init_random_seed(uint32 seed, const char* read_file, const char* write_file } if ( write_file && ! write_random_seeds(write_file, seed, buf, bufsiz) ) - fprintf(stderr, "Could not write seeds to file '%s'.\n", + reporter->Error("Could not write seeds to file '%s'.\n", write_file); } @@ -736,105 +737,6 @@ uint64 rand64bit() return base; } -void message(const char* msg) - { - pinpoint(); - fprintf(stderr, "%s\n", msg); - } - -void warn(const char* msg) - { - pinpoint(); - fprintf(stderr, "warning: %s\n", msg); - ++nwarn; - } - -void warn(const char* msg, const char* addl) - { - pinpoint(); - fprintf(stderr, "warning: %s %s\n", msg, addl); - ++nwarn; - } - -void error(const char* msg) - { - pinpoint(); - fprintf(stderr, "error: %s\n", msg); - ++nerr; - } - -void error(const char* msg, const char* addl) - { - pinpoint(); - fprintf(stderr, "error: %s %s\n", msg, addl); - ++nerr; - } - -void error(const char* msg, uint32 addl) - { - pinpoint(); - fprintf(stderr, "error: %s - %u\n", msg, addl); - ++nerr; - } - -void run_time(const char* msg) - { - pinpoint(); - fprintf(stderr, "run-time error: %s\n", msg); - ++nruntime; - } - -void run_time(const char* fmt, BroObj* obj) - { - ODesc d; - obj->Describe(&d); - run_time(fmt, d.Description()); - } - -void run_time(const char* fmt, const char* arg) - { - pinpoint(); - fprintf(stderr, "run-time error: "); - fprintf(stderr, fmt, arg); - fprintf(stderr, "\n"); - ++nruntime; - } - -void run_time(const char* fmt, const char* arg1, const char* arg2) - { - pinpoint(); - fprintf(stderr, "run-time error: "); - fprintf(stderr, fmt, arg1, arg2); - fprintf(stderr, "\n"); - ++nruntime; - } - -void internal_error(const char* fmt, ...) - { - va_list al; - - pinpoint(); - fprintf(stderr, "internal error: "); - va_start(al, fmt); - vfprintf(stderr, fmt, al); - va_end(al); - fprintf(stderr, "\n"); - set_processing_status("TERMINATED", "internal_error"); - abort(); - } - -void pinpoint() - { - if ( network_time > 0.0 ) - fprintf(stderr, "%.6f ", network_time); - else - { - if ( filename ) - fprintf(stderr, "%s, ", filename); - fprintf(stderr, "line %d: ", line_number); - } - } - int int_list_cmp(const void* v1, const void* v2) { ptr_compat_int i1 = *(ptr_compat_int*) v1; @@ -1052,7 +954,7 @@ FILE* rotate_file(const char* name, RecordVal* rotate_info) FILE* newf = fopen(tmpname, "w"); if ( ! newf ) { - run_time(fmt("rotate_file: can't open %s: %s", tmpname, strerror(errno))); + reporter->Error(fmt("rotate_file: can't open %s: %s", tmpname, strerror(errno))); return 0; } @@ -1061,7 +963,7 @@ FILE* rotate_file(const char* name, RecordVal* rotate_info) struct stat dummy; if ( link(name, newname) < 0 || stat(newname, &dummy) < 0 ) { - run_time(fmt("rotate_file: can't move %s to %s: %s", name, newname, strerror(errno))); + reporter->Error(fmt("rotate_file: can't move %s to %s: %s", name, newname, strerror(errno))); fclose(newf); unlink(newname); unlink(tmpname); @@ -1071,7 +973,7 @@ FILE* rotate_file(const char* name, RecordVal* rotate_info) // Close current file, and move the tmp to its place. if ( unlink(name) < 0 || link(tmpname, name) < 0 || unlink(tmpname) < 0 ) { - run_time(fmt("rotate_file: can't move %s to %s: %s", tmpname, name, strerror(errno))); + reporter->Error(fmt("rotate_file: can't move %s to %s: %s", tmpname, name, strerror(errno))); exit(1); // hard to fix, but shouldn't happen anyway... } @@ -1111,7 +1013,7 @@ double calc_next_rotate(double interval, const char* rotate_base_time) { struct tm t; if ( ! strptime(rotate_base_time, "%H:%M", &t) ) - run_time("calc_next_rotate(): can't parse rotation base time"); + reporter->Error("calc_next_rotate(): can't parse rotation base time"); else base = t.tm_min * 60 + t.tm_hour * 60 * 60; } @@ -1174,7 +1076,7 @@ double current_time(bool real) { struct timeval tv; if ( gettimeofday(&tv, 0) < 0 ) - internal_error("gettimeofday failed in current_time()"); + reporter->InternalError("gettimeofday failed in current_time()"); double t = double(tv.tv_sec) + double(tv.tv_usec) / 1e6; @@ -1264,8 +1166,7 @@ uint64 calculate_unique_id() void out_of_memory(const char* where) { - fprintf( stderr, "bro: out of memory in %s.\n", where ); - abort(); + reporter->FatalError("out of memory in %s.\n", where); } void get_memory_usage(unsigned int* total, unsigned int* malloced) diff --git a/src/util.h b/src/util.h index e3929fa850..a77f284ea0 100644 --- a/src/util.h +++ b/src/util.h @@ -171,19 +171,6 @@ typedef ptr_compat_uint SourceID; #define PRI_SOURCE_ID PRI_PTR_COMPAT_UINT static const SourceID SOURCE_LOCAL = 0; -class BroObj; -extern void message(const char* msg); -extern void warn(const char* msg); -extern void warn(const char* msg, const char* addl); -extern void error(const char* msg); -extern void error(const char* msg, const char* addl); -extern void error(const char* msg, uint32 addl); -extern void run_time(const char* msg); -extern void run_time(const char* fmt, BroObj* obj); -extern void run_time(const char* fmt, const char* arg); -extern void run_time(const char* fmt, const char* arg1, const char* arg2); -extern void internal_error(const char* fmt, ...) - myattribute((volatile, format (printf, 1, 2))); extern void pinpoint(); extern int int_list_cmp(const void* v1, const void* v2); diff --git a/testing/btest/Baseline/bifs.count_to_addr/out b/testing/btest/Baseline/bifs.count_to_addr/out index 1254fd94f1..15d6a4114e 100644 --- a/testing/btest/Baseline/bifs.count_to_addr/out +++ b/testing/btest/Baseline/bifs.count_to_addr/out @@ -1,4 +1,5 @@ 0.0.0.1 48.21.133.122 255.255.255.255 +error in /da/home/robin/bro/seth/testing/btest/.tmp/bifs.count_to_addr/count_to_addr.bro, line 19: conversion of non-IPv4 count to addr (count_to_v4_addr(to_count(a)) and 4294967296) 0.0.0.0 diff --git a/testing/btest/Baseline/core.reporter-error-in-handler/output b/testing/btest/Baseline/core.reporter-error-in-handler/output new file mode 100644 index 0000000000..3efb37942c --- /dev/null +++ b/testing/btest/Baseline/core.reporter-error-in-handler/output @@ -0,0 +1,2 @@ +1st error printed on script level +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-error-in-handler/reporter-error-in-handler.bro, line 22: no such index (a[2]) diff --git a/testing/btest/Baseline/core.reporter-parse-error/output b/testing/btest/Baseline/core.reporter-parse-error/output new file mode 100644 index 0000000000..ca0bc9304b --- /dev/null +++ b/testing/btest/Baseline/core.reporter-parse-error/output @@ -0,0 +1 @@ +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-parse-error/reporter-parse-error.bro, line 7: unknown identifier TESTFAILURE, at or near "TESTFAILURE" diff --git a/testing/btest/Baseline/core.reporter-runtime-error/output b/testing/btest/Baseline/core.reporter-runtime-error/output new file mode 100644 index 0000000000..828249b35f --- /dev/null +++ b/testing/btest/Baseline/core.reporter-runtime-error/output @@ -0,0 +1,2 @@ +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-runtime-error/reporter-runtime-error.bro, line 12: no such index (a[1]) +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-runtime-error/reporter-runtime-error.bro, line 9: no such index (a[2]) diff --git a/testing/btest/Baseline/core.reporter-type-mismatch/output b/testing/btest/Baseline/core.reporter-type-mismatch/output new file mode 100644 index 0000000000..6211752225 --- /dev/null +++ b/testing/btest/Baseline/core.reporter-type-mismatch/output @@ -0,0 +1,3 @@ +error in string and /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-type-mismatch/reporter-type-mismatch.bro, line 11: arithmetic mixed with non-arithmetic (string and 42) +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-type-mismatch/reporter-type-mismatch.bro, line 11 and string: type mismatch (42 and string) +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter-type-mismatch/reporter-type-mismatch.bro, line 11: argument type mismatch in event invocation (foo(42)) diff --git a/testing/btest/Baseline/core.reporter/logger-test.log b/testing/btest/Baseline/core.reporter/logger-test.log new file mode 100644 index 0000000000..7e62352088 --- /dev/null +++ b/testing/btest/Baseline/core.reporter/logger-test.log @@ -0,0 +1,6 @@ +reporter_message|init test-message|/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 8|0.000000 +reporter_warning|init test-warning|/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 9|0.000000 +reporter_error|init test-error|/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 10|0.000000 +reporter_message|done test-message|/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 15|0.000000 +reporter_warning|done test-warning|/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 16|0.000000 +reporter_error|done test-error|/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 17|0.000000 diff --git a/testing/btest/Baseline/core.reporter/output b/testing/btest/Baseline/core.reporter/output new file mode 100644 index 0000000000..3f18d9bbc1 --- /dev/null +++ b/testing/btest/Baseline/core.reporter/output @@ -0,0 +1,3 @@ +/da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 52: pre test-message +warning in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 53: pre test-warning +error in /da/home/robin/bro/seth/testing/btest/.tmp/core.reporter/reporter.bro, line 54: pre test-error diff --git a/testing/btest/Baseline/core.vlan-mpls/conn.log b/testing/btest/Baseline/core.vlan-mpls/conn.log index 3533354623..d49c8f7c1e 100644 --- a/testing/btest/Baseline/core.vlan-mpls/conn.log +++ b/testing/btest/Baseline/core.vlan-mpls/conn.log @@ -1,4 +1,4 @@ # ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes conn_state local_orig missed_bytes history notice_tags 952109346.874907 UWkUyAuUGXf 10.1.2.1 11001 10.34.0.1 23 tcp - 2.10255992412567 25 0 SH - 0 - - -1128727435.4509 50da4BEzauh 141.42.64.125 56730 125.190.109.199 80 tcp - 1.73330307006836 98 9417 SF - 0 ShADdFaf - -1278600802.06942 WUjEZFOdSS 10.20.80.1 50343 10.0.0.15 80 tcp - 0.00415205955505371 9 3429 SF - 0 ShADadfF - +1128727435.4509 56gKBmhBBB6 141.42.64.125 56730 125.190.109.199 80 tcp - 1.73330307006836 98 9417 SF - 0 ShADdFaf - +1278600802.06942 50da4BEzauh 10.20.80.1 50343 10.0.0.15 80 tcp - 0.00415205955505371 9 3429 SF - 0 ShADadfF - diff --git a/testing/btest/Baseline/language.wrong-delete-field/output b/testing/btest/Baseline/language.wrong-delete-field/output index 8d965362f1..f8271e43c2 100644 --- a/testing/btest/Baseline/language.wrong-delete-field/output +++ b/testing/btest/Baseline/language.wrong-delete-field/output @@ -1 +1 @@ -/da/home/robin/bro/master/testing/btest/.tmp/language.wrong-delete-field/wrong-delete-field.bro, line 10 (delete x$a): error, illegal delete statement +error in /da/home/robin/bro/seth/testing/btest/.tmp/language.wrong-delete-field/wrong-delete-field.bro, line 10: illegal delete statement (delete x$a) diff --git a/testing/btest/Baseline/language.wrong-record-extension/output b/testing/btest/Baseline/language.wrong-record-extension/output index 144a065f59..9d7b1fd5e0 100644 --- a/testing/btest/Baseline/language.wrong-record-extension/output +++ b/testing/btest/Baseline/language.wrong-record-extension/output @@ -1 +1 @@ - error, extension field must be &optional or have &default + extension field must be &optional or have &default (Foo) diff --git a/testing/btest/bifs/unique_id-rnd.bro b/testing/btest/bifs/unique_id-rnd.bro index 1b24c662e2..d3b3b85849 100644 --- a/testing/btest/bifs/unique_id-rnd.bro +++ b/testing/btest/bifs/unique_id-rnd.bro @@ -1,6 +1,6 @@ # -# @TEST-EXEC: BRO_SEED_FILE= bro %INPUT 2>/dev/null >out -# @TEST-EXEC: BRO_SEED_FILE= bro %INPUT 2>/dev/null >>out +# @TEST-EXEC: BRO_SEED_FILE= bro %INPUT >out +# @TEST-EXEC: BRO_SEED_FILE= bro %INPUT >>out # @TEST-EXEC: cat out | sort | uniq | wc -l | sed 's/ //g' >count # @TEST-EXEC: btest-diff count diff --git a/testing/btest/core/reporter-error-in-handler.bro b/testing/btest/core/reporter-error-in-handler.bro new file mode 100644 index 0000000000..c4a21d5902 --- /dev/null +++ b/testing/btest/core/reporter-error-in-handler.bro @@ -0,0 +1,29 @@ +# +# This test procudes a recursive error: the error handler is itself broken. Rather +# than looping indefinitly, the error inside the handler should reported to stderr. +# +# @TEST-EXEC: bro %INPUT >output 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff output + +global a: table[count] of count; + +global c = 0; + +event reporter_error(t: time, msg: string, location: string) +{ + c += 1; + + if ( c > 1 ) + print "FAILED: 2nd error reported to script as well."; + + else + { + print "1st error printed on script level"; + print a[2]; + } +} + +event bro_init() +{ + print a[1]; +} diff --git a/testing/btest/core/reporter-parse-error.bro b/testing/btest/core/reporter-parse-error.bro new file mode 100644 index 0000000000..25f33e2785 --- /dev/null +++ b/testing/btest/core/reporter-parse-error.bro @@ -0,0 +1,8 @@ +# +# @TEST-EXEC-FAIL: bro %INPUT >output 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff output + +event bro_init() +{ + print TESTFAILURE; +} diff --git a/testing/btest/core/reporter-runtime-error.bro b/testing/btest/core/reporter-runtime-error.bro new file mode 100644 index 0000000000..330e2a7e5c --- /dev/null +++ b/testing/btest/core/reporter-runtime-error.bro @@ -0,0 +1,13 @@ +# +# @TEST-EXEC: bro %INPUT >output 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff output + +global a: table[count] of count; + +event bro_init() +{ + print a[2]; +} + +print a[1]; + diff --git a/testing/btest/core/reporter-type-mismatch.bro b/testing/btest/core/reporter-type-mismatch.bro new file mode 100644 index 0000000000..0faa9b85e2 --- /dev/null +++ b/testing/btest/core/reporter-type-mismatch.bro @@ -0,0 +1,12 @@ +# +# @TEST-EXEC-FAIL: bro %INPUT >output 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff output + +event foo(a: string) +{ +} + +event bro_init() +{ + event foo(42); +} diff --git a/testing/btest/core/reporter.bro b/testing/btest/core/reporter.bro new file mode 100644 index 0000000000..70bb0b665c --- /dev/null +++ b/testing/btest/core/reporter.bro @@ -0,0 +1,55 @@ +# +# @TEST-EXEC: bro %INPUT >output 2>&1 +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff output +# @TEST-EXEC: TEST_DIFF_CANONIFIER=$SCRIPTS/diff-remove-abspath btest-diff logger-test.log + +event bro_init() +{ + Reporter::message("init test-message"); + Reporter::warning("init test-warning"); + Reporter::error("init test-error"); +} + +event bro_done() +{ + Reporter::message("done test-message"); + Reporter::warning("done test-warning"); + Reporter::error("done test-error"); +} + +global first = 1; + +event connection_established(c: connection) +{ + if ( ! first ) + return; + + print "established"; + + Reporter::message("processing test-message"); + Reporter::warning("processing test-warning"); + Reporter::error("processing test-error"); + first = 0; +} + +global f = open_log_file("logger-test"); + +event reporter_message(t: time, msg: string, location: string) + { + print f, fmt("reporter_message|%s|%s|%.6f", msg, location, t); + } + +event reporter_warning(t: time, msg: string, location: string) + { + print f, fmt("reporter_warning|%s|%s|%.6f", msg, location, t); + } + +event reporter_error(t: time, msg: string, location: string) + { + print f, fmt("reporter_error|%s|%s|%.6f", msg, location, t); + } + +Reporter::message("pre test-message"); +Reporter::warning("pre test-warning"); +Reporter::error("pre test-error"); +