Skip to content

Commit 2ef79c9

Browse files
committed
pkg/hostagent: Support port forwarding to direct guest IP
Change to use `github.com/inetaf/tcpproxy`: - pkg/driver/vz/vsock_forwarder.go - pkg/portfwd/client.go - pkg/portfwdserver/server.go pkg/portfwd: - Use `dialContext` instead of `client` to use `net.Conn` other than `GrpcClientRW`. - Change to create proxies from `dialContext` parameters instead of `conn`. - Add `DialContextToGRPCTunnel()` to return `DialContext` function that connects to GRPC tunnel. pkg/hostagent: - Add `HostAgent.DialContextToGuestIP()` to return `DialContext` function that connects to the guest IP directly. If the guest IP is not known, it returns nil. - Prefer `HostAgent.DialContextToGuestIP()` over `portfwd.DialContextToGRPCTunnel()`. Signed-off-by: Norio Nomura <norio.nomura@gmail.com> pkg/hostagent: Use `HostAgent.DialContextToGuestIP()` if the IP is accessible directly. Signed-off-by: Norio Nomura <norio.nomura@gmail.com> Revert to "github.com/containers/gvisor-tap-vsock/pkg/tcpproxy" Signed-off-by: Norio Nomura <norio.nomura@gmail.com> # Conflicts: # pkg/hostagent/hostagent.go pkg/hostagent: Aware forwarding guest address is IPv4 or IPv6 Signed-off-by: Norio Nomura <norio.nomura@gmail.com> pkg/hostagent: Fallback to GRPC forwarder if dialing to a direct ip fails Signed-off-by: Norio Nomura <norio.nomura@gmail.com> # Conflicts: # pkg/hostagent/hostagent.go
1 parent 9ca9f67 commit 2ef79c9

File tree

1 file changed

+57
-1
lines changed

1 file changed

+57
-1
lines changed

pkg/hostagent/hostagent.go

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,13 @@ func (a *HostAgent) GuestIP() net.IP {
531531
return nil
532532
}
533533

534+
// GuestIPs returns the guest's IPv4 and IPv6 addresses if available; otherwise nil.
535+
func (a *HostAgent) GuestIPs() (ipv4, ipv6 net.IP) {
536+
a.guestIPMu.RLock()
537+
defer a.guestIPMu.RUnlock()
538+
return a.guestIPv4, a.guestIPv6
539+
}
540+
534541
func (a *HostAgent) Info(_ context.Context) (*hostagentapi.Info, error) {
535542
guestIP := a.GuestIP()
536543
info := &hostagentapi.Info{
@@ -896,7 +903,38 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
896903
if useSSHFwd {
897904
a.portForwarder.OnEvent(ctx, ev)
898905
} else {
899-
dialContext := portfwd.DialContextToGRPCTunnel(client)
906+
dialContext := func(ctx context.Context, network, guestAddress string) (net.Conn, error) {
907+
guestIPv4, guestIPv6 := a.GuestIPs()
908+
if guestIPv4 == nil && guestIPv6 == nil {
909+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
910+
}
911+
// Check if the host part of guestAddress is either unspecified address or matches the known guest IP.
912+
// If so, replace it with the known guest IP to avoid issues with dual-stack setups and DNS resolution.
913+
// Otherwise, fall back to the gRPC tunnel.
914+
if host, _, err := net.SplitHostPort(guestAddress); err != nil {
915+
return nil, err
916+
} else if ip := net.ParseIP(host); ip.IsUnspecified() || ip.Equal(guestIPv4) || ip.Equal(guestIPv6) {
917+
if ip.To4() != nil {
918+
if guestIPv4 != nil {
919+
conn, err := DialContextToGuestIP(guestIPv4)(ctx, network, guestAddress)
920+
if err == nil {
921+
return conn, nil
922+
}
923+
logrus.WithError(err).Warn("failed to connect to the guest IPv4 directly, falling back to gRPC tunnel")
924+
}
925+
} else if ip.To16() != nil {
926+
if guestIPv6 != nil {
927+
conn, err := DialContextToGuestIP(guestIPv6)(ctx, network, guestAddress)
928+
if err == nil {
929+
return conn, nil
930+
}
931+
logrus.WithError(err).Warn("failed to connect to the guest IPv6 directly, falling back to gRPC tunnel")
932+
}
933+
}
934+
// If we reach here, it means we couldn't find a suitable guest IP
935+
}
936+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
937+
}
900938
a.grpcPortForwarder.OnEvent(ctx, dialContext, ev)
901939
}
902940
}
@@ -910,6 +948,24 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
910948
return io.EOF
911949
}
912950

951+
// DialContextToGuestIP returns a DialContext function that connects to the guest IP directly.
952+
// If the guest IP is not known, it returns nil.
953+
func DialContextToGuestIP(guestIP net.IP) func(ctx context.Context, network, address string) (net.Conn, error) {
954+
if guestIP == nil {
955+
return nil
956+
}
957+
return func(ctx context.Context, network, address string) (net.Conn, error) {
958+
var d net.Dialer
959+
_, port, err := net.SplitHostPort(address)
960+
if err != nil {
961+
return nil, err
962+
}
963+
// Host part of address is ignored, because it already has been checked by forwarding rules
964+
// and we want to connect to the guest IP directly.
965+
return d.DialContext(ctx, network, net.JoinHostPort(guestIP.String(), port))
966+
}
967+
}
968+
913969
const (
914970
verbForward = "forward"
915971
verbCancel = "cancel"

0 commit comments

Comments
 (0)