Skip to content

Commit

Permalink
Merge pull request #144 from kubescape/dns-tracer
Browse files Browse the repository at this point in the history
enrich network neighbors with DNS data
  • Loading branch information
Daniel-GrunbergerCA authored Nov 9, 2023
2 parents 7458b0d + 172f4b3 commit 9b12f91
Show file tree
Hide file tree
Showing 12 changed files with 355 additions and 47 deletions.
12 changes: 10 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"node-agent/pkg/applicationprofilemanager"
applicationprofilemanagerv1 "node-agent/pkg/applicationprofilemanager/v1"
"node-agent/pkg/config"
"node-agent/pkg/containerwatcher/dnsmanager"
"node-agent/pkg/containerwatcher/v1"
"node-agent/pkg/filehandler/v1"
"node-agent/pkg/networkmanager"
Expand Down Expand Up @@ -105,14 +106,21 @@ func main() {
}

var networkManagerClient networkmanager.NetworkManagerClient
var dnsManagerClient dnsmanager.DNSManagerClient

if cfg.EnableNetworkTracing {
networkManagerClient = networkmanager.CreateNetworkManager(ctx, cfg, k8sClient, storageClient, clusterData.ClusterName)
dnsManager := dnsmanager.CreateDNSManager(ctx, cfg, k8sClient, storageClient, clusterData.ClusterName)
dnsManagerClient = dnsManager

networkManagerClient = networkmanager.CreateNetworkManager(ctx, cfg, k8sClient, storageClient, clusterData.ClusterName, dnsManager)

} else {
networkManagerClient = networkmanager.CreateNetworkManagerMock()
dnsManagerClient = dnsmanager.CreateDNSManagerMock()
}

// Create the container handler
mainHandler, err := containerwatcher.CreateIGContainerWatcher(cfg, applicationProfileManager, k8sClient, relevancyManager, networkManagerClient)
mainHandler, err := containerwatcher.CreateIGContainerWatcher(cfg, applicationProfileManager, k8sClient, relevancyManager, networkManagerClient, dnsManagerClient)
if err != nil {
logger.L().Ctx(ctx).Fatal("error creating the container watcher", helpers.Error(err))
}
Expand Down
34 changes: 34 additions & 0 deletions pkg/containerwatcher/dnsmanager/dns_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package dnsmanager

import (
"context"
"node-agent/pkg/config"
"node-agent/pkg/k8sclient"
"node-agent/pkg/storage"

"github.com/goradd/maps"
tracerdnstype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types"
)

// DNSManager is used to manage DNS events and save IP resolutions. It exposes an API to resolve IP address to domain name.
type DNSManager struct {
addressToDomainMap maps.SafeMap[string, string] // this map is used to resolve IP address to domain name
}

var _ DNSManagerClient = (*DNSManager)(nil)
var _ DNSResolver = (*DNSManager)(nil)

func CreateDNSManager(ctx context.Context, cfg config.Config, k8sClient k8sclient.K8sClientInterface, storageClient storage.StorageClient, clusterName string) *DNSManager {
return &DNSManager{}
}

func (dm *DNSManager) ProcessDNSEvent(dnsEvent tracerdnstype.Event) {
for _, address := range dnsEvent.Addresses {
dm.addressToDomainMap.Set(address, dnsEvent.DNSName)
}
}

func (dm *DNSManager) ResolveIPAddress(ipAddr string) (string, bool) {
domain := dm.addressToDomainMap.Get(ipAddr)
return domain, domain != ""
}
13 changes: 13 additions & 0 deletions pkg/containerwatcher/dnsmanager/dns_manager_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dnsmanager

import (
tracerdnstype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types"
)

type DNSManagerClient interface {
ProcessDNSEvent(networkEvent tracerdnstype.Event)
}

type DNSResolver interface {
ResolveIPAddress(ipAddr string) (string, bool)
}
22 changes: 22 additions & 0 deletions pkg/containerwatcher/dnsmanager/dns_manager_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package dnsmanager

import (
tracerdnstype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types"
)

type DNSManagerMock struct {
}

var _ DNSManagerClient = (*DNSManagerMock)(nil)
var _ DNSResolver = (*DNSManagerMock)(nil)

func CreateDNSManagerMock() *DNSManagerMock {
return &DNSManagerMock{}
}

func (n *DNSManagerMock) ProcessDNSEvent(event tracerdnstype.Event) {
}

func (n *DNSManagerMock) ResolveIPAddress(ipAddr string) (string, bool) {
return "", false
}
50 changes: 50 additions & 0 deletions pkg/containerwatcher/dnsmanager/dns_manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package dnsmanager

import (
"testing"

tracerdnstype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types"
)

func TestResolveIPAddress(t *testing.T) {
tests := []struct {
name string
dnsEvent tracerdnstype.Event
ipAddr string
want string
}{
{
name: "ip found",
ipAddr: "14.23.332.4",
dnsEvent: tracerdnstype.Event{
DNSName: "test.com",
Addresses: []string{
"14.23.332.4",
},
},
want: "test.com",
},
{
name: "ip not found",
ipAddr: "14.23.332.4",
dnsEvent: tracerdnstype.Event{
DNSName: "test.com",
Addresses: []string{
"54.23.332.4",
},
},
want: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dm := &DNSManager{}
dm.ProcessDNSEvent(tt.dnsEvent)
got, _ := dm.ResolveIPAddress(tt.ipAddr)
if got != tt.want {
t.Errorf("ResolveIPAddress() got = %v, want %v", got, tt.want)
}
})
}
}
23 changes: 22 additions & 1 deletion pkg/containerwatcher/v1/container_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"node-agent/pkg/applicationprofilemanager"
"node-agent/pkg/config"
"node-agent/pkg/containerwatcher"
"node-agent/pkg/containerwatcher/dnsmanager"
"node-agent/pkg/networkmanager"
"node-agent/pkg/relevancymanager"
"node-agent/pkg/utils"
Expand All @@ -14,6 +15,8 @@ import (
tracerseccomp "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/advise/seccomp/tracer"
tracercapabilities "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/capabilities/tracer"
tracercapabilitiestype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/capabilities/types"
tracerdns "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/tracer"
tracerdnstype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types"
tracerexec "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/tracer"
tracerexectype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/exec/types"
tracernetwork "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/network/tracer"
Expand All @@ -32,11 +35,13 @@ const (
capabilitiesTraceName = "trace_capabilities"
execTraceName = "trace_exec"
networkTraceName = "trace_network"
dnsTraceName = "trace_dns"
openTraceName = "trace_open"
capabilitiesWorkerPoolSize = 1
execWorkerPoolSize = 2
openWorkerPoolSize = 8
networkWorkerPoolSize = 1
dnsWorkerPoolSize = 5
)

type IGContainerWatcher struct {
Expand All @@ -50,6 +55,7 @@ type IGContainerWatcher struct {
k8sClient *k8sinterface.KubernetesApi
relevancyManager relevancymanager.RelevancyManagerClient
networkManager networkmanager.NetworkManagerClient
dnsManager dnsmanager.DNSManagerClient
// IG Collections
containerCollection *containercollection.ContainerCollection
tracerCollection *tracercollection.TracerCollection
Expand All @@ -59,18 +65,20 @@ type IGContainerWatcher struct {
openTracer *traceropen.Tracer
syscallTracer *tracerseccomp.Tracer
networkTracer *tracernetwork.Tracer
dnsTracer *tracerdns.Tracer
kubeIPInstance operators.OperatorInstance
kubeNameInstance operators.OperatorInstance
// Worker pools
capabilitiesWorkerPool *ants.PoolWithFunc
execWorkerPool *ants.PoolWithFunc
openWorkerPool *ants.PoolWithFunc
networkWorkerPool *ants.PoolWithFunc
dnsWorkerPool *ants.PoolWithFunc
}

var _ containerwatcher.ContainerWatcher = (*IGContainerWatcher)(nil)

func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager applicationprofilemanager.ApplicationProfileManagerClient, k8sClient *k8sinterface.KubernetesApi, relevancyManager relevancymanager.RelevancyManagerClient, networkManagerClient networkmanager.NetworkManagerClient) (*IGContainerWatcher, error) {
func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager applicationprofilemanager.ApplicationProfileManagerClient, k8sClient *k8sinterface.KubernetesApi, relevancyManager relevancymanager.RelevancyManagerClient, networkManagerClient networkmanager.NetworkManagerClient, dnsManagerClient dnsmanager.DNSManagerClient) (*IGContainerWatcher, error) {
// Use container collection to get notified for new containers
containerCollection := &containercollection.ContainerCollection{}
// Create a tracer collection instance
Expand Down Expand Up @@ -130,6 +138,17 @@ func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager appli
networkManagerClient.SaveNetworkEvent(event.Runtime.ContainerID, event.K8s.PodName, event)
})

// Create a dns worker pool
dnsWorkerPool, err := ants.NewPoolWithFunc(dnsWorkerPoolSize, func(i interface{}) {
event := i.(tracerdnstype.Event)

if event.Qr != tracerdnstype.DNSPktTypeResponse {
return
}

dnsManagerClient.ProcessDNSEvent(event)
})

if err != nil {
return nil, fmt.Errorf("creating open network pool: %w", err)
}
Expand All @@ -143,6 +162,7 @@ func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager appli
k8sClient: k8sClient,
relevancyManager: relevancyManager,
networkManager: networkManagerClient,
dnsManager: dnsManagerClient,
// IG Collections
containerCollection: containerCollection,
tracerCollection: tracerCollection,
Expand All @@ -151,6 +171,7 @@ func CreateIGContainerWatcher(cfg config.Config, applicationProfileManager appli
execWorkerPool: execWorkerPool,
openWorkerPool: openWorkerPool,
networkWorkerPool: networkWorkerPool,
dnsWorkerPool: dnsWorkerPool,
}, nil
}

Expand Down
15 changes: 14 additions & 1 deletion pkg/containerwatcher/v1/container_watcher_private.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

containercollection "github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection"
"github.com/inspektor-gadget/inspektor-gadget/pkg/utils/host"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
)
Expand Down Expand Up @@ -101,11 +102,23 @@ func (ch *IGContainerWatcher) startTracers() error {
}

if ch.cfg.EnableNetworkTracing {
// Start network tracer
host.Init(host.Config{AutoMountFilesystems: true})

if err := ch.startKubernetesResolution(); err != nil {
logger.L().Error("error starting kubernetes resolution", helpers.Error(err))
return err
}

if err := ch.startDNSTracing(); err != nil {
// not failing on dns tracing error
logger.L().Error("error starting dns tracing", helpers.Error(err))
}

if err := ch.startNetworkTracing(); err != nil {
logger.L().Error("error starting network tracing", helpers.Error(err))
return err
}

}

return nil
Expand Down
63 changes: 63 additions & 0 deletions pkg/containerwatcher/v1/dns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package containerwatcher

import (
"fmt"

"github.com/inspektor-gadget/inspektor-gadget/pkg/container-collection/networktracer"
tracerdns "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/tracer"
tracerdnstype "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/trace/dns/types"
"github.com/inspektor-gadget/inspektor-gadget/pkg/types"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
)

func (ch *IGContainerWatcher) dnsEventCallback(event *tracerdnstype.Event) {
if event.Type != types.NORMAL {
logger.L().Ctx(ch.ctx).Warning("dns tracer got drop events - we may miss some realtime data", helpers.Interface("event", event), helpers.String("error", event.Message))
return
}

ch.containerCollection.EnrichByMntNs(&event.CommonData, event.MountNsID)

_ = ch.dnsWorkerPool.Invoke(*event)
}

func (ch *IGContainerWatcher) startDNSTracing() error {
if err := ch.tracerCollection.AddTracer(dnsTraceName, ch.containerSelector); err != nil {
return fmt.Errorf("adding tracer: %w", err)
}

tracerDns, err := tracerdns.NewTracer()
if err != nil {
return fmt.Errorf("creating tracer: %w", err)
}

tracerDns.SetEventHandler(ch.dnsEventCallback)

ch.dnsTracer = tracerDns

config := &networktracer.ConnectToContainerCollectionConfig[tracerdnstype.Event]{
Tracer: ch.dnsTracer,
Resolver: ch.containerCollection,
Selector: ch.containerSelector,
Base: tracerdnstype.Base,
}

_, err = networktracer.ConnectToContainerCollection(config)
if err != nil {
return fmt.Errorf("creating tracer: %w", err)
}

return nil
}

func (ch *IGContainerWatcher) stopDNSTracing() error {
// Stop dns tracer
if err := ch.tracerCollection.RemoveTracer(dnsTraceName); err != nil {
return fmt.Errorf("removing tracer: %w", err)
}

ch.dnsTracer.Close()

return nil
}
Loading

0 comments on commit 9b12f91

Please sign in to comment.