golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/conf/dnsresolver_windows.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package conf
     7  
     8  import (
     9  	"log"
    10  	"net/netip"
    11  	"time"
    12  	"unsafe"
    13  
    14  	"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
    15  
    16  	"golang.org/x/sys/windows"
    17  	"golang.zx2c4.com/wireguard/windows/services"
    18  )
    19  
    20  func resolveHostname(name string) (resolvedIPString string, err error) {
    21  	maxTries := 10
    22  	if services.StartedAtBoot() {
    23  		maxTries *= 3
    24  	}
    25  	for i := 0; i < maxTries; i++ {
    26  		if i > 0 {
    27  			time.Sleep(time.Second * 4)
    28  		}
    29  		resolvedIPString, err = resolveHostnameOnce(name)
    30  		if err == nil {
    31  			return
    32  		}
    33  		if err == windows.WSATRY_AGAIN {
    34  			log.Printf("Temporary DNS error when resolving %s, so sleeping for 4 seconds", name)
    35  			continue
    36  		}
    37  		if err == windows.WSAHOST_NOT_FOUND && services.StartedAtBoot() {
    38  			log.Printf("Host not found when resolving %s at boot time, so sleeping for 4 seconds", name)
    39  			continue
    40  		}
    41  		return
    42  	}
    43  	return
    44  }
    45  
    46  func resolveHostnameOnce(name string) (resolvedIPString string, err error) {
    47  	hints := windows.AddrinfoW{
    48  		Family:   windows.AF_UNSPEC,
    49  		Socktype: windows.SOCK_DGRAM,
    50  		Protocol: windows.IPPROTO_IP,
    51  	}
    52  	var result *windows.AddrinfoW
    53  	name16, err := windows.UTF16PtrFromString(name)
    54  	if err != nil {
    55  		return
    56  	}
    57  	err = windows.GetAddrInfoW(name16, nil, &hints, &result)
    58  	if err != nil {
    59  		return
    60  	}
    61  	if result == nil {
    62  		err = windows.WSAHOST_NOT_FOUND
    63  		return
    64  	}
    65  	defer windows.FreeAddrInfoW(result)
    66  	var v6 netip.Addr
    67  	for ; result != nil; result = result.Next {
    68  		if result.Family != windows.AF_INET && result.Family != windows.AF_INET6 {
    69  			continue
    70  		}
    71  		addr := (*winipcfg.RawSockaddrInet)(unsafe.Pointer(result.Addr)).Addr()
    72  		if addr.Is4() {
    73  			return addr.String(), nil
    74  		} else if !v6.IsValid() && addr.Is6() {
    75  			v6 = addr
    76  		}
    77  	}
    78  	if v6.IsValid() {
    79  		return v6.String(), nil
    80  	}
    81  	err = windows.WSAHOST_NOT_FOUND
    82  	return
    83  }
    84  
    85  func (config *Config) ResolveEndpoints() error {
    86  	for i := range config.Peers {
    87  		if config.Peers[i].Endpoint.IsEmpty() {
    88  			continue
    89  		}
    90  		var err error
    91  		config.Peers[i].Endpoint.Host, err = resolveHostname(config.Peers[i].Endpoint.Host)
    92  		if err != nil {
    93  			return err
    94  		}
    95  	}
    96  	return nil
    97  }