Skip to content

Commit b72864f

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 fc5a2ec commit b72864f

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
@@ -526,6 +526,13 @@ func (a *HostAgent) GuestIP() net.IP {
526526
return nil
527527
}
528528

529+
// GuestIPs returns the guest's IPv4 and IPv6 addresses if available; otherwise nil.
530+
func (a *HostAgent) GuestIPs() (ipv4, ipv6 net.IP) {
531+
a.guestIPMu.RLock()
532+
defer a.guestIPMu.RUnlock()
533+
return a.guestIPv4, a.guestIPv6
534+
}
535+
529536
func (a *HostAgent) Info(_ context.Context) (*hostagentapi.Info, error) {
530537
guestIP := a.GuestIP()
531538
info := &hostagentapi.Info{
@@ -885,7 +892,38 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
885892
if useSSHFwd {
886893
a.portForwarder.OnEvent(ctx, ev)
887894
} else {
888-
dialContext := portfwd.DialContextToGRPCTunnel(client)
895+
dialContext := func(ctx context.Context, network, guestAddress string) (net.Conn, error) {
896+
guestIPv4, guestIPv6 := a.GuestIPs()
897+
if guestIPv4 == nil && guestIPv6 == nil {
898+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
899+
}
900+
// Check if the host part of guestAddress is either unspecified address or matches the known guest IP.
901+
// If so, replace it with the known guest IP to avoid issues with dual-stack setups and DNS resolution.
902+
// Otherwise, fall back to the gRPC tunnel.
903+
if host, _, err := net.SplitHostPort(guestAddress); err != nil {
904+
return nil, err
905+
} else if ip := net.ParseIP(host); ip.IsUnspecified() || ip.Equal(guestIPv4) || ip.Equal(guestIPv6) {
906+
if ip.To4() != nil {
907+
if guestIPv4 != nil {
908+
conn, err := DialContextToGuestIP(guestIPv4)(ctx, network, guestAddress)
909+
if err == nil {
910+
return conn, nil
911+
}
912+
logrus.WithError(err).Warn("failed to connect to the guest IPv4 directly, falling back to gRPC tunnel")
913+
}
914+
} else if ip.To16() != nil {
915+
if guestIPv6 != nil {
916+
conn, err := DialContextToGuestIP(guestIPv6)(ctx, network, guestAddress)
917+
if err == nil {
918+
return conn, nil
919+
}
920+
logrus.WithError(err).Warn("failed to connect to the guest IPv6 directly, falling back to gRPC tunnel")
921+
}
922+
}
923+
// If we reach here, it means we couldn't find a suitable guest IP
924+
}
925+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
926+
}
889927
a.grpcPortForwarder.OnEvent(ctx, dialContext, ev)
890928
}
891929
}
@@ -899,6 +937,24 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
899937
return io.EOF
900938
}
901939

940+
// DialContextToGuestIP returns a DialContext function that connects to the guest IP directly.
941+
// If the guest IP is not known, it returns nil.
942+
func DialContextToGuestIP(guestIP net.IP) func(ctx context.Context, network, address string) (net.Conn, error) {
943+
if guestIP == nil {
944+
return nil
945+
}
946+
return func(ctx context.Context, network, address string) (net.Conn, error) {
947+
var d net.Dialer
948+
_, port, err := net.SplitHostPort(address)
949+
if err != nil {
950+
return nil, err
951+
}
952+
// Host part of address is ignored, because it already has been checked by forwarding rules
953+
// and we want to connect to the guest IP directly.
954+
return d.DialContext(ctx, network, net.JoinHostPort(guestIP.String(), port))
955+
}
956+
}
957+
902958
const (
903959
verbForward = "forward"
904960
verbCancel = "cancel"

0 commit comments

Comments
 (0)