mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-21 08:33:05 +00:00
The previous code tracked only by four-tuple, which meant that two connections with same address/port combinations in different namespace would clash and one would get dropped. Also previously the tuple was duplicated between the map key and value, so we remove it from the value. We only add the namespace in the case that the local address is loopback, which matches how the rest of Scope treats addresses.
292 lines
7.1 KiB
Go
292 lines
7.1 KiB
Go
// +build linux
|
|
|
|
package endpoint
|
|
|
|
import (
|
|
"net"
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/weaveworks/tcptracer-bpf/pkg/tracer"
|
|
|
|
"github.com/weaveworks/scope/probe/host"
|
|
)
|
|
|
|
func newMockEbpfTracker() *EbpfTracker {
|
|
return &EbpfTracker{
|
|
ready: true,
|
|
dead: false,
|
|
|
|
openConnections: map[ebpfKey]ebpfDetail{},
|
|
}
|
|
}
|
|
|
|
func TestHandleConnection(t *testing.T) {
|
|
var (
|
|
ServerPid uint32 = 42
|
|
ClientPid uint32 = 43
|
|
ServerAddr = [net.IPv4len]byte{127, 0, 0, 1}
|
|
ServerIP = net.IP(ServerAddr[:])
|
|
ClientAddr = [net.IPv4len]byte{127, 0, 0, 2}
|
|
ClientIP = net.IP(ClientAddr[:])
|
|
ServerPort uint16 = 12345
|
|
ClientPort uint16 = 6789
|
|
NetNS uint32 = 123456789
|
|
|
|
IPv4ConnectEvent = tracer.TcpV4{
|
|
CPU: 0,
|
|
Type: tracer.EventConnect,
|
|
Pid: ClientPid,
|
|
Comm: "cmd",
|
|
SAddr: ClientIP,
|
|
DAddr: ServerIP,
|
|
SPort: ClientPort,
|
|
DPort: ServerPort,
|
|
NetNS: NetNS,
|
|
}
|
|
|
|
IPv4ConnectEbpfConnection = ebpfDetail{
|
|
incoming: false,
|
|
pid: ClientPid,
|
|
}
|
|
|
|
IPv4ConnectCloseEvent = tracer.TcpV4{
|
|
CPU: 0,
|
|
Type: tracer.EventClose,
|
|
Pid: ClientPid,
|
|
Comm: "cmd",
|
|
SAddr: ClientIP,
|
|
DAddr: ServerIP,
|
|
SPort: ClientPort,
|
|
DPort: ServerPort,
|
|
NetNS: NetNS,
|
|
}
|
|
|
|
IPv4AcceptEvent = tracer.TcpV4{
|
|
CPU: 0,
|
|
Type: tracer.EventAccept,
|
|
Pid: ServerPid,
|
|
Comm: "cmd",
|
|
SAddr: ServerIP,
|
|
DAddr: ClientIP,
|
|
SPort: ServerPort,
|
|
DPort: ClientPort,
|
|
NetNS: NetNS,
|
|
}
|
|
|
|
IPv4AcceptEbpfConnection = ebpfDetail{
|
|
incoming: true,
|
|
pid: ServerPid,
|
|
}
|
|
|
|
IPv4AcceptCloseEvent = tracer.TcpV4{
|
|
CPU: 0,
|
|
Type: tracer.EventClose,
|
|
Pid: ClientPid,
|
|
Comm: "cmd",
|
|
SAddr: ServerIP,
|
|
DAddr: ClientIP,
|
|
SPort: ServerPort,
|
|
DPort: ClientPort,
|
|
NetNS: NetNS,
|
|
}
|
|
)
|
|
|
|
mockEbpfTracker := newMockEbpfTracker()
|
|
|
|
tuple := fourTuple{ClientAddr, ServerAddr, IPv4ConnectEvent.SPort, IPv4ConnectEvent.DPort}
|
|
mockEbpfTracker.handleConnection(IPv4ConnectEvent.Type, tuple, int(IPv4ConnectEvent.Pid), NetNS)
|
|
key := makeKey(tuple, NetNS)
|
|
if !reflect.DeepEqual(mockEbpfTracker.openConnections[key], IPv4ConnectEbpfConnection) {
|
|
t.Errorf("Connection mismatch connect event\nTarget connection:%v\nParsed connection:%v",
|
|
IPv4ConnectEbpfConnection, mockEbpfTracker.openConnections[key])
|
|
}
|
|
|
|
tuple = fourTuple{ClientAddr, ServerAddr, uint16(IPv4ConnectCloseEvent.SPort), uint16(IPv4ConnectCloseEvent.DPort)}
|
|
mockEbpfTracker.handleConnection(IPv4ConnectCloseEvent.Type, tuple, int(IPv4ConnectCloseEvent.Pid), NetNS)
|
|
key = makeKey(tuple, NetNS)
|
|
if len(mockEbpfTracker.openConnections) != 0 {
|
|
t.Errorf("Connection mismatch close event\nConnection to close:%v",
|
|
mockEbpfTracker.openConnections[key])
|
|
}
|
|
|
|
mockEbpfTracker = newMockEbpfTracker()
|
|
|
|
tuple = fourTuple{ServerAddr, ClientAddr, uint16(IPv4AcceptEvent.SPort), uint16(IPv4AcceptEvent.DPort)}
|
|
mockEbpfTracker.handleConnection(IPv4AcceptEvent.Type, tuple, int(IPv4AcceptEvent.Pid), NetNS)
|
|
key = makeKey(tuple, NetNS)
|
|
if !reflect.DeepEqual(mockEbpfTracker.openConnections[key], IPv4AcceptEbpfConnection) {
|
|
t.Errorf("Connection mismatch connect event\nTarget connection:%v\nParsed connection:%v",
|
|
IPv4AcceptEbpfConnection, mockEbpfTracker.openConnections[key])
|
|
}
|
|
|
|
tuple = fourTuple{ServerAddr, ClientAddr, uint16(IPv4AcceptCloseEvent.SPort), uint16(IPv4AcceptCloseEvent.DPort)}
|
|
mockEbpfTracker.handleConnection(IPv4AcceptCloseEvent.Type, tuple, int(IPv4AcceptCloseEvent.Pid), NetNS)
|
|
|
|
if len(mockEbpfTracker.openConnections) != 0 {
|
|
t.Errorf("Connection mismatch close event\nConnection to close:%v",
|
|
mockEbpfTracker.openConnections)
|
|
}
|
|
}
|
|
|
|
func TestWalkConnections(t *testing.T) {
|
|
var (
|
|
cnt int
|
|
activeKey = ebpfKey{networkNamespace: 12345}
|
|
inactiveKey = ebpfKey{networkNamespace: 12345}
|
|
)
|
|
mockEbpfTracker := newMockEbpfTracker()
|
|
mockEbpfTracker.openConnections[activeKey] = ebpfDetail{
|
|
pid: 0,
|
|
}
|
|
mockEbpfTracker.closedConnections = append(mockEbpfTracker.closedConnections,
|
|
ebpfClosedConnection{
|
|
key: inactiveKey,
|
|
ebpfDetail: ebpfDetail{
|
|
pid: 0,
|
|
},
|
|
})
|
|
mockEbpfTracker.walkConnections(func(k ebpfKey, e ebpfDetail) {
|
|
cnt++
|
|
})
|
|
if cnt != 2 {
|
|
t.Errorf("walkConnections found %v instead of 2 connections", cnt)
|
|
}
|
|
}
|
|
|
|
func TestInvalidTimeStampDead(t *testing.T) {
|
|
var (
|
|
cnt int
|
|
ClientPid uint32 = 43
|
|
ServerIP = net.ParseIP("127.0.0.1")
|
|
ClientIP = net.ParseIP("127.0.0.2")
|
|
ServerPort uint16 = 12345
|
|
ClientPort uint16 = 6789
|
|
NetNS uint32 = 123456789
|
|
event = tracer.TcpV4{
|
|
CPU: 0,
|
|
Type: tracer.EventConnect,
|
|
Pid: ClientPid,
|
|
Comm: "cmd",
|
|
SAddr: ClientIP,
|
|
DAddr: ServerIP,
|
|
SPort: ClientPort,
|
|
DPort: ServerPort,
|
|
NetNS: NetNS,
|
|
}
|
|
)
|
|
mockEbpfTracker := newMockEbpfTracker()
|
|
event.Timestamp = 0
|
|
mockEbpfTracker.TCPEventV4(event)
|
|
event2 := event
|
|
event2.SPort = 1
|
|
event2.Timestamp = 2
|
|
mockEbpfTracker.TCPEventV4(event2)
|
|
mockEbpfTracker.walkConnections(func(ebpfKey, ebpfDetail) {
|
|
cnt++
|
|
})
|
|
if cnt != 2 {
|
|
t.Errorf("walkConnections found %v instead of 2 connections", cnt)
|
|
}
|
|
if mockEbpfTracker.isDead() {
|
|
t.Errorf("expected ebpfTracker to be alive after events with valid order")
|
|
}
|
|
cnt = 0
|
|
event.Timestamp = 1
|
|
mockEbpfTracker.TCPEventV4(event)
|
|
mockEbpfTracker.walkConnections(func(ebpfKey, ebpfDetail) {
|
|
cnt++
|
|
})
|
|
if cnt != 2 {
|
|
t.Errorf("walkConnections found %v instead of 2 connections", cnt)
|
|
}
|
|
// EbpfTracker is marked as dead asynchronously.
|
|
deadline := time.Now().Add(5 * time.Second)
|
|
for time.Now().Before(deadline) {
|
|
if mockEbpfTracker.isDead() {
|
|
break
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
}
|
|
if !mockEbpfTracker.isDead() {
|
|
t.Errorf("expected ebpfTracker to be set to dead after events with wrong order")
|
|
}
|
|
}
|
|
|
|
func TestIsKernelSupported(t *testing.T) {
|
|
var release, version string
|
|
oldGetKernelReleaseAndVersion := host.GetKernelReleaseAndVersion
|
|
defer func() {
|
|
host.GetKernelReleaseAndVersion = oldGetKernelReleaseAndVersion
|
|
}()
|
|
host.GetKernelReleaseAndVersion = func() (string, string, error) { return release, version, nil }
|
|
testVersions := []struct {
|
|
release string
|
|
version string
|
|
supported bool
|
|
}{
|
|
{
|
|
"4.1",
|
|
"",
|
|
false,
|
|
},
|
|
{
|
|
"4.4",
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"4.4-custom",
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"4.4.127",
|
|
"",
|
|
true,
|
|
},
|
|
{
|
|
"4.4.0-119-generic",
|
|
"#143-Ubuntu SMP Mon Apr 2 16:08:24 UTC 2018",
|
|
false,
|
|
},
|
|
{
|
|
"4.4.0-127-generic",
|
|
"#153-Ubuntu SMP Sat May 19 10:58:46 UTC 2018",
|
|
true,
|
|
},
|
|
{
|
|
"4.4.0-116-generic",
|
|
"#140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018",
|
|
true,
|
|
},
|
|
{
|
|
"4.13.0-38-generic",
|
|
"#43-Ubuntu SMP Wed Mar 14 15:20:44 UTC 2018",
|
|
true,
|
|
},
|
|
{
|
|
"4.13.0-119-generic",
|
|
"#43-Ubuntu SMP Wed Apr 1 00:00:00 UTC 2018",
|
|
true,
|
|
},
|
|
{
|
|
"4.9.0-6-amd64",
|
|
"#1 SMP Debian 4.9.82-1+deb9u3 (2018-03-02)",
|
|
true,
|
|
},
|
|
}
|
|
for _, tv := range testVersions {
|
|
release = tv.release
|
|
version = tv.version
|
|
err := isKernelSupported()
|
|
if tv.supported && err != nil {
|
|
t.Errorf("expected kernel release %q version %q to be supported but got error: %v", release, version, err)
|
|
}
|
|
if !tv.supported && err == nil {
|
|
t.Errorf("expected kernel release %q version %q to not be supported", release, version)
|
|
}
|
|
}
|
|
}
|