316 lines
8.4 KiB
Go
316 lines
8.4 KiB
Go
package bcap
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDecoderDecodeARP(t *testing.T) {
|
|
decoder := NewDecoder()
|
|
base := time.Unix(1700005000, 0)
|
|
|
|
packet := mustBuildARPPacket(t, base, arpPacketSpec{
|
|
srcMAC: "02:00:00:00:00:01",
|
|
dstMAC: "ff:ff:ff:ff:ff:ff",
|
|
senderMAC: "02:00:00:00:00:01",
|
|
targetMAC: "00:00:00:00:00:00",
|
|
senderIP: "10.0.0.1",
|
|
targetIP: "10.0.0.2",
|
|
operation: 1,
|
|
})
|
|
|
|
decoded, err := decoder.Decode(packet)
|
|
if err != nil {
|
|
t.Fatalf("decode arp: %v", err)
|
|
}
|
|
if decoded.Network.Family != NetworkFamilyARP {
|
|
t.Fatalf("network family = %q, want %q", decoded.Network.Family, NetworkFamilyARP)
|
|
}
|
|
if decoded.Transport.Kind != ProtocolARP {
|
|
t.Fatalf("protocol = %q, want %q", decoded.Transport.Kind, ProtocolARP)
|
|
}
|
|
if decoded.Network.ARP == nil {
|
|
t.Fatal("expected arp facts")
|
|
}
|
|
if decoded.Network.ARP.SenderIP != "10.0.0.1" {
|
|
t.Fatalf("sender ip = %q, want %q", decoded.Network.ARP.SenderIP, "10.0.0.1")
|
|
}
|
|
if decoded.Network.ARP.TargetIP != "10.0.0.2" {
|
|
t.Fatalf("target ip = %q, want %q", decoded.Network.ARP.TargetIP, "10.0.0.2")
|
|
}
|
|
}
|
|
|
|
func TestDecoderDecodeIPv4WithoutTransportReturnsUnknown(t *testing.T) {
|
|
decoder := NewDecoder()
|
|
base := time.Unix(1700005001, 0)
|
|
|
|
packet := mustBuildIPv4OnlyPacket(t, base, "10.0.0.1", "10.0.0.2")
|
|
decoded, err := decoder.Decode(packet)
|
|
if err != nil {
|
|
t.Fatalf("decode ipv4-only: %v", err)
|
|
}
|
|
if decoded.Network.Family != NetworkFamilyIPv4 {
|
|
t.Fatalf("network family = %q, want %q", decoded.Network.Family, NetworkFamilyIPv4)
|
|
}
|
|
if decoded.Transport.Kind != ProtocolUnknown {
|
|
t.Fatalf("transport kind = %q, want %q", decoded.Transport.Kind, ProtocolUnknown)
|
|
}
|
|
}
|
|
|
|
func TestAnalyzerObservePacketTCP(t *testing.T) {
|
|
analyzer := NewAnalyzer()
|
|
defer analyzer.Stop()
|
|
base := time.Unix(1700005002, 0)
|
|
|
|
obs, err := analyzer.ObservePacket(mustBuildTCPPacket(t, base, tcpPacketSpec{
|
|
srcIP: "10.0.0.1",
|
|
dstIP: "10.0.0.2",
|
|
srcPort: 12345,
|
|
dstPort: 80,
|
|
seq: 100,
|
|
syn: true,
|
|
window: 4096,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("observe tcp packet: %v", err)
|
|
}
|
|
if obs.Flow.Forward.Protocol != ProtocolTCP {
|
|
t.Fatalf("flow protocol = %q, want %q", obs.Flow.Forward.Protocol, ProtocolTCP)
|
|
}
|
|
if obs.Hints.TCP == nil {
|
|
t.Fatal("expected tcp hint")
|
|
}
|
|
if obs.Hints.TCP.Event != TCPEventSYN {
|
|
t.Fatalf("tcp event = %q, want %q", obs.Hints.TCP.Event, TCPEventSYN)
|
|
}
|
|
if obs.Hints.Summary.Code != string(TagTCPHandshakeSYN) {
|
|
t.Fatalf("summary = %q, want %q", obs.Hints.Summary.Code, TagTCPHandshakeSYN)
|
|
}
|
|
}
|
|
|
|
func TestAnalyzerObservePacketARP(t *testing.T) {
|
|
analyzer := NewAnalyzer()
|
|
defer analyzer.Stop()
|
|
base := time.Unix(1700005003, 0)
|
|
|
|
obs, err := analyzer.ObservePacket(mustBuildARPPacket(t, base, arpPacketSpec{
|
|
srcMAC: "02:00:00:00:00:01",
|
|
dstMAC: "ff:ff:ff:ff:ff:ff",
|
|
senderMAC: "02:00:00:00:00:01",
|
|
targetMAC: "00:00:00:00:00:00",
|
|
senderIP: "10.0.0.1",
|
|
targetIP: "10.0.0.2",
|
|
operation: 1,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("observe arp packet: %v", err)
|
|
}
|
|
if obs.Flow.Forward.Protocol != ProtocolARP {
|
|
t.Fatalf("flow protocol = %q, want %q", obs.Flow.Forward.Protocol, ProtocolARP)
|
|
}
|
|
if obs.Hints.ARP == nil {
|
|
t.Fatal("expected arp hint")
|
|
}
|
|
if !obs.Hints.ARP.Request {
|
|
t.Fatal("expected arp request hint")
|
|
}
|
|
if obs.Hints.Summary.Code != string(TagARPRequest) {
|
|
t.Fatalf("summary = %q, want %q", obs.Hints.Summary.Code, TagARPRequest)
|
|
}
|
|
}
|
|
|
|
func TestTrackerObserveDecodedTCPWithoutRawPacket(t *testing.T) {
|
|
decoder := NewDecoder()
|
|
tracker := NewTracker()
|
|
defer tracker.Stop()
|
|
base := time.Unix(1700005004, 0)
|
|
|
|
decoded, err := decoder.Decode(mustBuildTCPPacket(t, base, tcpPacketSpec{
|
|
srcIP: "10.0.0.1",
|
|
dstIP: "10.0.0.2",
|
|
srcPort: 12345,
|
|
dstPort: 80,
|
|
seq: 100,
|
|
syn: true,
|
|
window: 4096,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("decode tcp: %v", err)
|
|
}
|
|
decoded.Raw.Packet = nil
|
|
|
|
obs, err := tracker.Observe(decoded)
|
|
if err != nil {
|
|
t.Fatalf("observe decoded tcp: %v", err)
|
|
}
|
|
if obs.Hints.TCP == nil {
|
|
t.Fatal("expected tcp hint")
|
|
}
|
|
if obs.Hints.TCP.Event != TCPEventSYN {
|
|
t.Fatalf("tcp event = %q, want %q", obs.Hints.TCP.Event, TCPEventSYN)
|
|
}
|
|
}
|
|
|
|
func TestAnalyzerObservePacketWithOptionsSrcMACOverride(t *testing.T) {
|
|
analyzer := NewAnalyzer()
|
|
defer analyzer.Stop()
|
|
|
|
override := net.HardwareAddr{0x02, 0xaa, 0xbb, 0xcc, 0xdd, 0xee}
|
|
base := time.Unix(1700005005, 0)
|
|
|
|
obs, err := analyzer.ObservePacketWithOptions(mustBuildTCPPacket(t, base, tcpPacketSpec{
|
|
srcIP: "10.0.0.1",
|
|
dstIP: "10.0.0.2",
|
|
srcPort: 12345,
|
|
dstPort: 80,
|
|
seq: 100,
|
|
syn: true,
|
|
window: 4096,
|
|
}), DecodeOptions{
|
|
SrcMACOverride: override,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("observe tcp packet with options: %v", err)
|
|
}
|
|
if got := obs.Packet.Link.SrcMAC.String(); got != override.String() {
|
|
t.Fatalf("src mac = %q, want %q", got, override.String())
|
|
}
|
|
if obs.Packet.Meta.RelativeTime != 0 {
|
|
t.Fatalf("relative time = %v, want 0", obs.Packet.Meta.RelativeTime)
|
|
}
|
|
}
|
|
|
|
func TestAnalyzerObservePacketTCPKeepaliveResponse(t *testing.T) {
|
|
analyzer := NewAnalyzer()
|
|
defer analyzer.Stop()
|
|
base := time.Unix(1700005006, 0)
|
|
|
|
_, err := analyzer.ObservePacket(mustBuildTCPPacket(t, base, tcpPacketSpec{
|
|
srcIP: "122.210.105.240",
|
|
dstIP: "122.210.110.99",
|
|
srcPort: 3306,
|
|
dstPort: 60818,
|
|
seq: 172126745,
|
|
ack: 2951532891,
|
|
ackFlag: true,
|
|
window: 258,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("observe baseline packet: %v", err)
|
|
}
|
|
|
|
probe, err := analyzer.ObservePacket(mustBuildTCPPacket(t, base.Add(75*time.Second), tcpPacketSpec{
|
|
srcIP: "122.210.105.240",
|
|
dstIP: "122.210.110.99",
|
|
srcPort: 3306,
|
|
dstPort: 60818,
|
|
seq: 172126745,
|
|
ack: 2951532891,
|
|
ackFlag: true,
|
|
window: 258,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("observe keepalive probe: %v", err)
|
|
}
|
|
if probe.Hints.TCP == nil || probe.Hints.TCP.Event != TCPEventKeepalive {
|
|
t.Fatalf("probe event = %#v, want %q", probe.Hints.TCP, TCPEventKeepalive)
|
|
}
|
|
|
|
resp, err := analyzer.ObservePacket(mustBuildTCPPacket(t, base.Add(75*time.Second+50*time.Millisecond), tcpPacketSpec{
|
|
srcIP: "122.210.110.99",
|
|
dstIP: "122.210.105.240",
|
|
srcPort: 60818,
|
|
dstPort: 3306,
|
|
seq: 2951532891,
|
|
ack: 172126746,
|
|
ackFlag: true,
|
|
window: 1024,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("observe keepalive response: %v", err)
|
|
}
|
|
if resp.Hints.TCP == nil {
|
|
t.Fatal("expected tcp hint")
|
|
}
|
|
if resp.Hints.TCP.LegacyState != StateTcpKeepalive {
|
|
t.Fatalf("legacy state = %d, want %d", resp.Hints.TCP.LegacyState, StateTcpKeepalive)
|
|
}
|
|
if resp.Hints.TCP.Event != TCPEventKeepaliveResp {
|
|
t.Fatalf("tcp event = %q, want %q", resp.Hints.TCP.Event, TCPEventKeepaliveResp)
|
|
}
|
|
if !resp.Hints.TCP.KeepaliveResponse {
|
|
t.Fatal("expected keepalive response flag")
|
|
}
|
|
if resp.Hints.Summary.Code != string(TagTCPKeepaliveResp) {
|
|
t.Fatalf("summary = %q, want %q", resp.Hints.Summary.Code, TagTCPKeepaliveResp)
|
|
}
|
|
if !containsTag(resp.Hints.Tags, TagTCPKeepaliveResp) {
|
|
t.Fatalf("tags = %v, want %q", resp.Hints.Tags, TagTCPKeepaliveResp)
|
|
}
|
|
if !containsTag(resp.Hints.Tags, TagTCPKeepalive) {
|
|
t.Fatalf("tags = %v, want %q", resp.Hints.Tags, TagTCPKeepalive)
|
|
}
|
|
}
|
|
|
|
func TestTrackerCleanupExpiredFlows(t *testing.T) {
|
|
cfg := DefaultConfig()
|
|
cfg.ConnectionTimeout = time.Second
|
|
cfg.CleanupInterval = 0
|
|
|
|
decoder := NewDecoder()
|
|
tracker := NewTrackerWithConfig(cfg)
|
|
defer tracker.Stop()
|
|
|
|
stale, err := decoder.Decode(mustBuildTCPPacket(t, time.Now().Add(-5*time.Second), tcpPacketSpec{
|
|
srcIP: "10.0.0.1",
|
|
dstIP: "10.0.0.2",
|
|
srcPort: 12345,
|
|
dstPort: 80,
|
|
seq: 100,
|
|
syn: true,
|
|
window: 4096,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("decode stale packet: %v", err)
|
|
}
|
|
if _, err := tracker.Observe(stale); err != nil {
|
|
t.Fatalf("observe stale packet: %v", err)
|
|
}
|
|
|
|
fresh, err := decoder.Decode(mustBuildTCPPacket(t, time.Now(), tcpPacketSpec{
|
|
srcIP: "10.0.0.3",
|
|
dstIP: "10.0.0.4",
|
|
srcPort: 23456,
|
|
dstPort: 443,
|
|
seq: 200,
|
|
syn: true,
|
|
window: 4096,
|
|
}))
|
|
if err != nil {
|
|
t.Fatalf("decode fresh packet: %v", err)
|
|
}
|
|
if _, err := tracker.Observe(fresh); err != nil {
|
|
t.Fatalf("observe fresh packet: %v", err)
|
|
}
|
|
|
|
if got := tracker.ActiveFlowCount(); got != 2 {
|
|
t.Fatalf("active flow count = %d, want 2", got)
|
|
}
|
|
if removed := tracker.CleanupExpiredFlows(); removed != 1 {
|
|
t.Fatalf("removed stale flows = %d, want 1", removed)
|
|
}
|
|
if got := tracker.ActiveFlowCount(); got != 1 {
|
|
t.Fatalf("active flow count after cleanup = %d, want 1", got)
|
|
}
|
|
}
|
|
|
|
func containsTag(tags []Tag, want Tag) bool {
|
|
for _, tag := range tags {
|
|
if tag == want {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|