mirror of
https://github.com/zeek/zeek.git
synced 2025-10-14 04:28:20 +00:00
Merge remote-tracking branch 'origin/master' into topic/bernhard/input-logging-commmon-functions
Conflicts: src/input/readers/Ascii.cc
This commit is contained in:
commit
1b0bb5063a
66 changed files with 2367 additions and 564 deletions
|
@ -361,6 +361,7 @@ set(bro_SRCS
|
|||
NetVar.cc
|
||||
NetbiosSSN.cc
|
||||
Obj.cc
|
||||
OpaqueVal.cc
|
||||
OSFinger.cc
|
||||
PacketFilter.cc
|
||||
PacketSort.cc
|
||||
|
|
101
src/Expr.cc
101
src/Expr.cc
|
@ -229,10 +229,15 @@ bool Expr::DoUnserialize(UnserialInfo* info)
|
|||
}
|
||||
|
||||
|
||||
NameExpr::NameExpr(ID* arg_id) : Expr(EXPR_NAME)
|
||||
NameExpr::NameExpr(ID* arg_id, bool const_init) : Expr(EXPR_NAME)
|
||||
{
|
||||
id = arg_id;
|
||||
SetType(id->Type()->Ref());
|
||||
in_const_init = const_init;
|
||||
|
||||
if ( id->AsType() )
|
||||
SetType(new TypeType(id->AsType()));
|
||||
else
|
||||
SetType(id->Type()->Ref());
|
||||
|
||||
EventHandler* h = event_registry->Lookup(id->Name());
|
||||
if ( h )
|
||||
|
@ -287,6 +292,9 @@ Expr* NameExpr::MakeLvalue()
|
|||
if ( id->AsType() )
|
||||
ExprError("Type name is not an lvalue");
|
||||
|
||||
if ( id->IsConst() && ! in_const_init )
|
||||
ExprError("const is not a modifiable lvalue");
|
||||
|
||||
return new RefExpr(this);
|
||||
}
|
||||
|
||||
|
@ -337,9 +345,11 @@ bool NameExpr::DoSerialize(SerialInfo* info) const
|
|||
|
||||
// Write out just the name of the function if requested.
|
||||
if ( info->globals_as_names && id->IsGlobal() )
|
||||
return SERIALIZE('n') && SERIALIZE(id->Name());
|
||||
return SERIALIZE('n') && SERIALIZE(id->Name()) &&
|
||||
SERIALIZE(in_const_init);
|
||||
else
|
||||
return SERIALIZE('f') && id->Serialize(info);
|
||||
return SERIALIZE('f') && id->Serialize(info) &&
|
||||
SERIALIZE(in_const_init);
|
||||
}
|
||||
|
||||
bool NameExpr::DoUnserialize(UnserialInfo* info)
|
||||
|
@ -370,6 +380,9 @@ bool NameExpr::DoUnserialize(UnserialInfo* info)
|
|||
if ( ! id )
|
||||
return false;
|
||||
|
||||
if ( ! UNSERIALIZE(&in_const_init) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2788,22 +2801,43 @@ bool AssignExpr::DoUnserialize(UnserialInfo* info)
|
|||
return UNSERIALIZE(&is_init);
|
||||
}
|
||||
|
||||
IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2)
|
||||
IndexExpr::IndexExpr(Expr* arg_op1, ListExpr* arg_op2, bool is_slice)
|
||||
: BinaryExpr(EXPR_INDEX, arg_op1, arg_op2)
|
||||
{
|
||||
if ( IsError() )
|
||||
return;
|
||||
|
||||
if ( is_slice )
|
||||
{
|
||||
if ( ! IsString(op1->Type()->Tag()) )
|
||||
ExprError("slice notation indexing only supported for strings currently");
|
||||
}
|
||||
|
||||
else if ( IsString(op1->Type()->Tag()) )
|
||||
{
|
||||
if ( arg_op2->Exprs().length() != 1 )
|
||||
ExprError("invalid string index expression");
|
||||
}
|
||||
|
||||
if ( IsError() )
|
||||
return;
|
||||
|
||||
int match_type = op1->Type()->MatchesIndex(arg_op2);
|
||||
if ( match_type == DOES_NOT_MATCH_INDEX )
|
||||
SetError("not an index type");
|
||||
|
||||
else if ( ! op1->Type()->YieldType() )
|
||||
{
|
||||
if ( IsString(op1->Type()->Tag()) &&
|
||||
match_type == MATCHES_INDEX_SCALAR )
|
||||
SetType(base_type(TYPE_STRING));
|
||||
else
|
||||
// It's a set - so indexing it yields void. We don't
|
||||
// directly generate an error message, though, since this
|
||||
// expression might be part of an add/delete statement,
|
||||
// rather than yielding a value.
|
||||
SetType(base_type(TYPE_VOID));
|
||||
SetType(base_type(TYPE_VOID));
|
||||
}
|
||||
|
||||
else if ( match_type == MATCHES_INDEX_SCALAR )
|
||||
SetType(op1->Type()->YieldType()->Ref());
|
||||
|
@ -2879,6 +2913,9 @@ void IndexExpr::Delete(Frame* f)
|
|||
|
||||
Expr* IndexExpr::MakeLvalue()
|
||||
{
|
||||
if ( IsString(op1->Type()->Tag()) )
|
||||
ExprError("cannot assign to string index expression");
|
||||
|
||||
return new RefExpr(this);
|
||||
}
|
||||
|
||||
|
@ -2952,10 +2989,37 @@ Val* IndexExpr::Fold(Val* v1, Val* v2) const
|
|||
|
||||
Val* v = 0;
|
||||
|
||||
if ( v1->Type()->Tag() == TYPE_VECTOR )
|
||||
switch ( v1->Type()->Tag() ) {
|
||||
case TYPE_VECTOR:
|
||||
v = v1->AsVectorVal()->Lookup(v2);
|
||||
else
|
||||
break;
|
||||
|
||||
case TYPE_TABLE:
|
||||
v = v1->AsTableVal()->Lookup(v2);
|
||||
break;
|
||||
|
||||
case TYPE_STRING:
|
||||
{
|
||||
const ListVal* lv = v2->AsListVal();
|
||||
const BroString* s = v1->AsString();
|
||||
int len = s->Len();
|
||||
bro_int_t first = lv->Index(0)->AsInt();
|
||||
bro_int_t last = lv->Length() > 1 ? lv->Index(1)->AsInt() : first;
|
||||
|
||||
if ( first < 0 )
|
||||
first += len;
|
||||
|
||||
if ( last < 0 )
|
||||
last += len;
|
||||
|
||||
BroString* substring = s->GetSubstring(first, last - first + 1);
|
||||
return new StringVal(substring ? substring : new BroString(""));
|
||||
}
|
||||
|
||||
default:
|
||||
Error("type cannot be indexed");
|
||||
break;
|
||||
}
|
||||
|
||||
if ( v )
|
||||
return v->Ref();
|
||||
|
@ -2982,14 +3046,25 @@ void IndexExpr::Assign(Frame* f, Val* v, Opcode op)
|
|||
return;
|
||||
}
|
||||
|
||||
if ( v1->Type()->Tag() == TYPE_VECTOR )
|
||||
{
|
||||
switch ( v1->Type()->Tag() ) {
|
||||
case TYPE_VECTOR:
|
||||
if ( ! v1->AsVectorVal()->Assign(v2, v, this, op) )
|
||||
Internal("assignment failed");
|
||||
}
|
||||
break;
|
||||
|
||||
else if ( ! v1->AsTableVal()->Assign(v2, v, op) )
|
||||
Internal("assignment failed");
|
||||
case TYPE_TABLE:
|
||||
if ( ! v1->AsTableVal()->Assign(v2, v, op) )
|
||||
Internal("assignment failed");
|
||||
break;
|
||||
|
||||
case TYPE_STRING:
|
||||
Internal("assignment via string index accessor not allowed");
|
||||
break;
|
||||
|
||||
default:
|
||||
Internal("bad index expression type in assignment");
|
||||
break;
|
||||
}
|
||||
|
||||
Unref(v1);
|
||||
Unref(v2);
|
||||
|
|
|
@ -198,7 +198,7 @@ protected:
|
|||
|
||||
class NameExpr : public Expr {
|
||||
public:
|
||||
NameExpr(ID* id);
|
||||
NameExpr(ID* id, bool const_init = false);
|
||||
~NameExpr();
|
||||
|
||||
ID* Id() const { return id; }
|
||||
|
@ -220,6 +220,7 @@ protected:
|
|||
DECLARE_SERIAL(NameExpr);
|
||||
|
||||
ID* id;
|
||||
bool in_const_init;
|
||||
};
|
||||
|
||||
class ConstExpr : public Expr {
|
||||
|
@ -645,7 +646,7 @@ protected:
|
|||
|
||||
class IndexExpr : public BinaryExpr {
|
||||
public:
|
||||
IndexExpr(Expr* op1, ListExpr* op2);
|
||||
IndexExpr(Expr* op1, ListExpr* op2, bool is_slice = false);
|
||||
|
||||
int CanAdd() const;
|
||||
int CanDel() const;
|
||||
|
|
|
@ -282,13 +282,14 @@ Val* BroFunc::Call(val_list* args, Frame* parent) const
|
|||
#ifdef PROFILE_BRO_FUNCTIONS
|
||||
DEBUG_MSG("Function: %s\n", id->Name());
|
||||
#endif
|
||||
if ( ! bodies.size() )
|
||||
if ( ! bodies.size() )
|
||||
{
|
||||
// Can only happen for events and hooks.
|
||||
assert(Flavor() == FUNC_FLAVOR_EVENT || Flavor() == FUNC_FLAVOR_HOOK);
|
||||
loop_over_list(*args, i)
|
||||
Unref((*args)[i]);
|
||||
return 0 ;
|
||||
|
||||
return Flavor() == FUNC_FLAVOR_HOOK ? new Val(true, TYPE_BOOL) : 0;
|
||||
}
|
||||
|
||||
SegmentProfiler(segment_logger, location);
|
||||
|
|
501
src/OpaqueVal.cc
Normal file
501
src/OpaqueVal.cc
Normal file
|
@ -0,0 +1,501 @@
|
|||
#include "OpaqueVal.h"
|
||||
#include "Reporter.h"
|
||||
#include "Serializer.h"
|
||||
|
||||
bool HashVal::IsValid() const
|
||||
{
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool HashVal::Init()
|
||||
{
|
||||
if ( valid )
|
||||
return false;
|
||||
|
||||
valid = DoInit();
|
||||
return valid;
|
||||
}
|
||||
|
||||
StringVal* HashVal::Get()
|
||||
{
|
||||
if ( ! valid )
|
||||
return new StringVal("");
|
||||
|
||||
StringVal* result = DoGet();
|
||||
valid = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool HashVal::Feed(const void* data, size_t size)
|
||||
{
|
||||
if ( valid )
|
||||
return DoFeed(data, size);
|
||||
|
||||
reporter->InternalError("invalid opaque hash value");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HashVal::DoInit()
|
||||
{
|
||||
assert(! "missing implementation of DoInit()");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HashVal::DoFeed(const void*, size_t)
|
||||
{
|
||||
assert(! "missing implementation of DoFeed()");
|
||||
return false;
|
||||
}
|
||||
|
||||
StringVal* HashVal::DoGet()
|
||||
{
|
||||
assert(! "missing implementation of DoGet()");
|
||||
return new StringVal("");
|
||||
}
|
||||
|
||||
HashVal::HashVal(OpaqueType* t) : OpaqueVal(t)
|
||||
{
|
||||
valid = false;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(HashVal, SER_HASH_VAL);
|
||||
|
||||
bool HashVal::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_HASH_VAL, OpaqueVal);
|
||||
return SERIALIZE(valid);
|
||||
}
|
||||
|
||||
bool HashVal::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(OpaqueVal);
|
||||
return UNSERIALIZE(&valid);
|
||||
}
|
||||
|
||||
void MD5Val::digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH])
|
||||
{
|
||||
MD5_CTX h;
|
||||
md5_init(&h);
|
||||
|
||||
loop_over_list(vlist, i)
|
||||
{
|
||||
Val* v = vlist[i];
|
||||
if ( v->Type()->Tag() == TYPE_STRING )
|
||||
{
|
||||
const BroString* str = v->AsString();
|
||||
md5_update(&h, str->Bytes(), str->Len());
|
||||
}
|
||||
else
|
||||
{
|
||||
ODesc d(DESC_BINARY);
|
||||
v->Describe(&d);
|
||||
md5_update(&h, (const u_char *) d.Bytes(), d.Len());
|
||||
}
|
||||
}
|
||||
|
||||
md5_final(&h, result);
|
||||
}
|
||||
|
||||
void MD5Val::hmac(val_list& vlist,
|
||||
u_char key[MD5_DIGEST_LENGTH],
|
||||
u_char result[MD5_DIGEST_LENGTH])
|
||||
{
|
||||
digest(vlist, result);
|
||||
for ( int i = 0; i < MD5_DIGEST_LENGTH; ++i )
|
||||
result[i] ^= key[i];
|
||||
|
||||
MD5(result, MD5_DIGEST_LENGTH, result);
|
||||
}
|
||||
|
||||
bool MD5Val::DoInit()
|
||||
{
|
||||
assert(! IsValid());
|
||||
md5_init(&ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MD5Val::DoFeed(const void* data, size_t size)
|
||||
{
|
||||
if ( ! IsValid() )
|
||||
return false;
|
||||
|
||||
md5_update(&ctx, data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
StringVal* MD5Val::DoGet()
|
||||
{
|
||||
if ( ! IsValid() )
|
||||
return new StringVal("");
|
||||
|
||||
u_char digest[MD5_DIGEST_LENGTH];
|
||||
md5_final(&ctx, digest);
|
||||
return new StringVal(md5_digest_print(digest));
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(MD5Val, SER_MD5_VAL);
|
||||
|
||||
bool MD5Val::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_MD5_VAL, HashVal);
|
||||
|
||||
if ( ! IsValid() )
|
||||
return true;
|
||||
|
||||
if ( ! (SERIALIZE(ctx.A) &&
|
||||
SERIALIZE(ctx.B) &&
|
||||
SERIALIZE(ctx.C) &&
|
||||
SERIALIZE(ctx.D) &&
|
||||
SERIALIZE(ctx.Nl) &&
|
||||
SERIALIZE(ctx.Nh)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < MD5_LBLOCK; ++i )
|
||||
{
|
||||
if ( ! SERIALIZE(ctx.data[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! SERIALIZE(ctx.num) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MD5Val::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(HashVal);
|
||||
|
||||
if ( ! IsValid() )
|
||||
return true;
|
||||
|
||||
if ( ! (UNSERIALIZE(&ctx.A) &&
|
||||
UNSERIALIZE(&ctx.B) &&
|
||||
UNSERIALIZE(&ctx.C) &&
|
||||
UNSERIALIZE(&ctx.D) &&
|
||||
UNSERIALIZE(&ctx.Nl) &&
|
||||
UNSERIALIZE(&ctx.Nh)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < MD5_LBLOCK; ++i )
|
||||
{
|
||||
if ( ! UNSERIALIZE(&ctx.data[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! UNSERIALIZE(&ctx.num) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHA1Val::digest(val_list& vlist, u_char result[SHA_DIGEST_LENGTH])
|
||||
{
|
||||
SHA_CTX h;
|
||||
sha1_init(&h);
|
||||
|
||||
loop_over_list(vlist, i)
|
||||
{
|
||||
Val* v = vlist[i];
|
||||
if ( v->Type()->Tag() == TYPE_STRING )
|
||||
{
|
||||
const BroString* str = v->AsString();
|
||||
sha1_update(&h, str->Bytes(), str->Len());
|
||||
}
|
||||
else
|
||||
{
|
||||
ODesc d(DESC_BINARY);
|
||||
v->Describe(&d);
|
||||
sha1_update(&h, (const u_char *) d.Bytes(), d.Len());
|
||||
}
|
||||
}
|
||||
|
||||
sha1_final(&h, result);
|
||||
}
|
||||
|
||||
bool SHA1Val::DoInit()
|
||||
{
|
||||
assert(! IsValid());
|
||||
sha1_init(&ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHA1Val::DoFeed(const void* data, size_t size)
|
||||
{
|
||||
if ( ! IsValid() )
|
||||
return false;
|
||||
|
||||
sha1_update(&ctx, data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
StringVal* SHA1Val::DoGet()
|
||||
{
|
||||
if ( ! IsValid() )
|
||||
return new StringVal("");
|
||||
|
||||
u_char digest[SHA_DIGEST_LENGTH];
|
||||
sha1_final(&ctx, digest);
|
||||
return new StringVal(sha1_digest_print(digest));
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(SHA1Val, SER_SHA1_VAL);
|
||||
|
||||
bool SHA1Val::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_SHA1_VAL, HashVal);
|
||||
|
||||
if ( ! IsValid() )
|
||||
return true;
|
||||
|
||||
if ( ! (SERIALIZE(ctx.h0) &&
|
||||
SERIALIZE(ctx.h1) &&
|
||||
SERIALIZE(ctx.h2) &&
|
||||
SERIALIZE(ctx.h3) &&
|
||||
SERIALIZE(ctx.h4) &&
|
||||
SERIALIZE(ctx.Nl) &&
|
||||
SERIALIZE(ctx.Nh)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < SHA_LBLOCK; ++i )
|
||||
{
|
||||
if ( ! SERIALIZE(ctx.data[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! SERIALIZE(ctx.num) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHA1Val::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(HashVal);
|
||||
|
||||
if ( ! IsValid() )
|
||||
return true;
|
||||
|
||||
if ( ! (UNSERIALIZE(&ctx.h0) &&
|
||||
UNSERIALIZE(&ctx.h1) &&
|
||||
UNSERIALIZE(&ctx.h2) &&
|
||||
UNSERIALIZE(&ctx.h3) &&
|
||||
UNSERIALIZE(&ctx.h4) &&
|
||||
UNSERIALIZE(&ctx.Nl) &&
|
||||
UNSERIALIZE(&ctx.Nh)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < SHA_LBLOCK; ++i )
|
||||
{
|
||||
if ( ! UNSERIALIZE(&ctx.data[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! UNSERIALIZE(&ctx.num) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SHA256Val::digest(val_list& vlist, u_char result[SHA256_DIGEST_LENGTH])
|
||||
{
|
||||
SHA256_CTX h;
|
||||
sha256_init(&h);
|
||||
|
||||
loop_over_list(vlist, i)
|
||||
{
|
||||
Val* v = vlist[i];
|
||||
if ( v->Type()->Tag() == TYPE_STRING )
|
||||
{
|
||||
const BroString* str = v->AsString();
|
||||
sha256_update(&h, str->Bytes(), str->Len());
|
||||
}
|
||||
else
|
||||
{
|
||||
ODesc d(DESC_BINARY);
|
||||
v->Describe(&d);
|
||||
sha256_update(&h, (const u_char *) d.Bytes(), d.Len());
|
||||
}
|
||||
}
|
||||
|
||||
sha256_final(&h, result);
|
||||
}
|
||||
|
||||
bool SHA256Val::DoInit()
|
||||
{
|
||||
assert( ! IsValid() );
|
||||
sha256_init(&ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHA256Val::DoFeed(const void* data, size_t size)
|
||||
{
|
||||
if ( ! IsValid() )
|
||||
return false;
|
||||
|
||||
sha256_update(&ctx, data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
StringVal* SHA256Val::DoGet()
|
||||
{
|
||||
if ( ! IsValid() )
|
||||
return new StringVal("");
|
||||
|
||||
u_char digest[SHA256_DIGEST_LENGTH];
|
||||
sha256_final(&ctx, digest);
|
||||
return new StringVal(sha256_digest_print(digest));
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(SHA256Val, SER_SHA256_VAL);
|
||||
|
||||
bool SHA256Val::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_SHA256_VAL, HashVal);
|
||||
|
||||
if ( ! IsValid() )
|
||||
return true;
|
||||
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
if ( ! SERIALIZE(ctx.h[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (SERIALIZE(ctx.Nl) &&
|
||||
SERIALIZE(ctx.Nh)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < SHA_LBLOCK; ++i )
|
||||
{
|
||||
if ( ! SERIALIZE(ctx.data[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (SERIALIZE(ctx.num) &&
|
||||
SERIALIZE(ctx.md_len)) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHA256Val::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(HashVal);
|
||||
|
||||
if ( ! IsValid() )
|
||||
return true;
|
||||
|
||||
for ( int i = 0; i < 8; ++i )
|
||||
{
|
||||
if ( ! UNSERIALIZE(&ctx.h[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (UNSERIALIZE(&ctx.Nl) &&
|
||||
UNSERIALIZE(&ctx.Nh)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < SHA_LBLOCK; ++i )
|
||||
{
|
||||
if ( ! UNSERIALIZE(&ctx.data[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ( ! (UNSERIALIZE(&ctx.num) &&
|
||||
UNSERIALIZE(&ctx.md_len)) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool EntropyVal::Feed(const void* data, size_t size)
|
||||
{
|
||||
state.add(data, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntropyVal::Get(double *r_ent, double *r_chisq, double *r_mean,
|
||||
double *r_montepicalc, double *r_scc)
|
||||
{
|
||||
state.end(r_ent, r_chisq, r_mean, r_montepicalc, r_scc);
|
||||
return true;
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(EntropyVal, SER_ENTROPY_VAL);
|
||||
|
||||
bool EntropyVal::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_ENTROPY_VAL, OpaqueVal);
|
||||
|
||||
for ( int i = 0; i < 256; ++i )
|
||||
{
|
||||
if ( ! SERIALIZE(state.ccount[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (SERIALIZE(state.totalc) &&
|
||||
SERIALIZE(state.mp) &&
|
||||
SERIALIZE(state.sccfirst)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < RT_MONTEN; ++i )
|
||||
{
|
||||
if ( ! SERIALIZE(state.monte[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (SERIALIZE(state.inmont) &&
|
||||
SERIALIZE(state.mcount) &&
|
||||
SERIALIZE(state.cexp) &&
|
||||
SERIALIZE(state.montex) &&
|
||||
SERIALIZE(state.montey) &&
|
||||
SERIALIZE(state.montepi) &&
|
||||
SERIALIZE(state.sccu0) &&
|
||||
SERIALIZE(state.scclast) &&
|
||||
SERIALIZE(state.scct1) &&
|
||||
SERIALIZE(state.scct2) &&
|
||||
SERIALIZE(state.scct3)) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntropyVal::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(OpaqueVal);
|
||||
|
||||
for ( int i = 0; i < 256; ++i )
|
||||
{
|
||||
if ( ! UNSERIALIZE(&state.ccount[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (UNSERIALIZE(&state.totalc) &&
|
||||
UNSERIALIZE(&state.mp) &&
|
||||
UNSERIALIZE(&state.sccfirst)) )
|
||||
return false;
|
||||
|
||||
for ( int i = 0; i < RT_MONTEN; ++i )
|
||||
{
|
||||
if ( ! UNSERIALIZE(&state.monte[i]) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! (UNSERIALIZE(&state.inmont) &&
|
||||
UNSERIALIZE(&state.mcount) &&
|
||||
UNSERIALIZE(&state.cexp) &&
|
||||
UNSERIALIZE(&state.montex) &&
|
||||
UNSERIALIZE(&state.montey) &&
|
||||
UNSERIALIZE(&state.montepi) &&
|
||||
UNSERIALIZE(&state.sccu0) &&
|
||||
UNSERIALIZE(&state.scclast) &&
|
||||
UNSERIALIZE(&state.scct1) &&
|
||||
UNSERIALIZE(&state.scct2) &&
|
||||
UNSERIALIZE(&state.scct3)) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
110
src/OpaqueVal.h
Normal file
110
src/OpaqueVal.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#ifndef OPAQUEVAL_H
|
||||
#define OPAQUEVAL_H
|
||||
|
||||
#include "RandTest.h"
|
||||
#include "Val.h"
|
||||
#include "digest.h"
|
||||
|
||||
class HashVal : public OpaqueVal {
|
||||
public:
|
||||
virtual bool IsValid() const;
|
||||
virtual bool Init();
|
||||
virtual bool Feed(const void* data, size_t size);
|
||||
virtual StringVal* Get();
|
||||
|
||||
protected:
|
||||
HashVal() { };
|
||||
HashVal(OpaqueType* t);
|
||||
virtual bool DoInit();
|
||||
virtual bool DoFeed(const void* data, size_t size);
|
||||
virtual StringVal* DoGet();
|
||||
|
||||
DECLARE_SERIAL(HashVal);
|
||||
|
||||
private:
|
||||
// This flag exists because Get() can only be called once.
|
||||
bool valid;
|
||||
};
|
||||
|
||||
class MD5Val : public HashVal {
|
||||
public:
|
||||
static void digest(val_list& vlist, u_char result[MD5_DIGEST_LENGTH]);
|
||||
|
||||
static void hmac(val_list& vlist,
|
||||
u_char key[MD5_DIGEST_LENGTH],
|
||||
u_char result[MD5_DIGEST_LENGTH]);
|
||||
|
||||
MD5Val() : HashVal(new OpaqueType("md5")) { }
|
||||
|
||||
protected:
|
||||
friend class Val;
|
||||
|
||||
virtual bool DoInit() /* override */;
|
||||
virtual bool DoFeed(const void* data, size_t size) /* override */;
|
||||
virtual StringVal* DoGet() /* override */;
|
||||
|
||||
DECLARE_SERIAL(MD5Val);
|
||||
|
||||
private:
|
||||
MD5_CTX ctx;
|
||||
};
|
||||
|
||||
class SHA1Val : public HashVal {
|
||||
public:
|
||||
static void digest(val_list& vlist, u_char result[SHA_DIGEST_LENGTH]);
|
||||
|
||||
SHA1Val() : HashVal(new OpaqueType("sha1")) { }
|
||||
|
||||
protected:
|
||||
friend class Val;
|
||||
|
||||
virtual bool DoInit() /* override */;
|
||||
virtual bool DoFeed(const void* data, size_t size) /* override */;
|
||||
virtual StringVal* DoGet() /* override */;
|
||||
|
||||
DECLARE_SERIAL(SHA1Val);
|
||||
|
||||
private:
|
||||
SHA_CTX ctx;
|
||||
};
|
||||
|
||||
class SHA256Val : public HashVal {
|
||||
public:
|
||||
static void digest(val_list& vlist, u_char result[SHA256_DIGEST_LENGTH]);
|
||||
|
||||
SHA256Val() : HashVal(new OpaqueType("sha256")) { }
|
||||
|
||||
protected:
|
||||
friend class Val;
|
||||
|
||||
virtual bool DoInit() /* override */;
|
||||
virtual bool DoFeed(const void* data, size_t size) /* override */;
|
||||
virtual StringVal* DoGet() /* override */;
|
||||
|
||||
DECLARE_SERIAL(SHA256Val);
|
||||
|
||||
private:
|
||||
SHA256_CTX ctx;
|
||||
};
|
||||
|
||||
class EntropyVal : public OpaqueVal {
|
||||
public:
|
||||
EntropyVal() : OpaqueVal(new OpaqueType("entropy")) { }
|
||||
|
||||
bool Feed(const void* data, size_t size);
|
||||
bool Get(double *r_ent, double *r_chisq, double *r_mean,
|
||||
double *r_montepicalc, double *r_scc);
|
||||
|
||||
protected:
|
||||
friend class Val;
|
||||
EntropyVal(OpaqueType* t);
|
||||
|
||||
DECLARE_SERIAL(EntropyVal);
|
||||
|
||||
private:
|
||||
RandTest state;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -12,7 +12,18 @@
|
|||
Modified for Bro by Seth Hall - July 2010
|
||||
*/
|
||||
|
||||
#include <RandTest.h>
|
||||
#include <math.h>
|
||||
#include "RandTest.h"
|
||||
|
||||
#define log2of10 3.32192809488736234787
|
||||
/* RT_LOG2 -- Calculate log to the base 2 */
|
||||
static double rt_log2(double x)
|
||||
{
|
||||
return log2of10 * log10(x);
|
||||
}
|
||||
|
||||
// RT_INCIRC = pow(pow(256.0, (double) (RT_MONTEN / 2)) - 1, 2.0);
|
||||
#define RT_INCIRC 281474943156225.0
|
||||
|
||||
RandTest::RandTest()
|
||||
{
|
||||
|
@ -28,9 +39,9 @@ RandTest::RandTest()
|
|||
}
|
||||
}
|
||||
|
||||
void RandTest::add(void *buf, int bufl)
|
||||
void RandTest::add(const void *buf, int bufl)
|
||||
{
|
||||
unsigned char *bp = (unsigned char*)buf;
|
||||
const unsigned char *bp = static_cast<const unsigned char*>(buf);
|
||||
int oc;
|
||||
|
||||
while (bufl-- > 0)
|
||||
|
@ -78,8 +89,8 @@ void RandTest::add(void *buf, int bufl)
|
|||
}
|
||||
}
|
||||
|
||||
void RandTest::end(double *r_ent, double *r_chisq,
|
||||
double *r_mean, double *r_montepicalc, double *r_scc)
|
||||
void RandTest::end(double* r_ent, double* r_chisq,
|
||||
double* r_mean, double* r_montepicalc, double* r_scc)
|
||||
{
|
||||
int i;
|
||||
double ent, chisq, scc, datasum;
|
||||
|
|
|
@ -1,34 +1,33 @@
|
|||
#include <math.h>
|
||||
#ifndef RANDTEST_H
|
||||
#define RANDTEST_H
|
||||
|
||||
#define log2of10 3.32192809488736234787
|
||||
/* RT_LOG2 -- Calculate log to the base 2 */
|
||||
static double rt_log2(double x)
|
||||
{
|
||||
return log2of10 * log10(x);
|
||||
}
|
||||
#include "util.h"
|
||||
|
||||
#define RT_MONTEN 6 /* Bytes used as Monte Carlo
|
||||
co-ordinates. This should be no more
|
||||
bits than the mantissa of your "double"
|
||||
floating point type. */
|
||||
class EntropyVal;
|
||||
|
||||
// RT_INCIRC = pow(pow(256.0, (double) (RT_MONTEN / 2)) - 1, 2.0);
|
||||
#define RT_INCIRC 281474943156225.0
|
||||
|
||||
class RandTest {
|
||||
public:
|
||||
RandTest();
|
||||
void add(void *buf, int bufl);
|
||||
void end(double *r_ent, double *r_chisq, double *r_mean,
|
||||
double *r_montepicalc, double *r_scc);
|
||||
void add(const void* buf, int bufl);
|
||||
void end(double* r_ent, double* r_chisq, double* r_mean,
|
||||
double* r_montepicalc, double* r_scc);
|
||||
|
||||
private:
|
||||
long ccount[256]; /* Bins to count occurrences of values */
|
||||
long totalc; /* Total bytes counted */
|
||||
friend class EntropyVal;
|
||||
|
||||
int64 ccount[256]; /* Bins to count occurrences of values */
|
||||
int64 totalc; /* Total bytes counted */
|
||||
int mp;
|
||||
int sccfirst;
|
||||
unsigned int monte[RT_MONTEN];
|
||||
long inmont, mcount;
|
||||
int64 inmont, mcount;
|
||||
double cexp, montex, montey, montepi,
|
||||
sccu0, scclast, scct1, scct2, scct3;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -98,6 +98,12 @@ SERIAL_VAL(RECORD_VAL, 10)
|
|||
SERIAL_VAL(ENUM_VAL, 11)
|
||||
SERIAL_VAL(VECTOR_VAL, 12)
|
||||
SERIAL_VAL(MUTABLE_VAL, 13)
|
||||
SERIAL_VAL(OPAQUE_VAL, 14)
|
||||
SERIAL_VAL(HASH_VAL, 15)
|
||||
SERIAL_VAL(MD5_VAL, 16)
|
||||
SERIAL_VAL(SHA1_VAL, 17)
|
||||
SERIAL_VAL(SHA256_VAL, 18)
|
||||
SERIAL_VAL(ENTROPY_VAL, 19)
|
||||
|
||||
#define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR)
|
||||
SERIAL_EXPR(EXPR, 1)
|
||||
|
@ -178,6 +184,7 @@ SERIAL_TYPE(SUBNET_TYPE, 8)
|
|||
SERIAL_TYPE(FILE_TYPE, 9)
|
||||
SERIAL_TYPE(ENUM_TYPE, 10)
|
||||
SERIAL_TYPE(VECTOR_TYPE, 11)
|
||||
SERIAL_TYPE(OPAQUE_TYPE, 12)
|
||||
|
||||
SERIAL_CONST2(ATTRIBUTES)
|
||||
SERIAL_CONST2(EVENT_HANDLER)
|
||||
|
|
182
src/Stmt.cc
182
src/Stmt.cc
|
@ -592,6 +592,21 @@ Case::~Case()
|
|||
|
||||
void Case::Describe(ODesc* d) const
|
||||
{
|
||||
if ( ! Cases() )
|
||||
{
|
||||
if ( ! d->IsBinary() )
|
||||
d->Add("default:");
|
||||
|
||||
d->AddCount(0);
|
||||
|
||||
d->PushIndent();
|
||||
Body()->AccessStats(d);
|
||||
Body()->Describe(d);
|
||||
d->PopIndent();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const expr_list& e = Cases()->Exprs();
|
||||
|
||||
if ( ! d->IsBinary() )
|
||||
|
@ -658,13 +673,64 @@ bool Case::DoUnserialize(UnserialInfo* info)
|
|||
return this->s != 0;
|
||||
}
|
||||
|
||||
SwitchStmt::SwitchStmt(Expr* index, case_list* arg_cases) :
|
||||
ExprStmt(STMT_SWITCH, index)
|
||||
static void int_del_func(void* v)
|
||||
{
|
||||
cases = arg_cases;
|
||||
delete (int*) v;
|
||||
}
|
||||
|
||||
//### need to loop over cases and make sure their type matches
|
||||
//### the index, and they're constant and not redundant
|
||||
void SwitchStmt::Init()
|
||||
{
|
||||
TypeList* t = new TypeList();
|
||||
t->Append(e->Type()->Ref());
|
||||
comp_hash = new CompositeHash(t);
|
||||
Unref(t);
|
||||
|
||||
case_label_map.SetDeleteFunc(int_del_func);
|
||||
}
|
||||
|
||||
SwitchStmt::SwitchStmt(Expr* index, case_list* arg_cases) :
|
||||
ExprStmt(STMT_SWITCH, index), cases(arg_cases), default_case_idx(-1)
|
||||
{
|
||||
Init();
|
||||
|
||||
if ( ! is_atomic_type(e->Type()) )
|
||||
e->Error("switch expression must be of an atomic type");
|
||||
|
||||
loop_over_list(*cases, i)
|
||||
{
|
||||
const Case* c = (*cases)[i];
|
||||
const ListExpr* le = c->Cases();
|
||||
|
||||
if ( le )
|
||||
{
|
||||
if ( ! le->Type()->AsTypeList()->AllMatch(e->Type(), false) )
|
||||
{
|
||||
le->Error("case expression type differs from switch type", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
const expr_list& exprs = le->Exprs();
|
||||
|
||||
loop_over_list(exprs, j)
|
||||
{
|
||||
if ( ! exprs[j]->IsConst() )
|
||||
exprs[j]->Error("case label expression isn't constant");
|
||||
else
|
||||
{
|
||||
if ( ! AddCaseLabelMapping(exprs[j]->ExprVal(), i) )
|
||||
exprs[j]->Error("duplicate case label");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if ( default_case_idx != -1 )
|
||||
c->Error("multiple default labels", (*cases)[default_case_idx]);
|
||||
else
|
||||
default_case_idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SwitchStmt::~SwitchStmt()
|
||||
|
@ -673,12 +739,80 @@ SwitchStmt::~SwitchStmt()
|
|||
Unref((*cases)[i]);
|
||||
|
||||
delete cases;
|
||||
delete comp_hash;
|
||||
}
|
||||
|
||||
Val* SwitchStmt::DoExec(Frame* /* f */, Val* /* v */, stmt_flow_type& /* flow */) const
|
||||
bool SwitchStmt::AddCaseLabelMapping(const Val* v, int idx)
|
||||
{
|
||||
printf("switch statement not implemented\n");
|
||||
return 0;
|
||||
HashKey* hk = comp_hash->ComputeHash(v, 1);
|
||||
|
||||
if ( ! hk )
|
||||
{
|
||||
reporter->PushLocation(e->GetLocationInfo());
|
||||
reporter->InternalError("switch expression type mismatch (%s/%s)",
|
||||
type_name(v->Type()->Tag()), type_name(e->Type()->Tag()));
|
||||
}
|
||||
|
||||
int* label_idx = case_label_map.Lookup(hk);
|
||||
|
||||
if ( label_idx )
|
||||
{
|
||||
delete hk;
|
||||
return false;
|
||||
}
|
||||
|
||||
case_label_map.Insert(hk, new int(idx));
|
||||
return true;
|
||||
}
|
||||
|
||||
int SwitchStmt::FindCaseLabelMatch(const Val* v) const
|
||||
{
|
||||
HashKey* hk = comp_hash->ComputeHash(v, 1);
|
||||
|
||||
if ( ! hk )
|
||||
{
|
||||
reporter->PushLocation(e->GetLocationInfo());
|
||||
reporter->InternalError("switch expression type mismatch (%s/%s)",
|
||||
type_name(v->Type()->Tag()), type_name(e->Type()->Tag()));
|
||||
}
|
||||
|
||||
int* label_idx = case_label_map.Lookup(hk);
|
||||
|
||||
delete hk;
|
||||
|
||||
if ( ! label_idx )
|
||||
return default_case_idx;
|
||||
else
|
||||
return *label_idx;
|
||||
}
|
||||
|
||||
Val* SwitchStmt::DoExec(Frame* f, Val* v, stmt_flow_type& flow) const
|
||||
{
|
||||
Val* rval = 0;
|
||||
|
||||
int matching_label_idx = FindCaseLabelMatch(v);
|
||||
|
||||
if ( matching_label_idx == -1 )
|
||||
return 0;
|
||||
|
||||
for ( int i = matching_label_idx; i < cases->length(); ++i )
|
||||
{
|
||||
const Case* c = (*cases)[i];
|
||||
|
||||
flow = FLOW_NEXT;
|
||||
rval = c->Body()->Exec(f, flow);
|
||||
|
||||
if ( flow == FLOW_BREAK )
|
||||
{
|
||||
flow = FLOW_NEXT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( flow == FLOW_RETURN )
|
||||
break;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
Stmt* SwitchStmt::DoSimplify()
|
||||
|
@ -697,7 +831,13 @@ Stmt* SwitchStmt::DoSimplify()
|
|||
}
|
||||
|
||||
if ( e->IsConst() )
|
||||
{ // ### go through cases and pull out the one it matches
|
||||
{
|
||||
// Could possibly remove all case labels before the one
|
||||
// that will match, but may be tricky to tell if any
|
||||
// subsequent ones can also be removed since it depends
|
||||
// on the evaluation of the body executing a break/return
|
||||
// statement. Then still need a way to bypass the lookup
|
||||
// DoExec for it to be beneficial.
|
||||
if ( ! optimize )
|
||||
Warn("constant in switch");
|
||||
}
|
||||
|
@ -770,6 +910,9 @@ bool SwitchStmt::DoSerialize(SerialInfo* info) const
|
|||
if ( ! (*cases)[i]->Serialize(info) )
|
||||
return false;
|
||||
|
||||
if ( ! SERIALIZE(default_case_idx) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -777,6 +920,8 @@ bool SwitchStmt::DoUnserialize(UnserialInfo* info)
|
|||
{
|
||||
DO_UNSERIALIZE(ExprStmt);
|
||||
|
||||
Init();
|
||||
|
||||
int len;
|
||||
if ( ! UNSERIALIZE(&len) )
|
||||
return false;
|
||||
|
@ -790,6 +935,25 @@ bool SwitchStmt::DoUnserialize(UnserialInfo* info)
|
|||
cases->append(c);
|
||||
}
|
||||
|
||||
if ( ! UNSERIALIZE(&default_case_idx) )
|
||||
return false;
|
||||
|
||||
loop_over_list(*cases, i)
|
||||
{
|
||||
const ListExpr* le = (*cases)[i]->Cases();
|
||||
|
||||
if ( ! le )
|
||||
continue;
|
||||
|
||||
const expr_list& exprs = le->Exprs();
|
||||
|
||||
loop_over_list(exprs, j)
|
||||
{
|
||||
if ( ! AddCaseLabelMapping(exprs[j]->ExprVal(), i) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
23
src/Stmt.h
23
src/Stmt.h
|
@ -17,6 +17,8 @@
|
|||
class StmtList;
|
||||
class ForStmt;
|
||||
|
||||
declare(PDict, int);
|
||||
|
||||
class Stmt : public BroObj {
|
||||
public:
|
||||
BroStmtTag Tag() const { return tag; }
|
||||
|
@ -187,7 +189,8 @@ protected:
|
|||
|
||||
class Case : public BroObj {
|
||||
public:
|
||||
Case(ListExpr* c, Stmt* arg_s) { cases = c; s = arg_s; }
|
||||
Case(ListExpr* c, Stmt* arg_s) :
|
||||
cases(simplify_expr_list(c,SIMPLIFY_GENERAL)), s(arg_s) { }
|
||||
~Case();
|
||||
|
||||
const ListExpr* Cases() const { return cases; }
|
||||
|
@ -226,7 +229,7 @@ public:
|
|||
|
||||
protected:
|
||||
friend class Stmt;
|
||||
SwitchStmt() { cases = 0; }
|
||||
SwitchStmt() { cases = 0; default_case_idx = -1; comp_hash = 0; }
|
||||
|
||||
Val* DoExec(Frame* f, Val* v, stmt_flow_type& flow) const;
|
||||
Stmt* DoSimplify();
|
||||
|
@ -234,7 +237,23 @@ protected:
|
|||
|
||||
DECLARE_SERIAL(SwitchStmt);
|
||||
|
||||
// Initialize composite hash and case label map.
|
||||
void Init();
|
||||
|
||||
// Adds an entry in case_label_map for the given value to associate it
|
||||
// with the given index in the cases list. If the entry already exists,
|
||||
// returns false, else returns true.
|
||||
bool AddCaseLabelMapping(const Val* v, int idx);
|
||||
|
||||
// Returns index of a case label that's equal to the value, or
|
||||
// default_case_idx if no case label matches (which may be -1 if there's
|
||||
// no default label).
|
||||
int FindCaseLabelMatch(const Val* v) const;
|
||||
|
||||
case_list* cases;
|
||||
int default_case_idx;
|
||||
CompositeHash* comp_hash;
|
||||
PDict(int) case_label_map;
|
||||
};
|
||||
|
||||
class AddStmt : public ExprStmt {
|
||||
|
|
40
src/TCP.cc
40
src/TCP.cc
|
@ -382,7 +382,7 @@ void TCP_Analyzer::ProcessFIN(double t, TCP_Endpoint* endpoint,
|
|||
endpoint->FIN_seq = base_seq - endpoint->StartSeq() + seq_len;
|
||||
}
|
||||
|
||||
bool TCP_Analyzer::ProcessRST(double t, TCP_Endpoint* endpoint,
|
||||
void TCP_Analyzer::ProcessRST(double t, TCP_Endpoint* endpoint,
|
||||
const IP_Hdr* ip, uint32 base_seq,
|
||||
int len, int& seq_len)
|
||||
{
|
||||
|
@ -406,11 +406,9 @@ bool TCP_Analyzer::ProcessRST(double t, TCP_Endpoint* endpoint,
|
|||
}
|
||||
|
||||
PacketWithRST();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int TCP_Analyzer::ProcessFlags(double t,
|
||||
void TCP_Analyzer::ProcessFlags(double t,
|
||||
const IP_Hdr* ip, const struct tcphdr* tp,
|
||||
uint32 tcp_hdr_len, int len, int& seq_len,
|
||||
TCP_Endpoint* endpoint, TCP_Endpoint* peer,
|
||||
|
@ -425,14 +423,11 @@ int TCP_Analyzer::ProcessFlags(double t,
|
|||
if ( flags.FIN() )
|
||||
ProcessFIN(t, endpoint, seq_len, base_seq);
|
||||
|
||||
if ( flags.RST() &&
|
||||
! ProcessRST(t, endpoint, ip, base_seq, len, seq_len) )
|
||||
return 0;
|
||||
if ( flags.RST() )
|
||||
ProcessRST(t, endpoint, ip, base_seq, len, seq_len);
|
||||
|
||||
if ( flags.ACK() )
|
||||
ProcessACK(endpoint, peer, ack_seq, is_orig, flags);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void TCP_Analyzer::TransitionFromInactive(double t, TCP_Endpoint* endpoint,
|
||||
|
@ -825,10 +820,27 @@ void TCP_Analyzer::UpdateClosedState(double t, TCP_Endpoint* endpoint,
|
|||
}
|
||||
}
|
||||
|
||||
void TCP_Analyzer::UpdateResetState(int len, TCP_Flags flags)
|
||||
void TCP_Analyzer::UpdateResetState(int len, TCP_Flags flags,
|
||||
TCP_Endpoint* endpoint, uint32 base_seq,
|
||||
uint32 last_seq)
|
||||
{
|
||||
if ( flags.SYN() )
|
||||
{
|
||||
Weird("SYN_after_reset");
|
||||
|
||||
if ( endpoint->prev_state == TCP_ENDPOINT_INACTIVE )
|
||||
{
|
||||
// Seq. numbers were initialized by a RST packet from this endpoint,
|
||||
// but now that a SYN is seen from it, that could mean the earlier
|
||||
// RST was spoofed/injected, so re-initialize. This mostly just
|
||||
// helps prevent misrepresentations of payload sizes that are based
|
||||
// on bad initial sequence values.
|
||||
endpoint->InitStartSeq(base_seq);
|
||||
endpoint->InitAckSeq(base_seq);
|
||||
endpoint->InitLastSeq(last_seq);
|
||||
}
|
||||
}
|
||||
|
||||
if ( flags.FIN() )
|
||||
Weird("FIN_after_reset");
|
||||
|
||||
|
@ -871,7 +883,7 @@ void TCP_Analyzer::UpdateStateMachine(double t,
|
|||
break;
|
||||
|
||||
case TCP_ENDPOINT_RESET:
|
||||
UpdateResetState(len, flags);
|
||||
UpdateResetState(len, flags, endpoint, base_seq, last_seq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -996,10 +1008,8 @@ void TCP_Analyzer::DeliverPacket(int len, const u_char* data, bool is_orig,
|
|||
|
||||
int seq_len = len; // length in terms of sequence space
|
||||
|
||||
if ( ! ProcessFlags(t, ip, tp, tcp_hdr_len, len, seq_len,
|
||||
endpoint, peer, base_seq, ack_seq,
|
||||
orig_addr, is_orig, flags) )
|
||||
return;
|
||||
ProcessFlags(t, ip, tp, tcp_hdr_len, len, seq_len, endpoint, peer, base_seq,
|
||||
ack_seq, orig_addr, is_orig, flags);
|
||||
|
||||
uint32 last_seq = base_seq + seq_len;
|
||||
|
||||
|
|
|
@ -135,13 +135,13 @@ protected:
|
|||
void ProcessFIN(double t, TCP_Endpoint* endpoint, int& seq_len,
|
||||
uint32 base_seq);
|
||||
|
||||
bool ProcessRST(double t, TCP_Endpoint* endpoint, const IP_Hdr* ip,
|
||||
void ProcessRST(double t, TCP_Endpoint* endpoint, const IP_Hdr* ip,
|
||||
uint32 base_seq, int len, int& seq_len);
|
||||
|
||||
void ProcessACK(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
|
||||
uint32 ack_seq, int is_orig, TCP_Flags flags);
|
||||
|
||||
int ProcessFlags(double t, const IP_Hdr* ip, const struct tcphdr* tp,
|
||||
void ProcessFlags(double t, const IP_Hdr* ip, const struct tcphdr* tp,
|
||||
uint32 tcp_hdr_len, int len, int& seq_len,
|
||||
TCP_Endpoint* endpoint, TCP_Endpoint* peer,
|
||||
uint32 base_seq, uint32 ack_seq,
|
||||
|
@ -186,7 +186,8 @@ protected:
|
|||
int delta_last, TCP_Flags flags,
|
||||
int& do_close);
|
||||
|
||||
void UpdateResetState(int len, TCP_Flags flags);
|
||||
void UpdateResetState(int len, TCP_Flags flags, TCP_Endpoint* endpoint,
|
||||
uint32 base_seq, uint32 last_seq);
|
||||
|
||||
void GeneratePacketEvent(TCP_Endpoint* endpoint, TCP_Endpoint* peer,
|
||||
uint32 base_seq, uint32 ack_seq,
|
||||
|
|
72
src/Type.cc
72
src/Type.cc
|
@ -30,6 +30,7 @@ const char* type_name(TypeTag t)
|
|||
"table", "union", "record", "types",
|
||||
"func",
|
||||
"file",
|
||||
"opaque",
|
||||
"vector",
|
||||
"type",
|
||||
"error",
|
||||
|
@ -96,6 +97,7 @@ BroType::BroType(TypeTag t, bool arg_base_type)
|
|||
case TYPE_LIST:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_FILE:
|
||||
case TYPE_OPAQUE:
|
||||
case TYPE_VECTOR:
|
||||
case TYPE_TYPE:
|
||||
internal_tag = TYPE_INTERNAL_OTHER;
|
||||
|
@ -114,8 +116,17 @@ BroType::~BroType()
|
|||
delete [] type_id;
|
||||
}
|
||||
|
||||
int BroType::MatchesIndex(ListExpr*& /* index */) const
|
||||
int BroType::MatchesIndex(ListExpr*& index) const
|
||||
{
|
||||
if ( Tag() == TYPE_STRING )
|
||||
{
|
||||
if ( index->Exprs().length() != 1 && index->Exprs().length() != 2 )
|
||||
return DOES_NOT_MATCH_INDEX;
|
||||
|
||||
if ( check_and_promote_exprs_to_type(index, ::base_type(TYPE_INT)) )
|
||||
return MATCHES_INDEX_SCALAR;
|
||||
}
|
||||
|
||||
return DOES_NOT_MATCH_INDEX;
|
||||
}
|
||||
|
||||
|
@ -1262,6 +1273,42 @@ bool FileType::DoUnserialize(UnserialInfo* info)
|
|||
return yield != 0;
|
||||
}
|
||||
|
||||
OpaqueType::OpaqueType(const string& arg_name) : BroType(TYPE_OPAQUE)
|
||||
{
|
||||
name = arg_name;
|
||||
}
|
||||
|
||||
void OpaqueType::Describe(ODesc* d) const
|
||||
{
|
||||
if ( d->IsReadable() )
|
||||
d->AddSP("opaque of");
|
||||
else
|
||||
d->Add(int(Tag()));
|
||||
|
||||
d->Add(name.c_str());
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(OpaqueType, SER_OPAQUE_TYPE);
|
||||
|
||||
bool OpaqueType::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_OPAQUE_TYPE, BroType);
|
||||
return SERIALIZE(name);
|
||||
}
|
||||
|
||||
bool OpaqueType::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(BroType);
|
||||
|
||||
char const* n;
|
||||
if ( ! UNSERIALIZE_STR(&n, 0) )
|
||||
return false;
|
||||
|
||||
name = n;
|
||||
delete [] n;
|
||||
return true;
|
||||
}
|
||||
|
||||
EnumType::EnumType(const string& arg_name)
|
||||
: BroType(TYPE_ENUM)
|
||||
{
|
||||
|
@ -1716,6 +1763,13 @@ int same_type(const BroType* t1, const BroType* t2, int is_init)
|
|||
case TYPE_FILE:
|
||||
return same_type(t1->YieldType(), t2->YieldType(), is_init);
|
||||
|
||||
case TYPE_OPAQUE:
|
||||
{
|
||||
const OpaqueType* ot1 = (const OpaqueType*) t1;
|
||||
const OpaqueType* ot2 = (const OpaqueType*) t2;
|
||||
return ot1->Name() == ot2->Name() ? 1 : 0;
|
||||
}
|
||||
|
||||
case TYPE_TYPE:
|
||||
return same_type(t1, t2, is_init);
|
||||
|
||||
|
@ -1805,6 +1859,7 @@ int is_assignable(BroType* t)
|
|||
|
||||
case TYPE_VECTOR:
|
||||
case TYPE_FILE:
|
||||
case TYPE_OPAQUE:
|
||||
case TYPE_TABLE:
|
||||
case TYPE_TYPE:
|
||||
return 1;
|
||||
|
@ -2190,3 +2245,18 @@ BroType* init_type(Expr* init)
|
|||
|
||||
return new SetType(t->AsTypeList(), 0);
|
||||
}
|
||||
|
||||
bool is_atomic_type(const BroType* t)
|
||||
{
|
||||
switch ( t->InternalType() ) {
|
||||
case TYPE_INTERNAL_INT:
|
||||
case TYPE_INTERNAL_UNSIGNED:
|
||||
case TYPE_INTERNAL_DOUBLE:
|
||||
case TYPE_INTERNAL_STRING:
|
||||
case TYPE_INTERNAL_ADDR:
|
||||
case TYPE_INTERNAL_SUBNET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
21
src/Type.h
21
src/Type.h
|
@ -29,6 +29,7 @@ typedef enum {
|
|||
TYPE_LIST,
|
||||
TYPE_FUNC,
|
||||
TYPE_FILE,
|
||||
TYPE_OPAQUE,
|
||||
TYPE_VECTOR,
|
||||
TYPE_TYPE,
|
||||
TYPE_ERROR
|
||||
|
@ -499,6 +500,23 @@ protected:
|
|||
BroType* yield;
|
||||
};
|
||||
|
||||
class OpaqueType : public BroType {
|
||||
public:
|
||||
OpaqueType(const string& name);
|
||||
virtual ~OpaqueType() { };
|
||||
|
||||
const string& Name() const { return name; }
|
||||
|
||||
void Describe(ODesc* d) const;
|
||||
|
||||
protected:
|
||||
OpaqueType() { }
|
||||
|
||||
DECLARE_SERIAL(OpaqueType)
|
||||
|
||||
string name;
|
||||
};
|
||||
|
||||
class EnumType : public BroType {
|
||||
public:
|
||||
EnumType(const string& arg_name);
|
||||
|
@ -625,6 +643,9 @@ BroType* merge_type_list(ListExpr* elements);
|
|||
// Given an expression, infer its type when used for an initialization.
|
||||
extern BroType* init_type(Expr* init);
|
||||
|
||||
// Returns true if argument is an atomic type.
|
||||
bool is_atomic_type(const BroType* t);
|
||||
|
||||
// True if the given type tag corresponds to an integral type.
|
||||
#define IsIntegral(t) (t == TYPE_INT || t == TYPE_COUNT || t == TYPE_COUNTER)
|
||||
|
||||
|
|
33
src/Val.cc
33
src/Val.cc
|
@ -3114,6 +3114,27 @@ void VectorVal::ValDescribe(ODesc* d) const
|
|||
d->Add("]");
|
||||
}
|
||||
|
||||
OpaqueVal::OpaqueVal(OpaqueType* t) : Val(t)
|
||||
{
|
||||
}
|
||||
|
||||
OpaqueVal::~OpaqueVal()
|
||||
{
|
||||
}
|
||||
|
||||
IMPLEMENT_SERIAL(OpaqueVal, SER_OPAQUE_VAL);
|
||||
|
||||
bool OpaqueVal::DoSerialize(SerialInfo* info) const
|
||||
{
|
||||
DO_SERIALIZE(SER_OPAQUE_VAL, Val);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpaqueVal::DoUnserialize(UnserialInfo* info)
|
||||
{
|
||||
DO_UNSERIALIZE(Val);
|
||||
return true;
|
||||
}
|
||||
|
||||
Val* check_and_promote(Val* v, const BroType* t, int is_init)
|
||||
{
|
||||
|
@ -3209,17 +3230,7 @@ int same_val(const Val* /* v1 */, const Val* /* v2 */)
|
|||
|
||||
bool is_atomic_val(const Val* v)
|
||||
{
|
||||
switch ( v->Type()->InternalType() ) {
|
||||
case TYPE_INTERNAL_INT:
|
||||
case TYPE_INTERNAL_UNSIGNED:
|
||||
case TYPE_INTERNAL_DOUBLE:
|
||||
case TYPE_INTERNAL_STRING:
|
||||
case TYPE_INTERNAL_ADDR:
|
||||
case TYPE_INTERNAL_SUBNET:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return is_atomic_type(v->Type());
|
||||
}
|
||||
|
||||
int same_atomic_val(const Val* v1, const Val* v2)
|
||||
|
|
14
src/Val.h
14
src/Val.h
|
@ -1013,6 +1013,20 @@ protected:
|
|||
VectorType* vector_type;
|
||||
};
|
||||
|
||||
// Base class for values with types that are managed completely internally,
|
||||
// with no further script-level operators provided (other than bif
|
||||
// functions). See OpaqueVal.h for derived classes.
|
||||
class OpaqueVal : public Val {
|
||||
public:
|
||||
OpaqueVal(OpaqueType* t);
|
||||
virtual ~OpaqueVal();
|
||||
|
||||
protected:
|
||||
friend class Val;
|
||||
OpaqueVal() { }
|
||||
|
||||
DECLARE_SERIAL(OpaqueVal);
|
||||
};
|
||||
|
||||
// Checks the given value for consistency with the given type. If an
|
||||
// exact match, returns it. If promotable, returns the promoted version,
|
||||
|
|
|
@ -210,7 +210,6 @@ static void make_var(ID* id, BroType* t, init_class c, Expr* init,
|
|||
// defined.
|
||||
Func* f = new BroFunc(id, 0, 0, 0, 0);
|
||||
id->SetVal(new Val(f));
|
||||
id->SetConst();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,8 +232,9 @@ Stmt* add_local(ID* id, BroType* t, init_class c, Expr* init,
|
|||
|
||||
Ref(id);
|
||||
|
||||
Expr* name_expr = new NameExpr(id, dt == VAR_CONST);
|
||||
Stmt* stmt =
|
||||
new ExprStmt(new AssignExpr(new NameExpr(id), init, 0, 0,
|
||||
new ExprStmt(new AssignExpr(name_expr, init, 0, 0,
|
||||
id->Attrs() ? id->Attrs()->Attrs() : 0 ));
|
||||
stmt->SetLocationInfo(init->GetLocationInfo());
|
||||
|
||||
|
|
425
src/bro.bif
425
src/bro.bif
|
@ -530,82 +530,7 @@ function piped_exec%(program: string, to_write: string%): bool
|
|||
%}
|
||||
|
||||
%%{
|
||||
static void hash_md5_val(val_list& vlist, unsigned char digest[16])
|
||||
{
|
||||
MD5_CTX h;
|
||||
|
||||
md5_init(&h);
|
||||
loop_over_list(vlist, i)
|
||||
{
|
||||
Val* v = vlist[i];
|
||||
if ( v->Type()->Tag() == TYPE_STRING )
|
||||
{
|
||||
const BroString* str = v->AsString();
|
||||
md5_update(&h, str->Bytes(), str->Len());
|
||||
}
|
||||
else
|
||||
{
|
||||
ODesc d(DESC_BINARY);
|
||||
v->Describe(&d);
|
||||
md5_update(&h, (const u_char *) d.Bytes(), d.Len());
|
||||
}
|
||||
}
|
||||
md5_final(&h, digest);
|
||||
}
|
||||
|
||||
static void hmac_md5_val(val_list& vlist, unsigned char digest[16])
|
||||
{
|
||||
hash_md5_val(vlist, digest);
|
||||
for ( int i = 0; i < 16; ++i )
|
||||
digest[i] = digest[i] ^ shared_hmac_md5_key[i];
|
||||
MD5(digest, 16, digest);
|
||||
}
|
||||
|
||||
static void hash_sha1_val(val_list& vlist, unsigned char digest[20])
|
||||
{
|
||||
SHA_CTX h;
|
||||
|
||||
sha1_init(&h);
|
||||
loop_over_list(vlist, i)
|
||||
{
|
||||
Val* v = vlist[i];
|
||||
if ( v->Type()->Tag() == TYPE_STRING )
|
||||
{
|
||||
const BroString* str = v->AsString();
|
||||
sha1_update(&h, str->Bytes(), str->Len());
|
||||
}
|
||||
else
|
||||
{
|
||||
ODesc d(DESC_BINARY);
|
||||
v->Describe(&d);
|
||||
sha1_update(&h, (const u_char *) d.Bytes(), d.Len());
|
||||
}
|
||||
}
|
||||
sha1_final(&h, digest);
|
||||
}
|
||||
|
||||
static void hash_sha256_val(val_list& vlist, unsigned char digest[32])
|
||||
{
|
||||
SHA256_CTX h;
|
||||
|
||||
sha256_init(&h);
|
||||
loop_over_list(vlist, i)
|
||||
{
|
||||
Val* v = vlist[i];
|
||||
if ( v->Type()->Tag() == TYPE_STRING )
|
||||
{
|
||||
const BroString* str = v->AsString();
|
||||
sha256_update(&h, str->Bytes(), str->Len());
|
||||
}
|
||||
else
|
||||
{
|
||||
ODesc d(DESC_BINARY);
|
||||
v->Describe(&d);
|
||||
sha256_update(&h, (const u_char *) d.Bytes(), d.Len());
|
||||
}
|
||||
}
|
||||
sha256_final(&h, digest);
|
||||
}
|
||||
#include "OpaqueVal.h"
|
||||
%%}
|
||||
|
||||
## Computes the MD5 hash value of the provided list of arguments.
|
||||
|
@ -623,8 +548,8 @@ static void hash_sha256_val(val_list& vlist, unsigned char digest[32])
|
|||
## friends.
|
||||
function md5_hash%(...%): string
|
||||
%{
|
||||
unsigned char digest[16];
|
||||
hash_md5_val(@ARG@, digest);
|
||||
unsigned char digest[MD5_DIGEST_LENGTH];
|
||||
MD5Val::digest(@ARG@, digest);
|
||||
return new StringVal(md5_digest_print(digest));
|
||||
%}
|
||||
|
||||
|
@ -643,8 +568,8 @@ function md5_hash%(...%): string
|
|||
## friends.
|
||||
function sha1_hash%(...%): string
|
||||
%{
|
||||
unsigned char digest[20];
|
||||
hash_sha1_val(@ARG@, digest);
|
||||
unsigned char digest[SHA_DIGEST_LENGTH];
|
||||
SHA1Val::digest(@ARG@, digest);
|
||||
return new StringVal(sha1_digest_print(digest));
|
||||
%}
|
||||
|
||||
|
@ -663,8 +588,8 @@ function sha1_hash%(...%): string
|
|||
## friends.
|
||||
function sha256_hash%(...%): string
|
||||
%{
|
||||
unsigned char digest[32];
|
||||
hash_sha256_val(@ARG@, digest);
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||
SHA256Val::digest(@ARG@, digest);
|
||||
return new StringVal(sha256_digest_print(digest));
|
||||
%}
|
||||
|
||||
|
@ -679,288 +604,183 @@ function sha256_hash%(...%): string
|
|||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function md5_hmac%(...%): string
|
||||
%{
|
||||
unsigned char digest[16];
|
||||
hmac_md5_val(@ARG@, digest);
|
||||
return new StringVal(md5_digest_print(digest));
|
||||
unsigned char hmac[MD5_DIGEST_LENGTH];
|
||||
MD5Val::hmac(@ARG@, shared_hmac_md5_key, hmac);
|
||||
return new StringVal(md5_digest_print(hmac));
|
||||
%}
|
||||
|
||||
%%{
|
||||
static map<BroString, MD5_CTX> md5_states;
|
||||
static map<BroString, SHA_CTX> sha1_states;
|
||||
static map<BroString, SHA256_CTX> sha256_states;
|
||||
|
||||
BroString* convert_index_to_string(Val* index)
|
||||
{
|
||||
ODesc d;
|
||||
index->Describe(&d);
|
||||
BroString* s = new BroString(1, d.TakeBytes(), d.Len());
|
||||
s->SetUseFreeToDelete(1);
|
||||
return s;
|
||||
}
|
||||
%%}
|
||||
|
||||
## Initializes MD5 state to enable incremental hash computation. After
|
||||
## initializing the MD5 state with this function, you can feed data to
|
||||
## :bro:id:`md5_hash_update` and finally need to call :bro:id:`md5_hash_finish`
|
||||
## to finish the computation and get the final hash value.
|
||||
## Constructs an MD5 handle to enable incremental hash computation. You can
|
||||
## feed data to the returned opaque value with :bro:id:`md5_hash_update` and
|
||||
## eventually need to call :bro:id:`md5_hash_finish` to finish the computation
|
||||
## and get the hash digest as result.
|
||||
##
|
||||
## For example, when computing incremental MD5 values of transferred files in
|
||||
## multiple concurrent HTTP connections, one would call ``md5_hash_init(c$id)``
|
||||
## once before invoking ``md5_hash_update(c$id, some_more_data)`` in the
|
||||
## multiple concurrent HTTP connections, one keeps an optional handle in the
|
||||
## HTTP session record. Then, one would call
|
||||
## ``c$http$md5_handle = md5_hash_init()`` once before invoking
|
||||
## ``md5_hash_update(c$http$md5_handle, some_more_data)`` in the
|
||||
## :bro:id:`http_entity_data` event handler. When all data has arrived, a call
|
||||
## to :bro:id:`md5_hash_finish` returns the final hash value.
|
||||
##
|
||||
## index: The unique identifier to associate with this hash computation.
|
||||
##
|
||||
## Returns: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function md5_hash_init%(index: any%): bool
|
||||
function md5_hash_init%(%): opaque of md5
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( md5_states.count(*s) < 1 )
|
||||
{
|
||||
MD5_CTX h;
|
||||
md5_init(&h);
|
||||
md5_states[*s] = h;
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
HashVal* digest = new MD5Val();
|
||||
digest->Init();
|
||||
return digest;
|
||||
%}
|
||||
|
||||
## Initializes SHA1 state to enable incremental hash computation. After
|
||||
## initializing the SHA1 state with this function, you can feed data to
|
||||
## :bro:id:`sha1_hash_update` and finally need to call
|
||||
## :bro:id:`sha1_hash_finish` to finish the computation and get the final hash
|
||||
## value.
|
||||
## Constructs an SHA1 handle to enable incremental hash computation. You can
|
||||
## feed data to the returned opaque value with :bro:id:`sha1_hash_update` and
|
||||
## finally need to call :bro:id:`sha1_hash_finish` to finish the computation
|
||||
## and get the hash digest as result.
|
||||
##
|
||||
## For example, when computing incremental SHA1 values of transferred files in
|
||||
## multiple concurrent HTTP connections, one would call ``sha1_hash_init(c$id)``
|
||||
## once before invoking ``sha1_hash_update(c$id, some_more_data)`` in the
|
||||
## multiple concurrent HTTP connections, one keeps an optional handle in the
|
||||
## HTTP session record. Then, one would call
|
||||
## ``c$http$sha1_handle = sha1_hash_init()`` ## once before invoking
|
||||
## ``sha1_hash_update(c$http$sha1_handle, some_more_data)`` in the
|
||||
## :bro:id:`http_entity_data` event handler. When all data has arrived, a call
|
||||
## to :bro:id:`sha1_hash_finish` returns the final hash value.
|
||||
##
|
||||
## index: The unique identifier to associate with this hash computation.
|
||||
## Returns: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function sha1_hash_init%(index: any%): bool
|
||||
function sha1_hash_init%(%): opaque of sha1
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( sha1_states.count(*s) < 1 )
|
||||
{
|
||||
SHA_CTX h;
|
||||
sha1_init(&h);
|
||||
sha1_states[*s] = h;
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
HashVal* digest = new SHA1Val();
|
||||
digest->Init();
|
||||
return digest;
|
||||
%}
|
||||
|
||||
## Initializes SHA256 state to enable incremental hash computation. After
|
||||
## initializing the SHA256 state with this function, you can feed data to
|
||||
## :bro:id:`sha256_hash_update` and finally need to call
|
||||
## :bro:id:`sha256_hash_finish` to finish the computation and get the final hash
|
||||
## value.
|
||||
## Constructs an SHA256 handle to enable incremental hash computation. You can
|
||||
## feed data to the returned opaque value with :bro:id:`sha256_hash_update` and
|
||||
## finally need to call :bro:id:`sha256_hash_finish` to finish the computation
|
||||
## and get the hash digest as result.
|
||||
##
|
||||
## For example, when computing incremental SHA256 values of transferred files in
|
||||
## multiple concurrent HTTP connections, one would call
|
||||
## ``sha256_hash_init(c$id)`` once before invoking
|
||||
## ``sha256_hash_update(c$id, some_more_data)`` in the
|
||||
## multiple concurrent HTTP connections, one keeps an optional handle in the
|
||||
## HTTP session record. Then, one would call
|
||||
## ``c$http$sha256_handle = sha256_hash_init()`` ## once before invoking
|
||||
## ``sha256_hash_update(c$http$sha256_handle, some_more_data)`` in the
|
||||
## :bro:id:`http_entity_data` event handler. When all data has arrived, a call
|
||||
## to :bro:id:`sha256_hash_finish` returns the final hash value.
|
||||
##
|
||||
## index: The unique identifier to associate with this hash computation.
|
||||
## Returns: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_update sha256_hash_finish
|
||||
function sha256_hash_init%(index: any%): bool
|
||||
function sha256_hash_init%(%): opaque of sha256
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( sha256_states.count(*s) < 1 )
|
||||
{
|
||||
SHA256_CTX h;
|
||||
sha256_init(&h);
|
||||
sha256_states[*s] = h;
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
HashVal* digest = new SHA256Val();
|
||||
digest->Init();
|
||||
return digest;
|
||||
%}
|
||||
|
||||
## Update the MD5 value associated with a given index. It is required to
|
||||
## Updates the MD5 value associated with a given index. It is required to
|
||||
## call :bro:id:`md5_hash_init` once before calling this
|
||||
## function.
|
||||
##
|
||||
## index: The unique identifier to associate with this hash computation.
|
||||
## handle: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## data: The data to add to the hash computation.
|
||||
##
|
||||
## Returns: True on success.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function md5_hash_update%(index: any, data: string%): bool
|
||||
function md5_hash_update%(handle: opaque of md5, data: string%): bool
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( md5_states.count(*s) > 0 )
|
||||
{
|
||||
md5_update(&md5_states[*s], data->Bytes(), data->Len());
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
bool rc = static_cast<HashVal*>(handle)->Feed(data->Bytes(), data->Len());
|
||||
return new Val(rc, TYPE_BOOL);
|
||||
%}
|
||||
|
||||
## Update the SHA1 value associated with a given index. It is required to
|
||||
## Updates the SHA1 value associated with a given index. It is required to
|
||||
## call :bro:id:`sha1_hash_init` once before calling this
|
||||
## function.
|
||||
##
|
||||
## index: The unique identifier to associate with this hash computation.
|
||||
## handle: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## data: The data to add to the hash computation.
|
||||
##
|
||||
## Returns: True on success.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function sha1_hash_update%(index: any, data: string%): bool
|
||||
function sha1_hash_update%(handle: opaque of sha1, data: string%): bool
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( sha1_states.count(*s) > 0 )
|
||||
{
|
||||
sha1_update(&sha1_states[*s], data->Bytes(), data->Len());
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
bool rc = static_cast<HashVal*>(handle)->Feed(data->Bytes(), data->Len());
|
||||
return new Val(rc, TYPE_BOOL);
|
||||
%}
|
||||
|
||||
## Update the SHA256 value associated with a given index. It is required to
|
||||
## Updates the SHA256 value associated with a given index. It is required to
|
||||
## call :bro:id:`sha256_hash_init` once before calling this
|
||||
## function.
|
||||
##
|
||||
## index: The unique identifier to associate with this hash computation.
|
||||
## handle: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## data: The data to add to the hash computation.
|
||||
##
|
||||
## Returns: True on success.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_finish
|
||||
function sha256_hash_update%(index: any, data: string%): bool
|
||||
function sha256_hash_update%(handle: opaque of sha256, data: string%): bool
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( sha256_states.count(*s) > 0 )
|
||||
{
|
||||
sha256_update(&sha256_states[*s], data->Bytes(), data->Len());
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
bool rc = static_cast<HashVal*>(handle)->Feed(data->Bytes(), data->Len());
|
||||
return new Val(rc, TYPE_BOOL);
|
||||
%}
|
||||
|
||||
## Returns the final MD5 digest of an incremental hash computation.
|
||||
##
|
||||
## index: The unique identifier of this hash computation.
|
||||
## handle: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## Returns: The hash value associated with the computation at *index*.
|
||||
## Returns: The hash value associated with the computation of *handle*.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update
|
||||
## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function md5_hash_finish%(index: any%): string
|
||||
function md5_hash_finish%(handle: opaque of md5%): string
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
StringVal* printable_digest;
|
||||
|
||||
if ( md5_states.count(*s) > 0 )
|
||||
{
|
||||
unsigned char digest[16];
|
||||
md5_final(&md5_states[*s], digest);
|
||||
md5_states.erase(*s);
|
||||
printable_digest = new StringVal(md5_digest_print(digest));
|
||||
}
|
||||
else
|
||||
printable_digest = new StringVal("");
|
||||
|
||||
delete s;
|
||||
return printable_digest;
|
||||
return static_cast<HashVal*>(handle)->Get();
|
||||
%}
|
||||
|
||||
## Returns the final SHA1 digest of an incremental hash computation.
|
||||
##
|
||||
## index: The unique identifier of this hash computation.
|
||||
## handle: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## Returns: The hash value associated with the computation at *index*.
|
||||
## Returns: The hash value associated with the computation of *handle*.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_update
|
||||
## sha256_hash sha256_hash_init sha256_hash_update sha256_hash_finish
|
||||
function sha1_hash_finish%(index: any%): string
|
||||
function sha1_hash_finish%(handle: opaque of sha1%): string
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
StringVal* printable_digest;
|
||||
|
||||
if ( sha1_states.count(*s) > 0 )
|
||||
{
|
||||
unsigned char digest[20];
|
||||
sha1_final(&sha1_states[*s], digest);
|
||||
sha1_states.erase(*s);
|
||||
printable_digest = new StringVal(sha1_digest_print(digest));
|
||||
}
|
||||
else
|
||||
printable_digest = new StringVal("");
|
||||
|
||||
delete s;
|
||||
return printable_digest;
|
||||
return static_cast<HashVal*>(handle)->Get();
|
||||
%}
|
||||
|
||||
## Returns the final SHA256 digest of an incremental hash computation.
|
||||
##
|
||||
## index: The unique identifier of this hash computation.
|
||||
## handle: The opaque handle associated with this hash computation.
|
||||
##
|
||||
## Returns: The hash value associated with the computation at *index*.
|
||||
## Returns: The hash value associated with the computation of *handle*.
|
||||
##
|
||||
## .. bro:see:: md5_hmac md5_hash md5_hash_init md5_hash_update md5_hash_finish
|
||||
## sha1_hash sha1_hash_init sha1_hash_update sha1_hash_finish
|
||||
## sha256_hash sha256_hash_init sha256_hash_update
|
||||
function sha256_hash_finish%(index: any%): string
|
||||
function sha256_hash_finish%(handle: opaque of sha256%): string
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
StringVal* printable_digest;
|
||||
|
||||
if ( sha256_states.count(*s) > 0 )
|
||||
{
|
||||
unsigned char digest[32];
|
||||
sha256_final(&sha256_states[*s], digest);
|
||||
sha256_states.erase(*s);
|
||||
printable_digest = new StringVal(sha256_digest_print(digest));
|
||||
}
|
||||
else
|
||||
printable_digest = new StringVal("");
|
||||
|
||||
delete s;
|
||||
return printable_digest;
|
||||
return static_cast<HashVal*>(handle)->Get();
|
||||
%}
|
||||
|
||||
## Generates a random number.
|
||||
|
@ -1058,11 +878,6 @@ function identify_data%(data: string, return_mime: bool%): string
|
|||
return new StringVal(descr);
|
||||
%}
|
||||
|
||||
%%{
|
||||
#include <RandTest.h>
|
||||
static map<BroString, RandTest*> entropy_states;
|
||||
%%}
|
||||
|
||||
## Performs an entropy test on the given data.
|
||||
## See http://www.fourmilab.ch/random.
|
||||
##
|
||||
|
@ -1107,13 +922,11 @@ function find_entropy%(data: string%): entropy_test_result
|
|||
%{
|
||||
double montepi, scc, ent, mean, chisq;
|
||||
montepi = scc = ent = mean = chisq = 0.0;
|
||||
EntropyVal e;
|
||||
e.Feed(data->Bytes(), data->Len());
|
||||
e.Get(&ent, &chisq, &mean, &montepi, &scc);
|
||||
|
||||
RecordVal* ent_result = new RecordVal(entropy_test_result);
|
||||
RandTest *rt = new RandTest();
|
||||
|
||||
rt->add((char*) data->Bytes(), data->Len());
|
||||
rt->end(&ent, &chisq, &mean, &montepi, &scc);
|
||||
delete rt;
|
||||
|
||||
ent_result->Assign(0, new Val(ent, TYPE_DOUBLE));
|
||||
ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE));
|
||||
ent_result->Assign(2, new Val(mean, TYPE_DOUBLE));
|
||||
|
@ -1124,85 +937,52 @@ function find_entropy%(data: string%): entropy_test_result
|
|||
|
||||
## Initializes data structures for incremental entropy calculation.
|
||||
##
|
||||
## index: An arbitrary unique value per distinct computation.
|
||||
##
|
||||
## Returns: True on success.
|
||||
## Returns: An opaque handle to be used in subsequent operations.
|
||||
##
|
||||
## .. bro:see:: find_entropy entropy_test_add entropy_test_finish
|
||||
function entropy_test_init%(index: any%): bool
|
||||
function entropy_test_init%(%): opaque of entropy
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( entropy_states.count(*s) < 1 )
|
||||
{
|
||||
entropy_states[*s] = new RandTest();
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
return new Val(status, TYPE_BOOL);
|
||||
return new EntropyVal();
|
||||
%}
|
||||
|
||||
## Adds data to an incremental entropy calculation. Before using this function,
|
||||
## one needs to invoke :bro:id:`entropy_test_init`.
|
||||
## Adds data to an incremental entropy calculation.
|
||||
##
|
||||
## handle: The opaque handle representing the entropy calculation state.
|
||||
##
|
||||
## data: The data to add to the entropy calculation.
|
||||
##
|
||||
## index: An arbitrary unique value that identifies a particular entropy
|
||||
## computation.
|
||||
##
|
||||
## Returns: True on success.
|
||||
##
|
||||
## .. bro:see:: find_entropy entropy_test_add entropy_test_finish
|
||||
function entropy_test_add%(index: any, data: string%): bool
|
||||
function entropy_test_add%(handle: opaque of entropy, data: string%): bool
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
int status = 0;
|
||||
|
||||
if ( entropy_states.count(*s) > 0 )
|
||||
{
|
||||
entropy_states[*s]->add((char*) data->Bytes(), data->Len());
|
||||
status = 1;
|
||||
}
|
||||
|
||||
delete s;
|
||||
bool status = static_cast<EntropyVal*>(handle)->Feed(data->Bytes(),
|
||||
data->Len());
|
||||
return new Val(status, TYPE_BOOL);
|
||||
%}
|
||||
|
||||
## Finishes an incremental entropy calculation. Before using this function,
|
||||
## one needs to initialize the computation with :bro:id:`entropy_test_init` and
|
||||
## one needs to obtain an opaque handle with :bro:id:`entropy_test_init` and
|
||||
## add data to it via :bro:id:`entropy_test_add`.
|
||||
##
|
||||
## index: An arbitrary unique value that identifies a particular entropy
|
||||
## computation.
|
||||
## handle: The opaque handle representing the entropy calculation state.
|
||||
##
|
||||
## Returns: The result of the entropy test. See :bro:id:`find_entropy` for a
|
||||
## description of the individual components.
|
||||
##
|
||||
## .. bro:see:: find_entropy entropy_test_init entropy_test_add
|
||||
function entropy_test_finish%(index: any%): entropy_test_result
|
||||
function entropy_test_finish%(handle: opaque of entropy%): entropy_test_result
|
||||
%{
|
||||
BroString* s = convert_index_to_string(index);
|
||||
double montepi, scc, ent, mean, chisq;
|
||||
montepi = scc = ent = mean = chisq = 0.0;
|
||||
static_cast<EntropyVal*>(handle)->Get(&ent, &chisq, &mean, &montepi, &scc);
|
||||
|
||||
RecordVal* ent_result = new RecordVal(entropy_test_result);
|
||||
|
||||
if ( entropy_states.count(*s) > 0 )
|
||||
{
|
||||
RandTest *rt = entropy_states[*s];
|
||||
rt->end(&ent, &chisq, &mean, &montepi, &scc);
|
||||
entropy_states.erase(*s);
|
||||
delete rt;
|
||||
}
|
||||
|
||||
ent_result->Assign(0, new Val(ent, TYPE_DOUBLE));
|
||||
ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE));
|
||||
ent_result->Assign(2, new Val(mean, TYPE_DOUBLE));
|
||||
ent_result->Assign(3, new Val(montepi, TYPE_DOUBLE));
|
||||
ent_result->Assign(4, new Val(scc, TYPE_DOUBLE));
|
||||
|
||||
delete s;
|
||||
return ent_result;
|
||||
%}
|
||||
|
||||
|
@ -2684,8 +2464,9 @@ function to_port%(s: string%): port
|
|||
if ( s->Len() < 10 )
|
||||
{
|
||||
char* slash;
|
||||
errno = 0;
|
||||
port = strtol(s->CheckString(), &slash, 10);
|
||||
if ( port )
|
||||
if ( ! errno )
|
||||
{
|
||||
++slash;
|
||||
if ( streq(slash, "tcp") )
|
||||
|
|
|
@ -74,7 +74,9 @@ HEX [0-9a-fA-F]+
|
|||
"set" return check_c_mode(TOK_SET);
|
||||
"table" return check_c_mode(TOK_TABLE);
|
||||
"vector" return check_c_mode(TOK_VECTOR);
|
||||
"module" return check_c_mode(TOK_MODULE);
|
||||
"of" return check_c_mode(TOK_OF);
|
||||
"opaque" return check_c_mode(TOK_OPAQUE);
|
||||
"module" return check_c_mode(TOK_MODULE);
|
||||
|
||||
"@ARG@" return TOK_ARG;
|
||||
"@ARGS@" return TOK_ARGS;
|
||||
|
|
|
@ -269,15 +269,15 @@ void print_event_c_body(FILE *fp)
|
|||
|
||||
%token TOK_LPP TOK_RPP TOK_LPB TOK_RPB TOK_LPPB TOK_RPPB TOK_VAR_ARG
|
||||
%token TOK_BOOL
|
||||
%token TOK_FUNCTION TOK_EVENT TOK_CONST TOK_ENUM
|
||||
%token TOK_TYPE TOK_RECORD TOK_SET TOK_VECTOR TOK_TABLE TOK_MODULE
|
||||
%token TOK_FUNCTION TOK_EVENT TOK_CONST TOK_ENUM TOK_OF
|
||||
%token TOK_TYPE TOK_RECORD TOK_SET TOK_VECTOR TOK_OPAQUE TOK_TABLE TOK_MODULE
|
||||
%token TOK_ARGS TOK_ARG TOK_ARGC
|
||||
%token TOK_ID TOK_ATTR TOK_CSTR TOK_LF TOK_WS TOK_COMMENT
|
||||
%token TOK_ATOM TOK_INT TOK_C_TOKEN
|
||||
|
||||
%left ',' ':'
|
||||
|
||||
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws
|
||||
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type
|
||||
%type <val> TOK_ATOM TOK_BOOL
|
||||
|
||||
%union {
|
||||
|
@ -584,7 +584,17 @@ args_1: args_1 ',' opt_ws arg opt_ws
|
|||
{ /* empty */ }
|
||||
;
|
||||
|
||||
arg: TOK_ID opt_ws ':' opt_ws TOK_ID
|
||||
// TODO: Migrate all other compound types to this rule. Once the BiF language
|
||||
// can parse all regular Bro types, we can throw out the unnecessary
|
||||
// boilerplate typedefs for addr_set, string_set, etc.
|
||||
type:
|
||||
TOK_OPAQUE opt_ws TOK_OF opt_ws TOK_ID
|
||||
{ $$ = concat("opaque of ", $5); }
|
||||
| TOK_ID
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
arg: TOK_ID opt_ws ':' opt_ws type
|
||||
{ args.push_back(new BuiltinFuncArg($1, $5)); }
|
||||
| TOK_VAR_ARG
|
||||
{
|
||||
|
@ -594,7 +604,7 @@ arg: TOK_ID opt_ws ':' opt_ws TOK_ID
|
|||
}
|
||||
;
|
||||
|
||||
return_type: ':' opt_ws TOK_ID opt_ws
|
||||
return_type: ':' opt_ws type opt_ws
|
||||
{
|
||||
BuiltinFuncArg* ret = new BuiltinFuncArg("", $3);
|
||||
ret->PrintBro(fp_bro_init);
|
||||
|
|
|
@ -213,8 +213,6 @@ bool Ascii::GetLine(string& str)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// read the entire file and send appropriate thingies back to InputMgr
|
||||
bool Ascii::DoUpdate()
|
||||
{
|
||||
|
|
16
src/parse.y
16
src/parse.y
|
@ -11,7 +11,7 @@
|
|||
%token TOK_DOUBLE TOK_ELSE TOK_ENUM TOK_EVENT TOK_EXPORT TOK_FILE TOK_FOR
|
||||
%token TOK_FUNCTION TOK_GLOBAL TOK_HOOK TOK_ID TOK_IF TOK_INT
|
||||
%token TOK_INTERVAL TOK_LIST TOK_LOCAL TOK_MODULE
|
||||
%token TOK_NEXT TOK_OF TOK_PATTERN TOK_PATTERN_TEXT
|
||||
%token TOK_NEXT TOK_OF TOK_OPAQUE TOK_PATTERN TOK_PATTERN_TEXT
|
||||
%token TOK_PORT TOK_PRINT TOK_RECORD TOK_REDEF
|
||||
%token TOK_REMOVE_FROM TOK_RETURN TOK_SCHEDULE TOK_SET
|
||||
%token TOK_STRING TOK_SUBNET TOK_SWITCH TOK_TABLE
|
||||
|
@ -418,6 +418,14 @@ expr:
|
|||
$$ = new IndexExpr($1, $3);
|
||||
}
|
||||
|
||||
| expr '[' expr ':' expr ']'
|
||||
{
|
||||
set_location(@1, @6);
|
||||
ListExpr* le = new ListExpr($3);
|
||||
le->Append($5);
|
||||
$$ = new IndexExpr($1, le, true);
|
||||
}
|
||||
|
||||
| expr '$' TOK_ID
|
||||
{
|
||||
set_location(@1, @3);
|
||||
|
@ -899,6 +907,12 @@ type:
|
|||
$$ = new FileType(base_type(TYPE_STRING));
|
||||
}
|
||||
|
||||
| TOK_OPAQUE TOK_OF TOK_ID
|
||||
{
|
||||
set_location(@1, @3);
|
||||
$$ = new OpaqueType($3);
|
||||
}
|
||||
|
||||
| resolve_id
|
||||
{
|
||||
if ( ! $1 || ! ($$ = $1->AsType()) )
|
||||
|
|
|
@ -298,6 +298,7 @@ local return TOK_LOCAL;
|
|||
module return TOK_MODULE;
|
||||
next return TOK_NEXT;
|
||||
of return TOK_OF;
|
||||
opaque return TOK_OPAQUE;
|
||||
pattern return TOK_PATTERN;
|
||||
port return TOK_PORT;
|
||||
print return TOK_PRINT;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue