k8s.io/kubernetes@v1.29.3/pkg/kubelet/network/dns/dns_windows.go (about) 1 //go:build windows 2 // +build windows 3 4 /* 5 Copyright 2023 The Kubernetes Authors. 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18 */ 19 20 package dns 21 22 import ( 23 "fmt" 24 "os" 25 "strings" 26 "syscall" 27 "unsafe" 28 29 "golang.org/x/sys/windows" 30 "golang.org/x/sys/windows/registry" 31 runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" 32 "k8s.io/klog/v2" 33 ) 34 35 const ( 36 netRegistry = `System\CurrentControlSet\Services\TCPIP\Parameters` 37 netIfacesRegistry = `System\CurrentControlSet\Services\TCPIP\Parameters\Interfaces` 38 maxHostnameLen = 128 39 maxDomainNameLen = 128 40 maxScopeIDLen = 256 41 42 // getHostDNSConfig will return the host's DNS configuration if the given resolverConfig argument 43 // is set to "Host". 44 hostResolvConf = "Host" 45 ) 46 47 // FixedInfo information: https://docs.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-fixed_info_w2ksp1 48 type FixedInfo struct { 49 HostName [maxHostnameLen + 4]byte 50 DomainName [maxDomainNameLen + 4]byte 51 CurrentDNSServer *syscall.IpAddrString 52 DNSServerList syscall.IpAddrString 53 NodeType uint32 54 ScopeID [maxScopeIDLen + 4]byte 55 EnableRouting uint32 56 EnableProxy uint32 57 EnableDNS uint32 58 } 59 60 var ( 61 // GetNetworkParams can be found in iphlpapi.dll 62 // see: https://docs.microsoft.com/windows/win32/api/iphlpapi/nf-iphlpapi-getnetworkparams 63 iphlpapidll = windows.MustLoadDLL("iphlpapi.dll") 64 procGetNetworkParams = iphlpapidll.MustFindProc("GetNetworkParams") 65 ) 66 67 func fileExists(filename string) (bool, error) { 68 stat, err := os.Stat(filename) 69 if os.IsNotExist(err) { 70 return false, nil 71 } 72 if err != nil { 73 return false, err 74 } 75 76 return stat.Mode().IsRegular(), nil 77 } 78 79 func getHostDNSConfig(resolverConfig string) (*runtimeapi.DNSConfig, error) { 80 if resolverConfig == "" { 81 // This handles "" by returning defaults. 82 return getDNSConfig(resolverConfig) 83 } 84 85 isFile, err := fileExists(resolverConfig) 86 if err != nil { 87 err = fmt.Errorf(`Unexpected error while getting os.Stat for "%s" resolver config. Error: %w`, resolverConfig, err) 88 klog.ErrorS(err, "Cannot get host DNS Configuration.") 89 return nil, err 90 } 91 if isFile { 92 // Get the DNS config from a resolv.conf-like file. 93 return getDNSConfig(resolverConfig) 94 } 95 96 if resolverConfig != hostResolvConf { 97 err := fmt.Errorf(`Unexpected resolver config value: "%s". Expected "", "%s", or a path to an existing resolv.conf file.`, resolverConfig, hostResolvConf) 98 klog.ErrorS(err, "Cannot get host DNS Configuration.") 99 return nil, err 100 } 101 102 // If we get here, the resolverConfig == hostResolvConf and that is not actually a file, so 103 // it means to use the host settings. 104 // Get host DNS settings 105 hostDNS, err := getDNSServerList() 106 if err != nil { 107 err = fmt.Errorf("Could not get the host's DNS Server List. Error: %w", err) 108 klog.ErrorS(err, "Encountered error while getting host's DNS Server List.") 109 return nil, err 110 } 111 hostSearch, err := getDNSSuffixList() 112 if err != nil { 113 err = fmt.Errorf("Could not get the host's DNS Suffix List. Error: %w", err) 114 klog.ErrorS(err, "Encountered error while getting host's DNS Suffix List.") 115 return nil, err 116 } 117 return &runtimeapi.DNSConfig{ 118 Servers: hostDNS, 119 Searches: hostSearch, 120 }, nil 121 } 122 123 func elemInList(elem string, list []string) bool { 124 for _, e := range list { 125 if e == elem { 126 return true 127 } 128 } 129 return false 130 } 131 132 func getRegistryStringValue(reg, key string) (string, error) { 133 regKey, err := registry.OpenKey(registry.LOCAL_MACHINE, reg, registry.QUERY_VALUE) 134 if err != nil { 135 return "", err 136 } 137 defer regKey.Close() 138 139 regValue, _, err := regKey.GetStringValue(key) 140 return regValue, err 141 } 142 143 // getDNSSuffixList reads DNS config file and returns the list of configured DNS suffixes 144 func getDNSSuffixList() ([]string, error) { 145 // We start with the general suffix list that apply to all network connections. 146 allSuffixes := []string{} 147 suffixes, err := getRegistryStringValue(netRegistry, "SearchList") 148 if err != nil { 149 return nil, err 150 } 151 allSuffixes = strings.Split(suffixes, ",") 152 153 // Then we append the network-specific DNS suffix lists. 154 regKey, err := registry.OpenKey(registry.LOCAL_MACHINE, netIfacesRegistry, registry.ENUMERATE_SUB_KEYS) 155 if err != nil { 156 return nil, err 157 } 158 defer regKey.Close() 159 160 ifaces, err := regKey.ReadSubKeyNames(0) 161 if err != nil { 162 return nil, err 163 } 164 for _, iface := range ifaces { 165 suffixes, err := getRegistryStringValue(fmt.Sprintf("%s\\%s", netIfacesRegistry, iface), "SearchList") 166 if err != nil { 167 return nil, err 168 } 169 if suffixes == "" { 170 continue 171 } 172 for _, suffix := range strings.Split(suffixes, ",") { 173 if !elemInList(suffix, allSuffixes) { 174 allSuffixes = append(allSuffixes, suffix) 175 } 176 } 177 } 178 179 return allSuffixes, nil 180 } 181 182 func getNetworkParams() (*FixedInfo, error) { 183 // We don't know how big we should make the byte buffer, but the call will tell us by 184 // setting the size afterwards. 185 var size int = 1 186 buffer := make([]byte, 1) 187 ret, _, err := procGetNetworkParams.Call( 188 uintptr(unsafe.Pointer(&buffer[0])), 189 uintptr(unsafe.Pointer(&size)), 190 ) 191 if ret != uintptr(syscall.ERROR_BUFFER_OVERFLOW) { 192 err = fmt.Errorf("Unexpected return value %d from GetNetworkParams. Expected: %d. Error: %w", ret, syscall.ERROR_BUFFER_OVERFLOW, err) 193 return nil, err 194 } 195 196 buffer = make([]byte, size) 197 ret, _, err = procGetNetworkParams.Call( 198 uintptr(unsafe.Pointer(&buffer[0])), 199 uintptr(unsafe.Pointer(&size)), 200 ) 201 if ret != 0 { 202 err = fmt.Errorf("Unexpected return value %d from GetNetworkParams. Expected: 0. Error: %w", ret, err) 203 return nil, err 204 } 205 206 info := (*FixedInfo)(unsafe.Pointer(&buffer[0])) 207 return info, nil 208 } 209 210 func getDNSServerList() ([]string, error) { 211 dnsServerList := []string{} 212 fixedInfo, err := getNetworkParams() 213 if err != nil { 214 return nil, err 215 } 216 217 list := &(fixedInfo.DNSServerList) 218 for list != nil { 219 dnsServer := strings.TrimRight(string(list.IpAddress.String[:]), "\x00") 220 dnsServerList = append(dnsServerList, dnsServer) 221 list = list.Next 222 } 223 return dnsServerList, nil 224 }