📄 proxy.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 "proxy.h"
#include "proxydev.h"
#include "auth.h"
#include "proxydbg.h"
#include <iphlpapi.h>
#include <ws2tcpip.h>
#include "resource.h"
#include "parser.h"
#include "filter.h"
ProxySettings* g_pSettings;
ProxyErrors* g_pErrors;
SVSThreadPool* g_pThreadPool;
DWORD InitStrings(void);
void DeinitStrings(void);
//
// The following methods belong to the CHttpProxy class which is the central
// class for the Web Proxy.
//
CHttpProxy::CHttpProxy(void)
{
}
DWORD CHttpProxy::Init(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
WSADATA wsadata;
svsutil_Initialize();
WSAStartup(MAKEWORD(2, 2), &wsadata);
g_pErrors = new ProxyErrors;
if (! g_pErrors) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
g_pSettings = new ProxySettings;
if (! g_pSettings) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
g_pParser = new CHttpParser;
if (! g_pParser) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
g_pSessionMgr = new CSessionMgr;
if (! g_pSessionMgr) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
g_pProxyFilter = new CProxyFilter;
if (! g_pProxyFilter) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory.\n")));
goto exit;
}
dwRetVal = InitStrings();
if (ERROR_SUCCESS != dwRetVal) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error initializing proxy strings.\n")));
goto exit;
}
m_fRunning = FALSE;
IFDBG(DebugOut(ZONE_SERVICE, _T("WebProxy: Service has been initialized successfully.\n")));
exit:
if (ERROR_SUCCESS != dwRetVal) {
if (g_pProxyFilter) {
delete g_pProxyFilter;
g_pProxyFilter = NULL;
}
if (g_pParser) {
delete g_pParser;
g_pParser = NULL;
}
if (g_pSessionMgr) {
delete g_pSessionMgr;
g_pSessionMgr = NULL;
}
}
return dwRetVal;
}
DWORD CHttpProxy::Deinit(void)
{
DeinitStrings();
delete g_pProxyFilter;
g_pProxyFilter = NULL;
delete g_pSessionMgr;
g_pSessionMgr = NULL;
delete g_pParser;
g_pParser = NULL;
WSACleanup();
svsutil_DeInitialize();
IFDBG(DebugOut(ZONE_SERVICE, _T("WebProxy: Service has been deinitialized successfully.\n")));
return ERROR_SUCCESS;
}
DWORD CHttpProxy::InitSettings(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
CReg regWebProxy;
//
// Set the default values for all registry configurable settings
//
DWORD cSessionThreads = DEFAULT_MAX_CONNECTIONS;
g_pSettings->Reset();
m_fRunning = FALSE;
//
// If we fail to open the registry key, that is ok as it is possible to desire all
// the default settings.
//
if (regWebProxy.Open(HKEY_LOCAL_MACHINE, RK_WEBPROXY)) {
WCHAR* pszTmp;
g_pSettings->iMaxConnections = regWebProxy.ValueDW(RV_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS);
g_pSettings->iPort = regWebProxy.ValueDW(RV_PORT, DEFAULT_PROXY_PORT);
g_pSettings->fNTLMAuth = regWebProxy.ValueDW(RV_AUTH_NTLM, DEFAULT_AUTH_NTLM);
g_pSettings->fBasicAuth = regWebProxy.ValueDW(RV_AUTH_BASIC, DEFAULT_AUTH_BASIC);
g_pSettings->iSessionTimeout = regWebProxy.ValueDW(RV_SESSION_TIMEOUT, DEFAULT_SESSION_TIMEOUT);
g_pSettings->iMaxBufferSize = regWebProxy.ValueDW(RV_MAXHEADERSSIZE, DEFAULT_MAX_BUFFER_SIZE);
g_pSettings->iSecondProxyPort = regWebProxy.ValueDW(RV_SECOND_PROXY_PORT, DEFAULT_HTTP_PORT);
cSessionThreads = regWebProxy.ValueDW(RV_SESSION_THREADS, g_pSettings->iMaxConnections);
pszTmp = (WCHAR *) regWebProxy.ValueSZ(RV_SECOND_PROXY_HOST);
if (pszTmp) {
DWORD cchTmp = wcslen(pszTmp);
g_pSettings->strSecondProxyHost.reserve(cchTmp+1);
WideCharToMultiByte(CP_ACP, 0, pszTmp, -1, g_pSettings->strSecondProxyHost.get_buffer(), g_pSettings->strSecondProxyHost.capacity(), NULL, NULL);
}
}
g_pThreadPool = new SVSThreadPool(cSessionThreads);
if (! g_pThreadPool) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Out of memory allocating SVSThreadPool.\n")));
goto exit;
}
g_pSettings->strHostName.reserve(MAX_PATH);
dwRetVal = gethostname(g_pSettings->strHostName.get_buffer(), g_pSettings->strHostName.capacity());
if (ERROR_SUCCESS != dwRetVal) {
g_pSettings->strHostName = DEFAULT_HOST_NAME_SZ;
}
g_pProxyFilter->LoadFilters();
if (g_pSettings->fNTLMAuth) {
dwRetVal = InitNTLMSecurityLib();
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
}
if (g_pSettings->fBasicAuth) {
dwRetVal = InitBasicAuth();
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
}
exit:
if (ERROR_SUCCESS != dwRetVal) {
g_pProxyFilter->RemoveAllFilters();
if (g_pThreadPool) {
delete g_pThreadPool;
g_pThreadPool = NULL;
}
}
return dwRetVal;
}
DWORD CHttpProxy::DeinitSettings(void)
{
if (g_pSettings->fNTLMAuth) {
DeinitNTLMSecurityLib();
}
if (g_pSettings->fBasicAuth) {
DeinitBasicAuth();
}
g_pProxyFilter->RemoveAllFilters();
delete g_pThreadPool;
g_pThreadPool = NULL;
return ERROR_SUCCESS;
}
DWORD CHttpProxy::Start(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
Lock();
InitSettings();
m_fRunning = TRUE;
UpdateAdapterInfo();
m_hServerThread = CreateThread(NULL, 0, ServerThread, (LPVOID)this, 0, NULL);
if (! m_hServerThread.valid()) {
dwRetVal = GetLastError();
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error creating ServerThread: %d.\n"), dwRetVal));
goto exit;
}
IFDBG(DebugOut(ZONE_SERVICE, _T("WebProxy: Service has been started successfully.\n")));
exit:
Unlock();
return dwRetVal;
}
DWORD CHttpProxy::Stop(void)
{
DWORD dwRetVal = ERROR_SUCCESS;
Lock();
m_fRunning = FALSE;
for (int i = 0; i < m_cSockets; i++) {
m_sockServer[i].close();
}
m_cSockets = 0;
// Need to shutdown each item in the list, then shutdown thread pool,
// then remove the items from the list.
g_pSessionMgr->ShutdownAllSessions();
g_pThreadPool->Shutdown();
g_pSessionMgr->RemoveAllSessions();
// If this function is being called from the ServerThread then we should not wait
if ((HANDLE)GetCurrentThreadId() != m_hServerThread) {
HANDLE h = m_hServerThread;
Unlock();
dwRetVal = WaitForSingleObject(h, INFINITE);
Lock();
if (WAIT_FAILED == dwRetVal) {
dwRetVal = GetLastError();
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error stopping ServerThread: %d.\n"), dwRetVal));
ASSERT(0);
goto exit;
}
}
DeinitSettings();
dwRetVal = ERROR_SUCCESS;
IFDBG(DebugOut(ZONE_SERVICE, _T("WebProxy: Service has been stopped successfully.\n")));
exit:
Unlock();
return dwRetVal;
}
DWORD CHttpProxy::NotifyAddrChange(PBYTE pBufIn, DWORD cbBufIn)
{
IFDBG(DebugOut(ZONE_SERVICE, _T("WebProxy: Received address change notification.\n")));
UpdateAdapterInfo();
return ERROR_SUCCESS;
}
DWORD CHttpProxy::SignalFilter(DWORD dwSignal)
{
return g_pProxyFilter->Signal(dwSignal);
}
DWORD WINAPI CHttpProxy::ServerThread(LPVOID pv)
{
CHttpProxy* pInst = reinterpret_cast<CHttpProxy*> (pv);
pInst->Run();
return 0;
}
void CHttpProxy::Run(void)
{
DWORD dwErr = ERROR_SUCCESS;
Lock();
dwErr = SetupServerSockets();
if (ERROR_SUCCESS != dwErr) {
Stop();
g_dwState = SERVICE_STATE_OFF;
goto exit;
}
while (1) {
int i = 0;
fd_set sockSet;
FD_ZERO(&sockSet);
for (i = 0; i < m_cSockets; i++) {
FD_SET(m_sockServer[i], &sockSet);
}
Unlock();
if (SERVICE_STATE_ON != g_dwState) {
// Another thread has indicated that the program should be terminated
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Web Proxy main thread will not continue because another thread has changed service state.\n")));
// do not break out of loop or goto exit block, but quit immediatly.
// Also no need to Stop() because the other thread shutting us down has performed this already
return;
}
int iSockets = select(0,&sockSet,NULL,NULL,NULL);
Lock();
// Check if service is being signalled to stop
if (! m_fRunning) {
IFDBG(DebugOut(ZONE_SERVICE, _T("WebProxy: Server thread is being signalled to stop, exiting...\n")));
break;
}
if ((0 == iSockets) || (SOCKET_ERROR == iSockets)) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error in call to select: %d\n"), WSAGetLastError()));
goto exit;
}
for (i = 0; i < iSockets; i++) {
SOCKADDR_STORAGE saClient;
int cbsa = sizeof(saClient);
auto_socket sockClient = accept(sockSet.fd_array[i], (SOCKADDR*)&saClient, &cbsa);
if (INVALID_SOCKET == sockClient) {
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Accept on server socket failed: %d\n"), WSAGetLastError()));
continue;
}
// Check if we have exceeded the maximum number of connections
if (g_pSessionMgr->GetSessionCount() > g_pSettings->iMaxConnections) {
sockClient.close();
IFDBG(DebugOut(ZONE_WARN, _T("WebProxy: Cannot accept any new connections - connection limit has been reached.\n")));
continue;
}
SessionSettings settings;
memset(&settings, 0, sizeof(settings));
settings.sockClient = sockClient;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -