101 lines
2.9 KiB
Go
101 lines
2.9 KiB
Go
package reachable
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Defends novox/hq ADR 0100: converging previews every listening socket and every published
|
|
// container port. Fixtures are captured from a real machine.
|
|
|
|
func fixture(t *testing.T, name string) string {
|
|
t.Helper()
|
|
raw, err := os.ReadFile("testdata/" + name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return string(raw)
|
|
}
|
|
|
|
func find(rs []Reach, protocol, address string, port int) (Reach, bool) {
|
|
for _, r := range rs {
|
|
if r.Protocol == protocol && r.Address == address && r.Port == port {
|
|
return r, true
|
|
}
|
|
}
|
|
return Reach{}, false
|
|
}
|
|
|
|
func TestSocketsAreReadWithWhatHoldsThem(t *testing.T) {
|
|
got := Sockets(fixture(t, "ss.txt"))
|
|
if r, ok := find(got, "tcp", "0.0.0.0", 22); !ok || r.By != "sshd" {
|
|
t.Errorf("ssh not read: %+v", r)
|
|
}
|
|
if r, ok := find(got, "tcp", "::", 445); !ok || r.By != "smbd" {
|
|
t.Errorf("an IPv6 wildcard listener not read: %+v", r)
|
|
}
|
|
if _, ok := find(got, "udp", "fe80::849e:ccff:fea8:24c7", 123); !ok {
|
|
t.Error("a link-local address with a scope was not read")
|
|
}
|
|
if r, ok := find(got, "udp", "127.0.0.1", 53); !ok || r.By != "dnsmasq" {
|
|
t.Errorf("a loopback udp socket not read: %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestPublishedPortsNameTheirContainerAndItsPort(t *testing.T) {
|
|
got := Published(fixture(t, "docker-ps.txt"))
|
|
if r, ok := find(got, "tcp", "0.0.0.0", 8770); !ok || r.By != "whisper" || r.ContainerPort != 8000 || !r.Published {
|
|
t.Errorf("a published port: %+v", r)
|
|
}
|
|
if r, ok := find(got, "tcp", "0.0.0.0", 9001); !ok || r.ContainerPort != 9001 {
|
|
t.Errorf("a published range was not expanded: %+v", r)
|
|
}
|
|
if r, ok := find(got, "tcp", "127.0.0.1", 15673); !ok || r.ContainerPort != 15672 {
|
|
t.Errorf("a loopback-published port: %+v", r)
|
|
}
|
|
for _, r := range got {
|
|
if r.By == "umami_db" {
|
|
t.Errorf("an exposed and unpublished port was reported reachable: %+v", r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAPublishedPortIsReportedOnceAsPublished(t *testing.T) {
|
|
merged := Merge(Sockets(fixture(t, "ss.txt")), Published(fixture(t, "docker-ps.txt")))
|
|
n := 0
|
|
for _, r := range merged {
|
|
if r.Protocol == "tcp" && r.Address == "0.0.0.0" && r.Port == 8770 {
|
|
n++
|
|
if !r.Published {
|
|
t.Errorf("the runtime's proxy was reported instead of the published port: %+v", r)
|
|
}
|
|
}
|
|
}
|
|
if n != 1 {
|
|
t.Errorf("port 8770 reported %d times", n)
|
|
}
|
|
if _, ok := find(merged, "tcp", "0.0.0.0", 22); !ok {
|
|
t.Error("a socket was lost in the merge")
|
|
}
|
|
}
|
|
|
|
func TestCollectAsksSsAndTheRuntime(t *testing.T) {
|
|
var asked []string
|
|
run := func(_ context.Context, name string, args ...string) (string, error) {
|
|
asked = append(asked, name+" "+strings.Join(args, " "))
|
|
if name == "ss" {
|
|
return fixture(t, "ss.txt"), nil
|
|
}
|
|
return fixture(t, "docker-ps.txt"), nil
|
|
}
|
|
got, err := Collect(context.Background(), run)
|
|
if err != nil || len(got) == 0 {
|
|
t.Fatalf("%v %v", got, err)
|
|
}
|
|
if len(asked) != 2 {
|
|
t.Errorf("asked %v", asked)
|
|
}
|
|
}
|