Skip to content

Commit

Permalink
fix: Ws2_32_LoopRecv: handle recv() == 0; handle conf and hosts with BOM
Browse files Browse the repository at this point in the history
  • Loading branch information
shunf4 committed Apr 27, 2020
1 parent 9edc0d5 commit 4f0a1be
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 14 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,13 +140,18 @@ See [DevNotes](DEVNOTES.md).

# To-do and Known Issues

- [ ] Correctly handle conf and hosts that start with BOM
- [ ] Add an option to totally prevent "DNS leak" ? (Do name lookup on
SOCKS5 server only)
- [ ] Properly handle "fork-and-exit" child process ? (In this case the
descendant processes' dns queries would never succeed)
- [ ] Remote DNS resolving based on UDP associate
- [ ] Hook `sendto()`, coping with applications which do TCP fast open
- [x] Connection closure should be correctly handled in
`Ws2_32_LoopRecv` and `Ws2_32_LoopSend` (fixed in 0.6.5)
- [x] A large part of socks5 server name possibly lost when parsing
configuration (fixed in 0.6.5)
- [x] Correctly handle conf and hosts that start with BOM (fixed in
0.6.5)
- [X] Detect .NET CLR programs that is AnyCPU&prefers 32-bit/targeted x86
/targeted x64. (These are "shimatta" programs, which must be
injected by `CreateRemoteThread()`) (fixed in 0.6.2)
Expand Down
2 changes: 1 addition & 1 deletion include/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@
#define PXCH_VERSION_MINOR 6
#endif
#ifndef PXCH_VERSION_PATCH
#define PXCH_VERSION_PATCH 4
#define PXCH_VERSION_PATCH 5
#endif
10 changes: 10 additions & 0 deletions src/dll/hook_connect_win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ int Ws2_32_LoopSend(void* pTempData, PXCH_UINT_PTR s, const char* SendBuf, int i

iReturn = send(s, pSendBuf, iRemaining, 0);
if (iReturn == SOCKET_ERROR) goto err_send;
if (iReturn == 0) goto err_send_zerobytes;
if (iReturn < iLength) {
FUNCIPCLOGD(L"send() only sent %d/%d bytes", iReturn, iLength);
}
Expand All @@ -462,6 +463,10 @@ int Ws2_32_LoopSend(void* pTempData, PXCH_UINT_PTR s, const char* SendBuf, int i
WSASetLastError(NO_ERROR);
return 0;

err_send_zerobytes:
FUNCIPCLOGW(L"send() sends zero bytes!");
goto err_return;

err_send_unexpected:
FUNCIPCLOGW(L"send() occurs unexpected error!");
goto err_return;
Expand Down Expand Up @@ -513,6 +518,7 @@ int Ws2_32_LoopRecv(void* pTempData, PXCH_UINT_PTR s, char* RecvBuf, int iLength

iReturn = recv(s, pRecvBuf, iRemaining, 0);
if (iReturn == SOCKET_ERROR) goto err_recv;
if (iReturn == 0) goto err_recv_closed;
if (iReturn < iLength) {
FUNCIPCLOGD(L"recv() only received %d/%d bytes", iReturn, iLength);
}
Expand All @@ -529,6 +535,10 @@ int Ws2_32_LoopRecv(void* pTempData, PXCH_UINT_PTR s, char* RecvBuf, int iLength
WSASetLastError(NO_ERROR);
return 0;

err_recv_closed:
FUNCIPCLOGW(L"recv() receives zero bytes, connection closed!");
goto err_return;

err_recv_unexpected:
FUNCIPCLOGW(L"recv() occurs unexpected error!");
goto err_return;
Expand Down
21 changes: 11 additions & 10 deletions src/exe/args_and_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ static int OptionGetIpPortValue(PXCH_IP_PORT* pIpPort, PXCH_UINT32* pdwPrefixLen
WCHAR* pStartPrefix;
WCHAR* pAfterPrefix;
WCHAR cSaved;
int iResult;

pAfterIpPort = ConsumeStringInSet(pStart, pEndOptional, PXCH_CONFIG_PARSE_IP_PORT);

Expand All @@ -242,14 +243,14 @@ static int OptionGetIpPortValue(PXCH_IP_PORT* pIpPort, PXCH_UINT32* pdwPrefixLen

cSaved = *pAfterIpPort;
*pAfterIpPort = L'\0';

ZeroMemory(pIpPort, sizeof(PXCH_IP_PORT));
if (StringToAddress(pStart, (LPSOCKADDR)pIpPort, sizeof(PXCH_IP_PORT))) {
iResult = StringToAddress(pStart, (LPSOCKADDR)pIpPort, sizeof(PXCH_IP_PORT));
*pAfterIpPort = cSaved;
if (iResult) {
pszParseErrorMessage = L"Invalid IP address";
return -1;
}

*pAfterIpPort = cSaved;
if (*pAfterIpPort == L'/') {
PXCH_IP_PORT PrefixIpPort;
long lPrefix = -1;
Expand All @@ -271,12 +272,13 @@ static int OptionGetIpPortValue(PXCH_IP_PORT* pIpPort, PXCH_UINT32* pdwPrefixLen
return -1;
}

cSaved = *pAfterPrefix;
*pAfterPrefix = L'\0';

ZeroMemory(&PrefixIpPort, sizeof(PXCH_IP_PORT));
if (OptionGetNumberValue(&lPrefix, pStartPrefix, pAfterPrefix, 0, 128, FALSE)) {
if (StringToAddress(pStartPrefix, (LPSOCKADDR)&PrefixIpPort, sizeof(PXCH_IP_PORT))) {
cSaved = *pAfterPrefix;
*pAfterPrefix = L'\0';
ZeroMemory(&PrefixIpPort, sizeof(PXCH_IP_PORT));
iResult = StringToAddress(pStartPrefix, (LPSOCKADDR)&PrefixIpPort, sizeof(PXCH_IP_PORT));
*pAfterPrefix = cSaved;
if (iResult) {
pszParseErrorMessage = L"Invalid CIDR prefix";
return -1;
} else {
Expand Down Expand Up @@ -310,13 +312,12 @@ static int OptionGetIpPortValue(PXCH_IP_PORT* pIpPort, PXCH_UINT32* pdwPrefixLen
}
}
} else {
if (PrefixIpPort.CommonHeader.wTag == PXCH_HOST_TYPE_IPV4 && lPrefix > 32) {
if (pIpPort->CommonHeader.wTag == PXCH_HOST_TYPE_IPV4 && lPrefix > 32) {
pszParseErrorMessage = L"Prefix length exceeds 32 for an IPv4 address";
return -1;
}
}

*pAfterPrefix = cSaved;
*pdwPrefixLength = (PXCH_UINT32)lPrefix;
} else {
pAfterPrefix = pAfterIpPort;
Expand Down
31 changes: 29 additions & 2 deletions src/stdlib_config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ PXCH_UINT32 OpenConfigurationFile(PROXYCHAINS_CONFIG* pPxchConfig)
int i;
int iReturn;
DWORD dwLastError;
wint_t chFirst;

CloseConfigurationFile();

Expand Down Expand Up @@ -110,13 +111,18 @@ PXCH_UINT32 OpenConfigurationFile(PROXYCHAINS_CONFIG* pPxchConfig)

validate_config_path:
for (i = 0; i < _countof(szConfigPathOptions) && szConfigPathOptions[i]; i++) {
if ((fPxchConfig = fopen(szConfigPathOptions[i], "r")) != NULL) {
if ((fPxchConfig = fopen(szConfigPathOptions[i], "r,ccs=UTF-8")) != NULL) {
break;
}
}

if (!fPxchConfig) goto err_not_found;

chFirst = fgetwc(fPxchConfig);
if (chFirst != WEOF && chFirst != 0xFEFF /* Unicode/UTF-16 BOM */) {
ungetwc(chFirst, fPxchConfig);
}

StringCchPrintfW(pPxchConfig->szConfigPath, _countof(pPxchConfig->szConfigPath), L"%S", szConfigPathOptions[i]);
LOGI(L"Configuration file: %ls", pPxchConfig->szConfigPath);
ullConfigurationLineNum = 0;
Expand All @@ -139,12 +145,18 @@ PXCH_UINT32 OpenConfigurationFile(PROXYCHAINS_CONFIG* pPxchConfig)
PXCH_UINT32 OpenHostsFile(const WCHAR* szHostsFilePath)
{
char szHostsFilePathNarrow[MAX_PATH * 2];
wint_t chFirst;

if (FAILED(StringCchPrintfA(szHostsFilePathNarrow, _countof(szHostsFilePathNarrow), "%ls", szHostsFilePath))) goto err_bufovf;

CloseHostsFile();

if ((fHosts = fopen(szHostsFilePathNarrow, "r")) == NULL) goto err_not_found;
// ccs=UTF-8 seems only work under Windows. Under cygwin, everything is assumed to be UTF-8
if ((fHosts = fopen(szHostsFilePathNarrow, "r,ccs=UTF-8")) == NULL) goto err_not_found;
chFirst = fgetwc(fHosts);
if (chFirst != WEOF && chFirst != 0xFEFF /* Unicode/UTF-16 BOM */) {
ungetwc(chFirst, fHosts);
}
return NO_ERROR;

err_not_found:
Expand Down Expand Up @@ -203,6 +215,7 @@ PXCH_UINT32 HostsFileReadLine(unsigned long long* pullHostsLineNum, wchar_t* chB

ullHostsLineNum++;
*pullHostsLineNum = ullHostsLineNum;

pBuf = fgetws(chBuf, (int)cbBufSize, fHosts);

if (pBuf == NULL) {
Expand Down Expand Up @@ -254,7 +267,14 @@ long ConfigurationTellPos()

void ConfigurationRewind()
{
wint_t chFirst;

rewind(fPxchConfig);

chFirst = fgetwc(fPxchConfig);
if (chFirst != WEOF && chFirst != 0xFEFF /* Unicode/UTF-16 BOM */) {
ungetwc(chFirst, fPxchConfig);
}
ullConfigurationLineNum = 0;
}

Expand All @@ -265,6 +285,13 @@ long HostsTellPos()

void HostsRewind()
{
wint_t chFirst;

rewind(fHosts);

chFirst = fgetwc(fHosts);
if (chFirst != WEOF && chFirst != 0xFEFF /* Unicode/UTF-16 BOM */) {
ungetwc(chFirst, fHosts);
}
ullHostsLineNum = 0;
}

0 comments on commit 4f0a1be

Please sign in to comment.