summaryrefslogtreecommitdiff
path: root/tools/network/dnssec/config_windows.go
blob: 5772d10b1b4626434c7a49c6a1229a769e3580f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (C) 2019-2024 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand.  If not, see <https://www.gnu.org/licenses/>.

//go:build windows
// +build windows

package dnssec

import (
	"fmt"
	"time"
	"unsafe"

	"golang.org/x/sys/windows"
)

var (
	dll               = windows.NewLazyDLL("iphlpapi.dll")
	networkParamsProc = dll.NewProc("GetNetworkParams")
)

// values from https://referencesource.microsoft.com/#System/net/System/Net/NetworkInformation/UnSafeNetInfoNativemethods.cs,c5dd09342271faba,references
const (
	max_hostname_len    = 128
	max_domain_name_len = 128
	max_scope_id_len    = 256
)

const ip_size = 16

//	typedef struct _IP_ADDR_STRING {
//		struct _IP_ADDR_STRING *Next;
//		IP_ADDRESS_STRING      IpAddress;  // The String member is a char array of size 16. This array holds an IPv4 address in dotted decimal notation.
//		IP_MASK_STRING         IpMask;     // The String member is a char array of size 16. This array holds the IPv4 subnet mask in dotted decimal notation.
//		DWORD                  Context;
//	  } IP_ADDR_STRING, *PIP_ADDR_STRING;
//
// https://docs.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-ip_addr_string
type ipAddrString struct {
	Next      uintptr
	IpAddress [ip_size]uint8
	IpMask    [ip_size]uint8
	Context   uint32
}

//	typedef struct {
//		char            HostName[MAX_HOSTNAME_LEN + 4];
//		char            DomainName[MAX_DOMAIN_NAME_LEN + 4];
//		PIP_ADDR_STRING CurrentDnsServer;
//		IP_ADDR_STRING  DnsServerList;
//		UINT            NodeType;
//		char            ScopeId[MAX_SCOPE_ID_LEN + 4];
//		UINT            EnableRouting;
//		UINT            EnableProxy;
//		UINT            EnableDns;
//	  } FIXED_INFO_W2KSP1, *PFIXED_INFO_W2KSP1;
//
// https://docs.microsoft.com/en-us/windows/win32/api/iptypes/ns-iptypes-fixed_info_w2ksp1
type fixedInfo struct {
	HostName         [max_hostname_len + 4]uint8
	DomainName       [max_domain_name_len + 4]uint8
	CurrentDnsServer uintptr
	DnsServerList    ipAddrString
	NodeType         uint32
	ScopeId          [max_scope_id_len + 4]uint8
	EnableRouting    uint32
	EnableProxy      uint32
	EnableDns        uint32
}

const ipAddrStringSizeof = 48

type fixedInfoWithOverlay struct {
	fixedInfo
	overlay [ipAddrStringSizeof * 32]uint8 // space for max 32 IP_ADDR_STRING entries in the overlay
}

// SystemConfig return list of DNS servers from Windows configuration
//
// See GetNetworkParams for details:
// https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getnetworkparams
func SystemConfig() (servers []ResolverAddress, timeout time.Duration, err error) {
	ulSize := uint32(unsafe.Sizeof(fixedInfoWithOverlay{}))

	buf, err := windows.LocalAlloc(windows.LMEM_FIXED|windows.LMEM_ZEROINIT, ulSize)
	if err != nil {
		err = fmt.Errorf("GetNetworkParams failed to allocate %d bytes of memory for fixedInfoWithOverlay", ulSize)
		return
	}

	defer windows.LocalFree(windows.Handle(buf))

	ret, _, _ := networkParamsProc.Call(
		buf,
		uintptr(unsafe.Pointer(&ulSize)),
	)
	if ret != 0 {
		if windows.Errno(ret) == windows.ERROR_BUFFER_OVERFLOW {
			err = fmt.Errorf("GetNetworkParams requested %d bytes of memory, max supported is %d. Error code is %x", ulSize, unsafe.Sizeof(fixedInfoWithOverlay{}), ret)
			return
		}
		err = fmt.Errorf("GetNetworkParams failed with code is %x", ret)
		return
	}

	fi := (*fixedInfoWithOverlay)(unsafe.Pointer(buf))

	var p *ipAddrString = &fi.DnsServerList
	for {
		ip := make([]byte, ip_size)
		for i := 0; i < len(p.IpAddress) && p.IpAddress[i] != 0; i++ {
			ip[i] = p.IpAddress[i]
		}
		servers = append(servers, MakeResolverAddress(string(ip), "53"))

		if p.Next == 0 {
			break
		}
		p = (*ipAddrString)(unsafe.Pointer(p.Next))
	}
	timeout = DefaultTimeout
	return
}