Improve entity metadata initialization

This commit is contained in:
Daniel 2023-09-06 11:07:31 +02:00
parent 42787b12ad
commit 21cd8cb9e5
4 changed files with 89 additions and 85 deletions

View file

@ -35,6 +35,14 @@ type Entity struct { //nolint:maligned
resolveSubDomainLists bool resolveSubDomainLists bool
checkCNAMEs bool checkCNAMEs bool
// IP is the IP address of the connection. If domain is
// set, IP has been resolved by following all CNAMEs.
IP net.IP
// IPScope holds the network scope of the IP.
// For DNS requests, this signifies in which scope the DNS request was resolved.
IPScope netutils.IPScope
// Protocol is the protcol number used by the connection. // Protocol is the protcol number used by the connection.
Protocol uint8 Protocol uint8
@ -55,14 +63,6 @@ type Entity struct { //nolint:maligned
// resolved for Domain. // resolved for Domain.
CNAME []string CNAME []string
// IP is the IP address of the connection. If domain is
// set, IP has been resolved by following all CNAMEs.
IP net.IP
// IPScope holds the network scope of the IP.
// For DNS requests, this signifies in which scope the DNS request was resolved.
IPScope netutils.IPScope
// Country holds the country the IP address (ASN) is // Country holds the country the IP address (ASN) is
// located in. // located in.
Country string Country string
@ -106,23 +106,28 @@ type Entity struct { //nolint:maligned
loadAsnListOnce sync.Once loadAsnListOnce sync.Once
} }
// Init initializes the internal state and returns the entity. // Init initializes internal metadata about the entity.
func (e *Entity) Init() *Entity { // If the entity does not describe a destination, you can supply a different
// for backwards compatibility, remove that one // destination port for endpoint matching.
// It returns the entity itself for single line formatting.
func (e *Entity) Init(dstPort uint16) *Entity {
// Get IP scope.
if e.IP != nil {
e.IPScope = netutils.GetIPScope(e.IP)
} else {
e.IPScope = netutils.Undefined
}
// Set dst port to given value or fall back to entity.
if dstPort > 0 {
e.dstPort = dstPort
} else {
e.dstPort = e.Port
}
return e return e
} }
// SetIP sets the IP address together with its network scope.
func (e *Entity) SetIP(ip net.IP) {
e.IP = ip
e.IPScope = netutils.GetIPScope(ip)
}
// SetDstPort sets the destination port.
func (e *Entity) SetDstPort(dstPort uint16) {
e.dstPort = dstPort
}
// DstPort returns the destination port. // DstPort returns the destination port.
func (e *Entity) DstPort() uint16 { func (e *Entity) DstPort() uint16 {
return e.dstPort return e.dstPort

View file

@ -438,12 +438,12 @@ func (conn *Connection) GatherConnectionInfo(pkt packet.Packet) (err error) {
// Create remote entity. // Create remote entity.
if conn.Entity == nil { if conn.Entity == nil {
// Remote // Remote
conn.Entity = &intel.Entity{ conn.Entity = (&intel.Entity{
IP: pkt.Info().RemoteIP(),
Protocol: uint8(pkt.Info().Protocol), Protocol: uint8(pkt.Info().Protocol),
Port: pkt.Info().RemotePort(), Port: pkt.Info().RemotePort(),
} }).Init(pkt.Info().DstPort)
conn.Entity.SetIP(pkt.Info().RemoteIP())
conn.Entity.SetDstPort(pkt.Info().DstPort)
// Local // Local
conn.SetLocalIP(pkt.Info().LocalIP()) conn.SetLocalIP(pkt.Info().LocalIP())
conn.LocalPort = pkt.Info().LocalPort() conn.LocalPort = pkt.Info().LocalPort()

View file

@ -27,11 +27,11 @@ func NewDefaultConnection(localIP net.IP, localPort uint16, remoteIP net.IP, rem
LocalIPScope: netutils.Global, LocalIPScope: netutils.Global,
LocalPort: localPort, LocalPort: localPort,
PID: process.UnidentifiedProcessID, PID: process.UnidentifiedProcessID,
Entity: &intel.Entity{ Entity: (&intel.Entity{
Protocol: uint8(protocol),
IP: remoteIP, IP: remoteIP,
Protocol: uint8(protocol),
Port: remotePort, Port: remotePort,
}, }).Init(0),
Resolver: nil, Resolver: nil,
Started: time.Now().Unix(), Started: time.Now().Unix(),
VerdictPermanent: false, VerdictPermanent: false,

View file

@ -19,8 +19,6 @@ func TestMain(m *testing.M) {
func testEndpointMatch(t *testing.T, ep Endpoint, entity *intel.Entity, expectedResult EPResult) { func testEndpointMatch(t *testing.T, ep Endpoint, entity *intel.Entity, expectedResult EPResult) {
t.Helper() t.Helper()
entity.SetDstPort(entity.Port)
result, _ := ep.Matches(context.TODO(), entity) result, _ := ep.Matches(context.TODO(), entity)
if result != expectedResult { if result != expectedResult {
t.Errorf( t.Errorf(
@ -75,13 +73,13 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
// DOMAIN // DOMAIN
@ -93,31 +91,31 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc-example.com.", Domain: "abc-example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc-example.com.", Domain: "abc-example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
ep, err = parseEndpoint("+ *.example.com") ep, err = parseEndpoint("+ *.example.com")
if err != nil { if err != nil {
@ -126,31 +124,31 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc-example.com.", Domain: "abc-example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc-example.com.", Domain: "abc-example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
ep, err = parseEndpoint("+ .example.com") ep, err = parseEndpoint("+ .example.com")
if err != nil { if err != nil {
@ -159,31 +157,31 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc-example.com.", Domain: "abc-example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc-example.com.", Domain: "abc-example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
ep, err = parseEndpoint("+ example.*") ep, err = parseEndpoint("+ example.*")
if err != nil { if err != nil {
@ -192,22 +190,22 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
ep, err = parseEndpoint("+ *.exampl*") ep, err = parseEndpoint("+ *.exampl*")
if err != nil { if err != nil {
@ -216,22 +214,22 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "abc.example.com.", Domain: "abc.example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
ep, err = parseEndpoint("+ *.com.") ep, err = parseEndpoint("+ *.com.")
if err != nil { if err != nil {
@ -240,10 +238,10 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.org.", Domain: "example.org.",
}).Init(), NoMatch) }).Init(0), NoMatch)
// protocol // protocol
@ -257,16 +255,16 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 17, Protocol: 17,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
// ports // ports
@ -280,24 +278,28 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 17, Protocol: 17,
Port: 441, Port: 441,
}).Init() }).Init(0)
testEndpointMatch(t, ep, entity, NoMatch) testEndpointMatch(t, ep, entity, NoMatch)
entity.Port = 442 entity.Port = 442
entity.Init(0)
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
entity.Port = 443 entity.Port = 443
entity.Init(0)
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
entity.Port = 444 entity.Port = 444
entity.Init(0)
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
entity.Port = 445 entity.Port = 445
entity.Init(0)
testEndpointMatch(t, ep, entity, NoMatch) testEndpointMatch(t, ep, entity, NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
// IP // IP
@ -311,30 +313,30 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
Protocol: 17, Protocol: 17,
Port: 443, Port: 443,
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "", Domain: "",
IP: net.ParseIP("10.2.3.3"), IP: net.ParseIP("10.2.3.3"),
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
IP: net.ParseIP("10.2.3.5"), IP: net.ParseIP("10.2.3.5"),
Protocol: 17, Protocol: 17,
Port: 443, Port: 443,
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
Domain: "example.com.", Domain: "example.com.",
}).Init(), NoMatch) }).Init(0), NoMatch)
// IP Range // IP Range
@ -344,13 +346,13 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
} }
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
IP: net.ParseIP("10.2.2.4"), IP: net.ParseIP("10.2.2.4"),
}).Init(), NoMatch) }).Init(0), NoMatch)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
IP: net.ParseIP("10.2.3.4"), IP: net.ParseIP("10.2.3.4"),
}).Init(), Permitted) }).Init(0), Permitted)
testEndpointMatch(t, ep, (&intel.Entity{ testEndpointMatch(t, ep, (&intel.Entity{
IP: net.ParseIP("10.2.4.4"), IP: net.ParseIP("10.2.4.4"),
}).Init(), NoMatch) }).Init(0), NoMatch)
// Skip test that need the geoip database in CI. // Skip test that need the geoip database in CI.
if !testing.Short() { if !testing.Short() {
@ -362,12 +364,10 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
t.Fatal(err) t.Fatal(err)
} }
entity = &intel.Entity{} entity = (&intel.Entity{IP: net.IPv4(8, 8, 8, 8)}).Init(0)
entity.SetIP(net.ParseIP("8.8.8.8"))
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
entity = &intel.Entity{} entity = (&intel.Entity{IP: net.IPv4(1, 1, 1, 1)}).Init(0)
entity.SetIP(net.ParseIP("1.1.1.1"))
testEndpointMatch(t, ep, entity, NoMatch) testEndpointMatch(t, ep, entity, NoMatch)
// Country // Country
@ -377,12 +377,10 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
t.Fatal(err) t.Fatal(err)
} }
entity = &intel.Entity{} entity = (&intel.Entity{IP: net.IPv4(194, 232, 104, 1)}).Init(0) // orf.at
entity.SetIP(net.ParseIP("194.232.104.1")) // orf.at
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
entity = &intel.Entity{} entity = (&intel.Entity{IP: net.IPv4(151, 101, 1, 164)}).Init(0) // nytimes.com
entity.SetIP(net.ParseIP("151.101.1.164")) // nytimes.com
testEndpointMatch(t, ep, entity, NoMatch) testEndpointMatch(t, ep, entity, NoMatch)
} }
@ -394,10 +392,10 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
t.Fatal(err) t.Fatal(err)
} }
entity = &intel.Entity{} entity = (&intel.Entity{IP: net.IPv4(192, 168, 0, 1)}).Init(0)
entity.SetIP(net.ParseIP("192.168.0.1"))
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
entity.SetIP(net.ParseIP("151.101.1.164")) // nytimes.com
entity = (&intel.Entity{IP: net.IPv4(151, 101, 1, 164)}).Init(0) // nytimes.com
testEndpointMatch(t, ep, entity, NoMatch) testEndpointMatch(t, ep, entity, NoMatch)
// Port with protocol wildcard // Port with protocol wildcard
@ -412,6 +410,7 @@ func TestEndpointMatching(t *testing.T) { //nolint:maintidx // TODO
Protocol: 6, Protocol: 6,
Port: 443, Port: 443,
} }
entity.Init(0)
testEndpointMatch(t, ep, entity, Permitted) testEndpointMatch(t, ep, entity, Permitted)
// Lists // Lists