Skip to content

Commit

Permalink
Add Command type
Browse files Browse the repository at this point in the history
Adds the `Command` type which allows projects to generate a properly formatted
gvproxy command in the form of a string slice without hard-coding it. Adds the
functionality to convert `Command` to a format in which os/exec can directly
execute it.

Signed-off-by: Jake Correnti <jakecorrenti+github@proton.me>
  • Loading branch information
jakecorrenti committed Aug 11, 2023
1 parent b0d9740 commit 6d88b0d
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 0 deletions.
187 changes: 187 additions & 0 deletions pkg/types/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package types

import (
"fmt"
"os/exec"
)

type Command struct {
// Print packets on stderr
Debug bool

// Length of packet
// Larger packets means less packets to exchange for the same amount of data (and less protocol overhead)
MTU int

// Values passed in by forward-xxx flags in commandline (forward-xxx:info)
forwardInfo map[string][]string

// List of endpoints the user wants to listen to
Endpoints []string

// Map of different sockets provided by user (socket-type flag:socket)
sockets map[string]string

// File where gvproxy's pid is stored
Pidfile string

// SSHPort to access the guest VM
SSHPort int
}

func NewCommand() Command {
return Command{
MTU: 1500,
SSHPort: 2222,
forwardInfo: map[string][]string{},
sockets: map[string]string{},
}
}

func (c *Command) checkSocketsInitialized() {
if len(c.sockets) < 1 {
c.sockets = map[string]string{}
}
}

func (c *Command) checkForwardInfoInitialized() {
if len(c.forwardInfo) < 1 {
c.forwardInfo = map[string][]string{}
}
}

func (c *Command) AddVpnkitSocket(socket string) {
c.checkSocketsInitialized()
c.sockets["listen-vpnkit"] = socket
}

func (c *Command) AddQemuSocket(socket string) {
c.checkSocketsInitialized()
c.sockets["listen-qemu"] = socket
}

func (c *Command) AddBessSocket(socket string) {
c.checkSocketsInitialized()
c.sockets["listen-bess"] = socket
}

func (c *Command) AddStdioSocket(socket string) {
c.checkSocketsInitialized()
c.sockets["listen-stdio"] = socket
}

func (c *Command) AddVfkitSocket(socket string) {
c.checkSocketsInitialized()
c.sockets["listen-vfkit"] = socket
}

func (c *Command) addForwardInfo(flag, value string) {
if _, ok := c.forwardInfo[flag]; ok {
c.forwardInfo[flag] = append(c.forwardInfo[flag], value)
} else {
c.forwardInfo[flag] = []string{value}
}
}

func (c *Command) AddForwardSock(socket string) {
c.checkForwardInfoInitialized()
c.addForwardInfo("forward-sock", socket)
}

func (c *Command) AddForwardDest(dest string) {
c.checkForwardInfoInitialized()
c.addForwardInfo("forward-dest", dest)
}

func (c *Command) AddForwardUser(user string) {
c.checkForwardInfoInitialized()
c.addForwardInfo("forward-user", user)
}

func (c *Command) AddForwardIdentity(identity string) {
c.checkForwardInfoInitialized()
c.addForwardInfo("forward-identity", identity)
}

// socketsToCmdline converts Command.Sockets to a commandline format
func (c *Command) socketsToCmdline() ([]string, error) {
args := []string{}

for socketFlag, socket := range c.sockets {
if socket != "" {
args = append(args, fmt.Sprintf("-%s %s", socketFlag, socket))
}
}

return args, nil
}

// forwardInfoToCmdline converts Command.ForwardInfo to a command line format
func (c *Command) forwardInfoToCmdline() ([]string, error) {
args := []string{}

for forwardInfoFlag, forwardInfo := range c.forwardInfo {
for _, i := range forwardInfo {
if i != "" {
args = append(args, fmt.Sprintf("-%s %s", forwardInfoFlag, i))
}
}
}

return args, nil
}

// ToCmdline converts Command to a properly formatted command for gvproxy based
// on its fields
func (c *Command) ToCmdline() ([]string, error) {
args := []string{}

// listen (endpoints)
for _, endpoint := range c.Endpoints {
args = append(args, "-listen "+endpoint)
}

// debug
if c.Debug {
args = append(args, "-debug")
}

// mtu
args = append(args, fmt.Sprintf("-mtu %d", c.MTU))

// ssh-port
args = append(args, fmt.Sprintf("-ssh-port %d", c.SSHPort))

// sockets
socketArgs, err := c.socketsToCmdline()
if err != nil {
return nil, err
}
args = append(args, socketArgs...)

// forward info
forwardInfoArgs, err := c.forwardInfoToCmdline()
if err != nil {
return nil, err
}
args = append(args, forwardInfoArgs...)

// pid-file
if c.Pidfile != "" {
args = append(args, "-pid-file "+c.Pidfile)
}

return args, nil
}

// Cmd converts Command to a commandline format and returns an exec.Cmd which
// can be executed by os/exec
func (c *Command) Cmd(gvproxyPath string) (*exec.Cmd, error) {
args, err := c.ToCmdline()
if err != nil {
return nil, err
}

cmd := exec.Command(gvproxyPath, args...)
return cmd, nil
}
23 changes: 23 additions & 0 deletions test/basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,26 @@ var _ = Describe("dns", func() {
Expect(string(out)).To(ContainSubstring("Address: 192.168.127.1"))
})
})

var _ = Describe("command-line format", func() {
It("should convert Command to command line format", func() {
command := types.NewCommand()
command.Endpoints = []string{"unix:///tmp/network.sock"}
command.Debug = true
command.AddQemuSocket("tcp://0.0.0.0:1234")
command.Pidfile = "~/gv-pidfile.txt"
command.AddForwardUser("demouser")

cmd, err := command.ToCmdline()
Expect(err).ShouldNot(HaveOccurred())
Expect(cmd).To(Equal([]string{
"-listen unix:///tmp/network.sock",
"-debug",
"-mtu 1500",
"-ssh-port 2222",
"-listen-qemu tcp://0.0.0.0:1234",
"-forward-user demouser",
"-pid-file ~/gv-pidfile.txt",
}))
})
})

0 comments on commit 6d88b0d

Please sign in to comment.