|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name: //KERNEL/RAZZLE3/src/sockets/tcpcmd/ipconfigext/ipcfgdll/ipconfig.c
SYNOPSIS: IPCFGDLL.DLL exports routines
Abstract:
Author: Richard L Firth (rfirth) 05-Feb-1994
Revision History:
05-Feb-1994 rfirth Created
04-Mar-1994 rfirth * Pick non-Dhcp registry values if DHCP not enabled * TCP and IP have been consolidated
27-Apr-1994 rfirth * added /release and /renew
06-Aug-1994 rfirth * Get IP address values from TCP/IP stack, not registry
30-Apr-97 MohsinA * Cleaning up for NT50.
17-Jan-98 RameshV * Removed ScopeId display as new UI does not have this... * Made ReadRegistryIpAddrString read both MULTI_SZ and REG_SZ * Changed domainname and Dns server list from global to per-adapter * Display DhcpServer only if address is NOT autoconfigured.. * AutoconfigEnabled is decided based on regval "AddressType" * Friendly names stubs are used.... * Error codes are converted first thru system library..
06-Mar-98 chunye * Made this a DLL for support IPHLPAPI etc. --*/
#include "precomp.h"
#include "ipcfgmsg.h"
#include <iprtrmib.h>
#include <ws2tcpip.h> // for in6addr_any
#include <ntddip.h>
#include <ntddip6.h>
#include <iphlpstk.h>
#include <nhapi.h>
#pragma warning(push)
#pragma warning(disable:4200)
#pragma warning(disable:4201)
#pragma warning(disable:4214)
#include <netconp.h>
#pragma warning(pop)
//
// manifests
//
#define DEVICE_PREFIX "\\Device\\"
#define TCPIP_DEVICE_PREFIX "\\Device\\Tcpip_"
const CHAR c_szDevice[] = "\\Device\\"; const CHAR c_szDeviceTcpip[] = "\\Device\\Tcpip_"; const WCHAR c_szDeviceNdiswanIp[] = L"\\Device\\NdiswanIp";
#define INITIAL_CAPABILITY 0x00000001
#define TCPIP_CAPABILITY 0x00000002
#define NETBT_CAPABILITY 0x00000004
#define STRING_ARRAY_DELIMITERS " \t,;"
#define MSG_NO_MESSAGE 0
#define KEY_TCP 1
#define KEY_NBT 2
#define KEY_TCP6 3
#define BNODE BROADCAST_NODETYPE
#define PNODE PEER_TO_PEER_NODETYPE
#define MNODE MIXED_NODETYPE
#define HNODE HYBRID_NODETYPE
#ifdef DBG
#define SET_DHCP_MODE 1
#define SET_AUTO_MODE 2
#endif
// ========================================================================
// macros
// ========================================================================
#define REG_OPEN_KEY(_hKey, _lpSubKey, _phkResult) \
RegOpenKeyEx(_hKey, _lpSubKey, 0, KEY_READ, _phkResult)
#define ALIGN_DOWN(length, type) \
((ULONG)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP(length, type) \
(ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
#define ALIGN_DOWN_PTR(length, type) \
((ULONG_PTR)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP_PTR(length, type) \
(ALIGN_DOWN_PTR(((ULONG_PTR)(length) + sizeof(type) - 1), type))
// ========================================================================
// types
// ========================================================================
typedef struct { DWORD Message; LPSTR String; } MESSAGE_STRING, *PMESSAGE_STRING;
#define MAX_STRING_LIST_LENGTH 32 // arbitrary
// ========================================================================
// macros
// ========================================================================
// #define IS_ARG(c) (((c) == '-') || ((c) == '/'))
// #define ReleaseMemory(p) LocalFree((HLOCAL)(p))
// #define MAP_YES_NO(i) ((i) ? MISC_MESSAGE(MI_YES) : MISC_MESSAGE(MI_NO))
#define ZERO_IP_ADDRESS(a) !strcmp((a), "0.0.0.0")
// ========================================================================
// prototypes
// ========================================================================
BOOL Initialize(PDWORD); VOID LoadMessages(VOID); VOID LoadMessageTable(PMESSAGE_STRING, UINT); BOOL ConvertOemToUnicode(LPSTR, LPWSTR);
BOOL WriteRegistryDword(HKEY hKey, LPSTR szParameter, DWORD *pdwValue ); BOOL WriteRegistryMultiString(HKEY, LPSTR, LPSTR);
static BOOL OpenAdapterKey(DWORD, const LPSTR, REGSAM, PHKEY); BOOL MyReadRegistryDword(HKEY, LPSTR, LPDWORD); BOOL ReadRegistryString(HKEY, LPSTR, LPSTR, LPDWORD); BOOL ReadRegistryOemString(HKEY, LPWSTR, LPSTR, LPDWORD); BOOL ReadRegistryIpAddrString(HKEY, LPSTR, PIP_ADDR_STRING); BOOL GetDnsServerList(PIP_ADDR_STRING);
LPSTR* GetBoundAdapterList(HKEY); LPSTR MapNodeType(UINT); LPSTR MapNodeTypeEx(UINT); LPSTR MapAdapterType(UINT); LPSTR MapAdapterTypeEx(UINT); LPSTR MapAdapterAddress(PIP_ADAPTER_INFO, LPSTR); LPSTR MapTime(PIP_ADAPTER_INFO, DWORD_PTR); LPSTR MapTimeEx(PIP_ADAPTER_INFO, DWORD_PTR); LPSTR MapScopeId(PVOID); VOID KillFixedInfo(PFIXED_INFO); VOID KillPerAdapterInfo(PIP_PER_ADAPTER_INFO); VOID KillAdapterAddresses(PIP_ADAPTER_ADDRESSES);
VOID Terminate(VOID); LPVOID GrabMemory(DWORD); VOID DisplayMessage(BOOL, DWORD, ...);
BOOL IsIncluded(DWORD Context, DWORD contextlist[], int len_contextlist); BOOL ReadRegistryList(HKEY Key, LPSTR ParameterName, DWORD NumList[], int *MaxList);
DWORD GetIgmpList(DWORD NTEAddr, DWORD *pIgmpList, PULONG dwOutBufLen); DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE, PULONG, BOOL);
// ========================================================================
// data
// ========================================================================
HKEY TcpipLinkageKey = INVALID_HANDLE_VALUE; HKEY TcpipParametersKey = INVALID_HANDLE_VALUE; HKEY NetbtParametersKey = INVALID_HANDLE_VALUE; HKEY NetbtInterfacesKey = INVALID_HANDLE_VALUE; // PHRLANCONNECTIONNAMEFROMGUIDORPATH HrLanConnectionNameFromGuid = NULL;
// HANDLE hNetMan = NULL;
//
// Note: The following variable caches whether IPv6 was installed and running
// at the time GetAdaptersAddresses() was called. If multiple threads
// are calling GetAdaptersAddresses() during an install/uninstall, its
// value may change. However, this is not really a problem. The set of
// IPv6 DNS server addresses may or may not be present on an interface,
// but this is the same as the behavior of the set of IPv6 addresses, which
// doesn't use this variable.
//
BOOL bIp6DriverInstalled;
#ifdef DBG
UINT uChangeMode = 0; #endif
#define FIELD_JUSTIFICATION_TEXT " "
// ========================================================================
// MESSAGE_STRING arrays - contain internationalizable strings loaded from this
// module. If a load error occurs, we use the English language defaults
// ========================================================================
LPSTR NodeTypesEx[] = { "", "Broadcast", "Peer-Peer", "Mixed", "Hybrid" };
MESSAGE_STRING NodeTypes[] = { MSG_NO_MESSAGE, TEXT(""), MSG_BNODE, TEXT("Broadcast"), MSG_PNODE, TEXT("Peer-Peer"), MSG_MNODE, TEXT("Mixed"), MSG_HNODE, TEXT("Hybrid") };
#define NUMBER_OF_NODE_TYPES (sizeof(NodeTypes)/sizeof(NodeTypes[0]))
#define FIRST_NODE_TYPE 1
#define LAST_NODE_TYPE 4
LPSTR AdapterTypesEx[] = { "Other", "Ethernet", "Token Ring", "FDDI", "PPP", "Loopback", "SLIP" };
MESSAGE_STRING AdapterTypes[] = { MSG_IF_TYPE_OTHER, TEXT("Other"), MSG_IF_TYPE_ETHERNET, TEXT("Ethernet"), MSG_IF_TYPE_TOKEN_RING, TEXT("Token Ring"), MSG_IF_TYPE_FDDI, TEXT("FDDI"), MSG_IF_TYPE_PPP, TEXT("PPP"), MSG_IF_TYPE_LOOPBACK, TEXT("Loopback"), MSG_IF_TYPE_SLIP, TEXT("SLIP") };
#define NUMBER_OF_ADAPTER_TYPES (sizeof(AdapterTypes)/sizeof(AdapterTypes[0]))
MESSAGE_STRING MiscMessages[] = { MSG_YES, TEXT("Yes"), MSG_NO, TEXT("No"), MSG_INIT_FAILED, TEXT("Failed to initialize"), MSG_TCP_NOT_RUNNING, TEXT("TCP/IP is not running on this system"), MSG_REG_BINDINGS_ERROR, TEXT("Cannot access adapter bindings registry key"), MSG_REG_INCONSISTENT_ERROR, TEXT("Inconsistent registry contents"), MSG_TCP_BINDING_ERROR, TEXT("TCP/IP not bound to any adapters"), MSG_MEMORY_ERROR, TEXT("Allocating memory"), MSG_ALL, TEXT("all"), MSG_RELEASE, TEXT("Release"), MSG_RENEW, TEXT("Renew"), MSG_ACCESS_DENIED, TEXT("Access Denied"), MSG_SERVER_UNAVAILABLE, TEXT("DHCP Server Unavailable"), MSG_ADDRESS_CONFLICT, TEXT("The DHCP client obtained an address that is already in use on the network.") };
#define NUMBER_OF_MISC_MESSAGES (sizeof(MiscMessages)/sizeof(MiscMessages[0]))
#define MISC_MESSAGE(i) MiscMessages[i].String
#define ADAPTER_TYPE(i) AdapterTypes[i].String
#define ADAPTER_TYPE_EX(i) AdapterTypesEx[i]
#define MI_IF_OTHER 0
#define MI_IF_ETHERNET 1
#define MI_IF_TOKEN_RING 2
#define MI_IF_FDDI 3
#define MI_IF_PPP 4
#define MI_IF_LOOPBACK 5
#define MI_IF_SLIP 6
#define MI_YES 0
#define MI_NO 1
#define MI_INIT_FAILED 2
#define MI_TCP_NOT_RUNNING 3
#define MI_REG_BINDINGS_ERROR 4
#define MI_REG_INCONSISTENT_ERROR 5
#define MI_TCP_BINDINGS_ERROR 6
#define MI_MEMORY_ERROR 7
#define MI_ALL 8
#define MI_RELEASE 9
#define MI_RENEW 10
#define MI_ACCESS_DENIED 11
#define MI_SERVER_UNAVAILABLE 12
#define MI_ADDRESS_CONFLICT 13
//
// Debugging
//
#if defined(DEBUG)
BOOL Debugging = FALSE; int MyTrace = 0;
#endif
// ========================================================================
// functions
// ========================================================================
BOOL IpcfgdllInit( HINSTANCE hInstDll, DWORD fdwReason, LPVOID pReserved ) {
DWORD capability;
UNREFERENCED_PARAMETER(hInstDll); UNREFERENCED_PARAMETER(pReserved);
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
// DisableThreadLibraryCalls(hInstDll);
//
// load all possible internationalizable strings
//
LoadMessages();
//
// what debug version is this?
//
DEBUG_PRINT(("IpcfgdllInit" __DATE__ " " __TIME__ "\n"));
//
// opens all the required registry keys
//
if (!Initialize(&capability)) {
LPSTR str = NULL;
//
// exit if we couldn't open the registry services key or
// IP or TCP keys.
// We will continue if the NetBT key couldn't be opened
//
if (!(capability & INITIAL_CAPABILITY)) {
str = MISC_MESSAGE(MI_INIT_FAILED);
} else if (!(capability & TCPIP_CAPABILITY)) {
str = MISC_MESSAGE(MI_TCP_NOT_RUNNING);
}
if (str) {
//DisplayMessage(FALSE, MSG_ERROR_STRING, str);
Terminate(); return FALSE;
} }
break;
case DLL_PROCESS_DETACH:
Terminate(); break;
default:
break;
}
return TRUE; }
/*******************************************************************************
* * Initialize * * Opens all the required registry keys * * ENTRY Capability * Pointer to returned set of capabilities (bitmap) * * EXIT *Capability * INITIAL_CAPABILITY * * TCPIP_CAPABILITY * we could open the Tcpip\Linkage and Tcpip\Parameters keys * TcpipLinkageKey and TcpipParametersKey contain the open handles * * NETBT_CAPABILITY * we could open the NetBT\Parameters key * NetbtInterfacesKey contains the open handle * * * RETURNS TRUE = success * FALSE = failure * * ASSUMES * ******************************************************************************/
#define TCPIP_LINKAGE_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Linkage"
#define TCPIP_PARAMS_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\"
#define TCPIP_PARAMS_INTER_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
#define TCPIP6_PARAMS_INTER_KEY "SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces\\"
#define NETBT_PARAMS_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters"
#define NETBT_INTERFACE_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters\\Interfaces"
#define NETBT_ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Services\\NetBT\\Adapters\\"
BOOL Initialize(PDWORD Capability) {
LONG err; char * name;
*Capability = INITIAL_CAPABILITY;
name = TCPIP_LINKAGE_KEY; TRACE_PRINT(("Initialize: RegOpenKey TcpipLinkageKey %s\n", name )); err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &TcpipLinkageKey );
if (err == ERROR_SUCCESS) {
*Capability |= TCPIP_CAPABILITY;
name = TCPIP_PARAMS_KEY; TRACE_PRINT(("Initialize: RegOpenKey TcpipParametersKey %s\n", name )); err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &TcpipParametersKey );
if (err == ERROR_SUCCESS) {
name = NETBT_INTERFACE_KEY; TRACE_PRINT(("Initialize: RegOpenKey NetbtInterfacesKey %s\n", name )); err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &NetbtInterfacesKey );
if (err == ERROR_SUCCESS) { *Capability |= NETBT_CAPABILITY; } else { NetbtInterfacesKey = INVALID_HANDLE_VALUE; } } else { *Capability &= ~TCPIP_CAPABILITY; TcpipParametersKey = INVALID_HANDLE_VALUE; } } else { TcpipLinkageKey = INVALID_HANDLE_VALUE; }
// =======================================================
name = NETBT_PARAMS_KEY; TRACE_PRINT(("Initialize: RegOpenKey NetbtParametersKey %s.\n", name )); err = REG_OPEN_KEY(HKEY_LOCAL_MACHINE, name, &NetbtParametersKey ); // ======================================================
if( err != ERROR_SUCCESS ){ DEBUG_PRINT(("Initialize: RegOpenKey %s failed, err=%d\n", name, GetLastError() )); }
TRACE_PRINT(("Initialize RegOpenKey ok: \n" " TcpipLinkageKey = %p\n" " TcpipParametersKey = %p\n" " NetbtInterfacesKey = %p\n" " NetbtParametersKey = %p\n", TcpipLinkageKey, TcpipParametersKey, NetbtInterfacesKey, NetbtParametersKey ));
return err == ERROR_SUCCESS; }
/*******************************************************************************
* * LoadMessages * * Loads all internationalizable messages into the various tables * * ENTRY * * EXIT AdapterTypes, MiscMessages updated * * RETURNS * * ASSUMES * * COHESION Temporal * ******************************************************************************/
VOID LoadMessages() { LoadMessageTable(NodeTypes, NUMBER_OF_NODE_TYPES); LoadMessageTable(AdapterTypes, NUMBER_OF_ADAPTER_TYPES); LoadMessageTable(MiscMessages, NUMBER_OF_MISC_MESSAGES); }
/*******************************************************************************
* * LoadMessageTable * * Loads internationalizable strings into a table, replacing the default for * each. If an error occurs, the English language default is left in place * * ENTRY Table * Pointer to table containing message ID and pointer to string * * MessageCount * Number of messages in Table * * EXIT Table updated * * RETURNS * * ASSUMES * ******************************************************************************/
VOID LoadMessageTable(PMESSAGE_STRING Table, UINT MessageCount) {
LPSTR string; DWORD count;
//
// for all messages in a MESSAGE_STRING table, load the string from this
// module, replacing the default string in the table (only there in case
// we get an error while loading the string, so we at least have English
// to fall back on)
//
while (MessageCount--) { if (Table->Message != MSG_NO_MESSAGE) {
//
// we really want LoadString here, but LoadString doesn't indicate
// how big the string is, so it doesn't give us an opportunity to
// allocate exactly the right buffer size. FormatMessage does the
// right thing
//
count = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, NULL, // use default hModule
Table->Message, 0, // use default language
(LPTSTR)&string, 0, // minimum size to allocate
NULL // no arguments for inclusion in strings
); if (count) {
//
// Format message returned the string: replace the English
// language default
//
Table->String = string; } else {
DEBUG_PRINT(("FormatMessage(%d) failed: %d\n", Table->Message, GetLastError()));
//
// this is ok if there is no string (e.g. just %0) in the .mc
// file
//
Table->String = ""; } } ++Table; } }
/*******************************************************************************
* * ConvertOemToUnicode * * Title says it all. Required because DhcpAcquireParameters etc. require the * adapter name to be UNICODE * * ENTRY OemString * Pointer to ANSI/OEM string to convert * * UnicodeString * Pointer to place to store converted results * * EXIT UnicodeString contains converted string if successful * * RETURNS TRUE - it worked * FALSE - it failed * * ASSUMES * ******************************************************************************/
BOOL ConvertOemToUnicode(LPSTR OemString, LPWSTR UnicodeString) {
OEM_STRING oString; UNICODE_STRING uString;
RtlInitString(&oString, OemString); uString.Buffer = UnicodeString; uString.MaximumLength = (USHORT)RtlOemStringToUnicodeSize(&oString); if (NT_SUCCESS(RtlOemStringToUnicodeString(&uString, &oString, FALSE))) { return TRUE; } return FALSE; }
/*******************************************************************************
* * GetFixedInfo * * Retrieves the fixed information we wish to display by querying it from the * various registry keys * * ENTRY nothing * * EXIT nothing * * RETURNS pointer to allocated FIXED_INFO structure * * ASSUMES * ******************************************************************************/
PFIXED_INFO GetFixedInfo() { PFIXED_INFO fixedInfo = NEW(FIXED_INFO);
TRACE_PRINT(("Entered GetFixedInfo\n"));
if (fixedInfo) {
DWORD length; BOOL ok;
length = sizeof(fixedInfo->HostName); ok = ReadRegistryOemString(TcpipParametersKey, L"Hostname", fixedInfo->HostName, &length );
//
// domain: first try Domain then DhcpDomain
//
length = sizeof(fixedInfo->DomainName); ok = ReadRegistryOemString(TcpipParametersKey, L"Domain", fixedInfo->DomainName, &length ); if (!ok) { length = sizeof(fixedInfo->DomainName); ok = ReadRegistryOemString(TcpipParametersKey, L"DhcpDomain", fixedInfo->DomainName, &length ); }
//
// DNS Server list: first try NameServer and then DhcpNameServer
//
#if 0
ok = ReadRegistryIpAddrString(TcpipParametersKey, TEXT("NameServer"), &fixedInfo->DnsServerList ); if (ok) { TRACE_PRINT(("GetFixedInfo: NameServer %s\n", fixedInfo->DnsServerList )); }
if (!ok) { ok = ReadRegistryIpAddrString(TcpipParametersKey, TEXT("DhcpNameServer"), &fixedInfo->DnsServerList ); if (ok) { TRACE_PRINT(("GetFixedInfo: DhcpNameServer %s\n", fixedInfo->DnsServerList)); } } #else
ok = GetDnsServerList(&fixedInfo->DnsServerList); if (ok) { TRACE_PRINT(("GetFixedInfo: DnsServerList %s\n", fixedInfo->DnsServerList.IpAddress.String)); } #endif
//
// NodeType: static then DHCP
//
ok = MyReadRegistryDword(NetbtParametersKey, TEXT("NodeType"), (LPDWORD)&fixedInfo->NodeType ); if (!ok) { ok = MyReadRegistryDword(NetbtParametersKey, TEXT("DhcpNodeType"), (LPDWORD)&fixedInfo->NodeType ); }
//
// ScopeId: static then DHCP
//
length = sizeof(fixedInfo->ScopeId); ok = ReadRegistryString(NetbtParametersKey, TEXT("ScopeId"), fixedInfo->ScopeId, &length ); if (!ok) { length = sizeof(fixedInfo->ScopeId); ok = ReadRegistryString(NetbtParametersKey, TEXT("DhcpScopeId"), fixedInfo->ScopeId, &length ); } ok = MyReadRegistryDword(TcpipParametersKey, TEXT("IPEnableRouter"), (LPDWORD)&fixedInfo->EnableRouting ); ok = MyReadRegistryDword(NetbtParametersKey, TEXT("EnableProxy"), (LPDWORD)&fixedInfo->EnableProxy ); ok = MyReadRegistryDword(NetbtParametersKey, TEXT("EnableDNS"), (LPDWORD)&fixedInfo->EnableDns ); }else{ DEBUG_PRINT(("No memory for fixedInfo\n")); }
TRACE_PRINT(("Exit GetFixedInfo @ %p\n", fixedInfo ));
return fixedInfo; }
/*******************************************************************************
* * GetAdapterNameToIndexInfo * * Gets the mapping between IP if_index and AdapterName. * * RETURNS pointer to a PIP_INTERFACE_INFO structure that has been allocated. * ******************************************************************************/
PIP_INTERFACE_INFO GetAdapterNameToIndexInfo( VOID ) { PIP_INTERFACE_INFO pInfo; ULONG dwSize, dwError;
dwSize = 0; pInfo = NULL;
for (;;) {
dwError = GetInterfaceInfo( pInfo, &dwSize ); if( (ERROR_INSUFFICIENT_BUFFER != dwError) && (ERROR_BUFFER_OVERFLOW != dwError) ) break;
if( NULL != pInfo ) ReleaseMemory(pInfo); if( 0 == dwSize ) return NULL;
pInfo = GrabMemory(dwSize); if( NULL == pInfo ) return NULL;
}
if( ERROR_SUCCESS != dwError || 0 == pInfo->NumAdapters ) { if( NULL != pInfo ) ReleaseMemory(pInfo); return NULL; }
return pInfo; }
/*******************************************************************************
* * GetAdapterInfo * * Gets a list of all adapters to which TCP/IP is bound and reads the per- * adapter information that we want to display. Most of the information now * comes from the TCP/IP stack itself. In order to keep the 'short' names that * exist in the registry to refer to the individual adapters, we read the names * from the registry then match them to the adapters returned by TCP/IP by * matching the IPInterfaceContext value with the adapter which owns the IP * address with that context value * * ENTRY nothing * * EXIT nothing * * RETURNS pointer to linked list of IP_ADAPTER_INFO structures * * ASSUMES * ******************************************************************************/
PIP_ADAPTER_INFO GetAdapterInfo(VOID) {
PIP_ADAPTER_INFO adapterList; PIP_ADAPTER_INFO adapter; PIP_INTERFACE_INFO currentAdapterNames; int i;
HKEY key;
TRACE_PRINT(("Entered GetAdapterInfo\n"));
if ((currentAdapterNames = GetAdapterNameToIndexInfo()) != NULL) { if ((adapterList = GetAdapterList()) != NULL) {
//
// apply the short name to the right adapter info by comparing
// the IPInterfaceContext value in the adapter\Parameters\Tcpip
// section with the context values read from the stack for the
// IP addresses
//
for (i = 0; i < currentAdapterNames->NumAdapters; ++i) { SIZE_T dwLength; DWORD dwIfIndex = currentAdapterNames->Adapter[i].Index;
TRACE_PRINT(("currentAdapterNames[%d]=%ws (if_index 0x%lx)\n", i, currentAdapterNames->Adapter[i].Name, dwIfIndex ));
//
// now search through the list of adapters, looking for the one
// that has the IP address with the same index value as that
// just read. When found, apply the short name to that adapter
//
for (adapter = adapterList; adapter ; adapter = adapter->Next ) {
if( adapter->Index == dwIfIndex ) {
dwLength = wcslen(currentAdapterNames->Adapter[i].Name) + 1 - strlen(TCPIP_DEVICE_PREFIX); dwLength = wcstombs(adapter->AdapterName, currentAdapterNames->Adapter[i].Name + strlen(TCPIP_DEVICE_PREFIX), dwLength); if( -1 == dwLength ) { adapter->AdapterName[0] = '\0'; }
break; }
} } } else { DEBUG_PRINT(("GetAdapterInfo: GetAdapterInfo gave NULL\n")); } ReleaseMemory(currentAdapterNames);
//
// now get the other pieces of info from the registry for each adapter
//
for (adapter = adapterList; adapter; adapter = adapter->Next) {
TRACE_PRINT(("GetAdapterInfo: '%s'\n", adapter->AdapterName ));
if (adapter->AdapterName[0] && OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
char dhcpServerAddress[4 * 4]; DWORD addressLength;
MyReadRegistryDword(key, TEXT("EnableDHCP"), (LPDWORD)&adapter->DhcpEnabled );
TRACE_PRINT(("..'EnableDHCP' %d\n", adapter->DhcpEnabled ));
#ifdef DBG
if ( uChangeMode ) { DWORD dwAutoconfigEnabled = ( uChangeMode == SET_AUTO_MODE );
WriteRegistryDword( key, "IPAutoconfigurationEnabled", &dwAutoconfigEnabled ); } #endif
if (adapter->DhcpEnabled) { DWORD Temp; MyReadRegistryDword(key, TEXT("LeaseObtainedTime"), &Temp );
adapter->LeaseObtained = Temp;
MyReadRegistryDword(key, TEXT("LeaseTerminatesTime"), &Temp );
adapter->LeaseExpires = Temp; }
addressLength = sizeof( dhcpServerAddress ); if (ReadRegistryString(key, TEXT("DhcpServer"), dhcpServerAddress, &addressLength )) { AddIpAddressString(&adapter->DhcpServer, dhcpServerAddress, "" ); }
RegCloseKey(key);
} else {
DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n", adapter->AdapterName, GetLastError())); }
//
// get the info from the NetBT key - the WINS addresses
//
GetWinsServers(adapter); }
} else {
DEBUG_PRINT(("GetAdapterInfo: GetBoundAdapterList gave NULL\n")); adapterList = NULL; }
TRACE_PRINT(("Exit GetAdapterInfo %p\n", adapterList));
return adapterList; }
/*******************************************************************************
* AddIPv6UnicastAddressInfo * * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address * to a list of entries. * * ENTRY IF - IPv6 interface information * ADE - IPv6 address entry * ppNext - Previous unicast entry's "next" pointer to update * * EXIT Entry added and args updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6UnicastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_UNICAST_ADDRESS **ppNext) { DWORD dwErr = NO_ERROR; PIP_ADAPTER_UNICAST_ADDRESS pCurr; SOCKADDR_IN6 *pAddr;
UNREFERENCED_PARAMETER(IF);
ASSERT(ADE->Type == ADE_UNICAST);
pCurr = MALLOC(sizeof(IP_ADAPTER_UNICAST_ADDRESS)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN6)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN6)); pAddr->sin6_family = AF_INET6; pAddr->sin6_scope_id = ADE->ScopeId; memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
pCurr->Next = NULL; pCurr->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS); pCurr->ValidLifetime = ADE->ValidLifetime; pCurr->PreferredLifetime = ADE->PreferredLifetime; pCurr->LeaseLifetime = 0xFFFFFFFF; pCurr->Flags = 0; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6); pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr; pCurr->PrefixOrigin = ADE->PrefixConf; pCurr->SuffixOrigin = ADE->InterfaceIdConf; pCurr->DadState = ADE->DADState;
// Only use DDNS on auto-configured addresses
// (either auto-configured by the system or from an RA)
// but NOT temporary addresses.
// Also do not use DDNS on link-local addresses
// or the loopback address.
if ((ADE->DADState == DAD_STATE_PREFERRED) && (pCurr->SuffixOrigin != IpSuffixOriginRandom) && !IN6_IS_ADDR_LOOPBACK(&ADE->This.Address) && !IN6_IS_ADDR_LINKLOCAL(&ADE->This.Address)) { pCurr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE; }
return dwErr; }
/*******************************************************************************
* AddIPv6AnycastAddressInfo * * This routine adds an IP_ADAPTER_ANYCAST_ADDRESS entry for an IPv6 address * to a list of entries. * * ENTRY IF - IPv6 interface information * ADE - IPv6 address entry * ppNext - Previous anycast entry's "next" pointer to update * * EXIT Entry added and args updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6AnycastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_ANYCAST_ADDRESS **ppNext) { DWORD dwErr = NO_ERROR; PIP_ADAPTER_ANYCAST_ADDRESS pCurr; SOCKADDR_IN6 *pAddr;
UNREFERENCED_PARAMETER(IF);
ASSERT(ADE->Type == ADE_ANYCAST);
pCurr = MALLOC(sizeof(IP_ADAPTER_ANYCAST_ADDRESS)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN6)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN6)); pAddr->sin6_family = AF_INET6; pAddr->sin6_scope_id = ADE->ScopeId; memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
pCurr->Next = NULL; pCurr->Length = sizeof(IP_ADAPTER_ANYCAST_ADDRESS); pCurr->Flags = 0; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6); pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr; }
/*******************************************************************************
* AddIPv6MulticastAddressInfo * * This routine adds an IP_ADAPTER_MULTICAST_ADDRESS entry for an IPv6 address * to a list of entries. * * ENTRY IF - IPv6 interface information * ADE - IPv6 address entry * ppNext - Previous multicast entry's "next" pointer to update * * EXIT Entry added and args updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6MulticastAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PIP_ADAPTER_MULTICAST_ADDRESS **ppNext) { DWORD dwErr = NO_ERROR; PIP_ADAPTER_MULTICAST_ADDRESS pCurr; SOCKADDR_IN6 *pAddr;
UNREFERENCED_PARAMETER(IF);
ASSERT(ADE->Type == ADE_MULTICAST);
pCurr = MALLOC(sizeof(IP_ADAPTER_MULTICAST_ADDRESS)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN6)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN6)); pAddr->sin6_family = AF_INET6; pAddr->sin6_scope_id = ADE->ScopeId; memcpy(&pAddr->sin6_addr, &ADE->This.Address, sizeof(ADE->This.Address));
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
pCurr->Next = NULL; pCurr->Length = sizeof(IP_ADAPTER_MULTICAST_ADDRESS); pCurr->Flags = 0; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6); pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr; }
/*******************************************************************************
* AddIPv6AddressInfo * * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address * to a list of entries. * * ENTRY IF - IPv6 interface information * ADE - IPv6 address entry * arg1 - Previous unicast entry's "next" pointer to update * arg2 - Previous anycast entry's "next" pointer to update * arg3 - Previous multicast entry's "next" pointer to update * arg4 - Unused * Flags - Flags specified by application * Family - Address family constraint (for DNS server addresses) * * EXIT Entry added and args updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6AddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, DWORD Family) { UNREFERENCED_PARAMETER(Family); UNREFERENCED_PARAMETER(arg4);
switch (ADE->Type) { case ADE_UNICAST: if (Flags & GAA_FLAG_SKIP_UNICAST) { return NO_ERROR; } return AddIPv6UnicastAddressInfo(IF, ADE, (PIP_ADAPTER_UNICAST_ADDRESS**)arg1); case ADE_ANYCAST: if (Flags & GAA_FLAG_SKIP_ANYCAST) { return NO_ERROR; } return AddIPv6AnycastAddressInfo(IF, ADE, (PIP_ADAPTER_ANYCAST_ADDRESS**)arg2); case ADE_MULTICAST: if (Flags & GAA_FLAG_SKIP_MULTICAST) { return NO_ERROR; } return AddIPv6MulticastAddressInfo(IF, ADE, (PIP_ADAPTER_MULTICAST_ADDRESS**)arg3); default: ASSERT(0); } return NO_ERROR; }
/*******************************************************************************
* ForEachIPv6Address * * This routine walks a set of IPv6 addresses and invokes a given function * on each one. * * ENTRY IF - IPv6 interface information * func - Function to invoke on each address * arg1 - Argument to pass to func * arg2 - Argument to pass to func * arg3 - Argument to pass to func * arg4 - Argument to pass to func * Flags - Flags to pass to func * Family - Address family constraint (for DNS server addresses) * * EXIT Nothing * * RETURNS Error status * ******************************************************************************/
DWORD ForEachIPv6Address( IPV6_INFO_INTERFACE *IF, DWORD (*func)(IPV6_INFO_INTERFACE *,IPV6_INFO_ADDRESS *, PVOID, PVOID, PVOID, PVOID, DWORD, DWORD), PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, DWORD Family) { IPV6_QUERY_ADDRESS Query; IPV6_INFO_ADDRESS ADE; DWORD BytesReturned, BytesIn; DWORD dwErr;
Query.IF = IF->This; Query.Address = in6addr_any;
for (;;) { BytesIn = sizeof Query; BytesReturned = sizeof ADE;
dwErr = WsControl( IPPROTO_IPV6, IOCTL_IPV6_QUERY_ADDRESS, &Query, &BytesIn, &ADE, &BytesReturned);
if (dwErr != NO_ERROR) { return dwErr; }
if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) {
dwErr = (*func)(IF, &ADE, arg1, arg2, arg3, arg4, Flags, Family); if (dwErr != NO_ERROR) { return dwErr; } }
if (IN6_ADDR_EQUAL(&ADE.Next.Address, &in6addr_any)) break; Query = ADE.Next; }
return NO_ERROR; }
/*******************************************************************************
* MapIpv4AddressToName * * This routine finds the name and description of the adapter which * has a given IPv4 address on it. * * ENTRY pAdapterInfo - Buffer obtained from GetAdaptersInfo * Ipv4Address - IPv4 address to search for * pDescription - Where to place a pointer to the description text * * EXIT pDescription updated, if found * * RETURNS Adapter name, or NULL if not found * ******************************************************************************/
LPSTR MapIpv4AddressToName(IP_ADAPTER_INFO *pAdapterInfo, DWORD Ipv4Address, PCHAR *pDescription) { IP_ADAPTER_INFO *pAdapter; IP_ADDR_STRING *pAddr;
for (pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) {
for (pAddr = &pAdapter->IpAddressList; pAddr; pAddr=pAddr->Next) { if (inet_addr(pAddr->IpAddress.String) == Ipv4Address) { *pDescription = pAdapter->Description; return pAdapter->AdapterName; } } }
return NULL; }
#define GUID_FORMAT_A "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}"
/*******************************************************************************
* ConvertGuidToStringA * * This routine converts a GUID to a character string. * * ENTRY pGuid - Contains the GUID to translate. * pszBuffer - Space for storing the string. * Must be >= 39 * sizeof(CHAR). * * EXIT pszBuffer updated * * RETURNS Whatever sprintf returns * ******************************************************************************/
DWORD ConvertGuidToStringA(GUID *pGuid, PCHAR pszBuffer) { return sprintf(pszBuffer, GUID_FORMAT_A, pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]); }
/*******************************************************************************
* ConvertStringToGuidA * * This routine converts a character string to a GUID. * * ENTRY pszGuid - Contains the string to translate * pGuid - Space for storing the GUID * * EXIT pGuid updated * * RETURNS Error status * ******************************************************************************/
DWORD ConvertStringToGuidA(PCHAR pszGuid, GUID *pGuid) { UNICODE_STRING Temp; WCHAR wszGuid[40+1];
MultiByteToWideChar(CP_ACP, 0, pszGuid, -1, wszGuid, 40);
RtlInitUnicodeString(&Temp, wszGuid); if(RtlGUIDFromString(&Temp, pGuid) != STATUS_SUCCESS) { return ERROR_INVALID_PARAMETER; }
return NO_ERROR; }
/*******************************************************************************
* MapGuidToAdapterName * * This routine gets an adapter name and description, given a GUID. * * ENTRY pAdapterInfo - Buffer obtained from GetAdaptersInfo * Guid - GUID of the adapter * pwszDescription - Buffer in which to place description text. * Must be at least MAX_ADAPTER_DESCRIPTION_LENGTH * WCHAR's long. * * EXIT pwszDescription buffer filled in, if found * * RETURNS Adapter name, or NULL if not found * ******************************************************************************/
LPSTR MapGuidToAdapterName(IP_ADAPTER_INFO *pAdapterInfo, GUID *Guid, PWCHAR pwszDescription) { IP_ADAPTER_INFO *pAdapter; CHAR szGuid[40];
ConvertGuidToStringA(Guid, szGuid);
for (pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) {
if (!strcmp(szGuid, pAdapter->AdapterName)) { MultiByteToWideChar(CP_ACP, 0, pAdapter->Description, -1, pwszDescription, MAX_ADAPTER_DESCRIPTION_LENGTH); return pAdapter->AdapterName; } }
pwszDescription[0] = L'\0'; return NULL; }
/*******************************************************************************
* AddDnsServerAddressInfo * * This routine adds an IP_ADAPTER_DNS_SERVER_ADDRESS entry for an address * to a list of entries. * * ENTRY IF - interface information * Addr - Address in sockaddr format * AddrLen- Size of sockaddr * pFirst - First DNS server entry * ppNext - Previous DNS server entry's "next" pointer to update * * EXIT Entry added and args updated * * RETURNS Error status * ******************************************************************************/
DWORD AddDnsServerAddressInfo(PIP_ADAPTER_DNS_SERVER_ADDRESS **ppNext, LPSOCKADDR Addr, SIZE_T AddrLen) { DWORD dwErr = NO_ERROR; PIP_ADAPTER_DNS_SERVER_ADDRESS pCurr; LPSOCKADDR pAddr;
pCurr = MALLOC(sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(AddrLen); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memcpy(pAddr, Addr, AddrLen);
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
pCurr->Next = NULL; pCurr->Length = sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS); pCurr->Address.iSockaddrLength = (INT)AddrLen; pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr; }
/*******************************************************************************
* GetAdapterDnsServers * * This routine reads a list of DNS server addresses from a registry key. * * ENTRY TcpipKey - Registry key to look under * pCurr - Interface entry to add servers to * * EXIT Entry updated * * RETURNS Error status * ******************************************************************************/
DWORD GetAdapterDnsServers(HKEY TcpipKey, PIP_ADAPTER_ADDRESSES pCurr) { DWORD Size, Type, dwErr, i; CHAR Servers[800], *Str; PIP_ADAPTER_DNS_SERVER_ADDRESS *ppDNext; ADDRINFO hints, *ai; static LONG Initialized = FALSE;
if (InterlockedExchange(&Initialized, TRUE) == FALSE) { WSADATA WsaData;
dwErr = WSAStartup(MAKEWORD(2, 0), &WsaData); if (NO_ERROR != dwErr) { return dwErr; } }
//
// Read DNS Server addresses.
//
Size = sizeof(Servers); ZeroMemory(Servers, Size); dwErr = RegQueryValueExA(TcpipKey, (LPSTR)"NameServer", NULL, &Type, (LPBYTE)Servers, &Size); if (NO_ERROR != dwErr) { if (ERROR_FILE_NOT_FOUND != dwErr) { return dwErr; } Size = 0; Type = REG_SZ; }
if (REG_SZ != Type) { return ERROR_INVALID_DATA; } if ((0 == Size) || (0 == strlen(Servers))) { Size = sizeof(Servers); dwErr = RegQueryValueExA(TcpipKey, (LPSTR)"DhcpNameServer", NULL, &Type, (LPBYTE)Servers, &Size); if (NO_ERROR != dwErr) { if (ERROR_FILE_NOT_FOUND != dwErr) { return dwErr; } Size = 0; Type = REG_SZ; } }
//
// If there are any DNS Servers, convert them to sockaddrs
//
ZeroMemory(&hints, sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; ppDNext = &pCurr->FirstDnsServerAddress; while (*ppDNext) { ppDNext = &(*ppDNext)->Next; } if ((0 != Size) && strlen(Servers)) { for (i = 0; i < Size; i ++) { if (Servers[i] == ' ' || Servers[i] == ',' || Servers[i] == ';') { Servers[i] = '\0'; } } Servers[Size] = '\0';
for (Str = (LPSTR)Servers; *Str != '\0'; Str += strlen(Str) + 1) { if (getaddrinfo(Str, NULL, &hints, &ai) == NO_ERROR) { AddDnsServerAddressInfo(&ppDNext, ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai); } } }
return NO_ERROR; }
/*******************************************************************************
* GetAdapterDnsInfo * * This routine reads DNS configuration information for an interface. * * ENTRY dwFamily - Address family constraint * name - Adapter name * pCurr - Interface entry to update * AppFlags - Flags controlling what fields to skip, if any * * EXIT Entry updated * * RETURNS Error status * ******************************************************************************/
DWORD GetAdapterDnsInfo(DWORD dwFamily, char *name, PIP_ADAPTER_ADDRESSES pCurr, DWORD AppFlags) { WCHAR Buffer[MAX_DOMAIN_NAME_LEN+1]; DWORD dwErr = NO_ERROR, Size, Type, Value; DWORD DnsSuffixSize = sizeof(Buffer); HKEY TcpipKey = NULL; PIP_ADAPTER_DNS_SERVER_ADDRESS DnsServerAddr; LPSOCKADDR_IN6 Sockaddr;
Buffer[0] = L'\0'; pCurr->DnsSuffix = NULL; pCurr->Flags = IP_ADAPTER_DDNS_ENABLED;
if (name == NULL) { //
// If we couldn't find an adapter name, just use the default settings.
//
goto Done; }
for (;;) { if (!OpenAdapterKey(KEY_TCP, name, KEY_READ, &TcpipKey)) { dwErr = ERROR_CAN_NOT_COMPLETE; break; }
//
// Get DnsSuffix for the interface
//
Size = DnsSuffixSize; dwErr = RegQueryValueExW(TcpipKey, (LPWSTR)L"Domain", NULL, &Type, (LPBYTE)Buffer, &Size ); if (NO_ERROR != dwErr) { if (ERROR_FILE_NOT_FOUND != dwErr) { break; }
Size = 0; Type = REG_SZ; }
if (REG_SZ != Type) { dwErr = ERROR_INVALID_DATA; break; } if ((0 == Size) || (0 == wcslen(Buffer))) { Size = DnsSuffixSize; dwErr = RegQueryValueExW(TcpipKey, (LPWSTR)L"DhcpDomain", NULL, &Type, (LPBYTE)Buffer, &Size ); if (NO_ERROR != dwErr) { if (ERROR_FILE_NOT_FOUND != dwErr) { break; }
Size = 0; Buffer[0] = L'\0'; } }
if (MyReadRegistryDword(TcpipKey, "RegistrationEnabled", &Value) && (Value == 0)) { pCurr->Flags &= ~IP_ADAPTER_DDNS_ENABLED; } if (MyReadRegistryDword(TcpipKey, "RegisterAdapterName", &Value) && Value) { pCurr->Flags |= IP_ADAPTER_REGISTER_ADAPTER_SUFFIX; }
//
// Now attempt to read the DnsServers list
//
if (!(AppFlags & GAA_FLAG_SKIP_DNS_SERVER)) { if ((dwFamily != AF_INET) && bIp6DriverInstalled) { //
// First look for IPv6 servers.
//
HKEY Tcpip6Key = NULL; if (OpenAdapterKey(KEY_TCP6, name, KEY_READ, &Tcpip6Key)) { GetAdapterDnsServers(Tcpip6Key, pCurr); RegCloseKey(Tcpip6Key); } if (pCurr->FirstDnsServerAddress == NULL) { //
// None are configured, so use the default list of
// well-known addresses.
//
SOCKADDR_IN6 Addr; PIP_ADAPTER_DNS_SERVER_ADDRESS *ppDNext; BYTE i; ZeroMemory(&Addr, sizeof(Addr)); Addr.sin6_family = AF_INET6; Addr.sin6_addr.s6_words[0] = 0xC0FE; Addr.sin6_addr.s6_words[3] = 0xFFFF; ppDNext = &pCurr->FirstDnsServerAddress; while (*ppDNext) { ppDNext = &(*ppDNext)->Next; } for (i=1; i<=3; i++) { Addr.sin6_addr.s6_bytes[15] = i; AddDnsServerAddressInfo(&ppDNext, (LPSOCKADDR)&Addr, sizeof(Addr)); } } // Now we need to go through any non-global IPv6 DNS server
// addresses and fill in the scope id.
for (DnsServerAddr = pCurr->FirstDnsServerAddress; DnsServerAddr; DnsServerAddr = DnsServerAddr->Next) { if (DnsServerAddr->Address.lpSockaddr->sa_family != AF_INET6) continue; Sockaddr = (LPSOCKADDR_IN6)DnsServerAddr->Address.lpSockaddr; if (IN6_IS_ADDR_LINKLOCAL(&Sockaddr->sin6_addr)) Sockaddr->sin6_scope_id = pCurr->ZoneIndices[ADE_LINK_LOCAL]; else if (IN6_IS_ADDR_SITELOCAL(&Sockaddr->sin6_addr)) Sockaddr->sin6_scope_id = pCurr->ZoneIndices[ADE_SITE_LOCAL]; } }
if (dwFamily != AF_INET6) { //
// Finally, add IPv4 servers.
//
GetAdapterDnsServers(TcpipKey, pCurr); } }
break; }
if (TcpipKey) { RegCloseKey(TcpipKey); }
Done: pCurr->DnsSuffix = MALLOC((wcslen(Buffer)+1) * sizeof(WCHAR)); if (pCurr->DnsSuffix) { wcscpy(pCurr->DnsSuffix, Buffer); }
return dwErr; }
/*******************************************************************************
* NewIpAdapter * * This routine allocates an IP_ADAPTER_ADDRESSES entry and appends it to * a list of such entries. * * ENTRY ppCurr - Location in which to return new entry * ppNext - Previous entry's "next" pointer to update * name - Adapter name * Ipv4IfIndex - IPv4 Interface index * Ipv6IfIndex - IPv6 Interface index * AppFlags - Flags controlling what fields to skip, if any * IfType - IANA ifType value * Mtu - Maximum transmission unit * PhysAddr - MAC address * PhysAddrLen - Byte count of PhysAddr * Description - Adapter description * FriendlyName - User-friendly interface name * Family - Address family constraint for DNS servers * * EXIT ppCurr and ppNext updated * * RETURNS Error status * ******************************************************************************/
DWORD NewIpAdapter(PIP_ADAPTER_ADDRESSES *ppCurr, PIP_ADAPTER_ADDRESSES **ppNext, char *AdapterName, char *NameForDnsInfo, UINT Ipv4IfIndex, UINT Ipv6IfIndex, DWORD AppFlags, DWORD IfType, SIZE_T Mtu, BYTE *PhysAddr, DWORD PhysAddrLen, PWCHAR Description, PWCHAR FriendlyName, DWORD *ZoneIndices, DWORD Family) { *ppCurr = MALLOC(sizeof(IP_ADAPTER_ADDRESSES)); if (!*ppCurr) { return ERROR_NOT_ENOUGH_MEMORY; } ZeroMemory(*ppCurr, sizeof(IP_ADAPTER_ADDRESSES)); (*ppCurr)->AdapterName = MALLOC(strlen(AdapterName)+1); if (!(*ppCurr)->AdapterName) { goto Fail; } (*ppCurr)->Description = MALLOC((wcslen(Description)+1) * sizeof(WCHAR)); if (!(*ppCurr)->Description) { goto Fail; } (*ppCurr)->FriendlyName = MALLOC((wcslen(FriendlyName)+1) * sizeof(WCHAR)); if (!(*ppCurr)->FriendlyName) { goto Fail; }
(*ppCurr)->Next = NULL; (*ppCurr)->Length = sizeof(IP_ADAPTER_ADDRESSES); strcpy((*ppCurr)->AdapterName, AdapterName); (*ppCurr)->IfIndex = Ipv4IfIndex; (*ppCurr)->Ipv6IfIndex = Ipv6IfIndex; (*ppCurr)->FirstUnicastAddress = NULL; (*ppCurr)->FirstAnycastAddress = NULL; (*ppCurr)->FirstMulticastAddress = NULL; (*ppCurr)->FirstDnsServerAddress = NULL; (*ppCurr)->OperStatus = IfOperStatusUp;
CopyMemory((*ppCurr)->ZoneIndices, ZoneIndices, ADE_GLOBAL * sizeof(DWORD)); (*ppCurr)->ZoneIndices[ADE_GLOBAL] = 0; (*ppCurr)->ZoneIndices[ADE_LARGEST_SCOPE] = 0;
//(*ppCurr)->Mtu = Mtu; "dword should be enough for MTU"
(*ppCurr)->Mtu = (DWORD)Mtu;
(*ppCurr)->IfType = IfType; (*ppCurr)->PhysicalAddressLength = PhysAddrLen; memcpy((*ppCurr)->PhysicalAddress, PhysAddr, PhysAddrLen); wcscpy((*ppCurr)->Description, Description); wcscpy((*ppCurr)->FriendlyName, FriendlyName);
GetAdapterDnsInfo(Family, (NameForDnsInfo != NULL)? NameForDnsInfo : AdapterName, *ppCurr, AppFlags); if ((*ppCurr)->DnsSuffix == NULL) { goto Fail; }
**ppNext = *ppCurr; *ppNext = &(*ppCurr)->Next;
return NO_ERROR;
Fail: if ((*ppCurr)->AdapterName) { FREE((*ppCurr)->AdapterName); } if ((*ppCurr)->FriendlyName) { FREE((*ppCurr)->FriendlyName); } if ((*ppCurr)->Description) { FREE((*ppCurr)->Description); } FREE(*ppCurr); return ERROR_NOT_ENOUGH_MEMORY; }
/*******************************************************************************
* FindOrCreateIpAdapter * * This routine finds an existing IP_ADAPTER_ADDRESSES entry (if any), or * creates a new one and appends it to a list of such entries. * * ENTRY pFirst - Pointer to start of list to search * ppCurr - Location in which to return new entry * ppNext - Previous entry's "next" pointer to update * name - Adapter name * Ipv4IfIndex - IPv4 Interface index * Ipv6IfIndex - IPv6 Interface index * AppFlags - Flags controlling what fields to skip, if any * IfType - IANA ifType value * Mtu - Maximum transmission unit * PhysAddr - MAC address * PhysAddrLen - Byte count of PhysAddr * Description - Adapter description * FriendlyName - User-friendly interface name * Family - Address family constraint (for DNS servers) * * EXIT ppCurr and ppNext updated * * RETURNS Error status * ******************************************************************************/
DWORD FindOrCreateIpAdapter(PIP_ADAPTER_ADDRESSES pFirst, PIP_ADAPTER_ADDRESSES *ppCurr, PIP_ADAPTER_ADDRESSES **ppNext, char *AdapterName, char *NameForDnsInfo, UINT Ipv4IfIndex, UINT Ipv6IfIndex, DWORD AppFlags, DWORD IfType, SIZE_T Mtu, BYTE *PhysAddr, DWORD PhysAddrLen, PWCHAR Description, PWCHAR FriendlyName, DWORD *ZoneIndices, DWORD Family) { PIP_ADAPTER_ADDRESSES pIf;
// Look for an existing entry for the GUID.
for (pIf = pFirst; pIf; pIf = pIf->Next) { if (!strcmp(AdapterName, pIf->AdapterName)) { if (Ipv4IfIndex != 0) { ASSERT(pIf->IfIndex == 0); pIf->IfIndex = Ipv4IfIndex; } if (Ipv6IfIndex != 0) { PIP_ADAPTER_DNS_SERVER_ADDRESS pDNS; PSOCKADDR_IN6 pAddr;
ASSERT(pIf->Ipv6IfIndex == 0); pIf->Ipv6IfIndex = Ipv6IfIndex;
CopyMemory(pIf->ZoneIndices, ZoneIndices, ADE_GLOBAL * sizeof(DWORD));
//
// Now that we have the zone ids, we need to update
// any IPv6 scoped DNS server addresses that were
// already added.
//
for (pDNS = pIf->FirstDnsServerAddress; pDNS != NULL; pDNS = pDNS->Next) { if (pDNS->Address.lpSockaddr->sa_family != AF_INET6) { continue; } pAddr = (PSOCKADDR_IN6) pDNS->Address.lpSockaddr; if (IN6_IS_ADDR_LINKLOCAL(&pAddr->sin6_addr)) { pAddr->sin6_scope_id = ZoneIndices[ScopeLevelLink]; } else if (IN6_IS_ADDR_SITELOCAL(&pAddr->sin6_addr)) { pAddr->sin6_scope_id = ZoneIndices[ScopeLevelSite]; } } } *ppCurr = pIf; return NO_ERROR; } }
return NewIpAdapter(ppCurr, ppNext, AdapterName, NameForDnsInfo, Ipv4IfIndex, Ipv6IfIndex, AppFlags, IfType, Mtu, PhysAddr, PhysAddrLen, Description, FriendlyName, ZoneIndices, Family); }
__inline int IN6_IS_ADDR_6TO4(const struct in6_addr *a) { return ((a->s6_bytes[0] == 0x20) && (a->s6_bytes[1] == 0x02)); }
__inline int IN6_IS_ADDR_ISATAP(const struct in6_addr *a) { return (((a->s6_words[4] & 0xfffd) == 0) && (a->s6_words[5] == 0xfe5e)); }
//
// This array is used to convert from an internal IPv6 interface type value,
// as defined in ntddip6.h, to an IANA ifType value as defined in ipifcons.h.
//
DWORD IPv6ToMibIfType[] = { IF_TYPE_SOFTWARE_LOOPBACK, IF_TYPE_ETHERNET_CSMACD, IF_TYPE_FDDI, IF_TYPE_TUNNEL, IF_TYPE_TUNNEL, IF_TYPE_TUNNEL, IF_TYPE_TUNNEL, IF_TYPE_TUNNEL }; #define NUM_IPV6_IFTYPES (sizeof(IPv6ToMibIfType)/sizeof(DWORD))
/*******************************************************************************
* AddIPv6Prefix * * This routine adds an IP_ADAPTER_PREFIX entry for an IPv6 prefix * to a list of entries. * * ENTRY Addr - IPv6 prefix (network byte order) * MaskLen - IPv6 prefix length * arg1 - Initial prefix entry, for duplicate avoidance * arg2 - Previous prefix entry's "next" pointer to update * * EXIT Entry added and arg2 updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6Prefix(IN6_ADDR *Addr, DWORD MaskLen, PVOID arg1, PVOID arg2) { PIP_ADAPTER_PREFIX pFirst = *(PIP_ADAPTER_PREFIX*)arg1; PIP_ADAPTER_PREFIX **ppNext = (PIP_ADAPTER_PREFIX**)arg2; PIP_ADAPTER_PREFIX pCurr; LPSOCKADDR_IN6 pAddr;
// Check if already in the list
for (pCurr = pFirst; pCurr; pCurr = pCurr->Next) { if ((pCurr->PrefixLength == MaskLen) && (pCurr->Address.lpSockaddr->sa_family == AF_INET6) && IN6_ADDR_EQUAL(&((LPSOCKADDR_IN6)pCurr->Address.lpSockaddr)->sin6_addr, Addr)) { return NO_ERROR; } }
pCurr = MALLOC(sizeof(IP_ADAPTER_PREFIX)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN6)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN6)); pAddr->sin6_family = AF_INET6; pAddr->sin6_addr = *Addr;
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
pCurr->Length = sizeof(IP_ADAPTER_PREFIX); pCurr->Flags = 0; pCurr->Next = NULL; pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN6); pCurr->PrefixLength = MaskLen;
return NO_ERROR; }
/*******************************************************************************
* AddIPv6AutoAddressInfo * * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv6 address * on an "automatic tunnel" interface to a list of entries. * * ENTRY IF - IPv6 interface information * ADE - IPv6 address entry * arg1 - Previous entry's "next" pointer to update * arg2 - Adapter info structure * arg3 - "First" entry pointer to update * arg4 - List of all adapters * Flags - flags specified by application * Family - Address family constraint (for DNS) * * EXIT Entry added and arg1 updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6AutoAddressInfo(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, DWORD Family) { PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1; IP_ADAPTER_INFO *pAdapterInfo = (IP_ADAPTER_INFO *)arg2; PIP_ADAPTER_ADDRESSES pCurr, *ppFirst = (PIP_ADAPTER_ADDRESSES*)arg3; PIP_ADAPTER_ADDRESSES pAdapterAddresses = (PIP_ADAPTER_ADDRESSES)arg4; PIP_ADAPTER_UNICAST_ADDRESS *pNextUnicastAddr; PIP_ADAPTER_ANYCAST_ADDRESS *pNextAnycastAddr; PIP_ADAPTER_MULTICAST_ADDRESS *pNextMulticastAddr; PIP_ADAPTER_PREFIX *pNextPrefix; CHAR szGuid[80]; char *NameForDnsInfo, *pszDescription; DWORD Ipv4Address, dwErr, dwIfType; WCHAR wszFriendlyName[MAX_INTERFACE_NAME_LEN+1], *pwszDescription; ULONG PrefixLength = 64; IN6_ADDR Prefix;
if (ADE->Type != ADE_UNICAST) { return NO_ERROR; }
ConvertGuidToStringA(&IF->This.Guid, szGuid);
//
// We need the GUID ("NameForDnsInfo") of an interface which we
// can use to find additional relevant configuration information.
// For IPv6 pseudo-interfaces, we'll extract the IPv4 address, and
// find the GUID of the interface it's on, and use that, which assumes
// that configuration information (e.g. the DNS server to use) will
// still apply.
//
if (IF->Type == IPV6_IF_TYPE_TUNNEL_6TO4) { if (IN6_IS_ADDR_6TO4(&ADE->This.Address)) { // Extract IPv4 address from middle of IPv6 address
memcpy(&Ipv4Address, &ADE->This.Address.s6_bytes[2], sizeof(Ipv4Address)); } else { return NO_ERROR; } pwszDescription = L"6to4 Tunneling Pseudo-Interface"; } else { if (IN6_IS_ADDR_V4COMPAT(&ADE->This.Address) || IN6_IS_ADDR_ISATAP(&ADE->This.Address)) {
// Extract IPv4 address from last 4 bytes of IPv6 address
memcpy(&Ipv4Address, &ADE->This.Address.s6_bytes[12], sizeof(Ipv4Address)); } else { return NO_ERROR; } pwszDescription = L"Automatic Tunneling Pseudo-Interface";
if (IN6_IS_ADDR_V4COMPAT(&ADE->This.Address)) { PrefixLength = 96; } }
// Look for an existing interface with same physical address and index.
for (pCurr = *ppFirst; pCurr; pCurr = pCurr->Next) { if ((pCurr->Ipv6IfIndex == ADE->This.IF.Index) && (*(DWORD*)pCurr->PhysicalAddress == Ipv4Address)) { break; } }
if (pCurr == NULL) { // Add an interface
NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription); if (NameForDnsInfo == NULL) { return NO_ERROR; }
wcscpy(wszFriendlyName, pwszDescription);
dwIfType = (IF->Type < NUM_IPV6_IFTYPES)? IPv6ToMibIfType[IF->Type] : MIB_IF_TYPE_OTHER;
//
// Inherit some zone ids from the underlying interface.
//
for (pCurr = pAdapterAddresses; pCurr != NULL; pCurr = pCurr->Next) { if (strcmp(pCurr->AdapterName, NameForDnsInfo) == 0) { IF->ZoneIndices[ADE_SITE_LOCAL] = pCurr->ZoneIndices[ADE_SITE_LOCAL]; if (pCurr->ZoneIndices[ADE_ADMIN_LOCAL] == pCurr->ZoneIndices[ADE_SITE_LOCAL]) { IF->ZoneIndices[ADE_ADMIN_LOCAL] = pCurr->ZoneIndices[ADE_ADMIN_LOCAL];
if (pCurr->ZoneIndices[ADE_SUBNET_LOCAL] == pCurr->ZoneIndices[ADE_SITE_LOCAL]) { IF->ZoneIndices[ADE_SUBNET_LOCAL] = pCurr->ZoneIndices[ADE_SUBNET_LOCAL]; } } break; } }
dwErr = NewIpAdapter(&pCurr, ppNext, szGuid, NameForDnsInfo, 0, ADE->This.IF.Index, Flags, dwIfType, IF->LinkMTU, (BYTE*)&Ipv4Address, sizeof(Ipv4Address), pwszDescription, wszFriendlyName, (DWORD*)IF->ZoneIndices, Family); if (dwErr != NO_ERROR) { return dwErr; }
// 6to4 and automatic tunneling interfaces don't support multicast
// today.
pCurr->Flags |= IP_ADAPTER_NO_MULTICAST;
if (*ppFirst == NULL) { *ppFirst = pCurr; } }
// Add the address to the interface
pNextUnicastAddr = &pCurr->FirstUnicastAddress; while (*pNextUnicastAddr) { pNextUnicastAddr = &(*pNextUnicastAddr)->Next; }
pNextAnycastAddr = &pCurr->FirstAnycastAddress; while (*pNextAnycastAddr) { pNextAnycastAddr = &(*pNextAnycastAddr)->Next; }
pNextMulticastAddr = &pCurr->FirstMulticastAddress; while (*pNextMulticastAddr) { pNextMulticastAddr = &(*pNextMulticastAddr)->Next; }
dwErr = AddIPv6AddressInfo(IF, ADE, &pNextUnicastAddr, &pNextAnycastAddr, &pNextMulticastAddr, NULL, Flags, Family); if (dwErr != NO_ERROR) { return dwErr; }
// Add the prefix to the interface
if (Flags & GAA_FLAG_INCLUDE_PREFIX) { ZeroMemory(&Prefix, sizeof(Prefix)); CopyMemory(&Prefix, &ADE->This.Address, PrefixLength / 8); pNextPrefix = &pCurr->FirstPrefix; while (*pNextPrefix) { pNextPrefix = &(*pNextPrefix)->Next; } dwErr = AddIPv6Prefix(&Prefix, PrefixLength, &pCurr->FirstPrefix, &pNextPrefix); }
return dwErr; }
/*******************************************************************************
* GetString * * This routine reads a string value from the registry. * * ENTRY hKey - Handle to registry key * lpName - Name of value to read * pwszBuff - Buffer in which to place value read * ulBytes - Size of buffer * * EXIT pwszBuff filled in * * RETURNS TRUE on success, FALSE on failure * ******************************************************************************/
BOOL GetString(HKEY hKey, LPCWSTR lpName, PWCHAR pwszBuff, SIZE_T ulBytes) { DWORD dwErr, dwType; ULONG ulSize, ulValue;
ulSize = sizeof(ulValue); dwErr = RegQueryValueExW(hKey, lpName, NULL, &dwType, (PBYTE)pwszBuff, (LPDWORD)&ulBytes);
if (dwErr != ERROR_SUCCESS) { return FALSE; }
if (dwType != REG_SZ) { return FALSE; }
return TRUE; }
BOOL MapAdapterNameToFriendlyName(GUID *Guid, char *name, PWCHAR pwszFriendlyName, ULONG ulNumChars) { DWORD dwErr, dwTemp;
dwTemp = ulNumChars;
//
// The following call can be time-consuming the first time it is called.
// If the caller doesn't need the friendly name, it should use the
// GAA_FLAG_SKIP_FRIENDLY_NAME flag, in which case we won't get called.
//
dwErr = HrLanConnectionNameFromGuidOrPath(Guid, NULL, pwszFriendlyName, &dwTemp); if (dwErr == NO_ERROR) { return TRUE; }
//
// NhGetInterfaceNameFromDeviceGuid uses a byte count rather than
// a character count.
//
dwTemp = ulNumChars * sizeof(WCHAR);
dwErr = NhGetInterfaceNameFromDeviceGuid(Guid, pwszFriendlyName, &dwTemp, TRUE, FALSE ); if (dwErr == NO_ERROR) { return TRUE; }
MultiByteToWideChar(CP_ACP, 0, name, -1, pwszFriendlyName, ulNumChars);
return FALSE; }
#define KEY_TCPIP6_IF L"System\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces"
VOID MapIpv6AdapterNameToFriendlyName(GUID *Guid, char *name, PWCHAR pwszFriendlyName, ULONG ulBytes) { DWORD dwErr; HKEY hInterfaces = NULL, hIf = NULL; CHAR szGuid[40];
if (MapAdapterNameToFriendlyName(Guid, name, pwszFriendlyName, ulBytes/sizeof(WCHAR))) { return; }
dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KEY_TCPIP6_IF, 0, GENERIC_READ, &hInterfaces); if (dwErr != NO_ERROR) { goto Fail; }
dwErr = RegOpenKeyEx(hInterfaces, name, 0, GENERIC_READ, &hIf); if (dwErr != NO_ERROR) { goto Fail; }
if (GetString(hIf, L"FriendlyName", pwszFriendlyName, ulBytes)) { goto Cleanup; }
Fail: ConvertGuidToStringA(Guid, szGuid); MultiByteToWideChar(CP_ACP, 0, szGuid, -1, pwszFriendlyName, ulBytes / sizeof(WCHAR)); Cleanup: if (hInterfaces) { RegCloseKey(hInterfaces); } if (hIf) { RegCloseKey(hIf); } }
IN6_ADDR Ipv6LinkLocalPrefix = { 0xfe, 0x80 };
/*******************************************************************************
* ForEachIPv6Prefix * * This routine walks the IPv6 routing table and invokes a given function * on each prefix on a given interface. * * ENTRY Ipv6IfIndex - IPv6 interface index * func - Function to invoke on each address * arg1 - Argument to pass to func * arg2 - Argument to pass to func * * EXIT Nothing * * RETURNS Error status * ******************************************************************************/
DWORD ForEachIPv6Prefix(ULONG Ipv6IfIndex, DWORD (*func)(IN6_ADDR *, DWORD, PVOID, PVOID), PVOID arg1, PVOID arg2) { IPV6_QUERY_ROUTE_TABLE Query, NextQuery; IPV6_INFO_ROUTE_TABLE RTE; DWORD BytesIn, BytesReturned; ULONG dwErr = NO_ERROR; BOOL SawLinkLocal = FALSE;
ZeroMemory(&NextQuery, sizeof(NextQuery));
for (;;) { Query = NextQuery;
BytesIn = sizeof Query; BytesReturned = sizeof RTE; dwErr = WsControl(IPPROTO_IPV6, IOCTL_IPV6_QUERY_ROUTE_TABLE, &Query, &BytesIn, &RTE, &BytesReturned); if (dwErr != NO_ERROR) { return dwErr; }
NextQuery = RTE.Next; RTE.This = Query;
// Skip if it's not an onlink prefix for this interface.
if ((RTE.This.Neighbor.IF.Index == Ipv6IfIndex) && !IN6_IS_ADDR_MULTICAST(&RTE.This.Prefix)) {
if (IN6_IS_ADDR_LINKLOCAL(&RTE.This.Prefix)) { // This interface has link-local addresses
// (the 6to4 interface, for example, does not).
SawLinkLocal = TRUE; }
if ((RTE.Type != RTE_TYPE_SYSTEM) && IN6_IS_ADDR_UNSPECIFIED(&RTE.This.Neighbor.Address)) {
dwErr = func(&RTE.This.Prefix, RTE.This.PrefixLength, arg1, arg2); if (dwErr != NO_ERROR) { return dwErr; } } }
if (NextQuery.Neighbor.IF.Index == 0) { break; } }
if (SawLinkLocal) { dwErr = func(&Ipv6LinkLocalPrefix, 64, arg1, arg2); }
return dwErr; }
//
// This array is used to convert from an internal IPv6 media status value,
// as defined in ntddip6.h, to a MIB ifOperStatus value as defined in
// iptypes.h.
//
DWORD IPv6ToMibOperStatus[] = { IfOperStatusDown, // IPV6_IF_MEDIA_STATUS_DISCONNECTED
IfOperStatusUp, // IPV6_IF_MEDIA_STATUS_RECONNECTED
IfOperStatusUp, // IPV6_IF_MEDIA_STATUS_CONNECTED
}; #define NUM_IPV6_MEDIA_STATUSES (sizeof(IPv6ToMibOperStatus)/sizeof(DWORD))
#define IPV6_LOOPBACK_NAME L"Loopback Pseudo-Interface"
#define IPV6_TEREDO_NAME L"Teredo Tunneling Pseudo-Interface"
/*******************************************************************************
* AddIPv6InterfaceInfo * * This routine adds an IP_ADAPTER_ADDRESSES entry for an IPv6 interface * to a list of such entries. * * ENTRY IF - IPv6 interface information * arg1 - Previous entry's "next" pointer to update * arg2 - Pointer to start of interface list * pAdapterInfo - Additional adapter information * Flags - Flags specified by application * Family - Address family constraint (for DNS servers) * * EXIT Entry added and arg1 updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv6InterfaceInfo(IPV6_INFO_INTERFACE *IF, PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family) { DWORD dwErr = NO_ERROR; PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1; PIP_ADAPTER_ADDRESSES pFirst = *(PIP_ADAPTER_ADDRESSES*)arg2; PIP_ADAPTER_ADDRESSES pCurr; PIP_ADAPTER_UNICAST_ADDRESS *pNextUnicastAddr; PIP_ADAPTER_ANYCAST_ADDRESS *pNextAnycastAddr; PIP_ADAPTER_MULTICAST_ADDRESS *pNextMulticastAddr; PIP_ADAPTER_PREFIX *pNextPrefix; char *NameForDnsInfo = NULL, *pszDescription; u_char *LinkLayerAddress; DWORD Ipv4Address, dwIfType; WCHAR wszDescription[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; WCHAR wszFriendlyName[MAX_INTERFACE_NAME_LEN + 1]; CHAR AdapterName[MAX_ADAPTER_NAME_LENGTH + 1];
LinkLayerAddress = (u_char *)(IF + 1);
ConvertGuidToStringA(&IF->This.Guid, AdapterName);
//
// Get a description and adapter name.
//
switch (IF->Type) { case IPV6_IF_TYPE_TUNNEL_6TO4: wcscpy(wszDescription, L"6to4 Pseudo-Interface"); NameForDnsInfo = AdapterName; pCurr = NULL; dwErr = ForEachIPv6Address(IF, AddIPv6AutoAddressInfo, ppNext, pAdapterInfo, (PVOID)&pCurr, pFirst, Flags, Family); if (dwErr != NO_ERROR) { return dwErr; }
//
// Ensure that there exists an entry for the 6to4 interface.
//
if (pCurr == NULL) { dwErr = NewIpAdapter(&pCurr, ppNext, AdapterName, NameForDnsInfo, 0, IF->This.Index, Flags, IF_TYPE_TUNNEL, IF->LinkMTU, LinkLayerAddress, IF->LinkLayerAddressLength, wszDescription, wszDescription, (DWORD*)IF->ZoneIndices, Family); }
return dwErr;
case IPV6_IF_TYPE_TUNNEL_AUTO: wcscpy(wszDescription, L"Automatic Tunneling Pseudo-Interface"); NameForDnsInfo = AdapterName; pCurr = NULL; dwErr = ForEachIPv6Address(IF, AddIPv6AutoAddressInfo, ppNext, pAdapterInfo, (PVOID)&pCurr, pFirst, Flags, Family);
if (dwErr != NO_ERROR) { return dwErr; }
//
// Ensure that there exists an entry for the ISATAP interface.
//
if (pCurr == NULL) { dwErr = NewIpAdapter(&pCurr, ppNext, AdapterName, NameForDnsInfo, 0, IF->This.Index, Flags, IF_TYPE_TUNNEL, IF->LinkMTU, LinkLayerAddress, IF->LinkLayerAddressLength, wszDescription, wszDescription, (DWORD*)IF->ZoneIndices, Family); }
return dwErr;
case IPV6_IF_TYPE_TUNNEL_6OVER4: wcscpy(wszDescription, L"6over4 Pseudo-Interface"); memcpy(&Ipv4Address, LinkLayerAddress, sizeof(Ipv4Address)); NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription); if (NameForDnsInfo == NULL) { //
// IPv4 address does not exist, so just use the interface GUID.
//
NameForDnsInfo = AdapterName; } break;
case IPV6_IF_TYPE_TUNNEL_V6V4: wcscpy(wszDescription, L"Configured Tunnel Interface"); memcpy(&Ipv4Address, LinkLayerAddress, sizeof(Ipv4Address)); NameForDnsInfo = MapIpv4AddressToName(pAdapterInfo, Ipv4Address, &pszDescription); if (NameForDnsInfo == NULL) { //
// IPv4 address does not exist, so just use the interface GUID.
//
NameForDnsInfo = AdapterName; } break;
case IPV6_IF_TYPE_TUNNEL_TEREDO: wcscpy(wszDescription, IPV6_TEREDO_NAME); NameForDnsInfo = AdapterName; break; case IPV6_IF_TYPE_LOOPBACK: wcscpy(wszDescription, IPV6_LOOPBACK_NAME); NameForDnsInfo = AdapterName; break;
default: NameForDnsInfo = MapGuidToAdapterName(pAdapterInfo, &IF->This.Guid, wszDescription); if (NameForDnsInfo != NULL) { strcpy(AdapterName, NameForDnsInfo); } }
if (Flags & GAA_FLAG_SKIP_FRIENDLY_NAME) { wszFriendlyName[0] = L'\0'; } else if (IF->Type == IPV6_IF_TYPE_TUNNEL_TEREDO) { //
// The Teredo interface does not have a friendly name.
//
wcscpy(wszFriendlyName, IPV6_TEREDO_NAME); } else if (IF->Type == IPV6_IF_TYPE_LOOPBACK) { //
// The IPv6 loopback interface will not have a friendly name,
// so use the same string as the description we set above.
//
wcscpy(wszFriendlyName, IPV6_LOOPBACK_NAME); } else { MapIpv6AdapterNameToFriendlyName(&IF->This.Guid, AdapterName, wszFriendlyName, sizeof(wszFriendlyName)); }
dwIfType = (IF->Type < NUM_IPV6_IFTYPES)? IPv6ToMibIfType[IF->Type] : MIB_IF_TYPE_OTHER;
dwErr = FindOrCreateIpAdapter(pFirst, &pCurr, ppNext, AdapterName, NameForDnsInfo, 0, IF->This.Index, Flags, dwIfType, IF->LinkMTU, LinkLayerAddress, IF->LinkLayerAddressLength, wszDescription, wszFriendlyName, (DWORD*)IF->ZoneIndices, Family); if (dwErr != NO_ERROR) { return dwErr; }
if (IF->OtherStatefulConfig != 0) { pCurr->Flags |= IP_ADAPTER_IPV6_OTHER_STATEFUL_CONFIG; }
pCurr->OperStatus = (IF->MediaStatus < NUM_IPV6_MEDIA_STATUSES) ? IPv6ToMibOperStatus[IF->MediaStatus] : IfOperStatusUnknown;
// Add addresses
pNextUnicastAddr = &pCurr->FirstUnicastAddress; while (*pNextUnicastAddr) { pNextUnicastAddr = &(*pNextUnicastAddr)->Next; }
pNextAnycastAddr = &pCurr->FirstAnycastAddress; while (*pNextAnycastAddr) { pNextAnycastAddr = &(*pNextAnycastAddr)->Next; }
pNextMulticastAddr = &pCurr->FirstMulticastAddress; while (*pNextMulticastAddr) { pNextMulticastAddr = &(*pNextMulticastAddr)->Next; }
dwErr = ForEachIPv6Address(IF, AddIPv6AddressInfo, &pNextUnicastAddr, &pNextAnycastAddr, &pNextMulticastAddr, NULL, Flags, Family); if (dwErr != NO_ERROR) { return dwErr; }
// Add prefixes
if (Flags & GAA_FLAG_INCLUDE_PREFIX) { pNextPrefix = &pCurr->FirstPrefix; while (*pNextPrefix) { pNextPrefix = &(*pNextPrefix)->Next; }
dwErr = ForEachIPv6Prefix(IF->This.Index, AddIPv6Prefix, &pCurr->FirstPrefix, &pNextPrefix); }
return dwErr; }
#define MAX_LINK_LEVEL_ADDRESS_LENGTH 64
/*******************************************************************************
* ForEachIPv6Interface * * This routine walks a set of IPv6 interfaces and invokes a given function * on each one. * * ENTRY func - Function to invoke on each interface * arg1 - Argument to pass to func * arg2 - Argument to pass to func * pAdapterInfo - List of adapter information * Flags - Flags to pass to func * Family - Address family constraint (for DNS servers) * * EXIT Nothing * * RETURNS Error status * ******************************************************************************/
DWORD ForEachIPv6Interface(DWORD (*func)(IPV6_INFO_INTERFACE *, PVOID, PVOID, IP_ADAPTER_INFO *, DWORD, DWORD), PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family) { IPV6_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; DWORD InfoSize, BytesReturned, BytesIn; DWORD dwErr;
InfoSize = sizeof *IF + 2 * MAX_LINK_LEVEL_ADDRESS_LENGTH; IF = (IPV6_INFO_INTERFACE *) MALLOC(InfoSize); if (IF == NULL) { return ERROR_NOT_ENOUGH_MEMORY; }
Query.Index = (u_int) -1;
for (;;) { BytesIn = sizeof Query; BytesReturned = InfoSize;
dwErr = WsControl( IPPROTO_IPV6, IOCTL_IPV6_QUERY_INTERFACE, &Query, &BytesIn, IF, &BytesReturned);
if (dwErr != NO_ERROR) { if (dwErr == ERROR_FILE_NOT_FOUND) { // IPv6 is not installed
dwErr = NO_ERROR; } break; }
if (Query.Index != (u_int) -1) {
if ((BytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (BytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) {
dwErr = ERROR_INVALID_PARAMETER; break; }
dwErr = (*func)(IF, arg1, arg2, pAdapterInfo, Flags, Family); if (dwErr != NO_ERROR) { break; } }
if (IF->Next.Index == (u_int) -1) break; Query = IF->Next; }
FREE(IF);
return dwErr; }
//
// IPv4 equivalents of some standard IN6_* macros
//
#define IN_IS_ADDR_LOOPBACK(x) (*(x) == INADDR_LOOPBACK)
#define IN_IS_ADDR_LINKLOCAL(x) ((*(x) & 0x0000ffff) == 0x0000fea9)
/*******************************************************************************
* AddIPv4MulticastAddressInfo * * This routine adds an IP_ADAPTER_MULTICAST_ADDRESS entry for an IPv4 address * to a list of entries. * * ENTRY IF - interface information * Addr - IPv4 address * pFirst - First multicast entry * ppNext - Previous multicast entry's "next" pointer to update * * EXIT Entry added and args updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv4MulticastAddressInfo(IP_ADAPTER_INFO *IF, DWORD Addr, PIP_ADAPTER_MULTICAST_ADDRESS *pFirst, PIP_ADAPTER_MULTICAST_ADDRESS **ppNext) { DWORD dwErr = NO_ERROR; PIP_ADAPTER_MULTICAST_ADDRESS pCurr; SOCKADDR_IN *pAddr;
UNREFERENCED_PARAMETER(IF);
for (pCurr=*pFirst; pCurr; pCurr=pCurr->Next) { pAddr = (SOCKADDR_IN *)pCurr->Address.lpSockaddr; if (pAddr->sin_family == AF_INET && pAddr->sin_addr.s_addr == Addr) { return NO_ERROR; } }
pCurr = MALLOC(sizeof(IP_ADAPTER_MULTICAST_ADDRESS)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN)); pAddr->sin_family = AF_INET; pAddr->sin_addr.s_addr = Addr;
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
pCurr->Next = NULL; pCurr->Length = sizeof(IP_ADAPTER_MULTICAST_ADDRESS); pCurr->Flags = 0; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN); pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
return dwErr; }
/*******************************************************************************
* AddIPv4UnicastAddressInfo * * This routine adds an IP_ADAPTER_UNICAST_ADDRESS entry for an IPv4 address * to a list of entries. * * ENTRY IF - IPv4 interface information * ADE - IPv4 address entry * arg1 - Previous unicast entry's "next" pointer to update * arg2 - Initial multicast entry, for duplicate avoidance * arg3 - Previous multicast entry's "next" pointer to update * AppFlags - Flags specified by application * * EXIT Entry added and arg1 updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv4UnicastAddressInfo(IP_ADAPTER_INFO *IF, MIB_IPADDRROW *ADE, PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD AppFlags) { PIP_ADAPTER_UNICAST_ADDRESS **ppNext = (PIP_ADAPTER_UNICAST_ADDRESS**)arg1; PIP_ADAPTER_UNICAST_ADDRESS pCurr; SOCKADDR_IN *pAddr; DWORD Address, *pIfFlags = (DWORD *)arg4; time_t Curtime; DWORD dwStatus = NO_ERROR, i;
Address = ADE->dwAddr; if (!Address) { // Do nothing if address is 0.0.0.0
return NO_ERROR; }
if ((Address & 0x000000FF) == 0) { //
// An address in 0/8 isn't a real IP address, it's a fake one that
// the IPv4 stack sticks on a receive-only adapter.
//
(*pIfFlags) |= IP_ADAPTER_RECEIVE_ONLY; return NO_ERROR; }
if (!(AppFlags & GAA_FLAG_SKIP_UNICAST)) { pCurr = MALLOC(sizeof(IP_ADAPTER_UNICAST_ADDRESS)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN)); pAddr->sin_family = AF_INET; memcpy(&pAddr->sin_addr, &Address, sizeof(Address));
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next;
time(&Curtime);
pCurr->Next = NULL; pCurr->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS); pCurr->LeaseLifetime = (ULONG)(IF->LeaseExpires - Curtime); pCurr->ValidLifetime = pCurr->PreferredLifetime = pCurr->LeaseLifetime; pCurr->Flags = 0; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN); pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr;
pCurr->PrefixOrigin = IpPrefixOriginManual; pCurr->SuffixOrigin = IpSuffixOriginManual; if (IF->DhcpEnabled) { if (IN_IS_ADDR_LINKLOCAL(&Address)) { pCurr->PrefixOrigin = IpPrefixOriginWellKnown; pCurr->SuffixOrigin = IpSuffixOriginRandom; } else { pCurr->PrefixOrigin = IpPrefixOriginDhcp; pCurr->SuffixOrigin = IpSuffixOriginDhcp; } } pCurr->DadState = IpDadStatePreferred;
if ((pCurr->DadState == IpDadStatePreferred) && (pCurr->SuffixOrigin != IpSuffixOriginRandom) && !IN_IS_ADDR_LOOPBACK(&Address) && !IN_IS_ADDR_LINKLOCAL(&Address)) { pCurr->Flags |= IP_ADAPTER_ADDRESS_DNS_ELIGIBLE; }
if (ADE->wType & MIB_IPADDR_TRANSIENT) { pCurr->Flags |= IP_ADAPTER_ADDRESS_TRANSIENT; } }
// Now add any new multicast addresses
if (!(AppFlags & GAA_FLAG_SKIP_MULTICAST)) { DWORD *pIgmpList = NULL; DWORD dwTotal, dwOutBufLen = 0;
dwStatus = GetIgmpList(Address, pIgmpList, &dwOutBufLen);
if (dwStatus == ERROR_INSUFFICIENT_BUFFER) { pIgmpList = MALLOC(dwOutBufLen); if (!pIgmpList) { return ERROR_NOT_ENOUGH_MEMORY; } dwStatus = GetIgmpList(Address, pIgmpList, &dwOutBufLen); }
if (dwStatus != NO_ERROR) { if (pIgmpList) { FREE(pIgmpList); } return dwStatus; }
dwTotal = dwOutBufLen/sizeof(Address);
for (i=0; (i<dwTotal) && (dwStatus == NO_ERROR); i++) { dwStatus = AddIPv4MulticastAddressInfo(IF, pIgmpList[i], (PIP_ADAPTER_MULTICAST_ADDRESS *)arg2, (PIP_ADAPTER_MULTICAST_ADDRESS **)arg3); }
if (pIgmpList) { FREE(pIgmpList); } }
return dwStatus; }
/*******************************************************************************
* ForEachIPv4Address * * This routine walks a set of IPv4 addresses and invokes a given function * on each one. * * ENTRY IF - IPv4 interface information * func - Function to invoke on each address * arg1 - Argument to pass to func * arg2 - Argument to pass to func * arg3 - Argument to pass to func * Flags - Flags to pass to func * pIpAddrTable - IPv4 address table with per-address flags * * EXIT Nothing * * RETURNS Error status * ******************************************************************************/
DWORD ForEachIPv4Address(IP_ADAPTER_INFO *IF, DWORD (*func)(IP_ADAPTER_INFO *,PMIB_IPADDRROW, PVOID, PVOID, PVOID, PVOID, DWORD), PVOID arg1, PVOID arg2, PVOID arg3, PVOID arg4, DWORD Flags, PMIB_IPADDRTABLE pIpAddrTable) { DWORD dwErr, i; PMIB_IPADDRROW ADE;
for (i=0; i<pIpAddrTable->dwNumEntries; i++) { ADE = &pIpAddrTable->table[i]; if (ADE->dwIndex != IF->Index) { continue; }
dwErr = (*func)(IF, ADE, arg1, arg2, arg3, arg4, Flags); if (dwErr != NO_ERROR) { return dwErr; } }
return NO_ERROR; }
DWORD MaskToMaskLen( DWORD dwMask ) { register int i;
for (i=0; i<32 && !(dwMask & (1<<i)); i++);
return 32-i; }
/*******************************************************************************
* AddIPv4Prefix * * This routine adds an IP_ADAPTER_PREFIX entry for an IPv4 prefix * to a list of entries. * * ENTRY IF - IPv4 interface information * Addr - IPv4 prefix (network byte order) * MaskLen - IPv4 prefix length * arg1 - Initial prefix entry, for duplicate avoidance * arg2 - Previous prefix entry's "next" pointer to update * * EXIT Entry added and arg2 updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv4Prefix(DWORD Addr, DWORD MaskLen, PVOID arg1, PVOID arg2) { PIP_ADAPTER_PREFIX pFirst = *(PIP_ADAPTER_PREFIX*)arg1; PIP_ADAPTER_PREFIX **ppNext = (PIP_ADAPTER_PREFIX**)arg2; PIP_ADAPTER_PREFIX pCurr; LPSOCKADDR_IN pAddr;
// Check if already in the list
for (pCurr = pFirst; pCurr; pCurr = pCurr->Next) { if ((pCurr->PrefixLength == MaskLen) && (pCurr->Address.lpSockaddr->sa_family == AF_INET) && (((LPSOCKADDR_IN)pCurr->Address.lpSockaddr)->sin_addr.s_addr == Addr)) { return NO_ERROR; } }
pCurr = MALLOC(sizeof(IP_ADAPTER_PREFIX)); if (!pCurr) { return ERROR_NOT_ENOUGH_MEMORY; }
pAddr = MALLOC(sizeof(SOCKADDR_IN)); if (!pAddr) { FREE(pCurr); return ERROR_NOT_ENOUGH_MEMORY; }
memset(pAddr, 0, sizeof(SOCKADDR_IN)); pAddr->sin_family = AF_INET; pAddr->sin_addr.s_addr = Addr;
// Add address to linked list
**ppNext = pCurr; *ppNext = &pCurr->Next; pCurr->Length = sizeof(IP_ADAPTER_PREFIX); pCurr->Flags = 0; pCurr->Next = NULL; pCurr->Address.lpSockaddr = (LPSOCKADDR)pAddr; pCurr->Address.iSockaddrLength = sizeof(SOCKADDR_IN); pCurr->PrefixLength = MaskLen;
return NO_ERROR; }
/*******************************************************************************
* ForEachIPv4Prefix * * This routine walks a set of IPv4 prefixes and invokes a given function * on each one. * * ENTRY IF - IPv4 interface information * func - Function to invoke on each address * arg1 - Argument to pass to func * arg2 - Argument to pass to func * * EXIT Nothing * * RETURNS Error status * ******************************************************************************/
DWORD ForEachIPv4Prefix(IP_ADAPTER_INFO *IF, DWORD (*func)(DWORD, DWORD, PVOID, PVOID), PVOID arg1, PVOID arg2) { PIP_ADDR_STRING Prefix; DWORD Addr, Mask, MaskLen, dwErr; for (Prefix = &IF->IpAddressList; Prefix; Prefix = Prefix->Next) { if (Prefix->IpAddress.String[0] == '\0') { continue; } Mask = inet_addr(Prefix->IpMask.String); Addr = inet_addr(Prefix->IpAddress.String) & Mask; MaskLen = MaskToMaskLen(ntohl(Mask));
dwErr = func(Addr, MaskLen, arg1, arg2); if (dwErr != NO_ERROR) { return dwErr; } }
return NO_ERROR; }
//
// This array is used to convert from an internal IPv4 oper status value,
// as defined in ipifcons.h, to a MIB ifOperStatus value as defined in
// iptypes.h.
//
DWORD IPv4ToMibOperStatus[] = { IfOperStatusDown, // IF_OPER_STATUS_NON_OPERATIONAL
IfOperStatusDown, // IF_OPER_STATUS_UNREACHABLE
IfOperStatusDormant, // IF_OPER_STATUS_DISCONNECTED
IfOperStatusDormant, // IF_OPER_STATUS_CONNECTING
IfOperStatusUp, // IF_OPER_STATUS_CONNECTED
IfOperStatusUp, // IF_OPER_STATUS_OPERATIONAL
}; #define NUM_IPV4_OPER_STATUSES (sizeof(IPv4ToMibOperStatus)/sizeof(DWORD))
/*******************************************************************************
* AddIPv4InterfaceInfo * * This routine adds an IP_ADAPTER_ADDRESSES entry for an IPv4 interface * to a list of such entries. * * ENTRY IF - IPv4 interface information * arg1 - Previous entry's "next" pointer to update * arg2 - Pointer to start of interface list * Flags - Flags controlling what fields to skip, if any * Family - Address family constraint (for DNS server addresses) * pAddrTable - IPv4 address table * * EXIT Entry added and arg updated * * RETURNS Error status * ******************************************************************************/
DWORD AddIPv4InterfaceInfo(IP_ADAPTER_INFO *IF, PVOID arg1, PVOID arg2, DWORD Flags, DWORD Family, PMIB_IPADDRTABLE pAddrTable) { DWORD dwErr = NO_ERROR, i; PIP_ADAPTER_ADDRESSES **ppNext = (PIP_ADAPTER_ADDRESSES**)arg1; PIP_ADAPTER_ADDRESSES pFirst = *(PIP_ADAPTER_ADDRESSES*)arg2; PIP_ADAPTER_ADDRESSES pCurr; PIP_ADAPTER_UNICAST_ADDRESS *pNextUAddr; PIP_ADAPTER_MULTICAST_ADDRESS *pNextMAddr; PIP_ADAPTER_PREFIX *pNextPrefix; WCHAR wszDescription[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; WCHAR wszFriendlyName[MAX_INTERFACE_NAME_LEN + 1]; MIB_IFROW IfEntry; GUID Guid; DWORD ZoneIndices[ADE_NUM_SCOPES];
MultiByteToWideChar(CP_ACP, 0, IF->Description, -1, wszDescription, MAX_ADAPTER_DESCRIPTION_LENGTH);
//
// Get information which isn't in IP_ADAPTER_INFO.
//
dwErr = GetIfEntryFromStack(&IfEntry, IF->Index, FALSE); if (dwErr != NO_ERROR) { return dwErr; }
if (ConvertStringToGuidA(IF->AdapterName, &Guid) != NO_ERROR) { ZeroMemory(&Guid, sizeof(Guid)); }
//
// Fill in some dummy zone indices.
//
ZoneIndices[0] = ZoneIndices[1] = ZoneIndices[2] = ZoneIndices[3] = IF->Index; for (i=ADE_ADMIN_LOCAL; i<ADE_NUM_SCOPES; i++) { ZoneIndices[i] = 1; }
if (Flags & GAA_FLAG_SKIP_FRIENDLY_NAME) { wszFriendlyName[0] = L'\0'; } else { MapAdapterNameToFriendlyName(&Guid, IF->AdapterName, wszFriendlyName, MAX_INTERFACE_NAME_LEN+1); }
dwErr = FindOrCreateIpAdapter(pFirst, &pCurr, ppNext, IF->AdapterName, IF->AdapterName, IF->Index, 0, Flags, IF->Type, IfEntry.dwMtu, IF->Address, IF->AddressLength, wszDescription, wszFriendlyName, ZoneIndices, Family); if (dwErr != NO_ERROR) { return dwErr; }
pCurr->OperStatus = (IfEntry.dwOperStatus < NUM_IPV4_OPER_STATUSES) ? IPv4ToMibOperStatus[IfEntry.dwOperStatus] : IfOperStatusUnknown; if (IF->DhcpEnabled) { pCurr->Flags |= IP_ADAPTER_DHCP_ENABLED; }
// Add addresses
pNextUAddr = &pCurr->FirstUnicastAddress; pNextMAddr = &pCurr->FirstMulticastAddress; dwErr = ForEachIPv4Address(IF, AddIPv4UnicastAddressInfo, &pNextUAddr, pNextMAddr, &pNextMAddr, &pCurr->Flags, Flags, pAddrTable); if (dwErr != NO_ERROR) { return dwErr; }
// Add prefixes
if (Flags & GAA_FLAG_INCLUDE_PREFIX) { pNextPrefix = &pCurr->FirstPrefix; dwErr = ForEachIPv4Prefix(IF, AddIPv4Prefix, &pCurr->FirstPrefix, &pNextPrefix); }
return dwErr; }
IP_ADAPTER_INFO IPv4LoopbackInterfaceInfo = { NULL, // Next
1, // ComboIndex
"MS TCP Loopback interface", // AdapterName
"MS TCP Loopback interface", // Description
0, // Address Length
{0}, // Address
1, // Index
MIB_IF_TYPE_LOOPBACK, // Type
FALSE, // DhcpEnabled
NULL, // CurrentIpAddress,
{NULL}, // IpAddressList,
{NULL}, // GatewayList,
{NULL}, // DhcpServer,
FALSE, // HaveWins
{NULL}, // PrimaryWinsServer,
{NULL}, // SecondaryWinsServer,
0, // LeaseObtained
0 // LeaseExpires
};
/*******************************************************************************
* ForEachIPv4Interface * * This routine walks a set of IPv4 interfaces and invokes a given function * on each one. * * ENTRY func - Function to invoke on each interface * arg1 - Argument to pass to func * arg2 - Argument to pass to func * pAdapterInfo - List of IPv4 interfaces * Flags - Flags to pass to func * Family - Address family constraint (for DNS server addresses) * * EXIT Nothing * * RETURNS Error status * ******************************************************************************/
DWORD ForEachIPv4Interface(DWORD (*func)(IP_ADAPTER_INFO *, PVOID, PVOID, DWORD, DWORD, PMIB_IPADDRTABLE), PVOID arg1, PVOID arg2, IP_ADAPTER_INFO *pAdapterInfo, DWORD Flags, DWORD Family, PMIB_IPADDRTABLE pIpAddrTable) { PIP_ADAPTER_INFO IF; DWORD dwErr;
for (IF=pAdapterInfo; IF; IF=IF->Next) { //
// An empty adapter name indicates the adapter should not be reported.
//
if (IF->AdapterName[0] == '\0') { continue; }
dwErr = (*func)(IF, arg1, arg2, Flags, Family, pIpAddrTable); if (dwErr != NO_ERROR) { return dwErr; } }
//
// The IPv4 loopback interface is missing from the pAdapterInfo list,
// so we special case it here.
//
dwErr = (*func)(&IPv4LoopbackInterfaceInfo, arg1, arg2, Flags, Family, pIpAddrTable); if (dwErr != NO_ERROR) { return dwErr; }
return NO_ERROR; }
DWORD GetAdapterAddresses(ULONG Family, DWORD Flags, PIP_ADAPTER_ADDRESSES *pAddresses) { IP_ADAPTER_INFO *pAdapterInfo = NULL; PIP_ADAPTER_ADDRESSES adapterList, *pCurr; DWORD dwErr = NO_ERROR; PMIB_IPADDRTABLE pIpAddrTable = NULL;
TRACE_PRINT(("Entered GetAdapterAddresses\n"));
pAdapterInfo = GetAdapterInfo();
*pAddresses = adapterList = NULL; pCurr = &adapterList; //
// If we want to return IPv6 DNS servers, find out now whether the
// IPv6 stack is installed.
//
if ((Family != AF_INET) && !(Flags & GAA_FLAG_SKIP_DNS_SERVER)) { IPV6_GLOBAL_PARAMETERS Params; DWORD BytesReturned = sizeof(Params); DWORD InputBufferLength = 0;
dwErr = WsControl(IPPROTO_IPV6, IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS, NULL, &InputBufferLength, &Params, &BytesReturned);
bIp6DriverInstalled = (dwErr == NO_ERROR); dwErr = NO_ERROR; }
if ((Family == AF_UNSPEC) || (Family == AF_INET)) { DWORD dwSize = 0;
//
// GetAdapterInfo alone isn't sufficient since it doesn't get
// per-address flags whereas GetIpAddrTable does.
// GetIpAddrTable doesn't get per-interface info however,
// so this is why we have to do both. We use pAdapterInfo
// for per-interface info and pIpAddrTable for
// per-address info.
//
dwErr = GetIpAddrTable(NULL, &dwSize, TRUE); if (dwErr == ERROR_INSUFFICIENT_BUFFER) { pIpAddrTable = MALLOC(dwSize); if (!pIpAddrTable) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
dwErr = GetIpAddrTable(pIpAddrTable, &dwSize, TRUE); } if (dwErr != NO_ERROR) { goto Cleanup; }
dwErr = ForEachIPv4Interface(AddIPv4InterfaceInfo, &pCurr, &adapterList, pAdapterInfo, Flags, Family, pIpAddrTable); if (dwErr != NO_ERROR) { goto Cleanup; } } if ((Family == AF_UNSPEC) || (Family == AF_INET6)) { dwErr = ForEachIPv6Interface(AddIPv6InterfaceInfo, &pCurr, &adapterList, pAdapterInfo, Flags, Family); if (dwErr != NO_ERROR) { goto Cleanup; } } *pAddresses = adapterList; adapterList = NULL;
Cleanup: if (pIpAddrTable) { FREE(pIpAddrTable); } if (pAdapterInfo) { KillAdapterInfo(pAdapterInfo); } if (adapterList) { KillAdapterAddresses(adapterList); }
TRACE_PRINT(("Exit GetAdapterAddresses %p\n", adapterList));
return dwErr; }
/*******************************************************************************
* * InternalGetPerAdapterInfo * * Gets per-adapter special information. * * ENTRY IfIndex * * EXIT nothing * * RETURNS pointer to the IP_PER_ADAPTER_INFO structure * * ASSUMES * ******************************************************************************/
PIP_PER_ADAPTER_INFO InternalGetPerAdapterInfo(ULONG IfIndex) {
PIP_ADAPTER_INFO adapterList; PIP_ADAPTER_INFO adapter; PIP_PER_ADAPTER_INFO perAdapterInfo = NULL; HKEY key; BOOL ok;
TRACE_PRINT(("Entered GetPerAdapterList\n"));
if ((adapterList = GetAdapterInfo()) != NULL) {
//
// scan the adapter list and find one that matches IfIndex
//
for (adapter = adapterList; adapter; adapter = adapter->Next) {
TRACE_PRINT(("GetPerAdapterInfo: '%s'\n", adapter->AdapterName));
if (adapter->Index == IfIndex && adapter->AdapterName[0] && OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
//
// found the right adapter so let's fill up the perAdapterInfo
//
perAdapterInfo = NEW(IP_PER_ADAPTER_INFO); if (perAdapterInfo == NULL) {
DEBUG_PRINT(("GetPerAdapterInfo: no memory for perAdapterInfo\n")); KillAdapterInfo(adapterList); RegCloseKey(key); return NULL; }
ZeroMemory(perAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
if (!MyReadRegistryDword(key, TEXT("IPAutoconfigurationEnabled"), (LPDWORD)&perAdapterInfo->AutoconfigEnabled)) {
//
// autoconfig is enabled if no regval exists for this
// adapter
//
perAdapterInfo->AutoconfigEnabled = TRUE; TRACE_PRINT(("IPAutoconfigurationEnabled not read\n")); }
TRACE_PRINT(("IPAutoconfigurationEnableda = %d\n", perAdapterInfo->AutoconfigEnabled));
if (perAdapterInfo->AutoconfigEnabled) {
MyReadRegistryDword(key, TEXT("AddressType"), (LPDWORD)&perAdapterInfo->AutoconfigActive);
TRACE_PRINT(("AddressType !%d\n", perAdapterInfo->AutoconfigActive)); }
//
// DNS Server list: first NameServer and then DhcpNameServer
//
ok = ReadRegistryIpAddrString(key, TEXT("NameServer"), &perAdapterInfo->DnsServerList); if (ok) { TRACE_PRINT(("GetPerAdapterInfo: DhcpNameServer %s\n", perAdapterInfo->DnsServerList)); }
if (!ok) {
ok = ReadRegistryIpAddrString(key, TEXT("DhcpNameServer"), &perAdapterInfo->DnsServerList); if (ok) { TRACE_PRINT(("GetPerAdapterInfo: DhcpNameServer %s\n", perAdapterInfo->DnsServerList)); } }
//
// we are done so let's exit the loop
//
RegCloseKey(key); break;
} else { DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n", adapter->AdapterName, GetLastError())); } }
KillAdapterInfo(adapterList); } else { DEBUG_PRINT(("GetPerAdapterInfo: GetAdapterInfo returns NULL\n")); }
TRACE_PRINT(("Exit GetPerAdapterInfo %p\n", perAdapterInfo));
return perAdapterInfo; }
/*******************************************************************************
* * OpenAdapterKey * * Opens one of the 3 per-adapter registry keys: * Tcpip\\Parameters"\<adapter> * or NetBT\Adapters\<Adapter> * or Tcpip6\Paramters\<adapter> * * ENTRY KeyType - KEY_TCP or KEY_NBT or KEY_TCP6 * Name - pointer to adapter name to use * Key - pointer to returned key * * EXIT Key updated * * RETURNS TRUE if success * * ASSUMES * HISTORY: MohsinA, 16-May-97. Fixing for PNP. * ******************************************************************************/
static BOOL OpenAdapterKey(DWORD KeyType, const LPSTR Name, REGSAM Access, PHKEY Key) {
LONG err; CHAR keyName[MAX_ADAPTER_NAME_LENGTH + sizeof(TCPIP_PARAMS_INTER_KEY)];
switch (KeyType) { case KEY_TCP:
//
// open the handle to this adapter's TCPIP parameter key
//
strcpy(keyName, TCPIP_PARAMS_INTER_KEY ); strcat(keyName, Name); break;
case KEY_TCP6:
//
// open the handle to this adapter's TCPIP6 parameter key
//
strcpy(keyName, TCPIP6_PARAMS_INTER_KEY ); strcat(keyName, Name); break;
case KEY_NBT:
//
// open the handle to the NetBT\Adapters\<Adapter> handle
//
strcpy(keyName, NETBT_ADAPTER_KEY ); strcat(keyName, Name); break;
default: return FALSE; }
TRACE_PRINT(("OpenAdapterKey: %s\n", keyName ));
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, Access, Key );
if( err != ERROR_SUCCESS ){ DEBUG_PRINT(("OpenAdapterKey: RegOpenKey %s, err=%d\n", keyName, GetLastError() )); }else{ TRACE_PRINT(("Exit OpenAdapterKey: %s ok\n", keyName )); }
return (err == ERROR_SUCCESS); }
BOOL WriteRegistryDword(HKEY hKey, LPSTR szParameter, DWORD *pdwValue ) { DWORD dwResult;
TRACE_PRINT(("WriteRegistryDword: %s %d\n", szParameter, *pdwValue ));
dwResult = RegSetValueEx( hKey, szParameter, 0, REG_DWORD, (CONST BYTE *) pdwValue, sizeof( *pdwValue ) );
return ( ERROR_SUCCESS == dwResult ); }
BOOL WriteRegistryMultiString(HKEY hKey, LPSTR szParameter, LPSTR szValue ) { DWORD dwResult; LPSTR psz;
for (psz = szValue; *psz; psz += lstrlen(szValue) + 1) { }
dwResult = RegSetValueEx( hKey, szParameter, 0, REG_MULTI_SZ, (CONST BYTE *) szValue, (DWORD)(psz - szValue) + 1 );
return ( ERROR_SUCCESS == dwResult ); }
/*******************************************************************************
* * MyReadRegistryDword * * Reads a registry value that is stored as a DWORD * * ENTRY Key - open registry key where value resides * ParameterName - name of value to read from registry * Value - pointer to returned value * * EXIT *Value = value read * * RETURNS TRUE if success * * ASSUMES * ******************************************************************************/
BOOL MyReadRegistryDword(HKEY Key, LPSTR ParameterName, LPDWORD Value) {
LONG err; DWORD valueLength; DWORD valueType;
valueLength = sizeof(*Value); err = RegQueryValueEx(Key, ParameterName, NULL, // reserved
&valueType, (LPBYTE)Value, &valueLength ); if ((err == ERROR_SUCCESS) && (valueType == REG_DWORD) && (valueLength == sizeof(DWORD))) {
DEBUG_PRINT(("MyReadRegistryDword(%s): val = %d, type = %d, len = %d\n", ParameterName, *Value, valueType, valueLength ));
} else {
DEBUG_PRINT(("MyReadRegistryDword(%p,%s): err = %d\n", Key, ParameterName, err));
err = !ERROR_SUCCESS; }
return (err == ERROR_SUCCESS); }
// ========================================================================
// Was DWORD IPInterfaceContext, now CHAR NTEContextList[][].
// Reads in a REG_MULTI_SZ and converts it into a list of numbers.
// MohsinA, 21-May-97.
// ========================================================================
// max length of REG_MULTI_SZ.
#define MAX_VALUE 5002
BOOL ReadRegistryList(HKEY Key, LPSTR ParameterName, DWORD NumList[], int *MaxList ) {
LONG err; DWORD valueType; BYTE Value[MAX_VALUE]; DWORD valueLength = MAX_VALUE; SIZE_T i = 0; int k = 0;
err = RegQueryValueEx(Key, ParameterName, NULL, &valueType, &Value[0], &valueLength );
if( ( err == ERROR_SUCCESS) && ( valueType == REG_MULTI_SZ ) && ((valueLength+2) < MAX_VALUE) ){ TRACE_PRINT(("ReadRegistryList %s ok\n", ParameterName )); Value[MAX_VALUE-1] = '\0'; Value[MAX_VALUE-2] = '\0';
while( (i < MAX_VALUE) && Value[i] && (k < (*MaxList)) ){ NumList[k] = strtoul( (const char*)&Value[i], NULL, 0 ); TRACE_PRINT((" NumList[%d] = '%s' => %d\n", k, &Value[i], NumList[k] )); k++; i += strlen( (const char*)&Value[i] ) + 1; } assert( (i < MAX_VALUE) && !Value[i] && (k < MaxList) ); *MaxList = k; } else { *MaxList = 0; DEBUG_PRINT(("ReadRegistryList %s failed\n", ParameterName )); err = !ERROR_SUCCESS; }
return (err == ERROR_SUCCESS); }
BOOL IsIncluded( DWORD Context, DWORD contextlist[], int len_contextlist ) { int i;
for( i = 0; i < len_contextlist; i++ ) { if( Context == contextlist[i] ){ return TRUE; } }
return FALSE; }
/*******************************************************************************
* * ReadRegistryString * * Reads a registry value that is stored as a string * * ENTRY Key - open registry key * ParameterName - name of value to read from registry * String - pointer to returned string * Length - IN: length of String buffer. OUT: length of returned string * * EXIT String contains string read * * RETURNS TRUE if success * * ASSUMES * ******************************************************************************/
BOOL ReadRegistryString(HKEY Key, LPSTR ParameterName, LPSTR String, LPDWORD Length) {
LONG err; DWORD valueType;
*String = '\0'; err = RegQueryValueEx(Key, ParameterName, NULL, // reserved
&valueType, (LPBYTE)String, Length );
if (err == ERROR_SUCCESS) {
ASSERT(valueType == REG_SZ || valueType == REG_MULTI_SZ);
DEBUG_PRINT(("ReadRegistryString(%s): val = \"%s\", type = %d, len = %d\n", ParameterName, String, valueType, *Length ));
} else {
DEBUG_PRINT(("ReadRegistryString(%s): err = %d\n", ParameterName, err));
}
return ((err == ERROR_SUCCESS) && (*Length > sizeof('\0'))); }
/*******************************************************************************
* * ReadRegistryOemString * * Reads a registry value as a wide character string * * ENTRY Key - open registry key * ParameterName - name of value to read from registry * String - pointer to returned string * Length - IN: length of String buffer. OUT: length of returned string * * EXIT String contains string read * * RETURNS TRUE if success * * ASSUMES * ******************************************************************************/
BOOL ReadRegistryOemString(HKEY Key, LPWSTR ParameterName, LPSTR String, LPDWORD Length) {
LONG err; DWORD valueType; DWORD valueLength;
//
// first, get the length of the string
//
*String = '\0'; err = RegQueryValueExW(Key, ParameterName, NULL, // reserved
&valueType, NULL, &valueLength ); if ((err == ERROR_SUCCESS) && (valueType == REG_SZ)) { if ((valueLength <= *Length) && (valueLength > sizeof(L'\0'))) {
UNICODE_STRING unicodeString; OEM_STRING oemString; LPWSTR str = (LPWSTR)GrabMemory(valueLength);
if (!str) { return FALSE; }
//
// read the UNICODE string into allocated memory
//
err = RegQueryValueExW(Key, ParameterName, NULL, &valueType, (LPBYTE)str, &valueLength ); if (err == ERROR_SUCCESS) {
NTSTATUS Status;
//
// convert the UNICODE string to OEM character set
//
RtlInitUnicodeString(&unicodeString, str); Status = RtlUnicodeStringToOemString(&oemString, &unicodeString, TRUE);
if (NT_SUCCESS(Status)) { strcpy(String, oemString.Buffer); RtlFreeOemString(&oemString); } else { err = !ERROR_SUCCESS; }
DEBUG_PRINT(("ReadRegistryOemString(%ws): val = \"%s\", len = %d\n", ParameterName, String, valueLength ));
} else {
DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n", ParameterName, err, valueType, valueLength ));
} ReleaseMemory(str); } else {
DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n", ParameterName, err, valueType, valueLength ));
err = !ERROR_SUCCESS; } } else {
DEBUG_PRINT(("ReadRegistryOemString(%ws): err = %d, type = %d, len = %d\n", ParameterName, err, valueType, valueLength ));
err = !ERROR_SUCCESS; } return (err == ERROR_SUCCESS); }
/*******************************************************************************
* * ReadRegistryIpAddrString * * Reads zero or more IP addresses from a space-delimited string in a registry * parameter and converts them to a list of IP_ADDR_STRINGs * * ENTRY Key - registry key * ParameterName - name of value entry under Key to read from * IpAddr - pointer to IP_ADDR_STRING to update * * EXIT IpAddr updated if success * * RETURNS TRUE if success * * ASSUMES * ******************************************************************************/
BOOL ReadRegistryIpAddrString(HKEY Key, LPSTR ParameterName, PIP_ADDR_STRING IpAddr) {
LONG err; DWORD valueLength; DWORD valueType; LPBYTE valueBuffer;
err = RegQueryValueEx(Key, ParameterName, NULL, // reserved
&valueType, NULL, &valueLength ); if ((err == ERROR_SUCCESS)) { if((valueLength > 1) && (valueType == REG_SZ) || (valueLength > 2) && (valueType == REG_MULTI_SZ) ) { valueBuffer = GrabMemory(valueLength); if (!valueBuffer) { return FALSE; } err = RegQueryValueEx(Key, ParameterName, NULL, // reserved
&valueType, valueBuffer, &valueLength ); if ((err == ERROR_SUCCESS) && (valueLength > 1)) {
UINT stringCount; LPSTR stringPointer = (LPSTR)valueBuffer; LPSTR *stringAddress; UINT i;
DEBUG_PRINT(("ReadRegistryIpAddrString(%s): \"%s\", len = %d\n", ParameterName, valueBuffer, valueLength ));
stringAddress = GrabMemory(valueLength / 2 * sizeof(LPSTR));
if (stringAddress) { if( REG_SZ == valueType ) { stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS); stringAddress[0] = stringPointer; stringCount = 1; while ((stringPointer = strpbrk(stringPointer, STRING_ARRAY_DELIMITERS)) != NULL) { *stringPointer++ = '\0'; stringPointer += strspn(stringPointer, STRING_ARRAY_DELIMITERS); stringAddress[stringCount] = stringPointer; if (*stringPointer) { ++stringCount; } }
for (i = 0; i < stringCount; ++i) { AddIpAddressString(IpAddr, stringAddress[i], ""); } } else if( REG_MULTI_SZ == valueType ) { stringCount = 0; while(strlen(stringPointer)) { AddIpAddressString(IpAddr, stringPointer, ""); stringPointer += 1+strlen(stringPointer); stringCount ++; } if( 0 == stringCount ) err = ERROR_PATH_NOT_FOUND; } else { err = ERROR_PATH_NOT_FOUND; } ReleaseMemory(stringAddress); } else { err = ERROR_NOT_ENOUGH_MEMORY; } } else {
DEBUG_PRINT(("ReadRegistryIpAddrString(%s): err = %d, len = %d\n", ParameterName, err, valueLength ));
err = ERROR_PATH_NOT_FOUND; } ReleaseMemory(valueBuffer); } else {
DEBUG_PRINT(("ReadRegistryIpAddrString(%s): err = %d, type = %d, len = %d\n", ParameterName, err, valueType, valueLength ));
err = ERROR_PATH_NOT_FOUND; } } return (err == ERROR_SUCCESS); }
/*******************************************************************************
* * GetBoundAdapterList * * Gets a list of names of all adapters bound to a protocol (TCP/IP). Returns * a pointer to an array of pointers to strings - basically an argv list. The * memory for the strings is concatenated to the array and the array is NULL * terminated. If Elnkii1 and IbmTok2 are bound to TCP/IP then this function * will return: * * ---> addr of string1 \ * addr of string2 \ * NULL > allocated as one block * &string1: "Elnkii1" / * &string2: "IbmTok2" / * * ENTRY BindingsSectionKey * - Open registry handle to a linkage key (e.g. Tcpip\Linkage) * * EXIT * * RETURNS pointer to argv[] style array, or NULL * * ASSUMES * ******************************************************************************/
LPSTR* GetBoundAdapterList(HKEY BindingsSectionKey) {
LONG err; DWORD valueType; PBYTE valueBuffer; DWORD valueLength; LPSTR* resultBuffer; LPSTR* nextResult; int len; DWORD resultLength; LPSTR nextValue; LPSTR variableData; DWORD numberOfBindings;
//
// get required size of value buffer
//
valueLength = 0; err = RegQueryValueEx(BindingsSectionKey, TEXT("Bind"), NULL, // reserved
&valueType, NULL, &valueLength ); if (err != ERROR_SUCCESS) { return NULL; } if (valueType != REG_MULTI_SZ) { return NULL; } if (!valueLength) { return NULL; } valueBuffer = (PBYTE)GrabMemory(valueLength); if (!valueBuffer) { return NULL; } err = RegQueryValueEx(BindingsSectionKey, TEXT("Bind"), NULL, // reserved
&valueType, valueBuffer, &valueLength ); if (err != ERROR_SUCCESS) { DEBUG_PRINT(("GetBoundAdapterList: RegQueryValueEx 'Bind' failed\n")); ReleaseMemory(valueBuffer); return NULL; } resultLength = sizeof(LPSTR); // the NULL at the end of the list
numberOfBindings = 0; nextValue = (LPSTR)valueBuffer; while ((len = (int)strlen(nextValue)) != 0) { resultLength += sizeof(LPSTR) + len + 1; if (!_strnicmp(nextValue, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) { resultLength -= sizeof(DEVICE_PREFIX) - 1; } nextValue += len + 1; ++numberOfBindings; } resultBuffer = (LPSTR*)GrabMemory(resultLength); if (!resultBuffer) { return NULL; } nextValue = (LPSTR)valueBuffer; nextResult = resultBuffer; variableData = (LPSTR)(((LPSTR*)resultBuffer) + numberOfBindings + 1); while (numberOfBindings--) {
LPSTR adapterName;
adapterName = nextValue; if (!_strnicmp(adapterName, DEVICE_PREFIX, sizeof(DEVICE_PREFIX) - 1)) { adapterName += sizeof(DEVICE_PREFIX) - 1; } *nextResult++ = variableData; strcpy(variableData, adapterName); TRACE_PRINT(("GetBoundAdapterList: adapterName=%s\n", adapterName )); while (*variableData) { ++variableData; } ++variableData; while (*nextValue) { ++nextValue; } ++nextValue; } *nextResult = NULL; ReleaseMemory(valueBuffer); return resultBuffer; }
/*******************************************************************************
* * MapNodeType * * Converts node type to descriptive string * * ENTRY * * EXIT * * RETURNS pointer to string * * ASSUMES * ******************************************************************************/
LPSTR MapNodeType(UINT Parm) {
DWORD dwParm = LAST_NODE_TYPE + 1;
//
// 1, 2, 4, 8 => log2(n) + 1 [1, 2, 3, 4]
//
switch (Parm) { case 0:
//
// according to JStew value of 0 will be treated as BNode (default)
//
case BNODE: dwParm = 1; break;
case PNODE: dwParm = 2; break;
case MNODE: dwParm = 3; break;
case HNODE: dwParm = 4; break; } if ((dwParm >= FIRST_NODE_TYPE) && (dwParm <= LAST_NODE_TYPE)) { return NodeTypes[dwParm].String; }
//
// if no node type is defined then we default to Hybrid
//
return NodeTypes[LAST_NODE_TYPE].String; }
/*******************************************************************************
* * MapNodeTypeEx * * Converts node type to descriptive string * * ENTRY * * EXIT * * RETURNS pointer to string * * ASSUMES * ******************************************************************************/
LPSTR MapNodeTypeEx(UINT Parm) {
DWORD dwParm = LAST_NODE_TYPE + 1; LPSTR Buf;
Buf = GrabMemory(10);
if (!Buf) { return NULL; }
//
// 1, 2, 4, 8 => log2(n) + 1 [1, 2, 3, 4]
//
switch (Parm) { case 0:
//
// according to JStew value of 0 will be treated as BNode (default)
//
case BNODE: dwParm = 1; break;
case PNODE: dwParm = 2; break;
case MNODE: dwParm = 3; break;
case HNODE: dwParm = 4; break; } if ((dwParm >= FIRST_NODE_TYPE) && (dwParm <= LAST_NODE_TYPE)) { strcpy(Buf, NodeTypesEx[dwParm]); return Buf; }
//
// if no node type is defined then we default to Hybrid
//
strcpy(Buf, NodeTypesEx[LAST_NODE_TYPE]); return Buf; }
/*******************************************************************************
* * MapAdapterType * * Returns a string describing the type of adapter, based on the type retrieved * from TCP/IP * * ENTRY type - type of adapter * * EXIT nothing * * RETURNS pointer to mapped type or pointer to NUL string * * ASSUMES * ******************************************************************************/
LPSTR MapAdapterType(UINT type) { switch (type) { case IF_TYPE_OTHER: return ADAPTER_TYPE(MI_IF_OTHER); // ?
case IF_TYPE_ETHERNET_CSMACD: return ADAPTER_TYPE(MI_IF_ETHERNET);
case IF_TYPE_ISO88025_TOKENRING: return ADAPTER_TYPE(MI_IF_TOKEN_RING);
case IF_TYPE_FDDI: return ADAPTER_TYPE(MI_IF_FDDI);
case IF_TYPE_PPP: return ADAPTER_TYPE(MI_IF_PPP);
case IF_TYPE_SOFTWARE_LOOPBACK: return ADAPTER_TYPE(MI_IF_LOOPBACK);
case IF_TYPE_SLIP: return ADAPTER_TYPE(MI_IF_SLIP); } return ""; }
/*******************************************************************************
* * MapAdapterTypeEx * * Returns a string describing the type of adapter, based on the type retrieved * from TCP/IP * * ENTRY type - type of adapter * * EXIT nothing * * RETURNS pointer to mapped type or pointer to NUL string * * ASSUMES * ******************************************************************************/
LPSTR MapAdapterTypeEx(UINT type) { LPSTR Buf;
Buf = GrabMemory(12);
if (!Buf) { return NULL; }
switch (type) { case IF_TYPE_OTHER: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_OTHER)); // ?
return Buf;
case IF_TYPE_ETHERNET_CSMACD: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_ETHERNET)); return Buf;
case IF_TYPE_ISO88025_TOKENRING: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_TOKEN_RING)); return Buf;
case IF_TYPE_FDDI: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_FDDI)); return Buf;
case IF_TYPE_PPP: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_PPP)); return Buf;
case IF_TYPE_SOFTWARE_LOOPBACK: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_LOOPBACK)); return Buf;
case IF_TYPE_SLIP: strcpy(Buf, ADAPTER_TYPE_EX(MI_IF_SLIP)); return Buf; } strcpy(Buf, ""); return Buf; }
/*******************************************************************************
* * MapAdapterAddress * * Converts the binary adapter address retrieved from TCP/IP into an ASCII * string. Allows for various conversions based on adapter type. The only * mapping we do currently is basic 6-byte MAC address (e.g. 02-60-8C-4C-97-0E) * * ENTRY pAdapterInfo - pointer to IP_ADAPTER_INFO containing address info * Buffer - pointer to buffer where address will be put * * EXIT Buffer - contains converted address * * RETURNS pointer to Buffer * * ASSUMES * ******************************************************************************/
LPSTR MapAdapterAddress(PIP_ADAPTER_INFO pAdapterInfo, LPSTR Buffer) {
LPSTR format; int separator; int len; int i; LPSTR pbuf = Buffer; UINT mask;
len = min((int)pAdapterInfo->AddressLength, sizeof(pAdapterInfo->Address));
switch (pAdapterInfo->Type) { case IF_TYPE_ETHERNET_CSMACD: case IF_TYPE_ISO88025_TOKENRING: case IF_TYPE_FDDI: format = "%02X"; mask = 0xff; separator = TRUE; break;
default: format = "%02x"; mask = 0xff; separator = TRUE; break; } for (i = 0; i < len; ++i) { pbuf += sprintf(pbuf, format, pAdapterInfo->Address[i] & mask); if (separator && (i != len - 1)) { pbuf += sprintf(pbuf, "-"); } } return Buffer; }
/*******************************************************************************
* * MapTime * * Converts IP lease time to more human-sensible string * * ENTRY AdapterInfo - pointer to IP_ADAPTER_INFO owning time variable * TimeVal - DWORD (time_t) time value (number of milliseconds since * virtual year dot) * * EXIT static buffer updated * * RETURNS pointer to string * * ASSUMES 1. The caller realizes this function returns a pointer to a static * buffer, hence calling this function a second time, but before * the results from the previous call have been used, will destroy * the previous results * ******************************************************************************/
LPSTR MapTime(PIP_ADAPTER_INFO AdapterInfo, DWORD_PTR TimeVal) {
struct tm* pTime; static char timeBuf[128]; static char oemTimeBuf[256];
UNREFERENCED_PARAMETER(AdapterInfo);
if ((pTime = localtime((const time_t*)&TimeVal)) != NULL) {
SYSTEMTIME systemTime; int n;
systemTime.wYear = (WORD)(pTime->tm_year + 1900); systemTime.wMonth = (WORD)(pTime->tm_mon + 1); systemTime.wDayOfWeek = (WORD)pTime->tm_wday; systemTime.wDay = (WORD)pTime->tm_mday; systemTime.wHour = (WORD)pTime->tm_hour; systemTime.wMinute = (WORD)pTime->tm_min; systemTime.wSecond = (WORD)pTime->tm_sec; systemTime.wMilliseconds = 0; n = GetDateFormat(0, DATE_LONGDATE, &systemTime, NULL, timeBuf, sizeof(timeBuf)); timeBuf[n - 1] = ' '; GetTimeFormat(0, 0, &systemTime, NULL, &timeBuf[n], sizeof(timeBuf) - n);
//
// we have to convert the returned ANSI string to the OEM charset
//
//
if (CharToOem(timeBuf, oemTimeBuf)) { return oemTimeBuf; }
return timeBuf; } return ""; }
/*******************************************************************************
* * MapTimeEx * * Converts IP lease time to more human-sensible string * * ENTRY AdapterInfo - pointer to IP_ADAPTER_INFO owning time variable * TimeVal - DWORD (time_t) time value (number of milliseconds since * virtual year dot) * * EXIT buffer allocated * * RETURNS pointer to string * * ASSUMES 1. The caller realizes this function returns a pointer to a static * buffer, hence calling this function a second time, but before * the results from the previous call have been used, will destroy * the previous results * ******************************************************************************/
LPSTR MapTimeEx(PIP_ADAPTER_INFO AdapterInfo, DWORD_PTR TimeVal) { LPSTR rettime, rettimeBuf;
rettimeBuf = GrabMemory(128); if (!rettimeBuf) { return NULL; }
rettime = MapTime(AdapterInfo, TimeVal);
if (strcmp(rettime, "") == 0) { rettimeBuf[0] = '\0'; } else { strcpy(rettimeBuf, rettime); } return rettimeBuf; }
/*******************************************************************************
* * MapScopeId * * Converts scope id value. Input is a string. If it is "*" then this denotes * that the scope id is really a null string, so we return an empty string. * Otherwise, the input string is returned * * ENTRY * * EXIT * * RETURNS pointer to string * * ASSUMES * ******************************************************************************/
LPSTR MapScopeId(PVOID Param) { return !strcmp((LPSTR)Param, "*") ? "" : (LPSTR)Param; }
/*******************************************************************************
* * Terminate * * Cleans up - closes the registry handles, ready for process exit * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
VOID Terminate() {
//
// this function probably isn't even necessary - I'm sure the system will
// clean up these handles if we just fall out
//
if (NetbtParametersKey != INVALID_HANDLE_VALUE) { RegCloseKey(NetbtParametersKey); } if (NetbtInterfacesKey != INVALID_HANDLE_VALUE) { RegCloseKey(NetbtInterfacesKey); } if (TcpipParametersKey != INVALID_HANDLE_VALUE) { RegCloseKey(TcpipParametersKey); } if (TcpipLinkageKey != INVALID_HANDLE_VALUE) { RegCloseKey(TcpipLinkageKey); }
}
/*******************************************************************************
* * GrabMemory * * Allocates memory. Exits with a fatal error if LocalAlloc fails, since on NT * I don't expect this ever to occur * * ENTRY size * Number of bytes to allocate * * EXIT * * RETURNS pointer to allocated memory * * ASSUMES * ******************************************************************************/
LPVOID GrabMemory(DWORD size) {
LPVOID p;
p = (LPVOID)LocalAlloc(LMEM_FIXED, size); if (!p) { return NULL; } return p; }
/*******************************************************************************
* * DisplayMessage * * Outputs a message retrieved from the string resource attached to the exe. * Mainly for internationalizable reasons * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
VOID DisplayMessage(BOOL Tabbed, DWORD MessageId, ...) {
va_list argptr; char messageBuffer[2048]; int count;
va_start(argptr, MessageId); count = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, NULL, // use default hModule
MessageId, 0, // use default Language
messageBuffer, sizeof(messageBuffer), &argptr );
if (count == 0) { DEBUG_PRINT(("DisplayMessage: GetLastError() returns %d\n", GetLastError())); }
va_end(argptr); if (Tabbed) { putchar('\t'); } printf(messageBuffer); }
/*******************************************************************************
* * KillFixedInfo * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
VOID KillFixedInfo(PFIXED_INFO Info) {
PIP_ADDR_STRING p; PIP_ADDR_STRING next;
for (p = Info->DnsServerList.Next; p != NULL; p = next) { next = p->Next; ReleaseMemory(p); } ReleaseMemory(Info); }
/*******************************************************************************
* * KillAdapterInfo * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
VOID KillAdapterInfo(PIP_ADAPTER_INFO Info) { PIP_ADDR_STRING p; PIP_ADDR_STRING next; PIP_ADAPTER_INFO CurrAdapter; PIP_ADAPTER_INFO NextAdapter;
for (CurrAdapter=Info; CurrAdapter != NULL; CurrAdapter = NextAdapter) { for (p = CurrAdapter->IpAddressList.Next; p != NULL; p = next) { next = p->Next; ReleaseMemory(p); } for (p = CurrAdapter->GatewayList.Next; p != NULL; p = next) { next = p->Next; ReleaseMemory(p); } for (p = CurrAdapter->SecondaryWinsServer.Next; p != NULL; p = next) { next = p->Next; ReleaseMemory(p); } NextAdapter = CurrAdapter->Next; ReleaseMemory(CurrAdapter); } }
VOID KillAdapterAddresses(PIP_ADAPTER_ADDRESSES Info) { PIP_ADAPTER_UNICAST_ADDRESS pU; PIP_ADAPTER_UNICAST_ADDRESS nextU; PIP_ADAPTER_ANYCAST_ADDRESS pA; PIP_ADAPTER_ANYCAST_ADDRESS nextA; PIP_ADAPTER_MULTICAST_ADDRESS pM; PIP_ADAPTER_MULTICAST_ADDRESS nextM; PIP_ADAPTER_DNS_SERVER_ADDRESS pD; PIP_ADAPTER_DNS_SERVER_ADDRESS nextD; PIP_ADAPTER_PREFIX pP; PIP_ADAPTER_PREFIX nextP; PIP_ADAPTER_ADDRESSES CurrAdapter; PIP_ADAPTER_ADDRESSES NextAdapter;
for (CurrAdapter=Info; CurrAdapter != NULL; CurrAdapter = NextAdapter) { FREE(CurrAdapter->Description); FREE(CurrAdapter->FriendlyName); FREE(CurrAdapter->DnsSuffix); FREE(CurrAdapter->AdapterName);
for (pU = CurrAdapter->FirstUnicastAddress; pU != NULL; pU = nextU) { FREE(pU->Address.lpSockaddr); nextU = pU->Next; FREE(pU); } for (pA = CurrAdapter->FirstAnycastAddress; pA != NULL; pA = nextA) { FREE(pA->Address.lpSockaddr); nextA = pA->Next; FREE(pA); } for (pM = CurrAdapter->FirstMulticastAddress; pM != NULL; pM = nextM) { FREE(pM->Address.lpSockaddr); nextM = pM->Next; FREE(pM); } for (pD = CurrAdapter->FirstDnsServerAddress; pD != NULL; pD = nextD) { FREE(pD->Address.lpSockaddr); nextD = pD->Next; FREE(pD); } for (pP = CurrAdapter->FirstPrefix; pP != NULL; pP = nextP) { FREE(pP->Address.lpSockaddr); nextP = pP->Next; FREE(pP); } NextAdapter = CurrAdapter->Next;
FREE(CurrAdapter); } }
/*******************************************************************************
* * KillPerAdapterInfo * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
VOID KillPerAdapterInfo(PIP_PER_ADAPTER_INFO Info) {
PIP_ADDR_STRING p; PIP_ADDR_STRING next;
for (p = Info->DnsServerList.Next; p != NULL; p = next) { next = p->Next; ReleaseMemory(p); } ReleaseMemory(Info); }
/*******************************************************************************
* * GetIPAddrStringLen * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetIPAddrStringLen(PIP_ADDR_STRING pIPAddrString) { PIP_ADDR_STRING Curr=pIPAddrString->Next; int len = 0;
while (Curr != NULL) { Curr=Curr->Next; len++; } return len; }
/*******************************************************************************
* * GetSizeofFixedInfo * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetSizeofFixedInfo(PFIXED_INFO pFixedInfo) { return (sizeof(FIXED_INFO) + (GetIPAddrStringLen(&pFixedInfo->DnsServerList) * sizeof(IP_ADDR_STRING))); }
/*******************************************************************************
* * GetFixedInfoEx * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetFixedInfoEx(PFIXED_INFO pFixedInfo, PULONG pOutBufLen) {
PFIXED_INFO getinfo; PIP_ADDR_STRING DnsServerList, CurrDnsServerList; uint len;
if (pOutBufLen == NULL) { return ERROR_INVALID_PARAMETER; }
getinfo = GetFixedInfo();
try {
if (!pFixedInfo || (*pOutBufLen < GetSizeofFixedInfo(getinfo)) ) { *pOutBufLen = GetSizeofFixedInfo(getinfo); KillFixedInfo(getinfo); return ERROR_BUFFER_OVERFLOW; }
ZeroMemory(pFixedInfo, *pOutBufLen); CopyMemory(pFixedInfo, getinfo, sizeof(FIXED_INFO));
DnsServerList = getinfo->DnsServerList.Next; CurrDnsServerList = &pFixedInfo->DnsServerList; CurrDnsServerList->Next = NULL; len = sizeof(FIXED_INFO);
while (DnsServerList != NULL) { CurrDnsServerList->Next = (PIP_ADDR_STRING)((ULONG_PTR)pFixedInfo + len); CopyMemory(CurrDnsServerList->Next, DnsServerList, sizeof(IP_ADDR_STRING)); CurrDnsServerList = CurrDnsServerList->Next; DnsServerList = DnsServerList->Next; len = len + sizeof(IP_ADDR_STRING); }
KillFixedInfo(getinfo); return ERROR_SUCCESS; }
except (EXCEPTION_EXECUTE_HANDLER) {
// printf("Exception %d \n", GetExceptionCode());
return ERROR_INVALID_PARAMETER; } }
/*******************************************************************************
* * GetSizeofAdapterInfo * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetSizeofAdapterInfo(PIP_ADAPTER_INFO pAdapterInfo) { DWORD size = 0;
while (pAdapterInfo != NULL) { size += sizeof(IP_ADAPTER_INFO) + (GetIPAddrStringLen(&pAdapterInfo->IpAddressList) * sizeof(IP_ADDR_STRING)) + (GetIPAddrStringLen(&pAdapterInfo->GatewayList) * sizeof(IP_ADDR_STRING)) + (GetIPAddrStringLen(&pAdapterInfo->SecondaryWinsServer) * sizeof(IP_ADDR_STRING)); pAdapterInfo = pAdapterInfo->Next; } return size; }
/*******************************************************************************
* GetSizeofAdapterAddresses * * This routine determines how much memory is used by data organized in a set * of IP_ADAPTER_ADDRESSES information. * * ENTRY pAdapterInfo - information to get total size for * * EXIT * * RETURNS amount of memory used * ******************************************************************************/
DWORD GetSizeofAdapterAddresses(PIP_ADAPTER_ADDRESSES pAdapterInfo) { DWORD size = 0; PIP_ADAPTER_UNICAST_ADDRESS pUAddress; PIP_ADAPTER_ANYCAST_ADDRESS pAAddress; PIP_ADAPTER_MULTICAST_ADDRESS pMAddress; PIP_ADAPTER_DNS_SERVER_ADDRESS pDAddress; PIP_ADAPTER_PREFIX pPrefix;
while (pAdapterInfo != NULL) { size += sizeof(IP_ADAPTER_ADDRESSES); size += (DWORD)(wcslen(pAdapterInfo->FriendlyName)+1) * sizeof(WCHAR); size += (DWORD)(wcslen(pAdapterInfo->Description)+1) * sizeof(WCHAR); size += (DWORD)(wcslen(pAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR); size += (DWORD)(strlen(pAdapterInfo->AdapterName)+1);
size = ALIGN_UP(size, PVOID); for ( pUAddress = pAdapterInfo->FirstUnicastAddress; pUAddress; pUAddress = pUAddress->Next) { size += sizeof(IP_ADAPTER_UNICAST_ADDRESS) + ALIGN_UP(pUAddress->Address.iSockaddrLength, PVOID); } for ( pAAddress = pAdapterInfo->FirstAnycastAddress; pAAddress; pAAddress = pAAddress->Next) { size += sizeof(IP_ADAPTER_ANYCAST_ADDRESS) + ALIGN_UP(pAAddress->Address.iSockaddrLength, PVOID); } for ( pMAddress = pAdapterInfo->FirstMulticastAddress; pMAddress; pMAddress = pMAddress->Next) { size += sizeof(IP_ADAPTER_MULTICAST_ADDRESS) + ALIGN_UP(pMAddress->Address.iSockaddrLength, PVOID); } for ( pDAddress = pAdapterInfo->FirstDnsServerAddress; pDAddress; pDAddress = pDAddress->Next) { size += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + ALIGN_UP(pDAddress->Address.iSockaddrLength, PVOID); } for ( pPrefix = pAdapterInfo->FirstPrefix; pPrefix; pPrefix = pPrefix->Next) { size += sizeof(IP_ADAPTER_PREFIX) + ALIGN_UP(pPrefix->Address.iSockaddrLength, PVOID); } pAdapterInfo = pAdapterInfo->Next; } return size; }
/*******************************************************************************
* * GetSizeofPerAdapterInfo * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetSizeofPerAdapterInfo(PIP_PER_ADAPTER_INFO pPerAdapterInfo) { return (sizeof(IP_PER_ADAPTER_INFO) + (GetIPAddrStringLen(&pPerAdapterInfo->DnsServerList) * sizeof(IP_ADDR_STRING))); }
/*******************************************************************************
* * GetAdapterInfoEx * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetAdapterInfoEx(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) {
PIP_ADAPTER_INFO getinfo, orginfoptr, CurrAdapterInfo; PIP_ADDR_STRING IpAddressList, CurrIpAddressList; PIP_ADDR_STRING GatewayList, CurrGatewayList; PIP_ADDR_STRING SecondaryWinsServer, CurrSecondaryWinsServer; uint len;
if (pOutBufLen == NULL) { return ERROR_INVALID_PARAMETER; }
getinfo = GetAdapterInfo();
if (getinfo == NULL) { return ERROR_NO_DATA; }
orginfoptr = getinfo;
try { if (!pAdapterInfo || (*pOutBufLen < GetSizeofAdapterInfo(getinfo)) ) { *pOutBufLen = GetSizeofAdapterInfo(getinfo); KillAdapterInfo(getinfo); return ERROR_BUFFER_OVERFLOW; }
ZeroMemory(pAdapterInfo, *pOutBufLen);
CurrAdapterInfo = pAdapterInfo;
while (getinfo != NULL) { // pAdapterInfo->Next = (PIP_ADAPTER_INFO)((uint)pAdapterInfo + len);
// copy the adapter info structure
CopyMemory(CurrAdapterInfo, getinfo, sizeof(IP_ADAPTER_INFO));
// copy the IPAddressList & GatewayList
IpAddressList = getinfo->IpAddressList.Next; CurrIpAddressList = &CurrAdapterInfo->IpAddressList; CurrIpAddressList->Next = NULL; len = sizeof(IP_ADAPTER_INFO);
while (IpAddressList != NULL) { CurrIpAddressList->Next = (PIP_ADDR_STRING)((ULONG_PTR)CurrAdapterInfo + len); CopyMemory(CurrIpAddressList->Next, IpAddressList, sizeof(IP_ADDR_STRING)); CurrIpAddressList = CurrIpAddressList->Next; IpAddressList = IpAddressList->Next; len = len + sizeof(IP_ADDR_STRING); }
GatewayList = getinfo->GatewayList.Next; CurrGatewayList = &CurrAdapterInfo->GatewayList; CurrGatewayList->Next = NULL;
while (GatewayList != NULL) { CurrGatewayList->Next = (PIP_ADDR_STRING) ((ULONG_PTR)CurrAdapterInfo + len); CopyMemory(CurrGatewayList->Next, GatewayList, sizeof(IP_ADDR_STRING)); CurrGatewayList = CurrGatewayList->Next; GatewayList = GatewayList->Next; len = len + sizeof(IP_ADDR_STRING); }
SecondaryWinsServer = getinfo->SecondaryWinsServer.Next; CurrSecondaryWinsServer = &CurrAdapterInfo->SecondaryWinsServer; CurrSecondaryWinsServer->Next = NULL;
while (SecondaryWinsServer != NULL) { CurrSecondaryWinsServer->Next = (PIP_ADDR_STRING) ((ULONG_PTR)CurrAdapterInfo + len); CopyMemory(CurrSecondaryWinsServer->Next, SecondaryWinsServer, sizeof(IP_ADDR_STRING)); CurrSecondaryWinsServer = CurrSecondaryWinsServer->Next; SecondaryWinsServer = SecondaryWinsServer->Next; len = len + sizeof(IP_ADDR_STRING); }
pAdapterInfo = CurrAdapterInfo; CurrAdapterInfo->Next = (PIP_ADAPTER_INFO)((ULONG_PTR)CurrAdapterInfo + len); CurrAdapterInfo = CurrAdapterInfo->Next; getinfo = getinfo->Next; }
pAdapterInfo->Next = NULL; KillAdapterInfo(orginfoptr); return ERROR_SUCCESS; } except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// printf("Exception %d \n", GetExceptionCode());
KillAdapterInfo(orginfoptr); return ERROR_INVALID_PARAMETER; } }
DWORD GetAdapterAddressesEx(ULONG Family, DWORD Flags, PIP_ADAPTER_ADDRESSES pAdapterInfo, PULONG pOutBufLen) {
PIP_ADAPTER_ADDRESSES getinfo, orginfoptr, CurrAdapterInfo; PIP_ADAPTER_UNICAST_ADDRESS SrcUAddress, *pDestUAddress; PIP_ADAPTER_ANYCAST_ADDRESS SrcAAddress, *pDestAAddress; PIP_ADAPTER_MULTICAST_ADDRESS SrcMAddress, *pDestMAddress; PIP_ADAPTER_DNS_SERVER_ADDRESS SrcDAddress, *pDestDAddress; ULONG_PTR pDestBuffer; DWORD dwErr;
if (pOutBufLen == NULL) { return ERROR_INVALID_PARAMETER; }
dwErr = GetAdapterAddresses(Family, Flags, &getinfo); if (dwErr != NO_ERROR) { if (getinfo) { KillAdapterAddresses(getinfo); } return dwErr; }
if (getinfo == NULL) { return ERROR_NO_DATA; }
orginfoptr = getinfo;
try { if (!pAdapterInfo || (*pOutBufLen < GetSizeofAdapterAddresses(getinfo)) ) { *pOutBufLen = GetSizeofAdapterAddresses(getinfo); KillAdapterAddresses(getinfo); return ERROR_BUFFER_OVERFLOW; }
ZeroMemory(pAdapterInfo, *pOutBufLen);
CurrAdapterInfo = pAdapterInfo;
while (getinfo != NULL) { // pAdapterInfo->Next = (PIP_ADAPTER_ADDRESSES)((uint)pAdapterInfo + len);
// copy the adapter info structure
CopyMemory(CurrAdapterInfo, getinfo, sizeof(IP_ADAPTER_ADDRESSES)); pDestBuffer = (ULONG_PTR)CurrAdapterInfo + sizeof(IP_ADAPTER_ADDRESSES);
CurrAdapterInfo->FriendlyName = (PWCHAR)pDestBuffer; wcscpy(CurrAdapterInfo->FriendlyName, getinfo->FriendlyName); pDestBuffer += (wcslen(CurrAdapterInfo->FriendlyName)+1) * sizeof(WCHAR);
CurrAdapterInfo->Description = (PWCHAR)pDestBuffer; wcscpy(CurrAdapterInfo->Description, getinfo->Description); pDestBuffer += (wcslen(CurrAdapterInfo->Description)+1) * sizeof(WCHAR);
CurrAdapterInfo->DnsSuffix = (PWCHAR)pDestBuffer; wcscpy(CurrAdapterInfo->DnsSuffix, getinfo->DnsSuffix); pDestBuffer += (wcslen(CurrAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR);
CurrAdapterInfo->AdapterName = (PCHAR)pDestBuffer; strcpy(CurrAdapterInfo->AdapterName, getinfo->AdapterName); pDestBuffer += (strlen(CurrAdapterInfo->AdapterName)+1);
pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
// copy the address lists
if (!(Flags & GAA_FLAG_SKIP_UNICAST)) { SrcUAddress = getinfo->FirstUnicastAddress; pDestUAddress = &CurrAdapterInfo->FirstUnicastAddress; while (SrcUAddress != NULL) { *pDestUAddress = (PIP_ADAPTER_UNICAST_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcUAddress, sizeof(IP_ADAPTER_UNICAST_ADDRESS)); pDestBuffer += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
(*pDestUAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcUAddress->Address.lpSockaddr, SrcUAddress->Address.iSockaddrLength); pDestBuffer += SrcUAddress->Address.iSockaddrLength; pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestUAddress = &(*pDestUAddress)->Next; SrcUAddress = SrcUAddress->Next; } }
if (!(Flags & GAA_FLAG_SKIP_ANYCAST)) { SrcAAddress = getinfo->FirstAnycastAddress; pDestAAddress = &CurrAdapterInfo->FirstAnycastAddress; while (SrcAAddress != NULL) { *pDestAAddress = (PIP_ADAPTER_ANYCAST_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcAAddress, sizeof(IP_ADAPTER_ANYCAST_ADDRESS)); pDestBuffer += sizeof(IP_ADAPTER_ANYCAST_ADDRESS);
(*pDestAAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcAAddress->Address.lpSockaddr, SrcAAddress->Address.iSockaddrLength); pDestBuffer += SrcAAddress->Address.iSockaddrLength; pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestAAddress = &(*pDestAAddress)->Next; SrcAAddress = SrcAAddress->Next; } }
if (!(Flags & GAA_FLAG_SKIP_MULTICAST)) { SrcMAddress = getinfo->FirstMulticastAddress; pDestMAddress = &CurrAdapterInfo->FirstMulticastAddress; while (SrcMAddress != NULL) { *pDestMAddress = (PIP_ADAPTER_MULTICAST_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcMAddress, sizeof(IP_ADAPTER_MULTICAST_ADDRESS)); pDestBuffer += sizeof(IP_ADAPTER_MULTICAST_ADDRESS);
(*pDestMAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcMAddress->Address.lpSockaddr, SrcMAddress->Address.iSockaddrLength); pDestBuffer += SrcMAddress->Address.iSockaddrLength; pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestMAddress = &(*pDestMAddress)->Next; SrcMAddress = SrcMAddress->Next; } }
if (!(Flags & GAA_FLAG_SKIP_DNS_SERVER)) { SrcDAddress = getinfo->FirstDnsServerAddress; pDestDAddress = &CurrAdapterInfo->FirstDnsServerAddress; while (SrcDAddress != NULL) { *pDestDAddress = (PIP_ADAPTER_DNS_SERVER_ADDRESS)pDestBuffer;
// copy address structure
CopyMemory((PVOID)pDestBuffer, SrcDAddress, sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS)); pDestBuffer += sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS);
(*pDestDAddress)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer;
// copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcDAddress->Address.lpSockaddr, SrcDAddress->Address.iSockaddrLength); pDestBuffer += SrcDAddress->Address.iSockaddrLength; pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestDAddress = &(*pDestDAddress)->Next; SrcDAddress = SrcDAddress->Next; } }
if (Flags & GAA_FLAG_INCLUDE_PREFIX) { PIP_ADAPTER_PREFIX SrcPrefix, *pDestPrefix;
SrcPrefix = getinfo->FirstPrefix; pDestPrefix = &CurrAdapterInfo->FirstPrefix; while (SrcPrefix != NULL) { *pDestPrefix = (PIP_ADAPTER_PREFIX)pDestBuffer;
// copy structure
CopyMemory((PVOID)pDestBuffer, SrcPrefix, sizeof(IP_ADAPTER_PREFIX)); pDestBuffer += sizeof(IP_ADAPTER_PREFIX); (*pDestPrefix)->Address.lpSockaddr = (LPSOCKADDR)pDestBuffer; // copy sockaddr
CopyMemory((PVOID)pDestBuffer, SrcPrefix->Address.lpSockaddr, SrcPrefix->Address.iSockaddrLength); pDestBuffer += SrcPrefix->Address.iSockaddrLength; pDestBuffer = ALIGN_UP_PTR(pDestBuffer, PVOID);
pDestPrefix = &(*pDestPrefix)->Next; SrcPrefix = SrcPrefix->Next; } }
pAdapterInfo = CurrAdapterInfo; CurrAdapterInfo->Next = (PIP_ADAPTER_ADDRESSES)pDestBuffer; CurrAdapterInfo = CurrAdapterInfo->Next; getinfo = getinfo->Next; }
pAdapterInfo->Next = NULL; KillAdapterAddresses(orginfoptr); return ERROR_SUCCESS; } except ((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// printf("Exception %d \n", GetExceptionCode());
KillAdapterAddresses(orginfoptr); return ERROR_INVALID_PARAMETER; } }
/*******************************************************************************
* * GetPerAdapterInfoEx * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD GetPerAdapterInfoEx(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen )
{
PIP_PER_ADAPTER_INFO getinfo; PIP_ADDR_STRING DnsServerList, CurrDnsServerList; UINT len;
if (pOutBufLen == NULL) { return ERROR_INVALID_PARAMETER; }
getinfo = InternalGetPerAdapterInfo(IfIndex);
if (getinfo == NULL) { return ERROR_NO_DATA; }
try {
if (!pPerAdapterInfo || *pOutBufLen < GetSizeofPerAdapterInfo(getinfo)) {
*pOutBufLen = GetSizeofPerAdapterInfo(getinfo); KillPerAdapterInfo(getinfo); return ERROR_BUFFER_OVERFLOW; }
ZeroMemory(pPerAdapterInfo, *pOutBufLen); CopyMemory(pPerAdapterInfo, getinfo, sizeof(IP_PER_ADAPTER_INFO));
DnsServerList = getinfo->DnsServerList.Next; CurrDnsServerList = &pPerAdapterInfo->DnsServerList; CurrDnsServerList->Next = NULL; len = sizeof(IP_PER_ADAPTER_INFO);
while (DnsServerList != NULL) { CurrDnsServerList->Next = (PIP_ADDR_STRING)((ULONG_PTR)pPerAdapterInfo + len); CopyMemory(CurrDnsServerList->Next, DnsServerList, sizeof(IP_ADDR_STRING)); CurrDnsServerList = CurrDnsServerList->Next; DnsServerList = DnsServerList->Next; len = len + sizeof(IP_ADDR_STRING); }
KillPerAdapterInfo(getinfo); return ERROR_SUCCESS; }
except (EXCEPTION_EXECUTE_HANDLER) {
// printf("Exception %d \n", GetExceptionCode());
return ERROR_INVALID_PARAMETER; } }
/*******************************************************************************
* * ReleaseAdapterIpAddress * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
BOOL ReleaseAdapterIpAddress(PIP_ADAPTER_INFO adapterInfo) {
WCHAR wAdapter[MAX_ALLOWED_ADAPTER_NAME_LENGTH + 1]; DWORD status;
//
// check adapter pointer and name
//
if (adapterInfo == NULL || strcmp(adapterInfo->AdapterName, "") == 0) { return FALSE; }
//
// don't bother releasing if the address is already released (0.0.0.0).
//
if (ZERO_IP_ADDRESS(adapterInfo->IpAddressList.IpAddress.String)) { return FALSE; }
//
// convert adapter name to unicode and call DhcpReleaseParameters
//
ConvertOemToUnicode(adapterInfo->AdapterName, wAdapter);
status = DhcpReleaseParameters(wAdapter); TRACE_PRINT(("DhcpReleaseParameters(%ws) returns %d\n", wAdapter, status));
return status == ERROR_SUCCESS; }
/*******************************************************************************
* * RenewAdapterIpAddress * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
BOOL RenewAdapterIpAddress(PIP_ADAPTER_INFO adapterInfo) {
WCHAR wAdapter[MAX_ALLOWED_ADAPTER_NAME_LENGTH + 1]; DWORD status;
//
// check adapter pointer and name
//
if (adapterInfo == NULL || strcmp(adapterInfo->AdapterName, "") == 0) { return FALSE; }
//
// convert adapter name to unicode and call DhcpAcquireParameters
//
ConvertOemToUnicode(adapterInfo->AdapterName, wAdapter);
status = DhcpAcquireParameters(wAdapter); TRACE_PRINT(("DhcpAcquireParameters(%ws) returns %d\n", wAdapter, status));
return status == ERROR_SUCCESS; }
/*******************************************************************************
* * SetAdapterIpAddress * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
DWORD APIENTRY SetAdapterIpAddress(LPSTR AdapterName, BOOL EnableDHCP, ULONG IPAddress, ULONG SubnetMask, ULONG DefaultGateway ) { DWORD dwEnableDHCP; DWORD dwWasDHCPEnabled = FALSE; IP_ADDR_STRING IpAddrString; HKEY key; WCHAR Name[MAX_ADAPTER_NAME_LENGTH + 1]; CHAR String[20]; DWORD status;
if (!OpenAdapterKey(KEY_TCP, AdapterName, KEY_ALL_ACCESS, &key)) { return ERROR_CAN_NOT_COMPLETE; }
//
// We cannot handle netcards with multiple addresses,
// so check for that case up front
//
ZeroMemory(&IpAddrString, sizeof(IpAddrString)); if (!ReadRegistryIpAddrString(key, "IPAddress", &IpAddrString)) { return ERROR_CAN_NOT_COMPLETE; }
if (IpAddrString.Next) { PIP_ADDR_STRING p; for (p = IpAddrString.Next; p != NULL; p = IpAddrString.Next) { IpAddrString.Next = p->Next; ReleaseMemory(p); } return ERROR_TOO_MANY_NAMES; }
//
// If we're setting a static address, check to see if the adapter
// currently has a static or DHCP address.
//
if (!EnableDHCP) { MyReadRegistryDword(key, "EnableDHCP", &dwWasDHCPEnabled); }
//
// Update the address, mask, and gateway in the registry
//
dwEnableDHCP = !!EnableDHCP; WriteRegistryDword(key, "EnableDHCP", &dwEnableDHCP);
if (EnableDHCP) { IPAddress = SubnetMask = DefaultGateway = 0; }
ZeroMemory(String, sizeof(String)); lstrcpy(String, inet_ntoa(*(struct in_addr*)&IPAddress)); WriteRegistryMultiString(key, "IPAddress", String);
ZeroMemory(String, sizeof(String)); lstrcpy(String, inet_ntoa(*(struct in_addr*)&SubnetMask)); WriteRegistryMultiString(key, "SubnetMask", String);
ZeroMemory(String, sizeof(String)); if (DefaultGateway) { lstrcpy(String, inet_ntoa(*(struct in_addr*)&DefaultGateway)); } WriteRegistryMultiString(key, "DefaultGateway", String); RegCloseKey(key);
//
// Notify DHCP of the change
//
mbstowcs(Name, AdapterName, MAX_ADAPTER_NAME_LENGTH); if (EnableDHCP) { status = DhcpNotifyConfigChange(NULL, Name, FALSE, 0, 0, 0, DhcpEnable ); } else { //
// If the netcard previously had a static address we need
// to remove it before setting the new address.
//
if (!dwWasDHCPEnabled) { DhcpNotifyConfigChange(NULL, Name, TRUE, 0, 0, 0, IgnoreFlag ); }
status = DhcpNotifyConfigChange(NULL, Name, TRUE, 0, IPAddress, SubnetMask, DhcpDisable ); } return status; }
/*******************************************************************************
* * GetDnsServerList * * Gets DNS server List * * ENTRY * * EXIT * * RETURNS * * ASSUMES * ******************************************************************************/
BOOL GetDnsServerList(PIP_ADDR_STRING IpAddr) {
PIP_ADAPTER_INFO adapterList; PIP_ADAPTER_INFO adapter; LONG err = ERROR_PATH_NOT_FOUND; HKEY key; BOOL ok;
TRACE_PRINT(("Entered GetDnsServerList\n"));
if ((adapterList = GetAdapterInfo()) != NULL) {
//
// scan the adapter list and try to insert DNS names to IpAddr
//
for (adapter = adapterList; adapter; adapter = adapter->Next) {
if (adapter->AdapterName[0] && OpenAdapterKey(KEY_TCP, adapter->AdapterName, KEY_READ, &key)) {
//
// DNS Server list: first NameServer and then DhcpNameServer
//
ok = ReadRegistryIpAddrString(key, TEXT("NameServer"), IpAddr);
if (!ok) {
ok = ReadRegistryIpAddrString(key, TEXT("DhcpNameServer"), IpAddr);
}
if (ok) { err = ERROR_SUCCESS; }
RegCloseKey(key);
} else { DEBUG_PRINT(("Cannot OpenAdapterKey KEY_TCP '%s', gle=%d\n", adapter->AdapterName, GetLastError())); } }
KillAdapterInfo(adapterList); } else { DEBUG_PRINT(("GetDnsServerList: GetAdapterInfo returns NULL\n")); }
TRACE_PRINT(("Exit GetDnsServerList\n"));
return (err == ERROR_SUCCESS); }
/*******************************************************************************
* GetAdapterOrderMap * * This routine builds an array which maps interface indices to their * respective adapter orderings. * * ENTRY nothing * * EXIT nothing * * RETURNS IP_ADAPTER_ORDER_MAP * ******************************************************************************/
PIP_ADAPTER_ORDER_MAP APIENTRY GetAdapterOrderMap() { LPWSTR AdapterOrder = NULL; LPWSTR Adapter; PIP_ADAPTER_ORDER_MAP AdapterOrderMap = NULL; DWORD dwErr; DWORD dwType; DWORD dwSize; DWORD i; DWORD j; PIP_INTERFACE_INFO InterfaceInfo = NULL;
for(;;) {
//
// Retrieve the 'Bind' REG_MULTI_SZ from the Tcpip\Linkage key.
// This string-list tells us the current adapter order,
// with each entry being of the form \Device\{GUID}.
//
dwSize = 0; dwErr = RegQueryValueExW(TcpipLinkageKey, L"Bind", NULL, &dwType, NULL, &dwSize); if (dwErr != NO_ERROR || dwType != REG_MULTI_SZ) { break; } AdapterOrder = (LPWSTR)GrabMemory(dwSize); if (!AdapterOrder) { break; } dwErr = RegQueryValueExW(TcpipLinkageKey, L"Bind", NULL, &dwType, (LPBYTE)AdapterOrder, &dwSize); if (dwErr != NO_ERROR || dwType != REG_MULTI_SZ) { break; }
//
// Retrieve the IP interface information from TCP/IP.
// This information tells us the interface index
// for each adapter GUID,
//
dwSize = 0; dwErr = GetInterfaceInfo(NULL, &dwSize); if (dwErr != ERROR_INSUFFICIENT_BUFFER && dwErr != ERROR_BUFFER_OVERFLOW) { break; } InterfaceInfo = GrabMemory(dwSize); if (!InterfaceInfo) { break; } dwErr = GetInterfaceInfo(InterfaceInfo, &dwSize); if (dwErr != NO_ERROR) { break; }
//
// Construct a mapping from the interfaces in 'InterfaceInfo'
// to their positions in 'AdapterOrder'. In other words,
// construct an array of interface indices in which location i
// contains the index of the interface which is in location i
// in 'AdapterOrder'.
//
AdapterOrderMap = GrabMemory(FIELD_OFFSET(IP_ADAPTER_ORDER_MAP, AdapterOrder[InterfaceInfo->NumAdapters])); if (!AdapterOrderMap) { break; }
for (i = 0, Adapter = AdapterOrder; *Adapter && i < (DWORD)InterfaceInfo->NumAdapters; Adapter += lstrlenW(Adapter) + 1) {
//
// See if this is the NdiswanIp device, which corresponds to
// all Ndiswan interfaces. To implement adapter ordering
// for Ndiswan interfaces, we store their indices
// into successive locations in the adapter-order map
// based on the location of the string '\Device\NdiswanIp'
// in the adapter-order list.
//
if (lstrcmpiW(c_szDeviceNdiswanIp, Adapter) == 0) {
//
// This is the \Device\NdiswanIp entry, so list all Ndiswan
// interfaces in the adapter-order map now.
// Unfortunately, 'InterfaceInfo' does not tell us the type
// of each interface. In order to figure out which interfaces
// are Ndiswan interfaces, we enumerate all interfaces (again)
// and look for entries whose type is 'IF_TYPE_PPP'.
//
PMIB_IFTABLE IfTable; dwErr = AllocateAndGetIfTableFromStack(&IfTable, FALSE, GetProcessHeap(), 0, FALSE); if (dwErr == NO_ERROR) { for (j = 0; j < IfTable->dwNumEntries && i < (DWORD)InterfaceInfo->NumAdapters; j++) { if (IfTable->table[j].dwType == IF_TYPE_PPP) { AdapterOrderMap->AdapterOrder[i++] = IfTable->table[j].dwIndex; } } HeapFree(GetProcessHeap(), 0, IfTable); } continue; }
//
// Now handle all other interfaces by matching the GUID
// in 'Adapter' to the GUID of an interface in 'InterfaceInfo'.
// We then store the index of the interface found, if any,
// in the next location in 'AdapterOrderMap'.
//
for (j = 0; j < (DWORD)InterfaceInfo->NumAdapters; j++) { if (lstrcmpiW(InterfaceInfo->Adapter[j].Name + sizeof(c_szDeviceTcpip) - 1, Adapter + sizeof(c_szDevice) - 1) == 0) { AdapterOrderMap->AdapterOrder[i++] = InterfaceInfo->Adapter[j].Index; break; } } } AdapterOrderMap->NumAdapters = i; ReleaseMemory(InterfaceInfo); ReleaseMemory(AdapterOrder); return AdapterOrderMap; } if (InterfaceInfo) { ReleaseMemory(InterfaceInfo); } if (AdapterOrder) { ReleaseMemory(AdapterOrder); } return NULL; }
|