218 lines
6.4 KiB
Go
218 lines
6.4 KiB
Go
package webdevice
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestIsPrivateIPv4Literal(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cases := map[string]bool{
|
|
"192.168.1.10": true,
|
|
"10.0.0.8": true,
|
|
"172.16.5.2": true,
|
|
"127.0.0.1": false,
|
|
"8.8.8.8": false,
|
|
"0.0.0.0": false,
|
|
"::1": false,
|
|
"bad-ip": false,
|
|
}
|
|
|
|
for input, want := range cases {
|
|
if got := IsPrivateIPv4Literal(input); got != want {
|
|
t.Fatalf("IsPrivateIPv4Literal(%q) = %v, want %v", input, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWebDeviceForwardPort(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
port, ok := WebDeviceForwardPort("192.168.1.124")
|
|
if !ok {
|
|
t.Fatal("WebDeviceForwardPort() ok = false")
|
|
}
|
|
if port != 31124 {
|
|
t.Fatalf("port = %d, want 31124", port)
|
|
}
|
|
}
|
|
|
|
func TestScanBuildsProxyURLAndAllowList(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService()
|
|
svc.interfaceGetter = func() ([]InterfaceInfo, error) {
|
|
return []InterfaceInfo{{
|
|
Name: "eth0",
|
|
IP: "10.8.0.14",
|
|
Netmask: "255.255.255.0",
|
|
}}, nil
|
|
}
|
|
svc.tcpScanner = func(ip, netmask string, port int, excludeIPs map[string]bool) ([]TCPDevice, error) {
|
|
return []TCPDevice{{IP: "192.168.1.124", Port: 80}}, nil
|
|
}
|
|
svc.newForwarder = func(ip string, port int, listenAddress, targetAddress string) (*webDeviceForwarder, error) {
|
|
return &webDeviceForwarder{ip: ip, port: port, targetAddress: targetAddress}, nil
|
|
}
|
|
|
|
req := httptest.NewRequest("GET", "http://10.8.0.14:13000/api/web-devices/scan", nil)
|
|
result, err := svc.Scan(req)
|
|
if err != nil {
|
|
t.Fatalf("Scan() error = %v", err)
|
|
}
|
|
if result.Count != 1 {
|
|
t.Fatalf("result.Count = %d", result.Count)
|
|
}
|
|
if !svc.IsAllowed("192.168.1.124") {
|
|
t.Fatal("expected IP to be allowed after scan")
|
|
}
|
|
if result.Devices[0].ProxyURL != "/proxy/web/192.168.1.124/" {
|
|
t.Fatalf("ProxyURL = %q", result.Devices[0].ProxyURL)
|
|
}
|
|
if result.Devices[0].DirectURL != "" {
|
|
t.Fatalf("DirectURL = %q, want empty", result.Devices[0].DirectURL)
|
|
}
|
|
}
|
|
|
|
func TestScanIncludesPrivateRequestHostSubnet(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService()
|
|
svc.hostLANGetter = nil
|
|
svc.interfaceGetter = func() ([]InterfaceInfo, error) {
|
|
return []InterfaceInfo{{
|
|
Name: "eth0",
|
|
IP: "172.18.0.2",
|
|
Netmask: "255.255.0.0",
|
|
}}, nil
|
|
}
|
|
svc.tcpScanner = func(ip, netmask string, port int, excludeIPs map[string]bool) ([]TCPDevice, error) {
|
|
if ip == "192.168.5.189" {
|
|
if netmask != "255.255.255.0" {
|
|
t.Fatalf("request host netmask = %q, want 255.255.255.0", netmask)
|
|
}
|
|
if !excludeIPs["192.168.5.189"] {
|
|
t.Fatal("expected request host IP to be excluded")
|
|
}
|
|
return []TCPDevice{{IP: "192.168.5.124", Port: 80}}, nil
|
|
}
|
|
return nil, nil
|
|
}
|
|
svc.newForwarder = func(ip string, port int, listenAddress, targetAddress string) (*webDeviceForwarder, error) {
|
|
return &webDeviceForwarder{ip: ip, port: port, targetAddress: targetAddress}, nil
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "http://192.168.5.189:13000/api/web-devices/scan", nil)
|
|
result, err := svc.Scan(req)
|
|
if err != nil {
|
|
t.Fatalf("Scan() error = %v", err)
|
|
}
|
|
if result.Count != 1 {
|
|
t.Fatalf("result.Count = %d, want 1", result.Count)
|
|
}
|
|
if result.Devices[0].Interface != "request-host" {
|
|
t.Fatalf("Interface = %q, want request-host", result.Devices[0].Interface)
|
|
}
|
|
}
|
|
|
|
func TestScanPrefersHostLANInterfaces(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
svc := NewService()
|
|
svc.interfaceGetter = func() ([]InterfaceInfo, error) {
|
|
return []InterfaceInfo{{
|
|
Name: "eth0",
|
|
IP: "172.20.0.4",
|
|
Netmask: "255.255.0.0",
|
|
}}, nil
|
|
}
|
|
svc.hostLANGetter = func() ([]InterfaceInfo, error) {
|
|
return []InterfaceInfo{{
|
|
Name: "eno1",
|
|
IP: "192.168.0.117",
|
|
Netmask: "255.255.255.0",
|
|
}}, nil
|
|
}
|
|
svc.tcpScanner = func(ip, netmask string, port int, excludeIPs map[string]bool) ([]TCPDevice, error) {
|
|
if ip != "192.168.0.117" {
|
|
t.Fatalf("scan ip = %q, want host LAN ip", ip)
|
|
}
|
|
if netmask != "255.255.255.0" {
|
|
t.Fatalf("netmask = %q, want 255.255.255.0", netmask)
|
|
}
|
|
if !excludeIPs["172.20.0.4"] || !excludeIPs["192.168.0.117"] {
|
|
t.Fatalf("excludeIPs = %#v, want container and host IPs", excludeIPs)
|
|
}
|
|
return []TCPDevice{{IP: "192.168.0.108", Port: 80}}, nil
|
|
}
|
|
svc.newForwarder = func(ip string, port int, listenAddress, targetAddress string) (*webDeviceForwarder, error) {
|
|
return &webDeviceForwarder{ip: ip, port: port, targetAddress: targetAddress}, nil
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "http://10.8.0.18:13000/api/web-devices/scan", nil)
|
|
result, err := svc.Scan(req)
|
|
if err != nil {
|
|
t.Fatalf("Scan() error = %v", err)
|
|
}
|
|
if result.Count != 1 {
|
|
t.Fatalf("result.Count = %d, want 1", result.Count)
|
|
}
|
|
if result.Devices[0].Interface != "eno1" {
|
|
t.Fatalf("Interface = %q, want eno1", result.Devices[0].Interface)
|
|
}
|
|
}
|
|
|
|
func TestParseHostLANInterfacesFiltersVirtualInterfaces(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
output := `2: eno1 inet 192.168.0.117/24 brd 192.168.0.255 scope global eno1
|
|
3: docker0 inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
|
|
4: tun0 inet 10.8.0.18/24 scope global tun0
|
|
5: wlan0 inet 192.168.5.10/23 brd 192.168.5.255 scope global wlan0
|
|
`
|
|
|
|
interfaces := parseHostLANInterfaces(output)
|
|
|
|
if len(interfaces) != 2 {
|
|
t.Fatalf("len(interfaces) = %d, want 2: %#v", len(interfaces), interfaces)
|
|
}
|
|
if interfaces[0].Name != "eno1" || interfaces[0].IP != "192.168.0.117" || interfaces[0].Netmask != "255.255.255.0" {
|
|
t.Fatalf("interfaces[0] = %#v", interfaces[0])
|
|
}
|
|
if interfaces[1].Name != "wlan0" || interfaces[1].IP != "192.168.5.10" || interfaces[1].Netmask != "255.255.254.0" {
|
|
t.Fatalf("interfaces[1] = %#v", interfaces[1])
|
|
}
|
|
}
|
|
|
|
func TestCalculateIPRangeCapsLargeSubnetToLocal24(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ipRange, err := calculateIPRange("192.168.5.189", "255.255.0.0")
|
|
if err != nil {
|
|
t.Fatalf("calculateIPRange() error = %v", err)
|
|
}
|
|
if got := ipRange.Start.String(); got != "192.168.5.0" {
|
|
t.Fatalf("Start = %q, want 192.168.5.0", got)
|
|
}
|
|
if got := ipRange.End.String(); got != "192.168.5.255" {
|
|
t.Fatalf("End = %q, want 192.168.5.255", got)
|
|
}
|
|
}
|
|
|
|
func TestCalculateIPRangeKeepsSmallSubnet(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
ipRange, err := calculateIPRange("192.168.5.189", "255.255.255.240")
|
|
if err != nil {
|
|
t.Fatalf("calculateIPRange() error = %v", err)
|
|
}
|
|
if got := ipRange.Start.String(); got != "192.168.5.176" {
|
|
t.Fatalf("Start = %q, want 192.168.5.176", got)
|
|
}
|
|
if got := ipRange.End.String(); got != "192.168.5.191" {
|
|
t.Fatalf("End = %q, want 192.168.5.191", got)
|
|
}
|
|
}
|