Files
elmprodvpn/selective-vpn-api/app/transport_netns_exec.go

98 lines
2.5 KiB
Go

package app
import (
"fmt"
"os"
"os/exec"
"strings"
"time"
)
func transportWrapExecWithNetns(client TransportClient, command string) string {
cmd := strings.TrimSpace(command)
if cmd == "" || !transportNetnsEnabled(client) {
return cmd
}
ns := transportNetnsName(client)
if ns == "" {
return cmd
}
name, args, err := transportNetnsExecCommand(client, ns, "/bin/sh", "-lc", cmd)
if err != nil {
return cmd
}
return shellJoinArgs(append([]string{name}, args...))
}
func transportResolveNetnsNsenterBin(client TransportClient) string {
if explicit := strings.TrimSpace(transportConfigString(client.Config, "netns_nsenter_bin")); explicit != "" {
return explicit
}
if p, err := exec.LookPath("nsenter"); err == nil {
return strings.TrimSpace(p)
}
candidates := []string{
"/usr/bin/nsenter",
"/bin/nsenter",
"/usr/sbin/nsenter",
"/sbin/nsenter",
}
for _, cand := range candidates {
if _, err := os.Stat(cand); err == nil {
return cand
}
}
return ""
}
func transportNetnsExecCommand(client TransportClient, ns string, command ...string) (string, []string, error) {
if strings.TrimSpace(ns) == "" {
return "", nil, fmt.Errorf("netns name is empty")
}
if len(command) == 0 {
return "", nil, fmt.Errorf("netns command is empty")
}
mode := strings.ToLower(strings.TrimSpace(transportConfigString(client.Config, "netns_exec_mode")))
useNsenter := false
switch mode {
case "ip", "ip-netns", "ip_netns":
useNsenter = false
case "nsenter":
useNsenter = true
case "", "auto":
useNsenter = true
default:
useNsenter = true
}
if useNsenter {
if bin := transportResolveNetnsNsenterBin(client); bin != "" {
args := []string{"--net=/var/run/netns/" + ns, "--"}
args = append(args, command...)
return bin, args, nil
}
}
ipBin := strings.TrimSpace(transportConfigString(client.Config, "netns_ip_bin"))
if ipBin == "" {
ipBin = "ip"
}
args := []string{"netns", "exec", ns}
args = append(args, command...)
return ipBin, args, nil
}
func transportRunInNetnsMust(timeout time.Duration, client TransportClient, ns string, command ...string) error {
name, args, err := transportNetnsExecCommand(client, ns, command...)
if err != nil {
return err
}
return transportRunMust(timeout, name, args...)
}
func transportRunInNetnsSoft(timeout time.Duration, client TransportClient, ns string, command ...string) error {
name, args, err := transportNetnsExecCommand(client, ns, command...)
if err != nil {
return err
}
return transportRunSoft(timeout, name, args...)
}