Merge remote-tracking branch 'origin/master' into topic/vladg/kerberos

This commit is contained in:
Vlad Grigorescu 2015-02-05 14:22:29 -05:00
commit 7e1fcb1a10
123 changed files with 7470 additions and 1344 deletions

View file

@ -18,7 +18,7 @@ const char* attr_name(attr_tag t)
"&encrypt",
"&raw_output", "&mergeable", "&priority",
"&group", "&log", "&error_handler", "&type_column",
"(&tracked)",
"(&tracked)", "&deprecated",
};
return attr_names[int(t)];
@ -212,6 +212,7 @@ void Attributes::DescribeReST(ODesc* d) const
void Attributes::CheckAttr(Attr* a)
{
switch ( a->Tag() ) {
case ATTR_DEPRECATED:
case ATTR_OPTIONAL:
case ATTR_REDEF:
break;

View file

@ -34,7 +34,8 @@ typedef enum {
ATTR_ERROR_HANDLER,
ATTR_TYPE_COLUMN, // for input framework
ATTR_TRACKED, // hidden attribute, tracked by NotifierRegistry
#define NUM_ATTRS (int(ATTR_TRACKED) + 1)
ATTR_DEPRECATED,
#define NUM_ATTRS (int(ATTR_DEPRECATED) + 1)
} attr_tag;
class Attr : public BroObj {

View file

@ -3213,6 +3213,10 @@ FieldExpr::FieldExpr(Expr* arg_op, const char* arg_field_name)
{
SetType(rt->FieldType(field)->Ref());
td = rt->FieldDecl(field);
if ( td->FindAttr(ATTR_DEPRECATED) )
reporter->Warning("deprecated (%s$%s)", rt->GetName().c_str(),
field_name);
}
}
}
@ -3333,6 +3337,9 @@ HasFieldExpr::HasFieldExpr(Expr* arg_op, const char* arg_field_name)
if ( field < 0 )
ExprError("no such field in record");
else if ( rt->FieldDecl(field)->FindAttr(ATTR_DEPRECATED) )
reporter->Warning("deprecated (%s?$%s)", rt->GetName().c_str(),
field_name);
SetType(base_type(TYPE_BOOL));
}
@ -4147,16 +4154,28 @@ RecordCoerceExpr::RecordCoerceExpr(Expr* op, RecordType* r)
}
for ( i = 0; i < map_size; ++i )
if ( map[i] == -1 &&
! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) )
{
if ( map[i] == -1 )
{
char buf[512];
safe_snprintf(buf, sizeof(buf),
"non-optional field \"%s\" missing", t_r->FieldName(i));
Error(buf);
SetError();
break;
if ( ! t_r->FieldDecl(i)->FindAttr(ATTR_OPTIONAL) )
{
char buf[512];
safe_snprintf(buf, sizeof(buf),
"non-optional field \"%s\" missing",
t_r->FieldName(i));
Error(buf);
SetError();
break;
}
}
else
{
if ( t_r->FieldDecl(i)->FindAttr(ATTR_DEPRECATED) )
reporter->Warning("deprecated (%s$%s)",
t_r->GetName().c_str(),
t_r->FieldName(i));
}
}
}
}

View file

@ -323,7 +323,7 @@ int BroFunc::IsPure() const
Val* BroFunc::Call(val_list* args, Frame* parent) const
{
#ifdef PROFILE_BRO_FUNCTIONS
DEBUG_MSG("Function: %s\n", id->Name());
DEBUG_MSG("Function: %s\n", Name());
#endif
SegmentProfiler(segment_logger, location);

View file

@ -248,6 +248,16 @@ void ID::UpdateValAttrs()
}
}
void ID::MakeDeprecated()
{
if ( IsDeprecated() )
return;
attr_list* attr = new attr_list;
attr->append(new Attr(ATTR_DEPRECATED));
AddAttrs(new Attributes(attr, Type(), false));
}
void ID::AddAttrs(Attributes* a)
{
if ( attrs )

View file

@ -80,6 +80,11 @@ public:
Attr* FindAttr(attr_tag t) const
{ return attrs ? attrs->FindAttr(t) : 0; }
bool IsDeprecated() const
{ return FindAttr(ATTR_DEPRECATED) != 0; }
void MakeDeprecated();
void Error(const char* msg, const BroObj* o2 = 0);
void Describe(ODesc* d) const;

View file

@ -1434,7 +1434,7 @@ EnumType::~EnumType()
// Note, we use reporter->Error() here (not Error()) to include the current script
// location in the error message, rather than the one where the type was
// originally defined.
void EnumType::AddName(const string& module_name, const char* name, bool is_export)
void EnumType::AddName(const string& module_name, const char* name, bool is_export, bool deprecated)
{
/* implicit, auto-increment */
if ( counter < 0)
@ -1443,11 +1443,11 @@ void EnumType::AddName(const string& module_name, const char* name, bool is_expo
SetError();
return;
}
CheckAndAddName(module_name, name, counter, is_export);
CheckAndAddName(module_name, name, counter, is_export, deprecated);
counter++;
}
void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export)
void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, bool deprecated)
{
/* explicit value specified */
if ( counter > 0 )
@ -1457,11 +1457,11 @@ void EnumType::AddName(const string& module_name, const char* name, bro_int_t va
return;
}
counter = -1;
CheckAndAddName(module_name, name, val, is_export);
CheckAndAddName(module_name, name, val, is_export, deprecated);
}
void EnumType::CheckAndAddName(const string& module_name, const char* name,
bro_int_t val, bool is_export)
bro_int_t val, bool is_export, bool deprecated)
{
if ( Lookup(val) )
{
@ -1477,6 +1477,10 @@ void EnumType::CheckAndAddName(const string& module_name, const char* name,
id = install_ID(name, module_name.c_str(), true, is_export);
id->SetType(this->Ref());
id->SetEnumConst();
if ( deprecated )
id->MakeDeprecated();
broxygen_mgr->Identifier(id);
}
else

View file

@ -554,12 +554,12 @@ public:
// The value of this name is next internal counter value, starting
// with zero. The internal counter is incremented.
void AddName(const string& module_name, const char* name, bool is_export);
void AddName(const string& module_name, const char* name, bool is_export, bool deprecated);
// The value of this name is set to val. Once a value has been
// explicitly assigned using this method, no further names can be
// added that aren't likewise explicitly initalized.
void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export);
void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export, bool deprecated);
// -1 indicates not found.
bro_int_t Lookup(const string& module_name, const char* name) const;
@ -580,7 +580,8 @@ protected:
const char* name, bro_int_t val, bool is_export);
void CheckAndAddName(const string& module_name,
const char* name, bro_int_t val, bool is_export);
const char* name, bro_int_t val, bool is_export,
bool deprecated);
typedef std::map< const char*, bro_int_t, ltstr > NameMap;
NameMap names;

View file

@ -435,6 +435,10 @@ void end_func(Stmt* body, attr_list* attrs)
loop_over_list(*attrs, i)
{
Attr* a = (*attrs)[i];
if ( a->Tag() == ATTR_DEPRECATED )
continue;
if ( a->Tag() != ATTR_PRIORITY )
{
a->Error("illegal attribute for function body");

View file

@ -97,7 +97,6 @@
// Binpac DNP3 Analyzer
#include "DNP3.h"
#include "analyzer/protocol/tcp/TCP_Reassembler.h"
#include "events.bif.h"
using namespace analyzer::dnp3;
@ -109,12 +108,14 @@ const unsigned int PSEUDO_APP_LAYER_INDEX = 11; // index of first DNP3 app-laye
const unsigned int PSEUDO_TRANSPORT_LEN = 1; // length of DNP3 Transport Layer
const unsigned int PSEUDO_LINK_LAYER_LEN = 8; // length of DNP3 Pseudo Link Layer
bool DNP3_Analyzer::crc_table_initialized = false;
unsigned int DNP3_Analyzer::crc_table[256];
bool DNP3_Base::crc_table_initialized = false;
unsigned int DNP3_Base::crc_table[256];
DNP3_Analyzer::DNP3_Analyzer(Connection* c) : TCP_ApplicationAnalyzer("DNP3", c)
DNP3_Base::DNP3_Base(analyzer::Analyzer* arg_analyzer)
{
interp = new binpac::DNP3::DNP3_Conn(this);
analyzer = arg_analyzer;
interp = new binpac::DNP3::DNP3_Conn(analyzer);
ClearEndpointState(true);
ClearEndpointState(false);
@ -123,49 +124,12 @@ DNP3_Analyzer::DNP3_Analyzer(Connection* c) : TCP_ApplicationAnalyzer("DNP3", c)
PrecomputeCRCTable();
}
DNP3_Analyzer::~DNP3_Analyzer()
DNP3_Base::~DNP3_Base()
{
delete interp;
}
void DNP3_Analyzer::Done()
{
TCP_ApplicationAnalyzer::Done();
interp->FlowEOF(true);
interp->FlowEOF(false);
}
void DNP3_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
try
{
if ( ! ProcessData(len, data, orig) )
SetSkip(1);
}
catch ( const binpac::Exception& e )
{
SetSkip(1);
throw;
}
}
void DNP3_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
interp->NewGap(orig, len);
}
void DNP3_Analyzer::EndpointEOF(bool is_orig)
{
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
interp->FlowEOF(is_orig);
}
bool DNP3_Analyzer::ProcessData(int len, const u_char* data, bool orig)
bool DNP3_Base::ProcessData(int len, const u_char* data, bool orig)
{
Endpoint* endp = orig ? &orig_state : &resp_state;
@ -174,25 +138,30 @@ bool DNP3_Analyzer::ProcessData(int len, const u_char* data, bool orig)
if ( endp->in_hdr )
{
// We're parsing the DNP3 header and link layer, get that in full.
if ( ! AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len) )
int res = AddToBuffer(endp, PSEUDO_APP_LAYER_INDEX, &data, &len);
if ( res == 0 )
return true;
if ( res < 0 )
return false;
// The first two bytes must always be 0x0564.
if( endp->buffer[0] != 0x05 || endp->buffer[1] != 0x64 )
{
Weird("dnp3_header_lacks_magic");
analyzer->Weird("dnp3_header_lacks_magic");
return false;
}
// Make sure header checksum is correct.
if ( ! CheckCRC(PSEUDO_LINK_LAYER_LEN, endp->buffer, endp->buffer + PSEUDO_LINK_LAYER_LEN, "header") )
{
ProtocolViolation("broken_checksum");
analyzer->ProtocolViolation("broken_checksum");
return false;
}
// If the checksum works out, we're pretty certainly DNP3.
ProtocolConfirmation();
analyzer->ProtocolConfirmation();
// DNP3 packets without transport and application
// layers can happen, we ignore them.
@ -207,7 +176,7 @@ bool DNP3_Analyzer::ProcessData(int len, const u_char* data, bool orig)
u_char ctrl = endp->buffer[PSEUDO_CONTROL_FIELD_INDEX];
if ( orig != (bool)(ctrl & 0x80) )
Weird("dnp3_unexpected_flow_direction");
analyzer->Weird("dnp3_unexpected_flow_direction");
// Update state.
endp->pkt_length = endp->buffer[PSEUDO_LENGTH_INDEX];
@ -222,7 +191,11 @@ bool DNP3_Analyzer::ProcessData(int len, const u_char* data, bool orig)
if ( ! endp->in_hdr )
{
assert(endp->pkt_length);
if ( endp->pkt_length <= 0 )
{
analyzer->Weird("dnp3_negative_or_zero_length_link_layer");
return false;
}
// We're parsing the DNP3 application layer, get that
// in full now as well. We calculate the number of
@ -230,11 +203,17 @@ bool DNP3_Analyzer::ProcessData(int len, const u_char* data, bool orig)
// the packet length by determining how much 16-byte
// chunks fit in there, and then add 2 bytes CRC for
// each.
int n = PSEUDO_APP_LAYER_INDEX + (endp->pkt_length - 5) + ((endp->pkt_length - 5) / 16) * 2 + 2 - 1;
int n = PSEUDO_APP_LAYER_INDEX + (endp->pkt_length - 5) + ((endp->pkt_length - 5) / 16) * 2
+ 2 * ( ((endp->pkt_length - 5) % 16 == 0) ? 0 : 1) - 1 ;
if ( ! AddToBuffer(endp, n, &data, &len) )
int res = AddToBuffer(endp, n, &data, &len);
if ( res == 0 )
return true;
if ( res < 0 )
return false;
// Parse the the application layer data.
if ( ! ParseAppLayer(endp) )
return false;
@ -248,22 +227,45 @@ bool DNP3_Analyzer::ProcessData(int len, const u_char* data, bool orig)
return true;
}
bool DNP3_Analyzer::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len)
int DNP3_Base::AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len)
{
if ( ! target_len )
return true;
return 1;
if ( *len < 0 )
{
reporter->AnalyzerError(analyzer, "dnp3 negative input length: %d", *len);
return -1;
}
if ( target_len < endp->buffer_len )
{
reporter->AnalyzerError(analyzer, "dnp3 invalid target length: %d - %d",
target_len, endp->buffer_len);
return -1;
}
int to_copy = min(*len, target_len - endp->buffer_len);
if ( endp->buffer_len + to_copy > MAX_BUFFER_SIZE )
{
reporter->AnalyzerError(analyzer, "dnp3 buffer length exceeded: %d + %d",
endp->buffer_len, to_copy);
return -1;
}
memcpy(endp->buffer + endp->buffer_len, *data, to_copy);
*data += to_copy;
*len -= to_copy;
endp->buffer_len += to_copy;
return endp->buffer_len == target_len;
if ( endp->buffer_len == target_len )
return 1;
return 0;
}
bool DNP3_Analyzer::ParseAppLayer(Endpoint* endp)
bool DNP3_Base::ParseAppLayer(Endpoint* endp)
{
bool orig = (endp == &orig_state);
binpac::DNP3::DNP3_Flow* flow = orig ? interp->upflow() : interp->downflow();
@ -291,8 +293,15 @@ bool DNP3_Analyzer::ParseAppLayer(Endpoint* endp)
if ( ! CheckCRC(n, data, data + n, "app_chunk") )
return false;
if ( data + n >= endp->buffer + endp->buffer_len )
{
reporter->AnalyzerError(analyzer,
"dnp3 app layer parsing overflow %d - %d",
endp->buffer_len, n);
return false;
}
// Pass on to BinPAC.
assert(data + n < endp->buffer + endp->buffer_len);
flow->flow_buffer()->BufferData(data + transport, data + n);
transport = 0;
@ -306,7 +315,7 @@ bool DNP3_Analyzer::ParseAppLayer(Endpoint* endp)
if ( ! is_first && ! endp->encountered_first_chunk )
{
// We lost the first chunk.
Weird("dnp3_first_application_layer_chunk_missing");
analyzer->Weird("dnp3_first_application_layer_chunk_missing");
return false;
}
@ -320,7 +329,7 @@ bool DNP3_Analyzer::ParseAppLayer(Endpoint* endp)
return true;
}
void DNP3_Analyzer::ClearEndpointState(bool orig)
void DNP3_Base::ClearEndpointState(bool orig)
{
Endpoint* endp = orig ? &orig_state : &resp_state;
binpac::DNP3::DNP3_Flow* flow = orig ? interp->upflow() : interp->downflow();
@ -333,18 +342,18 @@ void DNP3_Analyzer::ClearEndpointState(bool orig)
endp->pkt_cnt = 0;
}
bool DNP3_Analyzer::CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where)
bool DNP3_Base::CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where)
{
unsigned int crc = CalcCRC(len, data);
if ( crc16[0] == (crc & 0xff) && crc16[1] == (crc & 0xff00) >> 8 )
return true;
Weird(fmt("dnp3_corrupt_%s_checksum", where));
analyzer->Weird(fmt("dnp3_corrupt_%s_checksum", where));
return false;
}
void DNP3_Analyzer::PrecomputeCRCTable()
void DNP3_Base::PrecomputeCRCTable()
{
for( unsigned int i = 0; i < 256; i++)
{
@ -362,7 +371,7 @@ void DNP3_Analyzer::PrecomputeCRCTable()
}
}
unsigned int DNP3_Analyzer::CalcCRC(int len, const u_char* data)
unsigned int DNP3_Base::CalcCRC(int len, const u_char* data)
{
unsigned int crc = 0x0000;
@ -374,3 +383,76 @@ unsigned int DNP3_Analyzer::CalcCRC(int len, const u_char* data)
return ~crc & 0xFFFF;
}
DNP3_TCP_Analyzer::DNP3_TCP_Analyzer(Connection* c)
: DNP3_Base(this), TCP_ApplicationAnalyzer("DNP3_TCP", c)
{
}
DNP3_TCP_Analyzer::~DNP3_TCP_Analyzer()
{
}
void DNP3_TCP_Analyzer::Done()
{
TCP_ApplicationAnalyzer::Done();
Interpreter()->FlowEOF(true);
Interpreter()->FlowEOF(false);
}
void DNP3_TCP_Analyzer::DeliverStream(int len, const u_char* data, bool orig)
{
TCP_ApplicationAnalyzer::DeliverStream(len, data, orig);
try
{
if ( ! ProcessData(len, data, orig) )
SetSkip(1);
}
catch ( const binpac::Exception& e )
{
SetSkip(1);
throw;
}
}
void DNP3_TCP_Analyzer::Undelivered(uint64 seq, int len, bool orig)
{
TCP_ApplicationAnalyzer::Undelivered(seq, len, orig);
Interpreter()->NewGap(orig, len);
}
void DNP3_TCP_Analyzer::EndpointEOF(bool is_orig)
{
TCP_ApplicationAnalyzer::EndpointEOF(is_orig);
Interpreter()->FlowEOF(is_orig);
}
DNP3_UDP_Analyzer::DNP3_UDP_Analyzer(Connection* c)
: DNP3_Base(this), Analyzer("DNP3_UDP", c)
{
}
DNP3_UDP_Analyzer::~DNP3_UDP_Analyzer()
{
}
void DNP3_UDP_Analyzer::DeliverPacket(int len, const u_char* data, bool orig, uint64 seq, const IP_Hdr* ip, int caplen)
{
Analyzer::DeliverPacket(len, data, orig, seq, ip, caplen);
try
{
if ( ! ProcessData(len, data, orig) )
SetSkip(1);
}
catch ( const binpac::Exception& e )
{
SetSkip(1);
throw;
}
}

View file

@ -3,24 +3,20 @@
#define ANALYZER_PROTOCOL_DNP3_DNP3_H
#include "analyzer/protocol/tcp/TCP.h"
#include "analyzer/protocol/udp/UDP.h"
#include "dnp3_pac.h"
namespace analyzer { namespace dnp3 {
class DNP3_Analyzer : public tcp::TCP_ApplicationAnalyzer {
class DNP3_Base {
public:
DNP3_Analyzer(Connection* conn);
virtual ~DNP3_Analyzer();
DNP3_Base(analyzer::Analyzer* analyzer);
virtual ~DNP3_Base();
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
binpac::DNP3::DNP3_Conn* Interpreter() { return interp; }
static Analyzer* Instantiate(Connection* conn)
{ return new DNP3_Analyzer(conn); }
private:
protected:
static const int MAX_BUFFER_SIZE = 300;
struct Endpoint {
@ -35,22 +31,64 @@ private:
bool ProcessData(int len, const u_char* data, bool orig);
void ClearEndpointState(bool orig);
bool AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len);
/**
* Buffers packet data until it reaches a specified length.
* @param endp an endpoint speaking DNP3 to which data will be buffered.
* @param target_len the required length of the buffer
* @param data source buffer to copy bytes from. Will be incremented
* by the number of bytes copied by this function.
* @param len the number of bytes available in \a data. Will be decremented
* by the number of bytes copied by this function.
* @return -1 if invalid input parameters were supplied, 0 if the endpoint's
* buffer is not yet \a target_len bytes in size, or 1 the buffer is the
* required size.
*/
int AddToBuffer(Endpoint* endp, int target_len, const u_char** data, int* len);
bool ParseAppLayer(Endpoint* endp);
bool CheckCRC(int len, const u_char* data, const u_char* crc16, const char* where);
unsigned int CalcCRC(int len, const u_char* data);
binpac::DNP3::DNP3_Conn* interp;
Endpoint orig_state;
Endpoint resp_state;
static void PrecomputeCRCTable();
static bool crc_table_initialized;
static unsigned int crc_table[256];
analyzer::Analyzer* analyzer;
binpac::DNP3::DNP3_Conn* interp;
Endpoint orig_state;
Endpoint resp_state;
};
} } // namespace analyzer::*
class DNP3_TCP_Analyzer : public DNP3_Base, public tcp::TCP_ApplicationAnalyzer {
public:
DNP3_TCP_Analyzer(Connection* conn);
virtual ~DNP3_TCP_Analyzer();
virtual void Done();
virtual void DeliverStream(int len, const u_char* data, bool orig);
virtual void Undelivered(uint64 seq, int len, bool orig);
virtual void EndpointEOF(bool is_orig);
static Analyzer* Instantiate(Connection* conn)
{ return new DNP3_TCP_Analyzer(conn); }
};
class DNP3_UDP_Analyzer : public DNP3_Base, public analyzer::Analyzer {
public:
DNP3_UDP_Analyzer(Connection* conn);
virtual ~DNP3_UDP_Analyzer();
virtual void DeliverPacket(int len, const u_char* data, bool orig,
uint64 seq, const IP_Hdr* ip, int caplen);
static analyzer::Analyzer* Instantiate(Connection* conn)
{ return new DNP3_UDP_Analyzer(conn); }
};
} } // namespace analyzer::*
#endif

View file

@ -12,11 +12,12 @@ class Plugin : public plugin::Plugin {
public:
plugin::Configuration Configure()
{
AddComponent(new ::analyzer::Component("DNP3", ::analyzer::dnp3::DNP3_Analyzer::Instantiate));
AddComponent(new ::analyzer::Component("DNP3_TCP", ::analyzer::dnp3::DNP3_TCP_Analyzer::Instantiate));
AddComponent(new ::analyzer::Component("DNP3_UDP", ::analyzer::dnp3::DNP3_UDP_Analyzer::Instantiate));
plugin::Configuration config;
config.name = "Bro::DNP3";
config.description = "DNP3 analyzer";
config.description = "DNP3 UDP/TCP analyzers";
return config;
}
} plugin;

View file

@ -38,7 +38,7 @@ flow DNP3_Flow(is_orig: bool) {
return true;
%}
function get_dnp3_application_request_header(fc: uint8): bool
function get_dnp3_application_request_header(application_control: uint8, fc: uint8): bool
%{
if ( ::dnp3_application_request_header )
{
@ -46,13 +46,14 @@ flow DNP3_Flow(is_orig: bool) {
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),
application_control,
fc
);
}
return true;
%}
function get_dnp3_application_response_header(fc: uint8, iin: uint16): bool
function get_dnp3_application_response_header(application_control: uint8, fc: uint8, iin: uint16): bool
%{
if ( ::dnp3_application_response_header )
{
@ -60,6 +61,7 @@ flow DNP3_Flow(is_orig: bool) {
connection()->bro_analyzer(),
connection()->bro_analyzer()->Conn(),
is_orig(),
application_control,
fc,
iin
);
@ -743,11 +745,11 @@ refine typeattr Header_Block += &let {
};
refine typeattr DNP3_Application_Request_Header += &let {
process_request: bool = $context.flow.get_dnp3_application_request_header(function_code);
process_request: bool = $context.flow.get_dnp3_application_request_header(application_control, function_code);
};
refine typeattr DNP3_Application_Response_Header += &let {
process_request: bool = $context.flow.get_dnp3_application_response_header(function_code, internal_indications);
process_request: bool = $context.flow.get_dnp3_application_response_header(application_control, function_code, internal_indications);
};
refine typeattr Object_Header += &let {

View file

@ -90,7 +90,7 @@ type DNP3_Application_Response_Header = record {
type Request_Objects(function_code: uint8) = record {
object_header: Object_Header(function_code);
data: case (object_header.object_type_field) of {
0x0c03 -> bocmd_PM: Request_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1 ];
0x0c03 -> bocmd_PM: Request_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1*( object_header.number_of_item > ( (object_header.number_of_item / 8)*8 ) ) ];
0x3202 -> time_interval_ojbects: Request_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ object_header.number_of_item]
&check( object_header.qualifer_field == 0x0f && object_header.number_of_item == 0x01);
default -> ojbects: Request_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ object_header.number_of_item];
@ -112,10 +112,10 @@ type Request_Objects(function_code: uint8) = record {
type Response_Objects(function_code: uint8) = record {
object_header: Object_Header(function_code);
data: case (object_header.object_type_field) of {
0x0101 -> biwoflag: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1 ];
0x0301 -> diwoflag: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1 ];
0x0a01 -> bowoflag: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1 ];
0x0c03 -> bocmd_PM: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1 ];
0x0101 -> biwoflag: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1*( object_header.number_of_item > ( (object_header.number_of_item / 8)*8 ) ) ];
0x0301 -> diwoflag: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1*( object_header.number_of_item > ( (object_header.number_of_item / 8)*8 ) ) ];
0x0a01 -> bowoflag: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1*( object_header.number_of_item > ( (object_header.number_of_item / 8)*8 ) )];
0x0c03 -> bocmd_PM: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ ( object_header.number_of_item / 8 ) + 1*( object_header.number_of_item > ( (object_header.number_of_item / 8)*8 ) )];
default -> ojbects: Response_Data_Object(function_code, object_header.qualifier_field, object_header.object_type_field )[ object_header.number_of_item];
};
};

View file

@ -7,7 +7,7 @@
##
## fc: function code.
##
event dnp3_application_request_header%(c: connection, is_orig: bool, fc: count%);
event dnp3_application_request_header%(c: connection, is_orig: bool, application: count, fc: count%);
## Generated for a DNP3 response header.
##
@ -19,7 +19,7 @@ event dnp3_application_request_header%(c: connection, is_orig: bool, fc: count%)
##
## iin: internal indication number.
##
event dnp3_application_response_header%(c: connection, is_orig: bool, fc: count, iin: count%);
event dnp3_application_response_header%(c: connection, is_orig: bool, application: count, fc: count, iin: count%);
## Generated for the object header found in both DNP3 requests and responses.
##

View file

@ -9,7 +9,7 @@
##
## arg: The argument for the command (empty string if not provided).
##
## .. bro:see:: mysql_error mysql_ok mysql_server_version mysql_handshake_response
## .. bro:see:: mysql_error mysql_ok mysql_server_version mysql_handshake
event mysql_command_request%(c: connection, command: count, arg: string%);
## Generated for an unsuccessful MySQL response.
@ -23,7 +23,7 @@ event mysql_command_request%(c: connection, command: count, arg: string%);
##
## msg: Any extra details about the error (empty string if not provided).
##
## .. bro:see:: mysql_command_request mysql_ok mysql_server_version mysql_handshake_response
## .. bro:see:: mysql_command_request mysql_ok mysql_server_version mysql_handshake
event mysql_error%(c: connection, code: count, msg: string%);
## Generated for a successful MySQL response.
@ -35,7 +35,7 @@ event mysql_error%(c: connection, code: count, msg: string%);
##
## affected_rows: The number of rows that were affected.
##
## .. bro:see:: mysql_command_request mysql_error mysql_server_version mysql_handshake_response
## .. bro:see:: mysql_command_request mysql_error mysql_server_version mysql_handshake
event mysql_ok%(c: connection, affected_rows: count%);
## Generated for the initial server handshake packet, which includes the MySQL server version.
@ -47,7 +47,7 @@ event mysql_ok%(c: connection, affected_rows: count%);
##
## ver: The server version string.
##
## .. bro:see:: mysql_command_request mysql_error mysql_ok mysql_handshake_response
## .. bro:see:: mysql_command_request mysql_error mysql_ok mysql_handshake
event mysql_server_version%(c: connection, ver: string%);
## Generated for a client handshake response packet, which includes the username the client is attempting

View file

@ -287,7 +287,7 @@ void record_bif_item(const char* id, const char* type)
%left ',' ':'
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type attr_list opt_attr_list
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type attr_list opt_attr_list opt_func_attrs
%type <val> TOK_ATOM TOK_BOOL
%union {
@ -372,7 +372,13 @@ type_def_types: TOK_RECORD
{ set_definition_type(TYPE_DEF, "Table"); }
;
event_def: event_prefix opt_ws plain_head opt_attr_list
opt_func_attrs: attr_list opt_ws
{ $$ = $1; }
| /* nothing */
{ $$ = ""; }
;
event_def: event_prefix opt_ws plain_head opt_func_attrs
{ fprintf(fp_bro_init, "%s", $4); } end_of_head ';'
{
print_event_c_prototype(fp_func_h, true);
@ -380,13 +386,16 @@ event_def: event_prefix opt_ws plain_head opt_attr_list
print_event_c_body(fp_func_def);
}
func_def: func_prefix opt_ws typed_head end_of_head body
func_def: func_prefix opt_ws typed_head opt_func_attrs
{ fprintf(fp_bro_init, "%s", $4); } end_of_head body
;
enum_def: enum_def_1 enum_list TOK_RPB
enum_def: enum_def_1 enum_list TOK_RPB opt_attr_list
{
// First, put an end to the enum type decl.
fprintf(fp_bro_init, "};\n");
fprintf(fp_bro_init, "} ");
fprintf(fp_bro_init, "%s", $4);
fprintf(fp_bro_init, ";\n");
if ( decl.module_name != GLOBAL_MODULE_NAME )
fprintf(fp_netvar_h, "}; } }\n");
else

View file

@ -492,18 +492,22 @@ void File::EndOfFile()
if ( done )
return;
if ( ! did_mime_type &&
LookupFieldDefaultCount(missing_bytes_idx) == 0 )
DetectMIME();
analyzers.DrainModifications();
if ( file_reassembler )
{
file_reassembler->Flush();
analyzers.DrainModifications();
}
// Mark the bof_buffer as full in case it isn't yet
// so that the whole thing can be flushed out to
// any stream analyzers.
if ( ! bof_buffer.full )
{
bof_buffer.full = true;
DeliverStream((const u_char*) "", 0);
}
analyzers.DrainModifications();
done = true;
file_analysis::Analyzer* a = 0;

View file

@ -12,6 +12,11 @@ FileReassembler::FileReassembler(File *f, uint64 starting_offset)
{
}
FileReassembler::FileReassembler()
: Reassembler(), the_file(0), flushing(false)
{
}
FileReassembler::~FileReassembler()
{
}

View file

@ -48,7 +48,7 @@ public:
{ return flushing; }
protected:
FileReassembler() { }
FileReassembler();
DECLARE_SERIAL(FileReassembler);

View file

@ -29,7 +29,7 @@ function Files::__disable_reassembly%(file_id: string%): bool
return new Val(result, TYPE_BOOL);
%}
## :bro:see:`Files::set_reassembly_buffer`.
## :bro:see:`Files::set_reassembly_buffer_size`.
function Files::__set_reassembly_buffer%(file_id: string, max: count%): bool
%{
bool result = file_mgr->SetReassemblyBuffer(file_id->CheckString(), max);

View file

@ -2,7 +2,7 @@
// See the file "COPYING" in the main distribution directory for copyright.
%}
%expect 75
%expect 78
%token TOK_ADD TOK_ADD_TO TOK_ADDR TOK_ANY
%token TOK_ATENDIF TOK_ATELSE TOK_ATIF TOK_ATIFDEF TOK_ATIFNDEF
@ -24,7 +24,7 @@
%token TOK_ATTR_PERSISTENT TOK_ATTR_SYNCHRONIZED
%token TOK_ATTR_RAW_OUTPUT TOK_ATTR_MERGEABLE
%token TOK_ATTR_PRIORITY TOK_ATTR_LOG TOK_ATTR_ERROR_HANDLER
%token TOK_ATTR_TYPE_COLUMN
%token TOK_ATTR_TYPE_COLUMN TOK_ATTR_DEPRECATED
%token TOK_DEBUG
@ -44,7 +44,7 @@
%right '!'
%left '$' '[' ']' '(' ')' TOK_HAS_FIELD TOK_HAS_ATTR
%type <b> opt_no_test opt_no_test_block
%type <b> opt_no_test opt_no_test_block opt_deprecated
%type <str> TOK_ID TOK_PATTERN_TEXT single_pattern
%type <id> local_id global_id def_global_id event_id global_or_event_id resolve_id begin_func
%type <id_l> local_id_list
@ -227,6 +227,18 @@ static bool expr_is_table_type_name(const Expr* expr)
return false;
}
static bool has_attr(const attr_list* al, attr_tag tag)
{
if ( ! al )
return false;
for ( int i = 0; i < al->length(); ++i )
if ( (*al)[i]->Tag() == tag )
return true;
return false;
}
%}
%union {
@ -671,6 +683,9 @@ expr:
}
else
$$ = new NameExpr(id);
if ( id->IsDeprecated() )
reporter->Warning("deprecated (%s)", id->Name());
}
}
@ -759,7 +774,7 @@ enum_body_elem:
error messages if someboy tries to use constant variables as
enumerator.
*/
TOK_ID '=' TOK_CONSTANT
TOK_ID '=' TOK_CONSTANT opt_deprecated
{
set_location(@1, @3);
assert(cur_enum_type);
@ -768,7 +783,7 @@ enum_body_elem:
reporter->Error("enumerator is not a count constant");
else
cur_enum_type->AddName(current_module, $1,
$3->InternalUnsigned(), is_export);
$3->InternalUnsigned(), is_export, $4);
}
| TOK_ID '=' '-' TOK_CONSTANT
@ -780,11 +795,11 @@ enum_body_elem:
reporter->Error("enumerator is not a count constant");
}
| TOK_ID
| TOK_ID opt_deprecated
{
set_location(@1);
assert(cur_enum_type);
cur_enum_type->AddName(current_module, $1, is_export);
cur_enum_type->AddName(current_module, $1, is_export, $2);
}
;
@ -963,7 +978,12 @@ type:
$$ = error_type();
}
else
{
Ref($$);
if ( $1->IsDeprecated() )
reporter->Warning("deprecated (%s)", $1->Name());
}
}
;
@ -1139,6 +1159,9 @@ func_body:
{
saved_in_init.push_back(in_init);
in_init = 0;
if ( has_attr($1, ATTR_DEPRECATED) )
current_scope()->ScopeID()->MakeDeprecated();
}
stmt_list
@ -1265,6 +1288,8 @@ attr:
{ $$ = new Attr(ATTR_LOG); }
| TOK_ATTR_ERROR_HANDLER
{ $$ = new Attr(ATTR_ERROR_HANDLER); }
| TOK_ATTR_DEPRECATED
{ $$ = new Attr(ATTR_DEPRECATED); }
;
stmt:
@ -1450,6 +1475,10 @@ event:
{
set_location(@1, @4);
$$ = new EventExpr($1, $3);
ID* id = lookup_ID($1, current_module.c_str());
if ( id && id->IsDeprecated() )
reporter->Warning("deprecated (%s)", id->Name());
}
;
@ -1556,6 +1585,15 @@ global_or_event_id:
if ( ! $$->IsGlobal() )
$$->Error("already a local identifier");
if ( $$->IsDeprecated() )
{
BroType* t = $$->Type();
if ( t->Tag() != TYPE_FUNC ||
t->AsFuncType()->Flavor() != FUNC_FLAVOR_FUNCTION )
reporter->Warning("deprecated (%s)", $$->Name());
}
delete [] $1;
}
@ -1597,6 +1635,12 @@ opt_no_test_block:
|
{ $$ = false; }
opt_deprecated:
TOK_ATTR_DEPRECATED
{ $$ = true; }
|
{ $$ = false; }
%%
int yyerror(const char msg[])

View file

@ -243,7 +243,8 @@ void ComponentManager<T, C>::RegisterComponent(C* component,
// Install an identfier for enum value
string id = fmt("%s%s", prefix.c_str(), cname.c_str());
tag_enum_type->AddName(module, id.c_str(),
component->Tag().AsEnumVal()->InternalInt(), true);
component->Tag().AsEnumVal()->InternalInt(), true,
false);
}
} // namespace plugin

View file

@ -260,6 +260,7 @@ when return TOK_WHEN;
&create_expire return TOK_ATTR_EXPIRE_CREATE;
&default return TOK_ATTR_DEFAULT;
&delete_func return TOK_ATTR_DEL_FUNC;
&deprecated return TOK_ATTR_DEPRECATED;
&raw_output return TOK_ATTR_RAW_OUTPUT;
&encrypt return TOK_ATTR_ENCRYPT;
&error_handler return TOK_ATTR_ERROR_HANDLER;

View file

@ -130,7 +130,7 @@ BroString* cat_string_array_n(TableVal* tbl, int start, int end)
## .. bro:see:: cat cat_sep string_cat cat_string_array_n
## fmt
## join_string_vec join_string_array
function cat_string_array%(a: string_array%): string
function cat_string_array%(a: string_array%): string &deprecated
%{
TableVal* tbl = a->AsTableVal();
return new StringVal(cat_string_array_n(tbl, 1, a->AsTable()->Length()));
@ -149,7 +149,7 @@ function cat_string_array%(a: string_array%): string
## .. bro:see:: cat string_cat cat_string_array
## fmt
## join_string_vec join_string_array
function cat_string_array_n%(a: string_array, start: count, end: count%): string
function cat_string_array_n%(a: string_array, start: count, end: count%): string &deprecated
%{
TableVal* tbl = a->AsTableVal();
return new StringVal(cat_string_array_n(tbl, start, end));
@ -168,7 +168,7 @@ function cat_string_array_n%(a: string_array, start: count, end: count%): string
## .. bro:see:: cat cat_sep string_cat cat_string_array cat_string_array_n
## fmt
## join_string_vec
function join_string_array%(sep: string, a: string_array%): string
function join_string_array%(sep: string, a: string_array%): string &deprecated
%{
vector<const BroString*> vs;
TableVal* tbl = a->AsTableVal();
@ -230,7 +230,7 @@ function join_string_vec%(vec: string_vec, sep: string%): string
## Returns: A sorted copy of *a*.
##
## .. bro:see:: sort
function sort_string_array%(a: string_array%): string_array
function sort_string_array%(a: string_array%): string_array &deprecated
%{
TableVal* tbl = a->AsTableVal();
int n = a->AsTable()->Length();
@ -338,6 +338,62 @@ static int match_prefix(int s_len, const char* s, int t_len, const char* t)
return 1;
}
VectorVal* do_split_string(StringVal* str_val, RE_Matcher* re, int incl_sep,
int max_num_sep)
{
VectorVal* rval = new VectorVal(string_vec);
const u_char* s = str_val->Bytes();
int n = str_val->Len();
const u_char* end_of_s = s + n;
int num = 0;
int num_sep = 0;
int offset = 0;
while ( n >= 0 )
{
offset = 0;
// Find next match offset.
int end_of_match = 0;
while ( n > 0 &&
(end_of_match = re->MatchPrefix(s + offset, n)) <= 0 )
{
// Move on to next byte.
++offset;
--n;
}
if ( max_num_sep && num_sep >= max_num_sep )
{
offset = end_of_s - s;
n=0;
}
rval->Assign(num++, new StringVal(offset, (const char*) s));
// No more separators will be needed if this is the end of string.
if ( n <= 0 )
break;
if ( incl_sep )
{ // including the part that matches the pattern
rval->Assign(num++, new StringVal(end_of_match, (const char*) s+offset));
}
if ( max_num_sep && num_sep >= max_num_sep )
break;
++num_sep;
n -= end_of_match;
s += offset + end_of_match;;
if ( s > end_of_s )
reporter->InternalError("RegMatch in split goes beyond the string");
}
return rval;
}
Val* do_split(StringVal* str_val, RE_Matcher* re, int incl_sep, int max_num_sep)
{
TableVal* a = new TableVal(string_array);
@ -493,17 +549,33 @@ Val* do_sub(StringVal* str_val, RE_Matcher* re, StringVal* repl, int do_all)
## Returns: An array of strings where each element corresponds to a substring
## in *str* separated by *re*.
##
## .. bro:see:: split1 split_all split_n str_split
## .. bro:see:: split1 split_all split_n str_split split_string1 split_string_all split_string_n str_split
##
## .. note:: The returned table starts at index 1. Note that conceptually the
## return value is meant to be a vector and this might change in the
## future.
##
function split%(str: string, re: pattern%): string_array
function split%(str: string, re: pattern%): string_array &deprecated
%{
return do_split(str, re, 0, 0);
%}
## Splits a string into an array of strings according to a pattern.
##
## str: The string to split.
##
## re: The pattern describing the element separator in *str*.
##
## Returns: An array of strings where each element corresponds to a substring
## in *str* separated by *re*.
##
## .. bro:see:: split_string1 split_string_all split_string_n str_split
##
function split_string%(str: string, re: pattern%): string_vec
%{
return do_split_string(str, re, 0, 0);
%}
## Splits a string *once* into a two-element array of strings according to a
## pattern. This function is the same as :bro:id:`split`, but *str* is only
## split once (if possible) at the earliest position and an array of two strings
@ -518,12 +590,32 @@ function split%(str: string, re: pattern%): string_array
## second everything after *re*. An array of one string is returned
## when *s* cannot be split.
##
## .. bro:see:: split split_all split_n str_split
function split1%(str: string, re: pattern%): string_array
## .. bro:see:: split split_all split_n str_split split_string split_string_all split_string_n str_split
function split1%(str: string, re: pattern%): string_array &deprecated
%{
return do_split(str, re, 0, 1);
%}
## Splits a string *once* into a two-element array of strings according to a
## pattern. This function is the same as :bro:id:`split_string`, but *str* is
## only split once (if possible) at the earliest position and an array of two
## strings is returned.
##
## str: The string to split.
##
## re: The pattern describing the separator to split *str* in two pieces.
##
## Returns: An array of strings with two elements in which the first represents
## the substring in *str* up to the first occurence of *re*, and the
## second everything after *re*. An array of one string is returned
## when *s* cannot be split.
##
## .. bro:see:: split_string split_string_all split_string_n str_split
function split_string1%(str: string, re: pattern%): string_vec
%{
return do_split_string(str, re, 0, 1);
%}
## Splits a string into an array of strings according to a pattern. This
## function is the same as :bro:id:`split`, except that the separators are
## returned as well. For example, ``split_all("a-b--cd", /(\-)+/)`` returns
@ -538,12 +630,32 @@ function split1%(str: string, re: pattern%): string_array
## to a substring in *str* of the part not matching *re* (odd-indexed)
## and the part that matches *re* (even-indexed).
##
## .. bro:see:: split split1 split_n str_split
function split_all%(str: string, re: pattern%): string_array
## .. bro:see:: split split1 split_n str_split split_string split_string1 split_string_n str_split
function split_all%(str: string, re: pattern%): string_array &deprecated
%{
return do_split(str, re, 1, 0);
%}
## Splits a string into an array of strings according to a pattern. This
## function is the same as :bro:id:`split_string`, except that the separators
## are returned as well. For example, ``split_string_all("a-b--cd", /(\-)+/)``
## returns ``{"a", "-", "b", "--", "cd"}``: odd-indexed elements do match the
## pattern and even-indexed ones do not.
##
## str: The string to split.
##
## re: The pattern describing the element separator in *str*.
##
## Returns: An array of strings where each two successive elements correspond
## to a substring in *str* of the part not matching *re* (even-indexed)
## and the part that matches *re* (odd-indexed).
##
## .. bro:see:: split_string split_string1 split_string_n str_split
function split_string_all%(str: string, re: pattern%): string_vec
%{
return do_split_string(str, re, 1, 0);
%}
## Splits a string a given number of times into an array of strings according
## to a pattern. This function is similar to :bro:id:`split1` and
## :bro:id:`split_all`, but with customizable behavior with respect to
@ -563,13 +675,39 @@ function split_all%(str: string, re: pattern%): string_array
## not matching *re* (odd-indexed) and the part that matches *re*
## (even-indexed).
##
## .. bro:see:: split split1 split_all str_split
## .. bro:see:: split split1 split_all str_split split_string split_string1 split_string_all str_split
function split_n%(str: string, re: pattern,
incl_sep: bool, max_num_sep: count%): string_array
incl_sep: bool, max_num_sep: count%): string_array &deprecated
%{
return do_split(str, re, incl_sep, max_num_sep);
%}
## Splits a string a given number of times into an array of strings according
## to a pattern. This function is similar to :bro:id:`split_string1` and
## :bro:id:`split_string_all`, but with customizable behavior with respect to
## including separators in the result and the number of times to split.
##
## str: The string to split.
##
## re: The pattern describing the element separator in *str*.
##
## incl_sep: A flag indicating whether to include the separator matches in the
## result (as in :bro:id:`split_string_all`).
##
## max_num_sep: The number of times to split *str*.
##
## Returns: An array of strings where, if *incl_sep* is true, each two
## successive elements correspond to a substring in *str* of the part
## not matching *re* (event-indexed) and the part that matches *re*
## (odd-indexed).
##
## .. bro:see:: split_string split_string1 split_string_all str_split
function split_string_n%(str: string, re: pattern,
incl_sep: bool, max_num_sep: count%): string_vec
%{
return do_split_string(str, re, incl_sep, max_num_sep);
%}
## Substitutes a given replacement string for the first occurrence of a pattern
## in a given string.
##