@@ -89,6 +89,9 @@ type HostAgent struct {
8989 guestIPv4 net.IP
9090 guestIPv6 net.IP
9191 guestIPMu sync.RWMutex
92+ // Host IP address on the same subnet as the guest.
93+ hostIPv4 net.IP
94+ hostIPv6 net.IP
9295}
9396
9497type options struct {
@@ -542,6 +545,14 @@ func (a *HostAgent) GuestIPv6() net.IP {
542545 return a .guestIPv6
543546}
544547
548+ // HostIPs returns the host's IP addresses on the same subnet as the guest.
549+ // It returns nil if the guest is not reachable by a direct IP.
550+ func (a * HostAgent ) HostIPs () (ipv4 , ipv6 net.IP ) {
551+ a .guestIPMu .RLock ()
552+ defer a .guestIPMu .RUnlock ()
553+ return a .hostIPv4 , a .hostIPv6
554+ }
555+
545556func (a * HostAgent ) Info (_ context.Context ) (* hostagentapi.Info , error ) {
546557 guestIP := a .GuestIP ()
547558 info := & hostagentapi.Info {
@@ -800,7 +811,7 @@ func (a *HostAgent) watchGuestAgentEvents(ctx context.Context) {
800811func (a * HostAgent ) addStaticPortForwardsFromList (ctx context.Context , staticPortForwards []limatype.PortForward ) {
801812 // Since port forwarding to the guest IP directly does not require guest agent,
802813 // we can support static port forwarding if DialContextToGuestIP() returns non-nil.
803- dialContext := DialContextToGuestIP (a .GuestIP ())
814+ dialContext := a . DialContextToGuestIP (a .GuestIP ())
804815 sshAddress , sshPort := a .sshAddressPort ()
805816 for _ , rule := range staticPortForwards {
806817 if rule .GuestSocket == "" {
@@ -932,15 +943,15 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
932943 } else if ip := net .ParseIP (host ); ip .IsUnspecified () || ip .Equal (guestIPv4 ) || ip .Equal (guestIPv6 ) {
933944 if ip .To4 () != nil {
934945 if guestIPv4 != nil {
935- return DialContextToGuestIP (guestIPv4 )(ctx , network , guestAddress )
946+ return a . DialContextToGuestIP (guestIPv4 )(ctx , network , guestAddress )
936947 } else if guestIPv4 = a .GuestIPv6 ().To4 (); guestIPv4 != nil {
937- return DialContextToGuestIP (guestIPv4 )(ctx , network , guestAddress )
948+ return a . DialContextToGuestIP (guestIPv4 )(ctx , network , guestAddress )
938949 }
939950 } else if ip .To16 () != nil {
940951 if guestIPv6 != nil {
941- return DialContextToGuestIP (guestIPv6 )(ctx , network , guestAddress )
952+ return a . DialContextToGuestIP (guestIPv6 )(ctx , network , guestAddress )
942953 } else if guestIPv6 = a .GuestIPv4 ().To16 (); guestIPv6 != nil {
943- return DialContextToGuestIP (guestIPv6 )(ctx , network , guestAddress )
954+ return a . DialContextToGuestIP (guestIPv6 )(ctx , network , guestAddress )
944955 }
945956 }
946957 // If we reach here, it means we couldn't find a suitable guest IP
@@ -962,12 +973,21 @@ func (a *HostAgent) processGuestAgentEvents(ctx context.Context, client *guestag
962973
963974// DialContextToGuestIP returns a DialContext function that connects to the guest IP directly.
964975// If the guest IP is not known, it returns nil.
965- func DialContextToGuestIP (guestIP net.IP ) func (ctx context.Context , network , address string ) (net.Conn , error ) {
976+ func ( a * HostAgent ) DialContextToGuestIP (guestIP net.IP ) func (ctx context.Context , network , address string ) (net.Conn , error ) {
966977 if guestIP == nil {
967978 return nil
968979 }
980+ var sourceIP net.IP
981+ hostIPv4 , hostIPv6 := a .HostIPs ()
982+ if hostIPv4 != nil && guestIP .To4 () != nil {
983+ sourceIP = hostIPv4
984+ } else if hostIPv6 != nil && guestIP .To16 () != nil {
985+ sourceIP = hostIPv6
986+ } else {
987+ return nil
988+ }
969989 return func (ctx context.Context , network , address string ) (net.Conn , error ) {
970- var d net.Dialer
990+ d := net.Dialer { LocalAddr : & net. TCPAddr { IP : sourceIP }}
971991 _ , port , err := net .SplitHostPort (address )
972992 if err != nil {
973993 return nil , err
0 commit comments