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
This commit is contained in:
Art Yerkes 2003-12-28 09:09:50 +00:00
parent 4aa9677fa4
commit ff637e689a
5 changed files with 310 additions and 7 deletions

View file

@ -20,6 +20,8 @@
#include <iphlpapi.h>
#include <icmpapi.h>
#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
{

View file

@ -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*/

View file

@ -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*/

View file

@ -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)

View file

@ -0,0 +1,104 @@
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#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);
}
}