1 /* 2 * iphlpapi dll implementation -- Setting and storing route information 3 * 4 * These are stubs for functions that set routing information on the target 5 * operating system. They are grouped here because their implementation will 6 * vary widely by operating system. 7 * 8 * Copyright (C) 2004 Art Yerkes 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 #include <config.h> 25 #include "iphlpapi_private.h" 26 27 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); 28 29 typedef struct _NAME_SERVER_LIST_PRIVATE { 30 UINT NumServers; 31 IP_ADDR_STRING * pCurrent; 32 } NAME_SERVER_LIST_PRIVATE, *PNAME_SERVER_LIST_PRIVATE; 33 34 typedef VOID (*ENUM_INTERFACE_CALLBACK)( 35 HKEY ChildKeyHandle, 36 LPWSTR ChildKeyName, 37 PVOID CallbackContext); 38 39 LSTATUS 40 QueryNameServer( 41 IN HKEY hInterface, 42 IN LPCWSTR NameServerKey, 43 OUT LPWSTR * OutNameServer) 44 { 45 DWORD dwLength, dwType; 46 LPWSTR NameServer; 47 LSTATUS Status; 48 49 /* query ns */ 50 dwLength = 0; 51 Status = RegQueryValueExW(hInterface, NameServerKey, NULL, &dwType, NULL, &dwLength); 52 53 if (Status != ERROR_SUCCESS) 54 { 55 /* failed to retrieve size */ 56 TRACE("Status %x\n", Status); 57 return Status; 58 } 59 60 /* add terminating null */ 61 dwLength += sizeof(WCHAR); 62 63 /* allocate name server */ 64 NameServer = HeapAlloc(GetProcessHeap(), 0, dwLength); 65 66 if (!NameServer) 67 { 68 /* no memory */ 69 return ERROR_OUTOFMEMORY; 70 } 71 72 /* query ns */ 73 Status = RegQueryValueExW(hInterface, NameServerKey, NULL, &dwType, (LPBYTE)NameServer, &dwLength); 74 75 if (Status != ERROR_SUCCESS || dwType != REG_SZ) 76 { 77 /* failed to retrieve ns */ 78 HeapFree(GetProcessHeap(), 0, NameServer); 79 return Status; 80 } 81 82 /* null terminate it */ 83 NameServer[dwLength / sizeof(WCHAR)] = L'\0'; 84 85 /* store result */ 86 *OutNameServer = NameServer; 87 88 return STATUS_SUCCESS; 89 } 90 91 92 LSTATUS 93 EnumNameServers( 94 IN HKEY hInterface, 95 IN LPWSTR InterfaceName, 96 PVOID ServerCallbackContext, 97 EnumNameServersFunc CallbackRoutine) 98 { 99 LSTATUS Status; 100 LPWSTR NameServer; 101 WCHAR Buffer[50]; 102 DWORD Length; 103 LPWSTR Start, Comma; 104 105 /* query static assigned name server */ 106 Status = QueryNameServer(hInterface, L"NameServer", &NameServer); 107 if (Status != ERROR_SUCCESS) 108 { 109 /* query dynamic assigned name server */ 110 Status = QueryNameServer(hInterface, L"DhcpNameServer", &NameServer); 111 112 if (Status != ERROR_SUCCESS) 113 { 114 /* failed to retrieve name servers */ 115 return Status; 116 } 117 } 118 119 /* enumerate all name servers, terminated by comma */ 120 Start = NameServer; 121 122 do 123 { 124 /* find next terminator */ 125 Comma = wcschr(Start, L','); 126 127 if (Comma) 128 { 129 /* calculate length */ 130 Length = Comma - Start; 131 132 /* copy name server */ 133 RtlMoveMemory(Buffer, Start, Length * sizeof(WCHAR)); 134 135 /* null terminate it */ 136 Buffer[Length] = L'\0'; 137 138 /* perform callback */ 139 CallbackRoutine(InterfaceName, Buffer, ServerCallbackContext); 140 141 } 142 else 143 { 144 /* perform callback */ 145 CallbackRoutine(InterfaceName, Start, ServerCallbackContext); 146 147 /* last entry */ 148 break; 149 } 150 151 /* increment offset */ 152 Start = Comma + 1; 153 154 }while(TRUE); 155 156 /* free name server string */ 157 HeapFree(GetProcessHeap(), 0, NameServer); 158 159 /* done */ 160 return ERROR_SUCCESS; 161 } 162 163 LSTATUS 164 EnumInterfaces( 165 ENUM_INTERFACE_CALLBACK CallbackRoutine, 166 PVOID InterfaceCallbackContext) 167 { 168 HKEY hKey, hInterface; 169 LSTATUS Status; 170 DWORD NumInterfaces, InterfaceNameLen, Index, Length; 171 LPWSTR InterfaceName; 172 173 /* first open interface key */ 174 Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces", 0, KEY_READ, &hKey); 175 176 /* check for success */ 177 if (Status != ERROR_SUCCESS) 178 { 179 /* failed to open interface key */ 180 return Status; 181 } 182 183 /* now get maximum interface name length and number of interfaces */ 184 Status = RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &NumInterfaces, &InterfaceNameLen, NULL, NULL, NULL, NULL, NULL, NULL); 185 if (Status != ERROR_SUCCESS) 186 { 187 /* failed to get key info */ 188 RegCloseKey(hKey); 189 return Status; 190 } 191 192 /* RegQueryInfoKey does not include terminating null */ 193 InterfaceNameLen++; 194 195 /* allocate interface name */ 196 InterfaceName = (LPWSTR) HeapAlloc(GetProcessHeap(), 0, InterfaceNameLen * sizeof(WCHAR)); 197 198 if (!InterfaceName) 199 { 200 /* no memory */ 201 RegCloseKey(hKey); 202 return ERROR_OUTOFMEMORY; 203 } 204 205 /* no enumerate all interfaces */ 206 for(Index = 0; Index < NumInterfaces; Index++) 207 { 208 /* query interface name */ 209 Length = InterfaceNameLen; 210 Status = RegEnumKeyExW(hKey, Index, InterfaceName, &Length, NULL, NULL, NULL, NULL); 211 212 if (Status == ERROR_SUCCESS) 213 { 214 /* make sure it is null terminated */ 215 InterfaceName[Length] = L'\0'; 216 217 /* now open child key */ 218 Status = RegOpenKeyExW(hKey, InterfaceName, 0, KEY_READ, &hInterface); 219 220 if (Status == ERROR_SUCCESS) 221 { 222 /* perform enumeration callback */ 223 CallbackRoutine(hInterface, InterfaceName, InterfaceCallbackContext); 224 225 /* close interface key */ 226 RegCloseKey(hInterface); 227 } 228 } 229 } 230 231 /* free interface name */ 232 HeapFree(GetProcessHeap(), 0, InterfaceName); 233 234 /* close root interface key */ 235 RegCloseKey(hKey); 236 237 /* done */ 238 return Status; 239 } 240 241 VOID 242 CountNameServerCallback( 243 IN LPWSTR InterfaceName, 244 IN LPWSTR Server, 245 IN PVOID CallbackContext) 246 { 247 /* get context */ 248 PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)CallbackContext; 249 250 /* increment server count */ 251 Data->NumServers++; 252 } 253 254 VOID 255 CountServerCallbackTrampoline( 256 HKEY ChildKeyHandle, 257 LPWSTR ChildKeyName, 258 PVOID CallbackContext) 259 { 260 EnumNameServers(ChildKeyHandle, ChildKeyName, CallbackContext, CountNameServerCallback); 261 } 262 263 LSTATUS 264 CountNameServers( 265 IN PNAME_SERVER_LIST_PRIVATE PrivateData ) 266 { 267 return EnumInterfaces(CountServerCallbackTrampoline, (PVOID)PrivateData); 268 } 269 270 VOID 271 CreateNameServerListCallback( 272 IN LPWSTR InterfaceName, 273 IN LPWSTR Server, 274 IN PVOID CallbackContext) 275 { 276 /* get context */ 277 PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)CallbackContext; 278 279 /* convert to ansi ns string */ 280 if (WideCharToMultiByte(CP_ACP, 0, Server, -1, Data->pCurrent->IpAddress.String, 16, NULL, NULL)) 281 { 282 /* store offset to next name server struct */ 283 Data->pCurrent->Next = (struct _IP_ADDR_STRING*)(Data->pCurrent + 1); 284 285 /* move to next entry */ 286 Data->pCurrent = Data->pCurrent->Next; 287 288 /* increment server count */ 289 Data->NumServers++; 290 } 291 else 292 { 293 /* failed to convert dns server */ 294 Data->pCurrent->IpAddress.String[0] = '\0'; 295 } 296 } 297 298 VOID 299 CreateNameServerListCallbackTrampoline( 300 HKEY ChildKeyHandle, 301 LPWSTR ChildKeyName, 302 PVOID CallbackContext) 303 { 304 EnumNameServers(ChildKeyHandle, ChildKeyName, CallbackContext, CreateNameServerListCallback); 305 } 306 307 LSTATUS 308 MakeNameServerList( 309 PNAME_SERVER_LIST_PRIVATE PrivateData ) 310 { 311 return EnumInterfaces(CreateNameServerListCallbackTrampoline, (PVOID)PrivateData); 312 } 313 314 PIPHLP_RES_INFO 315 getResInfo() 316 { 317 NAME_SERVER_LIST_PRIVATE PrivateNSEnum; 318 PIPHLP_RES_INFO ResInfo; 319 IP_ADDR_STRING * DnsList = NULL; 320 LSTATUS Status; 321 322 PrivateNSEnum.NumServers = 0; 323 324 /* count name servers */ 325 Status = CountNameServers(&PrivateNSEnum); 326 327 if (Status != ERROR_SUCCESS) 328 { 329 /* failed to enumerate name servers */ 330 return NULL; 331 } 332 333 /* are there any servers */ 334 if (PrivateNSEnum.NumServers) 335 { 336 /* allocate dns servers */ 337 DnsList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PrivateNSEnum.NumServers * sizeof(IP_ADDR_STRING)); 338 339 if (!DnsList) 340 { 341 /* no memory */ 342 return NULL; 343 } 344 } 345 346 /* allocate private struct */ 347 ResInfo = (PIPHLP_RES_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IPHLP_RES_INFO)); 348 349 if(!ResInfo) 350 { 351 /* no memory */ 352 if (DnsList) 353 { 354 /* free dns list */ 355 HeapFree( GetProcessHeap(), 0, DnsList); 356 } 357 return NULL; 358 } 359 360 /* are there any servers */ 361 if (PrivateNSEnum.NumServers) 362 { 363 /* initialize enumeration context */ 364 PrivateNSEnum.NumServers = 0; 365 PrivateNSEnum.pCurrent = DnsList; 366 367 /* enumerate servers */ 368 MakeNameServerList( &PrivateNSEnum ); 369 370 /* store result */ 371 ResInfo->DnsList = DnsList; 372 ResInfo->riCount = PrivateNSEnum.NumServers; 373 } 374 375 /* done */ 376 return ResInfo; 377 } 378 379 VOID disposeResInfo( PIPHLP_RES_INFO InfoPtr ) 380 { 381 HeapFree(GetProcessHeap(), 0, InfoPtr->DnsList); 382 RtlFreeHeap( GetProcessHeap(), 0, InfoPtr ); 383 } 384