Skip to content

Commit f22a2f0

Browse files
committed
pkg/hostagent: Set LocalAddr to net.Dialer in DialContextToGuestIP()
Signed-off-by: Norio Nomura <[email protected]>
1 parent fcf679f commit f22a2f0

File tree

3 files changed

+60
-13
lines changed

3 files changed

+60
-13
lines changed

hack/test-templates.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ function diagnose() {
153153
cp -pf "$HOME_HOST/.lima/${NAME}"/*.log failure-logs/
154154
limactl shell "$NAME" sudo cat /var/log/cloud-init-output.log | tee failure-logs/cloud-init-output.log
155155
limactl shell "$NAME" sh -c "command -v journalctl >/dev/null && sudo journalctl -b --no-pager" >failure-logs/journal.log
156+
netstat -rn
156157
set +x -e
157158
}
158159

pkg/hostagent/hostagent.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

9497
type 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+
545556
func (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) {
800811
func (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,30 @@ 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+
var sourceAddr net.Addr
991+
switch network {
992+
case "tcp", "tcp4", "tcp6":
993+
sourceAddr = &net.TCPAddr{IP: sourceIP}
994+
case "udp", "udp4", "udp6":
995+
sourceAddr = &net.UDPAddr{IP: sourceIP}
996+
default:
997+
return nil, fmt.Errorf("unsupported network %q", network)
998+
}
999+
d := net.Dialer{LocalAddr: sourceAddr}
9711000
_, port, err := net.SplitHostPort(address)
9721001
if err != nil {
9731002
return nil, err

pkg/hostagent/requirements.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -321,19 +321,36 @@ func (a *HostAgent) detectGuestIfnameOnSameSubnetAtHost(stdout string) error {
321321
if err != nil {
322322
return fmt.Errorf("failed to get network interfaces: %w", err)
323323
}
324+
var (
325+
guestIfnameOnSameSubnetAsHost string
326+
hostIPv4 net.IP
327+
hostIPv6 net.IP
328+
)
324329
for _, neighbor := range neighbors {
325330
for _, ifi := range interfaces {
326331
if ifi.HardwareAddr.String() != neighbor.LLADDR {
327332
continue
328333
}
329-
a.guestIPMu.Lock()
330-
a.guestIfnameOnSameSubnetAsHost = neighbor.DEV
331-
a.guestIPMu.Unlock()
332-
logrus.Infof("Detected the guest has interface %q in same subnet on the host", neighbor.DEV)
333-
return nil
334+
guestIfnameOnSameSubnetAsHost = neighbor.DEV
335+
if hostIP := net.ParseIP(neighbor.DST); hostIP.To4() != nil {
336+
hostIPv4 = hostIP
337+
} else if hostIP.To16() != nil {
338+
hostIPv6 = hostIP
339+
}
334340
}
335341
}
336-
logrus.Info("The guest does not have interface in same subnet on the host")
342+
a.guestIPMu.Lock()
343+
a.guestIfnameOnSameSubnetAsHost = guestIfnameOnSameSubnetAsHost
344+
a.hostIPv4 = hostIPv4
345+
a.hostIPv6 = hostIPv6
346+
a.guestIPMu.Unlock()
347+
logrus.Infof("Detected the guest has interface %q in same subnet on the host", guestIfnameOnSameSubnetAsHost)
348+
if hostIPv4 != nil {
349+
logrus.Infof("The host IPv4 address on the same subnet as the guest is %q", hostIPv4)
350+
}
351+
if hostIPv6 != nil {
352+
logrus.Infof("The host IPv6 address on the same subnet as the guest is %q", hostIPv6)
353+
}
337354
return nil
338355
}
339356

0 commit comments

Comments
 (0)