Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

connect over stdio #177

Merged
merged 1 commit into from
Feb 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion cmd/gvproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"syscall"
"time"

"github.com/containers/gvisor-tap-vsock/pkg/net/stdio"
"github.com/containers/gvisor-tap-vsock/pkg/sshclient"
"github.com/containers/gvisor-tap-vsock/pkg/transport"
"github.com/containers/gvisor-tap-vsock/pkg/types"
Expand All @@ -34,6 +35,7 @@ var (
vpnkitSocket string
qemuSocket string
bessSocket string
stdioSocket string
forwardSocket arrayFlags
forwardDest arrayFlags
forwardUser arrayFlags
Expand All @@ -56,12 +58,14 @@ func main() {
flag.StringVar(&vpnkitSocket, "listen-vpnkit", "", "VPNKit socket to be used by Hyperkit")
flag.StringVar(&qemuSocket, "listen-qemu", "", "Socket to be used by Qemu")
flag.StringVar(&bessSocket, "listen-bess", "", "unixpacket socket to be used by Bess-compatible applications")
flag.StringVar(&stdioSocket, "listen-stdio", "", "accept stdio pipe")
flag.Var(&forwardSocket, "forward-sock", "Forwards a unix socket to the guest virtual machine over SSH")
flag.Var(&forwardDest, "forward-dest", "Forwards a unix socket to the guest virtual machine over SSH")
flag.Var(&forwardUser, "forward-user", "SSH user to use for unix socket forward")
flag.Var(&forwardIdentify, "forward-identity", "Path to SSH identity key for forwarding")
flag.StringVar(&pidFile, "pid-file", "", "Generate a file with the PID in it")
flag.Parse()

ctx, cancel := context.WithCancel(context.Background())
// Make this the last defer statement in the stack
defer os.Exit(exitCode)
Expand Down Expand Up @@ -275,7 +279,7 @@ func run(ctx context.Context, g *errgroup.Group, configuration *types.Configurat
for {
select {
case <-time.After(5 * time.Second):
fmt.Printf("%v sent to the VM, %v received from the VM\n", humanize.Bytes(vn.BytesSent()), humanize.Bytes(vn.BytesReceived()))
log.Debugf("%v sent to the VM, %v received from the VM\n", humanize.Bytes(vn.BytesSent()), humanize.Bytes(vn.BytesReceived()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:+1

case <-ctx.Done():
break debugLog
}
Expand Down Expand Up @@ -359,6 +363,13 @@ func run(ctx context.Context, g *errgroup.Group, configuration *types.Configurat
})
}

if stdioSocket != "" {
g.Go(func() error {
conn := stdio.GetStdioConn()
return vn.AcceptQemu(ctx, conn)
})
}

for i := 0; i < len(forwardSocket); i++ {
var (
src *url.URL
Expand Down
14 changes: 8 additions & 6 deletions cmd/vm/main_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ func run() error {
}
defer conn.Close()

req, err := http.NewRequest("POST", path, nil)
if err != nil {
return err
}
if err := req.Write(conn); err != nil {
return err
if path != "" {
req, err := http.NewRequest("POST", path, nil)
if err != nil {
return err
}
if err := req.Write(conn); err != nil {
return err
}
}

tap, err := water.New(water.Config{
Expand Down
51 changes: 51 additions & 0 deletions pkg/net/stdio/dial.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package stdio

import (
"net"
"os"
"os/exec"
"strconv"
)

func Dial(endpoint string, arg ...string) (net.Conn, error) {
cmd := exec.Command(endpoint, arg...)
cmd.Stderr = os.Stderr

stdin, err := cmd.StdinPipe()
if err != nil {
return nil, err
}

stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}

err = cmd.Start()
if err != nil {
return nil, err
}

local := IoAddr{path: strconv.Itoa(os.Getpid())}
remote := IoAddr{path: strconv.Itoa(cmd.Process.Pid)}
conn := IoConn{
reader: stdout,
writer: stdin,
local: local,
remote: remote,
close: cmd.Process.Kill,
}
return conn, nil
}

func GetStdioConn() net.Conn {
local := IoAddr{path: strconv.Itoa(os.Getpid())}
remote := IoAddr{path: "remote"}
conn := IoConn{
writer: os.Stdout,
reader: os.Stdin,
local: local,
remote: remote,
}
return conn
}
12 changes: 12 additions & 0 deletions pkg/net/stdio/ioaddr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package stdio

type IoAddr struct {
path string
}

func (a IoAddr) Network() string {
return "stdio"
}
func (a IoAddr) String() string {
return a.path
}
50 changes: 50 additions & 0 deletions pkg/net/stdio/ioconn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package stdio

import (
"io"
"net"
"time"
)

type IoConn struct {
writer io.Writer
reader io.Reader
local net.Addr
remote net.Addr
close func() error
}

func (c IoConn) Read(b []byte) (n int, err error) {
return c.reader.Read(b)
}

func (c IoConn) Write(b []byte) (n int, err error) {
return c.writer.Write(b)
}

func (c IoConn) Close() error {
if c.close != nil {
return c.close()
}
return nil
}

func (c IoConn) LocalAddr() net.Addr {
return c.local
}

func (c IoConn) RemoteAddr() net.Addr {
return c.remote
}

func (c IoConn) SetDeadline(t time.Time) error {
return nil
}

func (c IoConn) SetReadDeadline(t time.Time) error {
return nil
}

func (c IoConn) SetWriteDeadline(t time.Time) error {
return nil
}
11 changes: 11 additions & 0 deletions pkg/transport/dial_linux.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package transport

import (
"fmt"
"net"
"net/url"
"strconv"

"github.com/containers/gvisor-tap-vsock/pkg/net/stdio"
mdlayhervsock "github.com/mdlayher/vsock"
"github.com/pkg/errors"
)
Expand All @@ -29,6 +31,15 @@ func Dial(endpoint string) (net.Conn, string, error) {
case "unix":
conn, err := net.Dial("unix", parsed.Path)
return conn, "/connect", err
case "stdio":
var values []string
for k, vs := range parsed.Query() {
for _, v := range vs {
values = append(values, fmt.Sprintf("-%s=%s", k, v))
}
}
conn, err := stdio.Dial(parsed.Path, values...)
return conn, "", err
default:
return nil, "", errors.New("unexpected scheme")
}
Expand Down
9 changes: 9 additions & 0 deletions test/wsl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

set -x

./bin/vm \
-url="stdio:$(pwd)/bin/gvproxy-windows.exe?listen-stdio=accept&debug=true" \
-iface="eth1" \
-stop-if-exist="" \
-debug