You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5907 lines
181 KiB
5907 lines
181 KiB
/*++
|
|
|
|
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;
|
|
}
|