200 lines
5.9 KiB
Go
200 lines
5.9 KiB
Go
package app
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTransportWrapExecWithNetns(t *testing.T) {
|
|
client := TransportClient{
|
|
ID: "sg-1",
|
|
Config: map[string]any{
|
|
"netns_enabled": true,
|
|
"netns_name": "svpn-test",
|
|
"netns_exec_mode": "ip",
|
|
},
|
|
}
|
|
cmd := transportWrapExecWithNetns(client, "/usr/bin/sing-box run -c /etc/singbox/test.json")
|
|
if !strings.Contains(cmd, "'ip' 'netns' 'exec' 'svpn-test'") {
|
|
t.Fatalf("expected wrapped command with netns exec, got: %s", cmd)
|
|
}
|
|
if !strings.Contains(cmd, "'/bin/sh' '-lc'") {
|
|
t.Fatalf("expected wrapped command to keep payload shell execution, got: %s", cmd)
|
|
}
|
|
}
|
|
|
|
func TestTransportWrapExecWithNetnsNsenter(t *testing.T) {
|
|
client := TransportClient{
|
|
ID: "sg-1",
|
|
Config: map[string]any{
|
|
"netns_enabled": true,
|
|
"netns_name": "svpn-test",
|
|
"netns_exec_mode": "nsenter",
|
|
"netns_nsenter_bin": "/usr/bin/nsenter",
|
|
},
|
|
}
|
|
cmd := transportWrapExecWithNetns(client, "/usr/bin/sing-box run -c /etc/singbox/test.json")
|
|
if !strings.Contains(cmd, "'/usr/bin/nsenter' '--net=/var/run/netns/svpn-test' '--'") {
|
|
t.Fatalf("expected wrapped command with nsenter, got: %s", cmd)
|
|
}
|
|
if !strings.Contains(cmd, "'/bin/sh' '-lc'") {
|
|
t.Fatalf("expected wrapped command to keep payload shell execution, got: %s", cmd)
|
|
}
|
|
}
|
|
|
|
func TestTransportNetnsExecCommandModes(t *testing.T) {
|
|
clientNS := TransportClient{
|
|
ID: "sg-1",
|
|
Config: map[string]any{
|
|
"netns_exec_mode": "nsenter",
|
|
"netns_nsenter_bin": "/usr/bin/nsenter",
|
|
},
|
|
}
|
|
name, args, err := transportNetnsExecCommand(clientNS, "svpn-test", "ip", "link", "show")
|
|
if err != nil {
|
|
t.Fatalf("nsenter mode command error: %v", err)
|
|
}
|
|
if name != "/usr/bin/nsenter" {
|
|
t.Fatalf("expected nsenter binary, got: %q", name)
|
|
}
|
|
if len(args) < 5 || args[0] != "--net=/var/run/netns/svpn-test" || args[1] != "--" || args[2] != "ip" {
|
|
t.Fatalf("unexpected nsenter args: %#v", args)
|
|
}
|
|
|
|
clientIP := TransportClient{
|
|
ID: "sg-1",
|
|
Config: map[string]any{
|
|
"netns_exec_mode": "ip",
|
|
"netns_ip_bin": "/sbin/ip",
|
|
},
|
|
}
|
|
name, args, err = transportNetnsExecCommand(clientIP, "svpn-test", "ip", "link", "show")
|
|
if err != nil {
|
|
t.Fatalf("ip mode command error: %v", err)
|
|
}
|
|
if name != "/sbin/ip" {
|
|
t.Fatalf("expected ip binary, got: %q", name)
|
|
}
|
|
if len(args) < 6 || args[0] != "netns" || args[1] != "exec" || args[2] != "svpn-test" || args[3] != "ip" {
|
|
t.Fatalf("unexpected ip args: %#v", args)
|
|
}
|
|
}
|
|
|
|
func TestTransportSystemdBackendProvisionWrapsNetnsExec(t *testing.T) {
|
|
origRunner := transportRunCommand
|
|
origUnitsDir := transportSystemdUnitsDir
|
|
defer func() {
|
|
transportRunCommand = origRunner
|
|
transportSystemdUnitsDir = origUnitsDir
|
|
}()
|
|
|
|
tmpDir := t.TempDir()
|
|
transportSystemdUnitsDir = tmpDir
|
|
transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) {
|
|
cmd := name + " " + strings.Join(args, " ")
|
|
if cmd == "systemctl daemon-reload" {
|
|
return "", "", 0, nil
|
|
}
|
|
return "", "", 0, nil
|
|
}
|
|
|
|
client := TransportClient{
|
|
ID: "sg-netns",
|
|
Kind: TransportClientSingBox,
|
|
Config: map[string]any{
|
|
"runner": "systemd",
|
|
"unit": "sg-netns.service",
|
|
"exec_start": "/usr/bin/sing-box run -c /etc/singbox/eu.json",
|
|
"netns_enabled": true,
|
|
"netns_name": "svpn-test",
|
|
},
|
|
}
|
|
res := selectTransportBackend(client).Provision(client)
|
|
if !res.OK {
|
|
t.Fatalf("expected provision success, got %#v", res)
|
|
}
|
|
data, err := os.ReadFile(filepath.Join(tmpDir, "sg-netns.service"))
|
|
if err != nil {
|
|
t.Fatalf("failed to read unit: %v", err)
|
|
}
|
|
text := string(data)
|
|
if !strings.Contains(text, "netns") || !strings.Contains(text, "svpn-test") {
|
|
t.Fatalf("expected netns exec in unit ExecStart, got: %s", text)
|
|
}
|
|
}
|
|
|
|
func TestTransportSystemdBackendActionNetnsStrictFailure(t *testing.T) {
|
|
origRunner := transportRunCommand
|
|
defer func() { transportRunCommand = origRunner }()
|
|
|
|
transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) {
|
|
cmd := name + " " + strings.Join(args, " ")
|
|
if cmd == "ip netns list" {
|
|
return "", "cannot list netns", 1, nil
|
|
}
|
|
return "", "", 0, nil
|
|
}
|
|
|
|
client := TransportClient{
|
|
ID: "sg-netns",
|
|
Kind: TransportClientSingBox,
|
|
Config: map[string]any{
|
|
"runner": "systemd",
|
|
"unit": "singbox-test.service",
|
|
"netns_enabled": true,
|
|
"netns_setup_strict": true,
|
|
},
|
|
}
|
|
res := selectTransportBackend(client).Action(client, "start")
|
|
if res.OK {
|
|
t.Fatalf("expected strict netns setup failure, got %#v", res)
|
|
}
|
|
if res.Code != "TRANSPORT_BACKEND_NETNS_SETUP_FAILED" {
|
|
t.Fatalf("unexpected error code: %#v", res)
|
|
}
|
|
}
|
|
|
|
func TestTransportSystemdBackendActionNetnsWarningNonStrict(t *testing.T) {
|
|
origRunner := transportRunCommand
|
|
defer func() { transportRunCommand = origRunner }()
|
|
|
|
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 == "ip netns list" {
|
|
return "", "cannot list netns", 1, nil
|
|
}
|
|
if cmd == "systemctl start singbox-test.service" {
|
|
return "", "", 0, nil
|
|
}
|
|
return "", "", 0, nil
|
|
}
|
|
|
|
client := TransportClient{
|
|
ID: "sg-netns",
|
|
Kind: TransportClientSingBox,
|
|
Config: map[string]any{
|
|
"runner": "systemd",
|
|
"unit": "singbox-test.service",
|
|
"netns_enabled": true,
|
|
},
|
|
}
|
|
res := selectTransportBackend(client).Action(client, "start")
|
|
if !res.OK {
|
|
t.Fatalf("expected non-strict start success with warning, got %#v", res)
|
|
}
|
|
if !strings.Contains(strings.ToLower(res.Message), "warnings") {
|
|
t.Fatalf("expected warning marker in message, got %#v", res)
|
|
}
|
|
if !strings.Contains(strings.ToLower(res.Stderr), "netns:") {
|
|
t.Fatalf("expected netns warning in stderr, got %#v", res)
|
|
}
|
|
if !strings.Contains(strings.Join(calls, " | "), "systemctl start singbox-test.service") {
|
|
t.Fatalf("expected systemctl start call, got %#v", calls)
|
|
}
|
|
}
|