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

Add support for UDP forwarding #17

Merged
merged 1 commit into from
Sep 28, 2021
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
110 changes: 73 additions & 37 deletions go_src/vagrant-vmware-utility/internal/service/port_forwarding.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"io"
"net"
"strings"
"sync"

hclog "github.com/hashicorp/go-hclog"
Expand Down Expand Up @@ -39,59 +40,94 @@ func (f *Forward) Activate() error {
}
f.Active = true

l, err := net.Listen(f.Fwd.Host.Type, f.Fwd.Host.String())
if err != nil {
f.logger.Error("failed to setup host listener", "host", f.Fwd.Host, "error", err)
return err
}
if strings.Contains(f.Fwd.Host.Type, "tcp") {
l, err := net.Listen("tcp", f.Fwd.Host.String())
if err != nil {
f.logger.Error("failed to setup host listener", "type", "tcp", "host", f.Fwd.Host, "error", err)
return err
}

go func() {
<-f.Ctx.Done()
l.Close()
}()
go func() {
<-f.Ctx.Done()
l.Close()
}()

f.logger.Debug("activated port forwarding", "fwd", f)
f.logger.Debug("activated port forward", "type", "tcp", "fwd", f)

go func() {
for {
conn, err := l.Accept()
if err != nil {
f.logger.Error("failed to accept incoming connection", "fwd", f, "error", err)
f.cancel()
return
}
go func() {
for {
conn, err := l.Accept()
if err != nil {
f.logger.Error("failed to accept incoming connection", "type", "tcp", "fwd", f, "error", err)
f.cancel()
return
}

target, err := net.Dial(f.Fwd.Guest.Type, f.Fwd.Guest.String())
if err != nil {
f.logger.Warn("failed to connect to guest", "guest", f.Fwd.Guest)
continue
target, err := net.Dial("tcp", f.Fwd.Guest.String())
if err != nil {
f.logger.Warn("failed to connect to guest", "type", "tcp", "guest", f.Fwd.Guest)
continue
}

ctx, completed := context.WithCancel(f.Ctx)
f.logger.Debug("initializing new connection stream", "type", "tcp", "fwd", f, "source", conn.RemoteAddr())
go f.stream(conn, target, completed, "tcp", "outgoing")
go f.stream(target, conn, completed, "tcp", "incoming")

go func() {
select {
case <-ctx.Done():
case <-f.Ctx.Done():
}
conn.Close()
target.Close()
}()
}
}()
}

ctx, completed := context.WithCancel(f.Ctx)
f.logger.Debug("initializing new connection stream", "fwd", f, "source", conn.RemoteAddr())
go f.stream(conn, target, completed)
go f.stream(target, conn, completed)
if strings.Contains(f.Fwd.Host.Type, "udp") {
addr := &net.UDPAddr{
IP: net.ParseIP(f.Fwd.Host.Host),
Port: f.Fwd.Host.Port,
}
conn, err := net.ListenUDP("udp", addr)
if err != nil {
f.logger.Error("failed to setup host listener", "type", "udp", "host", f.Fwd.Host, "error", err)
return err
}

go func() {
select {
case <-ctx.Done():
case <-f.Ctx.Done():
}
conn.Close()
target.Close()
}()
target, err := net.Dial("udp", f.Fwd.Guest.String())
if err != nil {
f.logger.Error("failed to connect to guest", "type", "udp", "guest", f.Fwd.Guest, "error", err)
conn.Close()
return err
}
}()

ctx, completed := context.WithCancel(f.Ctx)
go func() {
select {
case <-ctx.Done():
case <-f.Ctx.Done():
}
conn.Close()
}()

f.logger.Debug("initializing connection stream", "type", "udp", "fwd", f)
go f.stream(conn, target, completed, "udp", "incoming")

f.logger.Debug("activated port forward", "type", "udp", "fwd", f)
}

return nil
}

func (f *Forward) stream(incoming io.ReadCloser, outgoing io.WriteCloser, complete context.CancelFunc) {
func (f *Forward) stream(incoming io.ReadCloser, outgoing io.WriteCloser, complete context.CancelFunc, kind, direction string) {
defer incoming.Close()
defer outgoing.Close()

n, err := io.Copy(outgoing, incoming)
f.logger.Debug("connection stream complete", "fwd", f, "bytes", n, "error", err)
f.logger.Debug("connection stream complete", "direction", direction, "type", kind, "fwd", f, "bytes", n, "error", err)
complete()
}

Expand Down
7 changes: 7 additions & 0 deletions lib/vagrant-vmware-desktop/driver/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,13 @@ def forwarded_ports_by_ip(ip = nil)
h_port = fwd[:port]
f_proto = fwd[:protocol].downcase.to_sym
result[g_ip] ||= {:tcp => {}, :udp => {}}
if f_proto != :tcp && f_proto != :udp
raise Errors::PortForwardInvalidProtocol,
guest_ip: g_ip,
guest_port: g_port,
host_port: h_port,
protocol: f_proto
end
result[g_ip][f_proto][g_port] = h_port
end
if ip
Expand Down
4 changes: 4 additions & 0 deletions lib/vagrant-vmware-desktop/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ class PackageNotSupported < Base
error_key(:package_not_supported)
end

class PortForwardInvalidProtocol < Base
error_key(:port_forward_invalid_protocol)
end

class RoutingTableError < Base; end

class RoutingTableCommandNotFound < RoutingTableError
Expand Down
17 changes: 15 additions & 2 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,20 @@ en:
The "package" command is not supported with VMware. We recommend
taking a look at Packer (www.packer.io) as an option for creating
VMware images.
port_forward_invalid_protocol: |-
An invalid protocol type has been provided for a port forward
configuration. Vagrant supports port forwarding protocols values:

* udp
* tcp

Please update your port forward configuration and run the command
again. Below is the invalid port forward entry:

Guest IP: %{guest_ip}
Guest Port: %{guest_port}
Host Port: %{host_port}
Protocol: %{protocol}
routing_table_command_not_found: |-
The external program used to read TCP/IP routing tables in order
to protect you against creating network collisions could not be
Expand Down Expand Up @@ -627,8 +641,7 @@ en:
Device: %{device}
MAC: %{mac}
Reason: %{message}
disks:
disks:
cap:
disks:
floppy_not_supported: "Floppy disk configuration not yet supported. Skipping disk '%{name}'..."