📄 socmfc.cpp
字号:
pEx->Delete();
Close();
AfxThrowWSocketException(nError);
}
}
void CWSocket::ConnectViaSocks5(LPCTSTR lpszHostAddress, UINT nHostPort, LPCTSTR lpszSocksServer, UINT nSocksPort, LPCTSTR lpszUserName, LPCTSTR lpszPassword, DWORD dwConnectionTimeout, BOOL bUDP)
{
USES_CONVERSION;
ASSERT(IsCreated()); //must have been created first
//connect to the proxy
Connect(lpszSocksServer, nSocksPort);
try
{
BOOL bAuthenticate = (lpszUserName != NULL);
//Fill in a connection request packet
WSOCKET_SOCKS5_IDENTIFIER_PACKET request;
request.VER = 5;
request.NMETHODS = 1;
request.METHODS[0] = 0;
if (bAuthenticate)
{
request.NMETHODS++;
request.METHODS[1] = 2;
}
Send(&request, bAuthenticate ? 4 : 3);
//Wait for the connection reply
WSOCKET_SOCKS5_METHODSELECTION_MESSAGE reply;
memset(&reply, 0, sizeof(reply));
int nDataReceived = 0;
while (nDataReceived < sizeof(reply))
{
if (IsReadible(dwConnectionTimeout))
{
int nData = Receive(((BYTE*) &reply) + nDataReceived, sizeof(reply) - nDataReceived);
nDataReceived += nData;
}
else
AfxThrowWSocketException(WSAETIMEDOUT);
}
//Validate the response
if ((bAuthenticate && ((reply.METHOD != 0) && (reply.METHOD != 2))) || (!bAuthenticate && (reply.METHOD != 0)))
AfxThrowWSocketException(WSAECONNREFUSED);
if (bAuthenticate && reply.METHOD == 2)
{
LPSTR pszAsciiUserName = T2A((LPTSTR) lpszUserName);
LPSTR pszAsciiPassword = T2A((LPTSTR) lpszPassword);
int nUserNameLength = (int) strlen(pszAsciiUserName);
int nPasswordLength = 0;
if (pszAsciiPassword)
nPasswordLength = (int) strlen(pszAsciiPassword);
if ((nUserNameLength > 255) || (nPasswordLength > 255))
AfxThrowWSocketException(ERROR_INVALID_PARAMETER);
int nUserRequestLength = 3 + nUserNameLength + nPasswordLength;
BYTE* pUserRequest = new BYTE[nUserRequestLength];
pUserRequest[0] = 1;
pUserRequest[1] = (BYTE) nUserNameLength;
CopyMemory(&(pUserRequest[2]), pszAsciiUserName, nUserNameLength);
pUserRequest[2 + nUserNameLength] = (BYTE) nPasswordLength;
CopyMemory(pUserRequest + 3 + nUserNameLength, pszAsciiPassword, nPasswordLength);
Send(pUserRequest, nUserRequestLength);
//Wait for the login reply
WSOCKET_SOCKS5_USERNAME_AUTHENTICATION_REPLY reply;
memset(&reply, 0, sizeof(reply));
int nDataReceived = 0;
while (nDataReceived < sizeof(reply))
{
if (IsReadible(dwConnectionTimeout))
{
int nData = Receive(((BYTE*) &reply) + nDataReceived, sizeof(reply) - nDataReceived);
nDataReceived += nData;
}
else
AfxThrowWSocketException(WSAETIMEDOUT);
}
if (reply.STATUS != 0)
AfxThrowWSocketException(ERROR_ACCESS_DENIED);
}
//Determine if the address is in dotted notation
LPSTR lpszAscii = T2A((LPTSTR) lpszHostAddress);
unsigned long nAddr = inet_addr(lpszAscii);
if (nAddr == INADDR_NONE)
{
//verify that the host name is less than 256 bytes which is the limit of the hostname which Socks5 can accomadate
int nHostLength = (int) strlen(lpszAscii);
if (nHostLength > 255)
AfxThrowWSocketException(ERROR_INVALID_PARAMETER);
WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS requestDetails;
memset(&requestDetails, 0, sizeof(requestDetails));
requestDetails.Base.VER = 5;
if (bUDP)
requestDetails.Base.CMD = 3;
else
requestDetails.Base.CMD = 1;
requestDetails.Base.ATYP = 3;
requestDetails.DST_HOST.LENGTH = (BYTE) nHostLength;
memcpy(requestDetails.DST_HOST.HOST, lpszAscii, nHostLength);
WORD* pPort = (WORD*) (requestDetails.DST_HOST.HOST + nHostLength);
*pPort = htons((u_short) nHostPort);
int nRequestDetailsSize = sizeof(requestDetails) - 256 + nHostLength + 1;
Send(&requestDetails, nRequestDetailsSize);
}
else
{
WSOCKET_SOCKS5_IP4_REQUEST_DETAILS requestDetails;
memset(&requestDetails, 0, sizeof(requestDetails));
requestDetails.Base.VER = 5;
requestDetails.Base.CMD = 1;
requestDetails.Base.ATYP = 1;
requestDetails.DST_IP.S_un.S_addr = nAddr;
requestDetails.DSTPORT = htons((u_short) nHostPort);
Send(&requestDetails, sizeof(requestDetails));
}
ReadSocks5ConnectReply(dwConnectionTimeout);
}
catch(CWSocketException* pEx)
{
//Close the socket before we rethrow the exception
int nError = pEx->m_nError;
pEx->Delete();
Close();
AfxThrowWSocketException(nError);
}
}
void CWSocket::ReadSocks5ConnectReply(DWORD dwTimeout)
{
//The local variables which will receive the data
int nBufSize = max(sizeof(WSOCKET_SOCKS5_IP4_REQUEST_DETAILS), sizeof(WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS));
BYTE* pRawRequest = new BYTE[nBufSize];
//retrieve the reponse
DWORD dwCurrentReadOffset = 0;
BOOL bMoreDataToRead = TRUE;
while (bMoreDataToRead)
{
if (IsReadible(dwTimeout))
{
int nBufRemaining = nBufSize - dwCurrentReadOffset;
int nData = Receive(pRawRequest + dwCurrentReadOffset, nBufRemaining);
//Increment the count of data received
dwCurrentReadOffset += nData;
//Try to parse out what we received
if (dwCurrentReadOffset >= sizeof(WSOCKET_SOCKS5_BASE_REQUEST_DETAILS))
{
WSOCKET_SOCKS5_BASE_REQUEST_DETAILS* pBaseRequest = (WSOCKET_SOCKS5_BASE_REQUEST_DETAILS*) pRawRequest;
if (pBaseRequest->ATYP == 1)
{
//An IP 4 address type destination
bMoreDataToRead = (dwCurrentReadOffset < sizeof(WSOCKET_SOCKS5_IP4_REQUEST_DETAILS));
if (!bMoreDataToRead)
{
if (pBaseRequest->CMD != 0)
{
delete [] pRawRequest;
AfxThrowWSocketException(ERROR_BAD_NET_RESP);
}
}
}
else if (pBaseRequest->ATYP == 3)
{
//A domain name type destination
if (dwCurrentReadOffset > sizeof(WSOCKET_SOCKS5_BASE_REQUEST_DETAILS))
{
WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS* pHostnameRequest = (WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS*) pRawRequest;
bMoreDataToRead = (dwCurrentReadOffset < ((sizeof(WSOCKET_SOCKS5_HOSTNAME_REQUEST_DETAILS) - 256) + pHostnameRequest->DST_HOST.LENGTH));
if (!bMoreDataToRead)
{
if (pBaseRequest->CMD != 0)
{
delete [] pRawRequest;
AfxThrowWSocketException(ERROR_BAD_NET_RESP);
}
}
}
}
else
{
delete [] pRawRequest;
AfxThrowWSocketException(ERROR_INVALID_PARAMETER);
}
}
}
else
{
delete [] pRawRequest;
AfxThrowWSocketException(WSAETIMEDOUT);
}
}
delete [] pRawRequest;
}
BOOL CWSocket::IsReadible(DWORD dwTimeout)
{
ASSERT(IsCreated()); //must have been created first
timeval timeout;
timeout.tv_sec = dwTimeout/1000;
timeout.tv_usec = (dwTimeout%1000)*1000;
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_hSocket, &fds);
int nStatus = select(0, &fds, NULL, NULL, &timeout);
if (nStatus == SOCKET_ERROR)
AfxThrowWSocketException();
return !(nStatus == 0);
}
BOOL CWSocket::IsWritable(DWORD dwTimeout)
{
ASSERT(IsCreated()); //must have been created first
timeval timeout;
timeout.tv_sec = dwTimeout/1000;
timeout.tv_usec = (dwTimeout%1000)*1000;
fd_set fds;
FD_ZERO(&fds);
FD_SET(m_hSocket, &fds);
int nStatus = select(0, NULL, &fds, NULL, &timeout);
if (nStatus == SOCKET_ERROR)
AfxThrowWSocketException();
return !(nStatus == 0);
}
BOOL CWSocket::IsCreated() const
{
return (m_hSocket != INVALID_SOCKET);
}
CWSocket::operator SOCKET()
{
return m_hSocket;
}
void CWSocket::ConnectViaHTTPProxy(LPCTSTR lpszHostAddress, UINT nHostPort, LPCTSTR lpszHTTPProxy, UINT nHTTPProxyPort, CString& sProxyResponse, LPCTSTR lpszUserName, LPCTSTR lpszPassword, DWORD dwConnectionTimeout, LPCTSTR lpszUserAgent)
{
USES_CONVERSION;
ASSERT(IsCreated()); //must have been created first
//connect to the proxy
Connect(lpszHTTPProxy, nHTTPProxyPort);
try
{
//Form the HTTP CONNECT request header
CString sLine;
sLine.Format(_T("CONNECT %s:%d HTTP/1.0\r\n"), lpszHostAddress, nHostPort);
CString sRequest(sLine);
//Form the authorization line if required
if (lpszUserName != NULL)
{
//Base64 encode the username password combination
CBase64 base64;
CString sUserNamePassword;
sUserNamePassword.Format(_T("%s:%s"), lpszUserName, lpszPassword);
char* pszUserNamePassword = T2A((LPTSTR) (LPCTSTR) sUserNamePassword);
int nUserNamePasswordLength = (int) strlen(pszUserNamePassword);
int nEncodedLength = base64.EncodeGetRequiredLength(nUserNamePasswordLength);
LPSTR pszEncoded = (LPSTR) _alloca(nEncodedLength + 1);
base64.Encode((const BYTE*) pszUserNamePassword, nUserNamePasswordLength, pszEncoded, &nEncodedLength);
pszEncoded[nEncodedLength] = '\0';
//Form the Authorization header line and add it to the request
sLine.Format(_T("Proxy-authorization: Basic %s\r\n"), A2T(pszEncoded));
sRequest += sLine;
}
//Form the user agent line if required
if (lpszUserAgent != NULL)
{
//Add the User Agent line to the request
sLine.Format(_T("User-Agent: %s\r\n"), lpszUserAgent);
sRequest += sLine;
}
//Add the final line feed to the request
sRequest += _T("\r\n");
//Finally send the request to the HTTP proxy
LPSTR pszRequest = T2A((LPTSTR) (LPCTSTR) sRequest);
Send(pszRequest, (int) strlen(pszRequest));
//Read the proxy response
ReadHTTPProxyResponse(dwConnectionTimeout, sProxyResponse);
//Next make sure that we got a HTTP code of 200 to indicate success
int nFirstSpace = sProxyResponse.Find(_T(" "));
if (nFirstSpace != -1)
{
CString sResponseCode = sProxyResponse.Right(sProxyResponse.GetLength() - nFirstSpace - 1);
int nResponseCode = _ttoi(sResponseCode);
if (nResponseCode != 200)
AfxThrowWSocketException(ERROR_CONNECTION_REFUSED);
}
}
catch(CWSocketException* pEx)
{
//Close the socket before we rethrow the exception
int nError = pEx->m_nError;
pEx->Delete();
Close();
AfxThrowWSocketException(nError);
}
}
void CWSocket::ReadHTTPProxyResponse(DWORD dwTimeout, CString& sResponse)
{
USES_CONVERSION;
ASSERT(IsCreated()); //must have been created first
//The local variables which will receive the data
DWORD dwGrowBy = 4096;
BYTE* pRawRequest = new BYTE[dwGrowBy];
DWORD dwBufSize = dwGrowBy;
DWORD dwRawRequestSize = 0;
//retrieve the reponse
BOOL bMoreDataToRead = TRUE;
while (bMoreDataToRead)
{
//check the socket for readability
if (!IsReadible(dwTimeout))
{
//Null terminate the data
pRawRequest[dwRawRequestSize] = '\0';
TRACE(_T("CWSocket::ReadHTTPProxyResponse, Timed out waiting for response from socket\n"));
AfxThrowWSocketException(WSAETIMEDOUT);
}
//receive the data from the socket
dwRawRequestSize += Receive(pRawRequest + dwRawRequestSize, 1);
//NULL terminate the data received
pRawRequest[dwRawRequestSize] = '\0';
//Check to see if the terminator character(s) have been found
if (dwRawRequestSize >= 4)
{
bMoreDataToRead = !((pRawRequest[dwRawRequestSize-4] == '\r') && (pRawRequest[dwRawRequestSize-3] == '\n') &&
(pRawRequest[dwRawRequestSize-2] == '\r') && (pRawRequest[dwRawRequestSize-1] == '\n'));
}
if (dwRawRequestSize >= dwBufSize) //No space left in the current buffer
{
//Allocate the new receive buffer
dwBufSize += dwGrowBy; //Grow the buffer by the specified amount
LPBYTE pNewBuf = new BYTE[dwBufSize];
//copy the old contents over to the new buffer and assign
//the new buffer to the local variable used for retreiving
//from the socket
CopyMemory(pNewBuf, pRawRequest, dwRawRequestSize);
delete [] pRawRequest;
pRawRequest = pNewBuf;
}
}
//Form the CString out parameter
sResponse = A2T((char*) pRawRequest);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -