1 /*
2  * reslist.c - get nameservers from windows *
3  *
4  * ircd-ratbox related changes are as follows
5  *
6  * Copyright (C) 2008 Aaron Sethman <androsyn@ratbox.org>
7  * Copyright (C) 2008-2012 ircd-ratbox development team
8  *
9  * pretty much all of this was yanked from c-ares ares_init.c here is the original
10  * header from there --
11  *
12  * Id: ares_init.c,v 1.72 2008-05-15 00:00:19 yangtse Exp $
13  * Copyright 1998 by the Massachusetts Institute of Technology.
14  * Copyright (C) 2007-2008 by Daniel Stenberg
15  *
16  * Permission to use, copy, modify, and distribute this
17  * software and its documentation for any purpose and without
18  * fee is hereby granted, provided that the above copyright
19  * notice appear in all copies and that both that copyright
20  * notice and this permission notice appear in supporting
21  * documentation, and that the name of M.I.T. not be used in
22  * advertising or publicity pertaining to distribution of the
23  * software without specific, written prior permission.
24  * M.I.T. makes no representations about the suitability of
25  * this software for any purpose.  It is provided "as is"
26  * without express or implied warranty.
27  *
28  *
29  */
30 
31 #ifdef _WIN32
32 #include <ratbox_lib.h>
33 
34 #include <windows.h>
35 #include <iphlpapi.h>
36 
37 const char *get_windows_nameservers(void);
38 
39 
40 #define IS_NT()        ((int)GetVersion() > 0)
41 #define WIN_NS_9X      "System\\CurrentControlSet\\Services\\VxD\\MSTCP"
42 #define WIN_NS_NT_KEY  "System\\CurrentControlSet\\Services\\Tcpip\\Parameters"
43 #define NAMESERVER     "NameServer"
44 #define DHCPNAMESERVER "DhcpNameServer"
45 #define DATABASEPATH   "DatabasePath"
46 #define WIN_PATH_HOSTS  "\\hosts"
47 
48 static int
get_iphlpapi_dns_info(char * ret_buf,size_t ret_size)49 get_iphlpapi_dns_info(char *ret_buf, size_t ret_size)
50 {
51 	FIXED_INFO *fi = alloca(sizeof(*fi));
52 	DWORD size = sizeof(*fi);
53 	typedef DWORD(WINAPI * get_net_param_func) (FIXED_INFO *, DWORD *);
54 	get_net_param_func xxGetNetworkParams;	/* available only on Win-98/2000+ */
55 	HMODULE handle;
56 	IP_ADDR_STRING *ipAddr;
57 	int i, count = 0;
58 	int debug = 0;
59 	size_t ip_size = sizeof("255.255.255.255,") - 1;
60 	size_t left = ret_size;
61 	char *ret = ret_buf;
62 	HRESULT res;
63 
64 	if(!fi)
65 		return (0);
66 
67 	handle = LoadLibrary("iphlpapi.dll");
68 	if(!handle)
69 		return (0);
70 
71 	xxGetNetworkParams = (get_net_param_func) GetProcAddress(handle, "GetNetworkParams");
72 	if(!xxGetNetworkParams)
73 		goto quit;
74 
75 	res = (*xxGetNetworkParams) (fi, &size);
76 	if((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS))
77 		goto quit;
78 
79 	fi = alloca(size);
80 	if(!fi || (*xxGetNetworkParams) (fi, &size) != ERROR_SUCCESS)
81 		goto quit;
82 
83 	if(debug)
84 	{
85 		printf("Host Name: %s\n", fi->HostName);
86 		printf("Domain Name: %s\n", fi->DomainName);
87 		printf("DNS Servers:\n" "    %s (primary)\n", fi->DnsServerList.IpAddress.String);
88 	}
89 	if(strlen(fi->DnsServerList.IpAddress.String) > 0 &&
90 	   inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE && left > ip_size)
91 	{
92 		ret += sprintf(ret, "%s,", fi->DnsServerList.IpAddress.String);
93 		left -= ret - ret_buf;
94 		count++;
95 	}
96 
97 	for(i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size;
98 	    ipAddr = ipAddr->Next, i++)
99 	{
100 		if(inet_addr(ipAddr->IpAddress.String) != INADDR_NONE)
101 		{
102 			ret += sprintf(ret, "%s,", ipAddr->IpAddress.String);
103 			left -= ret - ret_buf;
104 			count++;
105 		}
106 		if(debug)
107 			printf("    %s (secondary %d)\n", ipAddr->IpAddress.String, i + 1);
108 	}
109 
110       quit:
111 	if(handle)
112 		FreeLibrary(handle);
113 
114 	if(debug && left <= ip_size)
115 		printf("Too many nameservers. Truncating to %d addressess", count);
116 	if(ret > ret_buf)
117 		ret[-1] = '\0';
118 	return (count);
119 }
120 
121 /*
122  * Warning: returns a dynamically allocated buffer, the user MUST
123  * use free() / rb_free() if the function returns 1
124  */
125 static int
get_res_nt(HKEY hKey,const char * subkey,char ** obuf)126 get_res_nt(HKEY hKey, const char *subkey, char **obuf)
127 {
128 	/* Test for the size we need */
129 	DWORD size = 0;
130 	int result;
131 
132 	result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size);
133 	if((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size)
134 		return 0;
135 	*obuf = rb_malloc(size + 1);
136 	if(!*obuf)
137 		return 0;
138 
139 	if(RegQueryValueEx(hKey, subkey, 0, NULL, (LPBYTE) * obuf, &size) != ERROR_SUCCESS)
140 	{
141 		rb_free(*obuf);
142 		return 0;
143 	}
144 	if(size == 1)
145 	{
146 		rb_free(*obuf);
147 		return 0;
148 	}
149 	return 1;
150 }
151 
152 static int
get_res_interfaces_nt(HKEY hKey,const char * subkey,char ** obuf)153 get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf)
154 {
155 	char enumbuf[39];	/* GUIDs are 38 chars + 1 for NULL */
156 	DWORD enum_size = 39;
157 	int idx = 0;
158 	HKEY hVal;
159 
160 	while(RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0,
161 			   NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
162 	{
163 		int rc;
164 
165 		enum_size = 39;
166 		if(RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) != ERROR_SUCCESS)
167 			continue;
168 		rc = get_res_nt(hVal, subkey, obuf);
169 		RegCloseKey(hVal);
170 		if(rc)
171 			return 1;
172 	}
173 	return 0;
174 }
175 
176 const char *
get_windows_nameservers(void)177 get_windows_nameservers(void)
178 {
179 	/*
180 	   NameServer info via IPHLPAPI (IP helper API):
181 	   GetNetworkParams() should be the trusted source for this.
182 	   Available in Win-98/2000 and later. If that fail, fall-back to
183 	   registry information.
184 
185 	   NameServer Registry:
186 
187 	   On Windows 9X, the DNS server can be found in:
188 	   HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer
189 
190 	   On Windows NT/2000/XP/2003:
191 	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer
192 	   or
193 	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer
194 	   or
195 	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
196 	   NameServer
197 	   or
198 	   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\
199 	   DhcpNameServer
200 	 */
201 	static char namelist[512];
202 	HKEY mykey;
203 	HKEY subkey;
204 	DWORD data_type;
205 	DWORD bytes;
206 	DWORD result;
207 	char *line = NULL;
208 	memset(&namelist, 0, sizeof(namelist));
209 	if(get_iphlpapi_dns_info(namelist, sizeof(namelist)) > 0)
210 	{
211 		return namelist;
212 	}
213 
214 	if(IS_NT())
215 	{
216 		if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
217 				KEY_READ, &mykey) == ERROR_SUCCESS)
218 		{
219 			RegOpenKeyEx(mykey, "Interfaces", 0,
220 				     KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &subkey);
221 			if(get_res_nt(mykey, NAMESERVER, &line))
222 			{
223 				rb_strlcpy(namelist, line, sizeof(namelist));
224 				return namelist;
225 			}
226 			else if(get_res_nt(mykey, DHCPNAMESERVER, &line))
227 			{
228 				rb_strlcpy(namelist, line, sizeof(namelist));
229 				rb_free(line);
230 			}
231 			/* Try the interfaces */
232 			else if(get_res_interfaces_nt(subkey, NAMESERVER, &line))
233 			{
234 				rb_strlcpy(namelist, line, sizeof(namelist));
235 				rb_free(line);
236 			}
237 			else if(get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line))
238 			{
239 				rb_strlcpy(namelist, line, sizeof(namelist));
240 				rb_free(line);
241 			}
242 			RegCloseKey(subkey);
243 			RegCloseKey(mykey);
244 		}
245 	}
246 	else
247 	{
248 		if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0,
249 				KEY_READ, &mykey) == ERROR_SUCCESS)
250 		{
251 			if((result = RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
252 						     NULL, &bytes)) == ERROR_SUCCESS ||
253 			   result == ERROR_MORE_DATA)
254 			{
255 				if(bytes)
256 				{
257 					line = (char *)rb_malloc(bytes + 1);
258 					if(RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type,
259 							   (unsigned char *)line, &bytes) ==
260 					   ERROR_SUCCESS)
261 					{
262 						rb_strlcpy(namelist, line, sizeof(namelist));
263 					}
264 					free(line);
265 				}
266 			}
267 		}
268 		RegCloseKey(mykey);
269 	}
270 	if(strlen(namelist) > 0)
271 		return namelist;
272 	return NULL;
273 }
274 
275 
276 #endif
277