Skip to content

Commit 78347b4

Browse files
committed
Fix Windows DNS interface configuration
1 parent 43a01d4 commit 78347b4

4 files changed

Lines changed: 47 additions & 27 deletions

File tree

lib/instances/restore.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,12 @@ func reconfigureGuestNetworkConfig(ctx context.Context, stored *StoredMetadata,
487487
if err != nil {
488488
return err
489489
}
490+
if isWindowsPlatform(stored.Platform) {
491+
cfg.dns, err = parseWindowsDNSServers(netConfig.DNS)
492+
if err != nil {
493+
return err
494+
}
495+
}
490496

491497
dialer, err := hypervisor.NewVsockDialer(stored.HypervisorType, stored.VsockSocket, stored.VsockCID)
492498
if err != nil {
@@ -570,15 +576,19 @@ func guestNetworkReconfigureConfig(netConfig *network.NetworkConfig) (*guestNetw
570576
if err != nil {
571577
return nil, err
572578
}
579+
return &guestNetworkConfig{ip: ip, mac: mac, gateway: gateway, prefix: prefix}, nil
580+
}
581+
582+
func parseWindowsDNSServers(value string) ([]string, error) {
573583
var dns []string
574-
for _, server := range strings.FieldsFunc(netConfig.DNS, func(r rune) bool { return r == ',' || r == ' ' }) {
584+
for _, server := range strings.FieldsFunc(value, func(r rune) bool { return r == ',' || r == ' ' }) {
575585
server = strings.TrimSpace(server)
576586
if net.ParseIP(server).To4() == nil {
577-
return nil, fmt.Errorf("invalid DNS server %q", server)
587+
return nil, fmt.Errorf("invalid Windows DNS server %q", server)
578588
}
579589
dns = append(dns, server)
580590
}
581-
return &guestNetworkConfig{ip: ip, mac: mac, gateway: gateway, dns: dns, prefix: prefix}, nil
591+
return dns, nil
582592
}
583593

584594
func guestNetworkReconfigureCommand(alloc *network.Allocation) (string, error) {

lib/instances/restore_egress_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,20 @@ func TestNetworkConfigFromAllocation_PreservesDNS(t *testing.T) {
3030
assert.Equal(t, alloc.TAPDevice, cfg.TAPDevice)
3131
}
3232

33-
func TestGuestNetworkReconfigureConfigParsesDNS(t *testing.T) {
33+
func TestWindowsDNSServerParsingDoesNotAffectLinuxConfig(t *testing.T) {
3434
t.Parallel()
3535

36-
cfg, err := guestNetworkReconfigureConfig(&network.NetworkConfig{
37-
IP: "10.102.146.62", MAC: "02:00:00:85:17:c8", Gateway: "10.102.0.1", Netmask: "255.255.0.0", DNS: "1.1.1.1, 8.8.8.8",
38-
})
36+
dns, err := parseWindowsDNSServers("1.1.1.1, 8.8.8.8")
3937
require.NoError(t, err)
40-
assert.Equal(t, []string{"1.1.1.1", "8.8.8.8"}, cfg.dns)
38+
assert.Equal(t, []string{"1.1.1.1", "8.8.8.8"}, dns)
39+
_, err = parseWindowsDNSServers("2606:4700:4700::1111")
40+
require.ErrorContains(t, err, "invalid Windows DNS server")
4141

42-
_, err = guestNetworkReconfigureConfig(&network.NetworkConfig{
43-
IP: "10.102.146.62", MAC: "02:00:00:85:17:c8", Gateway: "10.102.0.1", Netmask: "255.255.0.0", DNS: "not-an-address",
42+
cfg, err := guestNetworkReconfigureConfig(&network.NetworkConfig{
43+
IP: "10.102.146.62", MAC: "02:00:00:85:17:c8", Gateway: "10.102.0.1", Netmask: "255.255.0.0", DNS: "2606:4700:4700::1111",
4444
})
45-
require.ErrorContains(t, err, "invalid DNS server")
45+
require.NoError(t, err)
46+
assert.Empty(t, cfg.dns)
4647
}
4748

4849
func TestGuestNetworkReconfigureCommand_AppliesAllocatedMAC(t *testing.T) {

lib/instances/windows_networking_integration_linux_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net"
1010
"os"
1111
"os/exec"
12+
"strings"
1213
"testing"
1314
"time"
1415

@@ -83,8 +84,11 @@ func assertWindowsNetworkReady(t *testing.T, ctx context.Context, manager *manag
8384

8485
dialer, err := manager.GetVsockDialer(ctx, instanceID)
8586
require.NoError(t, err)
87+
allocation, err := manager.networkManager.GetAllocation(ctx, instanceID)
88+
require.NoError(t, err)
89+
expectedDNS := strings.Join(strings.FieldsFunc(allocation.DNS, func(r rune) bool { return r == ',' || r == ' ' }), ",")
8690
var stdout, stderr bytes.Buffer
87-
command := fmt.Sprintf("$a=Get-NetIPAddress -AddressFamily IPv4 | Where-Object IPAddress -eq '%s'; if (-not $a) { exit 20 }; [System.Net.Dns]::GetHostAddresses('example.com') | Out-Null; [Console]::Out.Write($a.IPAddress)", expectedIP)
91+
command := fmt.Sprintf("$a=Get-NetIPAddress -AddressFamily IPv4 | Where-Object IPAddress -eq '%s'; if (-not $a) { exit 20 }; $dns=@((Get-DnsClientServerAddress -InterfaceIndex $a.InterfaceIndex -AddressFamily IPv4).ServerAddresses); if (($dns -join ',') -ne '%s') { exit 21 }; [System.Net.Dns]::GetHostAddresses('example.com') | Out-Null; [Console]::Out.Write($a.IPAddress)", expectedIP, expectedDNS)
8892
exit, err := guest.ExecIntoInstance(ctx, dialer, guest.ExecOptions{
8993
Command: []string{"powershell.exe", "-NoProfile", "-NonInteractive", "-Command", command},
9094
Stdout: &stdout,

lib/system/guest_agent/network_windows.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ import (
1717
)
1818

1919
const (
20-
addressFamilyIPv4 = 2
21-
gaaFlagIncludePrefixes = 0x10
22-
dnsSettingsVersion1 = 1
23-
dnsSettingNameServer = 0x2
24-
windowsErrorBufferLarge = syscall.Errno(111)
25-
windowsErrorNotFound = syscall.Errno(1168)
20+
addressFamilyIPv4 = 2
21+
gaaFlagIncludePrefixes = 0x10
22+
dnsSettingsVersion1 = 1
23+
dnsSettingNameServer = 0x2
2624
)
2725

2826
var (
@@ -35,6 +33,7 @@ var (
3533
createForwardEntryProc = ipHelperDLL.NewProc("CreateIpForwardEntry2")
3634
deleteForwardEntryProc = ipHelperDLL.NewProc("DeleteIpForwardEntry2")
3735
setInterfaceDNSSettingsProc = ipHelperDLL.NewProc("SetInterfaceDnsSettings")
36+
convertInterfaceLuidProc = ipHelperDLL.NewProc("ConvertInterfaceLuidToGuid")
3837
)
3938

4039
type dnsInterfaceSettings struct {
@@ -80,18 +79,18 @@ func (s *guestServer) ReconfigureNetwork(ctx context.Context, req *pb.Reconfigur
8079
return nil, err
8180
}
8281
if len(req.DnsServers) > 0 {
83-
if err := configureWindowsDNS(adapter.NetworkGUID, req.DnsServers); err != nil {
82+
if err := configureWindowsDNS(adapter.InterfaceGUID, req.DnsServers); err != nil {
8483
return nil, err
8584
}
8685
}
8786
return &pb.ReconfigureNetworkResponse{}, nil
8887
}
8988

9089
type windowsAdapterInfo struct {
91-
Luid uint64
92-
Index uint32
93-
NetworkGUID windows.GUID
94-
IPv4 []net.IP
90+
Luid uint64
91+
Index uint32
92+
InterfaceGUID windows.GUID
93+
IPv4 []net.IP
9594
}
9695

9796
func waitForWindowsAdapter(ctx context.Context, mac net.HardwareAddr, name string) (*windowsAdapterInfo, error) {
@@ -119,7 +118,7 @@ func findWindowsAdapter(mac net.HardwareAddr, name string) (*windowsAdapterInfo,
119118
buffer := make([]byte, size)
120119
first := (*windows.IpAdapterAddresses)(unsafe.Pointer(&buffer[0]))
121120
err := windows.GetAdaptersAddresses(addressFamilyIPv4, gaaFlagIncludePrefixes, 0, first, &size)
122-
if err == windowsErrorBufferLarge {
121+
if err == windows.ERROR_BUFFER_OVERFLOW {
123122
continue
124123
}
125124
if err != nil {
@@ -129,7 +128,13 @@ func findWindowsAdapter(mac net.HardwareAddr, name string) (*windowsAdapterInfo,
129128
physical := net.HardwareAddr(adapter.PhysicalAddress[:adapter.PhysicalAddressLength])
130129
friendlyName := windows.UTF16PtrToString(adapter.FriendlyName)
131130
if strings.EqualFold(physical.String(), mac.String()) && (name == "" || strings.EqualFold(name, friendlyName)) {
132-
result := &windowsAdapterInfo{Luid: adapter.Luid, Index: adapter.IfIndex, NetworkGUID: adapter.NetworkGuid}
131+
result := &windowsAdapterInfo{Luid: adapter.Luid, Index: adapter.IfIndex}
132+
if code, _, _ := convertInterfaceLuidProc.Call(
133+
uintptr(unsafe.Pointer(&result.Luid)),
134+
uintptr(unsafe.Pointer(&result.InterfaceGUID)),
135+
); code != 0 {
136+
return nil, fmt.Errorf("convert Windows interface LUID to GUID: %w", syscall.Errno(code))
137+
}
133138
for address := adapter.FirstUnicastAddress; address != nil; address = address.Next {
134139
if ipv4 := address.Address.IP().To4(); ipv4 != nil {
135140
result.IPv4 = append(result.IPv4, append(net.IP(nil), ipv4...))
@@ -149,7 +154,7 @@ func configureWindowsAddresses(adapter *windowsAdapterInfo, ipv4 net.IP, prefix
149154
row.InterfaceLuid = adapter.Luid
150155
row.InterfaceIndex = adapter.Index
151156
copyRawIPv4(unsafe.Pointer(&row.Address), address)
152-
if code, _, _ := deleteUnicastAddressProc.Call(uintptr(unsafe.Pointer(&row))); code != 0 && syscall.Errno(code) != windowsErrorNotFound {
157+
if code, _, _ := deleteUnicastAddressProc.Call(uintptr(unsafe.Pointer(&row))); code != 0 && syscall.Errno(code) != windows.ERROR_NOT_FOUND {
153158
return fmt.Errorf("delete Windows IPv4 address: %w", syscall.Errno(code))
154159
}
155160
}
@@ -164,7 +169,7 @@ func configureWindowsAddresses(adapter *windowsAdapterInfo, ipv4 net.IP, prefix
164169
destination := (*windows.RawSockaddrInet4)(unsafe.Pointer(&route.DestinationPrefix.Prefix))
165170
if route.InterfaceLuid == adapter.Luid && route.DestinationPrefix.PrefixLength == 0 && destination.Addr == [4]byte{} {
166171
row := route
167-
if code, _, _ := deleteForwardEntryProc.Call(uintptr(unsafe.Pointer(&row))); code != 0 && syscall.Errno(code) != windowsErrorNotFound {
172+
if code, _, _ := deleteForwardEntryProc.Call(uintptr(unsafe.Pointer(&row))); code != 0 && syscall.Errno(code) != windows.ERROR_NOT_FOUND {
168173
return fmt.Errorf("delete Windows default route: %w", syscall.Errno(code))
169174
}
170175
}

0 commit comments

Comments
 (0)