Skip to content

Commit f922a1e

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 c7764c3 commit f922a1e

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

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

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

0 commit comments

Comments
 (0)