windows-nt/Source/XPSP1/NT/termsrv/remdsk/server/ics/icshelper/raicshelp.c

2159 lines
54 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*****************************************************************************
******************************************************************************
**
**
** RAICShelp.c
** Contains the useful public entry points to an ICS-assistance library
** created for the Salem/PCHealth Remote Assistance feature in Whistler
**
** Dates:
** 11-1-2000 created by TomFr
** 11-17-2000 re-written as a DLL, had been an object.
** 2-15-20001 Changed to a static lib, support added for dpnathlp.dll
** 5-2-2001 Support added for dpnhupnp.dll & dpnhpast.dll
**
******************************************************************************
*****************************************************************************/
#define INIT_GUID
#include <windows.h>
#include <objbase.h>
#include <initguid.h>
#include <winsock2.h>
#include <MMSystem.h>
#include <WSIPX.h>
#include <Iphlpapi.h>
#include <stdlib.h>
#include <malloc.h>
#include "ICSutils.h"
#include "rsip.h"
#include "icshelpapi.h"
#include <dpnathlp.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*****************************************************************************
** Some global variables
*****************************************************************************/
// the mark of the beast...
#define NO_ICS_HANDLE 0x666
long g_waitDuration=120000;
BOOL g_boolIcsPresent = FALSE;
BOOL g_boolIcsOnThisMachine = FALSE;
BOOL g_boolIcsFound = FALSE;
BOOL g_boolUsingNatHelp = FALSE;
BOOL g_boolUsingNatPAST = FALSE;
BOOL g_boolInitialized = FALSE;
SOCKADDR_IN g_saddrLocal;
HANDLE g_hWorkerThread = 0;
HMODULE g_hModDpNatHlp = NULL;
PDIRECTPLAYNATHELP g_pDPNH = NULL;
char g_szPublicAddr[45];
char *g_lpszDllName = "NULL";
char szInternal[]="internal";
typedef struct _MAPHANDLES {
int iMapped;
DPNHHANDLE hMapped[16];
} MAPHANDLES, *PMAPHANDLES;
#define DP_NAT_HANDLES 256
PMAPHANDLES g_PortHandles[DP_NAT_HANDLES];
int iDbgFileHandle;
typedef struct _SUPDLLS {
char *szDllName;
BOOL bUsesUpnp; // TRUE if we ICS supports UPnP
} SUPDLLS, *PSUPDLLS;
SUPDLLS strDpHelp[] =
{
{"dpnhupnp.dll", TRUE},
{"dpnhpast.dll", FALSE},
{NULL, FALSE}
};
/******* USEFULL STUFF **********/
#ifndef ARRAYSIZE
#define ARRAYSIZE(x) sizeof(x)/sizeof(x[0])
#endif
// forward declares...
int GetTsPort(void);
/****************************************************************************
**
** DumpLibHr-
** Gives us debug spew for the HRESULTS coming back from DPNATHLP.DLL
**
****************************************************************************/
void DumpLibHr(HRESULT hr)
{
char *pErr = NULL;
char scr[400];
switch (hr){
case DPNH_OK:
pErr = "DPNH_OK";
break;
case DPNHSUCCESS_ADDRESSESCHANGED:
pErr = "DPNHSUCCESS_ADDRESSESCHANGED";
break;
case DPNHERR_ALREADYINITIALIZED:
pErr = "DPNHERR_ALREADYINITIALIZED";
break;
case DPNHERR_BUFFERTOOSMALL:
pErr = "DPNHERR_BUFFERTOOSMALL";
break;
case DPNHERR_GENERIC:
pErr = "DPNHERR_GENERIC";
break;
case DPNHERR_INVALIDFLAGS:
pErr = "DPNHERR_INVALIDFLAGS";
break;
case DPNHERR_INVALIDOBJECT:
pErr = "DPNHERR_INVALIDOBJECT";
break;
case DPNHERR_INVALIDPARAM:
pErr = "DPNHERR_INVALIDPARAM";
break;
case DPNHERR_INVALIDPOINTER:
pErr = "DPNHERR_INVALIDPOINTER";
break;
case DPNHERR_NOMAPPING:
pErr = "DPNHERR_NOMAPPING";
break;
case DPNHERR_NOMAPPINGBUTPRIVATE:
pErr = "DPNHERR_NOMAPPINGBUTPRIVATE";
break;
case DPNHERR_NOTINITIALIZED:
pErr = "DPNHERR_NOTINITIALIZED";
break;
case DPNHERR_OUTOFMEMORY:
pErr = "DPNHERR_OUTOFMEMORY";
break;
case DPNHERR_PORTALREADYREGISTERED:
pErr = "DPNHERR_PORTALREADYREGISTERED";
break;
case DPNHERR_PORTUNAVAILABLE:
pErr = "DPNHERR_PORTUNAVAILABLE";
break;
case DPNHERR_SERVERNOTAVAILABLE:
pErr = "DPNHERR_SERVERNOTAVAILABLE";
break;
case DPNHERR_UPDATESERVERSTATUS:
pErr = "DPNHERR_UPDATESERVERSTATUS";
break;
default:
wsprintfA(scr, "unknown error: 0x%x", hr);
pErr = scr;
break;
};
IMPORTANT_MSG((L"DpNatHlp result=%S", pErr));
}
/****************************************************************************
**
** GetAllAdapters
**
****************************************************************************/
int GetAllAdapters(int *iFound, int iMax, SOCKADDR_IN *sktArray)
{
PIP_ADAPTER_INFO p;
PIP_ADDR_STRING ps;
DWORD dw;
ULONG ulSize = 0;
int i=0;
PIP_ADAPTER_INFO pAdpInfo = NULL;
if (!iFound || !sktArray) return 1;
*iFound = 0;
ZeroMemory(sktArray, sizeof(SOCKADDR) * iMax);
dw = GetAdaptersInfo(
pAdpInfo,
&ulSize );
pAdpInfo = (IP_ADAPTER_INFO*)malloc(ulSize);
if (!pAdpInfo)
{
INTERESTING_MSG((L"GetAddr malloc failed"));
return 1;
}
dw = GetAdaptersInfo(
pAdpInfo,
&ulSize);
if (dw != ERROR_SUCCESS)
{
INTERESTING_MSG((L"GetAdaptersInfo failed"));
free(pAdpInfo);
return 1;
}
for(p=pAdpInfo; p!=NULL; p=p->Next)
{
for(ps = &(p->IpAddressList); ps; ps=ps->Next)
{
if (strcmp(ps->IpAddress.String, "0.0.0.0") != 0 && i < iMax)
{
sktArray[i].sin_family = AF_INET;
sktArray[i].sin_addr.S_un.S_addr = inet_addr(ps->IpAddress.String);
TRIVIAL_MSG((L"Found adapter #%d at [%S]", i+1, ps->IpAddress.String));
i++;
}
}
}
*iFound = i;
TRIVIAL_MSG((L"GetAllAdapters- %d found", *iFound));
free(pAdpInfo);
return 0;
}
/****************************************************************************
**
** OpenPort(int port)
** if there is no ICS available, then we should just return...
**
** Of course, we save away the Port, as it goes back in the
** FetchAllAddresses call, asthe formatted "port" whenever a
** different one is not specified.
**
****************************************************************************/
DWORD APIENTRY OpenPort(int Port)
{
DWORD dwRet = (int)-1;
TRIVIAL_MSG((L"OpenPort(%d)", Port ));
if (!g_boolInitialized)
{
HEINOUS_E_MSG((L"ERROR: OpenPort- library not initialized"));
return 0;
}
// save away for later retrieval
g_iPort = Port;
if (g_boolIcsPresent && g_pDPNH)
{
HRESULT hr=0;
int i;
DPNHHANDLE *pHnd;
SOCKADDR_IN lSockAddr[16];
PMAPHANDLES hMap;
for (i=0;g_PortHandles[i] != NULL; i++);
if (i >= ARRAYSIZE(g_PortHandles))
{
// we have no more memory for mappings!
// should never hit this, unless we are leaking...
HEINOUS_E_MSG((L"Out of table space in OpenPort"));
return 0;
}
// now we have a pointer for our handle array
hMap = (PMAPHANDLES)malloc(sizeof(MAPHANDLES));
g_PortHandles[i] = hMap;
dwRet = 0x8000000 + i;
// get adapters
GetAllAdapters(&hMap->iMapped, ARRAYSIZE(lSockAddr), &lSockAddr[0]);
TRIVIAL_MSG((L"GetAllAdapters found %d adapters to deal with", hMap->iMapped));
/* Now we cycle through all the found adapters and get a mapping for each
* This insures that the ICF is opened on all adapters...
*/
for (i = 0; i < hMap->iMapped; i++)
{
pHnd = &hMap->hMapped[i];
lSockAddr[i].sin_port = ntohs((unsigned)Port);
hr = IDirectPlayNATHelp_RegisterPorts(g_pDPNH,
(SOCKADDR *)&lSockAddr[i], sizeof(lSockAddr[0]), 1,
30000, pHnd, DPNHREGISTERPORTS_TCP);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"RegisterPorts failed in OpenPort for adapter #%d, ", i ));
DumpLibHr(hr);
}
else
{
TRIVIAL_MSG((L"OpenPort Assigned: 0x%x", *pHnd));
}
}
}
else
{
dwRet = NO_ICS_HANDLE;
TRIVIAL_MSG((L"OpenPort- no ICS found"));
}
TRIVIAL_MSG((L"OpenPort- returns 0x%x", dwRet ));
return dwRet;
}
/****************************************************************************
**
** Called to close a port, whenever a ticket is expired or closed.
**
****************************************************************************/
DWORD APIENTRY ClosePort(DWORD MapHandle)
{
DWORD dwRet = ERROR_SUCCESS;
DWORD dwIndex;
TRIVIAL_MSG((L"ClosePort(0x%x)", MapHandle ));
if (!g_boolInitialized)
{
HEINOUS_E_MSG((L"ERROR: ClosePort- library not initialized"));
return ERROR_INVALID_PARAMETER;
}
// if we didn't open this thru the ICS, then just return
if (!g_boolIcsPresent && MapHandle == NO_ICS_HANDLE)
return ERROR_SUCCESS;
dwIndex = MapHandle - 0x8000000;
if (g_boolIcsPresent && g_pDPNH && dwIndex < ARRAYSIZE(g_PortHandles))
{
HRESULT hr=0;
int i;
PMAPHANDLES pMap = g_PortHandles[dwIndex];
if (pMap)
{
TRIVIAL_MSG((L"closing %d port mappings", pMap->iMapped));
for (i = 0; i < pMap->iMapped; i++)
{
hr = IDirectPlayNATHelp_DeregisterPorts(g_pDPNH, pMap->hMapped[i], 0);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"DeregisterPorts failed in ClosePort for handle 0x%x", pMap->hMapped[i]));
DumpLibHr(hr);
dwRet = ERROR_INVALID_ACCESS;
}
}
// remove the handle from our array
free(g_PortHandles[dwIndex]);
g_PortHandles[dwIndex] = NULL;
}
}
else
IMPORTANT_MSG((L"Bad handle passed into ClosePort!!"));
TRIVIAL_MSG((L"ClosePort returning 0x%x", dwRet ));
return(dwRet);
}
/****************************************************************************
**
** FetchAllAddresses
** Returns a string listing all the valid IP addresses for the machine
** Formatting details:
** 1. Each address is seperated with a ";" (semicolon)
** 2. Each address consists of the "1.2.3.4", and is followed by ":p"
** where the colon is followed by the port number
**
****************************************************************************/
DWORD APIENTRY FetchAllAddresses(WCHAR *lpszAddr, int iBufSize)
{
return FetchAllAddressesEx(lpszAddr, iBufSize, IPF_ADD_DNS);
}
/****************************************************************************
**
** CloseAllPorts
** Does just that- closes all port mappings that have been opened
**
****************************************************************************/
DWORD APIENTRY CloseAllOpenPorts(void)
{
DWORD dwRet = 1;
INTERESTING_MSG((L"CloseAllOpenPorts()" ));
if (g_boolIcsPresent && g_pDPNH)
{
HRESULT hr=0;
int i;
// call DPNATHLP to unregister the mapping
// then remove the handle from our array
for (i = 0; i < ARRAYSIZE(g_PortHandles); i++)
{
if (g_PortHandles[i])
{
PMAPHANDLES pMap = g_PortHandles[i];
int j;
for (j = 0; j < pMap->iMapped; j++)
{
hr = IDirectPlayNATHelp_DeregisterPorts(g_pDPNH, pMap->hMapped[j], 0);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"DeregisterPorts failed in CloseAllOpenPorts"));
DumpLibHr(hr);
}
}
free(g_PortHandles[i]);
g_PortHandles[i] = 0;
}
}
}
return(dwRet);
}
/****************************************************************************
**
** The worker thread for use with the DPHATHLP.DLL.
**
** This keeps the leases updated on any open
** port assignments. Eventually, this will also check & update the sessmgr
** when the ICS comes & goes, or when the address list changes.
**
****************************************************************************/
DWORD WINAPI DpNatHlpThread(PVOID ContextPtr)
{
DWORD dwRet=1;
DWORD dwWaitResult=WAIT_TIMEOUT;
ULONG ulCurIpTblSz, ulLastIpTblSz;
long l_waitTime = g_waitDuration;
PMIB_IPADDRTABLE pCurIpTbl=NULL, pLastIpTbl=NULL;
TRIVIAL_MSG((L"DpNatHlpThread()" ));
/*
* Initialize the IP tables that we keep
* Get 1 copy from IP Helper, then make a
* second local copy for later comparison.
*/
ulLastIpTblSz=0;
GetIpAddrTable(NULL, &ulLastIpTblSz, FALSE);
pLastIpTbl = (PMIB_IPADDRTABLE)malloc(ulLastIpTblSz);
if (!pLastIpTbl)
goto shutdown;
if (NO_ERROR != GetIpAddrTable(pLastIpTbl, &ulLastIpTblSz, FALSE))
IMPORTANT_MSG((L"Failed to get initial IpAddrTable in DpNatHlpThread; err=0x%x", GetLastError()));
TRIVIAL_MSG((L"Initial IPtblSz = %d", ulLastIpTblSz));
ulCurIpTblSz=ulLastIpTblSz;
pCurIpTbl = (PMIB_IPADDRTABLE)malloc(ulCurIpTblSz);
if (!pCurIpTbl)
{
goto shutdown;
}
memcpy(pCurIpTbl, pLastIpTbl, ulCurIpTblSz);
/*
* Then the 2 minute wait loop
*/
while(dwWaitResult == WAIT_TIMEOUT)
{
DWORD dwTime;
BOOL bAddrChanged;
if (dwWaitResult != WAIT_TIMEOUT)
{
IMPORTANT_MSG((L"error: got bad wait return in DpNatHlpThread() val=0x%x", dwWaitResult));
goto shutdown;
}
// our default is NO CHANGE
bAddrChanged = FALSE;
if (NO_ERROR != GetIpAddrTable(pCurIpTbl, &ulCurIpTblSz, FALSE))
{
/*
* If we couldn't get the tables, it would be because the table grew
* in size beyind the old one. Hmm- that must mean that the table changed
*/
bAddrChanged=TRUE;
TRIVIAL_MSG((L"IpAddrTable GREW in DpNatHlpThread"));
}
else
{
/*
* If the table shrunk, then it must have changed
*/
if (ulCurIpTblSz != ulLastIpTblSz)
{
bAddrChanged = TRUE;
TRIVIAL_MSG((L"IpAddrTable SHRUNK in DpNatHlpThread"));
}
/*
* Maybe one of the addresses in the table changed?
*/
if (0 != memcmp(pCurIpTbl, pLastIpTbl, ulCurIpTblSz))
{
bAddrChanged=TRUE;
TRIVIAL_MSG((L"IpAddrTable CHANGED in DpNatHlpThread"));
}
}
if (bAddrChanged)
{
TRIVIAL_MSG((L"DpNatHlpThread: IP Tables changed; cur=%d, last=%d", ulCurIpTblSz, ulLastIpTblSz));
/* free the old tables */
if (pCurIpTbl) free(pCurIpTbl);
if (pLastIpTbl) free(pLastIpTbl);
/* then get new tables */
ulLastIpTblSz=0;
GetIpAddrTable(NULL, &ulLastIpTblSz, FALSE);
pLastIpTbl = (PMIB_IPADDRTABLE)malloc(ulLastIpTblSz);
if(pLastIpTbl)
{
if (NO_ERROR != GetIpAddrTable(pLastIpTbl, &ulLastIpTblSz, FALSE))
IMPORTANT_MSG((L"Failed to update IpAddrTable in DpNatHlpThread; err=0x%x", GetLastError()));
ulCurIpTblSz=ulLastIpTblSz;
pCurIpTbl = (PMIB_IPADDRTABLE)malloc(ulCurIpTblSz);
memcpy(pCurIpTbl, pLastIpTbl, ulCurIpTblSz);
}
else
{
/* we got here because the machine ran out of memory
* so we will try again later to allocate the tables
* maybe more memory will be free then.
*/
pCurIpTbl = NULL;
pLastIpTbl = NULL;
ulLastIpTblSz=0;
ulCurIpTblSz=1;
IMPORTANT_MSG((L"Failed to get memory for IP tables in DpNatHlpThread; err=0x%x", GetLastError()));
}
}
if (g_pDPNH)
{
HRESULT hr;
DPNHCAPS lCaps;
/* Call GetCaps to renew all open leases */
lCaps.dwSize = sizeof(lCaps);
hr = IDirectPlayNATHelp_GetCaps(g_pDPNH, &lCaps, DPNHGETCAPS_UPDATESERVERSTATUS);
if (hr == DPNH_OK)
{
if (lCaps.dwMinLeaseTimeRemaining)
l_waitTime = min(g_waitDuration, (long)lCaps.dwMinLeaseTimeRemaining);
}
else if (hr == DPNHSUCCESS_ADDRESSESCHANGED)
bAddrChanged = TRUE;
else
{
IMPORTANT_MSG((L"GetCaps failed in NatHlpDaemon"));
DumpLibHr(hr);
}
}
if (bAddrChanged && g_hAlertEvent)
{
SetEvent(g_hAlertEvent);
}
dwWaitResult = WaitForSingleObject(g_hThreadEvent, l_waitTime);
}
shutdown:
TRIVIAL_MSG((L"DpNatHlpThread shutting down"));
/*
* Then the shutdown code
* free all memory
* then close out DPNATHLP.DLL
* and return all objects
*/
if (pCurIpTbl) free(pCurIpTbl);
if (pLastIpTbl) free(pLastIpTbl);
if (g_pDPNH)
{
IDirectPlayNATHelp_Close(g_pDPNH, 0);
IDirectPlayNATHelp_Release(g_pDPNH);
}
g_pDPNH = NULL;
if (g_hModDpNatHlp)
FreeLibrary(g_hModDpNatHlp);
g_hModDpNatHlp = 0;
DeleteCriticalSection( &g_CritSec );
CloseHandle(g_hThreadEvent);
TRIVIAL_MSG((L"DpNatHlpThread() returning 0x%x", dwRet ));
WSACleanup();
ExitThread(dwRet);
// of course we never get this far...
return(dwRet);
}
/****************************************************************************
**
** The actual worker thread. This keeps the leases updated on any open
** port assignments. This will also check & update the sessmgr
** when the ICS comes & goes, or when the address list changes.
**
****************************************************************************/
DWORD WINAPI RsipDaemonThread(PVOID ContextPtr)
{
DWORD dwRet=1;
DWORD dwWaitResult=WAIT_TIMEOUT;
ULONG ulCurIpTblSz, ulLastIpTblSz;
PMIB_IPADDRTABLE pCurIpTbl=NULL, pLastIpTbl=NULL;
TRIVIAL_MSG((L"RsipDaemonThread()" ));
/*
* Initialize the IP tables that we keep
* Get 1 copy from IP Helper, then make a
* second local copy for later comparison.
*/
ulLastIpTblSz=0;
GetIpAddrTable(NULL, &ulLastIpTblSz, FALSE);
pLastIpTbl = (PMIB_IPADDRTABLE)malloc(ulLastIpTblSz);
if (NO_ERROR != GetIpAddrTable(pLastIpTbl, &ulLastIpTblSz, FALSE))
IMPORTANT_MSG((L"Failed to get initial IpAddrTable in RsipDaemonThread; err=0x%x", GetLastError()));
TRIVIAL_MSG((L"Initial IPtblSz = %d", ulLastIpTblSz));
ulCurIpTblSz=ulLastIpTblSz;
pCurIpTbl = (PMIB_IPADDRTABLE)malloc(ulCurIpTblSz);
if (!pCurIpTbl)
goto shutdown;
memcpy(pCurIpTbl, pLastIpTbl, ulCurIpTblSz);
/*
* Then the 2 minute wait loop
*/
while(dwWaitResult == WAIT_TIMEOUT)
{
DWORD dwTime;
BOOL bAddrChanged;
if (dwWaitResult != WAIT_TIMEOUT)
{
IMPORTANT_MSG((L"error: got bad wait return in RsipDaemonThread() val=0x%x", dwWaitResult));
goto shutdown;
}
// our default is NO CHANGE
bAddrChanged = FALSE;
if (NO_ERROR != GetIpAddrTable(pCurIpTbl, &ulCurIpTblSz, FALSE))
{
/*
* If we couldn't get the tables, it would be because the table grew
* in size beyind the old one. Hmm- that must mean that the table changed
*/
bAddrChanged=TRUE;
TRIVIAL_MSG((L"IpAddrTable GREW in RsipDaemonThread"));
}
else
{
/*
* If the table shrunk, then it must have changed
*/
if (ulCurIpTblSz != ulLastIpTblSz)
{
bAddrChanged = TRUE;
TRIVIAL_MSG((L"IpAddrTable SHRUNK in RsipDaemonThread"));
}
/*
* Maybe one of the addresses in the table changed?
*/
if (0 != memcmp(pCurIpTbl, pLastIpTbl, ulCurIpTblSz))
{
bAddrChanged=TRUE;
TRIVIAL_MSG((L"IpAddrTable CHANGED in RsipDaemonThread"));
}
}
if (bAddrChanged)
{
TRIVIAL_MSG((L"RsipDaemonThread: IP Tables changed; cur=%d, last=%d", ulCurIpTblSz, ulLastIpTblSz));
/* free the old tables */
if (pCurIpTbl) free(pCurIpTbl);
if (pLastIpTbl) free(pLastIpTbl);
/* then get new tables */
ulLastIpTblSz=0;
GetIpAddrTable(NULL, &ulLastIpTblSz, FALSE);
pLastIpTbl = (PMIB_IPADDRTABLE)malloc(ulLastIpTblSz);
if(pLastIpTbl)
{
if (NO_ERROR != GetIpAddrTable(pLastIpTbl, &ulLastIpTblSz, FALSE))
IMPORTANT_MSG((L"Failed to update IpAddrTable in RsipDaemonThread; err=0x%x", GetLastError()));
ulCurIpTblSz=ulLastIpTblSz;
pCurIpTbl = (PMIB_IPADDRTABLE)malloc(ulCurIpTblSz);
memcpy(pCurIpTbl, pLastIpTbl, ulCurIpTblSz);
}
else
{
/* we got here because the machine ran out of memory
* so we will try again later to allocate the tables
* maybe more memory will be free then.
*/
pCurIpTbl = NULL;
pLastIpTbl = NULL;
ulLastIpTblSz=0;
ulCurIpTblSz=1;
IMPORTANT_MSG((L"Failed to get memory for IP tables in RsipDaemonThread; err=0x%x", GetLastError()));
}
}
if (g_boolIcsPresent)
{
PRSIP_LEASE_RECORD pLeaseRecord;
// update the leases
dwTime = timeGetTime();
if (!PortExtend( dwTime ) && g_hAlertEvent)
{
// If we cannot extend the lease, then we must notify the user
TRIVIAL_MSG((L"Sending RSIP alert event from RsipDaemonThread"));
bAddrChanged = TRUE;
}
CacheClear( dwTime );
if (g_iPort && (pLeaseRecord = FindLease( TRUE, htons((WORD)g_iPort) )))
{
/* .
* We got here because there are open leases. That means we must
* periodically check to see if the public address has changed.
* This would happen if the ICS's modem got disconnected or
* reconnected. In the first case, we no longer have a valid public
* address, in the second case we have a new public address.
*/
SOCKADDR_IN saddrPublic, saddrNew;
DWORD dwBindId = 0;
DWORD dwSpewSave;
saddrPublic.sin_family = AF_INET;
saddrPublic.sin_addr.s_addr = pLeaseRecord->addrV4;
saddrPublic.sin_port = pLeaseRecord->rport;
dwSpewSave = gDbgFlag;
gDbgFlag |= 3;
/*
* The basic algorithm for this is to ask for a new port mapping
* and compare the address to what we already have. I chose to ask
* for a port that will never be mapped onto a MS PC- the Sun
* RPC port. This should always be available to us, as no
* smart gamer will use this port.
* It should not cause us any security problems, as the OS never
* has any sockets open & listening on that port. Besides, the
* port mapping is only valid for ~500 mSec- not long enough to cause
* any real mischief.
* BTW, this algorithm workd on WinME ICS servers as well.
*/
if (S_OK == AssignPort( TRUE, htons(111), (SOCKADDR *)&saddrNew, &dwBindId ))
{
// free the port mapping, as all we care about is the public address
FreePort(dwBindId);
gDbgFlag = dwSpewSave;
// check for invalid address (modem probably disconnected)
if (!saddrNew.sin_addr.s_addr)
{
TRIVIAL_MSG((L"Public address all zeros- no longer on Internet"));
/*
* How should this be handled?
* Well, if we notify Salem, then they will try to update the ticket.
* but that may cause more trouble, as that would cause a reconnect
* which would then cause another address change, which would cause
* a second ticket update.
*
* We certainly should try to maintain the current leases, in case
* the connection returns.
*/
// bAddrChanged=TRUE;
}
else if (saddrNew.sin_addr.s_addr != saddrPublic.sin_addr.s_addr)
{
// change the public address in all the leases...
RSIP_LEASE_RECORD *pLeaseWalker;
RSIP_LEASE_RECORD *pNextLease;
TRIVIAL_MSG((L"==> public address changed: OLD, then NEW address <=="));
DumpSocketAddress( 8, (SOCKADDR *)&saddrPublic, AF_INET );
DumpSocketAddress( 8, (SOCKADDR *)&saddrNew, AF_INET );
pLeaseWalker = g_pRsipLeaseRecords;
while( pLeaseWalker )
{
pNextLease = pLeaseWalker->pNext;
// copy the address
pLeaseWalker->addrV4 = saddrNew.sin_addr.s_addr;
pLeaseWalker=pNextLease;
}
bAddrChanged=TRUE;
}
}
else
{
gDbgFlag = dwSpewSave;
IMPORTANT_MSG((L"AssignPort failed in daemon thread"));
// Hmmm- we can't get to the ICS server any longer
bAddrChanged=TRUE;
// delete all open mappings
CloseAllOpenPorts();
}
}
}
if (bAddrChanged && g_hAlertEvent)
{
SetEvent(g_hAlertEvent);
}
dwWaitResult = WaitForSingleObject(g_hThreadEvent, g_waitDuration);
}
shutdown:
TRIVIAL_MSG((L"RsipDaemonThread shutting down"));
/*
* Then the shutdown code
* release any open ports
*/
if (pCurIpTbl) free(pCurIpTbl);
if (pLastIpTbl) free(pLastIpTbl);
Deinitialize();
DeleteCriticalSection( &g_CritSec );
CloseHandle(g_hThreadEvent);
TRIVIAL_MSG((L"RsipDaemonThread() returning 0x%x", dwRet ));
WSACleanup();
ExitThread(dwRet);
// of course we never get this far...
return(dwRet);
}
/****************************************************************************
**
** This should initialize the ICS library for use with the DirectPlay
** ICS/NAT helper DLL.
** All will happen in this order:
** 1. Call DirectPlayNATHelpCreate()
** 2. Call IDirectPlayNATHelp::Initialize to prepare the object
**
****************************************************************************/
DWORD StartDpNatHlp(void)
{
DWORD dwRet = ERROR_CALL_NOT_IMPLEMENTED;
HRESULT hr;
HMODULE hMod;
PFN_DIRECTPLAYNATHELPCREATE pfnDirectPlayNATHelpCreate;
PDIRECTPLAYNATHELP pDirectPlayNATHelp = NULL;
DPNHCAPS dpnhCaps;
PSUPDLLS pDll = &strDpHelp[0];
try_again:
TRIVIAL_MSG((L"starting StartDpNatHlp for %S (%S)", pDll->szDllName, pDll->bUsesUpnp?"UPnP":"PAST"));
// start out with no public address
g_szPublicAddr[0] = 0;
hMod = LoadLibraryA(pDll->szDllName);
if (!hMod)
{
IMPORTANT_MSG((L"ERROR:%S could not be found", pDll->szDllName));
pDll++;
if (!pDll->szDllName)
{
dwRet = ERROR_FILE_NOT_FOUND;
goto done;
}
goto try_again;
}
pfnDirectPlayNATHelpCreate = (PFN_DIRECTPLAYNATHELPCREATE) GetProcAddress(hMod, "DirectPlayNATHelpCreate");
if (!pfnDirectPlayNATHelpCreate)
{
IMPORTANT_MSG((L"\"DirectPlayNATHelpCreate\" proc in %S could not be found", pDll->szDllName));
dwRet = ERROR_INVALID_FUNCTION;
goto done;
}
hr = pfnDirectPlayNATHelpCreate(&IID_IDirectPlayNATHelp,
(void**) (&pDirectPlayNATHelp));
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"DirectPlayNATHelpCreate failed in %S", pDll->szDllName));
DumpLibHr(hr);
dwRet = ERROR_BAD_UNIT;
goto done;
}
hr = IDirectPlayNATHelp_Initialize(pDirectPlayNATHelp, 0);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"IDirectPlayNATHelp_Initialize failed in %S", pDll->szDllName));
DumpLibHr(hr);
dwRet = ERROR_BAD_UNIT;
goto done;
}
/* Get capabilities of NAT/RSIP/PAST server */
dpnhCaps.dwSize = sizeof(dpnhCaps);
hr = IDirectPlayNATHelp_GetCaps(pDirectPlayNATHelp, &dpnhCaps, DPNHGETCAPS_UPDATESERVERSTATUS);
if (hr != DPNH_OK && hr != DPNHSUCCESS_ADDRESSESCHANGED)
{
IMPORTANT_MSG((L"IDirectPlayNATHelp_GetCaps failed"));
DumpLibHr(hr);
dwRet = ERROR_BAD_UNIT;
goto done;
}
if (dpnhCaps.dwFlags & (DPNHCAPSFLAG_LOCALFIREWALLPRESENT | DPNHCAPSFLAG_GATEWAYPRESENT))
{
PIP_ADAPTER_INFO pAdpInfo = NULL;
SOCKADDR_IN saddrOurLAN;
PMIB_IPADDRTABLE pmib=NULL;
ULONG ulSize = 0;
DWORD dw;
g_boolIcsPresent = TRUE;
TRIVIAL_MSG((L"ICS server found using %S", pDll->szDllName));
g_lpszDllName = pDll->szDllName;
// copy this pointer where it will do us some good
g_pDPNH = pDirectPlayNATHelp;
g_boolUsingNatHelp = TRUE;
g_boolUsingNatPAST = pDll->bUsesUpnp;
dwRet = ERROR_SUCCESS;
// is this machine an ICS host?
if (dpnhCaps.dwFlags & (DPNHCAPSFLAG_LOCALFIREWALLPRESENT | DPNHCAPSFLAG_GATEWAYISLOCAL))
g_boolIcsOnThisMachine = TRUE;
ZeroMemory(&saddrOurLAN, sizeof(saddrOurLAN));
saddrOurLAN.sin_family = AF_INET;
dw = GetAdaptersInfo(
pAdpInfo,
&ulSize );
if (dw == ERROR_BUFFER_OVERFLOW && ulSize)
{
pAdpInfo = (IP_ADAPTER_INFO*)malloc(ulSize);
if (!pAdpInfo)
goto done;
dw = GetAdaptersInfo(
pAdpInfo,
&ulSize);
if (dw == ERROR_SUCCESS)
{
PIP_ADAPTER_INFO p;
PIP_ADDR_STRING ps;
for(p=pAdpInfo; p!=NULL; p=p->Next)
{
for(ps = &(p->IpAddressList); ps; ps=ps->Next)
{
if (strcmp(ps->IpAddress.String, "0.0.0.0") != 0)
{
// blah blah blah
saddrOurLAN.sin_addr.S_un.S_addr = inet_addr(ps->IpAddress.String);
TRIVIAL_MSG((L"Initializing RSIP to LAN adapter at [%S]", ps->IpAddress.String));
goto doit;
}
}
}
}
}
doit:
memcpy(&g_saddrLocal, &saddrOurLAN, sizeof(saddrOurLAN));
// Does the ICS have a public address?
if ( 1 )
{
/* then we will discover the public address */
DPNHHANDLE dpHnd;
saddrOurLAN.sin_port = ntohs(3389);
/* first we ask for a new mapping */
hr = IDirectPlayNATHelp_RegisterPorts(g_pDPNH,
(SOCKADDR *)&saddrOurLAN, sizeof(saddrOurLAN), 1,
30000, &dpHnd, DPNHREGISTERPORTS_TCP);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"IDirectPlayNATHelp_RegisterPorts failed in StartDpNatHlp"));
DumpLibHr(hr);
}
else
{
/* we succeeded, so query for the address */
SOCKADDR_IN lsi;
DWORD dwSize, dwTypes;
TRIVIAL_MSG((L"IDirectPlayNATHelp_RegisterPorts Assigned: 0x%x", dpHnd));
dwSize = sizeof(lsi);
ZeroMemory(&lsi, dwSize);
hr = IDirectPlayNATHelp_GetRegisteredAddresses(g_pDPNH, dpHnd, (SOCKADDR *)&lsi,
&dwSize, &dwTypes, NULL, 0, );
if (hr == DPNH_OK && dwSize)
{
wsprintfA(g_szPublicAddr, "%d.%d.%d.%d",
lsi.sin_addr.S_un.S_un_b.s_b1,
lsi.sin_addr.S_un.S_un_b.s_b2,
lsi.sin_addr.S_un.S_un_b.s_b3,
lsi.sin_addr.S_un.S_un_b.s_b4);
TRIVIAL_MSG((L"Public Address=[%S]", g_szPublicAddr ));
}
else
{
IMPORTANT_MSG((L"GetRegisteredAddresses[0x%x] failed, size=0x%x", dpHnd, dwSize));
DumpLibHr(hr);
}
/* close out the temp port we got */
hr = IDirectPlayNATHelp_DeregisterPorts(g_pDPNH, dpHnd, 0);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"DeregisterPorts failed in ClosePort"));
DumpLibHr(hr);
dwRet = ERROR_INVALID_ACCESS;
}
}
}
}
else
{
hr = IDirectPlayNATHelp_Close(pDirectPlayNATHelp, 0);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"IDirectPlayNATHelp_Close failed"));
DumpLibHr(hr);
}
hr = IDirectPlayNATHelp_Release(pDirectPlayNATHelp);
if (hr != DPNH_OK)
{
IMPORTANT_MSG((L"IDirectPlayNATHelp_Release failed"));
DumpLibHr(hr);
}
pDll++;
if (pDll->szDllName)
{
if (hMod) FreeLibrary(hMod);
hMod = 0;
goto try_again;
}
g_pDPNH = NULL;
g_boolUsingNatHelp = FALSE;
dwRet = ERROR_BAD_UNIT;
}
done:
if (dwRet != ERROR_SUCCESS)
{
if (hMod)
FreeLibrary(hMod);
hMod = 0;
}
TRIVIAL_MSG((L"done with StartDpNatHlp, result=0x%x", dwRet));
// save hMod so we can close it out in StopICSLibrary
g_hModDpNatHlp = hMod;
return dwRet;
};
/****************************************************************************
**
** The first call to be made into this library. It is responsible for
** starting up all worker threads, initializing all memory and libs,
** and starting up the DPHLPAPI.DLL function (if found).
**
****************************************************************************/
DWORD APIENTRY StartICSLib(void)
{
WSADATA WsaData;
DWORD dwThreadId;
HANDLE hEvent, hThread;
HKEY hKey;
int sktRet;
// open reg key first, to get ALL the spew...
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\ICSHelper", 0, KEY_READ, &hKey))
{
DWORD dwSize;
dwSize = sizeof(gDbgFlag);
RegQueryValueEx(hKey, L"DebugSpew", NULL, NULL, (LPBYTE)&gDbgFlag, &dwSize);
g_waitDuration = 0;
dwSize = sizeof(g_waitDuration);
RegQueryValueEx(hKey, L"RetryTimeout", NULL, NULL, (LPBYTE)&g_waitDuration, &dwSize);
if (g_waitDuration)
g_waitDuration *= 1000;
else
g_waitDuration = 120000;
RegCloseKey(hKey);
}
// should we create a debug log file?
if (gDbgFlag & DBG_MSG_DEST_FILE)
{
WCHAR szLogfileName[MAX_PATH];
GetSystemDirectory(szLogfileName, sizeof(szLogfileName)/sizeof(szLogfileName[0]));
lstrcat(szLogfileName, L"\\SalemICSHelper.log");
iDbgFileHandle = _wopen(szLogfileName, _O_APPEND | _O_BINARY | _O_RDWR, 0);
if (-1 != iDbgFileHandle)
{
OutputDebugStringA("opened debug log file\n");
}
else
{
unsigned char UniCode[2] = {0xff, 0xfe};
// we must create the file
OutputDebugStringA("must create debug log file");
iDbgFileHandle = _wopen(szLogfileName, _O_BINARY | _O_CREAT | _O_RDWR, _S_IREAD | _S_IWRITE);
if (-1 != iDbgFileHandle)
_write(iDbgFileHandle, &UniCode, sizeof(UniCode));
else
{
OutputDebugStringA("ERROR: failed to create debug log file");
iDbgFileHandle = 0;
}
}
}
g_iPort = GetTsPort();
TRIVIAL_MSG((L"StartICSLib()" ));
ZeroMemory(g_PortHandles, sizeof(g_PortHandles));
if (g_boolInitialized)
{
HEINOUS_E_MSG((L"ERROR: StartICSLib called twice"));
return ERROR_INVALID_PARAMETER;
}
else
g_boolInitialized = TRUE;
// of course, this must be done...
InitializeCriticalSection(&g_CritSec);
// create an event for later use by the daemon thread
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hEvent)
{
IMPORTANT_MSG((L"Could not create an event for RSIP worker thread, err=0x%x", GetLastError()));
return GetLastError();
}
g_hThreadEvent = hEvent;
if (0 != WSAStartup(MAKEWORD(2,2), &WsaData))
{
if (0 != (sktRet = WSAStartup(MAKEWORD(2,0), &WsaData)))
{
IMPORTANT_MSG((L"WSAStartup failed:"));
return sktRet;
}
}
if (ERROR_SUCCESS == StartDpNatHlp())
{
// start RSIP daemon process, which will do all the work
hThread = CreateThread( NULL, // SD- not needed
0, // Stack Size
(LPTHREAD_START_ROUTINE)DpNatHlpThread,
NULL,
0,
&dwThreadId );
}
else
{
// start up RSIP lib
g_szPublicAddr[0]=0;
if (RsipIsRunningOnThisMachine( &g_saddrPublic ))
{
// makes casting easier
SOCKADDR_IN *pPubAddr = (SOCKADDR_IN*)( &g_saddrPublic );
g_boolIcsPresent = g_boolIcsOnThisMachine = TRUE;
// save the public side address so that we can filter it out
// of the address list we return
wsprintfA(g_szPublicAddr, "%d.%d.%d.%d",
pPubAddr->sin_addr.S_un.S_un_b.s_b1,
pPubAddr->sin_addr.S_un.S_un_b.s_b2,
pPubAddr->sin_addr.S_un.S_un_b.s_b3,
pPubAddr->sin_addr.S_un.S_un_b.s_b4);
INTERESTING_MSG((L"PAST Host is local- public address is [%S]", &g_szPublicAddr));
}
else
{
SOCKADDR_IN saddrOurLAN;
PMIB_IPADDRTABLE pmib=NULL;
ULONG ulSize = 0;
DWORD dw;
PIP_ADAPTER_INFO pAdpInfo = NULL;
ZeroMemory(&saddrOurLAN, sizeof(saddrOurLAN));
saddrOurLAN.sin_family = AF_INET;
dw = GetAdaptersInfo(
pAdpInfo,
&ulSize );
if (dw == ERROR_BUFFER_OVERFLOW && ulSize)
{
pAdpInfo = (IP_ADAPTER_INFO*)malloc(ulSize);
if (!pAdpInfo)
goto done;
dw = GetAdaptersInfo(
pAdpInfo,
&ulSize);
if (dw == ERROR_SUCCESS)
{
PIP_ADAPTER_INFO p;
PIP_ADDR_STRING ps;
for(p=pAdpInfo; p!=NULL; p=p->Next)
{
for(ps = &(p->IpAddressList); ps; ps=ps->Next)
{
if (strcmp(ps->IpAddress.String, "0.0.0.0") != 0)
{
// blah blah blah
saddrOurLAN.sin_addr.S_un.S_addr = inet_addr(ps->IpAddress.String);
TRIVIAL_MSG((L"Initializing RSIP to LAN adapter at [%S]", ps->IpAddress.String));
goto doit;
}
}
}
}
}
doit:
g_boolIcsPresent = Initialize((SOCKADDR *)&saddrOurLAN, FALSE);
if (g_boolIcsPresent)
{
DWORD dwBindID=0;
SOCKADDR saddrAssigned;
if (S_OK == AssignPort( FALSE, 6969, &saddrAssigned, &dwBindID ))
{
// free the port, since we just wanted the public IP address
FreePort( dwBindID );
wsprintfA(g_szPublicAddr, "%d.%d.%d.%d",
(UCHAR)saddrAssigned.sa_data[2],
(UCHAR)saddrAssigned.sa_data[3],
(UCHAR)saddrAssigned.sa_data[4],
(UCHAR)saddrAssigned.sa_data[5]);
INTERESTING_MSG((L"PAST Host is NOT local- public address is [%S]", &g_szPublicAddr));
}
else
{
IMPORTANT_MSG((L"Failed to assign port when attempting to determine public network address!" ));
}
}
}
done:
g_lpszDllName = szInternal;
// start RSIP daemon process, which will do all the work
hThread = CreateThread( NULL, // SD- not needed
0, // Stack Size
(LPTHREAD_START_ROUTINE)RsipDaemonThread,
NULL,
0,
&dwThreadId );
}
if (!hThread)
{
IMPORTANT_MSG((L"Could not create RSIP worker thread, err=0x%x", GetLastError()));
return GetLastError();
}
// save this for later, as we need it in the close function
g_hWorkerThread = hThread;
TRIVIAL_MSG((L"StartICSLib() returning ERROR_SUCCESS"));
return(ERROR_SUCCESS);
}
/****************************************************************************
**
** The last call to be made into this library. Do not call any other
** functiopn in this library after you call this!
**
****************************************************************************/
DWORD APIENTRY StopICSLib(void)
{
DWORD dwRet = ERROR_SUCCESS;
DWORD dwTmp;
TRIVIAL_MSG((L"StopICSLib()" ));
// signal the worker thread, so that it will do a shutdown
SetEvent(g_hThreadEvent);
// then wait for it to shutdown.
dwTmp = WaitForSingleObject(g_hWorkerThread, 15000);
if (dwTmp == WAIT_OBJECT_0)
TRIVIAL_MSG((L"ICS worker thread closed down normally"));
else if (dwTmp == WAIT_ABANDONED)
IMPORTANT_MSG((L"ICS worker thread did not complete in 15 seconds"));
else
IMPORTANT_MSG((L"WaitForWorkerThread failed"));
CloseHandle(g_hWorkerThread);
TRIVIAL_MSG((L"StopICSLib() returning 0x%x", dwRet ));
_close(iDbgFileHandle);
g_boolInitialized = FALSE;
return(dwRet);
}
/****************************************************************************
**
** SetAlertEvent
** Pass in an event handle. Then, whenever the ICS changes state, I
** will signal that event.
**
****************************************************************************/
DWORD APIENTRY SetAlertEvent(HANDLE hEvent)
{
TRIVIAL_MSG((L"SetAlertEvent(0x%x)", hEvent));
g_hAlertEvent = hEvent;
return 1;
}
/****************************************************************************
**
** Address String Compression routines
**
*****************************************************************************
**
** The following is a group of routines designed to compress and expand
** IPV4 addresses into the absolute minimum size possible. This is to
** provide a compressed ASCII string that can be parsed using standard
** shell routines for command line parsing.
** The compressed string has the following restrictions:
** -> Must not expand to more characters if UTF8 encoded.
** -> Must not contain the NULL character so that string libs work.
** -> Cannot contain double quote character, the shell needs that.
** -> Does not have to be human readable.
**
** Data Types:
** There are three data types used here:
** szAddr The orginal IPV4 string address ("X.X.X.X:port")
** blobAddr Six byte struct with 4 bytes of address, and 2 bytes of port
** szComp Eight byte ascii string of compressed IPV4 address
**
****************************************************************************/
#define COMP_OFFSET '#'
#define COMP_SEPERATOR '!'
#pragma pack(push,1)
typedef struct _BLOB_ADDR {
UCHAR addr_d; // highest order address byte
UCHAR addr_c;
UCHAR addr_b;
UCHAR addr_a; // lowest order byte (last in IP string address)
WORD port;
} BLOB_ADDR, *PBLOB_ADDR;
#pragma pack(pop)
WCHAR b64Char[64]={
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9','+','/'
};
void DumpBlob(PBLOB_ADDR pba)
{
UCHAR *lpa;
lpa = (UCHAR *)pba;
TRIVIAL_MSG((L"blob (hex): %x,%x,%x,%x,%x,%x", *lpa, *(lpa+1), *(lpa+2), *(lpa+3), *(lpa+4), *(lpa+5)));
TRIVIAL_MSG((L" (struct): %x,%x,%x,%x:%x", pba->addr_d, pba->addr_c, pba->addr_b, pba->addr_a, pba->port));
TRIVIAL_MSG((L" (IP): %d.%d.%d.%d:%d", pba->addr_d, pba->addr_c, pba->addr_b, pba->addr_a, pba->port));
}
/****************************************************************************
** char * atob(char *szVal, UCHAR *result)
****************************************************************************/
WCHAR *atob(WCHAR *szVal, UCHAR *result)
{
WCHAR *lptr;
WCHAR ucb;
UCHAR foo;
if (!result || !szVal)
{
IMPORTANT_MSG((L"ERROR: NULL ptr passed in atob"));
return NULL;
}
// start ptr at the beginning of string
lptr = szVal;
foo = 0;
ucb = *lptr++ - '0';
while (ucb >= 0 && ucb <= 9)
{
foo *= 10;
foo += ucb;
ucb = (*lptr++)-'0';
}
*result = (UCHAR)foo;
return lptr;
}
/****************************************************************************
**
** CompressAddr(pszAddr, pblobAddr);
** Takes an ascii IP address (X.X.X.X:port) and converts it to a
** 6 byte binary blob.
**
** returns TRUE for success, FALSE for failure.
**
****************************************************************************/
BOOL CompressAddr(WCHAR *pszAddr, PBLOB_ADDR pblobAddr)
{
BLOB_ADDR lblob;
WCHAR *lpsz;
if (!pszAddr || !pblobAddr)
{
IMPORTANT_MSG((L"ERROR: NULL ptr passed in CompressAddr"));
return FALSE;
}
lpsz = pszAddr;
lpsz = atob(lpsz, &lblob.addr_d);
if (*(lpsz-1) != '.')
{
IMPORTANT_MSG((L"ERROR: bad address[0] passed in CompressAddr for %s", pszAddr));
return FALSE;
}
lpsz = atob(lpsz, &lblob.addr_c);
if (*(lpsz-1) != '.')
{
IMPORTANT_MSG((L"ERROR: bad address[1] passed in CompressAddr"));
return FALSE;
}
lpsz = atob(lpsz, &lblob.addr_b);
if (*(lpsz-1) != '.')
{
IMPORTANT_MSG((L"ERROR: bad address[2] passed in CompressAddr"));
return FALSE;
}
lpsz = atob(lpsz, &lblob.addr_a);
// is there a port number here?
if (*(lpsz-1) == ':')
lblob.port = (WORD)_wtoi(lpsz);
else
lblob.port = 0;
// copy back the result
memcpy(pblobAddr, &lblob, sizeof(*pblobAddr));
return TRUE;
}
/****************************************************************************
**
** ExpandAddr(pszAddr, pblobAddr);
** Takes 6 byte binary blob and converts it into an ascii IP
** address (X.X.X.X:port)
**
** returns TRUE for success, FALSE for failure.
**
****************************************************************************/
BOOL ExpandAddr(WCHAR *pszAddr, PBLOB_ADDR pba)
{
if (!pszAddr || !pba)
{
IMPORTANT_MSG((L"ERROR: NULL ptr passed in ExpandAddr"));
return FALSE;
}
wsprintf(pszAddr, L"%d.%d.%d.%d", pba->addr_d, pba->addr_c,
pba->addr_b, pba->addr_a);
if (pba->port)
{
WCHAR scratch[8];
wsprintf(scratch, L":%d", pba->port);
wcscat(pszAddr, scratch);
}
return TRUE;
}
/****************************************************************************
**
** AsciifyAddr(pszAddr, pblobAddr);
** Takes 6 byte binary blob and converts it into compressed ascii
** will return either 6 or 8 bytes of string
**
** returns TRUE for success, FALSE for failure.
**
****************************************************************************/
BOOL AsciifyAddr(WCHAR *pszAddr, PBLOB_ADDR pba)
{
UCHAR tmp;
DWORDLONG dwl;
int i, iCnt;
if (!pszAddr || !pba)
{
IMPORTANT_MSG((L"ERROR: NULL ptr passed in AsciifyAddr"));
return FALSE;
}
iCnt = 6;
if (pba->port)
iCnt = 8;
dwl = 0;
memcpy(&dwl, pba, sizeof(*pba));
for (i = 0; i < iCnt; i++)
{
// get 6 bits of data
tmp = (UCHAR)(dwl & 0x3f);
// add the offset to asciify this
// offset must be bigger the double-quote char.
pszAddr[i] = b64Char[tmp]; // (WCHAR)(tmp + COMP_OFFSET);
// Shift right 6 bits
dwl = Int64ShrlMod32(dwl, 6);
}
// terminating NULL
pszAddr[iCnt] = 0;
return TRUE;
}
/****************************************************************************
**
** DeAsciifyAddr(pszAddr, pblobAddr);
** Takes a compressed ascii string and converts it into a
** 6 or 8 byte binary blob
**
** returns TRUE for success, FALSE for failure.
**
****************************************************************************/
BOOL DeAsciifyAddr(WCHAR *pszAddr, PBLOB_ADDR pba)
{
UCHAR tmp;
WCHAR wtmp;
DWORDLONG dwl;
int i;
int iCnt;
if (!pszAddr || !pba)
{
IMPORTANT_MSG((L"ERROR: NULL ptr passed in DeAsciifyAddr"));
return FALSE;
}
/* how long is this string?
* if it is 6 bytes, then there is no port
* else it should be 8 bytes
*/
i = wcslen(pszAddr);
if (i == 6 || i == 8)
iCnt = i;
else
{
iCnt = 8;
IMPORTANT_MSG((L"Strlen (%d) is wrong in DeAsciifyAddr", i));
}
dwl = 0;
for (i = iCnt-1; i >= 0; i--)
{
wtmp = pszAddr[i];
if (wtmp >= L'A' && wtmp <= L'Z')
tmp = wtmp - L'A';
else if (wtmp >= L'a' && wtmp <= L'z')
tmp = wtmp - L'a' + 26;
else if (wtmp >= L'0' && wtmp <= L'9')
tmp = wtmp - L'0' + 52;
else if (wtmp == L'+')
tmp = 62;
else if (wtmp == L'/')
tmp = 63;
else
{
tmp = 0;
HEINOUS_E_MSG((L"ERROR:found invalid character in decode stream"));
}
// tmp = (UCHAR)(pszAddr[i] - COMP_OFFSET);
if (tmp > 63)
{
tmp = 0;
HEINOUS_E_MSG((L"ERROR:screwup in DeAsciify"));
}
dwl = Int64ShllMod32(dwl, 6);
dwl |= tmp;
}
memcpy(pba, &dwl, sizeof(*pba));
return TRUE;
}
/****************************************************************************
**
** SquishAddress(char *szIp, char *szCompIp)
** Takes one IP address and compresses it to minimum size
**
****************************************************************************/
DWORD APIENTRY SquishAddress(WCHAR *szIp, WCHAR *szCompIp)
{
WCHAR *thisAddr, *nextAddr;
BLOB_ADDR ba;
if (!szIp || !szCompIp)
{
HEINOUS_E_MSG((L"SquishAddress called with NULL ptr"));
return ERROR_INVALID_PARAMETER;
}
// TRIVIAL_MSG((L"SquishAddress(%s)", szIp));
thisAddr = szIp;
szCompIp[0] = 0;
while (thisAddr)
{
WCHAR scr[10];
nextAddr = wcschr(thisAddr, L';');
if (nextAddr && *(nextAddr+1))
{
*nextAddr = 0;
}
else
nextAddr=0;
CompressAddr(thisAddr, &ba);
// DumpBlob(&ba);
AsciifyAddr(scr, &ba);
wcscat(szCompIp, scr);
if (nextAddr)
{
// restore seperator found earlier
*nextAddr = ';';
nextAddr++;
wcscat(szCompIp, L"!" /* COMP_SEPERATOR */);
}
thisAddr = nextAddr;
}
// TRIVIAL_MSG((L"SquishAddress returns [%s]", szCompIp));
return ERROR_SUCCESS;
}
/****************************************************************************
**
** ExpandAddress(char *szIp, char *szCompIp)
** Takes a compressed IP address and returns it to
** "normal"
**
****************************************************************************/
DWORD APIENTRY ExpandAddress(WCHAR *szIp, WCHAR *szCompIp)
{
BLOB_ADDR ba;
WCHAR *thisAddr, *nextAddr;
if (!szIp || !szCompIp)
{
HEINOUS_E_MSG((L"ExpandAddress called with NULL ptr"));
return ERROR_INVALID_PARAMETER;
}
// TRIVIAL_MSG((L"ExpandAddress(%s)", szCompIp));
thisAddr = szCompIp;
szIp[0] = 0;
while (thisAddr)
{
WCHAR scr[32];
nextAddr = wcschr(thisAddr, COMP_SEPERATOR);
if (nextAddr) *nextAddr = 0;
DeAsciifyAddr(thisAddr, &ba);
// DumpBlob(&ba);
ExpandAddr(scr, &ba);
wcscat(szIp, scr);
if (nextAddr)
{
// restore seperator found earlier
*nextAddr = COMP_SEPERATOR;
nextAddr++;
wcscat(szIp, L";");
}
thisAddr = nextAddr;
}
// TRIVIAL_MSG((L"ExpandAddress returns [%s]", szIp));
return ERROR_SUCCESS;
}
/****************************************************************************
**
** FetchAllAddressesEx
** Returns a string listing all the valid IP addresses for the machine
** controlled by a set of "flags". These are as follows:
** IPflags=
** IPF_ADD_DNS adds the DNS name to the IP list
** IPF_COMPRESS compresses the IP address list (exclusive w/ IPF_ADD_DNS)
** IPF_NO_SORT do not sort adapter IP list
**
** Formatting details:
** 1. Each address is seperated with a ";" (semicolon)
** 2. Each address consists of the "1.2.3.4", and is followed by ":p"
** where the colon is followed by the port number
**
****************************************************************************/
#define WCHAR_CNT 4096
DWORD APIENTRY FetchAllAddressesEx(WCHAR *lpszAddr, int iBufSize, int IPflags)
{
DWORD dwRet = 1;
WCHAR *AddressLst;
int iAddrLen;
BOOL bSort=FALSE;
AddressLst = (WCHAR *) malloc(WCHAR_CNT * sizeof(WCHAR));
if (!AddressLst)
{
HEINOUS_E_MSG((L"Fatal error: malloc failed in FetchAllAddressesEx"));
return 0;
}
*AddressLst = 0;
INTERESTING_MSG((L"FetchAllAddressesEx()" ));
// sanity check the flags
if ((IPflags & IPF_COMPRESS) && IPflags != IPF_COMPRESS+IPF_NO_SORT)
{
IMPORTANT_MSG((L"Illegal IPflags value (0x%x) in FetchAllAddressesEx, forcing to IPF_COMPRESS+IPF_NO_SORT", IPflags));
IPflags = IPF_COMPRESS+IPF_NO_SORT;
}
if (g_boolIcsPresent && g_pDPNH)
{
if (g_boolUsingNatHelp)
{
int i;
// gotta cycle through the g_PortHandles list...
for (i=0;i<ARRAYSIZE(g_PortHandles); i++)
{
if (g_PortHandles[i])
{
HRESULT hr = E_FAIL;
SOCKADDR_IN lsi;
DWORD dwSize, dwTypes;
DPNHCAPS lCaps;
int j;
PMAPHANDLES pMap = g_PortHandles[i];
/*
* Call GetCaps so that we get an updated address list .
* Not sure why we would want any other kind...
*/
lCaps.dwSize = sizeof(lCaps);
hr = IDirectPlayNATHelp_GetCaps(g_pDPNH, &lCaps, DPNHGETCAPS_UPDATESERVERSTATUS);
for (j=0; j < pMap->iMapped; j++)
{
dwSize = sizeof(lsi);
ZeroMemory(&lsi, dwSize);
hr = IDirectPlayNATHelp_GetRegisteredAddresses(g_pDPNH, pMap->hMapped[j], (SOCKADDR *)&lsi,
&dwSize, &dwTypes, NULL, 0, );
if (hr == DPNH_OK && dwSize)
{
WCHAR scratch[32];
wsprintf(scratch, L"%d.%d.%d.%d:%d;",
lsi.sin_addr.S_un.S_un_b.s_b1,
lsi.sin_addr.S_un.S_un_b.s_b2,
lsi.sin_addr.S_un.S_un_b.s_b3,
lsi.sin_addr.S_un.S_un_b.s_b4,
ntohs( lsi.sin_port ));
wcscat(AddressLst, scratch);
TRIVIAL_MSG((L"GetRegisteredAddresses(0x%x)=[%s]", g_PortHandles[i], scratch ));
}
else
{
IMPORTANT_MSG((L"GetRegisteredAddresses[0x%x] failed, size=0x%x", g_PortHandles[i], dwSize));
DumpLibHr(hr);
}
}
goto got_addresses;
}
}
}
else
{
union AddrV4 {
DWORD d;
BYTE b[4];
};
WCHAR scratch[32];
union AddrV4 a;
RSIP_LEASE_RECORD *pLeaseWalker;
RSIP_LEASE_RECORD *pNextLease;
pLeaseWalker = g_pRsipLeaseRecords;
while( pLeaseWalker )
{
bSort=TRUE;
pNextLease = pLeaseWalker->pNext;
a.d = pLeaseWalker->addrV4;
wsprintf(scratch, L"%d.%d.%d.%d:%d;",
a.b[0],
a.b[1],
a.b[2],
a.b[3],
ntohs(pLeaseWalker->rport));
wcscat(AddressLst, scratch);
pLeaseWalker=pNextLease;
}
}
}
got_addresses:
iAddrLen = wcslen(AddressLst);
GetIPAddress(AddressLst+iAddrLen, WCHAR_CNT-iAddrLen, g_iPort);
if (IPflags & IPF_ADD_DNS)
{
WCHAR *DnsName=NULL;
DWORD dwNameSz=0;
GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, NULL, &dwNameSz);
dwNameSz++;
DnsName = (WCHAR *)malloc(dwNameSz * sizeof(WCHAR));
if (DnsName)
{
*DnsName = 0;
if (GetComputerNameEx(ComputerNamePhysicalDnsFullyQualified, DnsName, &dwNameSz))
{
if ((dwNameSz + iAddrLen) < WCHAR_CNT-4)
wcscat(AddressLst, DnsName);
if (g_iPort)
{
WCHAR scr[16];
wsprintf(scr, L":%d", g_iPort);
wcscat(AddressLst, scr);
}
}
free(DnsName);
}
}
if (!(IPflags & IPF_NO_SORT) && bSort)
{
WCHAR *lpStart;
WCHAR szLast[36];
int i=0;
TRIVIAL_MSG((L"Sorting address list : %s", AddressLst));
lpStart = AddressLst+iAddrLen;
while (*(lpStart+i) && *(lpStart+i) != L';')
{
szLast[i] = *(lpStart+i);
i++;
}
szLast[i++]=0;
wcscpy(lpStart, lpStart+i);
TRIVIAL_MSG((L"inter sort: %s, %s", AddressLst, szLast));
wcscat(AddressLst, L";");
wcscat(AddressLst, szLast);
TRIVIAL_MSG((L"sort done"));
}
if (IPflags & IPF_COMPRESS)
{
WCHAR compBfr[1000];
compBfr[0]=0;
SquishAddress(AddressLst, compBfr);
TRIVIAL_MSG((L"inner comp: %s, %s", AddressLst, compBfr));
wcscpy(AddressLst, compBfr);
}
dwRet = 1 + wcslen(AddressLst);
if (lpszAddr && iBufSize >= (int)dwRet)
memcpy(lpszAddr, AddressLst, dwRet*(sizeof(AddressLst[0])));
INTERESTING_MSG((L"Fetched all Ex-addresses:cnt=%d, sz=[%s]", dwRet, AddressLst));
free(AddressLst);
return dwRet;
}
// it is hard to imagine a machine with this many simultaneous connections, but it is possible, I suppose
#define RAS_CONNS 6
DWORD GetConnections()
{
DWORD dwRet;
RASCONN *lpRasConn, *lpFree;
DWORD lpcb, lpcConnections;
int i;
TRIVIAL_MSG((L"entered GetConnections"));
lpFree = NULL;
lpcb = RAS_CONNS * sizeof(RASCONN);
lpRasConn = (LPRASCONN) malloc(lpcb);
if (!lpRasConn) return 0;
lpFree = lpRasConn;
lpRasConn->dwSize = sizeof(RASCONN);
lpcConnections = RAS_CONNS;
dwRet = RasEnumConnections(lpRasConn, &lpcb, &lpcConnections);
if (dwRet != 0)
{
IMPORTANT_MSG((L"RasEnumConnections failed: Error = %d", dwRet));
free(lpFree);
return 0;
}
dwRet = 0;
TRIVIAL_MSG((L"Found %d connections", lpcConnections));
if (lpcConnections)
{
for (i = 0; i < (int)lpcConnections; i++)
{
TRIVIAL_MSG((L"Entry name: %s, type=%s\n", lpRasConn->szEntryName, lpRasConn->szDeviceType));
if (!_wcsicmp(lpRasConn->szDeviceType, RASDT_Modem ))
{
TRIVIAL_MSG((L"Found a modem (%s)", lpRasConn->szDeviceName));
dwRet |= 1;
}
else if (!_wcsicmp(lpRasConn->szDeviceType, RASDT_Vpn))
{
TRIVIAL_MSG((L"Found a VPN (%s)", lpRasConn->szDeviceName));
dwRet |= 2;
}
else
{
// probably ISDN, or something like that...
TRIVIAL_MSG((L"Found something else, (%s)", lpRasConn->szDeviceType));
dwRet |= 4;
}
lpRasConn++;
}
}
if (lpFree)
free(lpFree);
TRIVIAL_MSG((L"GetConnections returning 0x%x", dwRet));
return dwRet;
}
#undef RAS_CONNS
/****************************************************************************
**
** GetIcsStatus(PICSSTAT pStat)
** Returns a structure detailing much of what is going on inside this
** library. The dwSize entry must be filled in before calling this
** function. Use "sizeof(ICSSTAT))" to populate this.
**
****************************************************************************/
DWORD APIENTRY GetIcsStatus(PICSSTAT pStat)
{
DWORD dwSz;
if (!pStat || pStat->dwSize > sizeof(ICSSTAT))
{
HEINOUS_E_MSG((L"ERROR:Bad pointer or size passed in to GetIcsStatus"));
return ERROR_INVALID_PARAMETER;
}
// clear out the struct
dwSz = pStat->dwSize;
ZeroMemory(pStat, dwSz);
pStat->dwSize = dwSz;
pStat->bIcsFound = g_boolIcsPresent;
pStat->bIcsServer = g_boolIcsOnThisMachine;
pStat->bUsingDP = g_boolUsingNatHelp;
if (g_boolUsingNatHelp)
pStat->bUsingUpnp = !g_boolUsingNatPAST;
if (g_boolIcsPresent)
{
wsprintf(pStat->wszPubAddr, L"%S", g_szPublicAddr);
wsprintf(pStat->wszLocAddr, L"%d.%d.%d.%d",
g_saddrLocal.sin_addr.S_un.S_un_b.s_b1,
g_saddrLocal.sin_addr.S_un.S_un_b.s_b2,
g_saddrLocal.sin_addr.S_un.S_un_b.s_b3,
g_saddrLocal.sin_addr.S_un.S_un_b.s_b4);
wsprintf(pStat->wszDllName, L"%S", g_lpszDllName);
}
else
wsprintf(pStat->wszDllName, L"none");
dwSz = GetConnections();
if (dwSz & 1)
pStat->bModemPresent = TRUE;
if (dwSz & 2)
pStat->bVpnPresent = TRUE;
return ERROR_SUCCESS;
}
/*************************************************************************************
**
**
*************************************************************************************/
int GetTsPort(void)
{
DWORD dwRet = 3389;
HKEY hKey;
// open reg key first, to get ALL the spew...HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd\\Tds\\tcp
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\Wds\\rdpwd\\Tds\\tcp", 0, KEY_READ, &hKey))
{
DWORD dwSize;
dwSize = sizeof(dwRet);
RegQueryValueEx(hKey, L"PortNumber", NULL, NULL, (LPBYTE)&dwRet, &dwSize);
RegCloseKey(hKey);
}
return dwRet;
}