📄 session.cpp
字号:
}
//
// Update the response headers
//
headers.UpdateResponse();
cbNewHeaders = headers.GetBufferSize();
*pcchBuffer += (cbNewHeaders - cchHeaders);
*pcchSent = fAdditionalContent ? (cbNewHeaders + cbTotalContent) : *pcchBuffer;
pBuffer = buffer.GetBuffer(*pcchBuffer); // add one for a null terminating char
if(! pBuffer) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Insufficient memory to allocate send buffer.\n")));
goto exit;
}
// Copy response buffer
headers.GetResponseBuffer(pBuffer);
// Copy content back after headers
if (cbContent) {
memcpy(&pBuffer[cbNewHeaders], pContent, cbContent);
}
}
//
// Send the data along to the client
//
dwRetVal = SendData(m_sockClient, (char *)pBuffer, *pcchSent);
exit:
if (ERROR_SUCCESS != dwRetVal) {
SendMessage(m_sockClient, "502", gc_Reason502, g_pErrors->szMiscError, g_pErrors->cchMiscError);
}
return dwRetVal;
}
void CHttpSession::ClearRecvBuf(CBuffer& buffer)
{
DWORD dwRetVal;
PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
while (m_cbRequestRemain > 0) {
int cbRecved = 0;
SOCKET sock = m_sockClient;
SessionUnlock();
dwRetVal = NonBlockingRecv(sock, pBuffer, buffer.GetSize(), &cbRecved);
SessionLock();
if ((ERROR_SUCCESS != dwRetVal) || (0 == cbRecved)) {
break;
}
m_cbRequestRemain -= cbRecved;
}
m_cbRequestRemain = 0;
}
DWORD CHttpSession::HandleConnectRequest(stringi& strHost, stringi& strPort)
{
DWORD dwRetVal = ERROR_SUCCESS;
//
// Only accept CONNECT requests on HTTPS port. CONNECT requests on other ports represent
// a security risk and therefore, are rejected.
//
if (strPort == DEFAULT_HTTPS_PORT_SZ) {
dwRetVal = ConnectServer(strHost, DEFAULT_HTTPS_PORT);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
CHttpHeaders response;
response.strStatusCode = "200";
response.strReason = gc_Reason200Conn;
response.UpdateResponse();
dwRetVal = SendCustomPacket(m_sockClient, response);
if (ERROR_SUCCESS == dwRetVal) {
m_fSSLTunnel = TRUE;
}
}
else {
IFDBG(DebugOut(ZONE_OUTPUT, _T("WebProxy: A CONNECT request was attempted on a port other than 443 - this is not allowed.\n")));
dwRetVal = ERROR_INVALID_PARAMETER;
}
exit:
return dwRetVal;
}
DWORD CHttpSession::ConnectServer(const char* szHost, int iPort)
{
DWORD dwRetVal = ERROR_SUCCESS;
CHAR szPort[16];
stringi strNewHost;
ADDRINFO *pAI = NULL;
IFDBG(DebugOut(ZONE_CONNECT, _T("WebProxy: Trying to connect to host %S on port %d in session %d.\n"), szHost, iPort, m_dwSessionId));
sprintf(szPort, "%d", iPort);
dwRetVal = getaddrinfo(szHost, szPort, NULL, &pAI);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
m_sockServer = socket(pAI->ai_family, SOCK_STREAM, 0);
if (! m_sockServer.valid()) {
dwRetVal = WSAGetLastError();
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Error creating socket %d.\n"), dwRetVal));
goto exit;
}
// Connect to host
if (SOCKET_ERROR == connect(m_sockServer, pAI->ai_addr, pAI->ai_addrlen)) {
dwRetVal = WSAGetLastError();
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Connect call failed with error %d.\n"), dwRetVal));
m_sockServer.close();
goto exit;
}
m_strServerName = szHost;
IFDBG(DebugOut(ZONE_CONNECT, _T("WebProxy: Connected to host %S on port %d in session %d.\n"), szHost, ((iPort == -1) ? DEFAULT_HTTP_PORT : iPort), m_dwSessionId));
exit:
if (pAI) {
freeaddrinfo(pAI);
}
return dwRetVal;
}
DWORD CHttpSession::HandleAuthentication(CHttpHeaders& headers, CBuffer& buffer, BOOL* pfCloseConnection)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD dwAuthType = 0;
CHttpHeaders response;
BOOL fAuthSuccess = FALSE;
int cbUser = MAX_USER_NAME;
while (1) {
// Get authorization data
g_pParser->ParseAuthorization(headers, &dwAuthType);
if ((AUTH_TYPE_UNKNOWN == dwAuthType) || (headers.strProxyAuthorization == "")) {
//
// Unknown Authentication type, resend Authenticate headers
//
*pfCloseConnection = TRUE;
response.strProxyConnection = gc_ConnClose;
if (g_pSettings->fNTLMAuth) {
response.strProxyAuthenticate = gc_AuthNTLM;
}
if (g_pSettings->fBasicAuth) {
response.strProxyAuthenticate2 = gc_AuthBasic;
}
}
else if (AUTH_TYPE_NTLM == dwAuthType) {
//
// NTLM Authentication
//
string strNTLMAuth;
int cbNTLMAuthOut;
GetMaxNTLMBuffBase64Size((DWORD *)&cbNTLMAuthOut);
strNTLMAuth.reserve(cbNTLMAuthOut);
m_strUser.reserve(cbUser);
dwRetVal = HandleNTLMAuth(headers.strProxyAuthorization, strNTLMAuth.get_buffer(), cbNTLMAuthOut, m_strUser.get_buffer(), cbUser, &m_auth);
if (ERROR_INSUFFICIENT_BUFFER == dwRetVal) {
cbUser *= 2;
FreeNTLMHandles(&m_auth);
m_auth.m_Conversation = NTLM_NO_INIT_CONTEXT;
continue;
}
else if (ERROR_SUCCESS != dwRetVal) {
FreeNTLMHandles(&m_auth);
m_auth.m_Conversation = NTLM_NO_INIT_CONTEXT;
goto exit;
}
if (NTLM_DONE == m_auth.m_Conversation) {
FreeNTLMHandles(&m_auth);
m_auth.m_Conversation = NTLM_NO_INIT_CONTEXT;
}
//
// If m_strUser is empty then we did not authenticate on this pass. In this case strNTLMAuth should have data in
// which case you will return this to the client. If strNTLMAuth is also NULL then we failed to authenticate and
// should start from the beginning again.
//
if (m_strUser != "") {
fAuthSuccess = TRUE;
}
else if (strNTLMAuth != "") {
response.strConnection = gc_ConnKeepAlive;
response.strProxyConnection = gc_ConnKeepAlive;
response.strProxyAuthenticate = gc_AuthNTLM;
response.strProxyAuthenticate += " ";
response.strProxyAuthenticate += strNTLMAuth;
}
else {
*pfCloseConnection = TRUE;
response.strProxyConnection = gc_ConnClose;
if (g_pSettings->fNTLMAuth) {
response.strProxyAuthenticate = gc_AuthNTLM;
}
if (g_pSettings->fBasicAuth) {
response.strProxyAuthenticate2 = gc_AuthBasic;
}
}
}
else {
//
// Basic authentication
//
m_strUser.reserve(cbUser);
dwRetVal = HandleBasicAuth(headers.strProxyAuthorization, &fAuthSuccess, m_strUser.get_buffer(), cbUser);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
if ((! fAuthSuccess) || (m_strUser == "")) {
*pfCloseConnection = TRUE;
response.strProxyConnection = gc_ConnClose;
if (g_pSettings->fNTLMAuth) {
response.strProxyAuthenticate = gc_AuthNTLM;
}
if (g_pSettings->fBasicAuth) {
response.strProxyAuthenticate2 = gc_AuthBasic;
}
}
}
break;
}
//
// If we did not successfully authenticate, then respond to the client now with
// a 407 error.
//
if (! fAuthSuccess) {
ClearRecvBuf(buffer);
response.strStatusCode = "407";
response.strReason = gc_Reason407;
char szBuf[5];
response.strContentLength = _itoa(g_pErrors->cchProxyAuthFailed, szBuf, 10);
response.UpdateResponse();
// Send headers
dwRetVal = SendCustomPacket(m_sockClient, response);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
// Send "auth failed" content message
dwRetVal = SendData(m_sockClient, g_pErrors->szProxyAuthFailed, g_pErrors->cchProxyAuthFailed);
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
IFDBG(DebugOut(ZONE_AUTH, _T("WebProxy: Sent authentication response with status 407, to client in session %d.\n"), m_dwSessionId));
}
exit:
return dwRetVal;
}
DWORD CHttpSession::HandleProxyPacRequest(void)
{
CHAR szProxyPac[1024];
int cchProxyPac;
IFDBG(DebugOut(ZONE_REQUEST, _T("WebProxy: Sending proxy.pac file to client.\n")));
g_pSettings->Lock();
ULONG ulIpMask = inet_addr(g_pSettings->strPrivateMaskV4);
ULONG ulIpAddr = inet_addr(g_pSettings->strPrivateAddrV4);
sockaddr_in dest;
dest.sin_addr.S_un.S_addr = (ulIpAddr & ulIpMask);
string strDest = inet_ntoa(dest.sin_addr);
sprintf(szProxyPac, gc_szProxyPac, (LPCSTR)strDest, (LPCSTR)g_pSettings->strPrivateMaskV4, (LPCSTR)g_pSettings->strPrivateAddrV4, g_pSettings->iPort);
cchProxyPac = strlen(szProxyPac);
g_pSettings->Unlock();
return SendMessage(m_sockClient, "200", gc_Reason200, szProxyPac, cchProxyPac);
}
DWORD CHttpSession::ProxyRecv(SOCKET sock, CBuffer& buffer, int* pcbTotalRecved, int cbRemain, int* pcbHeaders)
{
DWORD dwRetVal = ERROR_SUCCESS;
int cbHeaders = 0;
PBYTE pBuffer = buffer.GetBuffer(0, FALSE);
ASSERT(pBuffer);
ASSERT(pcbTotalRecved);
//
// If all headers have not yet been read, we have to read them. Otherwise, this is just reading
// another chunk of data.
//
while (0 == cbHeaders) {
int cbBuffer;
int cbRecved = 0;
int cbRecvBufferIn;
PBYTE pBuff;
// If we have recved some data and are still in this loop then we have to recv more. Double the buffer
// size and proceed to recv more data.
cbBuffer = *pcbTotalRecved;
if (cbBuffer >= DEFAULT_BUFFER_SIZE - 1) {
cbBuffer *= 2;
if (cbBuffer > g_pSettings->iMaxBufferSize) {
dwRetVal = ERROR_INVALID_DATA;
goto exit;
}
}
else {
cbBuffer = DEFAULT_BUFFER_SIZE - 1;
}
pBuffer = buffer.GetBuffer(cbBuffer + 1, *pcbTotalRecved ? TRUE : FALSE); // add 1 to append '\0'
if(! pBuffer) {
dwRetVal = ERROR_OUTOFMEMORY;
IFDBG(DebugOut(ZONE_ERROR, _T("WebProxy: Insufficient memory to allocate recv buffer.\n")));
goto exit;
}
pBuff = pBuffer;
cbRecvBufferIn = buffer.GetSize() - *pcbTotalRecved - 1;
if ((cbRemain > 0) && (cbRecvBufferIn > cbRemain)) {
//
// If we have read all the headers and size of recv buffer is larger than what is left
// that has to be read, then just read the amount that has to be read for this response.
// Doing this ensures the start of a response will always be at the start of a packet.
//
cbRecvBufferIn = cbRemain;
}
SessionUnlock();
dwRetVal = NonBlockingRecv(sock, &pBuff[*pcbTotalRecved], cbRecvBufferIn, &cbRecved);
SessionLock();
if (ERROR_SUCCESS != dwRetVal) {
goto exit;
}
IFDBG(DebugOut(ZONE_PACKETS, _T("Received the following packet:\n")));
IFDBG(DumpBuff(pBuff, cbRecved));
*pcbTotalRecved += cbRecved;
pBuff[*pcbTotalRecved] = '\0';
// If we have already parsed the headers or we are just tunneling SSL data,
// then break from this loop now.
if ((0 != cbRemain) || m_fSSLTunnel) {
break;
}
// Both IE and Netscape append CRLF to POST but do not count it as part of the content-length. It is possible
// for these two bytes to be sent in their own packet and get unrecognized until this point.
if ((m_strCurrMethod == gc_MethodPost) && (cbRecved == 2) && (pBuff[0] == '\r') && (pBuff[1] == '\n')) {
m_cbRequestRemain = 2; // Reset this to two bytes left
break;
}
// This call will return 0 if all the headers have not been recved
cbHeaders = GetHeadersLength(pBuff);
}
exit:
if (pcbHeaders) {
*pcbHeaders = cbHeaders;
}
return dwRetVal;
}
DWORD CHttpSession::ReadChunkSize(SOCKET recvSock, CBuffer& buffer, int* pcbRecved, DWORD* pdwChunkSize, DWORD* pdwChunkHeaderSize)
{
DWORD dwRetVal = ERROR_SUCCESS;
DWORD dwReadAttempts = 0;
ASSERT(pcbRecved);
ASSERT(pdwChunkSize);
ASSERT(pdwChunkHeaderSize);
*pdwChunkSize = 0;
*pdwChunkHeaderSize = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -