📄 network.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <ssdppch.h>
#pragma hdrstop
#include <iphlpapi.h>
#include "md5.h"
#include "ipsupport.h"
#include "ssdpnetwork.h"
#include "upnp_config.h"
long g_bExitSSDPReadThread = FALSE;
CHAR g_lpszNls[100]; // string representation of current NLS
MD5_CTX g_md5Nls; // md5 context used during calculation of NLS
extern CHAR g_pszNlsFormat[65];
extern SOCKADDR_IN MulticastAddressIPv4;
extern SOCKADDR_IN6 MulticastLinkScopeAddressIPv6;
extern SOCKADDR_IN6 MulticastSiteScopeAddressIPv6;
// a list of distinct networks hosted on this machine
static LIST_ENTRY listNetwork;
static CRITICAL_SECTION CSListNetwork;
// prototypes
static PSSDPNetwork AddToListNetwork(PSOCKADDR_STORAGE IpAddress);
VOID FreeSSDPNetwork(SSDPNetwork *pSSDPNetwork);
// functions
VOID GetNetworkLock()
{
EnterCriticalSection(&CSListNetwork);
}
VOID FreeNetworkLock()
{
LeaveCriticalSection(&CSListNetwork);
}
// should be called while holding NetworkLock
PSSDPNetwork GetNextNetwork(PSSDPNetwork prev)
{
PLIST_ENTRY p = listNetwork.Flink;
PLIST_ENTRY pListHead = &listNetwork;
if (prev)
p = prev->linkage.Flink;
if (p != &listNetwork)
{
return CONTAINING_RECORD (p, SSDPNetwork, linkage);
}
return NULL;
}
/***********************************************************
Function : AddSocketToNetworkList()
New function pulled out of GetNetworks() as we may need to do this twice for each
interface. Once for v4 & once for v6.
Open & bind a socket (using SocketOpen() ) & then add it to the list
***********************************************************/
void AddSocketToNetworkList(PSOCKADDR_STORAGE pSockaddr, int iSockaddrLength, DWORD dwAdapterIndex)
{
SOCKET socketToOpen = INVALID_SOCKET;
PSOCKADDR pMulticastAddr = NULL;
DWORD dwScopeId = 0, dwScope = 0;
// select proper multicast address
if(pSockaddr->ss_family == AF_INET)
{
pMulticastAddr = (PSOCKADDR)&MulticastAddressIPv4;
((PSOCKADDR_IN)pSockaddr)->sin_port = htons(SSDP_PORT);
}
else if(pSockaddr->ss_family == AF_INET6)
{
((PSOCKADDR_IN6)pSockaddr)->sin6_port = htons(SSDP_PORT);
if(IN6_IS_ADDR_LINKLOCAL(&((PSOCKADDR_IN6)pSockaddr)->sin6_addr))
{
// scope and scope id for the link
dwScopeId = dwAdapterIndex;
dwScope = 1;
// multicast address with link scope
pMulticastAddr = (PSOCKADDR)&MulticastLinkScopeAddressIPv6;
}
else if(IN6_IS_ADDR_SITELOCAL(&((PSOCKADDR_IN6)pSockaddr)->sin6_addr))
{
// check if site scope should be supported
if(upnp_config::site_scope() < 3)
return;
// scope and scope id for the site
dwScopeId = ((PSOCKADDR_IN6)pSockaddr)->sin6_scope_id;
dwScope = 2;
// multicast address with site scope
pMulticastAddr = (PSOCKADDR)&MulticastSiteScopeAddressIPv6;
}
else
// scope not supported by UPnP
return;
Assert(dwScope != 0);
Assert(dwScopeId != 0);
// check if we already have address with the same scope and scope id
PSSDPNetwork pNet = NULL;
GetNetworkLock();
while(pNet = GetNextNetwork(pNet))
if(pNet->dwScopeId == dwScopeId && pNet->dwScope == dwScope)
break;
FreeNetworkLock();
if(pNet != NULL)
return;
}
else
return; // unknown address family
// create a socket
if(SocketOpen(&socketToOpen, (PSOCKADDR)pSockaddr, dwAdapterIndex, pMulticastAddr))
{
SSDPNetwork *pSsdpNetwork;
// create network
pSsdpNetwork = (SSDPNetwork*) malloc (sizeof(SSDPNetwork));
if (pSsdpNetwork != NULL)
{
WCHAR lpwszAddress[MAX_ADDRESS_SIZE];
DWORD dwSize;
// add address to the digest
MD5Update(&g_md5Nls, (uchar*)pSockaddr, iSockaddrLength);
memset(pSsdpNetwork, 0, sizeof(*pSsdpNetwork));
pSsdpNetwork->Type = SSDP_NETWORK_SIGNATURE;
pSsdpNetwork->state = NETWORK_INIT;
pSsdpNetwork->pMulticastAddr = pMulticastAddr;
pSsdpNetwork->dwIndex = dwAdapterIndex;
pSsdpNetwork->dwScopeId = dwScopeId;
pSsdpNetwork->dwScope = dwScope;
pSsdpNetwork->socket = socketToOpen;
// set UPnP port so that it is included in address string
if(pSockaddr->ss_family == AF_INET)
{
((PSOCKADDR_IN)pSockaddr)->sin_port = htons(upnp_config::port());
}
else
{
((PSOCKADDR_IN6)pSockaddr)->sin6_port = htons(upnp_config::port());
((PSOCKADDR_IN6)pSockaddr)->sin6_scope_id = 0;
}
// store address in string form
WSAAddressToString((LPSOCKADDR)pSockaddr, iSockaddrLength, NULL, lpwszAddress, &(dwSize = sizeof(lpwszAddress)));
wcstombs(pSsdpNetwork->pszAddressString, lpwszAddress, sizeof(pSsdpNetwork->pszAddressString));
// reset UPnP port and scope to get address string w/o port/scope id
if(pSockaddr->ss_family == AF_INET)
{
((PSOCKADDR_IN)pSockaddr)->sin_port = 0;
}
else
{
((PSOCKADDR_IN6)pSockaddr)->sin6_port = 0;
}
// store IP in string form
WSAAddressToString((LPSOCKADDR)pSockaddr, iSockaddrLength, NULL, lpwszAddress, &(dwSize = sizeof(lpwszAddress)));
wcstombs(pSsdpNetwork->pszIPString, lpwszAddress, sizeof(pSsdpNetwork->pszIPString));
// store multicast address in string form
WSAAddressToString((LPSOCKADDR)pMulticastAddr, iSockaddrLength, NULL, lpwszAddress, &(dwSize = sizeof(lpwszAddress)));
wcstombs(pSsdpNetwork->pszMulticastAddr, lpwszAddress, sizeof(pSsdpNetwork->pszMulticastAddr));
// Add it to the list
GetNetworkLock();
InsertHeadList(&listNetwork, &(pSsdpNetwork->linkage));
FreeNetworkLock();
}
else
{
TraceTag(ttidSsdpNetwork, "AddSocketToNetworkList() - couldn't allocate pSsdpNetwork");
}
} // END if( SocketOpen() )
}
/***********************************************************
Function : GetNetworks()
Build list of sockets on which we send & receive SSDP multicast announcements.
Almost complete rewrite of function which previously used getAdapters Info() to
build the list of addresses and chose the 1st address per adapter.
Loop through all the available adapters (interfaces)
For each adapter loop through the available addresses
Use addresses which are either loopback, or where the adapter is multicast capable
If address found is IPv4, just take the first one we find per adapter
If it's IPv6 then look at all the addresses & pick the most preferred (order is
Site Local 1st preference, then Link Local else we use a global address)
For the IPv6 loopback we select the standard loopback, i.e we'll take ::1 in preference
to fe80::1 .
For each chosen address open a socket & add it to the list using AddSocketToNetworkList()
We also now store the adapter guid, so that we can match V4 & V6 addresses to the same
interface in order to build the AL header.
On sucess returns 0.
***********************************************************/
INT GetNetworks()
{
PIP_ADAPTER_ADDRESSES pAdapterAddresses = NULL; // buffer used by GetAdaptersAddresses()
ULONG ulBufSize = 0; // size of buffer returned by GetAdaptersAddresses()
DWORD dwRes = 0; // result codes from iphelper apis
bool bIPv6 = false;
MD5Init(&g_md5Nls);
// Find out size of returned buffer
dwRes = GetAdaptersAddresses(
upnp_config::family(),
GAA_FLAG_SKIP_ANYCAST |GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdapterAddresses,
&ulBufSize
);
if(ulBufSize)
{
// Allocate sufficient Space
pAdapterAddresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(malloc(ulBufSize));
if (pAdapterAddresses !=NULL)
{
// Get Adapter List
dwRes = GetAdaptersAddresses(
upnp_config::family(),
GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_DNS_SERVER,
NULL,
pAdapterAddresses,
&ulBufSize
);
if (dwRes == ERROR_SUCCESS)
{
// Loop through all the adapters (interfaces) returned
for(PIP_ADAPTER_ADDRESSES pAdapterIter = pAdapterAddresses; pAdapterIter != NULL; pAdapterIter = pAdapterIter->Next)
{
// don't use tunneling adapters
if(pAdapterIter->IfType == IF_TYPE_TUNNEL)
continue;
if(!upnp_config::is_adapter_enabled(pAdapterIter->AdapterName))
continue;
TraceTag(ttidSsdpNetwork, "GetNetworks() - Adapter %d : %S \n", pAdapterIter->IfIndex, pAdapterIter->FriendlyName);
// Loop through all the addresses returned
for(PIP_ADAPTER_UNICAST_ADDRESS pUnicastAddress = pAdapterIter->FirstUnicastAddress;
pUnicastAddress != NULL;
pUnicastAddress = pUnicastAddress->Next)
{
SOCKADDR_STORAGE sockaddr = {0};
memcpy(&sockaddr, pUnicastAddress->Address.lpSockaddr, pUnicastAddress->Address.iSockaddrLength);
if(sockaddr.ss_family == AF_INET)
AddSocketToNetworkList(&sockaddr, pUnicastAddress->Address.iSockaddrLength, pAdapterIter->IfIndex);
else
{
AddSocketToNetworkList(&sockaddr, pUnicastAddress->Address.iSockaddrLength, pAdapterIter->Ipv6IfIndex);
bIPv6 = true;
}
}
}
}
// Tidy up
free (pAdapterAddresses);
}
}
MD5Final(&g_md5Nls);
sprintf(g_lpszNls, g_pszNlsFormat, ((WORD*)g_md5Nls.digest)[0],
((WORD*)g_md5Nls.digest)[1],
((WORD*)g_md5Nls.digest)[2],
((WORD*)g_md5Nls.digest)[3],
((WORD*)g_md5Nls.digest)[4],
((WORD*)g_md5Nls.digest)[5],
((WORD*)g_md5Nls.digest)[6],
((WORD*)g_md5Nls.digest)[7]);
if(!bIPv6 && !upnp_config::use_nls_for_IPv4())
g_lpszNls[0] = '\x0';
return 0;
}
VOID InitializeListNetwork()
{
InitializeCriticalSection(&CSListNetwork);
GetNetworkLock();
InitializeListHead(&listNetwork);
FreeNetworkLock();
}
VOID FreeSSDPNetwork(SSDPNetwork *pSSDPNetwork)
{
Assert(pSSDPNetwork);
GetNetworkLock();
RemoveEntryList(&(pSSDPNetwork->linkage));
if (pSSDPNetwork->socket != INVALID_SOCKET)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -