#include "Data.h" #include "broker/data.bif.h" #include #include using namespace std; OpaqueType* bro_broker::opaque_of_data_type; OpaqueType* bro_broker::opaque_of_set_iterator; OpaqueType* bro_broker::opaque_of_table_iterator; OpaqueType* bro_broker::opaque_of_vector_iterator; OpaqueType* bro_broker::opaque_of_record_iterator; static broker::port::protocol to_broker_port_proto(TransportProto tp) { switch ( tp ) { case TRANSPORT_TCP: return broker::port::protocol::tcp; case TRANSPORT_UDP: return broker::port::protocol::udp; case TRANSPORT_ICMP: return broker::port::protocol::icmp; case TRANSPORT_UNKNOWN: default: return broker::port::protocol::unknown; } } TransportProto bro_broker::to_bro_port_proto(broker::port::protocol tp) { switch ( tp ) { case broker::port::protocol::tcp: return TRANSPORT_TCP; case broker::port::protocol::udp: return TRANSPORT_UDP; case broker::port::protocol::icmp: return TRANSPORT_ICMP; case broker::port::protocol::unknown: default: return TRANSPORT_UNKNOWN; } } struct val_converter { using result_type = Val*; BroType* type; bool require_log_attr; result_type operator()(bool a) { if ( type->Tag() == TYPE_BOOL ) return new Val(a, TYPE_BOOL); return nullptr; } result_type operator()(uint64_t a) { if ( type->Tag() == TYPE_COUNT ) return new Val(a, TYPE_COUNT); if ( type->Tag() == TYPE_COUNTER ) return new Val(a, TYPE_COUNTER); return nullptr; } result_type operator()(int64_t a) { if ( type->Tag() == TYPE_INT ) return new Val(a, TYPE_INT); return nullptr; } result_type operator()(double a) { if ( type->Tag() == TYPE_DOUBLE ) return new Val(a, TYPE_DOUBLE); return nullptr; } result_type operator()(std::string& a) { switch ( type->Tag() ) { case TYPE_STRING: return new StringVal(a.size(), a.data()); case TYPE_FILE: { auto file = BroFile::GetFile(a.data()); if ( file ) { Ref(file); return new Val(file); } return nullptr; } case TYPE_FUNC: { auto id = lookup_ID(a.data(), GLOBAL_MODULE_NAME); auto rval = id ? id->ID_Val() : nullptr; Unref(id); if ( rval && rval->Type()->Tag() == TYPE_FUNC ) return rval; return nullptr; } default: return nullptr; } } result_type operator()(broker::address& a) { if ( type->Tag() == TYPE_ADDR ) { auto bits = reinterpret_cast(&a.bytes()); return new AddrVal(IPAddr(*bits)); } return nullptr; } result_type operator()(broker::subnet& a) { if ( type->Tag() == TYPE_SUBNET ) { auto bits = reinterpret_cast(&a.network().bytes()); return new SubNetVal(IPPrefix(IPAddr(*bits), a.length())); } return nullptr; } result_type operator()(broker::port& a) { if ( type->Tag() == TYPE_PORT ) return new PortVal(a.number(), bro_broker::to_bro_port_proto(a.type())); return nullptr; } result_type operator()(broker::time_point& a) { if ( type->Tag() == TYPE_TIME ) return new Val(a.value, TYPE_TIME); return nullptr; } result_type operator()(broker::time_duration& a) { if ( type->Tag() == TYPE_INTERVAL ) return new Val(a.value, TYPE_INTERVAL); return nullptr; } result_type operator()(broker::enum_value& a) { if ( type->Tag() == TYPE_ENUM ) { auto etype = type->AsEnumType(); auto i = etype->Lookup(GLOBAL_MODULE_NAME, a.name.data()); if ( i == -1 ) return nullptr; return new EnumVal(i, etype); } return nullptr; } result_type operator()(broker::set& a) { if ( ! type->IsSet() ) return nullptr; auto tt = type->AsTableType(); auto rval = new TableVal(tt); for ( auto& item : a ) { broker::vector composite_key; auto indices = broker::get(item); if ( ! indices ) { composite_key.emplace_back(move(item)); indices = &composite_key; } auto expected_index_types = tt->Indices()->Types(); if ( static_cast(expected_index_types->length()) != indices->size() ) { Unref(rval); return nullptr; } auto list_val = new ListVal(TYPE_ANY); for ( auto i = 0u; i < indices->size(); ++i ) { auto index_val = bro_broker::data_to_val(move((*indices)[i]), (*expected_index_types)[i]); if ( ! index_val ) { Unref(rval); Unref(list_val); return nullptr; } list_val->Append(index_val); } rval->Assign(list_val, nullptr); Unref(list_val); } return rval; } result_type operator()(broker::table& a) { if ( ! type->IsTable() ) return nullptr; auto tt = type->AsTableType(); auto rval = new TableVal(tt); for ( auto& item : a ) { broker::vector composite_key; auto indices = broker::get(item.first); if ( ! indices ) { composite_key.emplace_back(move(item.first)); indices = &composite_key; } auto expected_index_types = tt->Indices()->Types(); if ( static_cast(expected_index_types->length()) != indices->size() ) { Unref(rval); return nullptr; } auto list_val = new ListVal(TYPE_ANY); for ( auto i = 0u; i < indices->size(); ++i ) { auto index_val = bro_broker::data_to_val(move((*indices)[i]), (*expected_index_types)[i]); if ( ! index_val ) { Unref(rval); Unref(list_val); return nullptr; } list_val->Append(index_val); } auto value_val = bro_broker::data_to_val(move(item.second), tt->YieldType()); if ( ! value_val ) { Unref(rval); Unref(list_val); return nullptr; } rval->Assign(list_val, value_val); Unref(list_val); } return rval; } result_type operator()(broker::vector& a) { if ( type->Tag() != TYPE_VECTOR ) return nullptr; auto vt = type->AsVectorType(); auto rval = new VectorVal(vt); for ( auto& item : a ) { auto item_val = bro_broker::data_to_val(move(item), vt->YieldType()); if ( ! item_val ) { Unref(rval); return nullptr; } rval->Assign(rval->Size(), item_val); } return rval; } result_type operator()(broker::record& a) { if ( type->Tag() != TYPE_RECORD ) return nullptr; auto rt = type->AsRecordType(); auto rval = new RecordVal(rt); for ( auto i = 0u; i < static_cast(rt->NumFields()); ++i ) { if ( require_log_attr && ! rt->FieldDecl(i)->FindAttr(ATTR_LOG) ) continue; if ( i >= a.fields.size() ) { Unref(rval); return nullptr; } if ( ! a.fields[i] ) { rval->Assign(i, nullptr); continue; } auto item_val = bro_broker::data_to_val(move(*a.fields[i]), rt->FieldType(i)); if ( ! item_val ) { Unref(rval); return nullptr; } rval->Assign(i, item_val); } return rval; } }; Val* bro_broker::data_to_val(broker::data d, BroType* type, bool require_log_attr) { return broker::visit(val_converter{type, require_log_attr}, d); } broker::util::optional bro_broker::val_to_data(Val* v) { switch ( v->Type()->Tag() ) { case TYPE_BOOL: return {v->AsBool()}; case TYPE_INT: return {v->AsInt()}; case TYPE_COUNT: return {v->AsCount()}; case TYPE_COUNTER: return {v->AsCounter()}; case TYPE_PORT: { auto p = v->AsPortVal(); return {broker::port(p->Port(), to_broker_port_proto(p->PortType()))}; } case TYPE_ADDR: { auto a = v->AsAddr(); in6_addr tmp; a.CopyIPv6(&tmp); return {broker::address(reinterpret_cast(&tmp), broker::address::family::ipv6, broker::address::byte_order::network)}; } break; case TYPE_SUBNET: { auto s = v->AsSubNet(); in6_addr tmp; s.Prefix().CopyIPv6(&tmp); auto a = broker::address(reinterpret_cast(&tmp), broker::address::family::ipv6, broker::address::byte_order::network); return {broker::subnet(a, s.Length())}; } break; case TYPE_DOUBLE: return {v->AsDouble()}; case TYPE_TIME: return {broker::time_point(v->AsTime())}; case TYPE_INTERVAL: return {broker::time_duration(v->AsInterval())}; case TYPE_ENUM: { auto enum_type = v->Type()->AsEnumType(); auto enum_name = enum_type->Lookup(v->AsEnum()); return {broker::enum_value(enum_name ? enum_name : "")}; } case TYPE_STRING: { auto s = v->AsString(); return {string(reinterpret_cast(s->Bytes()), s->Len())}; } case TYPE_FILE: return {string(v->AsFile()->Name())}; case TYPE_FUNC: return {string(v->AsFunc()->Name())}; case TYPE_TABLE: { auto is_set = v->Type()->IsSet(); auto table = v->AsTable(); auto table_val = v->AsTableVal(); broker::data rval; if ( is_set ) rval = broker::set(); else rval = broker::table(); struct iter_guard { iter_guard(HashKey* arg_k, ListVal* arg_lv) : k(arg_k), lv(arg_lv) {} ~iter_guard() { delete k; Unref(lv); } HashKey* k; ListVal* lv; }; HashKey* k; TableEntryVal* entry; auto c = table->InitForIteration(); while ( (entry = table->NextEntry(k, c)) ) { auto vl = table_val->RecoverIndex(k); iter_guard ig(k, vl); broker::vector composite_key; composite_key.reserve(vl->Length()); for ( auto k = 0; k < vl->Length(); ++k ) { auto key_part = val_to_data((*vl->Vals())[k]); if ( ! key_part ) return {}; composite_key.emplace_back(move(*key_part)); } broker::data key; if ( composite_key.size() == 1 ) key = move(composite_key[0]); else key = move(composite_key); if ( is_set ) broker::get(rval)->emplace(move(key)); else { auto val = val_to_data(entry->Value()); if ( ! val ) return {}; broker::get(rval)->emplace(move(key), move(*val)); } } return {rval}; } case TYPE_VECTOR: { auto vec = v->AsVectorVal(); broker::vector rval; rval.reserve(vec->Size()); for ( auto i = 0u; i < vec->Size(); ++i ) { auto item_val = vec->Lookup(i); if ( ! item_val ) continue; auto item = val_to_data(item_val); if ( ! item ) return {}; rval.emplace_back(move(*item)); } return {rval}; } case TYPE_RECORD: { auto rec = v->AsRecordVal(); broker::record rval; size_t num_fields = v->Type()->AsRecordType()->NumFields(); rval.fields.reserve(num_fields); for ( auto i = 0u; i < num_fields; ++i ) { auto item_val = rec->LookupWithDefault(i); if ( ! item_val ) { rval.fields.emplace_back(broker::record::field{}); continue; } auto item = val_to_data(item_val); Unref(item_val); if ( ! item ) return {}; rval.fields.emplace_back(broker::record::field{move(*item)}); } return {rval}; } default: reporter->Error("unsupported Broker::Data type: %s", type_name(v->Type()->Tag())); break; } return {}; } RecordVal* bro_broker::make_data_val(Val* v) { auto rval = new RecordVal(BifType::Record::Broker::Data); auto data = val_to_data(v); if ( data ) rval->Assign(0, new DataVal(move(*data))); return rval; } RecordVal* bro_broker::make_data_val(broker::data d) { auto rval = new RecordVal(BifType::Record::Broker::Data); rval->Assign(0, new DataVal(move(d))); return rval; } struct data_type_getter { using result_type = EnumVal*; result_type operator()(bool a) { return new EnumVal(BifEnum::Broker::BOOL, BifType::Enum::Broker::DataType); } result_type operator()(uint64_t a) { return new EnumVal(BifEnum::Broker::COUNT, BifType::Enum::Broker::DataType); } result_type operator()(int64_t a) { return new EnumVal(BifEnum::Broker::INT, BifType::Enum::Broker::DataType); } result_type operator()(double a) { return new EnumVal(BifEnum::Broker::DOUBLE, BifType::Enum::Broker::DataType); } result_type operator()(const std::string& a) { return new EnumVal(BifEnum::Broker::STRING, BifType::Enum::Broker::DataType); } result_type operator()(const broker::address& a) { return new EnumVal(BifEnum::Broker::ADDR, BifType::Enum::Broker::DataType); } result_type operator()(const broker::subnet& a) { return new EnumVal(BifEnum::Broker::SUBNET, BifType::Enum::Broker::DataType); } result_type operator()(const broker::port& a) { return new EnumVal(BifEnum::Broker::PORT, BifType::Enum::Broker::DataType); } result_type operator()(const broker::time_point& a) { return new EnumVal(BifEnum::Broker::TIME, BifType::Enum::Broker::DataType); } result_type operator()(const broker::time_duration& a) { return new EnumVal(BifEnum::Broker::INTERVAL, BifType::Enum::Broker::DataType); } result_type operator()(const broker::enum_value& a) { return new EnumVal(BifEnum::Broker::ENUM, BifType::Enum::Broker::DataType); } result_type operator()(const broker::set& a) { return new EnumVal(BifEnum::Broker::SET, BifType::Enum::Broker::DataType); } result_type operator()(const broker::table& a) { return new EnumVal(BifEnum::Broker::TABLE, BifType::Enum::Broker::DataType); } result_type operator()(const broker::vector& a) { return new EnumVal(BifEnum::Broker::VECTOR, BifType::Enum::Broker::DataType); } result_type operator()(const broker::record& a) { return new EnumVal(BifEnum::Broker::RECORD, BifType::Enum::Broker::DataType); } }; EnumVal* bro_broker::get_data_type(RecordVal* v, Frame* frame) { return broker::visit(data_type_getter{}, opaque_field_to_data(v, frame)); } broker::data& bro_broker::opaque_field_to_data(RecordVal* v, Frame* f) { Val* d = v->Lookup(0); if ( ! d ) reporter->RuntimeError(f->GetCall()->GetLocationInfo(), "Broker::Data's opaque field is not set"); return static_cast(d)->data; } IMPLEMENT_SERIAL(bro_broker::DataVal, SER_COMM_DATA_VAL); bool bro_broker::DataVal::DoSerialize(SerialInfo* info) const { DO_SERIALIZE(SER_COMM_DATA_VAL, OpaqueVal); std::string serial; caf::binary_serializer bs(std::back_inserter(serial)); bs << data; if ( ! SERIALIZE_STR(serial.data(), serial.size()) ) return false; return true; } bool bro_broker::DataVal::DoUnserialize(UnserialInfo* info) { DO_UNSERIALIZE(OpaqueVal); const char* serial; int len; if ( ! UNSERIALIZE_STR(&serial, &len) ) return false; caf::binary_deserializer bd(serial, len); caf::uniform_typeid()->deserialize(&data, &bd); delete [] serial; return true; }