diff --git a/src/Func.cc b/src/Func.cc index 82cd1998ce..668499d2ed 100644 --- a/src/Func.cc +++ b/src/Func.cc @@ -562,7 +562,6 @@ void builtin_error(const char* msg, BroObj* arg) void init_builtin_funcs() { - ftp_port = internal_type("ftp_port")->AsRecordType(); bro_resources = internal_type("bro_resources")->AsRecordType(); net_stats = internal_type("NetStats")->AsRecordType(); matcher_stats = internal_type("matcher_stats")->AsRecordType(); diff --git a/src/analyzer/protocols/ftp/CMakeLists.txt b/src/analyzer/protocols/ftp/CMakeLists.txt index b8b2e1bb3e..9a92d95116 100644 --- a/src/analyzer/protocols/ftp/CMakeLists.txt +++ b/src/analyzer/protocols/ftp/CMakeLists.txt @@ -6,4 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(FTP) bro_plugin_cc(FTP.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_end() diff --git a/src/analyzer/protocols/ftp/Plugin.cc b/src/analyzer/protocols/ftp/Plugin.cc index 9a58990a63..d6bc3313e6 100644 --- a/src/analyzer/protocols/ftp/Plugin.cc +++ b/src/analyzer/protocols/ftp/Plugin.cc @@ -8,4 +8,5 @@ BRO_PLUGIN_BEGIN(FTP) BRO_PLUGIN_ANALYZER("FTP", ftp::FTP_Analyzer); BRO_PLUGIN_SUPPORT_ANALYZER("FTP_ADAT"); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/ftp/functions.bif b/src/analyzer/protocols/ftp/functions.bif new file mode 100644 index 0000000000..a667d8ca88 --- /dev/null +++ b/src/analyzer/protocols/ftp/functions.bif @@ -0,0 +1,220 @@ + +type ftp_port: record; + +%%{ + +static Val* parse_port(const char* line) + { + RecordVal* r = new RecordVal(BifType::Record::ftp_port); + + int bytes[6]; + if ( line && sscanf(line, "%d,%d,%d,%d,%d,%d", + &bytes[0], &bytes[1], &bytes[2], + &bytes[3], &bytes[4], &bytes[5]) == 6 ) + { + int good = 1; + + for ( int i = 0; i < 6; ++i ) + if ( bytes[i] < 0 || bytes[i] > 255 ) + { + good = 0; + break; + } + + uint32 addr = (bytes[0] << 24) | (bytes[1] << 16) | + (bytes[2] << 8) | bytes[3]; + uint32 port = (bytes[4] << 8) | bytes[5]; + + // Since port is unsigned, no need to check for < 0. + if ( port > 65535 ) + { + port = 0; + good = 0; + } + + r->Assign(0, new AddrVal(htonl(addr))); + r->Assign(1, new PortVal(port, TRANSPORT_TCP)); + r->Assign(2, new Val(good, TYPE_BOOL)); + } + else + { + r->Assign(0, new AddrVal(uint32(0))); + r->Assign(1, new PortVal(0, TRANSPORT_TCP)); + r->Assign(2, new Val(0, TYPE_BOOL)); + } + + return r; + } + +static Val* parse_eftp(const char* line) + { + RecordVal* r = new RecordVal(BifType::Record::ftp_port); + + int net_proto = 0; // currently not used + IPAddr addr; // unspecified IPv6 address (all 128 bits zero) + int port = 0; + int good = 0; + + if ( line ) + { + while ( isspace(*line) ) // skip whitespace + ++line; + + char delimiter = *line; + char* next_delim; + + if ( *line ) + { + good = 1; + ++line; // skip delimiter + + net_proto = strtol(line, &next_delim, 10); + if ( *next_delim != delimiter ) + good = 0; + + line = next_delim; + if ( *line ) + ++line; + + if ( *line && *line != delimiter ) + { + const char* nptr = strchr(line, delimiter); + if ( nptr == NULL ) + { + nptr = line + strlen(line); + good = 0; + } + + string s(line, nptr-line); // extract IP address + IPAddr tmp(s); + // on error, "tmp" will have all 128 bits zero + if ( tmp == addr ) + good = 0; + + addr = tmp; + } + + line = strchr(line, delimiter); + + if ( line != NULL ) + { + ++line; // now the port + port = strtol(line, &next_delim, 10); + if ( *next_delim != delimiter ) + good = 0; + } + + } + + } + + r->Assign(0, new AddrVal(addr)); + r->Assign(1, new PortVal(port, TRANSPORT_TCP)); + r->Assign(2, new Val(good, TYPE_BOOL)); + + return r; + } +%%} + +## Converts a string representation of the FTP PORT command to an ``ftp_port``. +## +## s: The string of the FTP PORT command, e.g., ``"10,0,0,1,4,31"``. +## +## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` +## +## .. bro:see:: parse_eftp_port parse_ftp_pasv parse_ftp_epsv fmt_ftp_port +function parse_ftp_port%(s: string%): ftp_port + %{ + return parse_port(s->CheckString()); + %} + +## Converts a string representation of the FTP EPRT command to an ``ftp_port``. +## See `RFC 2428 `_. +## The format is ``EPRT``, +## where ```` is a delimiter in the ASCII range 33-126 (usually ``|``). +## +## s: The string of the FTP EPRT command, e.g., ``"|1|10.0.0.1|1055|"``. +## +## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` +## +## .. bro:see:: parse_ftp_port parse_ftp_pasv parse_ftp_epsv fmt_ftp_port +function parse_eftp_port%(s: string%): ftp_port + %{ + return parse_eftp(s->CheckString()); + %} + +## Converts the result of the FTP PASV command to an ``ftp_port``. +## +## str: The string containing the result of the FTP PASV command. +## +## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` +## +## .. bro:see:: parse_ftp_port parse_eftp_port parse_ftp_epsv fmt_ftp_port +function parse_ftp_pasv%(str: string%): ftp_port + %{ + const char* s = str->CheckString(); + const char* line = strchr(s, '('); + if ( line ) + ++line; // move past '(' + else if ( (line = strstr(s, "PORT")) ) + line += 5; // Skip over + else if ( (line = strchr(s, ',')) ) + { // Look for comma-separated list. + while ( --line >= s && isdigit(*line) ) + ; // Back up over preceding digits. + ++line; // now points to first digit, or beginning of s + } + + return parse_port(line); + %} + +## Converts the result of the FTP EPSV command to an ``ftp_port``. +## See `RFC 2428 `_. +## The format is `` ()``, where ```` is a +## delimiter in the ASCII range 33-126 (usually ``|``). +## +## str: The string containing the result of the FTP EPSV command. +## +## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` +## +## .. bro:see:: parse_ftp_port parse_eftp_port parse_ftp_pasv fmt_ftp_port +function parse_ftp_epsv%(str: string%): ftp_port + %{ + const char* s = str->CheckString(); + const char* line = strchr(s, '('); + if ( line ) + ++line; // move past '(' + return parse_eftp(line); + %} + +## Formats an IP address and TCP port as an FTP PORT command. For example, +## ``10.0.0.1`` and ``1055/tcp`` yields ``"10,0,0,1,4,31"``. +## +## a: The IP address. +## +## p: The TCP port. +## +## Returns: The FTP PORT string. +## +## .. bro:see:: parse_ftp_port parse_eftp_port parse_ftp_pasv parse_ftp_epsv +function fmt_ftp_port%(a: addr, p: port%): string + %{ + const uint32* addr; + int len = a->AsAddr().GetBytes(&addr); + if ( len == 1 ) + { + uint32 a = ntohl(addr[0]); + uint32 pn = p->Port(); + return new StringVal(fmt("%d,%d,%d,%d,%d,%d", + a >> 24, (a >> 16) & 0xff, + (a >> 8) & 0xff, a & 0xff, + pn >> 8, pn & 0xff)); + } + else + { + builtin_error("conversion of non-IPv4 address in fmt_ftp_port", + @ARG@[0]); + return new StringVal(""); + } + %} + diff --git a/src/analyzer/protocols/http/Plugin.cc b/src/analyzer/protocols/http/Plugin.cc index a0e6e28f43..86f1cb0333 100644 --- a/src/analyzer/protocols/http/Plugin.cc +++ b/src/analyzer/protocols/http/Plugin.cc @@ -7,4 +7,5 @@ BRO_PLUGIN_BEGIN(HTTP) BRO_PLUGIN_DESCRIPTION("HTTP Analyzer"); BRO_PLUGIN_ANALYZER("HTTP", http::HTTP_Analyzer); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/login/CMakeLists.txt b/src/analyzer/protocols/login/CMakeLists.txt index 219c249d5e..60a5b57ec5 100644 --- a/src/analyzer/protocols/login/CMakeLists.txt +++ b/src/analyzer/protocols/login/CMakeLists.txt @@ -6,4 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(Login) bro_plugin_cc(Login.cc RSH.cc Telnet.cc Rlogin.cc NVT.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_end() diff --git a/src/analyzer/protocols/login/Plugin.cc b/src/analyzer/protocols/login/Plugin.cc index 3f98f99d2c..43784ba262 100644 --- a/src/analyzer/protocols/login/Plugin.cc +++ b/src/analyzer/protocols/login/Plugin.cc @@ -16,4 +16,5 @@ BRO_PLUGIN_BEGIN(Login) BRO_PLUGIN_SUPPORT_ANALYZER("Contents_Rsh"); BRO_PLUGIN_SUPPORT_ANALYZER("Contents_Rlogin"); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/login/functions.bif b/src/analyzer/protocols/login/functions.bif new file mode 100644 index 0000000000..c3d7cbf82b --- /dev/null +++ b/src/analyzer/protocols/login/functions.bif @@ -0,0 +1,62 @@ + +%%{ +#include "Login.h" +%%} + +## Returns the state of the given login (Telnet or Rlogin) connection. +## +## cid: The connection ID. +## +## Returns: False if the connection is not active or is not tagged as a +## login analyzer. Otherwise the function returns the state, which can +## be one of: +## +## - ``LOGIN_STATE_AUTHENTICATE``: The connection is in its +## initial authentication dialog. +## - ``LOGIN_STATE_LOGGED_IN``: The analyzer believes the user has +## successfully authenticated. +## - ``LOGIN_STATE_SKIP``: The analyzer has skipped any further +## processing of the connection. +## - ``LOGIN_STATE_CONFUSED``: The analyzer has concluded that it +## does not correctly know the state of the connection, and/or +## the username associated with it. +## +## .. bro:see:: set_login_state +function get_login_state%(cid: conn_id%): count + %{ + Connection* c = sessions->FindConnection(cid); + if ( ! c ) + return new Val(0, TYPE_BOOL); + + analyzer::Analyzer* la = c->FindAnalyzer("Login"); + if ( ! la ) + return new Val(0, TYPE_BOOL); + + return new Val(int(static_cast(la)->LoginState()), + TYPE_COUNT); + %} + +## Sets the login state of a connection with a login analyzer. +## +## cid: The connection ID. +## +## new_state: The new state of the login analyzer. See +## :bro:id:`get_login_state` for possible values. +## +## Returns: Returns false if *cid* is not an active connection +## or is not tagged as a login analyzer, and true otherwise. +## +## .. bro:see:: get_login_state +function set_login_state%(cid: conn_id, new_state: count%): bool + %{ + Connection* c = sessions->FindConnection(cid); + if ( ! c ) + return new Val(0, TYPE_BOOL); + + analyzer::Analyzer* la = c->FindAnalyzer("Login"); + if ( ! la ) + return new Val(0, TYPE_BOOL); + + static_cast(la)->SetLoginState(analyzer::login::login_state(new_state)); + return new Val(1, TYPE_BOOL); + %} diff --git a/src/analyzer/protocols/netbios-ssn/CMakeLists.txt b/src/analyzer/protocols/netbios-ssn/CMakeLists.txt index 8292c11546..4318fa2b34 100644 --- a/src/analyzer/protocols/netbios-ssn/CMakeLists.txt +++ b/src/analyzer/protocols/netbios-ssn/CMakeLists.txt @@ -6,4 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(NetbiosSSN) bro_plugin_cc(NetbiosSSN.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_end() diff --git a/src/analyzer/protocols/netbios-ssn/Plugin.cc b/src/analyzer/protocols/netbios-ssn/Plugin.cc index 8ed7824634..66b4e82d51 100644 --- a/src/analyzer/protocols/netbios-ssn/Plugin.cc +++ b/src/analyzer/protocols/netbios-ssn/Plugin.cc @@ -8,4 +8,5 @@ BRO_PLUGIN_BEGIN(NetbiosSSN) BRO_PLUGIN_ANALYZER("NetbiosSSN", netbios_ssn::NetbiosSSN_Analyzer); BRO_PLUGIN_SUPPORT_ANALYZER("Contents_NetbiosSSN"); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/netbios-ssn/functions.bif b/src/analyzer/protocols/netbios-ssn/functions.bif new file mode 100644 index 0000000000..d4316d0c66 --- /dev/null +++ b/src/analyzer/protocols/netbios-ssn/functions.bif @@ -0,0 +1,50 @@ + +## Decode a NetBIOS name. See http://support.microsoft.com/kb/194203. +## +## name: The encoded NetBIOS name, e.g., ``"FEEIEFCAEOEFFEECEJEPFDCAEOEBENEF"``. +## +## Returns: The decoded NetBIOS name, e.g., ``"THE NETBIOS NAME"``. +## +## .. bro:see:: decode_netbios_name_type +function decode_netbios_name%(name: string%): string + %{ + char buf[16]; + char result[16]; + const u_char* s = name->Bytes(); + int i, j; + + for ( i = 0, j = 0; i < 16; ++i ) + { + char c0 = (j < name->Len()) ? toupper(s[j++]) : 'A'; + char c1 = (j < name->Len()) ? toupper(s[j++]) : 'A'; + buf[i] = ((c0 - 'A') << 4) + (c1 - 'A'); + } + + for ( i = 0; i < 15; ++i ) + { + if ( isalnum(buf[i]) || ispunct(buf[i]) || + // \x01\x02 is seen in at least one case as the first two bytes. + // I think that any \x01 and \x02 should always be passed through. + buf[i] < 3 ) + result[i] = buf[i]; + else + break; + } + + return new StringVal(i, result); + %} + +## Converts a NetBIOS name type to its corresponding numeric value. +## See http://support.microsoft.com/kb/163409. +## +## name: The NetBIOS name type. +## +## Returns: The numeric value of *name*. +## +## .. bro:see:: decode_netbios_name +function decode_netbios_name_type%(name: string%): count + %{ + const u_char* s = name->Bytes(); + char return_val = ((toupper(s[30]) - 'A') << 4) + (toupper(s[31]) - 'A'); + return new Val(return_val, TYPE_COUNT); + %} diff --git a/src/analyzer/protocols/smtp/CMakeLists.txt b/src/analyzer/protocols/smtp/CMakeLists.txt index 53f9dd1246..1f4779c0f8 100644 --- a/src/analyzer/protocols/smtp/CMakeLists.txt +++ b/src/analyzer/protocols/smtp/CMakeLists.txt @@ -6,4 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(SMTP) bro_plugin_cc(SMTP.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_end() diff --git a/src/analyzer/protocols/smtp/Plugin.cc b/src/analyzer/protocols/smtp/Plugin.cc index 8a5095381d..6550733b92 100644 --- a/src/analyzer/protocols/smtp/Plugin.cc +++ b/src/analyzer/protocols/smtp/Plugin.cc @@ -7,4 +7,5 @@ BRO_PLUGIN_BEGIN(SMTP) BRO_PLUGIN_DESCRIPTION("SMTP Analyzer"); BRO_PLUGIN_ANALYZER("SMTP", smtp::SMTP_Analyzer); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/smtp/functions.bif b/src/analyzer/protocols/smtp/functions.bif new file mode 100644 index 0000000000..2bb0c52319 --- /dev/null +++ b/src/analyzer/protocols/smtp/functions.bif @@ -0,0 +1,17 @@ + +%%{ +#include "analyzer/protocols/smtp/SMTP.h" +%%} + +## Skips SMTP data until the next email in a connection. +## +## c: The SMTP connection. +## +## .. bro:see:: skip_http_entity_data +function skip_smtp_data%(c: connection%): any + %{ + analyzer::Analyzer* sa = c->FindAnalyzer("SMTP"); + if ( sa ) + static_cast(sa)->SkipData(); + return 0; + %} diff --git a/src/analyzer/protocols/socks/socks-analyzer.pac b/src/analyzer/protocols/socks/socks-analyzer.pac index 7ce364670b..80051f0b27 100644 --- a/src/analyzer/protocols/socks/socks-analyzer.pac +++ b/src/analyzer/protocols/socks/socks-analyzer.pac @@ -35,7 +35,7 @@ refine connection SOCKS_Conn += { new PortVal(${request.port} | TCP_PORT_MASK), array_to_string(${request.user})); - static_cast(bro_analyzer())->EndpointDone(true); + static_cast(bro_analyzer())->EndpointDone(true); return true; %} @@ -53,7 +53,7 @@ refine connection SOCKS_Conn += { new PortVal(${reply.port} | TCP_PORT_MASK)); bro_analyzer()->ProtocolConfirmation(); - static_cast(bro_analyzer())->EndpointDone(false); + static_cast(bro_analyzer())->EndpointDone(false); return true; %} @@ -97,7 +97,7 @@ refine connection SOCKS_Conn += { new PortVal(${request.port} | TCP_PORT_MASK), new StringVal("")); - static_cast(bro_analyzer())->EndpointDone(true); + static_cast(bro_analyzer())->EndpointDone(true); return true; %} @@ -136,7 +136,7 @@ refine connection SOCKS_Conn += { new PortVal(${reply.port} | TCP_PORT_MASK)); bro_analyzer()->ProtocolConfirmation(); - static_cast(bro_analyzer())->EndpointDone(false); + static_cast(bro_analyzer())->EndpointDone(false); return true; %} diff --git a/src/analyzer/protocols/ssl/CMakeLists.txt b/src/analyzer/protocols/ssl/CMakeLists.txt index 9ee8fd9b1e..57f9b47e4d 100644 --- a/src/analyzer/protocols/ssl/CMakeLists.txt +++ b/src/analyzer/protocols/ssl/CMakeLists.txt @@ -6,5 +6,6 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(SSL) bro_plugin_cc(SSL.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_pac(ssl.pac ssl-analyzer.pac ssl-protocol.pac ssl-defs.pac) bro_plugin_end() diff --git a/src/analyzer/protocols/ssl/Plugin.cc b/src/analyzer/protocols/ssl/Plugin.cc index 6fe3308818..b406e4aa8b 100644 --- a/src/analyzer/protocols/ssl/Plugin.cc +++ b/src/analyzer/protocols/ssl/Plugin.cc @@ -7,4 +7,5 @@ BRO_PLUGIN_BEGIN(SSL) BRO_PLUGIN_DESCRIPTION("SSL Analyzer"); BRO_PLUGIN_ANALYZER("SSL", ssl::SSL_Analyzer); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/ssl/functions.bif b/src/analyzer/protocols/ssl/functions.bif new file mode 100644 index 0000000000..f2d4861007 --- /dev/null +++ b/src/analyzer/protocols/ssl/functions.bif @@ -0,0 +1,132 @@ + +%%{ +#include +#include +#include + +// This is the indexed map of X509 certificate stores. +static map x509_stores; + +// ### 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 + } + +%%} + + +## Verifies a certificate. +## +## der_cert: The X.509 certificate in DER format. +## +## cert_stack: Specifies a certificate chain to validate against, with index 0 +## typically being the root CA. Bro uses the Mozilla root CA list +## by default. +## +## root_certs: A list of additional root certificates that extends +## *cert_stack*. +## +## Returns: A status code of the verification which can be converted into an +## ASCII string via :bro:id:`x509_err2str`. +## +## .. bro:see:: x509_err2str +function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: table_string_of_string%): count + %{ + X509_STORE* ctx = 0; + int i = 0; + + // If this certificate store was built previously, just reuse the old one. + if ( x509_stores.count(root_certs) > 0 ) + ctx = x509_stores[root_certs]; + + if ( ! ctx ) // lookup to see if we have this one built already! + { + ctx = X509_STORE_new(); + TableVal* root_certs2 = root_certs->AsTableVal(); + ListVal* idxs = root_certs2->ConvertToPureList(); + + // Build the validation store + for ( i = 0; i < idxs->Length(); ++i ) + { + Val* key = idxs->Index(i); + StringVal *sv = root_certs2->Lookup(key)->AsStringVal(); + const uint8* data = sv->Bytes(); + X509* x = d2i_X509_(NULL, &data, sv->Len()); + if ( ! x ) + { + 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); + } + delete idxs; + + // Save the newly constructed certificate store into the cacheing map. + x509_stores[root_certs] = ctx; + } + + const uint8 *cert_data = der_cert->Bytes(); + X509* cert = d2i_X509_(NULL, &cert_data, der_cert->Len()); + if ( ! cert ) + { + builtin_error(fmt("Certificate error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); + return new Val((uint64) ERR_get_error(), TYPE_COUNT); + } + + STACK_OF(X509)* untrusted_certs = sk_X509_new_null(); + if ( ! untrusted_certs ) + { + 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); + } + + VectorVal *cert_stack_vec = cert_stack->AsVectorVal(); + for ( i = 0; i < (int) cert_stack_vec->Size(); ++i ) + { + StringVal *sv = cert_stack_vec->Lookup(i)->AsStringVal(); + const uint8 *data = sv->Bytes(); + X509* x = d2i_X509_(NULL, &data, sv->Len()); + if ( ! x ) + { + X509_free(cert); + sk_X509_pop_free(untrusted_certs, X509_free); + 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); + } + + X509_STORE_CTX csc; + X509_STORE_CTX_init(&csc, ctx, cert, untrusted_certs); + X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time); + + int result = X509_verify_cert(&csc); + X509_STORE_CTX_cleanup(&csc); + + if ( untrusted_certs ) + sk_X509_pop_free(untrusted_certs, X509_free); + X509_free(cert); + + return new Val((uint64) csc.error, TYPE_COUNT); + %} + +## Converts a certificate verification error code into an ASCII string. +## +## err_num: The error code. +## +## Returns: A string representation of *err_num*. +## +## .. bro:see:: x509_verify +function x509_err2str%(err_num: count%): string + %{ + return new StringVal(X509_verify_cert_error_string(err_num)); + %} diff --git a/src/analyzer/protocols/tcp/CMakeLists.txt b/src/analyzer/protocols/tcp/CMakeLists.txt index b8cf0e2bf4..f61f27495b 100644 --- a/src/analyzer/protocols/tcp/CMakeLists.txt +++ b/src/analyzer/protocols/tcp/CMakeLists.txt @@ -6,4 +6,5 @@ include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DI bro_plugin_begin(TCP) bro_plugin_cc(TCP.cc TCP_Endpoint.cc TCP_Reassembler.cc ContentLine.cc Stats.cc Plugin.cc) bro_plugin_bif(events.bif) +bro_plugin_bif(functions.bif) bro_plugin_end() diff --git a/src/analyzer/protocols/tcp/Plugin.cc b/src/analyzer/protocols/tcp/Plugin.cc index defb0b330d..376c54d332 100644 --- a/src/analyzer/protocols/tcp/Plugin.cc +++ b/src/analyzer/protocols/tcp/Plugin.cc @@ -10,4 +10,5 @@ BRO_PLUGIN_BEGIN(TCP) BRO_PLUGIN_SUPPORT_ANALYZER("ContentLine"); BRO_PLUGIN_SUPPORT_ANALYZER("Contents"); BRO_PLUGIN_BIF_FILE(events); + BRO_PLUGIN_BIF_FILE(functions); BRO_PLUGIN_END diff --git a/src/analyzer/protocols/tcp/functions.bif b/src/analyzer/protocols/tcp/functions.bif new file mode 100644 index 0000000000..b0178a1279 --- /dev/null +++ b/src/analyzer/protocols/tcp/functions.bif @@ -0,0 +1,159 @@ + +%%{ +#include "analyzer/protocols/tcp/TCP.h" +%%} + +## Get the originator sequence number of a TCP connection. Sequence numbers +## are absolute (i.e., they reflect the values seen directly in packet headers; +## they are not relative to the beginning of the connection). +## +## cid: The connection ID. +## +## Returns: The highest sequence number sent by a connection's originator, or 0 +## if *cid* does not point to an active TCP connection. +## +## .. bro:see:: get_resp_seq +function get_orig_seq%(cid: conn_id%): count + %{ + Connection* c = sessions->FindConnection(cid); + if ( ! c ) + return new Val(0, TYPE_COUNT); + + if ( c->ConnTransport() != TRANSPORT_TCP ) + return new Val(0, TYPE_COUNT); + + analyzer::Analyzer* tc = c->FindAnalyzer("TCP"); + if ( tc ) + return new Val(static_cast(tc)->OrigSeq(), + TYPE_COUNT); + else + { + reporter->Error("connection does not have TCP analyzer"); + return new Val(0, TYPE_COUNT); + } + %} + +## Get the responder sequence number of a TCP connection. Sequence numbers +## are absolute (i.e., they reflect the values seen directly in packet headers; +## they are not relative to the beginning of the connection). +## +## cid: The connection ID. +## +## Returns: The highest sequence number sent by a connection's responder, or 0 +## if *cid* does not point to an active TCP connection. +## +## .. bro:see:: get_orig_seq +function get_resp_seq%(cid: conn_id%): count + %{ + Connection* c = sessions->FindConnection(cid); + if ( ! c ) + return new Val(0, TYPE_COUNT); + + if ( c->ConnTransport() != TRANSPORT_TCP ) + return new Val(0, TYPE_COUNT); + + analyzer::Analyzer* tc = c->FindAnalyzer("TCP"); + if ( tc ) + return new Val(static_cast(tc)->RespSeq(), + TYPE_COUNT); + else + { + reporter->Error("connection does not have TCP analyzer"); + return new Val(0, TYPE_COUNT); + } + %} + +## Returns statistics about TCP gaps. +## +## Returns: A record with TCP gap statistics. +## +## .. bro:see:: do_profiling +## net_stats +## resource_usage +## dump_rule_stats +## get_matcher_stats +function get_gap_summary%(%): gap_info + %{ + RecordVal* r = new RecordVal(gap_info); + r->Assign(0, new Val(tot_ack_events, TYPE_COUNT)); + r->Assign(1, new Val(tot_ack_bytes, TYPE_COUNT)); + r->Assign(2, new Val(tot_gap_events, TYPE_COUNT)); + r->Assign(3, new Val(tot_gap_bytes, TYPE_COUNT)); + + return r; + %} + +## Associates a file handle with a connection for writing TCP byte stream +## contents. +## +## cid: The connection ID. +## +## direction: Controls what sides of the connection to record. The argument can +## take one of the four values: +## +## - ``CONTENTS_NONE``: Stop recording the connection's content. +## - ``CONTENTS_ORIG``: Record the data sent by the connection +## originator (often the client). +## - ``CONTENTS_RESP``: Record the data sent by the connection +## responder (often the server). +## - ``CONTENTS_BOTH``: Record the data sent in both directions. +## Results in the two directions being +## intermixed in the file, in the order the +## data was seen by Bro. +## +## f: The file handle of the file to write the contents to. +## +## Returns: Returns false if *cid* does not point to an active connection, and +## true otherwise. +## +## .. note:: +## +## The data recorded to the file reflects the byte stream, not the +## contents of individual packets. Reordering and duplicates are +## removed. If any data is missing, the recording stops at the +## missing data; this can happen, e.g., due to an +## :bro:id:`ack_above_hole` event. +## +## .. bro:see:: get_contents_file set_record_packets +function set_contents_file%(cid: conn_id, direction: count, f: file%): bool + %{ + Connection* c = sessions->FindConnection(cid); + if ( ! c ) + return new Val(0, TYPE_BOOL); + + c->GetRootAnalyzer()->SetContentsFile(direction, f); + return new Val(1, TYPE_BOOL); + %} + +## Returns the file handle of the contents file of a connection. +## +## cid: The connection ID. +## +## direction: Controls what sides of the connection to record. See +## :bro:id:`set_contents_file` for possible values. +## +## Returns: The :bro:type:`file` handle for the contents file of the +## connection identified by *cid*. If the connection exists +## but there is no contents file for *direction*, then the function +## generates an error and returns a file handle to ``stderr``. +## +## .. bro:see:: set_contents_file set_record_packets +function get_contents_file%(cid: conn_id, direction: count%): file + %{ + Connection* c = sessions->FindConnection(cid); + BroFile* f = c ? c->GetRootAnalyzer()->GetContentsFile(direction) : 0; + + if ( f ) + { + Ref(f); + return new Val(f); + } + + // Return some sort of error value. + if ( ! c ) + builtin_error("unknown connection id in get_contents_file()", cid); + else + builtin_error("no contents file for given direction"); + + return new Val(new BroFile(stderr, "-", "w")); + %} diff --git a/src/bro.bif b/src/bro.bif index aa8229f92d..5c39e335a6 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -20,7 +20,6 @@ using namespace std; -RecordType* ftp_port; RecordType* net_stats; RecordType* bro_resources; RecordType* matcher_stats; @@ -1786,26 +1785,6 @@ function get_matcher_stats%(%): matcher_stats return r; %} -## Returns statistics about TCP gaps. -## -## Returns: A record with TCP gap statistics. -## -## .. bro:see:: do_profiling -## net_stats -## resource_usage -## dump_rule_stats -## get_matcher_stats -function get_gap_summary%(%): gap_info - %{ - RecordVal* r = new RecordVal(gap_info); - r->Assign(0, new Val(tot_ack_events, TYPE_COUNT)); - r->Assign(1, new Val(tot_ack_bytes, TYPE_COUNT)); - r->Assign(2, new Val(tot_gap_events, TYPE_COUNT)); - r->Assign(3, new Val(tot_gap_bytes, TYPE_COUNT)); - - return r; - %} - ## Generates a table of the size of all global variables. The table index is ## the variable name and the value is the variable size in bytes. ## @@ -2541,273 +2520,6 @@ function addr_to_ptr_name%(a: addr%): string return new StringVal(a->AsAddr().PtrName().c_str()); %} - -%%{ -static Val* parse_port(const char* line) - { - RecordVal* r = new RecordVal(ftp_port); - - int bytes[6]; - if ( line && sscanf(line, "%d,%d,%d,%d,%d,%d", - &bytes[0], &bytes[1], &bytes[2], - &bytes[3], &bytes[4], &bytes[5]) == 6 ) - { - int good = 1; - - for ( int i = 0; i < 6; ++i ) - if ( bytes[i] < 0 || bytes[i] > 255 ) - { - good = 0; - break; - } - - uint32 addr = (bytes[0] << 24) | (bytes[1] << 16) | - (bytes[2] << 8) | bytes[3]; - uint32 port = (bytes[4] << 8) | bytes[5]; - - // Since port is unsigned, no need to check for < 0. - if ( port > 65535 ) - { - port = 0; - good = 0; - } - - r->Assign(0, new AddrVal(htonl(addr))); - r->Assign(1, new PortVal(port, TRANSPORT_TCP)); - r->Assign(2, new Val(good, TYPE_BOOL)); - } - else - { - r->Assign(0, new AddrVal(uint32(0))); - r->Assign(1, new PortVal(0, TRANSPORT_TCP)); - r->Assign(2, new Val(0, TYPE_BOOL)); - } - - return r; - } - -static Val* parse_eftp(const char* line) - { - RecordVal* r = new RecordVal(ftp_port); - - int net_proto = 0; // currently not used - IPAddr addr; // unspecified IPv6 address (all 128 bits zero) - int port = 0; - int good = 0; - - if ( line ) - { - while ( isspace(*line) ) // skip whitespace - ++line; - - char delimiter = *line; - char* next_delim; - - if ( *line ) - { - good = 1; - ++line; // skip delimiter - - net_proto = strtol(line, &next_delim, 10); - if ( *next_delim != delimiter ) - good = 0; - - line = next_delim; - if ( *line ) - ++line; - - if ( *line && *line != delimiter ) - { - const char* nptr = strchr(line, delimiter); - if ( nptr == NULL ) - { - nptr = line + strlen(line); - good = 0; - } - - string s(line, nptr-line); // extract IP address - IPAddr tmp(s); - // on error, "tmp" will have all 128 bits zero - if ( tmp == addr ) - good = 0; - - addr = tmp; - } - - line = strchr(line, delimiter); - - if ( line != NULL ) - { - ++line; // now the port - port = strtol(line, &next_delim, 10); - if ( *next_delim != delimiter ) - good = 0; - } - - } - - } - - r->Assign(0, new AddrVal(addr)); - r->Assign(1, new PortVal(port, TRANSPORT_TCP)); - r->Assign(2, new Val(good, TYPE_BOOL)); - - return r; - } -%%} - -## Converts a string representation of the FTP PORT command to an ``ftp_port``. -## -## s: The string of the FTP PORT command, e.g., ``"10,0,0,1,4,31"``. -## -## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` -## -## .. bro:see:: parse_eftp_port parse_ftp_pasv parse_ftp_epsv fmt_ftp_port -function parse_ftp_port%(s: string%): ftp_port - %{ - return parse_port(s->CheckString()); - %} - -## Converts a string representation of the FTP EPRT command to an ``ftp_port``. -## See `RFC 2428 `_. -## The format is ``EPRT``, -## where ```` is a delimiter in the ASCII range 33-126 (usually ``|``). -## -## s: The string of the FTP EPRT command, e.g., ``"|1|10.0.0.1|1055|"``. -## -## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` -## -## .. bro:see:: parse_ftp_port parse_ftp_pasv parse_ftp_epsv fmt_ftp_port -function parse_eftp_port%(s: string%): ftp_port - %{ - return parse_eftp(s->CheckString()); - %} - -## Converts the result of the FTP PASV command to an ``ftp_port``. -## -## str: The string containing the result of the FTP PASV command. -## -## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` -## -## .. bro:see:: parse_ftp_port parse_eftp_port parse_ftp_epsv fmt_ftp_port -function parse_ftp_pasv%(str: string%): ftp_port - %{ - const char* s = str->CheckString(); - const char* line = strchr(s, '('); - if ( line ) - ++line; // move past '(' - else if ( (line = strstr(s, "PORT")) ) - line += 5; // Skip over - else if ( (line = strchr(s, ',')) ) - { // Look for comma-separated list. - while ( --line >= s && isdigit(*line) ) - ; // Back up over preceding digits. - ++line; // now points to first digit, or beginning of s - } - - return parse_port(line); - %} - -## Converts the result of the FTP EPSV command to an ``ftp_port``. -## See `RFC 2428 `_. -## The format is `` ()``, where ```` is a -## delimiter in the ASCII range 33-126 (usually ``|``). -## -## str: The string containing the result of the FTP EPSV command. -## -## Returns: The FTP PORT, e.g., ``[h=10.0.0.1, p=1055/tcp, valid=T]`` -## -## .. bro:see:: parse_ftp_port parse_eftp_port parse_ftp_pasv fmt_ftp_port -function parse_ftp_epsv%(str: string%): ftp_port - %{ - const char* s = str->CheckString(); - const char* line = strchr(s, '('); - if ( line ) - ++line; // move past '(' - return parse_eftp(line); - %} - -## Formats an IP address and TCP port as an FTP PORT command. For example, -## ``10.0.0.1`` and ``1055/tcp`` yields ``"10,0,0,1,4,31"``. -## -## a: The IP address. -## -## p: The TCP port. -## -## Returns: The FTP PORT string. -## -## .. bro:see:: parse_ftp_port parse_eftp_port parse_ftp_pasv parse_ftp_epsv -function fmt_ftp_port%(a: addr, p: port%): string - %{ - const uint32* addr; - int len = a->AsAddr().GetBytes(&addr); - if ( len == 1 ) - { - uint32 a = ntohl(addr[0]); - uint32 pn = p->Port(); - return new StringVal(fmt("%d,%d,%d,%d,%d,%d", - a >> 24, (a >> 16) & 0xff, - (a >> 8) & 0xff, a & 0xff, - pn >> 8, pn & 0xff)); - } - else - { - builtin_error("conversion of non-IPv4 address in fmt_ftp_port", - @ARG@[0]); - return new StringVal(""); - } - %} - -## Decode a NetBIOS name. See http://support.microsoft.com/kb/194203. -## -## name: The encoded NetBIOS name, e.g., ``"FEEIEFCAEOEFFEECEJEPFDCAEOEBENEF"``. -## -## Returns: The decoded NetBIOS name, e.g., ``"THE NETBIOS NAME"``. -## -## .. bro:see:: decode_netbios_name_type -function decode_netbios_name%(name: string%): string - %{ - char buf[16]; - char result[16]; - const u_char* s = name->Bytes(); - int i, j; - - for ( i = 0, j = 0; i < 16; ++i ) - { - char c0 = (j < name->Len()) ? toupper(s[j++]) : 'A'; - char c1 = (j < name->Len()) ? toupper(s[j++]) : 'A'; - buf[i] = ((c0 - 'A') << 4) + (c1 - 'A'); - } - - for ( i = 0; i < 15; ++i ) - { - if ( isalnum(buf[i]) || ispunct(buf[i]) || - // \x01\x02 is seen in at least one case as the first two bytes. - // I think that any \x01 and \x02 should always be passed through. - buf[i] < 3 ) - result[i] = buf[i]; - else - break; - } - - return new StringVal(i, result); - %} - -## Converts a NetBIOS name type to its corresponding numeric value. -## See http://support.microsoft.com/kb/163409. -## -## name: The NetBIOS name type. -## -## Returns: The numeric value of *name*. -## -## .. bro:see:: decode_netbios_name -function decode_netbios_name_type%(name: string%): count - %{ - const u_char* s = name->Bytes(); - char return_val = ((toupper(s[30]) - 'A') << 4) + (toupper(s[31]) - 'A'); - return new Val(return_val, TYPE_COUNT); - %} - ## Converts a string of bytes into its hexadecimal representation. ## For example, ``"04"`` would be converted to ``"3034"``. ## @@ -3789,138 +3501,6 @@ function lookup_asn%(a: addr%) : count return new Val(0, TYPE_COUNT); %} -%%{ -#include -#include -#include - -// This is the indexed map of X509 certificate stores. -static map x509_stores; - -// ### 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 - } - -%%} - - -## Verifies a certificate. -## -## der_cert: The X.509 certificate in DER format. -## -## cert_stack: Specifies a certificate chain to validate against, with index 0 -## typically being the root CA. Bro uses the Mozilla root CA list -## by default. -## -## root_certs: A list of additional root certificates that extends -## *cert_stack*. -## -## Returns: A status code of the verification which can be converted into an -## ASCII string via :bro:id:`x509_err2str`. -## -## .. bro:see:: x509_err2str -function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: table_string_of_string%): count - %{ - X509_STORE* ctx = 0; - int i = 0; - - // If this certificate store was built previously, just reuse the old one. - if ( x509_stores.count(root_certs) > 0 ) - ctx = x509_stores[root_certs]; - - if ( ! ctx ) // lookup to see if we have this one built already! - { - ctx = X509_STORE_new(); - TableVal* root_certs2 = root_certs->AsTableVal(); - ListVal* idxs = root_certs2->ConvertToPureList(); - - // Build the validation store - for ( i = 0; i < idxs->Length(); ++i ) - { - Val* key = idxs->Index(i); - StringVal *sv = root_certs2->Lookup(key)->AsStringVal(); - const uint8* data = sv->Bytes(); - X509* x = d2i_X509_(NULL, &data, sv->Len()); - if ( ! x ) - { - 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); - } - delete idxs; - - // Save the newly constructed certificate store into the cacheing map. - x509_stores[root_certs] = ctx; - } - - const uint8 *cert_data = der_cert->Bytes(); - X509* cert = d2i_X509_(NULL, &cert_data, der_cert->Len()); - if ( ! cert ) - { - builtin_error(fmt("Certificate error: %s", ERR_error_string(ERR_peek_last_error(),NULL))); - return new Val((uint64) ERR_get_error(), TYPE_COUNT); - } - - STACK_OF(X509)* untrusted_certs = sk_X509_new_null(); - if ( ! untrusted_certs ) - { - 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); - } - - VectorVal *cert_stack_vec = cert_stack->AsVectorVal(); - for ( i = 0; i < (int) cert_stack_vec->Size(); ++i ) - { - StringVal *sv = cert_stack_vec->Lookup(i)->AsStringVal(); - const uint8 *data = sv->Bytes(); - X509* x = d2i_X509_(NULL, &data, sv->Len()); - if ( ! x ) - { - X509_free(cert); - sk_X509_pop_free(untrusted_certs, X509_free); - 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); - } - - X509_STORE_CTX csc; - X509_STORE_CTX_init(&csc, ctx, cert, untrusted_certs); - X509_STORE_CTX_set_time(&csc, 0, (time_t) network_time); - - int result = X509_verify_cert(&csc); - X509_STORE_CTX_cleanup(&csc); - - if ( untrusted_certs ) - sk_X509_pop_free(untrusted_certs, X509_free); - X509_free(cert); - - return new Val((uint64) csc.error, TYPE_COUNT); - %} - -## Converts a certificate verification error code into an ASCII string. -## -## err_num: The error code. -## -## Returns: A string representation of *err_num*. -## -## .. bro:see:: x509_verify -function x509_err2str%(err_num: count%): string - %{ - return new StringVal(X509_verify_cert_error_string(err_num)); - %} - ## Converts UNIX file permissions given by a mode to an ASCII string. ## ## mode: The permissions (an octal number like 0644 converted to decimal). @@ -4108,81 +3688,6 @@ function set_record_packets%(cid: conn_id, do_record: bool%): bool return new Val(1, TYPE_BOOL); %} -## Associates a file handle with a connection for writing TCP byte stream -## contents. -## -## cid: The connection ID. -## -## direction: Controls what sides of the connection to record. The argument can -## take one of the four values: -## -## - ``CONTENTS_NONE``: Stop recording the connection's content. -## - ``CONTENTS_ORIG``: Record the data sent by the connection -## originator (often the client). -## - ``CONTENTS_RESP``: Record the data sent by the connection -## responder (often the server). -## - ``CONTENTS_BOTH``: Record the data sent in both directions. -## Results in the two directions being -## intermixed in the file, in the order the -## data was seen by Bro. -## -## f: The file handle of the file to write the contents to. -## -## Returns: Returns false if *cid* does not point to an active connection, and -## true otherwise. -## -## .. note:: -## -## The data recorded to the file reflects the byte stream, not the -## contents of individual packets. Reordering and duplicates are -## removed. If any data is missing, the recording stops at the -## missing data; this can happen, e.g., due to an -## :bro:id:`ack_above_hole` event. -## -## .. bro:see:: get_contents_file set_record_packets -function set_contents_file%(cid: conn_id, direction: count, f: file%): bool - %{ - Connection* c = sessions->FindConnection(cid); - if ( ! c ) - return new Val(0, TYPE_BOOL); - - c->GetRootAnalyzer()->SetContentsFile(direction, f); - return new Val(1, TYPE_BOOL); - %} - -## Returns the file handle of the contents file of a connection. -## -## cid: The connection ID. -## -## direction: Controls what sides of the connection to record. See -## :bro:id:`set_contents_file` for possible values. -## -## Returns: The :bro:type:`file` handle for the contents file of the -## connection identified by *cid*. If the connection exists -## but there is no contents file for *direction*, then the function -## generates an error and returns a file handle to ``stderr``. -## -## .. bro:see:: set_contents_file set_record_packets -function get_contents_file%(cid: conn_id, direction: count%): file - %{ - Connection* c = sessions->FindConnection(cid); - BroFile* f = c ? c->GetRootAnalyzer()->GetContentsFile(direction) : 0; - - if ( f ) - { - Ref(f); - return new Val(f); - } - - // Return some sort of error value. - if ( ! c ) - builtin_error("unknown connection id in get_contents_file()", cid); - else - builtin_error("no contents file for given direction"); - - return new Val(new BroFile(stderr, "-", "w")); - %} - ## Sets an individual inactivity timeout for a connection and thus ## overrides the global inactivity timeout. ## @@ -4203,145 +3708,6 @@ function set_inactivity_timeout%(cid: conn_id, t: interval%): interval return new Val(old_timeout, TYPE_INTERVAL); %} -## Returns the state of the given login (Telnet or Rlogin) connection. -## -## cid: The connection ID. -## -## Returns: False if the connection is not active or is not tagged as a -## login analyzer. Otherwise the function returns the state, which can -## be one of: -## -## - ``LOGIN_STATE_AUTHENTICATE``: The connection is in its -## initial authentication dialog. -## - ``LOGIN_STATE_LOGGED_IN``: The analyzer believes the user has -## successfully authenticated. -## - ``LOGIN_STATE_SKIP``: The analyzer has skipped any further -## processing of the connection. -## - ``LOGIN_STATE_CONFUSED``: The analyzer has concluded that it -## does not correctly know the state of the connection, and/or -## the username associated with it. -## -## .. bro:see:: set_login_state -function get_login_state%(cid: conn_id%): count - %{ - Connection* c = sessions->FindConnection(cid); - if ( ! c ) - return new Val(0, TYPE_BOOL); - - analyzer::Analyzer* la = c->FindAnalyzer("Login"); - if ( ! la ) - return new Val(0, TYPE_BOOL); - - return new Val(int(static_cast(la)->LoginState()), - TYPE_COUNT); - %} - -## Sets the login state of a connection with a login analyzer. -## -## cid: The connection ID. -## -## new_state: The new state of the login analyzer. See -## :bro:id:`get_login_state` for possible values. -## -## Returns: Returns false if *cid* is not an active connection -## or is not tagged as a login analyzer, and true otherwise. -## -## .. bro:see:: get_login_state -function set_login_state%(cid: conn_id, new_state: count%): bool - %{ - Connection* c = sessions->FindConnection(cid); - if ( ! c ) - return new Val(0, TYPE_BOOL); - - analyzer::Analyzer* la = c->FindAnalyzer("Login"); - if ( ! la ) - return new Val(0, TYPE_BOOL); - - static_cast(la)->SetLoginState(analyzer::login::login_state(new_state)); - return new Val(1, TYPE_BOOL); - %} - -%%{ -#include "analyzer/protocols/tcp/TCP.h" -%%} - -## Get the originator sequence number of a TCP connection. Sequence numbers -## are absolute (i.e., they reflect the values seen directly in packet headers; -## they are not relative to the beginning of the connection). -## -## cid: The connection ID. -## -## Returns: The highest sequence number sent by a connection's originator, or 0 -## if *cid* does not point to an active TCP connection. -## -## .. bro:see:: get_resp_seq -function get_orig_seq%(cid: conn_id%): count - %{ - Connection* c = sessions->FindConnection(cid); - if ( ! c ) - return new Val(0, TYPE_COUNT); - - if ( c->ConnTransport() != TRANSPORT_TCP ) - return new Val(0, TYPE_COUNT); - - analyzer::Analyzer* tc = c->FindAnalyzer("TCP"); - if ( tc ) - return new Val(static_cast(tc)->OrigSeq(), - TYPE_COUNT); - else - { - reporter->Error("connection does not have TCP analyzer"); - return new Val(0, TYPE_COUNT); - } - %} - -## Get the responder sequence number of a TCP connection. Sequence numbers -## are absolute (i.e., they reflect the values seen directly in packet headers; -## they are not relative to the beginning of the connection). -## -## cid: The connection ID. -## -## Returns: The highest sequence number sent by a connection's responder, or 0 -## if *cid* does not point to an active TCP connection. -## -## .. bro:see:: get_orig_seq -function get_resp_seq%(cid: conn_id%): count - %{ - Connection* c = sessions->FindConnection(cid); - if ( ! c ) - return new Val(0, TYPE_COUNT); - - if ( c->ConnTransport() != TRANSPORT_TCP ) - return new Val(0, TYPE_COUNT); - - analyzer::Analyzer* tc = c->FindAnalyzer("TCP"); - if ( tc ) - return new Val(static_cast(tc)->RespSeq(), - TYPE_COUNT); - else - { - reporter->Error("connection does not have TCP analyzer"); - return new Val(0, TYPE_COUNT); - } - %} - -%%{ -#include "analyzer/protocols/smtp/SMTP.h" -%%} - -## Skips SMTP data until the next email in a connection. -## -## c: The SMTP connection. -## -## .. bro:see:: skip_http_entity_data -function skip_smtp_data%(c: connection%): any - %{ - analyzer::Analyzer* sa = c->FindAnalyzer("SMTP"); - if ( sa ) - static_cast(sa)->SkipData(); - return 0; - %} - # =========================================================================== # # Files and Directories