package app import ( "context" "fmt" "net" "os" "path/filepath" "strings" "testing" "time" ) func TestSelectTransportBackendDefaultMock(t *testing.T) { b := selectTransportBackend(TransportClient{ Kind: TransportClientSingBox, Config: nil, }) if b.ID() != "mock" { t.Fatalf("expected mock backend, got %q", b.ID()) } } func TestSelectTransportBackendUnitInfersSystemd(t *testing.T) { b := selectTransportBackend(TransportClient{ Kind: TransportClientPhoenix, Config: map[string]any{ "unit": "phoenix.service", }, }) if b.ID() != "systemd" { t.Fatalf("expected systemd backend, got %q", b.ID()) } } func TestSelectTransportBackendRuntimeModeEmbeddedUnsupported(t *testing.T) { b := selectTransportBackend(TransportClient{ Kind: TransportClientSingBox, Config: map[string]any{ "runtime_mode": "embedded", "runner": "systemd", }, }) if b.ID() != "unsupported" { t.Fatalf("expected unsupported backend for embedded runtime_mode, got %q", b.ID()) } } func TestSelectTransportBackendRuntimeModeSidecarUnsupported(t *testing.T) { b := selectTransportBackend(TransportClient{ Kind: TransportClientPhoenix, Config: map[string]any{ "runtime_mode": "sidecar", "runner": "systemd", }, }) if b.ID() != "unsupported" { t.Fatalf("expected unsupported backend for sidecar runtime_mode, got %q", b.ID()) } } func TestTransportUnsupportedRuntimeBackendReturnsUnifiedError(t *testing.T) { client := TransportClient{ ID: "ph-1", Kind: TransportClientPhoenix, Config: map[string]any{ "runtime_mode": "sidecar", }, } backend := selectTransportBackend(client) act := backend.Action(client, "start") if act.OK { t.Fatalf("expected unsupported runtime action to fail") } if act.Code != "TRANSPORT_BACKEND_RUNTIME_MODE_UNSUPPORTED" { t.Fatalf("unexpected action code: %#v", act) } prov := backend.Provision(client) if prov.OK { t.Fatalf("expected unsupported runtime provision to fail") } if prov.Code != "TRANSPORT_BACKEND_RUNTIME_MODE_UNSUPPORTED" { t.Fatalf("unexpected provision code: %#v", prov) } health := backend.Health(client) if health.OK { t.Fatalf("expected unsupported runtime health to fail") } if health.Code != "TRANSPORT_BACKEND_RUNTIME_MODE_UNSUPPORTED" { t.Fatalf("unexpected health code: %#v", health) } if health.Status != TransportClientDegraded { t.Fatalf("expected degraded status for unsupported runtime_mode, got %#v", health) } } func TestTransportSystemdActionUnitsDNSTTSSHTunnel(t *testing.T) { client := TransportClient{ Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dnstt-client.service", "ssh_tunnel": true, "ssh_unit": "dnstt-ssh.service", }, } unitsStart, code, msg := transportSystemdActionUnits(client, "start") if code != "" || msg != "" { t.Fatalf("unexpected action-unit error: code=%q msg=%q", code, msg) } if strings.Join(unitsStart, ",") != "dnstt-ssh.service,dnstt-client.service" { t.Fatalf("unexpected start units order: %#v", unitsStart) } unitsStop, code, msg := transportSystemdActionUnits(client, "stop") if code != "" || msg != "" { t.Fatalf("unexpected action-unit error: code=%q msg=%q", code, msg) } if strings.Join(unitsStop, ",") != "dnstt-client.service,dnstt-ssh.service" { t.Fatalf("unexpected stop units order: %#v", unitsStop) } } func TestTransportSystemdBackendActionAndHealth(t *testing.T) { orig := transportRunCommand defer func() { transportRunCommand = orig }() calls := make([]string, 0, 8) transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") calls = append(calls, cmd) if cmd == "systemctl reset-failed dnstt-client.service" { return "", "", 0, nil } if cmd == "systemctl reset-failed dnstt-ssh.service" { return "", "", 0, nil } if cmd == "systemctl start dnstt-client.service" { return "", "", 0, nil } if cmd == "systemctl start dnstt-ssh.service" { return "", "", 0, nil } if cmd == "systemctl is-active dnstt-client.service" { return "active\n", "", 0, nil } if cmd == "systemctl is-active dnstt-ssh.service" { return "active\n", "", 0, nil } return "", "unexpected command", 1, fmt.Errorf("unexpected command: %s", cmd) } client := TransportClient{ Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dnstt-client.service", "ssh_tunnel": true, "ssh_unit": "dnstt-ssh.service", }, } backend := selectTransportBackend(client) res := backend.Action(client, "start") if !res.OK { t.Fatalf("expected action success, got %#v", res) } if len(calls) < 4 { t.Fatalf("expected start calls, got %#v", calls) } if calls[0] != "systemctl reset-failed dnstt-ssh.service" || calls[1] != "systemctl reset-failed dnstt-client.service" || calls[2] != "systemctl start dnstt-ssh.service" || calls[3] != "systemctl start dnstt-client.service" { t.Fatalf("unexpected call order: %#v", calls) } health := backend.Health(client) if !health.OK || health.Status != TransportClientUp { t.Fatalf("expected healthy up, got %#v", health) } } func TestTransportSystemdBackendStopMissingUnitIsNoop(t *testing.T) { orig := transportRunCommand defer func() { transportRunCommand = orig }() calls := make([]string, 0, 4) transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") calls = append(calls, cmd) if cmd == "systemctl stop singbox@sg-missing.service" { return "", "Failed to stop singbox@sg-missing.service: Unit singbox@sg-missing.service not loaded.", 5, fmt.Errorf("exit status 5") } return "", "unexpected command", 1, fmt.Errorf("unexpected command: %s", cmd) } client := TransportClient{ ID: "sg-missing", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", }, } backend := selectTransportBackend(client) res := backend.Action(client, "stop") if !res.OK { t.Fatalf("expected stop noop success, got %#v", res) } if len(calls) != 1 || calls[0] != "systemctl stop singbox@sg-missing.service" { t.Fatalf("unexpected calls: %#v", calls) } if !strings.Contains(strings.ToLower(res.Message), "systemctl stop ok") { t.Fatalf("unexpected success message: %#v", res) } } func TestTransportSystemdBackendStartAutoProvisionOnMissingUnit(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir startCalls := 0 transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") switch cmd { case "systemctl reset-failed singbox@sg-auto.service": return "", "", 0, nil case "systemctl daemon-reload": return "", "", 0, nil case "systemctl start singbox@sg-auto.service": startCalls++ if startCalls == 1 { return "", "Failed to start singbox@sg-auto.service: Unit singbox@sg-auto.service not found.", 5, fmt.Errorf("exit status 5") } return "", "", 0, nil default: return "", "", 0, nil } } client := TransportClient{ ID: "sg-auto", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", "exec_start": "/usr/bin/sing-box run -c /tmp/sg-auto.json", }, } backend := selectTransportBackend(client) res := backend.Action(client, "start") if !res.OK { t.Fatalf("expected start success after auto-provision, got %#v", res) } if startCalls != 2 { t.Fatalf("expected start retried after auto-provision, got calls=%d", startCalls) } if _, err := os.Stat(filepath.Join(tmpDir, "singbox@.service")); err != nil { t.Fatalf("expected provisioned template unit file, stat error: %v", err) } if _, err := os.Stat(filepath.Join(tmpDir, "singbox@sg-auto.service.d", transportSingBoxInstanceDropIn)); err != nil { t.Fatalf("expected provisioned template drop-in file, stat error: %v", err) } } func TestTransportSystemdBackendHealthOverlayMismatch(t *testing.T) { orig := transportRunCommand defer func() { transportRunCommand = orig }() transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") switch cmd { case "systemctl is-active dnstt-client.service": return "active\n", "", 0, nil case "systemctl is-active dnstt-ssh.service": return "inactive\n", "", 0, nil default: return "", "", 0, nil } } client := TransportClient{ Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dnstt-client.service", "ssh_overlay": true, "ssh_unit": "dnstt-ssh.service", }, } backend := selectTransportBackend(client) health := backend.Health(client) if health.OK { t.Fatalf("expected unhealthy overlay mismatch, got %#v", health) } if health.Code != "TRANSPORT_BACKEND_HEALTH_FAILED" { t.Fatalf("unexpected health code: %#v", health) } if health.Status != TransportClientDegraded { t.Fatalf("unexpected health status: %#v", health) } } func TestTransportCollectSingBoxConfigProbeEndpoints(t *testing.T) { tmpDir := t.TempDir() cfgPath := filepath.Join(tmpDir, "singbox.json") cfg := `{ "outbounds": [ { "type": "vless", "server": "n3.elmprod.tech", "server_port": 40903 }, { "type": "wireguard", "server": "198.51.100.5", "server_port": "51820" } ] }` if err := os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil { t.Fatalf("write config: %v", err) } client := TransportClient{ ID: "sg-probe", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", "config_path": cfgPath, }, } endpoints := transportCollectSingBoxConfigProbeEndpoints(client) got := make([]string, 0, len(endpoints)) for _, ep := range endpoints { got = append(got, ep.address()) } want := []string{"n3.elmprod.tech:40903", "198.51.100.5:51820"} for _, w := range want { found := false for _, g := range got { if g == w { found = true break } } if !found { t.Fatalf("missing endpoint %q in %#v", w, got) } } } func TestTransportSystemdBackendHealthIncludesLatencyProbe(t *testing.T) { origRun := transportRunCommand origDial := transportDialContext defer func() { transportRunCommand = origRun transportDialContext = origDial }() tmpDir := t.TempDir() cfgPath := filepath.Join(tmpDir, "singbox.json") cfg := `{ "outbounds": [ { "type": "vless", "server": "n3.elmprod.tech", "server_port": 40903 } ] }` if err := os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil { t.Fatalf("write config: %v", err) } transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") if cmd == "systemctl is-active singbox@sg-probe.service" { return "active\n", "", 0, nil } return "", "unexpected command", 1, fmt.Errorf("unexpected command: %s", cmd) } calledAddr := "" transportDialContext = func(_ context.Context, network, address string) (net.Conn, error) { if network != "tcp4" { return nil, fmt.Errorf("unexpected network: %s", network) } calledAddr = address c1, c2 := net.Pipe() _ = c2.Close() return c1, nil } client := TransportClient{ ID: "sg-probe", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", "config_path": cfgPath, }, } backend := selectTransportBackend(client) health := backend.Health(client) if !health.OK || health.Status != TransportClientUp { t.Fatalf("expected healthy up, got %#v", health) } if health.LatencyMS <= 0 { t.Fatalf("expected latency sample, got %#v", health) } if calledAddr != "n3.elmprod.tech:40903" { t.Fatalf("unexpected dial addr: %q", calledAddr) } } func TestTransportSystemdBackendHealthProbeFailureKeepsUpStatus(t *testing.T) { origRun := transportRunCommand origDial := transportDialContext defer func() { transportRunCommand = origRun transportDialContext = origDial }() tmpDir := t.TempDir() cfgPath := filepath.Join(tmpDir, "singbox.json") cfg := `{ "outbounds": [ { "type": "vless", "server": "n3.elmprod.tech", "server_port": 40903 } ] }` if err := os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil { t.Fatalf("write config: %v", err) } transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") if cmd == "systemctl is-active singbox@sg-probe.service" { return "active\n", "", 0, nil } return "", "unexpected command", 1, fmt.Errorf("unexpected command: %s", cmd) } transportDialContext = func(_ context.Context, _ string, _ string) (net.Conn, error) { return nil, fmt.Errorf("dial timeout") } client := TransportClient{ ID: "sg-probe", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", "config_path": cfgPath, }, } backend := selectTransportBackend(client) health := backend.Health(client) if !health.OK || health.Status != TransportClientUp { t.Fatalf("probe failure must not degrade systemd up status, got %#v", health) } if health.LatencyMS != 0 { t.Fatalf("latency must be empty when probe fails, got %#v", health) } } func TestTransportSystemdBackendHealthNetnsProbePreferred(t *testing.T) { origRun := transportRunCommand origDial := transportDialContext defer func() { transportRunCommand = origRun transportDialContext = origDial }() tmpDir := t.TempDir() cfgPath := filepath.Join(tmpDir, "singbox.json") cfg := `{ "outbounds": [ { "type": "vless", "server": "n3.elmprod.tech", "server_port": 40903 } ] }` if err := os.WriteFile(cfgPath, []byte(cfg), 0o644); err != nil { t.Fatalf("write config: %v", err) } netnsProbeCalled := false transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") switch cmd { case "systemctl is-active singbox@sg-probe.service": return "active\n", "", 0, nil } if strings.HasPrefix(cmd, "ip netns exec svpn-sg bash -lc ") { netnsProbeCalled = true return "", "", 0, nil } return "", "unexpected command", 1, fmt.Errorf("unexpected command: %s", cmd) } hostDialCalled := false transportDialContext = func(_ context.Context, _ string, _ string) (net.Conn, error) { hostDialCalled = true return nil, fmt.Errorf("must not use host dial when netns probe succeeds") } client := TransportClient{ ID: "sg-probe", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", "config_path": cfgPath, "netns_enabled": true, "netns_name": "svpn-sg", "netns_exec_mode": "ip", "netns_ip_bin": "ip", }, } backend := selectTransportBackend(client) health := backend.Health(client) if !health.OK || health.Status != TransportClientUp { t.Fatalf("expected healthy up, got %#v", health) } if health.LatencyMS <= 0 { t.Fatalf("expected latency sample from netns probe, got %#v", health) } if !netnsProbeCalled { t.Fatalf("expected netns probe command to be called") } if hostDialCalled { t.Fatalf("host dial must not be called when netns probe succeeds") } } func TestTransportSystemdBackendProvisionWritesUnits(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir calls := make([]string, 0, 8) transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") calls = append(calls, cmd) switch cmd { case "systemctl daemon-reload", "systemctl enable dnstt-ssh.service", "systemctl enable dnstt-client.service": return "", "", 0, nil default: return "", "", 0, nil } } client := TransportClient{ ID: "dnstt-home", Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dnstt-client.service", "doh_url": "https://dns.google/dns-query", "pubkey": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "domain": "tunnel.example.com", "local_addr": "127.0.0.1:7001", "ssh_tunnel": true, "ssh_unit": "dnstt-ssh.service", "ssh_exec_start": "/usr/bin/ssh -N -D 127.0.0.1:1080 root@example.com", "enable_on_boot": true, }, } backend := selectTransportBackend(client) res := backend.Provision(client) if !res.OK { t.Fatalf("expected provision success, got %#v", res) } if !strings.Contains(res.Message, "template:dnstt") { t.Fatalf("expected template source in provision message, got %#v", res) } primaryPath := filepath.Join(tmpDir, "dnstt-client.service") sshPath := filepath.Join(tmpDir, "dnstt-ssh.service") primaryData, err := os.ReadFile(primaryPath) if err != nil { t.Fatalf("failed to read primary unit: %v", err) } sshData, err := os.ReadFile(sshPath) if err != nil { t.Fatalf("failed to read ssh unit: %v", err) } primaryText := string(primaryData) if !strings.Contains(primaryText, "Requires=dnstt-ssh.service") { t.Fatalf("primary unit missing ssh require: %s", primaryText) } if !strings.Contains(primaryText, "dnstt-client") { t.Fatalf("primary unit missing dnstt command: %s", primaryText) } if !strings.Contains(primaryText, "ExecStart=/bin/sh -lc ") { t.Fatalf("primary unit missing shell exec start: %s", primaryText) } if !strings.Contains(string(sshData), "ExecStart=/bin/sh -lc ") { t.Fatalf("ssh unit missing shell exec start") } if len(calls) == 0 || calls[0] != "systemctl daemon-reload" { t.Fatalf("expected daemon-reload call first, got %#v", calls) } } func TestTransportSystemdBackendProvisionRequiresDNSTTTemplateFields(t *testing.T) { backend := transportSystemdBackend{} client := TransportClient{ ID: "dnstt-home", Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dnstt-client.service", }, } res := backend.Provision(client) if res.OK { t.Fatalf("expected provision failure without required dnstt template fields") } if res.Code != "TRANSPORT_BACKEND_PROVISION_CONFIG_REQUIRED" { t.Fatalf("unexpected code: %#v", res) } if !strings.Contains(strings.ToLower(res.Message), "dnstt template requires") { t.Fatalf("unexpected message: %#v", res) } } func TestTransportSystemdBackendCleanupRemovesOwnedUnits(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir unit := "sg-clean.service" unitPath := filepath.Join(tmpDir, unit) unitBody := "[Service]\nEnvironment=SVPN_TRANSPORT_ID=sg-clean\nExecStart=/usr/bin/sleep 60\n" if err := os.WriteFile(unitPath, []byte(unitBody), 0o644); err != nil { t.Fatalf("write unit file: %v", err) } calls := make([]string, 0, 8) transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") calls = append(calls, cmd) return "", "", 0, nil } client := TransportClient{ ID: "sg-clean", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": unit, }, } backend := selectTransportBackend(client) res := backend.Cleanup(client) if !res.OK { t.Fatalf("expected cleanup success, got %#v", res) } if _, err := os.Stat(unitPath); !os.IsNotExist(err) { t.Fatalf("unit file was not removed: %v", err) } got := strings.Join(calls, " | ") wantParts := []string{ "systemctl stop " + unit, "systemctl disable " + unit, "systemctl daemon-reload", "systemctl reset-failed " + unit, } for _, part := range wantParts { if !strings.Contains(got, part) { t.Fatalf("expected cleanup calls to contain %q, got: %s", part, got) } } } func TestTransportSystemdBackendCleanupSkipsForeignUnits(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir unit := "sg-foreign.service" unitPath := filepath.Join(tmpDir, unit) unitBody := "[Service]\nEnvironment=SVPN_TRANSPORT_ID=someone-else\nExecStart=/usr/bin/sleep 60\n" if err := os.WriteFile(unitPath, []byte(unitBody), 0o644); err != nil { t.Fatalf("write unit file: %v", err) } calls := make([]string, 0, 4) transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) { cmd := name + " " + strings.Join(args, " ") calls = append(calls, cmd) return "", "", 0, nil } client := TransportClient{ ID: "sg-clean", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": unit, }, } backend := selectTransportBackend(client) res := backend.Cleanup(client) if !res.OK { t.Fatalf("expected cleanup success for foreign unit skip, got %#v", res) } if !strings.Contains(strings.ToLower(res.Message), "no managed unit artifacts") { t.Fatalf("unexpected cleanup message: %#v", res) } if _, err := os.Stat(unitPath); err != nil { t.Fatalf("foreign unit should stay intact, stat error: %v", err) } if len(calls) != 0 { t.Fatalf("expected no systemctl calls for foreign unit, got %#v", calls) } } func TestResolveTransportPrimaryExecStartManualOverride(t *testing.T) { client := TransportClient{ Kind: TransportClientSingBox, Config: map[string]any{ "exec_start": " /custom/bin/sing-box run -c /tmp/custom.json ", }, } cmd, source, err := resolveTransportPrimaryExecStart(client) if err != nil { t.Fatalf("unexpected error: %v", err) } if source != "manual" { t.Fatalf("expected manual source, got %q", source) } if cmd != "/custom/bin/sing-box run -c /tmp/custom.json" { t.Fatalf("unexpected manual command: %q", cmd) } } func TestResolveTransportPrimaryExecStartSingBoxTemplate(t *testing.T) { client := TransportClient{ ID: "sg-eu", Kind: TransportClientSingBox, Config: map[string]any{ "bin": "/usr/bin/sing-box", "config_path": "/etc/singbox/eu.json", }, } cmd, source, err := resolveTransportPrimaryExecStart(client) if err != nil { t.Fatalf("unexpected error: %v", err) } if source != "template:singbox" { t.Fatalf("unexpected source: %q", source) } if !strings.Contains(cmd, "'/usr/bin/sing-box' 'run' '-c' '/etc/singbox/eu.json'") { t.Fatalf("unexpected template command: %q", cmd) } } func TestResolveTransportPrimaryExecStartPhoenixTemplate(t *testing.T) { client := TransportClient{ ID: "ph-eu", Kind: TransportClientPhoenix, Config: map[string]any{ "phoenix_bin": "/usr/local/bin/phoenix-client", "config_path": "/etc/phoenix/client.toml", }, } cmd, source, err := resolveTransportPrimaryExecStart(client) if err != nil { t.Fatalf("unexpected error: %v", err) } if source != "template:phoenix" { t.Fatalf("unexpected source: %q", source) } if !strings.Contains(cmd, "'/usr/local/bin/phoenix-client' '-config' '/etc/phoenix/client.toml'") { t.Fatalf("unexpected template command: %q", cmd) } } func TestBuildTransportDNSTTClientCommandTemplate(t *testing.T) { client := TransportClient{ ID: "dn-home", Kind: TransportClientDNSTT, Config: map[string]any{ "dnstt_bin": "/usr/local/bin/dnstt-client", "doh_url": "https://dns.example.com/dns-query", "pubkey": "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "domain": "tunnel.example.com", "local_addr": "127.0.0.1:7002", "utls": "HelloChrome_Auto", }, } cmd, err := buildTransportDNSTTClientCommand(client) if err != nil { t.Fatalf("unexpected error: %v", err) } wantParts := []string{ "'/usr/local/bin/dnstt-client'", "'-doh' 'https://dns.example.com/dns-query'", "'-pubkey' 'deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef'", "'-utls' 'HelloChrome_Auto'", "'tunnel.example.com' '127.0.0.1:7002'", } for _, part := range wantParts { if !strings.Contains(cmd, part) { t.Fatalf("command missing %q in %q", part, cmd) } } } func TestBuildTransportDNSTTClientCommandRequiresDomain(t *testing.T) { client := TransportClient{ Kind: TransportClientDNSTT, Config: map[string]any{ "doh_url": "https://dns.example.com/dns-query", "pubkey": "cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe", }, } _, err := buildTransportDNSTTClientCommand(client) if err == nil { t.Fatalf("expected error for missing domain") } if !strings.Contains(err.Error(), "config.domain") { t.Fatalf("unexpected error: %v", err) } } func TestBuildTransportSingBoxCommandBundledProfilePrefersBinRoot(t *testing.T) { tmpDir := t.TempDir() binPath := filepath.Join(tmpDir, "sing-box") if err := os.WriteFile(binPath, []byte("#!/bin/sh\nexit 0\n"), 0o755); err != nil { t.Fatalf("write bundled binary: %v", err) } client := TransportClient{ ID: "sg-pack", Kind: TransportClientSingBox, Config: map[string]any{ "packaging_profile": "bundled", "bin_root": tmpDir, "require_binary": true, "config_path": "/etc/singbox/eu.json", }, } cmd, err := buildTransportSingBoxCommand(client) if err != nil { t.Fatalf("unexpected error: %v", err) } if !strings.Contains(cmd, shellQuoteArg(binPath)) { t.Fatalf("expected bundled binary path in command, got %q", cmd) } } func TestBuildTransportPhoenixClientCommandRequireBinaryMissing(t *testing.T) { client := TransportClient{ ID: "ph-pack", Kind: TransportClientPhoenix, Config: map[string]any{ "packaging_profile": "bundled", "bin_root": t.TempDir(), "packaging_system_fallback": false, "require_binary": true, "config_path": "/etc/phoenix/client.toml", }, } _, err := buildTransportPhoenixClientCommand(client) if err == nil { t.Fatalf("expected error when required bundled binary is missing") } if !strings.Contains(err.Error(), "required phoenix binary not found") { t.Fatalf("unexpected error: %v", err) } } func TestBuildTransportSingBoxCommandRequireBinaryMissingManualOverride(t *testing.T) { client := TransportClient{ Kind: TransportClientSingBox, Config: map[string]any{ "singbox_bin": "/tmp/definitely-missing-sing-box-bin", "require_binary": true, "singbox_config_path": "/etc/singbox/eu.json", }, } _, err := buildTransportSingBoxCommand(client) if err == nil { t.Fatalf("expected manual binary validation error") } if !strings.Contains(err.Error(), "required singbox binary not found") { t.Fatalf("unexpected error: %v", err) } } func TestTransportSystemdBackendProvisionRendersServiceTuning(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir transportRunCommand = func(_ time.Duration, _ string, _ ...string) (string, string, int, error) { return "", "", 0, nil } client := TransportClient{ ID: "sg-eu", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "singbox@.service", "exec_start": "/usr/bin/sing-box run -c /etc/singbox/eu.json", "restart_policy": "on-failure", "restart_sec": 7, "start_limit_interval_sec": 900, "start_limit_burst": 11, "timeout_start_sec": 55, "timeout_stop_sec": 33, "watchdog_sec": 20, }, } backend := selectTransportBackend(client) res := backend.Provision(client) if !res.OK { t.Fatalf("expected provision success, got %#v", res) } unitPath := filepath.Join(tmpDir, "singbox@sg-eu.service.d", transportSingBoxInstanceDropIn) data, err := os.ReadFile(unitPath) if err != nil { t.Fatalf("failed to read drop-in unit: %v", err) } text := string(data) want := []string{ "StartLimitIntervalSec=900", "StartLimitBurst=11", "Restart=on-failure", "RestartSec=7", "TimeoutStartSec=55", "TimeoutStopSec=33", "WatchdogSec=20", "NotifyAccess=main", } for _, part := range want { if !strings.Contains(text, part) { t.Fatalf("expected unit to contain %q, got: %s", part, text) } } } func TestTransportSystemdBackendProvisionRendersSSHServiceTuningOverrides(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir transportRunCommand = func(_ time.Duration, _ string, _ ...string) (string, string, int, error) { return "", "", 0, nil } client := TransportClient{ ID: "dn-home", Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dnstt-home.service", "doh_url": "https://dns.google/dns-query", "pubkey": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "domain": "tunnel.example.com", "local_addr": "127.0.0.1:7003", "ssh_tunnel": true, "ssh_unit": "dnstt-home-ssh.service", "ssh_exec_start": "/usr/bin/ssh -N -D 127.0.0.1:1080 root@example.com", "restart_sec": 4, "ssh_restart_sec": 9, "watchdog_sec": 0, "ssh_watchdog_sec": 25, "ssh_restart_policy": "on-failure", }, } backend := selectTransportBackend(client) res := backend.Provision(client) if !res.OK { t.Fatalf("expected provision success, got %#v", res) } primaryData, err := os.ReadFile(filepath.Join(tmpDir, "dnstt-home.service")) if err != nil { t.Fatalf("failed to read primary unit: %v", err) } sshData, err := os.ReadFile(filepath.Join(tmpDir, "dnstt-home-ssh.service")) if err != nil { t.Fatalf("failed to read ssh unit: %v", err) } primaryText := string(primaryData) sshText := string(sshData) if !strings.Contains(primaryText, "RestartSec=4") { t.Fatalf("expected primary restart sec from base config: %s", primaryText) } if strings.Contains(primaryText, "WatchdogSec=") { t.Fatalf("did not expect primary watchdog line: %s", primaryText) } if !strings.Contains(sshText, "RestartSec=9") { t.Fatalf("expected ssh restart sec override: %s", sshText) } if !strings.Contains(sshText, "Restart=on-failure") { t.Fatalf("expected ssh restart policy override: %s", sshText) } if !strings.Contains(sshText, "WatchdogSec=25") { t.Fatalf("expected ssh watchdog override: %s", sshText) } } func TestTransportSystemdBackendProvisionDefaultHardeningEnabled(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir transportRunCommand = func(_ time.Duration, _ string, _ ...string) (string, string, int, error) { return "", "", 0, nil } client := TransportClient{ ID: "sg-hardened", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "sg-hardened.service", "exec_start": "/usr/bin/sing-box run -c /etc/singbox/eu.json", }, } backend := selectTransportBackend(client) res := backend.Provision(client) if !res.OK { t.Fatalf("expected provision success, got %#v", res) } data, err := os.ReadFile(filepath.Join(tmpDir, "sg-hardened.service")) if err != nil { t.Fatalf("failed to read unit: %v", err) } text := string(data) want := []string{ "NoNewPrivileges=yes", "PrivateTmp=yes", "ProtectSystem=full", "ProtectHome=read-only", "ProtectControlGroups=yes", "ProtectKernelModules=yes", "ProtectKernelTunables=yes", "RestrictSUIDSGID=yes", "LockPersonality=yes", "UMask=0077", } for _, part := range want { if !strings.Contains(text, part) { t.Fatalf("expected baseline hardening line %q in unit: %s", part, text) } } } func TestTransportSystemdBackendProvisionHardeningCanBeDisabled(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir transportRunCommand = func(_ time.Duration, _ string, _ ...string) (string, string, int, error) { return "", "", 0, nil } client := TransportClient{ ID: "sg-soft", Kind: TransportClientSingBox, Config: map[string]any{ "runner": "systemd", "unit": "sg-soft.service", "exec_start": "/usr/bin/sing-box run -c /etc/singbox/eu.json", "hardening_enabled": false, }, } backend := selectTransportBackend(client) res := backend.Provision(client) if !res.OK { t.Fatalf("expected provision success, got %#v", res) } data, err := os.ReadFile(filepath.Join(tmpDir, "sg-soft.service")) if err != nil { t.Fatalf("failed to read unit: %v", err) } text := string(data) blocked := []string{ "NoNewPrivileges=", "ProtectSystem=", "ProtectHome=", "RestrictSUIDSGID=", "UMask=", } for _, part := range blocked { if strings.Contains(text, part) { t.Fatalf("expected hardening line %q to be absent when disabled: %s", part, text) } } } func TestTransportSystemdBackendProvisionSSHHardeningOverrideDisabled(t *testing.T) { origRunner := transportRunCommand origUnitsDir := transportSystemdUnitsDir defer func() { transportRunCommand = origRunner transportSystemdUnitsDir = origUnitsDir }() tmpDir := t.TempDir() transportSystemdUnitsDir = tmpDir transportRunCommand = func(_ time.Duration, _ string, _ ...string) (string, string, int, error) { return "", "", 0, nil } client := TransportClient{ ID: "dn-hard", Kind: TransportClientDNSTT, Config: map[string]any{ "runner": "systemd", "unit": "dn-hard.service", "doh_url": "https://dns.google/dns-query", "pubkey": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "domain": "tunnel.example.com", "local_addr": "127.0.0.1:7004", "ssh_tunnel": true, "ssh_unit": "dn-hard-ssh.service", "ssh_exec_start": "/usr/bin/ssh -N -D 127.0.0.1:1080 root@example.com", "hardening_profile": "strict", "ssh_hardening_enabled": false, }, } backend := selectTransportBackend(client) res := backend.Provision(client) if !res.OK { t.Fatalf("expected provision success, got %#v", res) } primaryData, err := os.ReadFile(filepath.Join(tmpDir, "dn-hard.service")) if err != nil { t.Fatalf("failed to read primary unit: %v", err) } sshData, err := os.ReadFile(filepath.Join(tmpDir, "dn-hard-ssh.service")) if err != nil { t.Fatalf("failed to read ssh unit: %v", err) } primaryText := string(primaryData) sshText := string(sshData) if !strings.Contains(primaryText, "ProtectSystem=strict") { t.Fatalf("expected strict hardening in primary unit: %s", primaryText) } if !strings.Contains(primaryText, "PrivateDevices=yes") { t.Fatalf("expected strict private devices in primary unit: %s", primaryText) } if strings.Contains(sshText, "NoNewPrivileges=") || strings.Contains(sshText, "ProtectSystem=") { t.Fatalf("expected ssh unit hardening to be disabled by ssh_hardening_enabled=false: %s", sshText) } }