From 19c1816ebb20d574255b9c1bf2ee6cdb5f162de5 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 28 Mar 2013 21:47:44 -0700 Subject: [PATCH] Infrastructure for modularizing protocol analyzers. There's now a new directory "src/protocols/", and the plan is for each protocol analyzer to eventually have its own subdirectory in there that contains everything it defines (C++/pac/bif). The infrastructure to make that happen is in place, and two analyzers have been converted to the new model, HTTP and SSL; there's no further HTTP/SSL-specific code anywhere else in the core anymore (I believe :-) Further changes: - -N lists available plugins, -NN lists more details on what these plugins provide (analyzers, bif elements). (The latter does not work for analyzers that haven't been converted yet). - *.bif.bro files now go into scripts/base/bif/; and scripts/base/bif/plugins/ for bif files provided by plugins. - I've factored out the bifcl/binpac CMake magic from src/CMakeLists.txt to cmake/{BifCl,Binpac} - There's a new cmake/BroPlugin that contains magic to allow plugins to have a simple CMakeLists.txt. The hope is that eventually the same CMakeLists.txt can be used for compiling a plugin either statically or dynamically. - bifcl has a new option -c that changes the code it generates so that it can be used with a plugin. TODOs: - "make install" is probably broken. - Broxygen is probably broken for plugin-defined events. - event groups are broken (do we want to keep them?) --- bro-path-dev.in | 2 +- cmake | 2 +- scripts/base/frameworks/analyzer/main.bro | 2 +- scripts/base/frameworks/input/main.bro | 2 +- scripts/base/frameworks/logging/main.bro | 2 +- scripts/base/init-bare.bro | 14 +- src/CMakeLists.txt | 101 ++--- src/EventRegistry.cc | 4 +- src/FTP.cc | 13 +- src/Gnutella.cc | 7 +- src/Sessions.cc | 1 - src/analyzer/Manager.cc | 6 + src/analyzer/Manager.h | 3 +- src/bro-bif.h | 11 + src/bro.bif | 54 --- src/builtin-func.l | 151 +++++- src/builtin-func.y | 35 +- src/event.bif | 428 ------------------ src/main.cc | 32 +- src/plugin/Component.cc | 1 - src/plugin/Macros.h | 42 ++ src/plugin/Manager.cc | 47 +- src/plugin/Manager.h | 16 +- src/plugin/Plugin.cc | 80 +++- src/plugin/Plugin.h | 28 +- .../BuiltInAnalyzers.cc | 18 +- .../BuiltInAnalyzers.h | 0 src/protocols/CMakeLists.txt | 3 + src/protocols/http/CMakeLists.txt | 11 + src/{ => protocols/http}/HTTP.cc | 9 + src/{ => protocols/http}/HTTP.h | 2 + src/protocols/http/events.bif | 232 ++++++++++ src/protocols/http/functions.bif | 56 +++ src/protocols/ssl/CMakeLists.txt | 10 + src/protocols/ssl/Plugin.cc | 10 + src/{ => protocols/ssl}/SSL.cc | 1 + src/{ => protocols/ssl}/SSL.h | 2 + src/protocols/ssl/events.bif | 195 ++++++++ src/{ => protocols/ssl}/ssl-analyzer.pac | 0 src/{ => protocols/ssl}/ssl-defs.pac | 0 src/{ => protocols/ssl}/ssl-protocol.pac | 0 src/{ => protocols/ssl}/ssl.pac | 4 + src/{ => protocols/unused}/HTTP-binpac.cc | 0 src/{ => protocols/unused}/HTTP-binpac.h | 0 44 files changed, 974 insertions(+), 663 deletions(-) create mode 100644 src/bro-bif.h create mode 100644 src/plugin/Macros.h rename src/{analyzer => protocols}/BuiltInAnalyzers.cc (91%) rename src/{analyzer => protocols}/BuiltInAnalyzers.h (100%) create mode 100644 src/protocols/CMakeLists.txt create mode 100644 src/protocols/http/CMakeLists.txt rename src/{ => protocols/http}/HTTP.cc (99%) rename src/{ => protocols/http}/HTTP.h (99%) create mode 100644 src/protocols/http/events.bif create mode 100644 src/protocols/http/functions.bif create mode 100644 src/protocols/ssl/CMakeLists.txt create mode 100644 src/protocols/ssl/Plugin.cc rename src/{ => protocols/ssl}/SSL.cc (99%) rename src/{ => protocols/ssl}/SSL.h (97%) create mode 100644 src/protocols/ssl/events.bif rename src/{ => protocols/ssl}/ssl-analyzer.pac (100%) rename src/{ => protocols/ssl}/ssl-defs.pac (100%) rename src/{ => protocols/ssl}/ssl-protocol.pac (100%) rename src/{ => protocols/ssl}/ssl.pac (94%) rename src/{ => protocols/unused}/HTTP-binpac.cc (100%) rename src/{ => protocols/unused}/HTTP-binpac.h (100%) diff --git a/bro-path-dev.in b/bro-path-dev.in index 81d4f111fc..2c17d057c9 100755 --- a/bro-path-dev.in +++ b/bro-path-dev.in @@ -12,7 +12,7 @@ broPolicies=${BRO_SCRIPT_SOURCE_PATH}:${BRO_SCRIPT_SOURCE_PATH}/policy:${BRO_SCRIPT_SOURCE_PATH}/site -broGenPolicies=${CMAKE_BINARY_DIR}/src +broGenPolicies=${CMAKE_BINARY_DIR}/scripts installedPolicies=${BRO_SCRIPT_INSTALL_PATH}:${BRO_SCRIPT_INSTALL_PATH}/site diff --git a/cmake b/cmake index 94e72a3075..870dd2c240 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 94e72a3075bb0b9550ad05758963afda394bfb2c +Subproject commit 870dd2c240acaee5c2d75da0feb5fd5044177123 diff --git a/scripts/base/frameworks/analyzer/main.bro b/scripts/base/frameworks/analyzer/main.bro index d2f2b3172b..ea5ccb727c 100644 --- a/scripts/base/frameworks/analyzer/main.bro +++ b/scripts/base/frameworks/analyzer/main.bro @@ -59,7 +59,7 @@ export { &redef; } -@load base/analyzer.bif +@load base/bif/analyzer.bif global ports: table[Analyzer::Tag] of set[port]; diff --git a/scripts/base/frameworks/input/main.bro b/scripts/base/frameworks/input/main.bro index 1a05abce71..4de98ea0f2 100644 --- a/scripts/base/frameworks/input/main.bro +++ b/scripts/base/frameworks/input/main.bro @@ -149,7 +149,7 @@ export { global end_of_data: event(name: string, source:string); } -@load base/input.bif +@load base/bif/input.bif module Input; diff --git a/scripts/base/frameworks/logging/main.bro b/scripts/base/frameworks/logging/main.bro index 054ad4a30b..05a03ab11d 100644 --- a/scripts/base/frameworks/logging/main.bro +++ b/scripts/base/frameworks/logging/main.bro @@ -357,7 +357,7 @@ export { # We keep a script-level copy of all filters so that we can manipulate them. global filters: table[ID, string] of Filter; -@load base/logging.bif # Needs Filter and Stream defined. +@load base/bif/logging.bif # Needs Filter and Stream defined. module Log; diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index d8f38ed124..3afabd9ae0 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -1,5 +1,5 @@ -@load base/const.bif -@load base/types.bif +@load base/bif/const.bif.bro +@load base/bif/types.bif # Type declarations @@ -646,9 +646,9 @@ type entropy_test_result: record { }; # Prototypes of Bro built-in functions. -@load base/strings.bif -@load base/bro.bif -@load base/reporter.bif +@load base/bif/strings.bif +@load base/bif/bro.bif +@load base/bif/reporter.bif ## Deprecated. This is superseded by the new logging framework. global log_file_name: function(tag: string): string &redef; @@ -2656,7 +2656,7 @@ export { } module GLOBAL; -@load base/event.bif +@load base/bif/event.bif ## BPF filter the user has set via the -f command line options. Empty if none. const cmd_line_bpf_filter = "" &redef; @@ -3004,3 +3004,5 @@ const snaplen = 8192 &redef; @load base/frameworks/input @load base/frameworks/analyzer +# Load BiF defined by plugins. +@load base/bif/plugins diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b635360ac9..31192a8757 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -100,45 +100,7 @@ target_link_libraries(bifcl) ######################################################################## ## bifcl-dependent targets -# A macro to define a command that uses the BIF compiler to produce -# C++ segments and Bro language declarations from .bif file -# The outputs are appended to list ALL_BIF_OUTPUTS -# Outputs that should be installed are appended to INSTALL_BIF_OUTPUTS -macro(BIF_TARGET bifInput) - get_bif_output_files(${bifInput} bifOutputs) - add_custom_command(OUTPUT ${bifOutputs} - COMMAND bifcl - ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${bifInput} || (rm -f ${bifOutputs} && exit 1) - # In order be able to run bro from the build directory, - # the generated bro script needs to be inside a - # a directory tree named the same way it will be - # referenced from an @load. - COMMAND "${CMAKE_COMMAND}" - ARGS -E copy ${bifInput}.bro base/${bifInput}.bro - COMMAND "${CMAKE_COMMAND}" - ARGS -E remove -f ${bifInput}.bro - DEPENDS ${bifInput} - DEPENDS bifcl - COMMENT "[BIFCL] Processing ${bifInput}" - ) - list(APPEND ALL_BIF_OUTPUTS ${bifOutputs}) - list(APPEND INSTALL_BIF_OUTPUTS - ${CMAKE_CURRENT_BINARY_DIR}/base/${bifInput}.bro) -endmacro(BIF_TARGET) - -# returns a list of output files that bifcl will produce -# for given input file in ${outputFileVar} -macro(GET_BIF_OUTPUT_FILES inputFile outputFileVar) - set(${outputFileVar} - base/${inputFile}.bro - ${inputFile}.func_def - ${inputFile}.func_h - ${inputFile}.func_init - ${inputFile}.netvar_def - ${inputFile}.netvar_h - ${inputFile}.netvar_init - ) -endmacro(GET_BIF_OUTPUT_FILES) +include(BifCl) set(BIF_SRCS analyzer.bif @@ -156,36 +118,18 @@ foreach (bift ${BIF_SRCS}) bif_target(${bift}) endforeach () +add_custom_target(generate_standard_bifs DEPENDS ${ALL_BIF_OUTPUTS}) + ######################################################################## ## BinPAC-dependent targets -set(BINPAC_AUXSRC - binpac.pac - bro.pac - binpac_bro.h -) +include(BinPAC) -# A macro to define a command that uses the BinPac compiler to -# produce C++ code that implements a protocol parser/analyzer -# The outputs of the command are appended to list ALL_BINPAC_OUTPUTS -# All arguments to this macro are appended to list ALL_BINPAC_INPUTS -macro(BINPAC_TARGET pacFile) - get_filename_component(basename ${pacFile} NAME_WE) - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.h - ${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.cc - COMMAND ${BinPAC_EXE} - ARGS -q -d ${CMAKE_CURRENT_BINARY_DIR} - -I ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_SOURCE_DIR}/${pacFile} - DEPENDS ${BinPAC_EXE} ${pacFile} - ${BINPAC_AUXSRC} ${ARGN} - COMMENT "[BINPAC] Processing ${pacFile}" - ) - list(APPEND ALL_BINPAC_INPUTS ${ARGV}) - list(APPEND ALL_BINPAC_OUTPUTS - ${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.h - ${CMAKE_CURRENT_BINARY_DIR}/${basename}_pac.cc) -endmacro(BINPAC_TARGET) +set(BINPAC_AUXSRC + ${CMAKE_SOURCE_DIR}/src/binpac.pac + ${CMAKE_SOURCE_DIR}/src/bro.pac + ${CMAKE_SOURCE_DIR}/src/binpac_bro.h +) binpac_target(binpac-lib.pac) binpac_target(binpac_bro-lib.pac) @@ -206,8 +150,8 @@ binpac_target(dns_tcp.pac dns.pac) binpac_target(gtpv1.pac gtpv1-protocol.pac gtpv1-analyzer.pac) -binpac_target(http.pac - http-protocol.pac http-analyzer.pac) +# binpac_target(http.pac +# http-protocol.pac http-analyzer.pac) binpac_target(ncp.pac) binpac_target(netflow.pac netflow-protocol.pac netflow-analyzer.pac) @@ -215,13 +159,20 @@ binpac_target(smb.pac smb-protocol.pac smb-pipe.pac smb-mailslot.pac) binpac_target(socks.pac socks-protocol.pac socks-analyzer.pac) -binpac_target(ssl.pac - ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac) +# binpac_target(ssl.pac +# ssl-defs.pac ssl-protocol.pac ssl-analyzer.pac) binpac_target(syslog.pac syslog-protocol.pac syslog-analyzer.pac) binpac_target(modbus.pac modbus-protocol.pac modbus-analyzer.pac) +######################################################################## +## Including plug-ins that are compiled in statically. +######################################################################## + +set(bro_PLUGIN_OBJECT_LIBS CACHE INTERNAL "plugin object libraries" FORCE) +add_subdirectory(protocols) + ######################################################################## ## bro target @@ -334,8 +285,6 @@ set(bro_SRCS Func.cc Gnutella.cc GTPv1.cc - HTTP.cc - HTTP-binpac.cc Hash.cc ICMP.cc ID.cc @@ -390,7 +339,6 @@ set(bro_SRCS SMTP.cc SOCKS.cc SSH.cc - SSL.cc Scope.cc SerializationFormat.cc SerialObj.cc @@ -451,18 +399,19 @@ set(bro_SRCS plugin/Plugin.cc analyzer/Analyzer.cc - analyzer/BuiltInAnalyzers.cc analyzer/Manager.cc analyzer/PluginComponent.cc analyzer/Tag.cc + protocols/BuiltInAnalyzers.cc + nb_dns.c digest.h ) collect_headers(bro_HEADERS ${bro_SRCS}) -add_executable(bro ${bro_SRCS} ${bro_HEADERS}) +add_executable(bro ${bro_SRCS} ${bro_HEADERS} ${bro_PLUGIN_OBJECT_LIBS}) target_link_libraries(bro ${brodeps} ${CMAKE_THREAD_LIBS_INIT}) @@ -471,3 +420,7 @@ install(FILES ${INSTALL_BIF_OUTPUTS} DESTINATION ${BRO_SCRIPT_INSTALL_PATH}/base set(BRO_EXE bro CACHE STRING "Bro executable binary" FORCE) + +include(BroPlugin) +bro_plugin_bif_create_loader(bif_loader ${CMAKE_BINARY_DIR}/scripts/base/bif/plugins) +add_dependencies(bro bif_loader) diff --git a/src/EventRegistry.cc b/src/EventRegistry.cc index 4d29c5d95f..f51f624833 100644 --- a/src/EventRegistry.cc +++ b/src/EventRegistry.cc @@ -87,9 +87,11 @@ void EventRegistry::PrintDebug() void EventRegistry::SetGroup(const char* name, const char* group) { + return; // FIXME. THis triggers the error below for plugin events. + EventHandler* eh = Lookup(name); if ( ! eh ) - reporter->InternalError("unknown event handler in SetGroup()"); + reporter->InternalError("unknown event handler %s in SetGroup()", name); eh->SetGroup(group); } diff --git a/src/FTP.cc b/src/FTP.cc index 5430b9e754..a0cc25292c 100644 --- a/src/FTP.cc +++ b/src/FTP.cc @@ -8,8 +8,8 @@ #include "FTP.h" #include "NVT.h" #include "Event.h" -#include "SSL.h" #include "Base64.h" +#include "analyzer/Manager.h" FTP_Analyzer::FTP_Analyzer(Connection* conn) : TCP_ApplicationAnalyzer("FTP", conn) @@ -154,10 +154,13 @@ void FTP_Analyzer::DeliverStream(int length, const u_char* data, bool orig) // Server wants to proceed with an ADAT exchange and we // know how to analyze the GSI mechanism, so attach analyzer // to look for that. - SSL_Analyzer* ssl = new SSL_Analyzer(Conn()); - ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), true)); - ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), false)); - AddChildAnalyzer(ssl); + Analyzer* ssl = analyzer_mgr->InstantiateAnalyzer("SSL", Conn()); + if ( ssl ) + { + ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), true)); + ssl->AddSupportAnalyzer(new FTP_ADAT_Analyzer(Conn(), false)); + AddChildAnalyzer(ssl); + } } vl->append(new Val(reply_code, TYPE_COUNT)); diff --git a/src/Gnutella.cc b/src/Gnutella.cc index 6c8d4ee3f6..9cfab4ff1a 100644 --- a/src/Gnutella.cc +++ b/src/Gnutella.cc @@ -7,10 +7,10 @@ #include #include "NetVar.h" -#include "HTTP.h" #include "Gnutella.h" #include "Event.h" #include "PIA.h" +#include "analyzer/Manager.h" GnutellaMsgState::GnutellaMsgState() { @@ -129,9 +129,10 @@ int Gnutella_Analyzer::IsHTTP(string header) ConnectionEvent(gnutella_http_notify, vl); } - if ( HTTP_Analyzer::Available() ) + analyzer::Analyzer* a = analyzer_mgr->InstantiateAnalyzer("HTTP", Conn()); + + if ( a ) { - analyzer::Analyzer* a = new HTTP_Analyzer(Conn()); Parent()->AddChildAnalyzer(a); if ( Parent()->IsAnalyzer("TCP") ) diff --git a/src/Sessions.cc b/src/Sessions.cc index f18d12ef90..7586899e14 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -20,7 +20,6 @@ #include "UDP.h" #include "DNS-binpac.h" -#include "HTTP-binpac.h" #include "SteppingStone.h" #include "BackDoor.h" diff --git a/src/analyzer/Manager.cc b/src/analyzer/Manager.cc index 78c086d409..060595aea2 100644 --- a/src/analyzer/Manager.cc +++ b/src/analyzer/Manager.cc @@ -316,6 +316,12 @@ Analyzer* Manager::InstantiateAnalyzer(Tag tag, Connection* conn) return a; } +Analyzer* Manager::InstantiateAnalyzer(const char* name, Connection* conn) + { + Tag tag = GetAnalyzerTag(name); + return tag ? InstantiateAnalyzer(tag, conn) : 0; + } + const string& Manager::GetAnalyzerName(Tag tag) { static string error = ""; diff --git a/src/analyzer/Manager.h b/src/analyzer/Manager.h index ceca74bf0c..33b27ed38a 100644 --- a/src/analyzer/Manager.h +++ b/src/analyzer/Manager.h @@ -86,7 +86,8 @@ public: bool UnregisterAnalyzerForPort(EnumVal* tag, PortVal* port); bool UnregisterAnalyzerForPort(Tag tag, TransportProto proto, uint32 port); - Analyzer* InstantiateAnalyzer(Tag tag, Connection* c); // Null if disabled. + Analyzer* InstantiateAnalyzer(Tag tag, Connection* c); // Null if disabled or not available. + Analyzer* InstantiateAnalyzer(const char* name, Connection* c); // Null if disabled or not available. const string& GetAnalyzerName(Tag tag); const string& GetAnalyzerName(Val* val); diff --git a/src/bro-bif.h b/src/bro-bif.h new file mode 100644 index 0000000000..24312e4753 --- /dev/null +++ b/src/bro-bif.h @@ -0,0 +1,11 @@ + +#ifndef BRO_BIF_H +#define BRO_BIF_H + +// Headers to include by generated BiF code. +#include "analyzer/Analyzer.h" +#include "Conn.h" +#include "NetVar.h" +#include "Event.h" + +#endif diff --git a/src/bro.bif b/src/bro.bif index 4c88a7dd77..9b3eb946e2 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -3327,8 +3327,6 @@ function lookup_connection%(cid: conn_id%): connection %} %%{ -#include "HTTP.h" - const char* conn_id_string(Val* c) { Val* id = (*(c->AsRecord()))[0]; @@ -3344,58 +3342,6 @@ const char* conn_id_string(Val* c) } %%} -## Skips the data of the HTTP entity. -## -## c: The HTTP connection. -## -## is_orig: If true, the client data is skipped, and the server data otherwise. -## -## .. bro:see:: skip_smtp_data -function skip_http_entity_data%(c: connection, is_orig: bool%): any - %{ - analyzer::ID id = mgr.CurrentAnalyzer(); - if ( id ) - { - analyzer::Analyzer* ha = c->FindAnalyzer(id); - - if ( ha ) - { - if ( ha->IsAnalyzer("HTTP") ) - static_cast(ha)->SkipEntityData(is_orig); - else - reporter->Error("non-HTTP analyzer associated with connection record"); - } - else - reporter->Error("could not find analyzer for skip_http_entity_data"); - - } - else - reporter->Error("no analyzer associated with connection record"); - - return 0; - %} - -## Unescapes all characters in a URI (decode every ``%xx`` group). -## -## URI: The URI to unescape. -## -## Returns: The unescaped URI with all ``%xx`` groups decoded. -## -## .. note:: -## -## Unescaping reserved characters may cause loss of information. RFC 2396: -## A URI is always in an "escaped" form, since escaping or unescaping a -## completed URI might change its semantics. Normally, the only time -## escape encodings can safely be made is when the URI is being created -## from its component parts. -function unescape_URI%(URI: string%): string - %{ - const u_char* line = URI->Bytes(); - const u_char* const line_end = line + URI->Len(); - - return new StringVal(unescape_URI(line, line_end, 0)); - %} - ## Writes the current packet to a file. ## ## file_name: The name of the file to write the packet to. diff --git a/src/builtin-func.l b/src/builtin-func.l index 9baeb1a9f9..ec60f1c7ec 100644 --- a/src/builtin-func.l +++ b/src/builtin-func.l @@ -27,7 +27,7 @@ int check_c_mode(int t) WS [ \t]+ /* Note, bifcl only accepts a single "::" in IDs while the policy - layer acceptes multiple. (But the policy layer doesn't have + layer acceptes multiple. (But the policy layer doesn't have a hierachy. */ IDCOMPONENT [A-Za-z_][A-Za-z_0-9]* ID {IDCOMPONENT}(::{IDCOMPONENT})? @@ -137,6 +137,8 @@ int yywrap() extern int yyparse(); char* input_filename = 0; +char* input_filename_with_path = 0; +char* plugin = 0; FILE* fp_bro_init = 0; FILE* fp_func_def = 0; @@ -168,15 +170,108 @@ FILE* open_output_file(const char* surfix) return fp; } +void usage() + { + fprintf(stderr, "usage: bifcl [-p] *.bif\n"); + exit(1); + } + +void init_plugin_mode() + { + fp_bro_init = open_output_file("bro"); + fp_func_h = open_output_file("h"); + fp_func_def = open_output_file("cc"); + fp_func_init = open_output_file("init.cc"); + + fp_netvar_h = fp_func_h; + fp_netvar_def = fp_func_def; + fp_netvar_init = fp_func_init; + + int n = 1024 + strlen(input_filename); + char auto_gen_comment[n]; + + snprintf(auto_gen_comment, n, + "This file was automatically generated by bifcl from %s (plugin mode).", + input_filename_with_path); + + fprintf(fp_bro_init, "# %s\n\n", auto_gen_comment); + fprintf(fp_func_def, "// %s\n\n", auto_gen_comment); + fprintf(fp_func_h, "// %s\n\n", auto_gen_comment); + fprintf(fp_func_init, "// %s\n\n", auto_gen_comment); + + static char guard[1024]; + getcwd(guard, sizeof(guard)); + strncat(guard, "/", sizeof(guard)); + strncat(guard, input_filename, sizeof(guard)); + + for ( char* p = guard; *p; p++ ) + { + if ( strchr("/.", *p) ) + *p = '_'; + } + + fprintf(fp_func_h, "#ifndef %s\n", guard); + fprintf(fp_func_h, "#define %s\n", guard); + fprintf(fp_func_h, "\n"); + fprintf(fp_func_h, "#include \"bro-bif.h\"\n"); + + fprintf(fp_func_def, "\n"); + fprintf(fp_func_def, "#include \"%s.h\"\n", input_filename); + fprintf(fp_func_def, "\n"); + + static char name[1024]; + strncpy(name, input_filename, sizeof(name)); + char* dot = strchr(name, '.'); + if ( dot ) + *dot = '\0'; + + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "#include \n"); + fprintf(fp_func_init, "#include \n"); + fprintf(fp_func_init, "#include \"%s.h\"\n", input_filename); + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin); + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "std::list > __bif_%s_init()\n", name); + fprintf(fp_func_init, "\t{\n"); + fprintf(fp_func_init, "\tstd::list > bifs;\n"); + fprintf(fp_func_init, "\n"); + } + +void finish_plugin_mode() + { + fprintf(fp_func_h, "\n"); + fprintf(fp_func_h, "#endif\n"); + + fprintf(fp_func_init, "\n"); + fprintf(fp_func_init, "\treturn bifs;\n"); + fprintf(fp_func_init, "\t}\n"); + fprintf(fp_func_init, "} }\n"); + fprintf(fp_func_init, "\n"); + } int main(int argc, char* argv[]) { - for ( int i = 1; i < argc; i++ ) + char opt; + + while ( (opt = getopt(argc, argv, "p:")) != -1 ) + { + switch ( opt ) { + case 'p': + plugin = optarg; + break; + + default: + usage(); + } + } + + for ( int i = optind; i < argc; i++ ) { FILE* fp_input; char* slash; - input_filename = argv[i]; + input_filename = input_filename_with_path = argv[i]; slash = strrchr(input_filename, '/'); if ( (fp_input = fopen(input_filename, "r")) == NULL ) @@ -189,17 +284,41 @@ int main(int argc, char* argv[]) if ( slash ) input_filename = slash + 1; - fp_bro_init = open_output_file("bro"); - fp_func_h = open_output_file("func_h"); - fp_func_def = open_output_file("func_def"); - fp_func_init = open_output_file("func_init"); - fp_netvar_h = open_output_file("netvar_h"); - fp_netvar_def = open_output_file("netvar_def"); - fp_netvar_init = open_output_file("netvar_init"); + if ( ! plugin ) + { + fp_bro_init = open_output_file("bro"); + fp_func_h = open_output_file("func_h"); + fp_func_def = open_output_file("func_def"); + fp_func_init = open_output_file("func_init"); + fp_netvar_h = open_output_file("netvar_h"); + fp_netvar_def = open_output_file("netvar_def"); + fp_netvar_init = open_output_file("netvar_init"); + + int n = 1024 + strlen(input_filename); + char auto_gen_comment[n]; + + snprintf(auto_gen_comment, n, + "This file was automatically generated by bifcl from %s.", + input_filename); + + fprintf(fp_bro_init, "# %s\n\n", auto_gen_comment); + fprintf(fp_func_def, "// %s\n\n", auto_gen_comment); + fprintf(fp_func_h, "// %s\n\n", auto_gen_comment); + fprintf(fp_func_init, "// %s\n\n", auto_gen_comment); + fprintf(fp_netvar_def, "// %s\n\n", auto_gen_comment); + fprintf(fp_netvar_h, "// %s\n\n", auto_gen_comment); + fprintf(fp_netvar_init, "// %s\n\n", auto_gen_comment); + } + + else + init_plugin_mode(); yy_switch_to_buffer(yy_create_buffer(fp_input, YY_BUF_SIZE)); yyparse(); + if ( plugin ) + finish_plugin_mode(); + fclose(fp_input); close_all_output_files(); @@ -219,9 +338,13 @@ void close_all_output_files(void) close_if_open(&fp_func_h); close_if_open(&fp_func_def); close_if_open(&fp_func_init); - close_if_open(&fp_netvar_h); - close_if_open(&fp_netvar_def); - close_if_open(&fp_netvar_init); + + if ( ! plugin ) + { + close_if_open(&fp_netvar_h); + close_if_open(&fp_netvar_def); + close_if_open(&fp_netvar_init); + } } void remove_file(const char *surfix) @@ -232,7 +355,7 @@ void remove_file(const char *surfix) unlink(fn); } -void err_exit(void) +void err_exit(void) { close_all_output_files(); /* clean up. remove all output files we've generated so far */ diff --git a/src/builtin-func.y b/src/builtin-func.y index b5d076a56e..58acf64c8e 100644 --- a/src/builtin-func.y +++ b/src/builtin-func.y @@ -15,6 +15,7 @@ using namespace std; extern int line_number; extern char* input_filename; +extern char* plugin; #define print_line_directive(fp) fprintf(fp, "\n#line %d \"%s\"\n", line_number, input_filename) @@ -265,6 +266,15 @@ void print_event_c_body(FILE *fp) fprintf(fp, "\t} // event generation\n"); //fprintf(fp, "%s // end namespace\n", decl.generate_c_namespace_end.c_str()); } + +void record_bif_item(const char* id, int type) + { + if ( ! plugin ) + return; + + fprintf(fp_func_init, "\tbifs.push_back(std::make_pair(\"%s\", %d));\n", id, type); + } + %} %token TOK_LPP TOK_RPP TOK_LPB TOK_RPB TOK_LPPB TOK_RPPB TOK_VAR_ARG @@ -304,21 +314,6 @@ definitions: definitions definition opt_ws } | opt_ws { - int n = 1024 + strlen(input_filename); - char auto_gen_comment[n]; - - snprintf(auto_gen_comment, n, - "This file was automatically generated by bifcl from %s.", - input_filename); - - fprintf(fp_bro_init, "# %s\n\n", auto_gen_comment); - fprintf(fp_func_def, "// %s\n\n", auto_gen_comment); - fprintf(fp_func_h, "// %s\n\n", auto_gen_comment); - fprintf(fp_func_init, "// %s\n\n", auto_gen_comment); - fprintf(fp_netvar_def, "// %s\n\n", auto_gen_comment); - fprintf(fp_netvar_h, "// %s\n\n", auto_gen_comment); - fprintf(fp_netvar_init, "// %s\n\n", auto_gen_comment); - fprintf(fp_bro_init, "%s", $1); fprintf(fp_bro_init, "export {\n"); } @@ -362,6 +357,8 @@ type_def: TOK_TYPE opt_ws TOK_ID opt_ws ':' opt_ws type_def_types opt_ws ';' "\t%s = internal_type(\"%s\")->As%sType();\n", decl.c_fullname.c_str(), decl.bro_fullname.c_str(), type_name.c_str()); + + record_bif_item(decl.bro_fullname.c_str(), 5); } ; @@ -402,6 +399,8 @@ enum_def: enum_def_1 enum_list TOK_RPB fprintf(fp_netvar_init, "\t%s = internal_type(\"%s\")->AsEnumType();\n", decl.c_fullname.c_str(), decl.bro_fullname.c_str()); + + record_bif_item(decl.bro_fullname.c_str(), 5); } ; @@ -456,6 +455,8 @@ const_def: TOK_CONST opt_ws TOK_ID opt_ws ':' opt_ws TOK_ID opt_ws ';' fprintf(fp_netvar_init, "\t%s = internal_const_val(\"%s\")%s;\n", decl.c_fullname.c_str(), decl.bro_fullname.c_str(), accessor); + + record_bif_item(decl.bro_fullname.c_str(), 3); } @@ -545,6 +546,8 @@ head_1: TOK_ID opt_ws arg_begin fprintf(fp_func_def, "Val* %s(Frame* frame, val_list* %s)", decl.c_fullname.c_str(), arg_list_name); + + record_bif_item(decl.bro_fullname.c_str(), 1); } else if ( definition_type == EVENT_DEF ) { @@ -561,6 +564,8 @@ head_1: TOK_ID opt_ws arg_begin "\t%s = internal_handler(\"%s\");\n", decl.c_fullname.c_str(), decl.bro_fullname.c_str()); + record_bif_item(decl.bro_fullname.c_str(), 2); + // C++ prototypes of bro_event_* functions will // be generated later. } diff --git a/src/event.bif b/src/event.bif index dd7ab3c1d6..fbc02ef8b5 100644 --- a/src/event.bif +++ b/src/event.bif @@ -4713,238 +4713,6 @@ event dhcp_release%(c: connection, msg: dhcp_msg%); ## register a port for it or add a DPD payload signature. event dhcp_inform%(c: connection, msg: dhcp_msg%); -## Generated for HTTP requests. Bro supports persistent and pipelined HTTP -## sessions and raises corresponding events as it parses client/server -## dialogues. This event is generated as soon as a request's initial line has -## been parsed, and before any :bro:id:`http_header` events are raised. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## method: The HTTP method extracted from the request (e.g., ``GET``, ``POST``). -## -## original_URI: The unprocessed URI as specified in the request. -## -## unescaped_URI: The URI with all percent-encodings decoded. -## -## version: The version number specified in the request (e.g., ``1.1``). -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_entity_data http_event http_header http_message_done http_reply http_stats -## truncate_http_URI -event http_request%(c: connection, method: string, original_URI: string, unescaped_URI: string, version: string%) &group="http-request"; - -## Generated for HTTP replies. Bro supports persistent and pipelined HTTP -## sessions and raises corresponding events as it parses client/server -## dialogues. This event is generated as soon as a reply's initial line has -## been parsed, and before any :bro:id:`http_header` events are raised. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## version: The version number specified in the reply (e.g., ``1.1``). -## -## code: The numerical response code returned by the server. -## -## reason: The textual description returned by the server along with *code*. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_entity_data http_event http_header http_message_done http_request -## http_stats -event http_reply%(c: connection, version: string, code: count, reason: string%) &group="http-reply"; - -## Generated for HTTP headers. Bro supports persistent and pipelined HTTP -## sessions and raises corresponding events as it parses client/server -## dialogues. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the header was sent by the originator of the TCP connection. -## -## name: The name of the header. -## -## value: The value of the header. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_entity_data http_event http_message_done http_reply http_request -## http_stats -## -## .. note:: This event is also raised for headers found in nested body -## entities. -event http_header%(c: connection, is_orig: bool, name: string, value: string%) &group="http-header"; - -## Generated for HTTP headers, passing on all headers of an HTTP message at -## once. Bro supports persistent and pipelined HTTP sessions and raises -## corresponding events as it parses client/server dialogues. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the header was sent by the originator of the TCP connection. -## -## hlist: A *table* containing all headers extracted from the current entity. -## The table is indexed by the position of the header (1 for the first, -## 2 for the second, etc.). -## -## .. bro:see:: http_begin_entity http_content_type http_end_entity http_entity_data -## http_event http_header http_message_done http_reply http_request http_stats -## -## .. note:: This event is also raised for headers found in nested body -## entities. -event http_all_headers%(c: connection, is_orig: bool, hlist: mime_header_list%) &group="http-header"; - -## Generated when starting to parse an HTTP body entity. This event is generated -## at least once for each non-empty (client or server) HTTP body; and -## potentially more than once if the body contains further nested MIME -## entities. Bro raises this event just before it starts parsing each entity's -## content. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the entity was sent by the originator of the TCP -## connection. -## -## .. bro:see:: http_all_headers http_content_type http_end_entity http_entity_data -## http_event http_header http_message_done http_reply http_request http_stats -## mime_begin_entity -event http_begin_entity%(c: connection, is_orig: bool%) &group="http-body"; - -## Generated when finishing parsing an HTTP body entity. This event is generated -## at least once for each non-empty (client or server) HTTP body; and -## potentially more than once if the body contains further nested MIME -## entities. Bro raises this event at the point when it has finished parsing an -## entity's content. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the entity was sent by the originator of the TCP -## connection. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_entity_data -## http_event http_header http_message_done http_reply http_request -## http_stats mime_end_entity -event http_end_entity%(c: connection, is_orig: bool%) &group="http-body"; - -## Generated when parsing an HTTP body entity, passing on the data. This event -## can potentially be raised many times for each entity, each time passing a -## chunk of the data of not further defined size. -## -## A common idiom for using this event is to first *reassemble* the data -## at the scripting layer by concatenating it to a successively growing -## string; and only perform further content analysis once the corresponding -## :bro:id:`http_end_entity` event has been raised. Note, however, that doing so -## can be quite expensive for HTTP tranders. At the very least, one should -## impose an upper size limit on how much data is being buffered. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the entity was sent by the originator of the TCP -## connection. -## -## length: The length of *data*. -## -## data: One chunk of raw entity data. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_event http_header http_message_done http_reply http_request http_stats -## mime_entity_data http_entity_data_delivery_size skip_http_data -event http_entity_data%(c: connection, is_orig: bool, length: count, data: string%) &group="http-body"; - -## Generated for reporting an HTTP body's content type. This event is -## generated at the end of parsing an HTTP header, passing on the MIME -## type as specified by the ``Content-Type`` header. If that header is -## missing, this event is still raised with a default value of ``text/plain``. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the entity was sent by the originator of the TCP -## connection. -## -## ty: The main type. -## -## subty: The subtype. -## -## .. bro:see:: http_all_headers http_begin_entity http_end_entity http_entity_data -## http_event http_header http_message_done http_reply http_request http_stats -## -## .. note:: This event is also raised for headers found in nested body -## entities. -event http_content_type%(c: connection, is_orig: bool, ty: string, subty: string%) &group="http-body"; - -## Generated once at the end of parsing an HTTP message. Bro supports persistent -## and pipelined HTTP sessions and raises corresponding events as it parses -## client/server dialogues. A "message" is one top-level HTTP entity, such as a -## complete request or reply. Each message can have further nested sub-entities -## inside. This event is raised once all sub-entities belonging to a top-level -## message have been processed (and their corresponding ``http_entity_*`` events -## generated). -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## is_orig: True if the entity was sent by the originator of the TCP -## connection. -## -## stat: Further meta information about the message. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_entity_data http_event http_header http_reply http_request http_stats -event http_message_done%(c: connection, is_orig: bool, stat: http_message_stat%) &group="http-body"; - -## Generated for errors found when decoding HTTP requests or replies. -## -## See `Wikipedia `__ -## for more information about the HTTP protocol. -## -## c: The connection. -## -## event_type: A string describing the general category of the problem found -## (e.g., ``illegal format``). -## -## detail: Further more detailed description of the error. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_entity_data http_header http_message_done http_reply http_request -## http_stats mime_event -event http_event%(c: connection, event_type: string, detail: string%); - -## Generated at the end of an HTTP session to report statistics about it. This -## event is raised after all of an HTTP session's requests and replies have been -## fully processed. -## -## c: The connection. -## -## stats: Statistics summarizing HTTP-level properties of the finished -## connection. -## -## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity -## http_entity_data http_event http_header http_message_done http_reply -## http_request -event http_stats%(c: connection, stats: http_stats_rec%); - ## Generated when seeing an SSH client's version identification. The SSH ## protocol starts with a clear-text handshake message that reports client and ## server protocol/software versions. This event provides access to what the @@ -4983,202 +4751,6 @@ event ssh_client_version%(c: connection, version: string%); ## encrypted, Bro cannot further analyze SSH sessions. event ssh_server_version%(c: connection, version: string%); -## Generated for an SSL/TLS client's initial *hello* message. SSL/TLS sessions -## start with an unencrypted handshake, and Bro extracts as much information out -## of that as it can. This event provides access to the initial information -## sent by the client. -## -## See `Wikipedia `__ for -## more information about the SSL/TLS protocol. -## -## c: The connection. -## -## version: The protocol version as extracted from the client's message. The -## values are standardized as part of the SSL/TLS protocol. The -## :bro:id:`SSL::version_strings` table maps them to descriptive names. -## -## possible_ts: The current time as sent by the client. Note that SSL/TLS does -## not require clocks to be set correctly, so treat with care. -## -## session_id: The session ID sent by the client (if any). -## -## ciphers: The list of ciphers the client offered to use. The values are -## standardized as part of the SSL/TLS protocol. The -## :bro:id:`SSL::cipher_desc` table maps them to descriptive names. -## -## .. bro:see:: ssl_alert ssl_established ssl_extension ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension -event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%); - -## Generated for an SSL/TLS server's initial *hello* message. SSL/TLS sessions -## start with an unencrypted handshake, and Bro extracts as much information out -## of that as it can. This event provides access to the initial information -## sent by the client. -## -## See `Wikipedia `__ for -## more information about the SSL/TLS protocol. -## -## c: The connection. -## -## version: The protocol version as extracted from the server's message. -## The values are standardized as part of the SSL/TLS protocol. The -## :bro:id:`SSL::version_strings` table maps them to descriptive names. -## -## possible_ts: The current time as sent by the server. Note that SSL/TLS does -## not require clocks to be set correctly, so treat with care. -## -## session_id: The session ID as sent back by the server (if any). -## -## cipher: The cipher chosen by the server. The values are standardized as part -## of the SSL/TLS protocol. The :bro:id:`SSL::cipher_desc` table maps -## them to descriptive names. -## -## comp_method: The compression method chosen by the client. The values are -## standardized as part of the SSL/TLS protocol. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension -event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%); - -## Generated for SSL/TLS extensions seen in an initial handshake. SSL/TLS -## sessions start with an unencrypted handshake, and Bro extracts as much -## information out of that as it can. This event provides access to any -## extensions either side sends as part of an extended *hello* message. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## code: The numerical code of the extension. The values are standardized as -## part of the SSL/TLS protocol. The :bro:id:`SSL::extensions` table maps -## them to descriptive names. -## -## val: The raw extension value that was sent in the message. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension -event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%); - -## Generated at the end of an SSL/TLS handshake. SSL/TLS sessions start with -## an unencrypted handshake, and Bro extracts as much information out of that -## as it can. This event signals the time when an SSL/TLS has finished the -## handshake and its endpoints consider it as fully established. Typically, -## everything from now on will be encrypted. -## -## See `Wikipedia `__ for -## more information about the SSL/TLS protocol. -## -## c: The connection. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_extension ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension -event ssl_established%(c: connection%); - -## Generated for SSL/TLS alert records. SSL/TLS sessions start with an -## unencrypted handshake, and Bro extracts as much information out of that as -## it can. If during that handshake, an endpoint encounters a fatal error, it -## sends an *alert* record, that in turn triggers this event. After an *alert*, -## any endpoint may close the connection immediately. -## -## See `Wikipedia `__ for -## more information about the SSL/TLS protocol. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## level: The severity level, as sent in the *alert*. The values are defined as -## part of the SSL/TLS protocol. -## -## desc: A numerical value identifying the cause of the *alert*. The values are -## defined as part of the SSL/TLS protocol. -## -## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello -## ssl_session_ticket_handshake x509_certificate x509_error x509_extension -event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%); - -## Generated for SSL/TLS handshake messages that are a part of the -## stateless-server session resumption mechanism. SSL/TLS sessions start with -## an unencrypted handshake, and Bro extracts as much information out of that -## as it can. This event is raised when an SSL/TLS server passes a session -## ticket to the client that can later be used for resuming the session. The -## mechanism is described in :rfc:`4507` -## -## See `Wikipedia `__ for -## more information about the SSL/TLS protocol. -## -## c: The connection. -## -## ticket_lifetime_hint: A hint from the server about how long the ticket -## should be stored by the client. -## -## ticket: The raw ticket data. -## -## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello -## x509_certificate x509_error x509_extension ssl_alert -event ssl_session_ticket_handshake%(c: connection, ticket_lifetime_hint: count, ticket: string%); - -## Generated for X509 certificates seen in SSL/TLS connections. During the -## initial SSL/TLS handshake, certificates are exchanged in the clear. Bro -## raises this event for each certificate seen (including both a site's primary -## cert, and further certs sent as part of the validation chain). -## -## See `Wikipedia `__ for more information -## about the X.509 format. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## cert: The parsed certificate. -## -## chain_idx: The index in the validation chain that this cert has. Index zero -## indicates an endpoint's primary cert, while higher indices -## indicate the place in the validation chain (which has length -## *chain_len*). -## -## chain_len: The total length of the validation chain that this cert is part -## of. -## -## der_cert: The complete cert encoded in `DER -## `__ -## format. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_server_hello x509_error x509_extension x509_verify -event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string%); - -## Generated for X509 extensions seen in a certificate. -## -## See `Wikipedia `__ for more information -## about the X.509 format. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## data: The raw data associated with the extension. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_server_hello x509_certificate x509_error x509_verify -event x509_extension%(c: connection, is_orig: bool, data: string%); - -## Generated when errors occur during parsing an X509 certificate. -## -## See `Wikipedia `__ for more information -## about the X.509 format. -## -## c: The connection. -## -## is_orig: True if event is raised for originator side of the connection. -## -## err: An error code describing what went wrong. :bro:id:`SSL::x509_errors` -## maps error codes to a textual description. -## -## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension -## ssl_server_hello x509_certificate x509_extension x509_err2str x509_verify -event x509_error%(c: connection, is_orig: bool, err: count%); - ## TODO. ## ## .. bro:see:: rpc_call rpc_dialogue rpc_reply dce_rpc_bind dce_rpc_request diff --git a/src/main.cc b/src/main.cc index 8bfc9300c4..7a86bde6da 100644 --- a/src/main.cc +++ b/src/main.cc @@ -56,7 +56,6 @@ extern "C" void OPENSSL_add_all_algorithms_conf(void); #include "input/Manager.h" #include "logging/Manager.h" #include "logging/writers/Ascii.h" -#include "analyzer/BuiltInAnalyzers.h" #include "analyzer/Manager.h" #include "analyzer/Tag.h" #include "plugin/Manager.h" @@ -180,7 +179,7 @@ void usage() fprintf(stderr, " -I|--print-id | print out given ID\n"); fprintf(stderr, " -K|--md5-hashkey | set key for MD5-keyed hashing\n"); fprintf(stderr, " -L|--rule-benchmark | benchmark for rules\n"); - fprintf(stderr, " -N|--print-plugins | print all available plugins and exit\n"); + fprintf(stderr, " -N|--print-plugins | print available plugins and exit (-NN for verbose)\n"); fprintf(stderr, " -O|--optimize | optimize policy script\n"); fprintf(stderr, " -P|--prime-dns | prime DNS\n"); fprintf(stderr, " -R|--replay | replay events\n"); @@ -238,7 +237,7 @@ void usage() exit(1); } -void show_plugins() +void show_plugins(int level) { plugin::Manager::plugin_list plugins = plugin_mgr->Plugins(); @@ -250,10 +249,15 @@ void show_plugins() ODesc d; + if ( level == 1 ) + d.SetShort(); + for ( plugin::Manager::plugin_list::const_iterator i = plugins.begin(); i != plugins.end(); i++ ) { (*i)->Describe(&d); - d.NL(); + + if ( ! d.IsShort() ) + d.Add("\n"); } printf("%s", d.Description()); @@ -641,7 +645,7 @@ int main(int argc, char** argv) break; case 'N': - print_plugins = 1; + ++print_plugins; break; case 'O': @@ -785,7 +789,7 @@ int main(int argc, char** argv) if ( optind == argc && read_files.length() == 0 && flow_files.length() == 0 && interfaces.length() == 0 && - ! (id_name || bst_file) && ! command_line_policy ) + ! (id_name || bst_file) && ! command_line_policy && ! print_plugins ) add_input_file("-"); // Process remaining arguments. X=Y arguments indicate script @@ -816,16 +820,8 @@ int main(int argc, char** argv) log_mgr = new logging::Manager(); input_mgr = new input::Manager(); plugin_mgr = new plugin::Manager(); - - plugin_mgr->RegisterPlugin(new analyzer::BuiltinAnalyzers()); plugin_mgr->InitPlugins(); - if ( print_plugins ) - { - show_plugins(); - exit(1); - } - analyzer_mgr->Init(); if ( events_file ) @@ -846,6 +842,14 @@ int main(int argc, char** argv) yyparse(); + plugin_mgr->InitPluginsBif(); + + if ( print_plugins ) + { + show_plugins(print_plugins); + exit(1); + } + #ifdef USE_PERFTOOLS_DEBUG } #endif diff --git a/src/plugin/Component.cc b/src/plugin/Component.cc index c4276ca1ff..ddedf7abbb 100644 --- a/src/plugin/Component.cc +++ b/src/plugin/Component.cc @@ -1,4 +1,3 @@ - #include "Component.h" #include "../Desc.h" diff --git a/src/plugin/Macros.h b/src/plugin/Macros.h new file mode 100644 index 0000000000..f10d6adf45 --- /dev/null +++ b/src/plugin/Macros.h @@ -0,0 +1,42 @@ + +#ifndef PLUGIN_MACROS_H +#define PLUGIN_MACROS_H + +#include "analyzer/PluginComponent.h" + +#define BRO_PLUGIN_VERSION_BUILTIN -1 +#define BRO_PLUGIN_API_VERSION 1 + +#define _BRO_PLUGIN_VERSION_DEFAULT -1 + +#define BRO_PLUGIN_BEGIN(_name) \ + namespace plugin { namespace _name { \ + class Plugin : public plugin::Plugin { \ + protected: \ + void Init() \ + { \ + plugin::Description _desc; \ + _desc.name = #_name; \ + _desc.version = _BRO_PLUGIN_VERSION_DEFAULT; \ + _desc.api_version = BRO_PLUGIN_API_VERSION; + +#define BRO_PLUGIN_END \ + SetDescription(_desc); \ + } \ + }; \ + \ + static Plugin __plugin; \ + } } + +#define BRO_PLUGIN_DESCRIPTION _desc.description +#define BRO_PLUGIN_URL _desc.url +#define BRO_PLUGIN_VERSION _desc.version + +#define BRO_PLUGIN_BIF_FILE(file) \ + std::list > __bif_##file##_init(); \ + AddBifInitFunction(&__bif_##file##_init); + +#define BRO_PLUGIN_ANALYZER(tag, factory, enabled, partial) \ + AddComponent(new ::analyzer::PluginComponent(tag, factory, enabled, partial)); + +#endif diff --git a/src/plugin/Manager.cc b/src/plugin/Manager.cc index 62440c0039..b969e581c7 100644 --- a/src/plugin/Manager.cc +++ b/src/plugin/Manager.cc @@ -31,21 +31,7 @@ bool Manager::LoadPluginsFrom(const std::string& dir) bool Manager::RegisterPlugin(Plugin *plugin) { - assert(! init); - - plugin::Description desc = plugin->GetDescription(); - - if ( desc.version != plugin::API_BUILTIN ) - { - if ( desc.api_version == API_ERROR ) - reporter->InternalError("API version of plugin %s not initialized", desc.name.c_str()); - - if ( desc.api_version != API_VERSION ) - reporter->FatalError("API version mismatch for plugin %s: expected %d, but have %d", - desc.name.c_str(), API_VERSION, desc.version); - } - - plugins.push_back(plugin); + Manager::PluginsInternal()->push_back(plugin); return true; } @@ -53,29 +39,48 @@ void Manager::InitPlugins() { assert(! init); - for ( plugin_list::iterator i = plugins.begin(); i != plugins.end(); i++ ) + for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ ) (*i)->Init(); init = true; } +void Manager::InitPluginsBif() + { + assert(init); + + for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ ) + (*i)->InitBif(); + + init = true; + } + void Manager::FinishPlugins() { assert(init); - for ( plugin_list::iterator i = plugins.begin(); i != plugins.end(); i++ ) + for ( plugin_list::iterator i = Manager::PluginsInternal()->begin(); i != Manager::PluginsInternal()->end(); i++ ) { (*i)->Done(); - delete *i; +// delete *i; } - plugins.clear(); + Manager::PluginsInternal()->clear(); init = false; } Manager::plugin_list Manager::Plugins() const { - return plugins; -} + return *Manager::PluginsInternal(); + } +Manager::plugin_list* Manager::PluginsInternal() + { + static plugin_list* plugins = 0; + + if ( ! plugins ) + plugins = new plugin_list; + + return plugins; + } diff --git a/src/plugin/Manager.h b/src/plugin/Manager.h index 26f07dc944..44ec8913c6 100644 --- a/src/plugin/Manager.h +++ b/src/plugin/Manager.h @@ -29,15 +29,22 @@ public: /** * - * @param plugin: The plugin to register. The method takes ownership. + * @param plugin: The plugin to register. The method does not take + * ownershop but assume the pointer will leave at least until the + * Manager is destroyed. */ - bool RegisterPlugin(Plugin *plugin); // Takes ownership. + static bool RegisterPlugin(Plugin *plugin); /** * */ void InitPlugins(); + /** + * + */ + void InitPluginsBif(); + /** * */ @@ -55,8 +62,9 @@ public: std::list Components(component::Type type) const; private: + static plugin_list* PluginsInternal(); + bool init; - plugin_list plugins; }; template @@ -64,7 +72,7 @@ std::list Manager::Components(component::Type type) const { std::list result; - for ( plugin_list::const_iterator p = plugins.begin(); p != plugins.end(); p++ ) + for ( plugin_list::const_iterator p = PluginsInternal()->begin(); p != PluginsInternal()->end(); p++ ) { component_list components = (*p)->Components(); diff --git a/src/plugin/Plugin.cc b/src/plugin/Plugin.cc index e5a09e0dcc..69377fd97a 100644 --- a/src/plugin/Plugin.cc +++ b/src/plugin/Plugin.cc @@ -2,6 +2,7 @@ #include #include "Plugin.h" +#include "Manager.h" #include "Component.h" #include "../Desc.h" @@ -11,11 +12,15 @@ using namespace plugin; Description::Description() { name = ""; - api_version = API_VERSION; + + // These will be reset by the BRO_PLUGIN_* macros. + version = -9999; + api_version = -9999; } Plugin::Plugin() { + Manager::RegisterPlugin(this); } Description Plugin::GetDescription() const @@ -37,6 +42,27 @@ void Plugin::Init() { } +void Plugin::InitBif() + { + for ( bif_init_func_list::const_iterator f = bif_inits.begin(); f != bif_inits.end(); f++ ) + { + bif_init_func_result items = (**f)(); + + for ( bif_init_func_result::const_iterator i = items.begin(); i != items.end(); i++ ) + { + BifItem bi; + bi.id = (*i).first; + bi.type = (BifItem::Type)(*i).second; + bif_items.push_back(bi); + } + } + } + +const Plugin::bif_item_list& Plugin::BifItems() + { + return bif_items; + } + void Plugin::Done() { for ( component_list::const_iterator i = components.begin(); i != components.end(); i++ ) @@ -55,6 +81,11 @@ void Plugin::AddComponent(Component* c) components.push_back(c); } +void Plugin::AddBifInitFunction(bif_init_func c) + { + bif_inits.push_back(c); + } + void Plugin::Describe(ODesc* d) { d->Add("Plugin: "); @@ -66,7 +97,7 @@ void Plugin::Describe(ODesc* d) d->Add(description.description); } - if ( description.version != API_BUILTIN ) + if ( description.version != BRO_PLUGIN_VERSION_BUILTIN ) { d->Add(" (version "); d->Add(description.version); @@ -83,12 +114,53 @@ void Plugin::Describe(ODesc* d) else d->Add(" (built-in)"); - d->NL(); + d->Add("\n"); + + if ( d->IsShort() ) + return; for ( component_list::const_iterator i = components.begin(); i != components.end(); i++ ) { (*i)->Describe(d); - d->NL(); + d->Add("\n"); + } + + for ( bif_item_list::const_iterator i = bif_items.begin(); i != bif_items.end(); i++ ) + { + const char* type = 0; + + switch ( (*i).type ) { + case BifItem::FUNCTION: + type = "Function"; + break; + + case BifItem::EVENT: + type = "Event"; + break; + + case BifItem::CONSTANT: + type = "Constant"; + break; + + case BifItem::GLOBAL: + type = "Global"; + break; + + case BifItem::TYPE: + type = "Type"; + break; + + default: + type = ""; + } + + d->Add(" "); + d->Add("["); + d->Add(type); + d->Add("] "); + d->Add((*i).id); + d->Add("\n"); } } + diff --git a/src/plugin/Plugin.h b/src/plugin/Plugin.h index f62b81772f..314de47083 100644 --- a/src/plugin/Plugin.h +++ b/src/plugin/Plugin.h @@ -5,6 +5,8 @@ #include #include +#include "Macros.h" + class ODesc; namespace plugin { @@ -12,10 +14,6 @@ namespace plugin { class Manager; class Component; -static const int API_VERSION = 1; -static const int API_BUILTIN = -1; -static const int API_ERROR = -2; - struct Description { std::string name; std::string description; @@ -27,9 +25,18 @@ struct Description { void Describe(ODesc* d); }; +struct BifItem { + // Values must match the integers bifcl generates. + enum Type { FUNCTION = 1, EVENT = 2, CONSTANT = 3, GLOBAL = 4, TYPE = 5 }; + + std::string id; + Type type; +}; + class Plugin { public: typedef std::list component_list; + typedef std::list bif_item_list; Plugin(); virtual ~Plugin(); @@ -39,6 +46,11 @@ public: component_list Components(); + void InitBif(); + + // Must be called after InitBif() only. + const bif_item_list& BifItems(); + virtual void Init(); virtual void Done(); @@ -50,9 +62,17 @@ protected: */ void AddComponent(Component* c); + typedef std::list > bif_init_func_result; + typedef bif_init_func_result (*bif_init_func)(); + void AddBifInitFunction(bif_init_func c); + private: + typedef std::list bif_init_func_list; + plugin::Description description; component_list components; + bif_item_list bif_items; + bif_init_func_list bif_inits; }; } diff --git a/src/analyzer/BuiltInAnalyzers.cc b/src/protocols/BuiltInAnalyzers.cc similarity index 91% rename from src/analyzer/BuiltInAnalyzers.cc rename to src/protocols/BuiltInAnalyzers.cc index e65dbdb62e..0c96ab17e4 100644 --- a/src/analyzer/BuiltInAnalyzers.cc +++ b/src/protocols/BuiltInAnalyzers.cc @@ -1,6 +1,9 @@ +// TODO: This file will eventually go away once we've converrted all +// analyzers into separate plugins. + #include "BuiltInAnalyzers.h" -#include "PluginComponent.h" +#include "analyzer/PluginComponent.h" #include "../binpac_bro.h" @@ -11,8 +14,6 @@ #include "Finger.h" #include "InterConn.h" #include "NTP.h" -#include "HTTP.h" -#include "HTTP-binpac.h" #include "ICMP.h" #include "SteppingStone.h" #include "IRC.h" @@ -37,7 +38,6 @@ #include "POP3.h" #include "SOCKS.h" #include "SSH.h" -#include "SSL.h" #include "Syslog-binpac.h" #include "Teredo.h" #include "ConnSizeAnalyzer.h" @@ -45,6 +45,8 @@ using namespace analyzer; +BuiltinAnalyzers builtin_analyzers; + #define DEFINE_ANALYZER(name, factory, enabled, partial) \ AddComponent(new PluginComponent(name, factory, enabled, partial)) @@ -53,7 +55,7 @@ void BuiltinAnalyzers::Init() plugin::Description desc; desc.name = "Core-Analyzers"; desc.description = "Built-in protocol analyzers"; - desc.version = plugin::API_BUILTIN; + desc.version = BRO_PLUGIN_VERSION_BUILTIN; SetDescription(desc); DEFINE_ANALYZER("PIA_TCP", PIA_TCP::InstantiateAnalyzer, true, false); @@ -71,7 +73,7 @@ void BuiltinAnalyzers::Init() DEFINE_ANALYZER("FINGER", Finger_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("FTP", FTP_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("GNUTELLA", Gnutella_Analyzer::InstantiateAnalyzer, true, false); - DEFINE_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer, ! FLAGS_use_binpac, false); + // DEFINE_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer, ! FLAGS_use_binpac, false); DEFINE_ANALYZER("IDENT", Ident_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("IRC", IRC_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("LOGIN", 0, true, false); // just a base class @@ -92,8 +94,8 @@ void BuiltinAnalyzers::Init() DEFINE_ANALYZER("DHCP_BINPAC", DHCP_Analyzer_binpac::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("DNS_TCP_BINPAC", DNS_TCP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); DEFINE_ANALYZER("DNS_UDP_BINPAC", DNS_UDP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); - DEFINE_ANALYZER("HTTP_BINPAC", HTTP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); - DEFINE_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer, true, false); + // DEFINE_ANALYZER("HTTP_BINPAC", HTTP_Analyzer_binpac::InstantiateAnalyzer, FLAGS_use_binpac, false); + // DEFINE_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("SYSLOG_BINPAC", Syslog_Analyzer_binpac::InstantiateAnalyzer, true, false); DEFINE_ANALYZER("MODBUS", ModbusTCP_Analyzer::InstantiateAnalyzer, true, false); diff --git a/src/analyzer/BuiltInAnalyzers.h b/src/protocols/BuiltInAnalyzers.h similarity index 100% rename from src/analyzer/BuiltInAnalyzers.h rename to src/protocols/BuiltInAnalyzers.h diff --git a/src/protocols/CMakeLists.txt b/src/protocols/CMakeLists.txt new file mode 100644 index 0000000000..35db6549fa --- /dev/null +++ b/src/protocols/CMakeLists.txt @@ -0,0 +1,3 @@ + +add_subdirectory(http) +add_subdirectory(ssl) diff --git a/src/protocols/http/CMakeLists.txt b/src/protocols/http/CMakeLists.txt new file mode 100644 index 0000000000..b6d877cdd7 --- /dev/null +++ b/src/protocols/http/CMakeLists.txt @@ -0,0 +1,11 @@ + +include(BroPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +bro_plugin_begin(HTTP) +bro_plugin_cc(HTTP.cc) +bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) +bro_plugin_end() + diff --git a/src/HTTP.cc b/src/protocols/http/HTTP.cc similarity index 99% rename from src/HTTP.cc rename to src/protocols/http/HTTP.cc index 5b49f8844e..2812f3662b 100644 --- a/src/HTTP.cc +++ b/src/protocols/http/HTTP.cc @@ -13,6 +13,15 @@ #include "Event.h" #include "MIME.h" +#include "plugin/Plugin.h" + +BRO_PLUGIN_BEGIN(HTTP) + BRO_PLUGIN_DESCRIPTION = "HTTP Analyzer"; + BRO_PLUGIN_ANALYZER("HTTP", HTTP_Analyzer::InstantiateAnalyzer, true, false); + BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); +BRO_PLUGIN_END + const bool DEBUG_http = false; // The EXPECT_*_NOTHING states are used to prevent further parsing. Used if a diff --git a/src/HTTP.h b/src/protocols/http/HTTP.h similarity index 99% rename from src/HTTP.h rename to src/protocols/http/HTTP.h index e8746e9d52..6cb2199696 100644 --- a/src/HTTP.h +++ b/src/protocols/http/HTTP.h @@ -9,6 +9,8 @@ #include "binpac_bro.h" #include "ZIP.h" #include "IPAddr.h" +#include "HTTP.h" +#include "events.bif.h" enum CHUNKED_TRANSFER_STATE { NON_CHUNKED_TRANSFER, diff --git a/src/protocols/http/events.bif b/src/protocols/http/events.bif new file mode 100644 index 0000000000..e4f71f70fc --- /dev/null +++ b/src/protocols/http/events.bif @@ -0,0 +1,232 @@ + +## Generated for HTTP requests. Bro supports persistent and pipelined HTTP +## sessions and raises corresponding events as it parses client/server +## dialogues. This event is generated as soon as a request's initial line has +## been parsed, and before any :bro:id:`http_header` events are raised. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## method: The HTTP method extracted from the request (e.g., ``GET``, ``POST``). +## +## original_URI: The unprocessed URI as specified in the request. +## +## unescaped_URI: The URI with all percent-encodings decoded. +## +## version: The version number specified in the request (e.g., ``1.1``). +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_entity_data http_event http_header http_message_done ply http_stats +## truncate_http_URI +event http_request%(c: connection, method: string, original_URI: string, unescaped_URI: string, version: string%) &group="http-request"; + +## Generated for HTTP replies. Bro supports persistent and pipelined HTTP +## sessions and raises corresponding events as it parses client/server +## dialogues. This event is generated as soon as a reply's initial line has +## been parsed, and before any :bro:id:`http_header` events are raised. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## version: The version number specified in the reply (e.g., ``1.1``). +## +## code: The numerical response code returned by the server. +## +## reason: The textual description returned by the server along with *code*. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_entity_data http_event http_header http_message_done http_request +## http_stats +event http_reply%(c: connection, version: string, code: count, reason: string%) &group="http-reply"; + +## Generated for HTTP headers. Bro supports persistent and pipelined HTTP +## sessions and raises corresponding events as it parses client/server +## dialogues. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the header was sent by the originator of the TCP connection. +## +## name: The name of the header. +## +## value: The value of the header. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_entity_data http_event http_message_done http_reply http_request +## http_stats +## +## .. note:: This event is also raised for headers found in nested body +## entities. +event http_header%(c: connection, is_orig: bool, name: string, value: string%) &group="http-header"; + +## Generated for HTTP headers, passing on all headers of an HTTP message at +## once. Bro supports persistent and pipelined HTTP sessions and raises +## corresponding events as it parses client/server dialogues. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the header was sent by the originator of the TCP connection. +## +## hlist: A *table* containing all headers extracted from the current entity. +## The table is indexed by the position of the header (1 for the first, +## 2 for the second, etc.). +## +## .. bro:see:: http_begin_entity http_content_type http_end_entity http_entity_data +## http_event http_header http_message_done http_reply http_request http_stats +## +## .. note:: This event is also raised for headers found in nested body +## entities. +event http_all_headers%(c: connection, is_orig: bool, hlist: mime_header_list%) &group="http-header"; + +## Generated when starting to parse an HTTP body entity. This event is generated +## at least once for each non-empty (client or server) HTTP body; and +## potentially more than once if the body contains further nested MIME +## entities. Bro raises this event just before it starts parsing each entity's +## content. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the entity was sent by the originator of the TCP +## connection. +## +## .. bro:see:: http_all_headers http_content_type http_end_entity http_entity_data +## http_event http_header http_message_done http_reply http_request http_stats +## mime_begin_entity +event http_begin_entity%(c: connection, is_orig: bool%) &group="http-body"; + +## Generated when finishing parsing an HTTP body entity. This event is generated +## at least once for each non-empty (client or server) HTTP body; and +## potentially more than once if the body contains further nested MIME +## entities. Bro raises this event at the point when it has finished parsing an +## entity's content. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the entity was sent by the originator of the TCP +## connection. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_entity_data +## http_event http_header http_message_done http_reply http_request +## http_stats mime_end_entity +event http_end_entity%(c: connection, is_orig: bool%) &group="http-body"; + +## Generated when parsing an HTTP body entity, passing on the data. This event +## can potentially be raised many times for each entity, each time passing a +## chunk of the data of not further defined size. +## +## A common idiom for using this event is to first *reassemble* the data +## at the scripting layer by concatenating it to a successively growing +## string; and only perform further content analysis once the corresponding +## :bro:id:`http_end_entity` event has been raised. Note, however, that doing so +## can be quite expensive for HTTP tranders. At the very least, one should +## impose an upper size limit on how much data is being buffered. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the entity was sent by the originator of the TCP +## connection. +## +## length: The length of *data*. +## +## data: One chunk of raw entity data. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_event http_header http_message_done http_reply http_request http_stats +## mime_entity_data http_entity_data_delivery_size skip_http_data +event http_entity_data%(c: connection, is_orig: bool, length: count, data: string%) &group="http-body"; + +## Generated for reporting an HTTP body's content type. This event is +## generated at the end of parsing an HTTP header, passing on the MIME +## type as specified by the ``Content-Type`` header. If that header is +## missing, this event is still raised with a default value of ``text/plain``. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the entity was sent by the originator of the TCP +## connection. +## +## ty: The main type. +## +## subty: The subtype. +## +## .. bro:see:: http_all_headers http_begin_entity http_end_entity http_entity_data +## http_event http_header http_message_done http_reply http_request http_stats +## +## .. note:: This event is also raised for headers found in nested body +## entities. +event http_content_type%(c: connection, is_orig: bool, ty: string, subty: string%) &group="http-body"; + +## Generated once at the end of parsing an HTTP message. Bro supports persistent +## and pipelined HTTP sessions and raises corresponding events as it parses +## client/server dialogues. A "message" is one top-level HTTP entity, such as a +## complete request or reply. Each message can have further nested sub-entities +## inside. This event is raised once all sub-entities belonging to a top-level +## message have been processed (and their corresponding ``http_entity_*`` events +## generated). +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## is_orig: True if the entity was sent by the originator of the TCP +## connection. +## +## stat: Further meta information about the message. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_entity_data http_event http_header http_reply http_request http_stats +event http_message_done%(c: connection, is_orig: bool, stat: http_message_stat%) &group="http-body"; + +## Generated for errors found when decoding HTTP requests or replies. +## +## See `Wikipedia `__ +## for more information about the HTTP protocol. +## +## c: The connection. +## +## event_type: A string describing the general category of the problem found +## (e.g., ``illegal format``). +## +## detail: Further more detailed description of the error. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_entity_data http_header http_message_done http_reply http_request +## http_stats mime_event +event http_event%(c: connection, event_type: string, detail: string%); + +## Generated at the end of an HTTP session to report statistics about it. This +## event is raised after all of an HTTP session's requests and replies have been +## fully processed. +## +## c: The connection. +## +## stats: Statistics summarizing HTTP-level properties of the finished +## connection. +## +## .. bro:see:: http_all_headers http_begin_entity http_content_type http_end_entity +## http_entity_data http_event http_header http_message_done http_reply +## http_request +event http_stats%(c: connection, stats: http_stats_rec%); diff --git a/src/protocols/http/functions.bif b/src/protocols/http/functions.bif new file mode 100644 index 0000000000..0e1c63f721 --- /dev/null +++ b/src/protocols/http/functions.bif @@ -0,0 +1,56 @@ + +%%{ +#include "protocols/http/HTTP.h" +%%} + +## Skips the data of the HTTP entity. +## +## c: The HTTP connection. +## +## is_orig: If true, the client data is skipped, and the server data otherwise. +## +## .. bro:see:: skip_smtp_data +function skip_http_entity_data%(c: connection, is_orig: bool%): any + %{ + analyzer::ID id = mgr.CurrentAnalyzer(); + if ( id ) + { + analyzer::Analyzer* ha = c->FindAnalyzer(id); + + if ( ha ) + { + if ( ha->IsAnalyzer("HTTP") ) + static_cast(ha)->SkipEntityData(is_orig); + else + reporter->Error("non-HTTP analyzer associated with connection record"); + } + else + reporter->Error("could not find analyzer for skip_http_entity_data"); + + } + else + reporter->Error("no analyzer associated with connection record"); + + return 0; + %} + +## Unescapes all characters in a URI (decode every ``%xx`` group). +## +## URI: The URI to unescape. +## +## Returns: The unescaped URI with all ``%xx`` groups decoded. +## +## .. note:: +## +## Unescaping reserved characters may cause loss of information. RFC 2396: +## A URI is always in an "escaped" form, since escaping or unescaping a +## completed URI might change its semantics. Normally, the only time +## escape encodings can safely be made is when the URI is being created +## from its component parts. +function unescape_URI%(URI: string%): string + %{ + const u_char* line = URI->Bytes(); + const u_char* const line_end = line + URI->Len(); + + return new StringVal(unescape_URI(line, line_end, 0)); + %} diff --git a/src/protocols/ssl/CMakeLists.txt b/src/protocols/ssl/CMakeLists.txt new file mode 100644 index 0000000000..9ee8fd9b1e --- /dev/null +++ b/src/protocols/ssl/CMakeLists.txt @@ -0,0 +1,10 @@ + +include(BroPlugin) + +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + +bro_plugin_begin(SSL) +bro_plugin_cc(SSL.cc Plugin.cc) +bro_plugin_bif(events.bif) +bro_plugin_pac(ssl.pac ssl-analyzer.pac ssl-protocol.pac ssl-defs.pac) +bro_plugin_end() diff --git a/src/protocols/ssl/Plugin.cc b/src/protocols/ssl/Plugin.cc new file mode 100644 index 0000000000..3e42ae0c32 --- /dev/null +++ b/src/protocols/ssl/Plugin.cc @@ -0,0 +1,10 @@ + +#include "plugin/Plugin.h" + +#include "SSL.h" + +BRO_PLUGIN_BEGIN(SSL) + BRO_PLUGIN_DESCRIPTION = "SSL Analyzer"; + BRO_PLUGIN_ANALYZER("SSL", SSL_Analyzer::InstantiateAnalyzer, true, false); + BRO_PLUGIN_BIF_FILE(events); +BRO_PLUGIN_END diff --git a/src/SSL.cc b/src/protocols/ssl/SSL.cc similarity index 99% rename from src/SSL.cc rename to src/protocols/ssl/SSL.cc index 7dd2e0525a..da3e1e55f3 100644 --- a/src/SSL.cc +++ b/src/protocols/ssl/SSL.cc @@ -1,3 +1,4 @@ + #include "SSL.h" #include "TCP_Reassembler.h" #include "Reporter.h" diff --git a/src/SSL.h b/src/protocols/ssl/SSL.h similarity index 97% rename from src/SSL.h rename to src/protocols/ssl/SSL.h index ee2148450f..cf6269a6e4 100644 --- a/src/SSL.h +++ b/src/protocols/ssl/SSL.h @@ -1,6 +1,8 @@ #ifndef ssl_h #define ssl_h +#include "events.bif.h" + #include "TCP.h" #include "ssl_pac.h" diff --git a/src/protocols/ssl/events.bif b/src/protocols/ssl/events.bif new file mode 100644 index 0000000000..3d0c7e9d6a --- /dev/null +++ b/src/protocols/ssl/events.bif @@ -0,0 +1,195 @@ +## Generated for an SSL/TLS client's initial *hello* message. SSL/TLS sessions +## start with an unencrypted handshake, and Bro extracts as much information out +## of that as it can. This event provides access to the initial information +## sent by the client. +## +## See `Wikipedia `__ for +## more information about the SSL/TLS protocol. +## +## c: The connection. +## +## version: The protocol version as extracted from the client's message. The +## values are standardized as part of the SSL/TLS protocol. The +## :bro:id:`SSL::version_strings` table maps them to descriptive names. +## +## possible_ts: The current time as sent by the client. Note that SSL/TLS does +## not require clocks to be set correctly, so treat with care. +## +## session_id: The session ID sent by the client (if any). +## +## ciphers: The list of ciphers the client offered to use. The values are +## standardized as part of the SSL/TLS protocol. The +## :bro:id:`SSL::cipher_desc` table maps them to descriptive names. +## +## .. bro:see:: ssl_alert ssl_established ssl_extension ssl_server_hello +## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +event ssl_client_hello%(c: connection, version: count, possible_ts: time, session_id: string, ciphers: count_set%); + +## Generated for an SSL/TLS server's initial *hello* message. SSL/TLS sessions +## start with an unencrypted handshake, and Bro extracts as much information out +## of that as it can. This event provides access to the initial information +## sent by the client. +## +## See `Wikipedia `__ for +## more information about the SSL/TLS protocol. +## +## c: The connection. +## +## version: The protocol version as extracted from the server's message. +## The values are standardized as part of the SSL/TLS protocol. The +## :bro:id:`SSL::version_strings` table maps them to descriptive names. +## +## possible_ts: The current time as sent by the server. Note that SSL/TLS does +## not require clocks to be set correctly, so treat with care. +## +## session_id: The session ID as sent back by the server (if any). +## +## cipher: The cipher chosen by the server. The values are standardized as part +## of the SSL/TLS protocol. The :bro:id:`SSL::cipher_desc` table maps +## them to descriptive names. +## +## comp_method: The compression method chosen by the client. The values are +## standardized as part of the SSL/TLS protocol. +## +## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension +## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +event ssl_server_hello%(c: connection, version: count, possible_ts: time, session_id: string, cipher: count, comp_method: count%); + +## Generated for SSL/TLS extensions seen in an initial handshake. SSL/TLS +## sessions start with an unencrypted handshake, and Bro extracts as much +## information out of that as it can. This event provides access to any +## extensions either side sends as part of an extended *hello* message. +## +## c: The connection. +## +## is_orig: True if event is raised for originator side of the connection. +## +## code: The numerical code of the extension. The values are standardized as +## part of the SSL/TLS protocol. The :bro:id:`SSL::extensions` table maps +## them to descriptive names. +## +## val: The raw extension value that was sent in the message. +## +## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_server_hello +## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +event ssl_extension%(c: connection, is_orig: bool, code: count, val: string%); + +## Generated at the end of an SSL/TLS handshake. SSL/TLS sessions start with +## an unencrypted handshake, and Bro extracts as much information out of that +## as it can. This event signals the time when an SSL/TLS has finished the +## handshake and its endpoints consider it as fully established. Typically, +## everything from now on will be encrypted. +## +## See `Wikipedia `__ for +## more information about the SSL/TLS protocol. +## +## c: The connection. +## +## .. bro:see:: ssl_alert ssl_client_hello ssl_extension ssl_server_hello +## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +event ssl_established%(c: connection%); + +## Generated for SSL/TLS alert records. SSL/TLS sessions start with an +## unencrypted handshake, and Bro extracts as much information out of that as +## it can. If during that handshake, an endpoint encounters a fatal error, it +## sends an *alert* record, that in turn triggers this event. After an *alert*, +## any endpoint may close the connection immediately. +## +## See `Wikipedia `__ for +## more information about the SSL/TLS protocol. +## +## c: The connection. +## +## is_orig: True if event is raised for originator side of the connection. +## +## level: The severity level, as sent in the *alert*. The values are defined as +## part of the SSL/TLS protocol. +## +## desc: A numerical value identifying the cause of the *alert*. The values are +## defined as part of the SSL/TLS protocol. +## +## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello +## ssl_session_ticket_handshake x509_certificate x509_error x509_extension +event ssl_alert%(c: connection, is_orig: bool, level: count, desc: count%); + +## Generated for SSL/TLS handshake messages that are a part of the +## stateless-server session resumption mechanism. SSL/TLS sessions start with +## an unencrypted handshake, and Bro extracts as much information out of that +## as it can. This event is raised when an SSL/TLS server passes a session +## ticket to the client that can later be used for resuming the session. The +## mechanism is described in :rfc:`4507` +## +## See `Wikipedia `__ for +## more information about the SSL/TLS protocol. +## +## c: The connection. +## +## ticket_lifetime_hint: A hint from the server about how long the ticket +## should be stored by the client. +## +## ticket: The raw ticket data. +## +## .. bro:see:: ssl_client_hello ssl_established ssl_extension ssl_server_hello +## x509_certificate x509_error x509_extension ssl_alert +event ssl_session_ticket_handshake%(c: connection, ticket_lifetime_hint: count, ticket: string%); + +## Generated for X509 certificates seen in SSL/TLS connections. During the +## initial SSL/TLS handshake, certificates are exchanged in the clear. Bro +## raises this event for each certificate seen (including both a site's primary +## cert, and further certs sent as part of the validation chain). +## +## See `Wikipedia `__ for more information +## about the X.509 format. +## +## c: The connection. +## +## is_orig: True if event is raised for originator side of the connection. +## +## cert: The parsed certificate. +## +## chain_idx: The index in the validation chain that this cert has. Index zero +## indicates an endpoint's primary cert, while higher indices +## indicate the place in the validation chain (which has length +## *chain_len*). +## +## chain_len: The total length of the validation chain that this cert is part +## of. +## +## der_cert: The complete cert encoded in `DER +## `__ +## format. +## +## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension +## ssl_server_hello x509_error x509_extension x509_verify +event x509_certificate%(c: connection, is_orig: bool, cert: X509, chain_idx: count, chain_len: count, der_cert: string%); + +## Generated for X509 extensions seen in a certificate. +## +## See `Wikipedia `__ for more information +## about the X.509 format. +## +## c: The connection. +## +## is_orig: True if event is raised for originator side of the connection. +## +## data: The raw data associated with the extension. +## +## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension +## ssl_server_hello x509_certificate x509_error x509_verify +event x509_extension%(c: connection, is_orig: bool, data: string%); + +## Generated when errors occur during parsing an X509 certificate. +## +## See `Wikipedia `__ for more information +## about the X.509 format. +## +## c: The connection. +## +## is_orig: True if event is raised for originator side of the connection. +## +## err: An error code describing what went wrong. :bro:id:`SSL::x509_errors` +## maps error codes to a textual description. +## +## .. bro:see:: ssl_alert ssl_client_hello ssl_established ssl_extension +## ssl_server_hello x509_certificate x509_extension x509_err2str x509_verify +event x509_error%(c: connection, is_orig: bool, err: count%); diff --git a/src/ssl-analyzer.pac b/src/protocols/ssl/ssl-analyzer.pac similarity index 100% rename from src/ssl-analyzer.pac rename to src/protocols/ssl/ssl-analyzer.pac diff --git a/src/ssl-defs.pac b/src/protocols/ssl/ssl-defs.pac similarity index 100% rename from src/ssl-defs.pac rename to src/protocols/ssl/ssl-defs.pac diff --git a/src/ssl-protocol.pac b/src/protocols/ssl/ssl-protocol.pac similarity index 100% rename from src/ssl-protocol.pac rename to src/protocols/ssl/ssl-protocol.pac diff --git a/src/ssl.pac b/src/protocols/ssl/ssl.pac similarity index 94% rename from src/ssl.pac rename to src/protocols/ssl/ssl.pac index 25aed7a66f..150dc222cb 100644 --- a/src/ssl.pac +++ b/src/protocols/ssl/ssl.pac @@ -5,6 +5,10 @@ # - ssl-analyzer.pac: contains the SSL analyzer code # - ssl-record-layer.pac: describes the SSL record layer +%extern{ + #include "events.bif.h" +%} + %include binpac.pac %include bro.pac diff --git a/src/HTTP-binpac.cc b/src/protocols/unused/HTTP-binpac.cc similarity index 100% rename from src/HTTP-binpac.cc rename to src/protocols/unused/HTTP-binpac.cc diff --git a/src/HTTP-binpac.h b/src/protocols/unused/HTTP-binpac.h similarity index 100% rename from src/HTTP-binpac.h rename to src/protocols/unused/HTTP-binpac.h