mirror of
https://github.com/zeek/zeek.git
synced 2025-10-07 09:08:20 +00:00
Moving protocol-specific BiFs out of bro.bif.
I hope I found them all ...
This commit is contained in:
parent
5dc630f722
commit
3959e254e2
22 changed files with 657 additions and 639 deletions
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
220
src/analyzer/protocols/ftp/functions.bif
Normal file
220
src/analyzer/protocols/ftp/functions.bif
Normal file
|
@ -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 <http://tools.ietf.org/html/rfc2428>`_.
|
||||
## The format is ``EPRT<space><d><net-prt><d><net-addr><d><tcp-port><d>``,
|
||||
## where ``<d>`` 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 <http://tools.ietf.org/html/rfc2428>`_.
|
||||
## The format is ``<text> (<d><d><d><tcp-port><d>)``, where ``<d>`` 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("");
|
||||
}
|
||||
%}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
62
src/analyzer/protocols/login/functions.bif
Normal file
62
src/analyzer/protocols/login/functions.bif
Normal file
|
@ -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<analyzer::login::Login_Analyzer*>(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<analyzer::login::Login_Analyzer*>(la)->SetLoginState(analyzer::login::login_state(new_state));
|
||||
return new Val(1, TYPE_BOOL);
|
||||
%}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
50
src/analyzer/protocols/netbios-ssn/functions.bif
Normal file
50
src/analyzer/protocols/netbios-ssn/functions.bif
Normal file
|
@ -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);
|
||||
%}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
17
src/analyzer/protocols/smtp/functions.bif
Normal file
17
src/analyzer/protocols/smtp/functions.bif
Normal file
|
@ -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<analyzer::smtp::SMTP_Analyzer*>(sa)->SkipData();
|
||||
return 0;
|
||||
%}
|
|
@ -35,7 +35,7 @@ refine connection SOCKS_Conn += {
|
|||
new PortVal(${request.port} | TCP_PORT_MASK),
|
||||
array_to_string(${request.user}));
|
||||
|
||||
static_cast<SOCKS_Analyzer*>(bro_analyzer())->EndpointDone(true);
|
||||
static_cast<analyzer::socks::SOCKS_Analyzer*>(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<SOCKS_Analyzer*>(bro_analyzer())->EndpointDone(false);
|
||||
static_cast<analyzer::socks::SOCKS_Analyzer*>(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<SOCKS_Analyzer*>(bro_analyzer())->EndpointDone(true);
|
||||
static_cast<analyzer::socks::SOCKS_Analyzer*>(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<SOCKS_Analyzer*>(bro_analyzer())->EndpointDone(false);
|
||||
static_cast<analyzer::socks::SOCKS_Analyzer*>(bro_analyzer())->EndpointDone(false);
|
||||
return true;
|
||||
%}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
132
src/analyzer/protocols/ssl/functions.bif
Normal file
132
src/analyzer/protocols/ssl/functions.bif
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
%%{
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
// This is the indexed map of X509 certificate stores.
|
||||
static map<Val*, X509_STORE*> x509_stores;
|
||||
|
||||
// ### NOTE: while d2i_X509 does not take a const u_char** pointer,
|
||||
// here we assume d2i_X509 does not write to <data>, 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));
|
||||
%}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
159
src/analyzer/protocols/tcp/functions.bif
Normal file
159
src/analyzer/protocols/tcp/functions.bif
Normal file
|
@ -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<analyzer::tcp::TCP_Analyzer*>(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<analyzer::tcp::TCP_Analyzer*>(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"));
|
||||
%}
|
634
src/bro.bif
634
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 <http://tools.ietf.org/html/rfc2428>`_.
|
||||
## The format is ``EPRT<space><d><net-prt><d><net-addr><d><tcp-port><d>``,
|
||||
## where ``<d>`` 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 <http://tools.ietf.org/html/rfc2428>`_.
|
||||
## The format is ``<text> (<d><d><d><tcp-port><d>)``, where ``<d>`` 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 <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
// This is the indexed map of X509 certificate stores.
|
||||
static map<Val*, X509_STORE*> x509_stores;
|
||||
|
||||
// ### NOTE: while d2i_X509 does not take a const u_char** pointer,
|
||||
// here we assume d2i_X509 does not write to <data>, 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<analyzer::login::Login_Analyzer*>(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<analyzer::login::Login_Analyzer*>(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<analyzer::tcp::TCP_Analyzer*>(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<analyzer::tcp::TCP_Analyzer*>(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<analyzer::smtp::SMTP_Analyzer*>(sa)->SkipData();
|
||||
return 0;
|
||||
%}
|
||||
|
||||
# ===========================================================================
|
||||
#
|
||||
# Files and Directories
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue