diff --git a/README.md b/README.md index 4547e5d..0feec92 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/include/version.h b/include/version.h index 15d30f8..af7ef7a 100644 --- a/include/version.h +++ b/include/version.h @@ -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 \ No newline at end of file diff --git a/src/dll/hook_connect_win32.c b/src/dll/hook_connect_win32.c index 8f97f2e..f054f48 100644 --- a/src/dll/hook_connect_win32.c +++ b/src/dll/hook_connect_win32.c @@ -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); } @@ -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; @@ -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); } @@ -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; diff --git a/src/exe/args_and_config.c b/src/exe/args_and_config.c index 4e81f74..2afdbac 100644 --- a/src/exe/args_and_config.c +++ b/src/exe/args_and_config.c @@ -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); @@ -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; @@ -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 { @@ -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; diff --git a/src/stdlib_config_reader.c b/src/stdlib_config_reader.c index d6915c7..b0a8869 100644 --- a/src/stdlib_config_reader.c +++ b/src/stdlib_config_reader.c @@ -58,6 +58,7 @@ PXCH_UINT32 OpenConfigurationFile(PROXYCHAINS_CONFIG* pPxchConfig) int i; int iReturn; DWORD dwLastError; + wint_t chFirst; CloseConfigurationFile(); @@ -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; @@ -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: @@ -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) { @@ -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; } @@ -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; } \ No newline at end of file