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 TestScanBuildsDirectURLAndAllowList(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].DirectURL != "http://10.8.0.14:31124/" { t.Fatalf("DirectURL = %q", result.Devices[0].DirectURL) } } func TestScanIncludesPrivateRequestHostSubnet(t *testing.T) { t.Parallel() svc := NewService() 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 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) } }