/*++ 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 #include // for in6addr_any #include #include #include #include #include // // 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 #define MAX_FRIENDLY_NAME_LENGTH 80 #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(PPIP_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; 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; HKEY transientKey; 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)); } #endif // // NodeType: static then DHCP // ok = MyReadRegistryDword(NetbtParametersKey, TEXT("NodeType"), &fixedInfo->NodeType ); if (!ok) { ok = MyReadRegistryDword(NetbtParametersKey, TEXT("DhcpNodeType"), &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"), &fixedInfo->EnableRouting ); ok = MyReadRegistryDword(NetbtParametersKey, TEXT("EnableProxy"), &fixedInfo->EnableProxy ); ok = MyReadRegistryDword(NetbtParametersKey, TEXT("EnableDNS"), &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; while( 1 ) { 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; LPSTR name; int i; HKEY key; TRACE_PRINT(("Entered GetAdapterInfo\n")); if (currentAdapterNames = GetAdapterNameToIndexInfo()) { if (adapterList = GetAdapterList()) { // // 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) { ULONG 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; ULONG length; BOOL ok; MyReadRegistryDword(key, TEXT("EnableDHCP"), &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; 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 anonymous 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; 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; 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 * 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, DWORD Flags, DWORD Family) { 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 * 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, DWORD, DWORD), PVOID arg1, PVOID arg2, PVOID arg3, DWORD Flags, DWORD Family) { IPV6_QUERY_ADDRESS Query; IPV6_INFO_ADDRESS ADE; u_int 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, 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, ULONG 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 = 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 pD, *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); } } } 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; } do { 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); } } } while (FALSE); 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) { DWORD i; *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; DWORD dwErr; // 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) { ASSERT(pIf->Ipv6IfIndex == 0); pIf->Ipv6IfIndex = Ipv6IfIndex; CopyMemory(pIf->ZoneIndices, ZoneIndices, ADE_GLOBAL * sizeof(DWORD)); } *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 * 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, 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_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_FRIENDLY_NAME_LENGTH+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; dwErr = NewIpAdapter(&pCurr, ppNext, szGuid, NameForDnsInfo, 0, ADE->This.IF.Index, Flags, dwIfType, IF->LinkMTU, (BYTE*)&Ipv4Address, sizeof(Ipv4Address), pwszDescription, wszFriendlyName, 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, 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; WCHAR buff[NI_MAXHOST]; 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; } dwTemp = ulNumChars; 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, dwCount = 0; ULONG MaskLen, 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_FRIENDLY_NAME_LENGTH + 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, 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, 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, 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, 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, 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, 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; u_int 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; 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; (idwNumEntries; 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<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_FRIENDLY_NAME_LENGTH + 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; iAdapterName, wszFriendlyName, MAX_FRIENDLY_NAME_LENGTH); } 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; // // 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; } for (IF=pAdapterInfo; IF; IF=IF->Next) { dwErr = (*func)(IF, 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; u_int 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; Cleanup: if (pIpAddrTable) { FREE(pIpAddrTable); } if (pAdapterInfo) { KillAdapterInfo(pAdapterInfo); } 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"), &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"), &perAdapterInfo->AutoconfigActive); TRACE_PRINT(("AddressType !%s\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"\ * or NetBT\Adapters\ * or Tcpip6\Paramters\ * * 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\ 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; int i = 0, 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( &Value[i], NULL, 0 ); TRACE_PRINT((" NumList[%d] = '%s' => %d\n", k, &Value[i], NumList[k] )); k++; i += strlen( &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 = 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)) { *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 = strlen(nextValue)) { 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]; if (pTime = localtime(&TimeVal)) { SYSTEMTIME systemTime; char* pTimeBuf = timeBuf; int n; systemTime.wYear = pTime->tm_year + 1900; systemTime.wMonth = 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 += (wcslen(pAdapterInfo->FriendlyName)+1) * sizeof(WCHAR); size += (wcslen(pAdapterInfo->Description)+1) * sizeof(WCHAR); size += (wcslen(pAdapterInfo->DnsSuffix)+1) * sizeof(WCHAR); size += (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 (EXCEPTION_EXECUTE_HANDLER) { // 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; uint len; 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 (EXCEPTION_EXECUTE_HANDLER) { // 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 dwDHCPEnabled; 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) { if (!MyReadRegistryDword(key, "EnableDHCP", &dwDHCPEnabled)) { // // If an error occurs assume that DHCP was NOT enabled. // dwDHCPEnabled = FALSE; } } // // 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 (!dwDHCPEnabled) { 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; PIP_PER_ADAPTER_INFO perAdapterInfo = NULL; 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; do { // // 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; } while(FALSE); if (InterfaceInfo) { ReleaseMemory(InterfaceInfo); } if (AdapterOrder) { ReleaseMemory(AdapterOrder); } return NULL; }