mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
More fixes
This commit is contained in:
parent
70070c43af
commit
d6e6fda327
18 changed files with 222 additions and 177 deletions
|
@ -29,7 +29,8 @@ uint64_t Connection::total_connections = 0;
|
||||||
uint64_t Connection::current_connections = 0;
|
uint64_t Connection::current_connections = 0;
|
||||||
|
|
||||||
Connection::Connection(IPBasedConnKeyPtr k, zeek::ConnTuple& ct, double t, uint32_t flow, const Packet* pkt)
|
Connection::Connection(IPBasedConnKeyPtr k, zeek::ConnTuple& ct, double t, uint32_t flow, const Packet* pkt)
|
||||||
: Session(t, connection_timeout, connection_status_update, detail::connection_status_update_interval), key(k) {
|
: Session(t, connection_timeout, connection_status_update, detail::connection_status_update_interval),
|
||||||
|
key(std::move(k)) {
|
||||||
orig_addr = ct.src_addr;
|
orig_addr = ct.src_addr;
|
||||||
resp_addr = ct.dst_addr;
|
resp_addr = ct.dst_addr;
|
||||||
orig_port = ct.src_port;
|
orig_port = ct.src_port;
|
||||||
|
|
|
@ -54,7 +54,7 @@ enum ConnEventToFlag {
|
||||||
};
|
};
|
||||||
|
|
||||||
class IPBasedConnKey;
|
class IPBasedConnKey;
|
||||||
using IPBasedConnKeyPtr = zeek::IntrusivePtr<IPBasedConnKey>;
|
using IPBasedConnKeyPtr = std::unique_ptr<IPBasedConnKey>;
|
||||||
|
|
||||||
static inline int addr_port_canon_lt(const IPAddr& addr1, uint32_t p1, const IPAddr& addr2, uint32_t p2) {
|
static inline int addr_port_canon_lt(const IPAddr& addr1, uint32_t p1, const IPAddr& addr2, uint32_t p2) {
|
||||||
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
|
return addr1 < addr2 || (addr1 == addr2 && p1 < p2);
|
||||||
|
@ -64,7 +64,6 @@ static inline int addr_port_canon_lt(const IPAddr& addr1, uint32_t p1, const IPA
|
||||||
class Connection final : public session::Session {
|
class Connection final : public session::Session {
|
||||||
public:
|
public:
|
||||||
Connection(zeek::IPBasedConnKeyPtr k, zeek::ConnTuple& ct, double t, uint32_t flow, const Packet* pkt);
|
Connection(zeek::IPBasedConnKeyPtr k, zeek::ConnTuple& ct, double t, uint32_t flow, const Packet* pkt);
|
||||||
// Connection(const detail::ConnKey& k, double t, const ConnTuple* id, uint32_t flow, const Packet* pkt);
|
|
||||||
~Connection() override;
|
~Connection() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -814,9 +814,9 @@ TEST_SUITE("Analyzer management") {
|
||||||
|
|
||||||
zeek::Packet p;
|
zeek::Packet p;
|
||||||
zeek::ConnTuple ct;
|
zeek::ConnTuple ct;
|
||||||
zeek::IPBasedConnKeyPtr kp = zeek::make_intrusive<zeek::IPConnKey>();
|
zeek::IPBasedConnKeyPtr kp = std::make_unique<zeek::IPConnKey>();
|
||||||
// auto conn = std::make_unique<zeek::Connection>(zeek::detail::OLD_ConnKey(t), 0, &t, 0, &p);
|
// auto conn = std::make_unique<zeek::Connection>(zeek::detail::OLD_ConnKey(t), 0, &t, 0, &p);
|
||||||
auto conn = std::make_unique<zeek::Connection>(kp, ct, 0, 0, &p);
|
auto conn = std::make_unique<zeek::Connection>(std::move(kp), ct, 0, 0, &p);
|
||||||
auto* tcp = new zeek::packet_analysis::TCP::TCPSessionAdapter(conn.get());
|
auto* tcp = new zeek::packet_analysis::TCP::TCPSessionAdapter(conn.get());
|
||||||
conn->SetSessionAdapter(tcp, nullptr);
|
conn->SetSessionAdapter(tcp, nullptr);
|
||||||
|
|
||||||
|
@ -848,8 +848,8 @@ TEST_SUITE("Analyzer management") {
|
||||||
|
|
||||||
zeek::Packet p;
|
zeek::Packet p;
|
||||||
zeek::ConnTuple ct;
|
zeek::ConnTuple ct;
|
||||||
zeek::IPBasedConnKeyPtr kp = zeek::make_intrusive<zeek::IPConnKey>();
|
zeek::IPBasedConnKeyPtr kp = std::make_unique<zeek::IPConnKey>();
|
||||||
auto conn = std::make_unique<zeek::Connection>(kp, ct, 0, 0, &p);
|
auto conn = std::make_unique<zeek::Connection>(std::move(kp), ct, 0, 0, &p);
|
||||||
|
|
||||||
auto ssh = zeek::analyzer_mgr->InstantiateAnalyzer("SSH", conn.get());
|
auto ssh = zeek::analyzer_mgr->InstantiateAnalyzer("SSH", conn.get());
|
||||||
REQUIRE(ssh);
|
REQUIRE(ssh);
|
||||||
|
|
|
@ -329,8 +329,8 @@ private:
|
||||||
TEST_CASE("line forward testing") {
|
TEST_CASE("line forward testing") {
|
||||||
zeek::Packet p;
|
zeek::Packet p;
|
||||||
zeek::ConnTuple ct;
|
zeek::ConnTuple ct;
|
||||||
zeek::IPBasedConnKeyPtr kp = zeek::make_intrusive<zeek::IPConnKey>();
|
zeek::IPBasedConnKeyPtr kp = std::make_unique<zeek::IPConnKey>();
|
||||||
auto conn = std::make_unique<zeek::Connection>(kp, ct, 0, 0, &p);
|
auto conn = std::make_unique<zeek::Connection>(std::move(kp), ct, 0, 0, &p);
|
||||||
auto smtp_analyzer =
|
auto smtp_analyzer =
|
||||||
std::unique_ptr<zeek::analyzer::Analyzer>(zeek::analyzer_mgr->InstantiateAnalyzer("SMTP", conn.get()));
|
std::unique_ptr<zeek::analyzer::Analyzer>(zeek::analyzer_mgr->InstantiateAnalyzer("SMTP", conn.get()));
|
||||||
auto mail = std::make_unique<Test_MIME_Message>(smtp_analyzer.get());
|
auto mail = std::make_unique<Test_MIME_Message>(smtp_analyzer.get());
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "zeek/conntuple/Builder.h"
|
#include "zeek/conntuple/Builder.h"
|
||||||
|
|
||||||
|
#include "zeek/Val.h"
|
||||||
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
||||||
|
|
||||||
namespace zeek::conntuple {
|
namespace zeek::conntuple {
|
||||||
|
@ -9,6 +10,81 @@ namespace zeek::conntuple {
|
||||||
Builder::Builder() {}
|
Builder::Builder() {}
|
||||||
Builder::~Builder() {}
|
Builder::~Builder() {}
|
||||||
|
|
||||||
zeek::ConnKeyPtr Builder::NewConnKey() { return zeek::make_intrusive<zeek::IPConnKey>(); }
|
bool fill_from_val(const IPBasedConnKey* ck, const zeek::ValPtr& v) {
|
||||||
|
auto& t = ck->RawTuple();
|
||||||
|
|
||||||
|
const auto& vt = v->GetType();
|
||||||
|
if ( ! IsRecord(vt->Tag()) ) {
|
||||||
|
t.transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
||||||
|
assert(ck->Error().has_value());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordType* vr = vt->AsRecordType();
|
||||||
|
auto vl = v->As<RecordVal*>();
|
||||||
|
|
||||||
|
int orig_h, orig_p; // indices into record's value list
|
||||||
|
int resp_h, resp_p;
|
||||||
|
int proto;
|
||||||
|
|
||||||
|
if ( vr == id::conn_id ) {
|
||||||
|
orig_h = 0;
|
||||||
|
orig_p = 1;
|
||||||
|
resp_h = 2;
|
||||||
|
resp_p = 3;
|
||||||
|
proto = 4;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// While it's not a conn_id, it may have equivalent fields.
|
||||||
|
orig_h = vr->FieldOffset("orig_h");
|
||||||
|
resp_h = vr->FieldOffset("resp_h");
|
||||||
|
orig_p = vr->FieldOffset("orig_p");
|
||||||
|
resp_p = vr->FieldOffset("resp_p");
|
||||||
|
proto = vr->FieldOffset("proto");
|
||||||
|
|
||||||
|
if ( orig_h < 0 || resp_h < 0 || orig_p < 0 || resp_p < 0 || proto < 0 ) {
|
||||||
|
t.transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
||||||
|
assert(ck->Error().has_value());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO we ought to check that the fields have the right
|
||||||
|
// types, too.
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! vl->HasField(orig_h) || ! vl->HasField(resp_h) || ! vl->HasField(orig_p) || ! vl->HasField(resp_p) ) {
|
||||||
|
t.transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
||||||
|
assert(ck->Error().has_value());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IPAddr& orig_addr = vl->GetFieldAs<AddrVal>(orig_h);
|
||||||
|
const IPAddr& resp_addr = vl->GetFieldAs<AddrVal>(resp_h);
|
||||||
|
|
||||||
|
const auto& orig_portv = vl->GetFieldAs<PortVal>(orig_p);
|
||||||
|
const auto& resp_portv = vl->GetFieldAs<PortVal>(resp_p);
|
||||||
|
|
||||||
|
const auto& protov = vl->GetField<CountVal>(proto);
|
||||||
|
|
||||||
|
auto ct = ConnTuple{orig_addr, resp_addr, ntohs(orig_portv->Port()), ntohs(resp_portv->Port()),
|
||||||
|
static_cast<uint16_t>(protov->AsCount())};
|
||||||
|
|
||||||
|
detail::init_raw_tuple(t, ct);
|
||||||
|
assert(! ck->Error().has_value());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
zeek::ConnKeyPtr Builder::NewConnKey() { return std::make_unique<zeek::IPConnKey>(); }
|
||||||
|
|
||||||
|
// Creating a ConnKey instance from a ValPtr, assuming conn_id.
|
||||||
|
zeek::ConnKeyPtr Builder::FromVal(const zeek::ValPtr& v) {
|
||||||
|
auto ck = NewConnKey();
|
||||||
|
auto* k = static_cast<zeek::IPBasedConnKey*>(ck.get());
|
||||||
|
if ( ! fill_from_val(k, v) ) {
|
||||||
|
assert(ck->Error().has_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
return ck;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace zeek::conntuple
|
} // namespace zeek::conntuple
|
||||||
|
|
|
@ -14,12 +14,19 @@ namespace conntuple {
|
||||||
class Builder;
|
class Builder;
|
||||||
using BuilderPtr = std::unique_ptr<Builder>;
|
using BuilderPtr = std::unique_ptr<Builder>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fill an IPBasedConnKey from a Zeek script value.
|
||||||
|
*/
|
||||||
|
bool fill_from_val(const IPBasedConnKey* k, const zeek::ValPtr& v);
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
public:
|
public:
|
||||||
Builder();
|
Builder();
|
||||||
virtual ~Builder();
|
virtual ~Builder();
|
||||||
|
|
||||||
|
// TODO: Should these better be abstract?
|
||||||
virtual zeek::ConnKeyPtr NewConnKey();
|
virtual zeek::ConnKeyPtr NewConnKey();
|
||||||
|
virtual zeek::ConnKeyPtr FromVal(const zeek::ValPtr& v);
|
||||||
|
|
||||||
static zeek::conntuple::BuilderPtr Instantiate() { return std::make_unique<Builder>(); }
|
static zeek::conntuple::BuilderPtr Instantiate() { return std::make_unique<Builder>(); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
#include "zeek/conntuple/vlan/Builder.h"
|
#include "zeek/conntuple/vlan/Builder.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "zeek/ID.h"
|
#include "zeek/ID.h"
|
||||||
|
#include "zeek/conntuple/Builder.h"
|
||||||
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
||||||
#include "zeek/session/Session.h"
|
#include "zeek/session/Session.h"
|
||||||
|
|
||||||
|
@ -20,18 +23,11 @@ public:
|
||||||
key.inner_vlan = pkt.inner_vlan;
|
key.inner_vlan = pkt.inner_vlan;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FromConnIdVal(const zeek::RecordValPtr& rv) override {
|
|
||||||
if ( ! zeek::IPBasedConnKey::FromConnIdVal(rv) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// TODO: Also load vlan and inner_vlan from the record!
|
|
||||||
}
|
|
||||||
|
|
||||||
zeek::Span<const std::byte> Key() const override {
|
zeek::Span<const std::byte> Key() const override {
|
||||||
return {reinterpret_cast<const std::byte*>(&key), reinterpret_cast<const std::byte*>(&key) + sizeof(key)};
|
return {reinterpret_cast<const std::byte*>(&key), reinterpret_cast<const std::byte*>(&key) + sizeof(key)};
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::RawConnTuple& RawTuple() override { return key.tuple; }
|
detail::RawConnTuple& RawTuple() const override { return key.tuple; }
|
||||||
|
|
||||||
virtual void FillConnIdVal(RecordValPtr& conn_id) override {
|
virtual void FillConnIdVal(RecordValPtr& conn_id) override {
|
||||||
if ( conn_id->NumFields() <= 5 )
|
if ( conn_id->NumFields() <= 5 )
|
||||||
|
@ -47,14 +43,41 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class Builder;
|
||||||
|
|
||||||
// Key bytes.
|
// Key bytes.
|
||||||
struct {
|
struct {
|
||||||
struct detail::RawConnTuple tuple;
|
// mutable for non-const RawTuple() return value.
|
||||||
|
mutable struct detail::RawConnTuple tuple;
|
||||||
// Add 802.1Q vlan tags to connection tuples. The tag representation here is as
|
// Add 802.1Q vlan tags to connection tuples. The tag representation here is as
|
||||||
// in the Packet class, since that's where we learn the tag values from.
|
// in the Packet class, since that's where we learn the tag values from.
|
||||||
uint32_t vlan;
|
uint32_t vlan;
|
||||||
uint32_t inner_vlan;
|
uint32_t inner_vlan;
|
||||||
} key;
|
} __attribute__((packed, aligned)) key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
zeek::ConnKeyPtr Builder::NewConnKey() { return std::make_unique<IPVlanConnKey>(); }
|
||||||
|
|
||||||
|
zeek::ConnKeyPtr Builder::FromVal(const zeek::ValPtr& v) {
|
||||||
|
auto ck = NewConnKey();
|
||||||
|
auto* k = static_cast<IPVlanConnKey*>(ck.get());
|
||||||
|
if ( ! zeek::conntuple::fill_from_val(k, v) ) {
|
||||||
|
assert(ck->Error().has_value());
|
||||||
|
return ck;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rt = v->GetType()->AsRecordType();
|
||||||
|
auto vl = v->As<RecordVal*>();
|
||||||
|
|
||||||
|
// XXX: Use static field offsets
|
||||||
|
if ( rt->GetFieldType(5)->Tag() == TYPE_INT && vl->HasField(5) )
|
||||||
|
k->key.vlan = vl->GetFieldAs<zeek::IntVal>(5);
|
||||||
|
|
||||||
|
if ( rt->GetFieldType(6)->Tag() == TYPE_INT && vl->HasField(6) )
|
||||||
|
k->key.inner_vlan = vl->GetFieldAs<zeek::IntVal>(6);
|
||||||
|
|
||||||
|
|
||||||
|
return ck;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace zeek::plugin::Zeek_Conntuple_VLAN
|
} // namespace zeek::plugin::Zeek_Conntuple_VLAN
|
||||||
|
|
|
@ -8,6 +8,7 @@ namespace zeek::plugin::Zeek_Conntuple_VLAN {
|
||||||
class Builder : public conntuple::Builder {
|
class Builder : public conntuple::Builder {
|
||||||
public:
|
public:
|
||||||
virtual zeek::ConnKeyPtr NewConnKey() override;
|
virtual zeek::ConnKeyPtr NewConnKey() override;
|
||||||
|
virtual zeek::ConnKeyPtr FromVal(const zeek::ValPtr& v) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace zeek::plugin::Zeek_Conntuple_VLAN
|
} // namespace zeek::plugin::Zeek_Conntuple_VLAN
|
||||||
|
|
|
@ -22,12 +22,12 @@ bool GTPv1_Analyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
const auto& key = conn->Key();
|
const auto& key = conn->Key();
|
||||||
auto sk = key.SessionKey();
|
auto sk = key.SessionKey();
|
||||||
|
|
||||||
|
|
||||||
auto cm_it = conn_map.find(sk);
|
auto cm_it = conn_map.find(sk);
|
||||||
if ( cm_it == conn_map.end() ) {
|
if ( cm_it == conn_map.end() ) {
|
||||||
sk.CopyData();
|
sk.CopyData(); // Copy key data to store in map.
|
||||||
ConnMap::value_type p{std::move(sk), std::make_unique<binpac::GTPv1::GTPv1_Conn>(this)};
|
auto [it, inserted] = conn_map.emplace(std::move(sk), std::make_unique<binpac::GTPv1::GTPv1_Conn>(this));
|
||||||
// cm_it = conn_map.insert(cm_it, std::move(p));
|
assert(inserted);
|
||||||
|
cm_it = it;
|
||||||
|
|
||||||
// Let script land know about the state we created, so it will
|
// Let script land know about the state we created, so it will
|
||||||
// register a conn removal hook for cleanup.
|
// register a conn removal hook for cleanup.
|
||||||
|
|
|
@ -13,8 +13,8 @@ function remove_gtpv1_connection%(cid: conn_id%) : bool
|
||||||
zeek::packet_analysis::AnalyzerPtr gtpv1 = zeek::packet_mgr->GetAnalyzer("GTPv1");
|
zeek::packet_analysis::AnalyzerPtr gtpv1 = zeek::packet_mgr->GetAnalyzer("GTPv1");
|
||||||
if ( gtpv1 )
|
if ( gtpv1 )
|
||||||
{
|
{
|
||||||
auto ck = zeek::conntuple_mgr->GetBuilder().NewConnKey();
|
// XXX: Should be IP specific builder!
|
||||||
// ck->LoadConnIdVal(v);
|
auto ck = zeek::conntuple_mgr->GetBuilder().FromVal({zeek::NewRef{}, cid});
|
||||||
auto sk = ck->SessionKey();
|
auto sk = ck->SessionKey();
|
||||||
static_cast<zeek::packet_analysis::gtpv1::GTPv1_Analyzer*>(gtpv1.get())->RemoveConnection(sk);
|
static_cast<zeek::packet_analysis::gtpv1::GTPv1_Analyzer*>(gtpv1.get())->RemoveConnection(sk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
#include "zeek/packet_analysis/protocol/ip/IPBasedAnalyzer.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "zeek/Conn.h"
|
#include "zeek/Conn.h"
|
||||||
#include "zeek/RunState.h"
|
#include "zeek/RunState.h"
|
||||||
#include "zeek/Val.h"
|
#include "zeek/Val.h"
|
||||||
|
@ -14,65 +16,6 @@
|
||||||
using namespace zeek;
|
using namespace zeek;
|
||||||
using namespace zeek::packet_analysis::IP;
|
using namespace zeek::packet_analysis::IP;
|
||||||
|
|
||||||
// Populate a ConnKey from a conn_id record instance.
|
|
||||||
bool IPBasedConnKey::FromConnIdVal(const zeek::RecordValPtr& rv) {
|
|
||||||
auto& t = RawTuple();
|
|
||||||
const auto& vt = rv->GetType();
|
|
||||||
if ( ! IsRecord(vt->Tag()) ) {
|
|
||||||
t.transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordType* vr = vt->AsRecordType();
|
|
||||||
auto vl = rv->As<RecordVal*>();
|
|
||||||
|
|
||||||
int orig_h, orig_p; // indices into record's value list
|
|
||||||
int resp_h, resp_p;
|
|
||||||
int proto;
|
|
||||||
|
|
||||||
if ( vr == id::conn_id ) {
|
|
||||||
orig_h = 0;
|
|
||||||
orig_p = 1;
|
|
||||||
resp_h = 2;
|
|
||||||
resp_p = 3;
|
|
||||||
proto = 4;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// While it's not a conn_id, it may have equivalent fields.
|
|
||||||
orig_h = vr->FieldOffset("orig_h");
|
|
||||||
resp_h = vr->FieldOffset("resp_h");
|
|
||||||
orig_p = vr->FieldOffset("orig_p");
|
|
||||||
resp_p = vr->FieldOffset("resp_p");
|
|
||||||
proto = vr->FieldOffset("proto");
|
|
||||||
|
|
||||||
if ( orig_h < 0 || resp_h < 0 || orig_p < 0 || resp_p < 0 || proto < 0 ) {
|
|
||||||
t.transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO we ought to check that the fields have the right
|
|
||||||
// types, too.
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! vl->HasField(orig_h) || ! vl->HasField(resp_h) || ! vl->HasField(orig_p) || ! vl->HasField(resp_p) ) {
|
|
||||||
t.transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IPAddr& orig_addr = vl->GetFieldAs<AddrVal>(orig_h);
|
|
||||||
const IPAddr& resp_addr = vl->GetFieldAs<AddrVal>(resp_h);
|
|
||||||
|
|
||||||
const auto& orig_portv = vl->GetFieldAs<PortVal>(orig_p);
|
|
||||||
const auto& resp_portv = vl->GetFieldAs<PortVal>(resp_p);
|
|
||||||
|
|
||||||
const auto& protov = vl->GetField<CountVal>(proto);
|
|
||||||
|
|
||||||
auto ct = ConnTuple{orig_addr, resp_addr, orig_portv->Port(), resp_portv->Port(),
|
|
||||||
static_cast<uint16_t>(protov->AsCount())};
|
|
||||||
InitRawConnTuple(ct);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPBasedAnalyzer::IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask, bool report_unknown_protocols)
|
IPBasedAnalyzer::IPBasedAnalyzer(const char* name, TransportProto proto, uint32_t mask, bool report_unknown_protocols)
|
||||||
: zeek::packet_analysis::Analyzer(name, report_unknown_protocols), transport(proto), server_port_mask(mask) {}
|
: zeek::packet_analysis::Analyzer(name, report_unknown_protocols), transport(proto), server_port_mask(mask) {}
|
||||||
|
|
||||||
|
@ -87,17 +30,21 @@ bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt
|
||||||
if ( ! BuildConnTuple(len, data, pkt, tuple) )
|
if ( ! BuildConnTuple(len, data, pkt, tuple) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The IPBasedAnalyzer requires a builder that produces IPConnKey instances.
|
static IPBasedConnKeyPtr key; // Watch: This is static for reuse!
|
||||||
// We could check with dynamic_cast, but that's probably slow, so assume
|
if ( ! key ) {
|
||||||
// plugin providers know what they're doing here and anyhow, we don't really
|
ConnKeyPtr ck = conntuple_mgr->GetBuilder().NewConnKey();
|
||||||
// have analyzers that instantiate non-IP connections today and definitely
|
|
||||||
// not here!
|
// The IPBasedAnalyzer requires a builder that produces IPBasedConnKey instances.
|
||||||
auto key = cast_intrusive<IPConnKey>(zeek::conntuple_mgr->GetBuilder().NewConnKey());
|
// We could check with dynamic_cast, but that's probably slow, so assume plugin
|
||||||
|
// providers know what they're doing here and anyhow, we don't really have analyzers
|
||||||
|
// that instantiate non-IP connections today and definitely not here!
|
||||||
|
key = std::unique_ptr<IPBasedConnKey>(static_cast<IPBasedConnKey*>(ck.release()));
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the key with the IP conn tuple and the packet as additional context.
|
// Initialize the key with the IP conn tuple and the packet as additional context.
|
||||||
//
|
//
|
||||||
// Custom IPConnKey implementations can fiddle with the Key through
|
// Custom IPConnKey implementations can fiddle with the Key through
|
||||||
// the DoInit(const Packet& pkt) hook at this point.
|
// the DoInit(const Packet& pkt) hook called at this point.
|
||||||
key->Init(tuple, *pkt);
|
key->Init(tuple, *pkt);
|
||||||
|
|
||||||
const std::shared_ptr<IP_Hdr>& ip_hdr = pkt->ip_hdr;
|
const std::shared_ptr<IP_Hdr>& ip_hdr = pkt->ip_hdr;
|
||||||
|
@ -108,6 +55,8 @@ bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt
|
||||||
conn = NewConn(std::move(key), tuple, pkt);
|
conn = NewConn(std::move(key), tuple, pkt);
|
||||||
if ( conn )
|
if ( conn )
|
||||||
session_mgr->Insert(conn, false);
|
session_mgr->Insert(conn, false);
|
||||||
|
|
||||||
|
assert(! key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( conn->IsReuse(run_state::processing_start_time, ip_hdr->Payload()) ) {
|
if ( conn->IsReuse(run_state::processing_start_time, ip_hdr->Payload()) ) {
|
||||||
|
@ -117,16 +66,14 @@ bool IPBasedAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pkt
|
||||||
conn = NewConn(std::move(key), tuple, pkt);
|
conn = NewConn(std::move(key), tuple, pkt);
|
||||||
if ( conn )
|
if ( conn )
|
||||||
session_mgr->Insert(conn, false);
|
session_mgr->Insert(conn, false);
|
||||||
|
|
||||||
|
assert(! key);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
conn->CheckEncapsulation(pkt->encap);
|
conn->CheckEncapsulation(pkt->encap);
|
||||||
|
|
||||||
// We could give back the ConnKey for re-use to avoid the malloc/memset()
|
// The next time we get here, the key instance
|
||||||
// overhead if we already knew about the session and don't had a use for
|
assert(key);
|
||||||
// the key other than facilitating the lookup of the session. Not sure
|
|
||||||
// that's worth it.
|
|
||||||
//
|
|
||||||
// GetBuilder().ReturnKey(std::move(key));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include "zeek/Conn.h"
|
#include "zeek/Conn.h"
|
||||||
|
@ -30,13 +31,36 @@ namespace detail {
|
||||||
// UNKNOWN_IP_PROTO is 65535
|
// UNKNOWN_IP_PROTO is 65535
|
||||||
constexpr uint16_t INVALID_CONN_KEY_IP_PROTO = 65534;
|
constexpr uint16_t INVALID_CONN_KEY_IP_PROTO = 65534;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Struct for embedding into a IPBasedConnKey.
|
||||||
|
*/
|
||||||
struct RawConnTuple {
|
struct RawConnTuple {
|
||||||
in6_addr ip1;
|
in6_addr ip1;
|
||||||
in6_addr ip2;
|
in6_addr ip2;
|
||||||
uint16_t port1 = 0;
|
uint16_t port1 = 0;
|
||||||
uint16_t port2 = 0;
|
uint16_t port2 = 0;
|
||||||
uint16_t transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
uint16_t transport = detail::INVALID_CONN_KEY_IP_PROTO;
|
||||||
};
|
} __attribute__((packed, aligned));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a raw conn tuple from a conn tuple in canonicalized form.
|
||||||
|
*/
|
||||||
|
inline void init_raw_tuple(RawConnTuple& t, const ConnTuple& ct) {
|
||||||
|
if ( ct.is_one_way || addr_port_canon_lt(ct.src_addr, ct.src_port, ct.dst_addr, ct.dst_port) ) {
|
||||||
|
ct.src_addr.CopyIPv6(&t.ip1);
|
||||||
|
ct.dst_addr.CopyIPv6(&t.ip2);
|
||||||
|
t.port1 = ct.src_port;
|
||||||
|
t.port2 = ct.dst_port;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ct.dst_addr.CopyIPv6(&t.ip1);
|
||||||
|
ct.src_addr.CopyIPv6(&t.ip2);
|
||||||
|
t.port1 = ct.dst_port;
|
||||||
|
t.port2 = ct.src_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.transport = ct.proto;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
@ -56,44 +80,31 @@ public:
|
||||||
* subclasses to hook into the initialization of the key.
|
* subclasses to hook into the initialization of the key.
|
||||||
*/
|
*/
|
||||||
void Init(const ConnTuple& ct, const Packet& pkt) {
|
void Init(const ConnTuple& ct, const Packet& pkt) {
|
||||||
InitRawConnTuple(ct);
|
init_raw_tuple(RawTuple(), ct);
|
||||||
ConnKey::Init(pkt);
|
ConnKey::Init(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FromConnIdVal(const zeek::RecordValPtr& conn_id) override;
|
std::optional<std::string> Error() const override {
|
||||||
|
auto& rt = RawTuple();
|
||||||
|
if ( rt.transport == detail::INVALID_CONN_KEY_IP_PROTO )
|
||||||
|
return "invalid connection ID record";
|
||||||
|
if ( rt.transport == UNKNOWN_IP_PROTO )
|
||||||
|
return "invalid connection ID record: the proto field has the \"unknown\" 65535 value. Did you forget to "
|
||||||
|
"set it?";
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a modifiable version of the raw Conn Tuple.
|
* Return a modifiable version of the embedded RawConnTuple.
|
||||||
*
|
*
|
||||||
* This is virtual such that subclasses can control where
|
* This is virtual such that subclasses can control where
|
||||||
* their own ConnTuple instance to allow.
|
* they'd like to place the RawConnTuple within the key.
|
||||||
*/
|
*/
|
||||||
virtual detail::RawConnTuple& RawTuple() = 0;
|
virtual detail::RawConnTuple& RawTuple() const = 0;
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* Helper for subclasses that override Init() to initialize this key's tuple in normalized form.
|
|
||||||
*/
|
|
||||||
void InitRawConnTuple(const ConnTuple& ct) {
|
|
||||||
auto& t = RawTuple();
|
|
||||||
if ( ct.is_one_way || addr_port_canon_lt(ct.src_addr, ct.src_port, ct.dst_addr, ct.dst_port) ) {
|
|
||||||
ct.src_addr.CopyIPv6(&t.ip1);
|
|
||||||
ct.dst_addr.CopyIPv6(&t.ip2);
|
|
||||||
t.port1 = ct.src_port;
|
|
||||||
t.port2 = ct.dst_port;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ct.dst_addr.CopyIPv6(&t.ip1);
|
|
||||||
ct.src_addr.CopyIPv6(&t.ip2);
|
|
||||||
t.port1 = ct.dst_port;
|
|
||||||
t.port2 = ct.src_port;
|
|
||||||
}
|
|
||||||
|
|
||||||
t.transport = ct.proto;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using IPBasedConnKeyPtr = zeek::IntrusivePtr<IPBasedConnKey>;
|
using IPBasedConnKeyPtr = std::unique_ptr<IPBasedConnKey>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,7 +114,6 @@ class IPConnKey : public IPBasedConnKey {
|
||||||
public:
|
public:
|
||||||
IPConnKey() {
|
IPConnKey() {
|
||||||
// Fill holes as we use the full tuple as a Key!
|
// Fill holes as we use the full tuple as a Key!
|
||||||
// Could we h
|
|
||||||
memset(static_cast<void*>(&key), '\0', sizeof(key));
|
memset(static_cast<void*>(&key), '\0', sizeof(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +121,12 @@ public:
|
||||||
return {reinterpret_cast<const std::byte*>(&key), reinterpret_cast<const std::byte*>(&key) + sizeof(key)};
|
return {reinterpret_cast<const std::byte*>(&key), reinterpret_cast<const std::byte*>(&key) + sizeof(key)};
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::RawConnTuple& RawTuple() override { return key.tuple; }
|
detail::RawConnTuple& RawTuple() const override { return key.tuple; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct {
|
struct {
|
||||||
struct detail::RawConnTuple tuple;
|
// mutable for non-const RawTuple() return value.
|
||||||
|
mutable struct detail::RawConnTuple tuple;
|
||||||
} key;
|
} key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -185,10 +185,8 @@ bool TeredoAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& k = conn->Key();
|
const auto& k = conn->Key();
|
||||||
auto sk = k.SessionKey();
|
auto sk = k.SessionKey();
|
||||||
|
|
||||||
// zeek::detail::OLD_ConnKey conn_key = conn->Key();
|
|
||||||
OrigRespMap::iterator or_it = orig_resp_map.find(sk);
|
OrigRespMap::iterator or_it = orig_resp_map.find(sk);
|
||||||
|
|
||||||
// The first time a teredo packet is parsed successfully, insert
|
// The first time a teredo packet is parsed successfully, insert
|
||||||
|
@ -196,9 +194,10 @@ bool TeredoAnalyzer::AnalyzePacket(size_t len, const uint8_t* data, Packet* pack
|
||||||
// see valid Teredo packets. Further, raise an event so that script
|
// see valid Teredo packets. Further, raise an event so that script
|
||||||
// layer can install a connection removal hooks to cleanup later.
|
// layer can install a connection removal hooks to cleanup later.
|
||||||
if ( or_it == orig_resp_map.end() ) {
|
if ( or_it == orig_resp_map.end() ) {
|
||||||
sk.CopyData();
|
sk.CopyData(); // Copy key data to store in map.
|
||||||
// OrigRespMap::value_type p{std::move(sk), OrigResp{}};
|
auto [it, inserted] = orig_resp_map.emplace(std::move(sk), OrigResp{});
|
||||||
auto [it, inserted] = orig_resp_map.insert_or_assign(std::move(sk), OrigResp{});
|
assert(inserted);
|
||||||
|
or_it = it;
|
||||||
|
|
||||||
packet->session->EnqueueEvent(new_teredo_state, nullptr, packet->session->GetVal());
|
packet->session->EnqueueEvent(new_teredo_state, nullptr, packet->session->GetVal());
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ protected:
|
||||||
bool valid_resp = false;
|
bool valid_resp = false;
|
||||||
bool confirmed = false;
|
bool confirmed = false;
|
||||||
};
|
};
|
||||||
using OrigRespMap = std::unordered_map<zeek::session::detail::Key, OrigResp, zeek::session::detail::KeyHash>;
|
using OrigRespMap = std::map<zeek::session::detail::Key, OrigResp>;
|
||||||
OrigRespMap orig_resp_map;
|
OrigRespMap orig_resp_map;
|
||||||
|
|
||||||
std::unique_ptr<zeek::detail::Specific_RE_Matcher> pattern_re;
|
std::unique_ptr<zeek::detail::Specific_RE_Matcher> pattern_re;
|
||||||
|
|
|
@ -13,8 +13,8 @@ function remove_teredo_connection%(cid: conn_id%) : bool
|
||||||
zeek::packet_analysis::AnalyzerPtr teredo = zeek::packet_mgr->GetAnalyzer("Teredo");
|
zeek::packet_analysis::AnalyzerPtr teredo = zeek::packet_mgr->GetAnalyzer("Teredo");
|
||||||
if ( teredo )
|
if ( teredo )
|
||||||
{
|
{
|
||||||
auto ck = zeek::conntuple_mgr->GetBuilder().NewConnKey();
|
// XXX: Should be IP specific builder!
|
||||||
// ck->LoadConnIdVal(v);
|
auto ck = zeek::conntuple_mgr->GetBuilder().FromVal({zeek::NewRef{}, cid});
|
||||||
auto sk = ck->SessionKey();
|
auto sk = ck->SessionKey();
|
||||||
static_cast<zeek::packet_analysis::teredo::TeredoAnalyzer*>(teredo.get())->RemoveConnection(sk);
|
static_cast<zeek::packet_analysis::teredo::TeredoAnalyzer*>(teredo.get())->RemoveConnection(sk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "zeek/Hash.h"
|
#include "zeek/Hash.h"
|
||||||
#include "zeek/IntrusivePtr.h"
|
#include "zeek/IntrusivePtr.h"
|
||||||
|
@ -100,7 +101,14 @@ class ConnKey {
|
||||||
public:
|
public:
|
||||||
virtual ~ConnKey() {}
|
virtual ~ConnKey() {}
|
||||||
|
|
||||||
// Init function called by analyzers or subclassed.
|
/**
|
||||||
|
* ConnKeys created from Vals may be invalid, Error() can be used to determine validity.
|
||||||
|
*/
|
||||||
|
virtual std::optional<std::string> Error() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization of this key with the current packet.
|
||||||
|
*/
|
||||||
void Init(const Packet& pkt) { DoInit(pkt); }
|
void Init(const Packet& pkt) { DoInit(pkt); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,11 +125,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual void FillConnIdVal(RecordValPtr& conn_id) {};
|
virtual void FillConnIdVal(RecordValPtr& conn_id) {};
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate a ConnKey instance from a script layer record value.
|
|
||||||
*/
|
|
||||||
virtual bool FromConnIdVal(const RecordValPtr& conn_id) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* They Key over which to compute a hash or use for comparison with other keys.
|
* They Key over which to compute a hash or use for comparison with other keys.
|
||||||
*
|
*
|
||||||
|
@ -130,28 +133,16 @@ public:
|
||||||
virtual zeek::Span<const std::byte> Key() const = 0;
|
virtual zeek::Span<const std::byte> Key() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View over the key data as a SessionKey.
|
* View over key data as returned by Key() as session::detail::Key instance.
|
||||||
*
|
*
|
||||||
* Not sure this makes much sense, it might also be possible to switch
|
* Mostly for plumbing the session/Manager.h code.
|
||||||
* the session_map to hold ConnKeyPtr instead with specialized hash and
|
|
||||||
* equals functions instead.
|
|
||||||
*/
|
*/
|
||||||
zeek::session::detail::Key SessionKey() const {
|
zeek::session::detail::Key SessionKey() const {
|
||||||
auto span = Key();
|
auto span = Key();
|
||||||
return zeek::session::detail::Key(span.data(), span.size(), session::detail::Key::CONNECTION_KEY_TYPE);
|
return zeek::session::detail::Key(span.data(), span.size(), session::detail::Key::CONNECTION_KEY_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support usage as IntrusivePtr.
|
|
||||||
int ref_cnt = 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void Ref(ConnKey* k) { ++k->ref_cnt; }
|
using ConnKeyPtr = std::unique_ptr<ConnKey>;
|
||||||
|
|
||||||
inline void Unref(ConnKey* k) {
|
|
||||||
if ( --k->ref_cnt == 0 )
|
|
||||||
delete k;
|
|
||||||
}
|
|
||||||
|
|
||||||
using ConnKeyPtr = zeek::IntrusivePtr<ConnKey>;
|
|
||||||
|
|
||||||
} // namespace zeek
|
} // namespace zeek
|
||||||
|
|
|
@ -91,31 +91,21 @@ Manager::~Manager() {
|
||||||
void Manager::Done() {}
|
void Manager::Done() {}
|
||||||
|
|
||||||
Connection* Manager::FindConnection(Val* v) {
|
Connection* Manager::FindConnection(Val* v) {
|
||||||
// zeek::detail::OLD_ConnKeyPtr conn_key = conntuple_mgr->GetBuilder().GetKey(v);
|
// XXX: Technically we should probably dispatch between different builders for different kinds of Val instances.
|
||||||
|
// conn_id is IP specific, so if ``v`` is something else, maybe we'd like to use a different builder.
|
||||||
|
auto conn_key = conntuple_mgr->GetBuilder().FromVal({zeek::NewRef{}, v});
|
||||||
|
|
||||||
auto conn_key = conntuple_mgr->GetBuilder().NewConnKey();
|
if ( conn_key->Error() ) {
|
||||||
/**
|
|
||||||
// conn_key->LoadConnIdVal(v);
|
|
||||||
|
|
||||||
This is IP specific stuff!
|
|
||||||
|
|
||||||
if ( ! conn_key->Valid() ) {
|
|
||||||
// Produce a loud error for invalid script-layer conn_id records.
|
// Produce a loud error for invalid script-layer conn_id records.
|
||||||
const char* extra = "";
|
zeek::emit_builtin_error(conn_key->Error()->c_str());
|
||||||
if ( conn_key->transport == UNKNOWN_IP_PROTO )
|
|
||||||
extra = ": the proto field has the \"unknown\" 65535 value. Did you forget to set it?";
|
|
||||||
|
|
||||||
zeek::emit_builtin_error(zeek::util::fmt("invalid connection ID record encountered%s", extra));
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
return FindConnection(*conn_key);
|
return FindConnection(*conn_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection* Manager::FindConnection(const zeek::ConnKey& conn_key) {
|
Connection* Manager::FindConnection(const zeek::ConnKey& conn_key) {
|
||||||
detail::Key key{conn_key.SessionKey()};
|
auto key = conn_key.SessionKey();
|
||||||
|
|
||||||
auto it = session_map.find(key);
|
auto it = session_map.find(key);
|
||||||
if ( it != session_map.end() )
|
if ( it != session_map.end() )
|
||||||
|
|
|
@ -93,7 +93,7 @@ public:
|
||||||
size_t CurrentSessions() { return session_map.size(); }
|
size_t CurrentSessions() { return session_map.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using SessionMap = std::unordered_map<zeek::session::detail::Key, Session*, detail::KeyHash>;
|
using SessionMap = std::unordered_map<detail::Key, Session*, detail::KeyHash>;
|
||||||
|
|
||||||
// Inserts a new connection into the sessions map. If a connection with
|
// Inserts a new connection into the sessions map. If a connection with
|
||||||
// the same key already exists in the map, it will be overwritten by
|
// the same key already exists in the map, it will be overwritten by
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue