mirror of
https://github.com/zeek/zeek.git
synced 2025-10-14 20:48:21 +00:00
Merge remote-tracking branch 'origin/master' into topic/vladg/kerberos
This commit is contained in:
commit
7e1fcb1a10
123 changed files with 7470 additions and 1344 deletions
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
35
src/Expr.cc
35
src/Expr.cc
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
10
src/ID.cc
10
src/ID.cc
|
@ -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 )
|
||||
|
|
5
src/ID.h
5
src/ID.h
|
@ -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;
|
||||
|
|
14
src/Type.cc
14
src/Type.cc
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
##
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -12,6 +12,11 @@ FileReassembler::FileReassembler(File *f, uint64 starting_offset)
|
|||
{
|
||||
}
|
||||
|
||||
FileReassembler::FileReassembler()
|
||||
: Reassembler(), the_file(0), flushing(false)
|
||||
{
|
||||
}
|
||||
|
||||
FileReassembler::~FileReassembler()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
{ return flushing; }
|
||||
|
||||
protected:
|
||||
FileReassembler() { }
|
||||
FileReassembler();
|
||||
|
||||
DECLARE_SERIAL(FileReassembler);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
58
src/parse.y
58
src/parse.y
|
@ -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[])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
162
src/strings.bif
162
src/strings.bif
|
@ -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.
|
||||
##
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue