From ff637e689a32d870f6b23acfadbbff98c75eaf1c Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Sun, 28 Dec 2003 09:09:50 +0000 Subject: [PATCH] Nameservers are now correctly listed when per adapter nameservers are specified in the registry. This now does the same thing I observe on win2k, GetNetworkParams. This function is used by our DNS query implementation to find out what nameservers it should use. There is a test case in apps/tests/nameserverlist. svn path=/trunk/; revision=7282 --- reactos/lib/iphlpapi/iphlpapi.c | 181 +++++++++++++++++++++++++++- reactos/lib/iphlpapi/ipprivate.h | 15 +++ reactos/lib/iphlpapi/ipregprivate.h | 13 ++ reactos/lib/iphlpapi/makefile | 4 +- reactos/lib/iphlpapi/registry.c | 104 ++++++++++++++++ 5 files changed, 310 insertions(+), 7 deletions(-) create mode 100644 reactos/lib/iphlpapi/ipprivate.h create mode 100644 reactos/lib/iphlpapi/ipregprivate.h create mode 100644 reactos/lib/iphlpapi/registry.c diff --git a/reactos/lib/iphlpapi/iphlpapi.c b/reactos/lib/iphlpapi/iphlpapi.c index 3e22a93cdcd..c44e23dede7 100644 --- a/reactos/lib/iphlpapi/iphlpapi.c +++ b/reactos/lib/iphlpapi/iphlpapi.c @@ -20,6 +20,8 @@ #include #include +#include "ipprivate.h" +#include "ipregprivate.h" #include "debug.h" //#include "trace.h" @@ -142,7 +144,8 @@ GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) return ERROR_INVALID_PARAMETER; ZeroMemory(pAdapterInfo, *pOutBufLen); - lErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters", 0, KEY_READ, &hAdapters); + lErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Adapters", 0, KEY_READ, &hAdapters); if(lErr != ERROR_SUCCESS) return lErr; @@ -309,7 +312,7 @@ GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG pOutBufLen) int i = 0; if ((errCode = GetNumberOfInterfaces(&dwNumIf)) != NO_ERROR) { - _tprintf(_T("GetInterfaceInfo() failed with code 0x%08X - Use FormatMessage to obtain the message string for the returned error\n"), errCode); + _tprintf(_T("GetInterfaceInfo() failed with code 0x%08X - Use FormatMessage to obtain the message string for the returned error\n"), (int)errCode); return errCode; } if (dwNumIf == 0) return ERROR_NO_DATA; // No adapter information exists for the local computer @@ -347,6 +350,123 @@ GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG pOutBufLen) return result; } +/* + * EnumNameServers + */ + +static void EnumNameServers( HANDLE RegHandle, PWCHAR Interface, + PVOID Data, EnumNameServersFunc cb ) { + PWCHAR NameServerString = QueryRegistryValueString(RegHandle, L"NameServer"); + /* Now, count the non-empty comma separated */ + if (NameServerString) { + DWORD ch; + DWORD LastNameStart = 0; + for (ch = 0; NameServerString[ch]; ch++) { + if (NameServerString[ch] == ',') { + if (ch - LastNameStart > 0) { /* Skip empty entries */ + PWCHAR NameServer = malloc(sizeof(WCHAR) * (ch - LastNameStart + 1)); + if (NameServer) { + memcpy(NameServer,NameServerString + LastNameStart, + (ch - LastNameStart) * sizeof(WCHAR)); + NameServer[ch - LastNameStart] = 0; + cb( Interface, NameServer, Data ); + free(NameServer); + } + } + LastNameStart = ch + 1; /* The first one after the comma */ + } + } + if (ch - LastNameStart > 0) { /* A last name? */ + PWCHAR NameServer = malloc(sizeof(WCHAR) * (ch - LastNameStart + 1)); + memcpy(NameServer,NameServerString + LastNameStart, + (ch - LastNameStart) * sizeof(WCHAR)); + NameServer[ch - LastNameStart] = 0; + cb( Interface, NameServer, Data ); + free(NameServer); + } + ConsumeRegValueString(NameServerString); + } +} + +/* + * EnumInterfaces + * + * Call the enumeration function for each name server. + */ + +static void EnumInterfaces( PVOID Data, EnumInterfacesFunc cb ) { + HANDLE RegHandle; + HANDLE ChildKeyHandle = 0; + PWCHAR RegKeyToEnumerate = + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; + PWCHAR ChildKeyName = 0; + DWORD CurrentInterface; + + if (OpenChildKeyRead(HKEY_LOCAL_MACHINE,RegKeyToEnumerate,&RegHandle)) { + return; + } + + for (CurrentInterface = 0; TRUE; CurrentInterface++) { + ChildKeyName = GetNthChildKeyName( RegHandle, CurrentInterface ); + if (!ChildKeyName) break; + if (OpenChildKeyRead(RegHandle,ChildKeyName, + &ChildKeyHandle) == 0) { + cb( ChildKeyHandle, ChildKeyName, Data ); + RegCloseKey( ChildKeyHandle ); + } + ConsumeChildKeyName( ChildKeyName ); + } +} + +static void CreateNameServerListEnumNamesFuncCount( PWCHAR Interface, + PWCHAR Server, + PVOID _Data ) { + PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)_Data; + Data->NumServers++; +} + +static void CreateNameServerListEnumIfFuncCount( HANDLE RegHandle, + PWCHAR InterfaceName, + PVOID _Data ) { + PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)_Data; + EnumNameServers(RegHandle,InterfaceName,Data, + CreateNameServerListEnumNamesFuncCount); +} + +static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, + PWCHAR Server, + PVOID _Data ) { + PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)_Data; + wcstombs(Data->AddrString[Data->CurrentName].IpAddress.String, + Server, + sizeof(IP_ADDRESS_STRING)); + strcpy(Data->AddrString[Data->CurrentName].IpMask.String,"0.0.0.0"); + Data->AddrString[Data->CurrentName].Context = 0; + if (Data->CurrentName < Data->NumServers - 1) { + Data->AddrString[Data->CurrentName].Next = + &Data->AddrString[Data->CurrentName+1]; + } else + Data->AddrString[Data->CurrentName].Next = 0; + + Data->CurrentName++; +} + +static void CreateNameServerListEnumIfFunc( HANDLE RegHandle, + PWCHAR InterfaceName, + PVOID _Data ) { + PNAME_SERVER_LIST_PRIVATE Data = (PNAME_SERVER_LIST_PRIVATE)_Data; + EnumNameServers(RegHandle,InterfaceName,Data, + CreateNameServerListEnumNamesFunc); +} + +static int CountNameServers( PNAME_SERVER_LIST_PRIVATE PrivateData ) { + EnumInterfaces(PrivateData,CreateNameServerListEnumIfFuncCount); + return PrivateData->NumServers; +} + +static void MakeNameServerList( PNAME_SERVER_LIST_PRIVATE PrivateData ) { + EnumInterfaces(PrivateData,CreateNameServerListEnumIfFunc); +} /* * @implemented @@ -359,17 +479,23 @@ GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen) DWORD dwSize; HKEY hKey; LONG errCode; + NAME_SERVER_LIST_PRIVATE PrivateNSEnum = { 0 }; - if (pFixedInfo == NULL || pOutBufLen == NULL) return ERROR_INVALID_PARAMETER; + CountNameServers( &PrivateNSEnum ); + + if (pOutBufLen == NULL) return ERROR_INVALID_PARAMETER; if (*pOutBufLen < sizeof(FIXED_INFO)) { - *pOutBufLen = sizeof(FIXED_INFO); + *pOutBufLen = sizeof(FIXED_INFO) + + ((PrivateNSEnum.NumServers - 1) * sizeof(IP_ADDR_STRING)); return ERROR_BUFFER_OVERFLOW; } + if (pFixedInfo == NULL) return ERROR_INVALID_PARAMETER; memset(pFixedInfo, 0, sizeof(FIXED_INFO)); - errCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &hKey); + errCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", 0, KEY_READ, &hKey); if (errCode == ERROR_SUCCESS) { dwSize = sizeof(pFixedInfo->HostName); @@ -384,6 +510,51 @@ GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen) dwSize = sizeof(pFixedInfo->EnableRouting); errCode = RegQueryValueExW(hKey, L"IPEnableRouter", NULL, NULL, (LPBYTE)&pFixedInfo->EnableRouting, &dwSize); RegCloseKey(hKey); + + /* Get the number of name servers */ + PIP_ADDR_STRING AddressAfterFixedInfo; + AddressAfterFixedInfo = (PIP_ADDR_STRING)&pFixedInfo[1]; + DWORD NumberOfServersAllowed = 0, CurrentServer = 0; + + while( &AddressAfterFixedInfo[NumberOfServersAllowed] < + (PIP_ADDR_STRING)(((PCHAR)pFixedInfo) + *pOutBufLen) ) + NumberOfServersAllowed++; + + NumberOfServersAllowed++; /* One struct is built in */ + + /* Since the first part of the struct is built in, we have to do some + fiddling */ + PrivateNSEnum.AddrString = + malloc(NumberOfServersAllowed * sizeof(IP_ADDR_STRING)); + if (PrivateNSEnum.NumServers > NumberOfServersAllowed) + PrivateNSEnum.NumServers = NumberOfServersAllowed; + MakeNameServerList( &PrivateNSEnum ); + + /* Now we have the name servers, place the first one in the struct, + and follow it with the rest */ + if (!PrivateNSEnum.NumServers) + RtlZeroMemory( &pFixedInfo->DnsServerList, sizeof(IP_ADDR_STRING) ); + else + memcpy( &pFixedInfo->DnsServerList, &PrivateNSEnum.AddrString[0], + sizeof(PrivateNSEnum.AddrString[0]) ); + pFixedInfo->CurrentDnsServer = &pFixedInfo->DnsServerList; + if (PrivateNSEnum.NumServers > 1) + memcpy( &AddressAfterFixedInfo[0], + &PrivateNSEnum.AddrString[1], + sizeof(IP_ADDR_STRING) * NumberOfServersAllowed - 1 ); + else + pFixedInfo->CurrentDnsServer->Next = 0; + + for( CurrentServer = 0; + CurrentServer < PrivateNSEnum.NumServers - 1; + CurrentServer++ ) { + pFixedInfo->CurrentDnsServer->Next = &AddressAfterFixedInfo[CurrentServer]; + pFixedInfo->CurrentDnsServer = &AddressAfterFixedInfo[CurrentServer]; + pFixedInfo->CurrentDnsServer->Next = 0; + } + /* For now, set the first server as the current server */ + pFixedInfo->CurrentDnsServer = &pFixedInfo->DnsServerList; + free(PrivateNSEnum.AddrString); } else { diff --git a/reactos/lib/iphlpapi/ipprivate.h b/reactos/lib/iphlpapi/ipprivate.h new file mode 100644 index 00000000000..d71fd6268d8 --- /dev/null +++ b/reactos/lib/iphlpapi/ipprivate.h @@ -0,0 +1,15 @@ +#ifndef IPPRIVATE_H +#define IPPRIVATE_H + +typedef void (*EnumInterfacesFunc)( HANDLE RegHandle, PWCHAR InterfaceName, + PVOID Data ); +typedef void (*EnumNameServersFunc)( PWCHAR InterfaceName, PWCHAR Server, + PVOID Data ); + +typedef struct { + int NumServers; + int CurrentName; + PIP_ADDR_STRING AddrString; +} NAME_SERVER_LIST_PRIVATE, *PNAME_SERVER_LIST_PRIVATE; + +#endif/*IPPRIVATE_H*/ diff --git a/reactos/lib/iphlpapi/ipregprivate.h b/reactos/lib/iphlpapi/ipregprivate.h new file mode 100644 index 00000000000..98b3e87654b --- /dev/null +++ b/reactos/lib/iphlpapi/ipregprivate.h @@ -0,0 +1,13 @@ +#ifndef IPREGPRIVATE_H +#define IPREGPRIVATE_H + +int GetLongestChildKeyName( HANDLE RegHandle ); +LONG OpenChildKeyRead( HANDLE RegHandle, + PWCHAR ChildKeyName, + HANDLE *ReturnHandle ); +PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ); +void ConsumeChildKeyName( PWCHAR Name ); +PWCHAR QueryRegistryValueString( HANDLE RegHandle, PWCHAR ValueName ); +void ConsumeRegValueString( PWCHAR NameServer ); + +#endif/*IPREGPRIVATE_H*/ diff --git a/reactos/lib/iphlpapi/makefile b/reactos/lib/iphlpapi/makefile index d7d38082e6a..73ae38320a9 100644 --- a/reactos/lib/iphlpapi/makefile +++ b/reactos/lib/iphlpapi/makefile @@ -11,11 +11,11 @@ TARGET_BASE = 0x777c0000 TARGET_CFLAGS = -DUNICODE -D_UNICODE # require os code to explicitly request A/W version of structs/functions -TARGET_CFLAGS += -D_DISABLE_TIDENTS -Wall -Werror +TARGET_CFLAGS += -D_DISABLE_TIDENTS -Wall -Werror -g TARGET_SDKLIBS = ntdll.a kernel32.a -TARGET_OBJECTS = $(TARGET_NAME).o +TARGET_OBJECTS = $(TARGET_NAME).o registry.o DEP_OBJECTS = $(TARGET_OBJECTS) diff --git a/reactos/lib/iphlpapi/registry.c b/reactos/lib/iphlpapi/registry.c new file mode 100644 index 00000000000..970b4d24a4b --- /dev/null +++ b/reactos/lib/iphlpapi/registry.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include "ipregprivate.h" + +#include "debug.h" + +int GetLongestChildKeyName( HANDLE RegHandle ) { + LONG Status; + DWORD MaxAdapterName; + + Status = RegQueryInfoKeyW(RegHandle, + NULL, + NULL, + NULL, + NULL, + &MaxAdapterName, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL); + if (Status == STATUS_SUCCESS) + return MaxAdapterName + 1; + else + return -1; +} + +LONG OpenChildKeyRead( HANDLE RegHandle, + PWCHAR ChildKeyName, + HANDLE *ReturnHandle ) { + return RegOpenKeyExW( RegHandle, + ChildKeyName, + 0, + KEY_READ, + ReturnHandle ); +} + +/* + * Yields a malloced value that must be freed. + */ + +PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ) { + LONG Status; + int MaxAdapterName = GetLongestChildKeyName( RegHandle ); + PWCHAR Value; + DWORD ValueLen; + + if (MaxAdapterName == -1) { + RegCloseKey( RegHandle ); + return 0; + } + + ValueLen = MaxAdapterName; + Value = (PWCHAR)malloc( MaxAdapterName * sizeof(WCHAR) ); + Status = RegEnumKeyExW( RegHandle, n, Value, &ValueLen, + NULL, NULL, NULL, NULL ); + if (Status != STATUS_SUCCESS) + return 0; + else { + Value[ValueLen] = 0; + return Value; + } +} + +void ConsumeChildKeyName( PWCHAR Name ) { + if (Name) free( Name ); +} + +PWCHAR QueryRegistryValueString( HANDLE RegHandle, PWCHAR ValueName ) { + PWCHAR Name; + DWORD ReturnedSize = 0; + + if (RegQueryValueExW( RegHandle, ValueName, NULL, NULL, NULL, + &ReturnedSize ) != 0) + return 0; + else { + Name = malloc( (ReturnedSize + 1) * sizeof(WCHAR) ); + RegQueryValueExW( RegHandle, ValueName, NULL, NULL, (PVOID)Name, + &ReturnedSize ); + Name[ReturnedSize] = 0; + return Name; + } +} + +void ConsumeRegValueString( PWCHAR Value ) { + if (Value) free(Value); +} + +PWCHAR *QueryRegistryValueStringMulti( HANDLE RegHandle, PWCHAR ValueName ) { + return 0; /* FIXME if needed */ +} + +void ConsumeRegValueStringMulti( PWCHAR *Value ) { + PWCHAR *Orig = Value; + if (Value) { + while (*Value) { + free(*Value); + } + free(Orig); + } +}