Skip to content

Commit

Permalink
cmds/exp/tcpdump: add tests
Browse files Browse the repository at this point in the history
Signed-off-by: Fabian Wienand <[email protected]>
  • Loading branch information
Fabian Wienand authored and RiSKeD committed Aug 8, 2024
1 parent fd92925 commit b7dc420
Show file tree
Hide file tree
Showing 11 changed files with 979 additions and 147 deletions.
85 changes: 85 additions & 0 deletions cmds/exp/tcpdump/domain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// Copyright 2024 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"testing"

"github.com/gopacket/gopacket/layers"
)

func TestDnsData(t *testing.T) {
tests := []struct {
name string
layer *layers.DNS
expected string
}{
{
name: "No error response code, no answers",
layer: &layers.DNS{
ID: 1234,
ResponseCode: layers.DNSResponseCodeNoErr,
Questions: []layers.DNSQuestion{
{Type: layers.DNSTypeA, Name: []byte("example.com")},
},
},
expected: "1234 A? example.com (0)",
},
{
name: "Error response code",
layer: &layers.DNS{
ID: 5678,
ResponseCode: layers.DNSResponseCodeNXDomain,
},
expected: "5678 Non-Existent Domain (0)",
},
{
name: "answer",
layer: &layers.DNS{
ID: 9101,
ResponseCode: layers.DNSResponseCodeNoErr,
AA: true,
Answers: []layers.DNSResourceRecord{
{Name: []byte("example.com"), Type: layers.DNSTypeA, Class: layers.DNSClassAny, IP: []byte{192, 0, 2, 1}},
},
},
expected: "9101*<Any, A> (0)",
},
{
name: " 2 answers",
layer: &layers.DNS{
ID: 9101,
ResponseCode: layers.DNSResponseCodeNoErr,
AA: true,
Answers: []layers.DNSResourceRecord{
{Name: []byte("example.com"), Type: layers.DNSTypeA, Class: layers.DNSClassAny, IP: []byte{192, 0, 2, 1}},
{Name: []byte("example.io"), Type: layers.DNSTypeA, Class: layers.DNSClassAny, IP: []byte{192, 0, 2, 2}},
},
},
expected: "9101* 2/0/0 <Any, A>, <Any, A> (0)",
},
{
name: "Recursive desired",
layer: &layers.DNS{
ID: 1213,
ResponseCode: layers.DNSResponseCodeNoErr,
RD: true,
Answers: []layers.DNSResourceRecord{
{Name: []byte("example.com"), Type: layers.DNSTypeA, Class: layers.DNSClassAny, IP: []byte{192, 0, 2, 1}},
},
},
expected: "1213+<Any, A> (0)",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := dnsData(tt.layer)
if result != tt.expected {
t.Errorf("dnsData() = %v, want %v", result, tt.expected)
}
})
}
}
5 changes: 3 additions & 2 deletions cmds/exp/tcpdump/ethernet.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
)

func (cmd cmd) ethernetInfo(ethernetLayer gopacket.LinkLayer, networkLayer gopacket.NetworkLayer) string {
if !cmd.Opts.ether {
return fmt.Sprintf("%s %s", networkLayer.NetworkFlow().EndpointType(), cmd.Opts.device)
if !cmd.Opts.Ether {
return fmt.Sprintf("%s %s", networkLayer.NetworkFlow().EndpointType(), cmd.Opts.Device)
}

src, dst := ethernetLayer.LinkFlow().Endpoints()
Expand All @@ -20,6 +20,7 @@ func (cmd cmd) ethernetInfo(ethernetLayer gopacket.LinkLayer, networkLayer gopac
if dstHost == "ff:ff:ff:ff:ff:ff" {
dstHost = "Broadcast"
}

length := len(ethernetLayer.LayerContents()) + len(ethernetLayer.LayerPayload())

return fmt.Sprintf("%s > %s, ethertype %s, length %d:", src, dstHost, networkLayer.NetworkFlow().EndpointType(), length)
Expand Down
100 changes: 100 additions & 0 deletions cmds/exp/tcpdump/ethernet_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2024 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"testing"

"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
)

func TestEthernetInfo(t *testing.T) {
tests := []struct {
name string
cmd cmd
ethernetLayer gopacket.LinkLayer
networkLayer gopacket.NetworkLayer
expectedOutput string
}{
{
name: "Ether option disabled",
cmd: cmd{
Opts: flags{
Ether: false,
Device: "eth0",
},
},
ethernetLayer: &layers.Ethernet{
SrcMAC: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
DstMAC: []byte{0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB},
EthernetType: layers.EthernetTypeIPv4,
},
networkLayer: &layers.IPv4{
SrcIP: []byte{192, 168, 0, 1},
DstIP: []byte{192, 168, 0, 2},
Protocol: layers.IPProtocolTCP,
},
expectedOutput: "IPv4 eth0",
},
{
name: "Ether option enabled with broadcast",
cmd: cmd{
Opts: flags{
Ether: true,
Device: "eth0",
},
},
ethernetLayer: &layers.Ethernet{
SrcMAC: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
DstMAC: []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
EthernetType: layers.EthernetTypeIPv4,
Length: 14,
BaseLayer: layers.BaseLayer{
Contents: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x08, 0x00},
},
},
networkLayer: &layers.IPv4{
SrcIP: []byte{192, 168, 0, 1},
DstIP: []byte{192, 168, 0, 2},
Protocol: layers.IPProtocolTCP,
},
expectedOutput: "00:11:22:33:44:55 > Broadcast, ethertype IPv4, length 14:",
},
{
name: "Ether option enabled with unicast",
cmd: cmd{
Opts: flags{
Ether: true,
Device: "eth0",
},
},
ethernetLayer: &layers.Ethernet{
SrcMAC: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55},
DstMAC: []byte{0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB},
EthernetType: layers.EthernetTypeIPv4,
Length: 14,
BaseLayer: layers.BaseLayer{
Contents: []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0x08, 0x00},
},
},
networkLayer: &layers.IPv4{
SrcIP: []byte{192, 168, 0, 1},
DstIP: []byte{192, 168, 0, 2},
Protocol: layers.IPProtocolTCP,
},
expectedOutput: "00:11:22:33:44:55 > 66:77:88:99:aa:bb, ethertype IPv4, length 14:",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.cmd.ethernetInfo(tt.ethernetLayer, tt.networkLayer)
if result != tt.expectedOutput {
t.Errorf("ethernetInfo() = %v, want %v", result, tt.expectedOutput)
}
})
}
}
1 change: 1 addition & 0 deletions cmds/exp/tcpdump/filter.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tcp
64 changes: 64 additions & 0 deletions cmds/exp/tcpdump/icmp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2024 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"testing"

"github.com/gopacket/gopacket"
"github.com/gopacket/gopacket/layers"
)

func TestParseICMP(t *testing.T) {
tests := []struct {
name string
packet gopacket.Packet
expectedOutput string
}{
{
name: "ICMPv4 Echo Request",
packet: gopacket.NewPacket(
[]byte{
0x08, 0x00, 0x4d, 0x3d, 0x00, 0x46, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64,
},
layers.LayerTypeICMPv4,
gopacket.Default,
),
expectedOutput: "ICMP EchoRequest, id 70, seq 1, length 12",
},
{
name: "ICMPv6 Echo Request",
packet: gopacket.NewPacket(
[]byte{
0x80, 0x00, 0x4d, 0x3d, 0x1c, 0x46, 0x00, 0x01, 0x61, 0x62, 0x63, 0x64,
},
layers.LayerTypeICMPv6,
gopacket.Default,
),
expectedOutput: "ICMP6 EchoRequest, length 12",
},
{
name: "Non-ICMP Packet",
packet: gopacket.NewPacket(
[]byte{
0x45, 0x00, 0x00, 0x3c, 0x1c, 0x46, 0x40, 0x00, 0x40, 0x06, 0xb1, 0xe6, 0xc0, 0xa8, 0x00, 0x68,
0xc0, 0xa8, 0x00, 0x01,
},
layers.LayerTypeIPv4,
gopacket.Default,
),
expectedOutput: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := parseICMP(tt.packet)
if result != tt.expectedOutput {
t.Errorf("parseICMP() = %v, want %v", result, tt.expectedOutput)
}
})
}
}
Loading

0 comments on commit b7dc420

Please sign in to comment.