Merge remote-tracking branch 'origin/master' into topic/bernhard/input-logging-commmon-functions

Conflicts:
	src/input/readers/Ascii.cc
This commit is contained in:
Bernhard Amann 2013-01-11 09:48:53 -08:00
commit 1b0bb5063a
66 changed files with 2367 additions and 564 deletions

View file

@ -361,6 +361,7 @@ set(bro_SRCS
NetVar.cc
NetbiosSSN.cc
Obj.cc
OpaqueVal.cc
OSFinger.cc
PacketFilter.cc
PacketSort.cc

View file

@ -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);

View file

@ -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;

View file

@ -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
View 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
View 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

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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 {

View file

@ -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;

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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)

View file

@ -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,

View file

@ -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());

View file

@ -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") )

View file

@ -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;

View file

@ -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);

View file

@ -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()
{

View file

@ -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()) )

View file

@ -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;