...

Source file src/k8s.io/kubernetes/pkg/kubelet/network/dns/dns_windows.go

Documentation: k8s.io/kubernetes/pkg/kubelet/network/dns

     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  }
   225  

View as plain text