From 8bacb6eb3d9b5ad9dca8001d02f563dab8a46b51 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 7 Jul 2011 18:41:50 -0700 Subject: [PATCH] New BiF record_field_vals() that returns the fields of a record in a table with meta-information. Example: type r: record { a: count; b: string &default="Foo"; c: double &optional; d: string &log; }; event bro_init() { local x: r = [$a=42, $d="Bar"]; print record_fields(x); } This prints: { [a] = [type_name=record, log=F, value=42, default_val=] [b] = [type_name=record, log=F, value=, default_val=Foo], [c] = [type_name=record, log=F, value=, default_val=], [d] = [type_name=record, log=T, value=Bar, default_val=], } This is one more step in Seth's quest for full inspection support. :-) --- policy/bro.init | 13 +++++- src/NetVar.cc | 4 ++ src/NetVar.h | 2 + src/Type.cc | 12 ++++++ src/Type.h | 1 + src/Val.cc | 6 +-- src/bro.bif | 42 ++++++++++++++++++- .../btest/Baseline/bifs.records_fields/out | 8 ++++ testing/btest/bifs/records_fields.bro | 20 +++++++++ 9 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 testing/btest/Baseline/bifs.records_fields/out create mode 100644 testing/btest/bifs/records_fields.bro diff --git a/policy/bro.init b/policy/bro.init index 8f2ef568c6..2f3db3939d 100644 --- a/policy/bro.init +++ b/policy/bro.init @@ -183,6 +183,17 @@ type script_id: record { value: any &optional; }; +type id_table: table[string] of script_id; + +type record_field: record { + type_name: string; + log: bool; + value: any &optional; + default_val: any &optional; +}; + +type record_field_table: table[string] of record_field; + # The following two variables are defined here until the core is not # dependent on the names remaining as they are now. ## This is the list of capture filters indexed by some user-definable ID. @@ -190,8 +201,6 @@ global capture_filters: table[string] of string &redef; ## This is the list of restriction filters indexed by some user-definable ID. global restrict_filters: table[string] of string &redef; -type id_table: table[string] of script_id; - # {precompile,install}_pcap_filter identify the filter by IDs type PcapFilterID: enum { None }; diff --git a/src/NetVar.cc b/src/NetVar.cc index b8ea954c45..cc40681494 100644 --- a/src/NetVar.cc +++ b/src/NetVar.cc @@ -248,6 +248,8 @@ int record_all_packets; RecordType* script_id; TableType* id_table; +RecordType* record_field; +TableType* record_field_table; StringVal* cmd_line_bpf_filter; @@ -550,4 +552,6 @@ void init_net_var() script_id = internal_type("script_id")->AsRecordType(); id_table = internal_type("id_table")->AsTableType(); + record_field = internal_type("record_field")->AsRecordType(); + record_field_table = internal_type("record_field_table")->AsTableType(); } diff --git a/src/NetVar.h b/src/NetVar.h index 50b558a69b..b9667a19c9 100644 --- a/src/NetVar.h +++ b/src/NetVar.h @@ -251,6 +251,8 @@ extern int record_all_packets; extern RecordType* script_id; extern TableType* id_table; +extern RecordType* record_field; +extern TableType* record_field_table; extern StringVal* cmd_line_bpf_filter; diff --git a/src/Type.cc b/src/Type.cc index 5da892d87f..521db20ebf 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -987,6 +987,18 @@ BroType* RecordType::FieldType(int field) const } } +Val* RecordType::FieldDefault(int field) const + { + const TypeDecl* td = FieldDecl(field); + + if ( ! td->attrs ) + return false; + + const Attr* def_attr = td->attrs->FindAttr(ATTR_DEFAULT); + + return def_attr ? def_attr->AttrExpr()->Eval(0) : 0; + } + int RecordType::FieldOffset(const char* field) const { if ( types ) diff --git a/src/Type.h b/src/Type.h index b8cb7e2aa5..6ab8c65e03 100644 --- a/src/Type.h +++ b/src/Type.h @@ -448,6 +448,7 @@ public: int HasField(const char* field) const; BroType* FieldType(const char* field) const; BroType* FieldType(int field) const; + Val* FieldDefault(int field) const; // Ref's the returned value; 0 if none. // A field's offset is its position in the type_decl_list, // starting at 0. Returns negative if the field doesn't exist. diff --git a/src/Val.cc b/src/Val.cc index 3aaf0d7bf0..0172657366 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -2935,11 +2935,7 @@ Val* RecordVal::LookupWithDefault(int field) const if ( val ) return val->Ref(); - // Check for &default. - const Attr* def_attr = - record_type->FieldDecl(field)->attrs->FindAttr(ATTR_DEFAULT); - - return def_attr ? def_attr->AttrExpr()->Eval(0) : 0; + return record_type->FieldDefault(field); } RecordVal* RecordVal::CoerceTo(const RecordType* t, Val* aggr) const diff --git a/src/bro.bif b/src/bro.bif index 5f078c2769..d77d6b53f7 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -1657,6 +1657,44 @@ function global_ids%(%): id_table return ids; %} +function record_fields%(rec: any%): record_field_table + %{ + TableVal* fields = new TableVal(record_field_table); + + RecordVal* rv = rec->AsRecordVal(); + RecordType* rt = rv->Type()->AsRecordType(); + + if ( rt->Tag() != TYPE_RECORD ) + { + reporter->Error("non-record passed to record_fields"); + return fields; + } + + for ( int i = 0; i < rt->NumFields(); ++i ) + { + BroType* ft = rt->FieldType(i); + TypeDecl* fd = rt->FieldDecl(i); + Val* fv = rv->Lookup(i); + + if ( fv ) + Ref(fv); + + bool logged = (fd->attrs && fd->FindAttr(ATTR_LOG) != 0); + + RecordVal* nr = new RecordVal(record_field); + nr->Assign(0, new StringVal(type_name(rt->Tag()))); + nr->Assign(1, new Val(logged, TYPE_BOOL)); + nr->Assign(2, fv); + nr->Assign(3, rt->FieldDefault(i)); + + Val* field_name = new StringVal(rt->FieldName(i)); + fields->Assign(field_name, nr); + Unref(field_name); + } + + return fields; + %} + %%{ #include "Anon.h" %%} @@ -3410,7 +3448,7 @@ function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: tabl BroString* s = convert_index_to_string(root_certs); if ( x509_stores.count(*s) > 0 ) ctx = x509_stores[*s]; - + if ( ! ctx ) // lookup to see if we have this one built already! { ctx = X509_STORE_new(); @@ -3437,7 +3475,7 @@ function x509_verify%(der_cert: string, cert_stack: string_vec, root_certs: tabl x509_stores[*s] = ctx; } delete s; - + const uint8 *cert_data = der_cert->Bytes(); X509* cert = d2i_X509_(NULL, &cert_data, der_cert->Len()); if ( ! cert ) diff --git a/testing/btest/Baseline/bifs.records_fields/out b/testing/btest/Baseline/bifs.records_fields/out new file mode 100644 index 0000000000..b221230fc0 --- /dev/null +++ b/testing/btest/Baseline/bifs.records_fields/out @@ -0,0 +1,8 @@ +[a=42, b=, c=, d=Bar] +{ +[b] = [type_name=record, log=F, value=, default_val=Foo], +[d] = [type_name=record, log=T, value=Bar, default_val=], +[c] = [type_name=record, log=F, value=, default_val=], +[a] = [type_name=record, log=F, value=42, default_val=] +} +F diff --git a/testing/btest/bifs/records_fields.bro b/testing/btest/bifs/records_fields.bro new file mode 100644 index 0000000000..4f8cc0538a --- /dev/null +++ b/testing/btest/bifs/records_fields.bro @@ -0,0 +1,20 @@ +# +# @TEST-EXEC: bro %INPUT >out +# @TEST-EXEC: btest-diff out + +type r: record { + a: count; + b: string &default="Foo"; + c: double &optional; + d: string &log; +}; + +event bro_init() +{ + local x: r = [$a=42, $d="Bar"]; + print x; + local t: record_field_table; + t = record_fields(x); + print t; + print t["c"]?$value; +}