Skip to content

Commit cdf34b0

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 3681784 commit cdf34b0

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{
@@ -891,7 +898,38 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
891898
if useSSHFwd {
892899
a.portForwarder.OnEvent(ctx, ev)
893900
} else {
894-
dialContext := portfwd.DialContextToGRPCTunnel(client)
901+
dialContext := func(ctx context.Context, network, guestAddress string) (net.Conn, error) {
902+
guestIPv4, guestIPv6 := a.GuestIPs()
903+
if guestIPv4 == nil && guestIPv6 == nil {
904+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
905+
}
906+
// Check if the host part of guestAddress is either unspecified address or matches the known guest IP.
907+
// If so, replace it with the known guest IP to avoid issues with dual-stack setups and DNS resolution.
908+
// Otherwise, fall back to the gRPC tunnel.
909+
if host, _, err := net.SplitHostPort(guestAddress); err != nil {
910+
return nil, err
911+
} else if ip := net.ParseIP(host); ip.IsUnspecified() || ip.Equal(guestIPv4) || ip.Equal(guestIPv6) {
912+
if ip.To4() != nil {
913+
if guestIPv4 != nil {
914+
conn, err := DialContextToGuestIP(guestIPv4)(ctx, network, guestAddress)
915+
if err == nil {
916+
return conn, nil
917+
}
918+
logrus.WithError(err).Warn("failed to connect to the guest IPv4 directly, falling back to gRPC tunnel")
919+
}
920+
} else if ip.To16() != nil {
921+
if guestIPv6 != nil {
922+
conn, err := DialContextToGuestIP(guestIPv6)(ctx, network, guestAddress)
923+
if err == nil {
924+
return conn, nil
925+
}
926+
logrus.WithError(err).Warn("failed to connect to the guest IPv6 directly, falling back to gRPC tunnel")
927+
}
928+
}
929+
// If we reach here, it means we couldn't find a suitable guest IP
930+
}
931+
return portfwd.DialContextToGRPCTunnel(client)(ctx, network, guestAddress)
932+
}
895933
a.grpcPortForwarder.OnEvent(ctx, dialContext, ev)
896934
}
897935
}
@@ -905,6 +943,24 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
905943
return io.EOF
906944
}
907945

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

0 commit comments

Comments
 (0)