// See the file "COPYING" in the main distribution directory for copyright. #include "zeek-config.h" #include #include "Net.h" #include "NetVar.h" #include "Conn.h" #include "Event.h" #include "Sessions.h" #include "Reporter.h" #include "Timer.h" #include "analyzer/protocol/pia/PIA.h" #include "binpac.h" #include "TunnelEncapsulation.h" #include "analyzer/Analyzer.h" #include "analyzer/Manager.h" void ConnectionTimer::Init(Connection* arg_conn, timer_func arg_timer, int arg_do_expire) { conn = arg_conn; timer = arg_timer; do_expire = arg_do_expire; Ref(conn); } ConnectionTimer::~ConnectionTimer() { if ( conn->RefCnt() < 1 ) reporter->InternalError("reference count inconsistency in ~ConnectionTimer"); conn->RemoveTimer(this); Unref(conn); } void ConnectionTimer::Dispatch(double t, int is_expire) { if ( is_expire && ! do_expire ) return; // Remove ourselves from the connection's set of timers so // it doesn't try to cancel us. conn->RemoveTimer(this); (conn->*timer)(t); if ( conn->RefCnt() < 1 ) reporter->InternalError("reference count inconsistency in ConnectionTimer::Dispatch"); } IMPLEMENT_SERIAL(ConnectionTimer, SER_CONNECTION_TIMER); bool ConnectionTimer::DoSerialize(SerialInfo* info) const { DO_SERIALIZE(SER_CONNECTION_TIMER, Timer); // We enumerate all the possible timer functions here ... This // has to match the list is DoUnserialize()! char type = 0; if ( timer == timer_func(&Connection::DeleteTimer) ) type = 1; else if ( timer == timer_func(&Connection::InactivityTimer) ) type = 2; else if ( timer == timer_func(&Connection::StatusUpdateTimer) ) type = 3; else if ( timer == timer_func(&Connection::RemoveConnectionTimer) ) type = 4; else reporter->InternalError("unknown function in ConnectionTimer::DoSerialize()"); return conn->Serialize(info) && SERIALIZE(type) && SERIALIZE(do_expire); } bool ConnectionTimer::DoUnserialize(UnserialInfo* info) { DO_UNSERIALIZE(Timer); conn = Connection::Unserialize(info); if ( ! conn ) return false; char type; if ( ! UNSERIALIZE(&type) || ! UNSERIALIZE(&do_expire) ) return false; switch ( type ) { case 1: timer = timer_func(&Connection::DeleteTimer); break; case 2: timer = timer_func(&Connection::InactivityTimer); break; case 3: timer = timer_func(&Connection::StatusUpdateTimer); break; case 4: timer = timer_func(&Connection::RemoveConnectionTimer); break; default: info->s->Error("unknown connection timer function"); return false; } return true; } uint64 Connection::total_connections = 0; uint64 Connection::current_connections = 0; uint64 Connection::external_connections = 0; IMPLEMENT_SERIAL(Connection, SER_CONNECTION); Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id, uint32 flow, const Packet* pkt, const EncapsulationStack* arg_encap) { sessions = s; key = k; start_time = last_time = t; orig_addr = id->src_addr; resp_addr = id->dst_addr; orig_port = id->src_port; resp_port = id->dst_port; proto = TRANSPORT_UNKNOWN; orig_flow_label = flow; resp_flow_label = 0; saw_first_orig_packet = 1; saw_first_resp_packet = 0; if ( pkt->l2_src ) memcpy(orig_l2_addr, pkt->l2_src, sizeof(orig_l2_addr)); else bzero(orig_l2_addr, sizeof(orig_l2_addr)); if ( pkt->l2_dst ) memcpy(resp_l2_addr, pkt->l2_dst, sizeof(resp_l2_addr)); else bzero(resp_l2_addr, sizeof(resp_l2_addr)); vlan = pkt->vlan; inner_vlan = pkt->inner_vlan; conn_val = 0; login_conn = 0; is_active = 1; skip = 0; weird = 0; persistent = 0; suppress_event = 0; record_contents = record_packets = 1; record_current_packet = record_current_content = 0; timers_canceled = 0; inactivity_timeout = 0; installed_status_timer = 0; finished = 0; hist_seen = 0; history = ""; root_analyzer = 0; primary_PIA = 0; ++current_connections; ++total_connections; TimerMgr::Tag* tag = current_iosrc->GetCurrentTag(); conn_timer_mgr = tag ? new TimerMgr::Tag(*tag) : 0; if ( arg_encap ) encapsulation = new EncapsulationStack(*arg_encap); else encapsulation = 0; if ( conn_timer_mgr ) { ++external_connections; // We schedule a timer which removes this connection from memory // indefinitively into the future. Ii will expire when the timer // mgr is drained but not before. ADD_TIMER(&Connection::RemoveConnectionTimer, 1e20, 1, TIMER_REMOVE_CONNECTION); } } Connection::~Connection() { if ( ! finished ) reporter->InternalError("Done() not called before destruction of Connection"); CancelTimers(); if ( conn_val ) { conn_val->SetOrigin(0); Unref(conn_val); } delete key; delete root_analyzer; delete conn_timer_mgr; delete encapsulation; --current_connections; if ( conn_timer_mgr ) --external_connections; } void Connection::CheckEncapsulation(const EncapsulationStack* arg_encap) { if ( encapsulation && arg_encap ) { if ( *encapsulation != *arg_encap ) { Event(tunnel_changed, 0, arg_encap->GetVectorVal()); delete encapsulation; encapsulation = new EncapsulationStack(*arg_encap); } } else if ( encapsulation ) { EncapsulationStack empty; Event(tunnel_changed, 0, empty.GetVectorVal()); delete encapsulation; encapsulation = 0; } else if ( arg_encap ) { Event(tunnel_changed, 0, arg_encap->GetVectorVal()); encapsulation = new EncapsulationStack(*arg_encap); } } void Connection::Done() { finished = 1; if ( root_analyzer && ! root_analyzer->IsFinished() ) root_analyzer->Done(); } void Connection::NextPacket(double t, int is_orig, const IP_Hdr* ip, int len, int caplen, const u_char*& data, int& record_packet, int& record_content, // arguments for reproducing packets const Packet *pkt) { current_timestamp = t; current_pkt = pkt; if ( Skipping() ) return; if ( root_analyzer ) { record_current_packet = record_packet; record_current_content = record_content; root_analyzer->NextPacket(len, data, is_orig, -1, ip, caplen); record_packet = record_current_packet; record_content = record_current_content; } else last_time = t; current_timestamp = 0; current_pkt = 0; } void Connection::SetLifetime(double lifetime) { ADD_TIMER(&Connection::DeleteTimer, network_time + lifetime, 0, TIMER_CONN_DELETE); } bool Connection::IsReuse(double t, const u_char* pkt) { return root_analyzer && root_analyzer->IsReuse(t, pkt); } bool Connection::ScaledHistoryEntry(char code, uint32& counter, uint32& scaling_threshold, uint32 scaling_base) { if ( ++counter == scaling_threshold ) { AddHistory(code); auto new_threshold = scaling_threshold * scaling_base; if ( new_threshold <= scaling_threshold ) // This can happen due to wrap-around. In that // case, reset the counter but leave the threshold // unchanged. counter = 0; else scaling_threshold = new_threshold; return true; } return false; } void Connection::HistoryThresholdEvent(EventHandlerPtr e, bool is_orig, uint32 threshold) { if ( ! e ) return; if ( threshold == 1 ) // This will be far and away the most common case, // and at this stage it's not a *multiple* instance. return; ConnectionEventFast(e, 0, { BuildConnVal(), val_mgr->GetBool(is_orig), val_mgr->GetCount(threshold) }); } void Connection::DeleteTimer(double /* t */) { if ( is_active ) Event(connection_timeout, 0); sessions->Remove(this); } void Connection::InactivityTimer(double t) { // If the inactivity_timeout is zero, there has been an active // timeout once, but it's disabled now. We do nothing then. if ( inactivity_timeout ) { if ( last_time + inactivity_timeout <= t ) { Event(connection_timeout, 0); sessions->Remove(this); ++killed_by_inactivity; } else ADD_TIMER(&Connection::InactivityTimer, last_time + inactivity_timeout, 0, TIMER_CONN_INACTIVITY); } } void Connection::RemoveConnectionTimer(double t) { Event(connection_state_remove, 0); sessions->Remove(this); } void Connection::SetInactivityTimeout(double timeout) { // We add a new inactivity timer even if there already is one. When // it fires, we always use the current value to check for inactivity. if ( timeout ) ADD_TIMER(&Connection::InactivityTimer, last_time + timeout, 0, TIMER_CONN_INACTIVITY); inactivity_timeout = timeout; } void Connection::EnableStatusUpdateTimer() { if ( connection_status_update && connection_status_update_interval ) { ADD_TIMER(&Connection::StatusUpdateTimer, network_time + connection_status_update_interval, 0, TIMER_CONN_STATUS_UPDATE); installed_status_timer = 1; } } void Connection::StatusUpdateTimer(double t) { ConnectionEventFast(connection_status_update, 0, { BuildConnVal() }); ADD_TIMER(&Connection::StatusUpdateTimer, network_time + connection_status_update_interval, 0, TIMER_CONN_STATUS_UPDATE); } RecordVal* Connection::BuildConnVal() { if ( ! conn_val ) { conn_val = new RecordVal(connection_type); TransportProto prot_type = ConnTransport(); RecordVal* id_val = new RecordVal(conn_id); id_val->Assign(0, new AddrVal(orig_addr)); id_val->Assign(1, val_mgr->GetPort(ntohs(orig_port), prot_type)); id_val->Assign(2, new AddrVal(resp_addr)); id_val->Assign(3, val_mgr->GetPort(ntohs(resp_port), prot_type)); RecordVal* orig_endp = new RecordVal(endpoint); orig_endp->Assign(0, val_mgr->GetCount(0)); orig_endp->Assign(1, val_mgr->GetCount(0)); orig_endp->Assign(4, val_mgr->GetCount(orig_flow_label)); const int l2_len = sizeof(orig_l2_addr); char null[l2_len]{}; if ( memcmp(&orig_l2_addr, &null, l2_len) != 0 ) orig_endp->Assign(5, new StringVal(fmt_mac(orig_l2_addr, l2_len))); RecordVal* resp_endp = new RecordVal(endpoint); resp_endp->Assign(0, val_mgr->GetCount(0)); resp_endp->Assign(1, val_mgr->GetCount(0)); resp_endp->Assign(4, val_mgr->GetCount(resp_flow_label)); if ( memcmp(&resp_l2_addr, &null, l2_len) != 0 ) resp_endp->Assign(5, new StringVal(fmt_mac(resp_l2_addr, l2_len))); conn_val->Assign(0, id_val); conn_val->Assign(1, orig_endp); conn_val->Assign(2, resp_endp); // 3 and 4 are set below. conn_val->Assign(5, new TableVal(string_set)); // service conn_val->Assign(6, val_mgr->GetEmptyString()); // history if ( ! uid ) uid.Set(bits_per_uid); conn_val->Assign(7, new StringVal(uid.Base62("C").c_str())); if ( encapsulation && encapsulation->Depth() > 0 ) conn_val->Assign(8, encapsulation->GetVectorVal()); if ( vlan != 0 ) conn_val->Assign(9, val_mgr->GetInt(vlan)); if ( inner_vlan != 0 ) conn_val->Assign(10, val_mgr->GetInt(inner_vlan)); } if ( root_analyzer ) root_analyzer->UpdateConnVal(conn_val); conn_val->Assign(3, new Val(start_time, TYPE_TIME)); // ### conn_val->Assign(4, new Val(last_time - start_time, TYPE_INTERVAL)); conn_val->Assign(6, new StringVal(history.c_str())); conn_val->SetOrigin(this); Ref(conn_val); return conn_val; } analyzer::Analyzer* Connection::FindAnalyzer(analyzer::ID id) { return root_analyzer ? root_analyzer->FindChild(id) : 0; } analyzer::Analyzer* Connection::FindAnalyzer(analyzer::Tag tag) { return root_analyzer ? root_analyzer->FindChild(tag) : 0; } analyzer::Analyzer* Connection::FindAnalyzer(const char* name) { return root_analyzer->FindChild(name); } void Connection::AppendAddl(const char* str) { Unref(BuildConnVal()); const char* old = conn_val->Lookup(6)->AsString()->CheckString(); const char* format = *old ? "%s %s" : "%s%s"; conn_val->Assign(6, new StringVal(fmt(format, old, str))); } // Returns true if the character at s separates a version number. static inline bool is_version_sep(const char* s, const char* end) { return // foo-1.2.3 (s < end - 1 && ispunct(s[0]) && isdigit(s[1])) || // foo-v1.2.3 (s < end - 2 && ispunct(s[0]) && tolower(s[1]) == 'v' && isdigit(s[2])) || // foo 1.2.3 isspace(s[0]); } void Connection::Match(Rule::PatternType type, const u_char* data, int len, bool is_orig, bool bol, bool eol, bool clear_state) { if ( primary_PIA ) primary_PIA->Match(type, data, len, is_orig, bol, eol, clear_state); } Val* Connection::BuildVersionVal(const char* s, int len) { Val* name = 0; Val* major = 0; Val* minor = 0; Val* minor2 = 0; Val* addl = 0; const char* last = s + len; const char* e = s; // This is all just a guess... // Eat non-alpha-numerical chars. for ( ; s < last && ! isalnum(*s); ++s ) ; // Leading characters are the program name. // (first character must not be a digit) if ( isalpha(*s) ) { for ( e = s; e < last && ! is_version_sep(e, last); ++e ) ; if ( s != e ) name = new StringVal(e - s, s); } // Find first number - that's the major version. for ( s = e; s < last && ! isdigit(*s); ++s ) ; for ( e = s; e < last && isdigit(*e); ++e ) ; if ( s != e ) major = val_mgr->GetInt(atoi(s)); // Find second number seperated only by punctuation chars - // that's the minor version. for ( s = e; s < last && ispunct(*s); ++s ) ; for ( e = s; e < last && isdigit(*e); ++e ) ; if ( s != e ) minor = val_mgr->GetInt(atoi(s)); // Find second number seperated only by punctuation chars; - // that's the minor version. for ( s = e; s < last && ispunct(*s); ++s ) ; for ( e = s; e < last && isdigit(*e); ++e ) ; if ( s != e ) minor2 = val_mgr->GetInt(atoi(s)); // Anything after following punctuation and until next white space is // an additional version string. for ( s = e; s < last && ispunct(*s); ++s ) ; for ( e = s; e < last && ! isspace(*e); ++e ) ; if ( s != e ) addl = new StringVal(e - s, s); // If we do not have a name yet, the next alphanumerical string is it. if ( ! name ) { // eat non-alpha-numerical characters for ( s = e; s < last && ! isalpha(*s); ++s ) ; // Get name. for ( e = s; e < last && (isalnum(*e) || *e == '_'); ++e ) ; if ( s != e ) name = new StringVal(e - s, s); } // We need at least a name. if ( ! name ) { Unref(major); Unref(minor); Unref(minor2); Unref(addl); return 0; } RecordVal* version = new RecordVal(software_version); version->Assign(0, major ? major : val_mgr->GetInt(-1)); version->Assign(1, minor ? minor : val_mgr->GetInt(-1)); version->Assign(2, minor2 ? minor2 : val_mgr->GetInt(-1)); version->Assign(3, addl ? addl : val_mgr->GetEmptyString()); RecordVal* sw = new RecordVal(software); sw->Assign(0, name); sw->Assign(1, version); return sw; } int Connection::VersionFoundEvent(const IPAddr& addr, const char* s, int len, analyzer::Analyzer* analyzer) { if ( ! software_version_found && ! software_parse_error ) return 1; if ( ! is_printable(s, len) ) return 0; Val* val = BuildVersionVal(s, len); if ( ! val ) { if ( software_parse_error ) { ConnectionEventFast(software_parse_error, analyzer, { BuildConnVal(), new AddrVal(addr), new StringVal(len, s), }); } return 0; } if ( software_version_found ) { ConnectionEventFast(software_version_found, 0, { BuildConnVal(), new AddrVal(addr), val, new StringVal(len, s), }); } else Unref(val); return 1; } int Connection::UnparsedVersionFoundEvent(const IPAddr& addr, const char* full, int len, analyzer::Analyzer* analyzer) { // Skip leading white space. while ( len && isspace(*full) ) { --len; ++full; } if ( ! is_printable(full, len) ) return 0; if ( software_unparsed_version_found ) { ConnectionEventFast(software_unparsed_version_found, analyzer, { BuildConnVal(), new AddrVal(addr), new StringVal(len, full), }); } return 1; } void Connection::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, const char* name) { if ( ! f ) return; if ( name ) ConnectionEventFast(f, analyzer, {new StringVal(name), BuildConnVal()}); else ConnectionEventFast(f, analyzer, {BuildConnVal()}); } void Connection::Event(EventHandlerPtr f, analyzer::Analyzer* analyzer, Val* v1, Val* v2) { if ( ! f ) { Unref(v1); Unref(v2); return; } if ( v2 ) ConnectionEventFast(f, analyzer, {BuildConnVal(), v1, v2}); else ConnectionEventFast(f, analyzer, {BuildConnVal(), v1}); } void Connection::ConnectionEvent(EventHandlerPtr f, analyzer::Analyzer* a, val_list vl) { if ( ! f ) { // This may actually happen if there is no local handler // and a previously existing remote handler went away. loop_over_list(vl, i) Unref(vl[i]); return; } // "this" is passed as a cookie for the event mgr.QueueEvent(f, std::move(vl), SOURCE_LOCAL, a ? a->GetID() : 0, GetTimerMgr(), this); } void Connection::ConnectionEventFast(EventHandlerPtr f, analyzer::Analyzer* a, val_list vl) { // "this" is passed as a cookie for the event mgr.QueueEventFast(f, std::move(vl), SOURCE_LOCAL, a ? a->GetID() : 0, GetTimerMgr(), this); } void Connection::ConnectionEvent(EventHandlerPtr f, analyzer::Analyzer* a, val_list* vl) { ConnectionEvent(f, a, std::move(*vl)); delete vl; } void Connection::Weird(const char* name, const char* addl) { weird = 1; reporter->Weird(this, name, addl ? addl : ""); } void Connection::AddTimer(timer_func timer, double t, int do_expire, TimerType type) { if ( timers_canceled ) return; // If the key is cleared, the connection isn't stored in the connection // table anymore and will soon be deleted. We're not installing new // timers anymore then. if ( ! key ) return; Timer* conn_timer = new ConnectionTimer(this, timer, t, do_expire, type); GetTimerMgr()->Add(conn_timer); timers.append(conn_timer); } void Connection::RemoveTimer(Timer* t) { timers.remove(t); } void Connection::CancelTimers() { // We are going to cancel our timers which, in turn, may cause them to // call RemoveTimer(), which would then modify the list we're just // traversing. Thus, we first make a copy of the list which we then // iterate through. timer_list tmp(timers.length()); loop_over_list(timers, j) tmp.append(timers[j]); loop_over_list(tmp, i) GetTimerMgr()->Cancel(tmp[i]); timers_canceled = 1; timers.clear(); } TimerMgr* Connection::GetTimerMgr() const { if ( ! conn_timer_mgr ) // Global manager. return timer_mgr; // We need to check whether the local timer manager still exists; // it may have already been timed out, in which case we fall back // to the global manager (though this should be rare). TimerMgr* local_mgr = sessions->LookupTimerMgr(conn_timer_mgr, false); return local_mgr ? local_mgr : timer_mgr; } void Connection::FlipRoles() { IPAddr tmp_addr = resp_addr; resp_addr = orig_addr; orig_addr = tmp_addr; uint32 tmp_port = resp_port; resp_port = orig_port; orig_port = tmp_port; const int l2_len = sizeof(orig_l2_addr); u_char tmp_l2_addr[l2_len]; memcpy(tmp_l2_addr, resp_l2_addr, l2_len); memcpy(resp_l2_addr, orig_l2_addr, l2_len); memcpy(orig_l2_addr, tmp_l2_addr, l2_len); bool tmp_bool = saw_first_resp_packet; saw_first_resp_packet = saw_first_orig_packet; saw_first_orig_packet = tmp_bool; uint32 tmp_flow = resp_flow_label; resp_flow_label = orig_flow_label; orig_flow_label = tmp_flow; Unref(conn_val); conn_val = 0; if ( root_analyzer ) root_analyzer->FlipRoles(); analyzer_mgr->ApplyScheduledAnalyzers(this); AddHistory('^'); } unsigned int Connection::MemoryAllocation() const { return padded_sizeof(*this) + (key ? key->MemoryAllocation() : 0) + (timers.MemoryAllocation() - padded_sizeof(timers)) + (conn_val ? conn_val->MemoryAllocation() : 0) + (root_analyzer ? root_analyzer->MemoryAllocation(): 0) // login_conn is just a casted 'this'. // primary_PIA is already contained in the analyzer tree. ; } unsigned int Connection::MemoryAllocationConnVal() const { return conn_val ? conn_val->MemoryAllocation() : 0; } void Connection::Describe(ODesc* d) const { d->Add(start_time); d->Add("("); d->Add(last_time); d->AddSP(")"); switch ( proto ) { case TRANSPORT_TCP: d->Add("TCP"); break; case TRANSPORT_UDP: d->Add("UDP"); break; case TRANSPORT_ICMP: d->Add("ICMP"); break; case TRANSPORT_UNKNOWN: d->Add("unknown"); reporter->InternalWarning( "unknown transport in Connction::Describe()"); break; default: reporter->InternalError( "unhandled transport type in Connection::Describe"); } d->SP(); d->Add(orig_addr); d->Add(":"); d->Add(ntohs(orig_port)); d->SP(); d->AddSP("->"); d->Add(resp_addr); d->Add(":"); d->Add(ntohs(resp_port)); d->NL(); } void Connection::IDString(ODesc* d) const { d->Add(orig_addr); d->AddRaw(":", 1); d->Add(ntohs(orig_port)); d->AddRaw(" > ", 3); d->Add(resp_addr); d->AddRaw(":", 1); d->Add(ntohs(resp_port)); } bool Connection::Serialize(SerialInfo* info) const { return SerialObj::Serialize(info); } Connection* Connection::Unserialize(UnserialInfo* info) { return (Connection*) SerialObj::Unserialize(info, SER_CONNECTION); } bool Connection::DoSerialize(SerialInfo* info) const { DO_SERIALIZE(SER_CONNECTION, BroObj); // First we write the members which are needed to // create the HashKey. if ( ! SERIALIZE(orig_addr) || ! SERIALIZE(resp_addr) ) return false; if ( ! SERIALIZE(orig_port) || ! SERIALIZE(resp_port) ) return false; if ( ! SERIALIZE(timers.length()) ) return false; loop_over_list(timers, i) if ( ! timers[i]->Serialize(info) ) return false; SERIALIZE_OPTIONAL(conn_val); // FIXME: RuleEndpointState not yet serializable. // FIXME: Analyzers not yet serializable. return SERIALIZE(int(proto)) && SERIALIZE(history) && SERIALIZE(hist_seen) && SERIALIZE(start_time) && SERIALIZE(last_time) && SERIALIZE(inactivity_timeout) && SERIALIZE(suppress_event) && SERIALIZE(login_conn != 0) && SERIALIZE_BIT(installed_status_timer) && SERIALIZE_BIT(timers_canceled) && SERIALIZE_BIT(is_active) && SERIALIZE_BIT(skip) && SERIALIZE_BIT(weird) && SERIALIZE_BIT(finished) && SERIALIZE_BIT(record_packets) && SERIALIZE_BIT(record_contents) && SERIALIZE_BIT(persistent); } bool Connection::DoUnserialize(UnserialInfo* info) { // Make sure this is initialized for the condition in Unserialize(). persistent = 0; DO_UNSERIALIZE(BroObj); // Build the hash key first. Some of the recursive *::Unserialize() // functions may need it. ConnID id; if ( ! UNSERIALIZE(&orig_addr) || ! UNSERIALIZE(&resp_addr) ) goto error; if ( ! UNSERIALIZE(&orig_port) || ! UNSERIALIZE(&resp_port) ) goto error; id.src_addr = orig_addr; id.dst_addr = resp_addr; // This doesn't work for ICMP. But I guess this is not really important. id.src_port = orig_port; id.dst_port = resp_port; id.is_one_way = 0; // ### incorrect for ICMP key = BuildConnIDHashKey(id); int len; if ( ! UNSERIALIZE(&len) ) goto error; while ( len-- ) { Timer* t = Timer::Unserialize(info); if ( ! t ) goto error; timers.append(t); } UNSERIALIZE_OPTIONAL(conn_val, (RecordVal*) Val::Unserialize(info, connection_type)); int iproto; if ( ! (UNSERIALIZE(&iproto) && UNSERIALIZE(&history) && UNSERIALIZE(&hist_seen) && UNSERIALIZE(&start_time) && UNSERIALIZE(&last_time) && UNSERIALIZE(&inactivity_timeout) && UNSERIALIZE(&suppress_event)) ) goto error; proto = static_cast(iproto); bool has_login_conn; if ( ! UNSERIALIZE(&has_login_conn) ) goto error; login_conn = has_login_conn ? (LoginConn*) this : 0; UNSERIALIZE_BIT(installed_status_timer); UNSERIALIZE_BIT(timers_canceled); UNSERIALIZE_BIT(is_active); UNSERIALIZE_BIT(skip); UNSERIALIZE_BIT(weird); UNSERIALIZE_BIT(finished); UNSERIALIZE_BIT(record_packets); UNSERIALIZE_BIT(record_contents); UNSERIALIZE_BIT(persistent); // Hmm... Why does each connection store a sessions ptr? sessions = ::sessions; root_analyzer = 0; primary_PIA = 0; conn_timer_mgr = 0; return true; error: abort(); CancelTimers(); return false; } void Connection::SetRootAnalyzer(analyzer::TransportLayerAnalyzer* analyzer, analyzer::pia::PIA* pia) { root_analyzer = analyzer; primary_PIA = pia; } void Connection::CheckFlowLabel(bool is_orig, uint32 flow_label) { uint32& my_flow_label = is_orig ? orig_flow_label : resp_flow_label; if ( my_flow_label != flow_label ) { if ( conn_val ) { RecordVal *endp = conn_val->Lookup(is_orig ? 1 : 2)->AsRecordVal(); endp->Assign(4, val_mgr->GetCount(flow_label)); } if ( connection_flow_label_changed && (is_orig ? saw_first_orig_packet : saw_first_resp_packet) ) { ConnectionEventFast(connection_flow_label_changed, 0, { BuildConnVal(), val_mgr->GetBool(is_orig), val_mgr->GetCount(my_flow_label), val_mgr->GetCount(flow_label), }); } my_flow_label = flow_label; } if ( is_orig ) saw_first_orig_packet = 1; else saw_first_resp_packet = 1; } bool Connection::PermitWeird(const char* name, uint64 threshold, uint64 rate, double duration) { return ::PermitWeird(weird_state, name, threshold, rate, duration); }