GH-998: Fix Reporter::conn_weird() to handle expired connections

This introduces a new sampling state-map for expired connections to fix
segfaults that previously occured when passing in a `connection` record
to `Reporter::conn_weird()` for which the internal `Connection` object
had already been expired and deleted.  This also introduces a new event
called `expired_conn_weird`, which is similar to `conn_weird`, except
the full `connection` record is no longer available, just the `conn_id`
and UID string.
This commit is contained in:
Jon Siwek 2020-06-15 12:53:46 -07:00
parent 8d9e85b842
commit 51e738a1c0
9 changed files with 163 additions and 5 deletions

View file

@ -273,6 +273,21 @@ public:
IPPair endpoints;
};
class ConnTupleWeirdTimer final : public Timer {
public:
using ConnTuple = Reporter::ConnTuple;
ConnTupleWeirdTimer(double t, ConnTuple id, double timeout)
: Timer(t + timeout, TIMER_CONN_TUPLE_WEIRD_EXPIRE),
conn_id(std::move(id))
{}
void Dispatch(double t, bool is_expire) override
{ reporter->ResetExpiredConnWeird(conn_id); }
ConnTuple conn_id;
};
void Reporter::ResetNetWeird(const std::string& name)
{
net_weird_state.erase(name);
@ -283,6 +298,11 @@ void Reporter::ResetFlowWeird(const IPAddr& orig, const IPAddr& resp)
flow_weird_state.erase(std::make_pair(orig, resp));
}
void Reporter::ResetExpiredConnWeird(const ConnTuple& id)
{
expired_conn_weird_state.erase(id);
}
bool Reporter::PermitNetWeird(const char* name)
{
auto& count = net_weird_state[name];
@ -325,6 +345,35 @@ bool Reporter::PermitFlowWeird(const char* name,
return false;
}
bool Reporter::PermitExpiredConnWeird(const char* name, const RecordVal& conn_id)
{
auto conn_tuple = std::make_tuple(conn_id.GetField("orig_h")->AsAddr(),
conn_id.GetField("resp_h")->AsAddr(),
conn_id.GetField("orig_p")->AsPortVal()->Port(),
conn_id.GetField("resp_p")->AsPortVal()->Port(),
conn_id.GetField("resp_p")->AsPortVal()->PortType());
auto& map = expired_conn_weird_state[conn_tuple];
if ( map.empty() )
timer_mgr->Add(new ConnTupleWeirdTimer(network_time,
std::move(conn_tuple),
weird_sampling_duration));
auto& count = map[name];
++count;
if ( count <= weird_sampling_threshold )
return true;
auto num_above_threshold = count - weird_sampling_threshold;
if ( weird_sampling_rate )
return num_above_threshold % weird_sampling_rate == 0;
else
return false;
}
void Reporter::Weird(const char* name, const char* addl)
{
UpdateWeirdStats(name);
@ -368,6 +417,22 @@ void Reporter::Weird(Connection* conn, const char* name, const char* addl)
"%s", name);
}
void Reporter::Weird(IntrusivePtr<RecordVal> conn_id, IntrusivePtr<StringVal> uid,
const char* name, const char* addl)
{
UpdateWeirdStats(name);
if ( ! WeirdOnSamplingWhiteList(name) )
{
if ( ! PermitExpiredConnWeird(name, *conn_id) )
return;
}
WeirdHelper(expired_conn_weird,
{conn_id.release(), uid.release(), new StringVal(addl)},
"%s", name);
}
void Reporter::Weird(const IPAddr& orig, const IPAddr& resp, const char* name, const char* addl)
{
UpdateWeirdStats(name);