From 4daf8fb7160fa53b599f59672b6db88c852322e1 Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Wed, 20 Jan 2021 21:49:14 +0100 Subject: [PATCH] port: add ChildIP allow users to override the IP to use for the connection inside the network namespace. It is useful e.g. with slirp4netns to override the IP to "10.0.2.100". Signed-off-by: Giuseppe Scrivano --- go.sum | 1 + pkg/port/builtin/child/child.go | 16 +++++++++++++++- pkg/port/builtin/msg/msg.go | 2 ++ pkg/port/port.go | 1 + pkg/port/slirp4netns/slirp4netns.go | 16 +++++++++++++++- pkg/port/socat/socat.go | 18 ++++++++++++++++-- 6 files changed, 50 insertions(+), 4 deletions(-) diff --git a/go.sum b/go.sum index 7179a8e6..f88a70a6 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,7 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.3 h1:twObb+9XcuH5B9V1TBCvvvZoO6iEdILi2a76PYn5rJI= github.com/google/uuid v1.1.3/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.4/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.5 h1:kxhtnfFVi+rYdOALN0B3k9UT86zVJKfBimRaciULW4I= github.com/google/uuid v1.1.5/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= diff --git a/pkg/port/builtin/child/child.go b/pkg/port/builtin/child/child.go index 112a926c..e2876619 100644 --- a/pkg/port/builtin/child/child.go +++ b/pkg/port/builtin/child/child.go @@ -106,7 +106,21 @@ func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *msg.Request) er return errors.Errorf("unknown proto: %q", req.Proto) } var dialer net.Dialer - targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("127.0.0.1:%d", req.Port)) + ip := req.IP + if ip == "" { + ip = "127.0.0.1" + } else { + p := net.ParseIP(ip) + if p == nil { + return errors.Errorf("invalid IP: %q", ip) + } + p = p.To4() + if p == nil { + return errors.Errorf("unsupported IP (v6?): %s", ip) + } + ip = p.String() + } + targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("%s:%d", ip, req.Port)) if err != nil { return err } diff --git a/pkg/port/builtin/msg/msg.go b/pkg/port/builtin/msg/msg.go index e95b6219..a8c8e038 100644 --- a/pkg/port/builtin/msg/msg.go +++ b/pkg/port/builtin/msg/msg.go @@ -20,6 +20,7 @@ const ( type Request struct { Type string // "init" or "connect" Proto string // "tcp" or "udp" + IP string Port int } @@ -53,6 +54,7 @@ func ConnectToChild(c *net.UnixConn, spec port.Spec) (int, error) { Type: RequestTypeConnect, Proto: spec.Proto, Port: spec.ChildPort, + IP: spec.ChildIP, } if _, err := msgutil.MarshalToWriter(c, &req); err != nil { return 0, err diff --git a/pkg/port/port.go b/pkg/port/port.go index 9ef46f54..d996192d 100644 --- a/pkg/port/port.go +++ b/pkg/port/port.go @@ -10,6 +10,7 @@ type Spec struct { ParentIP string `json:"parentIP,omitempty"` // IPv4 address. can be empty (0.0.0.0). ParentPort int `json:"parentPort,omitempty"` ChildPort int `json:"childPort,omitempty"` + ChildIP string `json:"childIP,omitempty"` // IPv4 address. If not specified, "127.0.0.1" is used. } type Status struct { diff --git a/pkg/port/slirp4netns/slirp4netns.go b/pkg/port/slirp4netns/slirp4netns.go index 6f53c82e..d91067d8 100644 --- a/pkg/port/slirp4netns/slirp4netns.go +++ b/pkg/port/slirp4netns/slirp4netns.go @@ -55,13 +55,27 @@ func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, err if err != nil { return nil, err } + ip := spec.ChildIP + if ip == "" { + ip = d.childIP + } else { + p := net.ParseIP(ip) + if p == nil { + return nil, errors.Errorf("invalid IP: %q", ip) + } + p = p.To4() + if p == nil { + return nil, errors.Errorf("unsupported IP (v6?): %s", ip) + } + ip = p.String() + } req := request{ Execute: "add_hostfwd", Arguments: addHostFwdArguments{ Proto: spec.Proto, HostAddr: spec.ParentIP, HostPort: spec.ParentPort, - GuestAddr: d.childIP, + GuestAddr: ip, GuestPort: spec.ChildPort, }, } diff --git a/pkg/port/socat/socat.go b/pkg/port/socat/socat.go index 9dbb0a5c..cc3609e5 100644 --- a/pkg/port/socat/socat.go +++ b/pkg/port/socat/socat.go @@ -135,6 +135,20 @@ func createSocatCmd(ctx context.Context, spec port.Spec, logWriter io.Writer, ch if spec.ChildPort < 1 || spec.ChildPort > 65535 { return nil, errors.Errorf("unsupported childPort: %d", spec.ChildPort) } + ip := spec.ChildIP + if ip == "" { + ip = "127.0.0.1" + } else { + p := net.ParseIP(ip) + if p == nil { + return nil, errors.Errorf("invalid IP: %q", ip) + } + p = p.To4() + if p == nil { + return nil, errors.Errorf("unsupported IP (v6?): %s", ip) + } + ip = p.String() + } var cmd *exec.Cmd switch spec.Proto { case "tcp": @@ -142,13 +156,13 @@ func createSocatCmd(ctx context.Context, spec port.Spec, logWriter io.Writer, ch "socat", fmt.Sprintf("TCP-LISTEN:%d,bind=%s,reuseaddr,fork,rcvbuf=65536,sndbuf=65536", spec.ParentPort, ipStr), fmt.Sprintf("EXEC:\"%s\",nofork", - fmt.Sprintf("nsenter -U -n --preserve-credentials -t %d socat STDIN TCP4:127.0.0.1:%d", childPID, spec.ChildPort))) + fmt.Sprintf("nsenter -U -n --preserve-credentials -t %d socat STDIN TCP4:%s:%d", childPID, ip, spec.ChildPort))) case "udp": cmd = exec.CommandContext(ctx, "socat", fmt.Sprintf("UDP-LISTEN:%d,bind=%s,reuseaddr,fork,rcvbuf=65536,sndbuf=65536", spec.ParentPort, ipStr), fmt.Sprintf("EXEC:\"%s\",nofork", - fmt.Sprintf("nsenter -U -n --preserve-credentials -t %d socat STDIN UDP4:127.0.0.1:%d", childPID, spec.ChildPort))) + fmt.Sprintf("nsenter -U -n --preserve-credentials -t %d socat STDIN UDP4:%s:%d", childPID, ip, spec.ChildPort))) } cmd.Env = os.Environ() cmd.Stdout = logWriter