From f3b148b019ee3db1ce82c92161e3aa05e45073a8 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 19 Jan 2011 09:36:06 -0500 Subject: [PATCH 001/150] Checkpoint for logging framework --- policy/logging.bro | 93 +++++++++++++++++++++++++++++++++++++++++ policy/test-logging.bro | 27 ++++++++++++ src/Type.cc | 4 +- src/Val.cc | 4 ++ src/bro.bif | 12 ++++++ 5 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 policy/logging.bro create mode 100644 policy/test-logging.bro diff --git a/policy/logging.bro b/policy/logging.bro new file mode 100644 index 0000000000..2a61a12a63 --- /dev/null +++ b/policy/logging.bro @@ -0,0 +1,93 @@ +module Logging; + +export { + # The set of writers Bro provides. + type Writer: enum { + WRITER_DEFAULT, # See default_writer below. + WRITER_CSV, + WRITER_DATA_SERIES, + WRITER_SYSLOG + }; + + # Each stream gets a unique ID. This type will be extended by + # other scripts. + type ID: enum { + Unknown + }; + + # The default writer to use if a filter does not specify + # anything else. + const default_writer = WRITER_CSV &redef; + + # Type defining a stream. + type Stream: record { + id : ID; # The ID of the stream. + columns : any; # A record type defining the stream's output columns. + }; + + # A filter defining what to record. + type Filter: record { + # A name to reference this filter. + name: string; + + # A predicate returning True if the filter wants a log entry + # to be recorded. If not given, an implicit True is assumed + # for all entries. The predicate receives one parameter: + # an instance of the log's record type with the fields to be + # logged. + pred: function(log: any) &optional; + + # A path for outputting everything matching this + # filter. The path is either a string, or a function + # called with a single ``ID`` argument and returning a string. + # + # The specific interpretation of the string is left to the + # Writer, but if it's refering to a file, it's assumed that no + # extension is given; the writer will add whatever is + # appropiate. + path: any &optional; + + # A subset of column names to record. If not given, all + # columns are recorded. + select: set[string] &optional; + + # An event that is raised whenever the filter is applied + # to an entry. The event receives the same parameter + # as the predicate. It will always be generated, + # independent of what the predicate returns. + ev: event(c: connection, log: any) &optional; + + # The writer to use. + writer: Writer &default=default_writer; + }; + + global filters: table[ID] of set[Filter]; + + # Logs the record "rec" to the stream "id". The type of + # "rec" must match the stream's "columns" field. + global log: function(id: ID, rec: any); + + # Returns an existing filter previously installed for stream + # "id" under the given "name". If no such filter exists, + # the record "NoSuchFilter" is returned. + global get_filter: function(id: ID, name: string) : Filter; + + global create: function(stream: Stream); + global add_filter: function(id: ID, filter: Filter); +} + +# Sentinel representing an unknown filter. +const NoSuchFilter: Filter = [$name=""]; + +function add_filter(id: ID, filter: Filter) + { + if ( id !in filters ) + filters[id] = set(); + + add filters[id][filter]; + } + +function log(id: ID, rec: any) + { + logging_log(id, rec); + } \ No newline at end of file diff --git a/policy/test-logging.bro b/policy/test-logging.bro new file mode 100644 index 0000000000..267f9c36a5 --- /dev/null +++ b/policy/test-logging.bro @@ -0,0 +1,27 @@ +module SSH; + +@load logging + +# Create a new ID for our log stream +redef enum Logging::ID += { SSH }; + +# Define a record with all the columns the log file can have. +# (I'm using a subset of fields from ssh-ext for demonstration.) +type Log: record { + t: time; + id: conn_id; # Will be rolled out into individual columns. + status: string &optional; + country: string &default="unknown"; +}; + +event bro_init() +{ + # Create the stream. + Logging::create([$id=SSH, $columns=Log]); + + # Add a default filter that simply logs everything to "ssh.log" using the default writer. + #Logging::add_filter(SSH, [$name="default", $path="ssh"]); +} + +# Log something. +Logging::log(SSH, [$t=network_time(), $status="ok"]); diff --git a/src/Type.cc b/src/Type.cc index 1f5c22d58b..7e08c4b140 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1336,7 +1336,9 @@ static int is_init_compat(const BroType* t1, const BroType* t2) int same_type(const BroType* t1, const BroType* t2, int is_init) { - if ( t1 == t2 ) + if ( t1 == t2 || + t1->Tag() == TYPE_ANY || + t2->Tag() == TYPE_ANY ) return 1; t1 = flatten_type(t1); diff --git a/src/Val.cc b/src/Val.cc index f43bafe4d7..307bad61d1 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -3300,6 +3300,10 @@ Val* check_and_promote(Val* v, const BroType* t, int is_init) TypeTag t_tag = t->Tag(); TypeTag v_tag = vt->Tag(); + + // More thought definitely needs to go into this. + if ( t_tag == TYPE_ANY || v_tag == TYPE_ANY ) + return v; if ( ! EitherArithmetic(t_tag, v_tag) || /* allow sets as initializers */ diff --git a/src/bro.bif b/src/bro.bif index 0de77bfc49..78e83b920b 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -359,6 +359,18 @@ function cat%(...%): string return new StringVal(s); %} + +function logging_log%(id: Logging_ID, rec: any%): bool + %{ + // Generate the log line event + // Lookup the log file + TableVal *f = opt_internal_table("Logging::filters"); + TableVal *s = f->Lookup(id, 0)->AsTableVal(); + + // For each filter on 'id' + // Format the output + // Print the line + %} function cat_sep%(sep: string, def: string, ...%): string %{ From 4df961aa60296214af90232f236a4e2587e7e880 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Fri, 21 Jan 2011 16:46:06 -0500 Subject: [PATCH 002/150] Log specific event and debug log printing is working! This is mostly a code checkpoint though. --- policy/logging.bro | 55 +++++++++++++++++++------- policy/test-logging.bro | 37 +++++++++++------- src/bro.bif | 87 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 142 insertions(+), 37 deletions(-) diff --git a/policy/logging.bro b/policy/logging.bro index 2a61a12a63..10690a8fbd 100644 --- a/policy/logging.bro +++ b/policy/logging.bro @@ -20,10 +20,10 @@ export { const default_writer = WRITER_CSV &redef; # Type defining a stream. - type Stream: record { - id : ID; # The ID of the stream. - columns : any; # A record type defining the stream's output columns. - }; + #type Stream: record { + # id : string; # The ID of the stream. + # columns : string_vec; # A record type defining the stream's output columns. + #}; # A filter defining what to record. type Filter: record { @@ -61,33 +61,58 @@ export { writer: Writer &default=default_writer; }; - global filters: table[ID] of set[Filter]; + global filters: table[string] of set[Filter]; + global streams: table[string] of string_vec; # Logs the record "rec" to the stream "id". The type of # "rec" must match the stream's "columns" field. - global log: function(id: ID, rec: any); + global log: function(id: string, rec: any); + global log_ev: event(id: string, rec: any); # Returns an existing filter previously installed for stream # "id" under the given "name". If no such filter exists, # the record "NoSuchFilter" is returned. - global get_filter: function(id: ID, name: string) : Filter; + global get_filter: function(id: string, name: string) : Filter; + + global create_stream: function(id: string, columns: string); + global add_filter: function(id: string, filter: Filter); + + global open_log_files: function(id: string); - global create: function(stream: Stream); - global add_filter: function(id: ID, filter: Filter); } # Sentinel representing an unknown filter. const NoSuchFilter: Filter = [$name=""]; -function add_filter(id: ID, filter: Filter) +function create_stream(id: string, columns: string) { - if ( id !in filters ) - filters[id] = set(); + if ( id in streams ) + print fmt("Stream %s already exists!", id); - add filters[id][filter]; + streams[id] = record_type_to_vector(columns); } - -function log(id: ID, rec: any) + +function add_filter(id: string, filter: Filter) + { + #if ( id !in filters ) + # filters[id] = set(); + # + #add filters[id][filter]; + } + +function log(id: string, rec: any) { logging_log(id, rec); + } + + +# THIS IS ONLY FOR THE PROTOTYPE. +# It will be implemented in the core later +function open_log_files(id: string) + { + # Open default log + #open_log_file(id); + + # Find all second names from filters + # Open log for each secondary name } \ No newline at end of file diff --git a/policy/test-logging.bro b/policy/test-logging.bro index 267f9c36a5..0bb97b962f 100644 --- a/policy/test-logging.bro +++ b/policy/test-logging.bro @@ -2,26 +2,35 @@ module SSH; @load logging -# Create a new ID for our log stream -redef enum Logging::ID += { SSH }; +export { + # Create a new ID for our log stream + redef enum Logging::ID += { LOG_SSH }; -# Define a record with all the columns the log file can have. -# (I'm using a subset of fields from ssh-ext for demonstration.) -type Log: record { - t: time; - id: conn_id; # Will be rolled out into individual columns. - status: string &optional; - country: string &default="unknown"; -}; + # Define a record with all the columns the log file can have. + # (I'm using a subset of fields from ssh-ext for demonstration.) + type Log: record { + t: time; + id: conn_id; # Will be rolled out into individual columns. + status: string &optional; + country: string &default="unknown"; + }; + + global ssh_log: event(rec: Log); +} event bro_init() { # Create the stream. - Logging::create([$id=SSH, $columns=Log]); + Logging::create_stream("ssh", "SSH::Log"); # Add a default filter that simply logs everything to "ssh.log" using the default writer. - #Logging::add_filter(SSH, [$name="default", $path="ssh"]); + #Logging::add_filter("SSH", [$name="default", $path="ssh"]); + + # Log something. + Logging::log("ssh", [$t=network_time(), $country="US", $status="ok"]); } -# Log something. -Logging::log(SSH, [$t=network_time(), $status="ok"]); +event ssh_log(rec: Log) + { + print "Ran the ssh_log handler! kick ass"; + } \ No newline at end of file diff --git a/src/bro.bif b/src/bro.bif index c9e40f6278..c1eeb4145e 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -360,18 +360,89 @@ function cat%(...%): string return new StringVal(s); %} -function logging_log%(id: Logging_ID, rec: any%): bool +function logging_log%(index: string, rec: any%): bool %{ - // Generate the log line event - // Lookup the log file - TableVal *f = opt_internal_table("Logging::filters"); - TableVal *s = f->Lookup(id, 0)->AsTableVal(); + // Verify that rec is a record + // Lookup the stream + TableVal *streams = opt_internal_table("Logging::streams"); + VectorVal *columns; + if ( streams ) + { + Val *lookup_v = streams->Lookup(index); + if ( lookup_v ) + columns = lookup_v->AsVectorVal(); + } + else + { + printf("Logging framework is dead (Logging::streams not found).\n"); + return false; + } + // Generate the event for the log stream + // TODO: make it actually figure out the right handler name. + EventHandlerPtr ev_ptr = internal_handler("SSH::ssh_log"); + if ( ev_ptr ) + { + val_list* vl = new val_list; + vl->append(rec->Ref()); + mgr.QueueEvent(, vl, SOURCE_LOCAL); + } + + // Lookup all filters for stream + TableVal *filters = opt_internal_table("Logging::filters"); + RecordVal *stream_filters; + if ( filters ) + { + Val *lookup_v = filters->Lookup(index); + if ( lookup_v ) + stream_filters = lookup_v->AsRecordVal(); + } + else + { + printf("Logging framework is dead (Logging::filters not found).\n"); + return false; + } + + ODesc d; + const char *field_name; + int field = 0; + RecordType *rt = rec->Type()->AsRecordType(); + for ( unsigned i = 1; i <= columns->Size(); ++i ) + { + field_name = columns->Lookup(i)->AsStringVal()->CheckString(); + field = rec->Type()->AsRecordType()->FieldOffset(field_name); + if ( field >= 0 ) // or if there is a default value + { + rec->AsRecordVal()->Lookup(field)->Describe(&d); + d.Add("\t",0); + } + //printf("Test: %s\n", field_name); + } + printf("Full line: %s\n", d.TakeBytes()); // For each filter on 'id' - // Format the output - // Print the line + // Format the output (iterate through columns and grab fields from rec as found) + // Print the line (send line onward to WRITER) + return false; %} - + +function record_type_to_vector%(rt: string%): string_vec + %{ + VectorVal* result = + new VectorVal(internal_type("string_vec")->AsVectorType()); + + RecordType *type = internal_type(rt->CheckString())->AsRecordType(); + if ( type ) + { + for ( int i = 0; i < type->NumFields(); ++i ) + { + StringVal* val = new StringVal(type->FieldName(i)); + result->Assign(i+1, val, 0); + } + } + return result; + %} + + function cat_sep%(sep: string, def: string, ...%): string %{ ODesc d; From d2628d30fa3c9ebfd37d2276b5db7d333c6e4142 Mon Sep 17 00:00:00 2001 From: Seth Hall Date: Wed, 26 Jan 2011 15:29:20 -0500 Subject: [PATCH 003/150] Logging framework core functionality now implemented. --- policy/logging.bro | 118 +++++++++++++++++++--------------------- policy/test-logging.bro | 23 ++++++-- src/bro.bif | 65 +++++++++++++--------- 3 files changed, 112 insertions(+), 94 deletions(-) diff --git a/policy/logging.bro b/policy/logging.bro index 10690a8fbd..26f9c01640 100644 --- a/policy/logging.bro +++ b/policy/logging.bro @@ -3,66 +3,67 @@ module Logging; export { # The set of writers Bro provides. type Writer: enum { - WRITER_DEFAULT, # See default_writer below. - WRITER_CSV, - WRITER_DATA_SERIES, - WRITER_SYSLOG + WRITER_DEFAULT, # See default_writer below. + WRITER_CSV, + WRITER_DATA_SERIES, + WRITER_SYSLOG }; # Each stream gets a unique ID. This type will be extended by # other scripts. type ID: enum { - Unknown - }; - + Unknown + }; + # The default writer to use if a filter does not specify # anything else. const default_writer = WRITER_CSV &redef; # Type defining a stream. - #type Stream: record { - # id : string; # The ID of the stream. - # columns : string_vec; # A record type defining the stream's output columns. - #}; + type Stream: record { + name: string; + columns: string_vec; + }; # A filter defining what to record. type Filter: record { - # A name to reference this filter. - name: string; - - # A predicate returning True if the filter wants a log entry - # to be recorded. If not given, an implicit True is assumed - # for all entries. The predicate receives one parameter: - # an instance of the log's record type with the fields to be - # logged. - pred: function(log: any) &optional; - - # A path for outputting everything matching this - # filter. The path is either a string, or a function - # called with a single ``ID`` argument and returning a string. - # - # The specific interpretation of the string is left to the - # Writer, but if it's refering to a file, it's assumed that no - # extension is given; the writer will add whatever is - # appropiate. - path: any &optional; - - # A subset of column names to record. If not given, all - # columns are recorded. - select: set[string] &optional; - - # An event that is raised whenever the filter is applied - # to an entry. The event receives the same parameter - # as the predicate. It will always be generated, - # independent of what the predicate returns. - ev: event(c: connection, log: any) &optional; - - # The writer to use. - writer: Writer &default=default_writer; - }; + # A name to reference this filter. + name: string; + + # A predicate returning True if the filter wants a log entry + # to be recorded. If not given, an implicit True is assumed + # for all entries. The predicate receives one parameter: + # an instance of the log's record type with the fields to be + # logged. + pred: function(log: any) &optional; + + # A path for outputting everything matching this + # filter. The path is either a string, or a function + # called with a single ``ID`` argument and returning a string. + # + # The specific interpretation of the string is left to the + # Writer, but if it's refering to a file, it's assumed that no + # extension is given; the writer will add whatever is + # appropiate. + path: any &optional; + + # A subset of column names to record. If not given, all + # columns are recorded. + select: set[string] &optional; + + # An event that is raised whenever the filter is applied + # to an entry. The event receives the same parameter + # as the predicate. It will always be generated, + # independent of what the predicate returns. + ev: event(l: any) &optional; + + # The writer to use. + writer: Writer &default=default_writer; + }; + global filters: table[string] of set[Filter]; - global streams: table[string] of string_vec; + global streams: table[string] of Stream; # Logs the record "rec" to the stream "id". The type of # "rec" must match the stream's "columns" field. @@ -74,7 +75,7 @@ export { # the record "NoSuchFilter" is returned. global get_filter: function(id: string, name: string) : Filter; - global create_stream: function(id: string, columns: string); + global create_stream: function(id: string, log_record_type: string); global add_filter: function(id: string, filter: Filter); global open_log_files: function(id: string); @@ -84,20 +85,22 @@ export { # Sentinel representing an unknown filter. const NoSuchFilter: Filter = [$name=""]; -function create_stream(id: string, columns: string) +function create_stream(id: string, log_record_type: string) { if ( id in streams ) print fmt("Stream %s already exists!", id); - streams[id] = record_type_to_vector(columns); + streams[id] = [$name=log_record_type, $columns=record_type_to_vector(log_record_type)]; } function add_filter(id: string, filter: Filter) { - #if ( id !in filters ) - # filters[id] = set(); - # - #add filters[id][filter]; + if ( id !in filters ) + filters[id] = set(); + + # TODO: This is broken and waiting on a bug fix for &optional fields + # in records being used as indexes. + #add filt[filter]; } function log(id: string, rec: any) @@ -105,14 +108,3 @@ function log(id: string, rec: any) logging_log(id, rec); } - -# THIS IS ONLY FOR THE PROTOTYPE. -# It will be implemented in the core later -function open_log_files(id: string) - { - # Open default log - #open_log_file(id); - - # Find all second names from filters - # Open log for each secondary name - } \ No newline at end of file diff --git a/policy/test-logging.bro b/policy/test-logging.bro index 0bb97b962f..dde9bb8a2f 100644 --- a/policy/test-logging.bro +++ b/policy/test-logging.bro @@ -15,22 +15,37 @@ export { country: string &default="unknown"; }; - global ssh_log: event(rec: Log); + # This is the prototype for the event that the logging framework tries + # to generate if there is a handler for it. + global log: event(rec: Log); } event bro_init() { # Create the stream. + # First argument is the ID for the stream. + # Second argument is the log record type. Logging::create_stream("ssh", "SSH::Log"); # Add a default filter that simply logs everything to "ssh.log" using the default writer. - #Logging::add_filter("SSH", [$name="default", $path="ssh"]); + # Filtering is not implemented yet. Waiting on ticket #366 + # Log line event generation is autogenerated for now by checking for + # handlers for MODULE_NAME::log + #Logging::add_filter("ssh", [$name="default", $path="ssh", $ev=log]); # Log something. Logging::log("ssh", [$t=network_time(), $country="US", $status="ok"]); } -event ssh_log(rec: Log) +event log(rec: Log) { - print "Ran the ssh_log handler! kick ass"; + print fmt("Ran the log handler from the same module. Extracting time: %0.6f", rec$t); + } + + +module WHATEVER; + +event SSH::log(rec: SSH::Log) + { + print fmt("Ran the SSH::log handler from a different module. Extracting time: %0.6f", rec$t); } \ No newline at end of file diff --git a/src/bro.bif b/src/bro.bif index c1eeb4145e..ec14775a69 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -360,17 +360,22 @@ function cat%(...%): string return new StringVal(s); %} -function logging_log%(index: string, rec: any%): bool +function logging_log%(index: string, rec: any%): any %{ // Verify that rec is a record + // Lookup the stream TableVal *streams = opt_internal_table("Logging::streams"); VectorVal *columns; + RecordVal *stream_record; if ( streams ) { - Val *lookup_v = streams->Lookup(index); - if ( lookup_v ) - columns = lookup_v->AsVectorVal(); + stream_record = streams->Lookup(index)->AsRecordVal(); + if ( stream_record ) + { + int columns_field = stream_record->Type()->AsRecordType()->FieldOffset("columns"); + columns = stream_record->Lookup(columns_field)->AsVectorVal(); + } } else { @@ -378,31 +383,40 @@ function logging_log%(index: string, rec: any%): bool return false; } - // Generate the event for the log stream - // TODO: make it actually figure out the right handler name. - EventHandlerPtr ev_ptr = internal_handler("SSH::ssh_log"); + // Generate the event for the log stream + // This happens regardless of all filters. + int name_field = stream_record->Type()->AsRecordType()->FieldOffset("name"); + StringVal *log_type = stream_record->AsRecordVal()->Lookup(name_field)->AsStringVal(); + string ID_module = extract_module_name(log_type->CheckString()); + // The log event that is generated by default is MODULE_NAME::log + string log_event_name = make_full_var_name(ID_module.c_str(), "log"); + EventHandlerPtr ev_ptr = internal_handler(log_event_name.c_str()); if ( ev_ptr ) { val_list* vl = new val_list; vl->append(rec->Ref()); - mgr.QueueEvent(, vl, SOURCE_LOCAL); + mgr.QueueEvent(ev_ptr, vl, SOURCE_LOCAL); } // Lookup all filters for stream - TableVal *filters = opt_internal_table("Logging::filters"); - RecordVal *stream_filters; - if ( filters ) - { - Val *lookup_v = filters->Lookup(index); - if ( lookup_v ) - stream_filters = lookup_v->AsRecordVal(); - } - else - { - printf("Logging framework is dead (Logging::filters not found).\n"); - return false; - } + // (ignore this code, it will probably be done in the logging.bro script + // with the "match" statement) + //TableVal *filters = opt_internal_table("Logging::filters"); + //RecordVal *stream_filters; + //if ( filters ) + // { + // Val *lookup_v = filters->Lookup(index); + // if ( lookup_v ) + // stream_filters = lookup_v->AsRecordVal(); + // } + //else + // { + // printf("Logging framework is dead (Logging::filters not found).\n"); + // return false; + // } + // Print the line + // (send line onward to the filter's WRITER in the future) ODesc d; const char *field_name; int field = 0; @@ -416,13 +430,10 @@ function logging_log%(index: string, rec: any%): bool rec->AsRecordVal()->Lookup(field)->Describe(&d); d.Add("\t",0); } - //printf("Test: %s\n", field_name); } - printf("Full line: %s\n", d.TakeBytes()); - // For each filter on 'id' - // Format the output (iterate through columns and grab fields from rec as found) - // Print the line (send line onward to WRITER) - return false; + + printf("%s: %s\n", ID_module.c_str(), d.TakeBytes()); + return 0; %} function record_type_to_vector%(rt: string%): string_vec From 7abd8f177f1d6a082cf2539266cd53d730f664cf Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Wed, 2 Feb 2011 18:06:02 -0800 Subject: [PATCH 004/150] Fixing a problem with records having optional fields when used as table/set indices. This addresses #367. In principle, the fix is quite straightford. However, it turns out that sometimes record fields lost their attributes on assignment, and then the hashing can't decide anymore whether a field is optional or not. So that needed to be fixed as well. --- src/Attr.cc | 35 ++++++++++++++++++++++++ src/Attr.h | 16 +++++++++++ src/CompHash.cc | 62 +++++++++++++++++++++++++++++++++--------- src/CompHash.h | 6 ++--- src/Expr.cc | 71 +++++++++++++++++++++++++++++++++++++------------ src/Type.cc | 11 ++++++++ src/Type.h | 3 +++ 7 files changed, 171 insertions(+), 33 deletions(-) diff --git a/src/Attr.cc b/src/Attr.cc index 5a83d0501b..e03367c41e 100644 --- a/src/Attr.cc +++ b/src/Attr.cc @@ -327,6 +327,41 @@ void Attributes::CheckAttr(Attr* a) } } +bool Attributes::operator==(const Attributes& other) const + { + if ( ! attrs ) + return other.attrs; + + if ( ! other.attrs ) + return false; + + loop_over_list(*attrs, i) + { + Attr* a = (*attrs)[i]; + Attr* o = other.FindAttr(a->Tag()); + + if ( ! o ) + return false; + + if ( ! (*a == *o) ) + return false; + } + + loop_over_list(*other.attrs, j) + { + Attr* o = (*other.attrs)[j]; + Attr* a = FindAttr(o->Tag()); + + if ( ! a ) + return false; + + if ( ! (*a == *o) ) + return false; + } + + return true; + } + bool Attributes::Serialize(SerialInfo* info) const { return SerialObj::Serialize(info); diff --git a/src/Attr.h b/src/Attr.h index 73fb101841..26231baeb4 100644 --- a/src/Attr.h +++ b/src/Attr.h @@ -52,6 +52,20 @@ public: void Describe(ODesc* d) const; + bool operator==(const Attr& other) const + { + if ( tag != other.tag ) + return false; + + if ( expr || other.expr ) + // If any has an expression and they aren't the same object, we + // declare them unequal, as we can't really find out if the two + // expressions are equivalent. + return (expr == other.expr); + + return true; + } + protected: void AddTag(ODesc* d) const; @@ -79,6 +93,8 @@ public: bool Serialize(SerialInfo* info) const; static Attributes* Unserialize(UnserialInfo* info); + bool operator==(const Attributes& other) const; + protected: Attributes() { type = 0; attrs = 0; } void CheckAttr(Attr* attr); diff --git a/src/CompHash.cc b/src/CompHash.cc index 2e0870303c..cc4f440e06 100644 --- a/src/CompHash.cc +++ b/src/CompHash.cc @@ -65,11 +65,22 @@ CompositeHash::~CompositeHash() // Computes the piece of the hash for Val*, returning the new kp. char* CompositeHash::SingleValHash(int type_check, char* kp0, - BroType* bt, Val* v) const + BroType* bt, Val* v, bool optional) const { char* kp1 = 0; InternalTypeTag t = bt->InternalType(); + if ( optional ) + { + // Add a marker saying whether the optional field is set. + char* kp = AlignAndPadType(kp0); + *kp = ( v ? 1 : 0); + kp0 = reinterpret_cast(kp+1); + + if ( ! v ) + return kp0; + } + if ( type_check ) { InternalTypeTag vt = v->Type()->InternalType(); @@ -163,12 +174,16 @@ char* CompositeHash::SingleValHash(int type_check, char* kp0, for ( int i = 0; i < num_fields; ++i ) { Val* rv_i = rv->Lookup(i); - if ( ! rv_i ) + + Attributes* a = rt->FieldDecl(i)->attrs; + bool optional = (a && a->FindAttr(ATTR_OPTIONAL)); + + if ( ! (rv_i || optional) ) return 0; if ( ! (kp = SingleValHash(type_check, kp, rt->FieldType(i), - rv_i)) ) + rv_i, optional)) ) return 0; } @@ -248,7 +263,7 @@ HashKey* CompositeHash::ComputeHash(const Val* v, int type_check) const char* kp = k; loop_over_list(*tl, i) { - kp = SingleValHash(type_check, kp, (*tl)[i], (*vl)[i]); + kp = SingleValHash(type_check, kp, (*tl)[i], (*vl)[i], false); if ( ! kp ) return 0; } @@ -315,10 +330,13 @@ HashKey* CompositeHash::ComputeSingletonHash(const Val* v, int type_check) const } int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v, - int type_check, int sz) const + int type_check, int sz, bool optional) const { InternalTypeTag t = bt->InternalType(); + if ( optional ) + sz = SizeAlign(sz, sizeof(char)); + if ( type_check && v ) { InternalTypeTag vt = v->Type()->InternalType(); @@ -369,9 +387,12 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v, for ( int i = 0; i < num_fields; ++i ) { + Attributes* a = rt->FieldDecl(i)->attrs; + bool optional = (a && a->FindAttr(ATTR_OPTIONAL)); + sz = SingleTypeKeySize(rt->FieldType(i), rv ? rv->Lookup(i) : 0, - type_check, sz); + type_check, sz, optional); if ( ! sz ) return 0; } @@ -418,7 +439,7 @@ int CompositeHash::ComputeKeySize(const Val* v, int type_check) const loop_over_list(*tl, i) { sz = SingleTypeKeySize((*tl)[i], v ? v->AsListVal()->Index(i) : 0, - type_check, sz); + type_check, sz, false); if ( ! sz ) return 0; } @@ -495,20 +516,20 @@ ListVal* CompositeHash::RecoverVals(const HashKey* k) const loop_over_list(*tl, i) { Val* v; - kp = RecoverOneVal(k, kp, k_end, (*tl)[i], v); + kp = RecoverOneVal(k, kp, k_end, (*tl)[i], v, false); ASSERT(v); l->Append(v); } if ( kp != k_end ) - internal_error("under-ran key in CompositeHash::DescribeKey"); + internal_error("under-ran key in CompositeHash::DescribeKey %ld", k_end - kp); return l; } const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, const char* const k_end, BroType* t, - Val*& pval) const + Val*& pval, bool optional) const { // k->Size() == 0 for a single empty string. if ( kp0 >= k_end && k->Size() > 0 ) @@ -516,9 +537,20 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, TypeTag tag = t->Tag(); InternalTypeTag it = t->InternalType(); - const char* kp1 = 0; + if ( optional ) + { + const char* kp = AlignType(kp0); + kp0 = kp1 = reinterpret_cast(kp+1); + + if ( ! *kp ) + { + pval = 0; + return kp0; + } + } + switch ( it ) { case TYPE_INTERNAL_INT: { @@ -647,9 +679,13 @@ const char* CompositeHash::RecoverOneVal(const HashKey* k, const char* kp0, for ( i = 0; i < num_fields; ++i ) { Val* v; + + Attributes* a = rt->FieldDecl(i)->attrs; + bool optional = (a && a->FindAttr(ATTR_OPTIONAL)); + kp = RecoverOneVal(k, kp, k_end, - rt->FieldType(i), v); - if ( ! v ) + rt->FieldType(i), v, optional); + if ( ! (v || optional) ) { internal_error("didn't recover expected number of fields from HashKey"); pval = 0; diff --git a/src/CompHash.h b/src/CompHash.h index a0632e1bfe..12ab9f7422 100644 --- a/src/CompHash.h +++ b/src/CompHash.h @@ -30,7 +30,7 @@ protected: // Computes the piece of the hash for Val*, returning the new kp. // Used as a helper for ComputeHash in the non-singleton case. char* SingleValHash(int type_check, char* kp, - BroType* bt, Val* v) const; + BroType* bt, Val* v, bool optional) const; // Recovers just one Val of possibly many; called from RecoverVals. // Upon return, pval will point to the recovered Val of type t. @@ -38,7 +38,7 @@ protected: // upon errors, so there is no return value for invalid input. const char* RecoverOneVal(const HashKey* k, const char* kp, const char* const k_end, - BroType* t, Val*& pval) const; + BroType* t, Val*& pval, bool optional) const; // Rounds the given pointer up to the nearest multiple of the // given size, if not already a multiple. @@ -77,7 +77,7 @@ protected: int ComputeKeySize(const Val* v = 0, int type_check = 1) const; int SingleTypeKeySize(BroType*, const Val*, - int type_check, int sz) const; + int type_check, int sz, bool optional) const; TypeList* type; char* key; // space for composite key diff --git a/src/Expr.cc b/src/Expr.cc index dbfca7c9cb..5788cdeb7b 100644 --- a/src/Expr.cc +++ b/src/Expr.cc @@ -2531,16 +2531,35 @@ bool AssignExpr::TypeCheck() return true; } + if ( op1->Type()->Tag() == TYPE_RECORD && + op2->Type()->Tag() == TYPE_RECORD ) + { + if ( same_type(op1->Type(), op2->Type()) ) + { + RecordType* rt1 = op1->Type()->AsRecordType(); + RecordType* rt2 = op2->Type()->AsRecordType(); + + // Make sure the attributes match as well. + for ( int i = 0; i < rt1->NumFields(); ++i ) + { + const TypeDecl* td1 = rt1->FieldDecl(i); + const TypeDecl* td2 = rt2->FieldDecl(i); + + if ( same_attrs(td1->attrs, td2->attrs) ) + // Everything matches. + return true; + } + } + + // Need to coerce. + op2 = new RecordCoerceExpr(op2, op1->Type()->AsRecordType()); + return true; + } + if ( ! same_type(op1->Type(), op2->Type()) ) { - if ( op1->Type()->Tag() == TYPE_RECORD && - op2->Type()->Tag() == TYPE_RECORD ) - op2 = new RecordCoerceExpr(op2, op1->Type()->AsRecordType()); - else - { - ExprError("type clash in assignment"); - return false; - } + ExprError("type clash in assignment"); + return false; } return true; @@ -5308,21 +5327,39 @@ int check_and_promote_expr(Expr*& e, BroType* t) return 1; } - else if ( ! same_type(t, et) ) + if ( t->Tag() == TYPE_RECORD && et->Tag() == TYPE_RECORD ) { - if ( t->Tag() == TYPE_RECORD && et->Tag() == TYPE_RECORD ) - { - RecordType* t_r = t->AsRecordType(); - RecordType* et_r = et->AsRecordType(); + RecordType* t_r = t->AsRecordType(); + RecordType* et_r = et->AsRecordType(); - if ( record_promotion_compatible(t_r, et_r) ) + if ( same_type(t, et) ) + { + // Make sure the attributes match as well. + for ( int i = 0; i < t_r->NumFields(); ++i ) { - e = new RecordCoerceExpr(e, t_r); - return 1; + const TypeDecl* td1 = t_r->FieldDecl(i); + const TypeDecl* td2 = et_r->FieldDecl(i); + + if ( same_attrs(td1->attrs, td2->attrs) ) + // Everything matches perfectly. + return 1; } } - else if ( t->Tag() == TYPE_TABLE && et->Tag() == TYPE_TABLE && + if ( record_promotion_compatible(t_r, et_r) ) // Note: This is always true currently. + { + e = new RecordCoerceExpr(e, t_r); + return 1; + } + + t->Error("incompatible record types", e); + return 0; + } + + + if ( ! same_type(t, et) ) + { + if ( t->Tag() == TYPE_TABLE && et->Tag() == TYPE_TABLE && et->AsTableType()->IsUnspecifiedTable() ) { e = new TableCoerceExpr(e, t->AsTableType()); diff --git a/src/Type.cc b/src/Type.cc index 55794dfce5..62e0f195ec 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1430,6 +1430,17 @@ int same_type(const BroType* t1, const BroType* t2, int is_init) return 0; } +int same_attrs(const Attributes* a1, const Attributes* a2) + { + if ( ! a1 ) + return (a2 != 0); + + if ( ! a2 ) + return 0; + + return (*a1 == *a2); + } + int record_promotion_compatible(const RecordType* /* super_rec */, const RecordType* /* sub_rec */) { diff --git a/src/Type.h b/src/Type.h index ff4d3df9e6..7e890d9e07 100644 --- a/src/Type.h +++ b/src/Type.h @@ -509,6 +509,9 @@ inline BroType* error_type() { return base_type(TYPE_ERROR); } // test is done in the context of an initialization. extern int same_type(const BroType* t1, const BroType* t2, int is_init=0); +// True if the two attribute lists are equivalent. +extern int same_attrs(const Attributes* a1, const Attributes* a2); + // Returns true if the record sub_rec can be promoted to the record // super_rec. extern int record_promotion_compatible(const RecordType* super_rec, From 0dbbee46ae47b46bb724b151471ca11c09581fd7 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 14:46:28 -0800 Subject: [PATCH 005/150] Teaching bifcl to accept scoped IDs. --- src/builtin-func.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin-func.l b/src/builtin-func.l index ca7923b852..a9459ea4a8 100644 --- a/src/builtin-func.l +++ b/src/builtin-func.l @@ -27,7 +27,7 @@ int check_c_mode(int t) %} WS [ \t]+ -ID [A-Za-z_][A-Za-z_0-9]* +ID [A-Za-z_](([A-Za-z_0-9]|::)*[A-Za-z_0-9])? ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+)) %option nodefault From f43766650f730b9f03bbc800e88066b8197c70a2 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 14:46:49 -0800 Subject: [PATCH 006/150] Fixing hashing records with optional strings. --- src/CompHash.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CompHash.cc b/src/CompHash.cc index cc4f440e06..2f1a41e311 100644 --- a/src/CompHash.cc +++ b/src/CompHash.cc @@ -407,7 +407,7 @@ int CompositeHash::SingleTypeKeySize(BroType* bt, const Val* v, case TYPE_INTERNAL_STRING: if ( ! v ) - return 0; + return optional ? sz : 0; // Factor in length field. sz = SizeAlign(sz, sizeof(int)); From cdb20e61b753d27bbf8be3550488b3854c6e9758 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 14:46:28 -0800 Subject: [PATCH 007/150] Teaching bifcl to accept scoped IDs. --- src/builtin-func.l | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/builtin-func.l b/src/builtin-func.l index ca7923b852..a9459ea4a8 100644 --- a/src/builtin-func.l +++ b/src/builtin-func.l @@ -27,7 +27,7 @@ int check_c_mode(int t) %} WS [ \t]+ -ID [A-Za-z_][A-Za-z_0-9]* +ID [A-Za-z_](([A-Za-z_0-9]|::)*[A-Za-z_0-9])? ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+)) %option nodefault From 95069f0993d06913d855ad8d6bc4765ca892ca57 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 16:04:32 -0800 Subject: [PATCH 008/150] Implementing += operator for record types. This is per #375. Record types can now get additional fields later via '+='. The added fields must however either be &optional or have a &default value. Example: type Foo: record { a: count; b: count &optional; }; redef record Foo += { c: count &default=42; d: count &optional; }; global f: Foo = [$a=21]; print f; Output: [a=21, b=, c=42, d=] --- src/Type.cc | 20 ++++++++++++++++++++ src/Type.h | 4 ++++ src/parse.y | 22 ++++++++++++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/Type.cc b/src/Type.cc index ec7c8e510b..cfb7f86c0b 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -898,6 +898,26 @@ void RecordType::Describe(ODesc* d) const } } +const char* RecordType::AddFields(type_decl_list* others) + { + assert(types); + + loop_over_list(*others, i) + { + TypeDecl* td = (*others)[i]; + + if ( ! td->FindAttr(ATTR_DEFAULT) && ! td->FindAttr(ATTR_OPTIONAL) ) + return "extension field must be &optional or have &default"; + + types->append(td); + } + + delete others; + + num_fields = types->length(); + return 0; + } + void RecordType::DescribeFields(ODesc* d) const { if ( d->IsReadable() ) diff --git a/src/Type.h b/src/Type.h index ff4d3df9e6..23cdd0af25 100644 --- a/src/Type.h +++ b/src/Type.h @@ -409,6 +409,10 @@ public: int NumFields() const { return num_fields; } + // Returns 0 if all is ok, otherwise a pointer to an error message. Takes + // ownership of list. + const char* AddFields(type_decl_list* types); + void Describe(ODesc* d) const; void DescribeFields(ODesc* d) const; diff --git a/src/parse.y b/src/parse.y index 3cf2c07b18..b4d01c624c 100644 --- a/src/parse.y +++ b/src/parse.y @@ -799,8 +799,8 @@ decl: | TOK_REDEF global_id opt_type init_class opt_init opt_attr ';' { add_global($2, $3, $4, $5, $6, VAR_REDEF); } - | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO - '{' enum_id_list opt_comma '}' ';' + | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO + '{' enum_id_list opt_comma '}' ';' { if ( ! $3->Type() ) $3->Error("unknown identifier"); @@ -815,6 +815,24 @@ decl: } } + | TOK_REDEF TOK_RECORD global_id TOK_ADD_TO + '{' type_decl_list '}' ';' + { + if ( ! $3->Type() ) + $3->Error("unknown identifier"); + else + { + RecordType* add_to = $3->Type()->AsRecordType(); + if ( ! add_to ) + $3->Error("not a record type"); + else { + const char* error = add_to->AddFields($6); + if ( error ) + $3->Error(error); + } + } + } + | TOK_TYPE global_id ':' refined_type opt_attr ';' { add_type($2, $4, $5, 0); From 2f30c3d245f75fbe14012e2d3ab480f3556de922 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 16:10:09 -0800 Subject: [PATCH 009/150] Adding some tests for the record-extension feature. These will go somewhere else eventually, just making sure they don't get lost. --- testing/rec.bro | 17 +++++++++++++++++ testing/rec2.bro | 17 +++++++++++++++++ testing/wrong-rec.bro | 13 +++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 testing/rec.bro create mode 100644 testing/rec2.bro create mode 100644 testing/wrong-rec.bro diff --git a/testing/rec.bro b/testing/rec.bro new file mode 100644 index 0000000000..904edd4e8c --- /dev/null +++ b/testing/rec.bro @@ -0,0 +1,17 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count &default=42; + d: count &optional; +}; + +global f: Foo = [$a=21]; + +print f; + diff --git a/testing/rec2.bro b/testing/rec2.bro new file mode 100644 index 0000000000..c8324ae577 --- /dev/null +++ b/testing/rec2.bro @@ -0,0 +1,17 @@ +# @TEST-EXEC: bro %INPUT >output +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count &default=42; + d: string &optional; +}; + +global f: Foo = [$a=21, $d="XXX"]; + +print f; + diff --git a/testing/wrong-rec.bro b/testing/wrong-rec.bro new file mode 100644 index 0000000000..e5f553bf45 --- /dev/null +++ b/testing/wrong-rec.bro @@ -0,0 +1,13 @@ +# @TEST-EXEC-FAIL: bro %INPUT >output 2>&1 +# @TEST-EXEC: btest-diff output + +type Foo: record { + a: count; + b: count &optional; +}; + +redef record Foo += { + c: count; + d: string &optional; +}; + From 3942b253cc474c58ba917814c2109c5190cd7912 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Mon, 7 Feb 2011 21:47:29 -0800 Subject: [PATCH 010/150] Adding a test for SSL-based communciation to the istate testsuite. --- .../istate/base/events-display-ssl/stdout.log | 35 ++++++ testing/istate/base/events-rcv-ssl/conn.log | 2 + testing/istate/base/events-rcv-ssl/http.log | 18 +++ testing/istate/base/events-rcv-ssl/stderr.log | 3 + testing/istate/base/events-rcv-ssl/stdout.log | 0 testing/istate/base/events-send-ssl/conn.log | 3 + testing/istate/base/events-send-ssl/http.log | 18 +++ .../istate/base/events-send-ssl/stderr.log | 0 .../istate/base/events-send-ssl/stdout.log | 0 testing/istate/istate.py | 28 +++++ testing/istate/scripts/bro.pem | 30 +++++ testing/istate/scripts/ca_cert.pem | 18 +++ testing/istate/scripts/events-rcv-ssl.bro | 21 ++++ testing/istate/scripts/events-send-ssl.bro | 26 ++++ testing/istate/tests.py | 114 +++++++++--------- 15 files changed, 260 insertions(+), 56 deletions(-) create mode 100644 testing/istate/base/events-display-ssl/stdout.log create mode 100644 testing/istate/base/events-rcv-ssl/conn.log create mode 100644 testing/istate/base/events-rcv-ssl/http.log create mode 100644 testing/istate/base/events-rcv-ssl/stderr.log create mode 100644 testing/istate/base/events-rcv-ssl/stdout.log create mode 100644 testing/istate/base/events-send-ssl/conn.log create mode 100644 testing/istate/base/events-send-ssl/http.log create mode 100644 testing/istate/base/events-send-ssl/stderr.log create mode 100644 testing/istate/base/events-send-ssl/stdout.log create mode 100644 testing/istate/scripts/bro.pem create mode 100644 testing/istate/scripts/ca_cert.pem create mode 100644 testing/istate/scripts/events-rcv-ssl.bro create mode 100644 testing/istate/scripts/events-send-ssl.bro diff --git a/testing/istate/base/events-display-ssl/stdout.log b/testing/istate/base/events-display-ssl/stdout.log new file mode 100644 index 0000000000..6aae4f8eb5 --- /dev/null +++ b/testing/istate/base/events-display-ssl/stdout.log @@ -0,0 +1,35 @@ +Event [xxxxxxxxxx.xxxxxx] bro_done() +Event [xxxxxxxxxx.xxxxxx] connection_established([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=0, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.182510137557983, service={}, addl="", hot=0, history="Sh"]) +Event [xxxxxxxxxx.xxxxxx] connection_finished([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=5], resp=[size=9417, state=5], start_time=xxxxxxxxxx.xxxxxx, duration=1.73330307006836, service={}, addl="%events-send-1", hot=0, history="ShADdFaf"]) +Event [xxxxxxxxxx.xxxxxx] connection_pending([id=[orig_h=141.42.64.125, orig_p=56729/tcp, resp_h=125.190.109.199, resp_p=12345/tcp], orig=[size=0, state=1], resp=[size=0, state=6], start_time=xxxxxxxxxx.xxxxxx, duration=0.182432889938354, service={}, addl="", hot=0, history="Sr"]) +Event [xxxxxxxxxx.xxxxxx] connection_state_remove([id=[orig_h=141.42.64.125, orig_p=56729/tcp, resp_h=125.190.109.199, resp_p=12345/tcp], orig=[size=0, state=1], resp=[size=0, state=6], start_time=xxxxxxxxxx.xxxxxx, duration=0.182432889938354, service={}, addl="", hot=0, history="Sr"]) +Event [xxxxxxxxxx.xxxxxx] connection_state_remove([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=5], resp=[size=9417, state=5], start_time=xxxxxxxxxx.xxxxxx, duration=1.73330307006836, service={}, addl="%events-send-1", hot=0, history="ShADdFaf"]) +Event [xxxxxxxxxx.xxxxxx] http_begin_entity([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1", hot=0, history="ShAD"]T) +Event [xxxxxxxxxx.xxxxxx] http_begin_entity([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F) +Event [xxxxxxxxxx.xxxxxx] http_content_type([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T"TEXT""PLAIN") +Event [xxxxxxxxxx.xxxxxx] http_content_type([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"TEXT""HTML") +Event [xxxxxxxxxx.xxxxxx] http_end_entity([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T) +Event [xxxxxxxxxx.xxxxxx] http_end_entity([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=9417, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.73563814163208, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F) +Event [xxxxxxxxxx.xxxxxx] http_entity_data([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=5792, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.551820039749146, service={}, addl="%events-send-1", hot=0, history="ShADd"]F4096"^JICIR^J^JICIR
^J

^JICIR (The ICSI Center for Internet Research)^Jis a ^Jnon-profit^Jresearch institute at^JICSI^Jin ^JBerkeley, ^JCalifornia.
^JFor the three years from 1999 to 2001 we were named^JACIRI, the AT&T Center for Internet Research at ICSI, ^Jand were funded by AT&T.
^J^JThe goals of ICIR are to:^J

    ^J
  • Pursue research on the Internet architecture and related networking issues,^J
  • ^JParticipate actively in the research (SIGCOMM and IRTF) and^Jstandards (IETF) communities,^J
  • Bridge the gap between the Internet research community and commercial ^Jinterests by providing a neutral forum where topics of mutual technical ^Jinterest can be addressed.^J
^J

^J^J


^J^J
^J^J^J^J^J^J^J^J^J^J^J
^J^J

^JPeople^J

^J^J^J
^J^J

^JPublications^J

^J^J^J

^JProjects ^J

^J^J^J^J
^J ^J

Research

^J   Transport and Congestion^J
    ^J
  • ^JDCCP^J(Datagram Congestion Control Protocol).^J
  • ^JECN^J(Explicit Congestion Notification).^J
  • ^J^JIntegrated services.^J
  • ^JRED ^Jqueue management, and^JRED-PD.^J
  • ^JHighSpeed TCP.^J
  • ^J^JTCP Implementation.^J
  • ^JReordering-Robust TCP ^J(RR-TCP).^J
  • TCP^JSACK ^J(Selective Acknowledgment).^J
  • ^JTFRC ^J(TCP-Friendly Rate Control).^J
^J^J   Traffic and Topology^J
    ^J
  • ^JIDMaps ^J(Internet Distance Mapping).^J
  • The ^JInternet Traffic Archive.^J
  • ^JMINC^J(Multicast-based Inference of Network-internal Characteristics).^J
  • ^JNIMI^J(N") +Event [xxxxxxxxxx.xxxxxx] http_entity_data([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=9417, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.73563814163208, service={}, addl="%events-send-1", hot=0, history="ShADd"]F938"ational Internet Measurement Infrastructure).^J
^J^J

^J^JCollaborators^J

^J^J^J^J
^J
^J^J
^J

Information for visitors and local users.

^J
^JLast modified: June 2004. Copyright notice.^J^JOlder versions of this web page, in its ACIRI incarnation..^J
^JFor more information about this server, mail www@aciri.org. ^J
^JTo report unusual activity by any of our hosts, mail abuse@aciri.org.^J^J") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T"ACCEPT""*/*") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T"CONNECTION""Keep-Alive") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T"HOST""www.icir.org") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T"USER-AGENT""Wget/1.10") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"ACCEPT-RANGES""bytes") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"CONNECTION""Keep-Alive") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"CONTENT-LENGTH""9130") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"CONTENT-TYPE""text/html") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"DATE""Fri, 07 Oct 2005 23:23:55 GMT") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"ETAG"""2c96c-23aa-4346a0e5"") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"KEEP-ALIVE""timeout=15, max=100") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"LAST-MODIFIED""Fri, 07 Oct 2005 16:23:01 GMT") +Event [xxxxxxxxxx.xxxxxx] http_header([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F"SERVER""Apache/1.3.33 (Unix)") +Event [xxxxxxxxxx.xxxxxx] http_message_done([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShAD"]T[start=xxxxxxxxxx.xxxxxx, interrupted=F, finish_msg="message ends normally", body_length=0, content_gap_length=0, header_length=86]) +Event [xxxxxxxxxx.xxxxxx] http_message_done([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=9417, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.73563814163208, service={}, addl="%events-send-1 %events-rcv-1", hot=0, history="ShADd"]F[start=xxxxxxxxxx.xxxxxx, interrupted=F, finish_msg="message ends normally", body_length=9130, content_gap_length=0, header_length=265]) +Event [xxxxxxxxxx.xxxxxx] http_reply([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=1448, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.367331027984619, service={}, addl="%events-send-1", hot=0, history="ShADd"]"1.1"200"OK") +Event [xxxxxxxxxx.xxxxxx] http_request([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="", hot=0, history="ShAD"]"GET""/""/""1.0") +Event [xxxxxxxxxx.xxxxxx] net_done(xxxxxxxxxx.xxxxxx) +Event [xxxxxxxxxx.xxxxxx] new_connection([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=0, state=1], resp=[size=0, state=0], start_time=xxxxxxxxxx.xxxxxx, duration=0.0, service={}, addl="cc=1", hot=0, history=""]) +Event [xxxxxxxxxx.xxxxxx] protocol_confirmation([id=[orig_h=141.42.64.125, orig_p=56730/tcp, resp_h=125.190.109.199, resp_p=80/tcp], orig=[size=98, state=4], resp=[size=0, state=4], start_time=xxxxxxxxxx.xxxxxx, duration=0.183290958404541, service={}, addl="", hot=0, history="ShAD"]165) diff --git a/testing/istate/base/events-rcv-ssl/conn.log b/testing/istate/base/events-rcv-ssl/conn.log new file mode 100644 index 0000000000..b38c0a2e70 --- /dev/null +++ b/testing/istate/base/events-rcv-ssl/conn.log @@ -0,0 +1,2 @@ +xxxxxxxxxx.xxxxxx 0.182433 141.42.64.125 125.190.109.199 other 56729 12345 tcp ? ? REJ X +xxxxxxxxxx.xxxxxx 1.733303 141.42.64.125 125.190.109.199 http 56730 80 tcp 98 9417 SF X %events-send-1 diff --git a/testing/istate/base/events-rcv-ssl/http.log b/testing/istate/base/events-rcv-ssl/http.log new file mode 100644 index 0000000000..db049772d8 --- /dev/null +++ b/testing/istate/base/events-rcv-ssl/http.log @@ -0,0 +1,18 @@ +xxxxxxxxxx.xxxxxx %events-rcv-1 start 141.42.64.125:56730 > 125.190.109.199:80 +xxxxxxxxxx.xxxxxx %events-rcv-1 > USER-AGENT: Wget/1.10 +xxxxxxxxxx.xxxxxx %events-rcv-1 > ACCEPT: */* +xxxxxxxxxx.xxxxxx %events-rcv-1 > HOST: www.icir.org +xxxxxxxxxx.xxxxxx %events-rcv-1 > CONNECTION: Keep-Alive +xxxxxxxxxx.xxxxxx %events-rcv-1 < DATE: Fri, 07 Oct 2005 23:23:55 GMT +xxxxxxxxxx.xxxxxx %events-rcv-1 < SERVER: Apache/1.3.33 (Unix) +xxxxxxxxxx.xxxxxx %events-rcv-1 < LAST-MODIFIED: Fri, 07 Oct 2005 16:23:01 GMT +xxxxxxxxxx.xxxxxx %events-rcv-1 < ETAG: "2c96c-23aa-4346a0e5" +xxxxxxxxxx.xxxxxx %events-rcv-1 < ACCEPT-RANGES: bytes +xxxxxxxxxx.xxxxxx %events-rcv-1 < CONTENT-LENGTH: 9130 +xxxxxxxxxx.xxxxxx %events-rcv-1 < KEEP-ALIVE: timeout=15, max=100 +xxxxxxxxxx.xxxxxx %events-rcv-1 < CONNECTION: Keep-Alive +xxxxxxxxxx.xxxxxx %events-rcv-1 < CONTENT-TYPE: text/html +xxxxxxxxxx.xxxxxx %events-rcv-1 <= 4096 bytes: "^J^J

^JPublications^J

^J