├── .gitignore ├── DNS2SOCKS.c ├── DNS2SOCKS.manifest ├── DNS2SOCKS.rc ├── DNS2SOCKS.vcxproj ├── DNS2SOCKS.vcxproj.filters ├── stdafx.c └── stdafx.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | -------------------------------------------------------------------------------- /DNS2SOCKS.c: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | //helpful URLs: 4 | // http://www.networksorcery.com/enp/protocol/dns.htm 5 | // http://www.freesoft.org/CIE/RFC/1035/43.htm 6 | // https://tools.ietf.org/html/rfc2671 7 | // https://tools.ietf.org/html/rfc3225 8 | // https://tools.ietf.org/html/rfc7871 9 | 10 | //application name and version 11 | #define APP_NAME "DNS2SOCKS V2.1" 12 | //first output line in console 13 | #define APP_STRING "\n" APP_NAME " (free software, use parameter /? to display help)\n" 14 | //log file header line 15 | #define LOG_HEADER APP_NAME " log opened" 16 | //date/time format string for ISO 8601 format, but leave away the T delimiter as it's bad to read 17 | #define DATE_TIME_FORMAT "%u-%02u-%02u %02u:%02u:%02u " 18 | //127.0.0.1 for default SOCKS5 server 19 | #define DEFAULT_SOCKS_SERVER "127.0.0.1" 20 | //9050 for default SOCKS5 port 21 | #define DEFAULT_SOCKS_PORT "9050" 22 | //46.182.19.48 for default DNS server supporting TCP (Digitalcourage e.V.) 23 | #define DEFAULT_DNS_SERVER "46.182.19.48" 24 | //127.0.0.1 for local IP address for listening 25 | #define DEFAULT_LISTEN_IP "127.0.0.1" 26 | //53 for default DNS port 27 | #define DEFAULT_DNS_PORT "53" 28 | 29 | //defines for OutputToLog (bits) 30 | #define OUTPUT_LINE_BREAK (1) 31 | #define OUTPUT_DATE_TIME (2) 32 | #define OUTPUT_CONSOLE (4) 33 | #define OUTPUT_ALL (OUTPUT_LINE_BREAK|OUTPUT_DATE_TIME|OUTPUT_CONSOLE) 34 | 35 | //on some systems a failing send command raises a signal; we want to disable that by passing MSG_NOSIGNAL 36 | //some systems (Windows) don't define that -> define it to 0 37 | #ifndef MSG_NOSIGNAL 38 | #define MSG_NOSIGNAL (0) 39 | #endif 40 | 41 | 42 | union UClient 43 | { 44 | struct sockaddr_storage sAddr; //address of requesting client for UDP 45 | SOCKET hSock; //socket handle for TCP 46 | }; 47 | 48 | //entry for DNS request and answer (cache entry) 49 | struct SEntry 50 | { 51 | struct SEntry* psNext; //next list entry or NULL 52 | uint16_t* u16aAnswer; //pointer to answer or NULL 53 | time_t iTime; //time when the answer was deliviered last time 54 | union UClient client; //information on how to send response back to client 55 | unsigned char uAddrLen; //length of used part of sAddr for UDP, sizeof(SOCKET) for TCP 56 | uint16_t u16aRequest[1]; //extended dynamically at malloc for "struct SEntry" (use "uint16_t" to ensure according alignment, first element contains length in big endian format) 57 | }; 58 | 59 | static struct SEntry* g_psFirst=NULL; //list of DNS requests and answers (cache) 60 | static unsigned int g_uCacheCount=0; //amout of entries in list g_psFirst 61 | static int g_bCacheEnabled=1; //!=0 when cache is enabled 62 | static struct sockaddr_storage g_sDnsSrvAddr; //DNS server supporting TCP 63 | static struct sockaddr_storage g_sSocksAddr; //SOCKS5 server 64 | static CRITICAL_SECTION g_sCritSect; //to protect the list g_psFirst and g_uCacheCount 65 | static SOCKET g_hSockUdp; //UDP socket 66 | static unsigned char* g_uaUsrPwd=NULL; //authentication package for SOCKS 67 | static int g_iUsrPwdLen; //length of g_caUsrPwd 68 | static int g_iHttpProxyConnectLen=0; //length of CONNECT command in g_caHttpProxyConnect 69 | static char g_caHttpProxyConnect[300]; //CONNECT command in case of using HTTP proxy 70 | static uint8_t g_u8aEcsOption[8+16]; //EDNS Client Subnet EDNS0 option (maximum necessary bytes reserved, actual amount in g_iEcsOptionLen) 71 | static int g_iEcsOptionLen=0; //actual amount bytes used of g_u8aEcsOption 72 | static int g_bForceEcs=0; //!=0 to replace existing EDNS Client Subnet option by our one 73 | 74 | //OS specific functionality 75 | #ifdef _WIN32 76 | 77 | //for Windows we can create an own console window, so here we use some OS specific functions; 78 | //also for the file access we use the WIN32 API - we could use the C API as we do for the other OSes 79 | //but as we need to take special care about the line break (\r\n) anyway and WIN32 should be a little 80 | //bit faster, we use WIN32 81 | 82 | static HANDLE g_hConsole=NULL; //handle for console output 83 | static HANDLE g_hLogFile=INVALID_HANDLE_VALUE; //handle for log file 84 | 85 | //passes a string and its length to a function 86 | #define STRING_AND_LEN(szString) szString, sizeof(szString)-1 87 | 88 | static char* GetSysError(int iErrNo) 89 | { 90 | char* szBuffer; 91 | size_t uLen; 92 | 93 | if(!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, iErrNo, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&szBuffer, 0, NULL)) 94 | { 95 | szBuffer=(char*)LocalAlloc(LMEM_FIXED, 14); 96 | memcpy(szBuffer, "Unknown error", 14); 97 | } 98 | else 99 | { 100 | //remove line breaks at the end 101 | uLen=strlen(szBuffer); 102 | while(uLen>0 && (szBuffer[uLen-1]=='\n' || szBuffer[uLen-1]=='\r')) 103 | szBuffer[--uLen]='\0'; 104 | } 105 | return szBuffer; 106 | } 107 | 108 | static void FreeSysError(char* szString) 109 | { 110 | LocalFree(szString); 111 | } 112 | 113 | static void OutputToLog(unsigned int uOutputSettingBits, const char* szFormatString, ...) 114 | { 115 | va_list pArgs; 116 | int iLenPrefix; 117 | int iLen; 118 | DWORD uDummy; 119 | char szBuf[1024]; 120 | 121 | //nothing to do? 122 | if((!g_hConsole || !(uOutputSettingBits&OUTPUT_CONSOLE)) && g_hLogFile==INVALID_HANDLE_VALUE) 123 | return; 124 | //add line break? 125 | if(uOutputSettingBits&OUTPUT_LINE_BREAK) 126 | { 127 | szBuf[0]='\r'; 128 | szBuf[1]='\n'; 129 | iLenPrefix=2; 130 | } 131 | else 132 | iLenPrefix=0; 133 | if(uOutputSettingBits&OUTPUT_DATE_TIME) 134 | { 135 | SYSTEMTIME sTime; 136 | 137 | //add date/time string 138 | GetLocalTime(&sTime); 139 | iLen=_snprintf_s(szBuf+iLenPrefix, ARRAYSIZE(szBuf)-iLenPrefix, _TRUNCATE, DATE_TIME_FORMAT, sTime.wYear, sTime.wMonth, sTime.wDay, sTime.wHour, sTime.wMinute, sTime.wSecond); 140 | if(iLen<0) //error? 141 | return; 142 | iLenPrefix+=iLen; 143 | } 144 | //add log string 145 | va_start(pArgs, szFormatString); 146 | iLen=_vsnprintf_s(szBuf+iLenPrefix, ARRAYSIZE(szBuf)-iLenPrefix, _TRUNCATE, szFormatString, pArgs); 147 | if(iLen<0) //error? 148 | return; 149 | iLen+=iLenPrefix; 150 | //output 151 | if(g_hConsole && (uOutputSettingBits&OUTPUT_CONSOLE)) 152 | { 153 | wchar_t wcBuf[1024]; 154 | 155 | //convert to wide char to avoid trouble with special characters 156 | iLen=MultiByteToWideChar(CP_ACP, 0, szBuf, iLen, wcBuf, ARRAYSIZE(wcBuf)); 157 | if(iLen) 158 | WriteConsoleW(g_hConsole, wcBuf, iLen, &uDummy, NULL); 159 | } 160 | if(g_hLogFile) 161 | WriteFile(g_hLogFile, szBuf, iLen, &uDummy, NULL); 162 | } 163 | 164 | static void OpenLogFile(const char* szFilePath, int bAppend) 165 | { 166 | g_hLogFile=CreateFile(szFilePath, GENERIC_WRITE, FILE_SHARE_READ, NULL, bAppend?OPEN_ALWAYS:CREATE_ALWAYS, 0, NULL); 167 | if(g_hLogFile==INVALID_HANDLE_VALUE) 168 | { 169 | char* szErrMsg=GetSysError(GetLastError()); 170 | 171 | OutputToLog(OUTPUT_ALL, "Failed to open log file \"%s\": %s", szFilePath, szErrMsg); 172 | FreeSysError(szErrMsg); 173 | } 174 | else 175 | { 176 | //append and no new file was created? 177 | if(bAppend && GetLastError()==ERROR_ALREADY_EXISTS) 178 | { 179 | DWORD uDummy; 180 | 181 | //go to end of file for appending 182 | SetFilePointer(g_hLogFile, 0, NULL, FILE_END); 183 | //add line breaks for appending 184 | WriteFile(g_hLogFile, STRING_AND_LEN("\r\n\r\n"), &uDummy, NULL); 185 | } 186 | //output header string in log 187 | OutputToLog(OUTPUT_DATE_TIME, LOG_HEADER); 188 | } 189 | } 190 | 191 | static void OpenConsole() 192 | { 193 | if(g_hConsole) //already openend? 194 | return; 195 | AllocConsole(); 196 | g_hConsole=GetStdHandle(STD_OUTPUT_HANDLE); 197 | if(g_hConsole) 198 | { 199 | DWORD uDummy; 200 | 201 | WriteConsole(g_hConsole, STRING_AND_LEN(APP_STRING), &uDummy, NULL); 202 | } 203 | } 204 | 205 | static void OutputFatal(const char* szFormatString, ...) 206 | { 207 | HANDLE hReadConsole; 208 | va_list pArgs; 209 | int iLen; 210 | DWORD uDummy; 211 | INPUT_RECORD sRecord; 212 | char szBuf[4096]; 213 | 214 | OpenConsole(); 215 | if(!g_hConsole) //console available? 216 | return; 217 | va_start(pArgs, szFormatString); 218 | iLen=_vsnprintf_s(szBuf, ARRAYSIZE(szBuf), _TRUNCATE, szFormatString, pArgs); 219 | if(iLen<0) //error? 220 | return; 221 | //output 222 | WriteConsole(g_hConsole, szBuf, iLen, &uDummy, NULL); 223 | WriteConsole(g_hConsole, STRING_AND_LEN("\nPress any key to close the application..."), &uDummy, NULL); 224 | hReadConsole=GetStdHandle(STD_INPUT_HANDLE); 225 | //wait for key 226 | while(ReadConsoleInput(hReadConsole, &sRecord, 1, &uDummy) && (sRecord.EventType!=KEY_EVENT || !sRecord.Event.KeyEvent.bKeyDown)) 227 | ; 228 | } 229 | 230 | //thread handling for Windows 231 | #define THREAD_FUNCTION(threadFunction, pParam) static DWORD __stdcall threadFunction(LPVOID pParam) 232 | 233 | int ThreadCreate(LPTHREAD_START_ROUTINE pThreadFunction, void* pParam) 234 | { 235 | DWORD uId; 236 | HANDLE hThread=CreateThread(NULL, 0, pThreadFunction, pParam, 0, &uId); 237 | 238 | if(!hThread) 239 | { 240 | char* szErrMsg=GetSysError(GetLastError()); 241 | 242 | OutputToLog(OUTPUT_ALL, "Creating new thread has failed: %s", szErrMsg); 243 | FreeSysError(szErrMsg); 244 | return 0; //error 245 | } 246 | CloseHandle(hThread); 247 | return 1; //o.k. 248 | } 249 | 250 | #else //#ifdef _WIN32 251 | 252 | //on other OS create no own console window 253 | static int g_bConsole=0; //console output enabled? 254 | static FILE* g_pLogFile=NULL; //log file pointer 255 | 256 | #define GetSysError(iErrNo) strerror(iErrNo) 257 | #define FreeSysError(szString) //nothing to do 258 | 259 | static void OutputToLog(unsigned int uOutputSettingBits, const char* szFormatString, ...) 260 | { 261 | va_list pArgs; 262 | int iLenPrefix; 263 | int iLen; 264 | char szBuf[4096]; 265 | 266 | //nothing to do? 267 | if((!g_bConsole || !(uOutputSettingBits&OUTPUT_CONSOLE)) && !g_pLogFile) 268 | return; 269 | //add line break? 270 | if(uOutputSettingBits&OUTPUT_LINE_BREAK) 271 | { 272 | szBuf[0]='\n'; 273 | iLenPrefix=1; 274 | } 275 | else 276 | iLenPrefix=0; 277 | if(uOutputSettingBits&OUTPUT_DATE_TIME) 278 | { 279 | //add date/time string 280 | time_t iTime; 281 | struct tm* psTime; 282 | 283 | if(time(&iTime)==(time_t)-1) 284 | return; //error 285 | psTime=localtime(&iTime); 286 | if(!psTime) //error? 287 | return; 288 | iLen=snprintf(szBuf+iLenPrefix, sizeof(szBuf)-iLenPrefix, DATE_TIME_FORMAT, psTime->tm_year+1900, psTime->tm_mon+1, psTime->tm_mday, psTime->tm_hour, psTime->tm_min, psTime->tm_sec); 289 | if(iLen<0) //error? 290 | return; 291 | iLenPrefix+=iLen; 292 | } 293 | //add log string 294 | va_start(pArgs, szFormatString); 295 | iLen=vsnprintf(szBuf+iLenPrefix, sizeof(szBuf)-iLenPrefix, szFormatString, pArgs); 296 | va_end(pArgs); 297 | if(iLen<0) //error? 298 | return; 299 | iLen+=iLenPrefix; 300 | if(iLen>=sizeof(szBuf)) //truncated? -> make sure to add \0 301 | { 302 | szBuf[sizeof(szBuf)-1]='\0'; 303 | iLen=sizeof(szBuf)-1; 304 | } 305 | //output 306 | if(g_bConsole && (uOutputSettingBits&OUTPUT_CONSOLE)) 307 | fputs(szBuf, stdout); 308 | if(g_pLogFile) 309 | fwrite(szBuf, 1, iLen, g_pLogFile); 310 | } 311 | 312 | static void OpenLogFile(const char* szFilePath, int bAppend) 313 | { 314 | g_pLogFile=fopen(szFilePath, bAppend?"ab":"wb"); 315 | if(!g_pLogFile) 316 | OutputToLog(OUTPUT_ALL, "Failed to open log file \"%s\": %s", szFilePath, strerror(errno)); 317 | else 318 | { 319 | //append and file is not empty? 320 | if(bAppend && ftell(g_pLogFile)) 321 | { 322 | //add line breaks for appending 323 | fputs("\n\n", g_pLogFile); 324 | } 325 | setbuf(g_pLogFile, NULL); //disable buffering (no newline needed for actual output) 326 | //output header string in log 327 | OutputToLog(OUTPUT_DATE_TIME, LOG_HEADER); 328 | } 329 | } 330 | 331 | static void OpenConsole() 332 | { 333 | if(g_bConsole) //already openend? 334 | return; 335 | g_bConsole=1; 336 | setbuf(stdout, NULL); //disable buffering (no newline needed for actual output) 337 | printf(APP_STRING); 338 | } 339 | 340 | //for OutputFatal we can just use a macro to prefix the parameters 341 | #define OutputFatal OpenConsole(); printf 342 | 343 | //thread handling via pthread 344 | #define THREAD_FUNCTION(threadFunction, pParam) static void* threadFunction(void* pParam) 345 | 346 | int ThreadCreate(void* (*pThreadFunction)(void*), void* pParam) 347 | { 348 | pthread_t hThread; 349 | int iErrNo=pthread_create(&hThread, NULL, pThreadFunction, pParam); 350 | 351 | if(iErrNo) 352 | { 353 | OutputToLog(OUTPUT_ALL, "Creating new thread has failed: error code %d", iErrNo); 354 | return 0; //error 355 | } 356 | pthread_detach(hThread); 357 | return 1; //o.k. 358 | } 359 | 360 | #endif //#ifdef _WIN32 361 | 362 | 363 | //returns the internal length of a socket address (IPv4 / IPv6) 364 | static unsigned int GetAddrLen(const struct sockaddr_storage* psAddr) 365 | { 366 | if(psAddr->ss_family==AF_INET) 367 | return sizeof(struct sockaddr_in); 368 | return sizeof(struct sockaddr_in6); 369 | } 370 | 371 | //sends UDP answer 372 | static void SendAnswer(struct SEntry* psEntry) 373 | { 374 | //ignore error here 375 | //UDP? 376 | if(psEntry->uAddrLen!=sizeof(SOCKET)) 377 | //+2 because DNS on UDP doesn't include the length 378 | sendto(g_hSockUdp, (char*)(psEntry->u16aAnswer+1), ntohs(*psEntry->u16aAnswer), MSG_NOSIGNAL, (struct sockaddr*)&psEntry->client.sAddr, psEntry->uAddrLen); 379 | else 380 | { 381 | //TCP 382 | send(*(SOCKET*)&psEntry->client.hSock, (char*)psEntry->u16aAnswer, ntohs(*psEntry->u16aAnswer)+2, MSG_NOSIGNAL); 383 | closesocket(psEntry->client.hSock); 384 | } 385 | } 386 | 387 | //searches for an entry in the cache list and removes it - also closes a socket and outputs an error message 388 | static void RemoveEntry(struct SEntry* psEntry, SOCKET hSock, int bUseCriticalSection) 389 | { 390 | struct SEntry** ppsPrev; 391 | struct SEntry* psEntry2; 392 | 393 | //close the socket created by the caller 394 | if(hSock!=SOCKET_ERROR) 395 | closesocket(hSock); 396 | if(bUseCriticalSection) 397 | EnterCriticalSection(&g_sCritSect); 398 | ppsPrev=&g_psFirst; 399 | for(psEntry2=g_psFirst; psEntry2; psEntry2=psEntry2->psNext) 400 | { 401 | //found entry? 402 | if(psEntry==psEntry2) 403 | { 404 | //remove entry from list 405 | *ppsPrev=psEntry->psNext; 406 | --g_uCacheCount; 407 | break; 408 | } 409 | ppsPrev=&psEntry2->psNext; 410 | } 411 | //free the entry 412 | free(psEntry->u16aAnswer); //should be NULL anyway 413 | //close socket in case of TCP 414 | if(psEntry->uAddrLen==sizeof(SOCKET)) 415 | closesocket(psEntry->client.hSock); 416 | free(psEntry); 417 | if(bUseCriticalSection) 418 | LeaveCriticalSection(&g_sCritSect); 419 | } 420 | 421 | //outputs error for TTL check (i32TimeOffset>=0) or searching OPT pseudo-RR (i32TimeOffset<0) 422 | static int InvalidDnsMsgErrorOutput(int32_t i32TimeOffset) 423 | { 424 | if(i32TimeOffset>=0) 425 | OutputToLog(OUTPUT_ALL, "Invalid DNS answer detected while calculating TTL"); 426 | else 427 | OutputToLog(OUTPUT_ALL, "Invalid DNS requested detected while searching OPT pseudo-RR"); 428 | return 0; //error 429 | } 430 | 431 | //iterates through DNS message parts 432 | //either to update/check TTL (i32TimeOffset>=0) or to find OPT pseudo-RR (i32TimeOffset<0) 433 | //returns 0 on error/TTL expiration, 1 on success or offset of OPT pseudo-RR 434 | static int IterateDnsMessage(uint16_t* u16aMessage, int32_t i32TimeOffset) 435 | { 436 | int32_t i32TimeToLive; 437 | uint16_t u16ContentLen; 438 | uint16_t u16AmountQuestions; 439 | uint16_t u16Len; 440 | uint8_t* pu8Pos; 441 | uint8_t* pu8MessageEnd; 442 | uint8_t u8NameLen; 443 | 444 | u16Len=ntohs(*u16aMessage); 445 | if(u16Len<=12) 446 | return InvalidDnsMsgErrorOutput(i32TimeOffset); //answer has no useful information 447 | pu8Pos=(uint8_t*)u16aMessage+2; 448 | pu8MessageEnd=pu8Pos+u16Len; 449 | u16AmountQuestions=ntohs(((uint16_t*)pu8Pos)[2]); 450 | pu8Pos+=12; //go behind header 451 | //ignore questions 452 | for(; u16AmountQuestions; --u16AmountQuestions) 453 | { 454 | //ignore name 455 | for(;;) 456 | { 457 | if(pu8Pos>=pu8MessageEnd) 458 | return InvalidDnsMsgErrorOutput(i32TimeOffset); //failed 459 | u8NameLen=*pu8Pos; 460 | if(!u8NameLen) 461 | break; //end of name 462 | if(u8NameLen>=0xc0) //compression used? (reference to other name via offset) 463 | { 464 | ++pu8Pos; //ignore 2nd part of offset 465 | break; 466 | } 467 | pu8Pos+=u8NameLen+1; 468 | } 469 | pu8Pos+=5; //ignore type and class 470 | } 471 | //for finding OPT pseudo-RR the DNS request might end after the questions 472 | if(i32TimeOffset<0 && pu8Pos==pu8MessageEnd) 473 | return 1; //found no OPT pseudo-RR 474 | //for all records 475 | do 476 | { 477 | //ignore name of resource record 478 | for(;;) 479 | { 480 | if(pu8Pos>=pu8MessageEnd) 481 | return InvalidDnsMsgErrorOutput(i32TimeOffset); //failed 482 | u8NameLen=*pu8Pos; 483 | if(!u8NameLen) 484 | break; //end of name 485 | if(u8NameLen>=0xc0) //compression used? (reference to other name via offset) 486 | { 487 | ++pu8Pos; //ignore 2nd part of offset 488 | break; 489 | } 490 | pu8Pos+=u8NameLen+1; 491 | } 492 | pu8Pos+=5; //jump behind type and class 493 | if(pu8Pos>pu8MessageEnd-6) //6: TTL + RDLEN 494 | return InvalidDnsMsgErrorOutput(i32TimeOffset); //failed 495 | //type is OPT pseudo-RR which has no real TTL value? 496 | if(ntohs(*(uint16_t*)(pu8Pos-4))==41) 497 | { 498 | //searching OPT pseudo-RR? 499 | if(i32TimeOffset<0) 500 | return (int)((pu8Pos+6)-(uint8_t*)u16aMessage); //return offset to data 501 | } 502 | else if(i32TimeOffset>=0) 503 | { 504 | //check time to live field (0 means "omitted") 505 | i32TimeToLive=ntohl(*(uint32_t*)pu8Pos); 506 | if(i32TimeToLive>0) 507 | { 508 | i32TimeToLive-=i32TimeOffset; 509 | if(i32TimeToLive<=0) 510 | return 0; //expired 511 | *(uint32_t*)pu8Pos=htonl(i32TimeToLive); //update field 512 | } 513 | else if(i32TimeToLive<0) 514 | return 0; //failed, TTL must be positive; mark as expired, however: no error output in this case 515 | } 516 | //ignore record content 517 | u16ContentLen=ntohs(*(uint16_t*)(pu8Pos+4)); 518 | pu8Pos+=6+u16ContentLen; 519 | if(pu8Pos>pu8MessageEnd) 520 | return InvalidDnsMsgErrorOutput(i32TimeOffset); //failed 521 | } 522 | while(pu8PosiTime==(time_t)-1) 533 | return 1; //getting time failed last time; without a working timer we ignore time to live stuff completely 534 | //calculate amount of seconds since last delivery 535 | if(time(&iCurTime)==(time_t)-1) 536 | return 1; //error, can't get current time -> ignore time to live stuff completely 537 | i32TimeOffset=(int32_t)(iCurTime-psEntry->iTime); 538 | if(i32TimeOffset<0) 539 | return 0; //time increased; overflow? Mark as expired 540 | psEntry->iTime=iCurTime; //store current time for next delivery 541 | return IterateDnsMessage(psEntry->u16aAnswer, i32TimeOffset); 542 | } 543 | 544 | //receives a specific amount of bytes 545 | static int ReceiveBytes(SOCKET hSock, unsigned int uAmount, uint16_t* u16aBuf) 546 | { 547 | unsigned int uPos=0; 548 | int iLen; 549 | char* szErrMsg; 550 | 551 | for(;;) 552 | { 553 | iLen=recv(hSock, (char*)u16aBuf+uPos, uAmount, 0); 554 | switch(iLen) 555 | { 556 | case SOCKET_ERROR: 557 | szErrMsg=GetSysError(WSAGetLastError()); 558 | OutputToLog(OUTPUT_ALL, "Receiving from SOCKS server has failed: %s", szErrMsg); 559 | FreeSysError(szErrMsg); 560 | return 0; //failed 561 | case 0: 562 | OutputToLog(OUTPUT_ALL, "The SOCKS server has closed the connection unexpectedly"); 563 | return 0; //failed 564 | default: 565 | uAmount-=iLen; 566 | if(!uAmount) 567 | return 1; //succeeded 568 | uPos+=iLen; 569 | } 570 | } 571 | } 572 | 573 | //for sending DNS requests where we add/manipulate the ECS option 574 | //returns 0 on error, -1 to send original message or the new message length otherwise 575 | static int AddEcsOption(uint16_t* u16aRequest, uint16_t* u16aDestBuf) 576 | { 577 | //try to find OPT pseudo-RR 578 | int iOffset=IterateDnsMessage(u16aRequest, -1); 579 | 580 | switch(iOffset) 581 | { 582 | case 0: //error 583 | return 0; 584 | case 1: //no OPT pseudo-RR 585 | { 586 | //add it 587 | uint16_t u16Len=ntohs(*(uint16_t*)u16aRequest); 588 | uint32_t u32NewLen=u16Len+g_iEcsOptionLen+11; 589 | uint8_t* u8aDest; 590 | 591 | //new length exceeds maximum? 592 | if(u32NewLen>65535) 593 | { 594 | OutputToLog(OUTPUT_ALL, "Cannot add EDNS client subnet info to DNS request as it would exceed the maximum size"); 595 | return 0; 596 | } 597 | //create new DNS request; starts with length as we use TCP 598 | *u16aDestBuf=htons((uint16_t)u32NewLen); 599 | memcpy(u16aDestBuf+1, u16aRequest+1, u16Len); //copy original request 600 | u16aDestBuf[6]=htons(ntohs(u16aDestBuf[6])+1); //increase "additional count" 601 | u8aDest=((uint8_t*)(u16aDestBuf+1))+u16Len; //jump after original message 602 | //add OPT pseudo-RR 603 | u8aDest[0]=0; //name -> empty 604 | u8aDest[1]=0; 605 | u8aDest[2]=41; //type -> OPT pseudo-RR 606 | u8aDest[3]=0x10;//max UDP size: 4096 607 | u8aDest[4]=0; 608 | *(uint32_t*)(u8aDest+5)=0; //TTL (here: extended RCODE and flags -> all 0 -> no DNSSEC) 609 | *(uint16_t*)(u8aDest+9)=htons((uint16_t)g_iEcsOptionLen); //option length 610 | memcpy(u8aDest+11, g_u8aEcsOption, g_iEcsOptionLen); //add option 611 | return (int)(u32NewLen+2); //+2 for length field 612 | } 613 | default: //found OPT pseudo-RR 614 | { 615 | //try to find EDNS Client Subnet option 616 | uint8_t* pu8Pos=((uint8_t*)u16aRequest)+iOffset; //offset points to option data 617 | uint16_t u16OptLen=ntohs(((uint16_t*)pu8Pos)[-1]); //length before data 618 | uint8_t* pu8OptionsEnd=pu8Pos+u16OptLen; 619 | uint16_t u16Len=ntohs(*(uint16_t*)u16aRequest); 620 | uint8_t* pu8MessageEnd=((uint8_t*)u16aRequest)+2+u16Len; 621 | uint16_t u16LenIncludingOptionsToCopy; 622 | uint16_t u16CurOptLen; 623 | uint32_t u32NewLen; 624 | 625 | //pu8OptionsEnd beyond end of message? -> error 626 | if(pu8OptionsEnd>pu8MessageEnd) 627 | return InvalidDnsMsgErrorOutput(-1); 628 | for(;; pu8Pos+=u16CurOptLen) 629 | { 630 | if(pu8Pos>=pu8OptionsEnd) 631 | { 632 | //no EDNS Client Subnet option -> add it 633 | break; 634 | } 635 | u16CurOptLen=ntohs(*(uint16_t*)(pu8Pos+2))+4; 636 | if(u16CurOptLen<4 || pu8Pos>pu8OptionsEnd-u16CurOptLen) //overflow or beyond end of message? 637 | return InvalidDnsMsgErrorOutput(-1); //failed 638 | //EDNS Client Subnet option? 639 | if(ntohs(*(uint16_t*)pu8Pos)==8) 640 | { 641 | if(!g_bForceEcs) 642 | return -1; //special return value to send original DNS message as we shall not replace ECS 643 | //replace existing option 644 | //correct parameters for lower message creation 645 | pu8OptionsEnd=pu8Pos+u16CurOptLen; //behind EDNS Client Subnet option 646 | u16OptLen-=u16CurOptLen; 647 | u16Len-=u16CurOptLen; 648 | break; 649 | } 650 | } 651 | u32NewLen=u16Len+g_iEcsOptionLen; 652 | //new length exceeds maximum? 653 | if(u32NewLen>65535) 654 | { 655 | OutputToLog(OUTPUT_ALL, "Cannot add EDNS client subnet info to DNS request as it would exceed the maximum size"); 656 | return 0; 657 | } 658 | *u16aDestBuf=htons((uint16_t)u32NewLen); 659 | u16LenIncludingOptionsToCopy=(uint16_t)(pu8Pos-(uint8_t*)u16aRequest); 660 | memcpy(u16aDestBuf+1, u16aRequest+1, u16LenIncludingOptionsToCopy-2); //copy part of original request without length field 661 | memcpy(((uint8_t*)u16aDestBuf)+u16LenIncludingOptionsToCopy, g_u8aEcsOption, g_iEcsOptionLen); //add ECS option 662 | memcpy(((uint8_t*)u16aDestBuf)+u16LenIncludingOptionsToCopy+g_iEcsOptionLen, pu8OptionsEnd, pu8MessageEnd-pu8OptionsEnd); //copy rest of original message 663 | //correct length of options 664 | *(uint16_t*)(((uint8_t*)u16aDestBuf)+iOffset-2)=htons((uint16_t)(u16OptLen+g_iEcsOptionLen)); 665 | return (int)(u32NewLen+2); //+2 for length field 666 | } 667 | } 668 | } 669 | 670 | //sends CONNECT command to HTTP proxy and checks answer 671 | static int HandleHttpProxy(SOCKET hSock, char* caBuf) 672 | { 673 | char* szErrMsg; 674 | char* szPosEnd; 675 | const char* szPosStatus; 676 | int iRet; 677 | int iPos; 678 | 679 | iRet=send(hSock, g_caHttpProxyConnect, g_iHttpProxyConnectLen, MSG_NOSIGNAL); 680 | if(iRet!=g_iHttpProxyConnectLen) 681 | { 682 | szErrMsg=(iRet==SOCKET_ERROR)?GetSysError(WSAGetLastError()):"Invalid amount of sent bytes"; 683 | OutputToLog(OUTPUT_ALL, "Sending to HTTP proxy has failed: %s", szErrMsg); 684 | if(iRet==SOCKET_ERROR) 685 | FreeSysError(szErrMsg); 686 | return 0; //error 687 | } 688 | //receive answer 689 | iPos=0; 690 | for(;;) 691 | { 692 | iRet=recv(hSock, caBuf+iPos, 2000-iPos, 0); 693 | if(iRet<=0) 694 | { 695 | if(iRet==SOCKET_ERROR) 696 | OutputToLog(OUTPUT_ALL, "The HTTP proxy has closed the connection unexpectedly"); 697 | else 698 | { 699 | szErrMsg=GetSysError(WSAGetLastError()); 700 | OutputToLog(OUTPUT_ALL, "Receiving from HTTP proxy has failed: %s", szErrMsg); 701 | FreeSysError(szErrMsg); 702 | } 703 | return 0; //error 704 | } 705 | iPos+=iRet; 706 | if(iPos<4) 707 | continue; //continue receiving 708 | //check header, must begin with HTTP 709 | if(caBuf[0]=='H' || caBuf[1]=='T' || caBuf[2]=='T' || caBuf[3]=='P') 710 | { 711 | caBuf[iPos]='\0'; //terminate the string 712 | //try to find empty line that marks the end of the HTTP proxy answer 713 | szPosEnd=strstr(caBuf, "\r\n\r\n"); 714 | if(!szPosEnd) 715 | continue; //continue receiving 716 | //extract status code -> scan for space character (also stops on any control character) 717 | szPosStatus=caBuf+4; 718 | while(*(unsigned char*)szPosStatus>' ') 719 | ++szPosStatus; 720 | if(*szPosStatus==' ') 721 | { 722 | //we want: 200 Connection established 723 | if(atoi(++szPosStatus)==200) 724 | break; //header reception complete 725 | //find end of line (must be there, otherwise upper search for empty line would have failed 726 | szPosEnd=strchr(szPosStatus, '\r'); 727 | *szPosEnd='\0'; 728 | OutputToLog(OUTPUT_ALL, "Connecting DNS server has failed: %s", szPosStatus); 729 | return 0; //error 730 | } 731 | } 732 | OutputToLog(OUTPUT_ALL, "Invalid answer from HTTP proxy"); 733 | return 0; //error 734 | } 735 | //so far there shouldn't be an answer from the DNS server (nothing after \r\n\r\n) 736 | if(szPosEnd[4]) 737 | { 738 | OutputToLog(OUTPUT_ALL, "DNS server answered before request"); 739 | return 0; //error 740 | } 741 | return 1; //o.k. 742 | } 743 | 744 | //thread for connecting the SOCKS server and resolving the DNS request 745 | THREAD_FUNCTION(DnsThread, pEntry) 746 | { 747 | uint16_t u16aBuf[32769]; //max DNS packet length 2(length)+65535(data) bytes - using uint16_t here for alignment 748 | struct SEntry* psEntry=(struct SEntry*)pEntry; 749 | char* szErrMsg; 750 | SOCKET hSock=socket(g_sSocksAddr.ss_family, SOCK_STREAM, IPPROTO_TCP); 751 | int iRet; 752 | int iPos; 753 | int iLen; 754 | 755 | if(hSock==SOCKET_ERROR) 756 | { 757 | szErrMsg=GetSysError(WSAGetLastError()); 758 | OutputToLog(OUTPUT_ALL, "Creating a TCP socket has failed: %s", szErrMsg); 759 | FreeSysError(szErrMsg); 760 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 761 | return 0; 762 | } 763 | //connect SOCKS server or HTTP proxy 764 | if(connect(hSock, (struct sockaddr*)&g_sSocksAddr, GetAddrLen(&g_sSocksAddr))==SOCKET_ERROR) 765 | { 766 | szErrMsg=GetSysError(WSAGetLastError()); 767 | OutputToLog(OUTPUT_ALL, "Connecting the SOCKS server has failed: %s", szErrMsg); 768 | FreeSysError(szErrMsg); 769 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 770 | return 0; 771 | } 772 | //using HTTP proxy instead of SOCKS? 773 | if(g_iHttpProxyConnectLen) 774 | { 775 | if(!HandleHttpProxy(hSock, (char*)u16aBuf)) 776 | { 777 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 778 | return 0; 779 | } 780 | } 781 | else 782 | { 783 | ((uint8_t*)u16aBuf)[0]=5; //version 5 as we use SOCKS5 784 | ((uint8_t*)u16aBuf)[1]=1; //number of authentication methods supported 785 | ((uint8_t*)u16aBuf)[2]=g_uaUsrPwd?2:0; //user/password authentication or no authentication 786 | iLen=send(hSock, (const char*)u16aBuf, 3, MSG_NOSIGNAL); 787 | if(iLen!=3) 788 | { 789 | szErrMsg=(iLen==SOCKET_ERROR)?GetSysError(WSAGetLastError()):"Invalid amount of sent bytes"; 790 | OutputToLog(OUTPUT_ALL, "Sending to SOCKS server has failed: %s", szErrMsg); 791 | if(iLen==SOCKET_ERROR) 792 | FreeSysError(szErrMsg); 793 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 794 | return 0; 795 | } 796 | //check respons 797 | if(!ReceiveBytes(hSock, 2, u16aBuf+8)) 798 | { 799 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 800 | return 0; 801 | } 802 | if(((uint8_t*)u16aBuf)[16]!=5 || ((uint8_t*)u16aBuf)[17]!=((uint8_t*)u16aBuf)[2]) 803 | { 804 | if(((uint8_t*)u16aBuf)[16]!=5) 805 | OutputToLog(OUTPUT_ALL, "The SOCKS server has answered with a SOCKS version number unequal to 5"); 806 | else if(g_uaUsrPwd) 807 | OutputToLog(OUTPUT_ALL, "The SOCKS server does not support user/password authentication"); 808 | else 809 | OutputToLog(OUTPUT_ALL, "The SOCKS server wants an authentication"); 810 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 811 | return 0; 812 | } 813 | //send authentication if enabled 814 | if(g_uaUsrPwd) 815 | { 816 | iLen=send(hSock, (const char*)g_uaUsrPwd, g_iUsrPwdLen, MSG_NOSIGNAL); 817 | if(iLen!=g_iUsrPwdLen) 818 | { 819 | szErrMsg=(iLen==SOCKET_ERROR)?GetSysError(WSAGetLastError()):"Invalid amount of sent bytes"; 820 | OutputToLog(OUTPUT_ALL, "Sending to SOCKS server has failed: %s", szErrMsg); 821 | if(iLen==SOCKET_ERROR) 822 | FreeSysError(szErrMsg); 823 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 824 | return 0; 825 | } 826 | //check response 827 | if(!ReceiveBytes(hSock, 2, u16aBuf+8)) 828 | { 829 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 830 | return 0; 831 | } 832 | if(((uint8_t*)u16aBuf)[17]) //2nd byte of answer must be 0 for "success" 833 | { 834 | OutputToLog(OUTPUT_ALL, "The SOCKS server authentication has failed (error code %u)", (unsigned int)((uint8_t*)u16aBuf)[17]); 835 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 836 | return 0; 837 | } 838 | } 839 | //connect DNS server via SOCKS, the DNS server must support TCP 840 | ((uint8_t*)u16aBuf)[1]=1; //establish a TCP/IP stream connection 841 | ((uint8_t*)u16aBuf)[2]=0; //reserved, must be 0x00 842 | switch(g_sDnsSrvAddr.ss_family) 843 | { 844 | case AF_UNSPEC: //use name 845 | ((uint8_t*)u16aBuf)[3]=3; //name 846 | iLen=(int)((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_flowinfo; //length in sin6_flowinfo (see ParseIpAndPort) 847 | ((uint8_t*)u16aBuf)[4]=(uint8_t)iLen; //maximum length is 255 848 | memcpy(((uint8_t*)u16aBuf)+5, *(char**)&((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_addr, iLen); //copy name (see ParseIpAndPort) 849 | *(uint16_t*)(((uint8_t*)u16aBuf)+iLen+5)=((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_port; //port 850 | iPos=iLen+7; 851 | break; 852 | case AF_INET: //use IPv4 853 | ((uint8_t*)u16aBuf)[3]=1; //IPv4 address 854 | *(uint32_t*)(u16aBuf+2)=((struct sockaddr_in*)&g_sDnsSrvAddr)->sin_addr.s_addr; //address 855 | *(uint16_t*)(u16aBuf+4)=((struct sockaddr_in*)&g_sDnsSrvAddr)->sin_port; //port 856 | iPos=10; 857 | break; 858 | default: //use IPv6 859 | ((uint8_t*)u16aBuf)[3]=4; //IPv6 address 860 | memcpy(u16aBuf+2, &((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_addr, 16); //address 861 | *(uint16_t*)(u16aBuf+10)=((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_port; //port 862 | iPos=22; 863 | } 864 | iLen=send(hSock, (const char*)u16aBuf, iPos, MSG_NOSIGNAL); 865 | if(iLen!=iPos) 866 | { 867 | szErrMsg=(iLen==SOCKET_ERROR)?GetSysError(WSAGetLastError()):"Invalid amount of sent bytes"; 868 | OutputToLog(OUTPUT_ALL, "Connecting through SOCKS server has failed: %s", szErrMsg); 869 | if(iLen==SOCKET_ERROR) 870 | FreeSysError(szErrMsg); 871 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 872 | return 0; 873 | } 874 | //check expected answer (get first 5 bytes to detect address type) 875 | if(!ReceiveBytes(hSock, 5, u16aBuf)) 876 | { 877 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 878 | return 0; 879 | } 880 | if(((uint8_t*)u16aBuf)[0]!=5 || ((uint8_t*)u16aBuf)[1]!=0 || (((uint8_t*)u16aBuf)[3]!=1 && ((uint8_t*)u16aBuf)[3]!=3 && ((uint8_t*)u16aBuf)[3]!=4)) 881 | { 882 | szErrMsg="Unexpected answer from SOCKS server"; 883 | //correct version -> try to resolve the error code 884 | if(((uint8_t*)u16aBuf)[0]==5) 885 | switch(((uint8_t*)u16aBuf)[1]) 886 | { 887 | case 2: 888 | szErrMsg="Connection not allowed by ruleset"; 889 | break; 890 | case 3: 891 | szErrMsg="Network unreachable"; 892 | break; 893 | case 4: 894 | szErrMsg="Host unreachable"; 895 | break; 896 | case 5: 897 | szErrMsg="Connection refused by destination host"; 898 | break; 899 | case 6: 900 | szErrMsg="TTL expired"; 901 | break; 902 | case 7: 903 | szErrMsg="Command not supported / protocol error"; 904 | break; 905 | case 8: 906 | szErrMsg="Address type not supported"; 907 | } 908 | OutputToLog(OUTPUT_ALL, "Connecting through SOCKS server has failed: %s", szErrMsg); 909 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 910 | return 0; 911 | } 912 | //get rest of answer 913 | //all bytes after that are part of the "normal" communication 914 | switch(((uint8_t*)u16aBuf)[3]) 915 | { 916 | case 1: //IPv4 917 | iLen=5; 918 | break; 919 | case 4: //IPv6 920 | iLen=17; 921 | break; 922 | default: //name 923 | iLen=2+((uint8_t*)u16aBuf)[4]; //port length plus length of name 924 | } 925 | if(!ReceiveBytes(hSock, iLen, u16aBuf)) 926 | { 927 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 928 | return 0; 929 | } 930 | } 931 | //send DNS request via SOCKS; TCP variant starts with 2 byte length field 932 | //add ECS? 933 | if(g_iEcsOptionLen) 934 | iPos=AddEcsOption(psEntry->u16aRequest, u16aBuf); 935 | else 936 | iPos=-1; //no ECS -> send original message 937 | switch(iPos) 938 | { 939 | case 0: //error 940 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 941 | return 0; 942 | case -1: //send original message 943 | iPos=2+ntohs(*psEntry->u16aRequest); 944 | iLen=send(hSock, (const char*)psEntry->u16aRequest, iPos, MSG_NOSIGNAL); 945 | break; 946 | default: //send message created by AddEcsOption 947 | iLen=send(hSock, (const char*)u16aBuf, iPos, MSG_NOSIGNAL); 948 | } 949 | //error or not sent all bytes? 950 | if(iLen!=iPos) 951 | { 952 | szErrMsg=(iLen==SOCKET_ERROR)?GetSysError(WSAGetLastError()):"Invalid amount of sent bytes"; 953 | OutputToLog(OUTPUT_ALL, "Sending through SOCKS server has failed: %s", szErrMsg); 954 | if(iLen==SOCKET_ERROR) 955 | FreeSysError(szErrMsg); 956 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 957 | return 0; 958 | } 959 | //receive answer 960 | iPos=0; 961 | for(;;) 962 | { 963 | iRet=recv(hSock, (char*)u16aBuf+iPos, sizeof(u16aBuf)-iPos, 0); 964 | if(iRet<=0) 965 | { 966 | szErrMsg=(iRet==SOCKET_ERROR)?GetSysError(WSAGetLastError()):"Server has closed the connection unexpectedly"; 967 | OutputToLog(OUTPUT_ALL, "Broken answer from DNS server: %s", szErrMsg); 968 | if(iRet==SOCKET_ERROR) 969 | FreeSysError(szErrMsg); 970 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 971 | return 0; 972 | } 973 | iPos+=iRet; 974 | //first 2 bytes contain length (Big Endian) 975 | if(iPos>=2) 976 | { 977 | iLen=2+ntohs(*u16aBuf); //iLen maximum is 2+65535 (smaller than sizeof(u16aBuf)) 978 | if(iPos>=iLen) 979 | break; //answer completely received 980 | } 981 | } 982 | //invalid answer? 983 | if(iPos<=4) 984 | { 985 | OutputToLog(OUTPUT_ALL, "Answer from DNS server too short!"); 986 | RemoveEntry(psEntry, hSock, g_bCacheEnabled); 987 | return 0; 988 | } 989 | closesocket(hSock); 990 | if(g_bCacheEnabled) 991 | { 992 | //store answer in cache 993 | EnterCriticalSection(&g_sCritSect); 994 | psEntry->u16aAnswer=(uint16_t*)malloc(iLen); 995 | memcpy(psEntry->u16aAnswer, u16aBuf, iLen); 996 | //copy ID 997 | psEntry->u16aAnswer[1]=psEntry->u16aRequest[1]; 998 | //remember current time for time to live calculations 999 | psEntry->iTime=time(NULL); 1000 | //send DNS answer to original requesting client via UDP or TCP 1001 | SendAnswer(psEntry); 1002 | LeaveCriticalSection(&g_sCritSect); 1003 | } 1004 | else 1005 | { 1006 | //send DNS answer to original requesting client via UDP or TCP 1007 | psEntry->u16aAnswer=u16aBuf; 1008 | SendAnswer(psEntry); 1009 | free(psEntry); 1010 | } 1011 | return 0; 1012 | } 1013 | 1014 | //searches the cache for the same request and sends the answer if there is a cache hit 1015 | //or creates a thread for forwarding the request to the DNS server via SOCKS 1016 | static void HandleDnsRequest(uint16_t* u16aRequest, int iLen, void* pClientAddr, socklen_t iAddrLen) 1017 | { 1018 | uint8_t* pu8Pos; 1019 | uint8_t* pu8End; 1020 | struct SEntry* psEntry; 1021 | unsigned char uLen; 1022 | 1023 | //search in cache 1024 | EnterCriticalSection(&g_sCritSect); 1025 | for(psEntry=g_psFirst; ; psEntry=psEntry->psNext) 1026 | { 1027 | if(!psEntry) 1028 | { 1029 | //create new entry (length of struct SEntry up to u16aRequest plus request length plus 2 for length) 1030 | psEntry=(struct SEntry*)malloc(((uint8_t*)psEntry->u16aRequest-(uint8_t*)psEntry)+iLen+2); 1031 | psEntry->iTime=(time_t)-1; 1032 | psEntry->u16aAnswer=NULL; 1033 | psEntry->uAddrLen=(unsigned char)iAddrLen; 1034 | memcpy(&psEntry->client, pClientAddr, iAddrLen); 1035 | *psEntry->u16aRequest=htons((uint16_t)iLen); 1036 | memcpy(psEntry->u16aRequest+1, u16aRequest, iLen); 1037 | //add entry to cache list in case cache is enabled 1038 | psEntry->psNext=g_psFirst; 1039 | if(g_bCacheEnabled) 1040 | g_psFirst=psEntry; 1041 | //create thread to resolve entry 1042 | if(ThreadCreate(DnsThread, psEntry)) 1043 | { 1044 | ++g_uCacheCount; 1045 | //output amount of entries and current entry 1046 | pu8Pos=(uint8_t*)u16aRequest+12; 1047 | pu8End=(uint8_t*)u16aRequest+iLen; 1048 | while(pu8Pos=0xc0) //compression used? (reference to other name via offset) 1057 | break; //no output in this case 1058 | *pu8Pos='.'; //replace length by . 1059 | pu8Pos+=uLen+1; 1060 | } 1061 | } 1062 | else 1063 | { 1064 | //remove entry from cache list 1065 | g_psFirst=psEntry->psNext; 1066 | free(psEntry); 1067 | } 1068 | break; 1069 | } 1070 | //cache hit? (do not compare ID in first 2 bytes of request) 1071 | if((uint16_t)iLen==ntohs(*psEntry->u16aRequest) && memcmp(u16aRequest+1, psEntry->u16aRequest+2, iLen-2)==0) 1072 | { 1073 | //answer already received? 1074 | if(psEntry->u16aAnswer) 1075 | { 1076 | //answer to current address 1077 | psEntry->uAddrLen=(unsigned char)iAddrLen; 1078 | memcpy(&psEntry->client, pClientAddr, iAddrLen); 1079 | //check if expired 1080 | if(!CalculateTimeToLive(psEntry)) 1081 | { 1082 | //expired -> kill last answer 1083 | free(psEntry->u16aAnswer); 1084 | psEntry->u16aAnswer=NULL; 1085 | //copy current ID 1086 | psEntry->u16aRequest[1]=*u16aRequest; 1087 | //create thread to resolve request again 1088 | if(!ThreadCreate(DnsThread, psEntry)) 1089 | RemoveEntry(psEntry, (SOCKET)SOCKET_ERROR, 0); 1090 | } 1091 | else 1092 | { 1093 | //use current ID 1094 | psEntry->u16aAnswer[1]=*u16aRequest; 1095 | SendAnswer(psEntry); 1096 | } 1097 | } 1098 | else 1099 | { 1100 | //copy current ID so the thread uses that one if it gets the answer 1101 | psEntry->u16aRequest[1]=*u16aRequest; 1102 | //overwrite address; currently we can only handle one request address while waiting for an answer through SOCKS 1103 | //current address is TCP? -> need to close it before overwriting it 1104 | if(psEntry->uAddrLen==sizeof(SOCKET)) 1105 | closesocket(psEntry->client.hSock); 1106 | psEntry->uAddrLen=(unsigned char)iAddrLen; 1107 | memcpy(&psEntry->client, pClientAddr, iAddrLen); 1108 | } 1109 | break; 1110 | } 1111 | } 1112 | LeaveCriticalSection(&g_sCritSect); 1113 | } 1114 | 1115 | //outputs an error caused by "bind" and closes the according socket 1116 | static void OutputBindError(SOCKET hSock, struct sockaddr_storage* psAddr, int bUdp) 1117 | { 1118 | char szAddr[256]; 1119 | char szNo[16]; 1120 | char* szErrMsg=GetSysError(WSAGetLastError()); 1121 | 1122 | closesocket(hSock); 1123 | if(getnameinfo((struct sockaddr*)psAddr, GetAddrLen(psAddr), szAddr, sizeof(szAddr), szNo, sizeof(szNo), NI_NUMERICHOST|NI_NUMERICSERV)) 1124 | { 1125 | //should never happen 1126 | strcpy(szAddr, "unknown address"); 1127 | strcpy(szNo, "unknown"); 1128 | } 1129 | //UDP is mandatory, TCP is optional 1130 | if(bUdp) 1131 | { 1132 | //need { ... } on *nix as OutputFatal is a multi-line macro there 1133 | OutputFatal("\nBinding on %s, UDP port %s has failed: %s\n", szAddr, szNo, szErrMsg); 1134 | } 1135 | else 1136 | OutputToLog(OUTPUT_ALL, "Binding on %s, TCP port %s has failed: %s", szAddr, szNo, szErrMsg); 1137 | FreeSysError(szErrMsg); 1138 | } 1139 | 1140 | //thread for receiving DNS requests via TCP 1141 | THREAD_FUNCTION(TcpThread, pAddr) 1142 | { 1143 | SOCKET hSockServer; 1144 | SOCKET hSock; 1145 | uint16_t u16aBuf[32769]; //maximum possible DNS request size plus one byte - using uint16_t here for alignment; the actual size is stored in the first 2 bytes which can have a maximum value of 0xffff 1146 | socklen_t iAddrLen; 1147 | int iCurBufLen; 1148 | int iLen; 1149 | uint16_t u16ReqLen; 1150 | struct sockaddr_storage sAddr; 1151 | char* szErrMsg; 1152 | 1153 | hSockServer=socket(((struct sockaddr_storage*)pAddr)->ss_family, SOCK_STREAM, IPPROTO_TCP); 1154 | if(hSockServer==SOCKET_ERROR) 1155 | { 1156 | szErrMsg=GetSysError(WSAGetLastError()); 1157 | OutputToLog(OUTPUT_ALL, "Creating a TCP socket has failed: %s", szErrMsg); 1158 | FreeSysError(szErrMsg); 1159 | return 0; 1160 | } 1161 | //bind+listen on local TCP port (get DNS requests) 1162 | if(bind(hSockServer, (struct sockaddr*)pAddr, GetAddrLen((struct sockaddr_storage*)pAddr))==SOCKET_ERROR) 1163 | { 1164 | OutputBindError(hSockServer, (struct sockaddr_storage*)pAddr, 0); 1165 | return 0; 1166 | } 1167 | if(listen(hSockServer, 5)==SOCKET_ERROR) 1168 | { 1169 | szErrMsg=GetSysError(WSAGetLastError()); 1170 | closesocket(hSockServer); 1171 | OutputToLog(OUTPUT_ALL, "Listening on TCP socket has failed: %s", szErrMsg); 1172 | FreeSysError(szErrMsg); 1173 | return 0; 1174 | } 1175 | //as long as "accept" is working 1176 | for(;;) 1177 | { 1178 | iAddrLen=sizeof(sAddr); 1179 | hSock=accept(hSockServer, (struct sockaddr*)&sAddr, &iAddrLen); 1180 | if(hSock==SOCKET_ERROR) 1181 | { 1182 | szErrMsg=GetSysError(WSAGetLastError()); 1183 | OutputToLog(OUTPUT_ALL, "Accepting new connection on TCP socket has failed: %s", szErrMsg); 1184 | FreeSysError(szErrMsg); 1185 | break; 1186 | } 1187 | //collect the whole DNS request 1188 | iCurBufLen=0; 1189 | for(;;) 1190 | { 1191 | iLen=recv(hSock, (char*)u16aBuf+iCurBufLen, sizeof(u16aBuf)-iCurBufLen, 0); 1192 | if(iLen<=0) 1193 | { 1194 | szErrMsg=GetSysError(WSAGetLastError()); 1195 | closesocket(hSock); 1196 | OutputToLog(OUTPUT_ALL, "DNS request on TCP broken: %s", szErrMsg); 1197 | FreeSysError(szErrMsg); 1198 | break; 1199 | } 1200 | iCurBufLen+=iLen; 1201 | //got the whole DNS request? 1202 | if(iCurBufLen>=2 && (u16ReqLen=ntohs(*u16aBuf))+2>=iCurBufLen) 1203 | { 1204 | if(u16ReqLen>12) //12 bytes header plus at least one byte of data 1205 | HandleDnsRequest(u16aBuf+1, u16ReqLen, &hSock, sizeof(hSock)); //HandleDnsRequest takes care of hSock now 1206 | else 1207 | closesocket(hSock); 1208 | break; 1209 | } 1210 | } 1211 | } 1212 | closesocket(hSockServer); 1213 | return 0; 1214 | } 1215 | 1216 | //parses parameter /e:IP/Bits 1217 | static int ParseEcs(char* szIpAndAmountBits) 1218 | { 1219 | struct addrinfo sHint; 1220 | struct addrinfo* psResult; 1221 | char* szPos=strchr(szIpAndAmountBits, '/'); 1222 | int iBits; 1223 | int iMaxBits; 1224 | 1225 | if(!szPos) 1226 | return 0; //error 1227 | *szPos='\0'; //overwrite '/' for getaddrinfo below 1228 | //prepare hint: only numeric values 1229 | memset(&sHint, 0, sizeof(sHint)); 1230 | sHint.ai_family=AF_UNSPEC; 1231 | sHint.ai_flags=AI_NUMERICHOST; 1232 | //now resolve it 1233 | if(getaddrinfo(szIpAndAmountBits, NULL, &sHint, &psResult)) 1234 | { 1235 | //some getaddrinfo implementations seem to have some trouble, so try the old IPv4 variant additionally 1236 | //use sHint for that 1237 | ((struct in_addr*)(g_u8aEcsOption+8))->s_addr=inet_addr(szIpAndAmountBits); 1238 | if(INADDR_NONE==((struct in_addr*)(g_u8aEcsOption+8))->s_addr) 1239 | { 1240 | OutputFatal("\nInvalid address '%s' specified for EDNS Client Subnet!\n", szIpAndAmountBits); 1241 | return 0; //error 1242 | } 1243 | g_u8aEcsOption[5]=1; //FAMILY IPv4 1244 | iMaxBits=32; 1245 | } 1246 | else 1247 | { 1248 | switch(psResult->ai_family) 1249 | { 1250 | case AF_INET: 1251 | memcpy(g_u8aEcsOption+8, &((struct sockaddr_in*)psResult->ai_addr)->sin_addr, 4); 1252 | g_u8aEcsOption[5]=1; //FAMILY IPv4 1253 | iMaxBits=32; 1254 | break; 1255 | case AF_INET6: 1256 | memcpy(g_u8aEcsOption+8, &((struct sockaddr_in6*)psResult->ai_addr)->sin6_addr, 16); 1257 | g_u8aEcsOption[5]=2; //FAMILY IPv6 1258 | iMaxBits=128; 1259 | break; 1260 | default: 1261 | OutputFatal("\nInvalid address '%s' specified for EDNS Client Subnet!\n", szIpAndAmountBits); 1262 | return 0; //error 1263 | } 1264 | } 1265 | //check amount of bits to use 1266 | iBits=atoi(szPos+1); 1267 | if(iBits<=0 || iBits>iMaxBits) 1268 | { 1269 | OutputFatal("\nInvalid amount of bits '%s' specified for EDNS Client Subnet!\n", szPos+1); 1270 | return 0; //error 1271 | } 1272 | //OPTION-CODE 1273 | g_u8aEcsOption[0]=0; 1274 | g_u8aEcsOption[1]=8; 1275 | //OPTION-LENGTH 1276 | g_u8aEcsOption[2]=0; 1277 | g_iEcsOptionLen=8+(iBits+7)/8; //round up to amount bytes 1278 | g_u8aEcsOption[3]=(uint8_t)(g_iEcsOptionLen-4); 1279 | //mask last byte of address 1280 | g_u8aEcsOption[g_iEcsOptionLen-1]&=(uint8_t)(0xff<<(7-((iBits+7)&7))); 1281 | //set rest to 0 1282 | memset(g_u8aEcsOption+g_iEcsOptionLen, 0, sizeof(g_u8aEcsOption)-g_iEcsOptionLen); 1283 | //1st byte of FAMILY always 0 1284 | g_u8aEcsOption[4]=0; 1285 | //SOURCE PREFIX-LENGTH 1286 | g_u8aEcsOption[6]=(uint8_t)iBits; 1287 | //SCOPE PREFIX-LENGTH always 0 1288 | g_u8aEcsOption[7]=0; 1289 | return 1; //o.k. 1290 | } 1291 | 1292 | //parses a command line parameter of the format IPv4 or IPv4:port or IPv6 or [IPv6]:port 1293 | static int ParseIpAndPort(int iFlag, const char* szParamName, const char* szPort, char* szIpAndPort, struct sockaddr_storage* psAddr) 1294 | { 1295 | struct addrinfo sHint; 1296 | struct addrinfo* psResult; 1297 | char* szPos; 1298 | 1299 | if(strchr(szIpAndPort, '.')) 1300 | { 1301 | //seems to be IPv4 1302 | szPos=strchr(szIpAndPort, ':'); 1303 | if(szPos) 1304 | { 1305 | *szPos='\0'; //overwrite ':' for getaddrinfo below 1306 | szPort=szPos+1; 1307 | } 1308 | } 1309 | else 1310 | { 1311 | //seems to be IPv6 1312 | //format [IPv6]:port? 1313 | if(*szIpAndPort=='[') 1314 | { 1315 | ++szIpAndPort; 1316 | szPos=strchr(szIpAndPort, ']'); 1317 | if(szPos) 1318 | { 1319 | *szPos='\0'; //overwrite ']' for getaddrinfo below 1320 | //is there a port specification? 1321 | if(szPos[1]==':') 1322 | szPort=szPos+2; 1323 | } 1324 | } 1325 | } 1326 | 1327 | //prepare hint: only numeric values 1328 | memset(&sHint, 0, sizeof(sHint)); 1329 | sHint.ai_family=AF_UNSPEC; 1330 | sHint.ai_flags=iFlag|AI_NUMERICHOST|AI_NUMERICSERV; 1331 | //now resolve it 1332 | if(getaddrinfo(szIpAndPort, szPort, &sHint, &psResult)) 1333 | { 1334 | //some getaddrinfo implementations seem to have some trouble, so try the old IPv4 variant additionally 1335 | ((struct sockaddr_in*)psAddr)->sin_addr.s_addr=inet_addr(szIpAndPort); 1336 | if(INADDR_NONE!=((struct sockaddr_in*)psAddr)->sin_addr.s_addr) 1337 | { 1338 | ((struct sockaddr_in*)psAddr)->sin_port=htons((uint16_t)atoi(szPort)); 1339 | if(((struct sockaddr_in*)psAddr)->sin_port) 1340 | { 1341 | ((struct sockaddr_in*)psAddr)->sin_family=AF_INET; 1342 | return 1; //o.k. 1343 | } 1344 | } 1345 | //only for the DNS server also support name 1346 | if(&g_sDnsSrvAddr==psAddr) 1347 | { 1348 | size_t uLen=strlen(szIpAndPort); 1349 | 1350 | if(uLen<256 && uLen) 1351 | { 1352 | ((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_port=htons((uint16_t)atoi(szPort)); 1353 | if(((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_port) 1354 | { 1355 | g_sDnsSrvAddr.ss_family=AF_UNSPEC; //this marks usage of name 1356 | *(char**)&((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_addr=szIpAndPort; //use sin6_addr for pointer to name (128 bit -> large enough, alignment should also be fine) 1357 | ((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_flowinfo=(uint8_t)uLen; //use sin6_flowinfo for length 1358 | return 1; //o.k. 1359 | } 1360 | } 1361 | } 1362 | OutputFatal("\nInvalid address '%s' and port '%s' specified for %s!\n", szIpAndPort, szPort, szParamName); 1363 | return 0; //error 1364 | } 1365 | if(psResult->ai_addrlen>sizeof(*psAddr)) 1366 | { 1367 | //should never happen 1368 | OutputFatal("\nAddress '%s' and port '%s' specified for %s too long for internal storage!\n", szIpAndPort, szPort, szParamName); 1369 | return 0; //error 1370 | } 1371 | //copy 1st result 1372 | memcpy(psAddr, psResult->ai_addr, psResult->ai_addrlen); 1373 | freeaddrinfo(psResult); 1374 | return 1; //o.k. 1375 | } 1376 | 1377 | //creates CONNECT command for HTTP proxy containing DNS address 1378 | static int CreateHttpProxyConnectCommand() 1379 | { 1380 | memcpy(g_caHttpProxyConnect, "CONNECT ", 8); 1381 | g_iHttpProxyConnectLen=8; 1382 | if(g_sDnsSrvAddr.ss_family==AF_UNSPEC) 1383 | { 1384 | //sin6_addr contains pointer to name, see ParseIpAndPort (max. length is 255) 1385 | int iLenDnsAddr=sprintf(g_caHttpProxyConnect+g_iHttpProxyConnectLen, "%s:%u", *(char**)&((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_addr, ntohs(((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_port)); 1386 | 1387 | if(iLenDnsAddr<=0) 1388 | return 0; //error 1389 | g_iHttpProxyConnectLen+=iLenDnsAddr; 1390 | } 1391 | else 1392 | { 1393 | //add IP and port to g_caHttpProxyConnect 1394 | char szPort[6]; 1395 | int iLenPort; 1396 | 1397 | if(g_sDnsSrvAddr.ss_family==AF_INET6) 1398 | g_caHttpProxyConnect[g_iHttpProxyConnectLen++]='['; //enclose with [] for IPv6 1399 | if(getnameinfo((struct sockaddr*)&g_sDnsSrvAddr, GetAddrLen(&g_sDnsSrvAddr), g_caHttpProxyConnect+g_iHttpProxyConnectLen, 128, szPort, sizeof(szPort), NI_NUMERICHOST|NI_NUMERICSERV)) 1400 | return 0; //error 1401 | g_iHttpProxyConnectLen+=(int)strlen(g_caHttpProxyConnect+g_iHttpProxyConnectLen); 1402 | if(g_sDnsSrvAddr.ss_family==AF_INET6) 1403 | g_caHttpProxyConnect[g_iHttpProxyConnectLen++]=']'; //enclose with [] for IPv6 1404 | g_caHttpProxyConnect[g_iHttpProxyConnectLen++]=':'; 1405 | iLenPort=(int)strlen(szPort); 1406 | memcpy(g_caHttpProxyConnect+g_iHttpProxyConnectLen, szPort, iLenPort); 1407 | g_iHttpProxyConnectLen+=iLenPort; 1408 | } 1409 | //complete command 1410 | memcpy(g_caHttpProxyConnect+g_iHttpProxyConnectLen, " HTTP/1.0\r\n\r\n", 13); 1411 | g_iHttpProxyConnectLen+=13; 1412 | return 1; //o.k. 1413 | } 1414 | 1415 | int main(int iArgCount, char** szaArgs) 1416 | { 1417 | static struct sockaddr_storage sAddr; //make it static so the lower array assignment causes no compiler warning 1418 | const char* szUser; 1419 | const char* szPassword; 1420 | char** pszCurArg; 1421 | char* szCurArg; 1422 | char* szLogFilePath; 1423 | char* szErrMsg; 1424 | size_t uUserLen; 1425 | size_t uPasswordLen; 1426 | socklen_t iAddrLen; 1427 | int iAddrCount; 1428 | int iLen; 1429 | int bAppend; //append log file? 1430 | int bQuiet; //parameter q specified? 1431 | uint16_t u16aBuf[32754]; //max UDP packet length on Windows plus one byte - using uint16_t here for alignment 1432 | //struct array for the three addresses passed via command line 1433 | struct SAddr 1434 | { 1435 | struct sockaddr_storage* psAddr; 1436 | const char* szDefaultAddress; 1437 | const char* szDefaultPort; 1438 | const char* szName; 1439 | int iFlag; 1440 | } saAddresses[3]= 1441 | { 1442 | { &g_sSocksAddr, DEFAULT_SOCKS_SERVER, DEFAULT_SOCKS_PORT, "SOCKS server", 0 }, 1443 | { &g_sDnsSrvAddr, DEFAULT_DNS_SERVER, DEFAULT_DNS_PORT, "DNS server", 0 }, 1444 | { &sAddr, DEFAULT_LISTEN_IP, DEFAULT_DNS_PORT, "listening", AI_PASSIVE } //AI_PASSIVE for "getaddrinfo" as we use it for "bind" 1445 | }; 1446 | 1447 | //parse command line - use e.g. "/?" to display the usage 1448 | bQuiet=0; 1449 | bAppend=0; 1450 | iAddrCount=0; 1451 | szLogFilePath=NULL; 1452 | szUser=NULL; 1453 | szPassword=NULL; 1454 | for(pszCurArg=szaArgs+1; --iArgCount; ++pszCurArg) 1455 | { 1456 | szCurArg=*pszCurArg; 1457 | //no address parameter? 1458 | if(*szCurArg=='-' || *szCurArg=='/') 1459 | { 1460 | switch(szCurArg[1]) 1461 | { 1462 | case 'd': //disable cache? 1463 | case 'D': 1464 | if(!szCurArg[2]) 1465 | { 1466 | g_bCacheEnabled=0; 1467 | continue; //correct parameter, go to next one 1468 | } 1469 | break; 1470 | case 'q': //no console output? 1471 | case 'Q': 1472 | if(!szCurArg[2]) 1473 | { 1474 | bQuiet=1; 1475 | continue; //correct parameter, go to next one 1476 | } 1477 | break; 1478 | case 'l': //log output? 1479 | case 'L': 1480 | if(!szLogFilePath) //only allowed once 1481 | { 1482 | bAppend=(szCurArg[2]=='a' || szCurArg[2]=='A'); //append? 1483 | if(szCurArg[2+bAppend]==':') 1484 | { 1485 | szLogFilePath=szCurArg+3+bAppend; 1486 | continue; //correct parameter, go to next one 1487 | } 1488 | } 1489 | break; 1490 | case 'u': //user? 1491 | case 'U': 1492 | if(!szUser && szCurArg[2]==':') //only allowed once and : must be 2nd char 1493 | { 1494 | szUser=szCurArg+3; 1495 | continue; //correct parameter, go to next one 1496 | } 1497 | break; 1498 | case 'p': //password? 1499 | case 'P': 1500 | if(!szPassword && szCurArg[2]==':') //only allowed once and : must be 2nd char 1501 | { 1502 | szPassword=szCurArg+3; 1503 | continue; //correct parameter, go to next one 1504 | } 1505 | break; 1506 | case 't': //HTTP proxy? 1507 | case 'T': 1508 | g_iHttpProxyConnectLen=1; //used as boolean here; later it contains the real length of the CONNECT command 1509 | continue; //correct parameter, go to next one 1510 | case 'e': //EDNS Client Subnet 1511 | case 'E': 1512 | //only allowed once 1513 | if(!g_iEcsOptionLen) 1514 | { 1515 | g_bForceEcs=(szCurArg[2]=='f' || szCurArg[2]=='F'); //force? 1516 | szCurArg+=g_bForceEcs; 1517 | if(szCurArg[2]==':' && ParseEcs(szCurArg+3)) 1518 | continue; //correct parameter, go to next one 1519 | } 1520 | } 1521 | //wrong/unknown parameter; display help 1522 | } 1523 | else 1524 | { 1525 | //try to parse address 1526 | if(iAddrCount display usage and stop 1536 | OutputFatal("\nDNS2SOCKS tunnels DNS requests via SOCKS5 and caches the answers.\n\n\n" 1537 | "Usage:\n\n" 1538 | "DNS2SOCKS [/?] [/t] [/d] [/q] [/l[a]:FilePath] [/u:User /p:Password]\n" 1539 | " [/e[f]:IP/Bits]\n" 1540 | " [Socks5ServerIP[:Port]] [DNSServerIPorName[:Port]] [ListenIP[:Port]]\n\n" 1541 | "/? to view this help\n" 1542 | "/t to use a HTTP proxy instead of a SOCKS server\n" 1543 | " (here: Socks5ServerIP = HttpProxyIP, no support for /u and /p)\n" 1544 | "/d to disable the cache\n" 1545 | "/q to suppress the text output\n" 1546 | "/l:FilePath to create a new log file \"FilePath\"\n" 1547 | "/la:FilePath to create a new log file or append to the existing \"FilePath\"\n" 1548 | "/u:User user name if your SOCKS server uses user/password authentication\n" 1549 | "/p:Password password if your SOCKS server uses user/password authentication\n" 1550 | "/e:IP/Bits to enable and specify EDNS client subnet in DNS queries\n" 1551 | "/ef:IP/Bits same as above but also replaces EDNS client subnet if it exists\n\n" 1552 | "Default Socks5ServerIP:Port = %s:%s\n" 1553 | "Default DNSServerIPorName:Port = %s:%s\n" 1554 | "Default ListenIP:Port = %s:%s\n", 1555 | DEFAULT_SOCKS_SERVER, DEFAULT_SOCKS_PORT, 1556 | DEFAULT_DNS_SERVER, DEFAULT_DNS_PORT, 1557 | DEFAULT_LISTEN_IP, DEFAULT_DNS_PORT); 1558 | return 1; 1559 | } 1560 | if(szPassword && !szUser) 1561 | { 1562 | OutputFatal("\nPassword specified but no user!\n"); 1563 | return 1; 1564 | } 1565 | if(!szPassword && szUser) 1566 | { 1567 | OutputFatal("\nUser specified but no password!\n"); 1568 | return 1; 1569 | } 1570 | if(g_iHttpProxyConnectLen && szPassword) 1571 | { 1572 | OutputFatal("\nAuthentication not supported for HTTP proxy!\n"); 1573 | return 1; 1574 | } 1575 | if(szUser) 1576 | { 1577 | uUserLen=strlen(szUser); 1578 | if(uUserLen>255) 1579 | { 1580 | OutputFatal("\nUser exceeds 255 characters!\n"); 1581 | return 1; 1582 | } 1583 | uPasswordLen=strlen(szPassword); 1584 | if(uPasswordLen>255) 1585 | { 1586 | OutputFatal("\nPassword exceeds 255 characters!\n"); 1587 | return 1; 1588 | } 1589 | } 1590 | else 1591 | { 1592 | //initialize uUserLen and uPasswordLen - otherwise VC++ 2010 outputs a wrong warning 1593 | uUserLen=0; 1594 | uPasswordLen=0; 1595 | } 1596 | 1597 | //fill unspecified addresses with default values 1598 | while(iAddrCountsin6_addr); 1642 | sprintf((char*)u16aBuf+768, "%hu", ntohs(((struct sockaddr_in6*)&g_sDnsSrvAddr)->sin6_port)); 1643 | } 1644 | else if(getnameinfo((struct sockaddr*)&g_sDnsSrvAddr, GetAddrLen(&g_sDnsSrvAddr), (char*)u16aBuf+512, 256, (char*)u16aBuf+768, 256, NI_NUMERICHOST|NI_NUMERICSERV)) 1645 | { 1646 | //should never happen 1647 | strcpy((char*)u16aBuf+512, "unknown address"); 1648 | strcpy((char*)u16aBuf+768, "unknown"); 1649 | } 1650 | if(getnameinfo((struct sockaddr*)&sAddr, GetAddrLen(&sAddr), (char*)u16aBuf+1024, 256, (char*)u16aBuf+1280, 256, NI_NUMERICHOST|NI_NUMERICSERV)) 1651 | { 1652 | //should never happen 1653 | strcpy((char*)u16aBuf+1024, "unknown address"); 1654 | strcpy((char*)u16aBuf+1280, "unknown"); 1655 | } 1656 | 1657 | //use (char*)u16aBuf+1536 as string buffer to output information about ECS 1658 | if(g_iEcsOptionLen) 1659 | { 1660 | struct sockaddr_storage sEcsAddr; 1661 | socklen_t uSockLen; 1662 | 1663 | memset(&sEcsAddr, 0, sizeof(sEcsAddr)); 1664 | //IPv6? 1665 | if(g_u8aEcsOption[5]==2) 1666 | { 1667 | uSockLen=sizeof(struct sockaddr_in6); 1668 | ((struct sockaddr_in6*)&sEcsAddr)->sin6_family=AF_INET6; 1669 | memcpy(&((struct sockaddr_in6*)&sEcsAddr)->sin6_addr, g_u8aEcsOption+8, 16); 1670 | } 1671 | else 1672 | { 1673 | uSockLen=sizeof(struct sockaddr_in); 1674 | ((struct sockaddr_in*)&sEcsAddr)->sin_family=AF_INET; 1675 | memcpy(&((struct sockaddr_in*)&sEcsAddr)->sin_addr, g_u8aEcsOption+8, 4); 1676 | } 1677 | if(getnameinfo((struct sockaddr*)&sEcsAddr, uSockLen, (char*)u16aBuf+1536, 256, NULL, 0, NI_NUMERICHOST)) 1678 | { 1679 | //should never happen 1680 | strcpy((char*)u16aBuf+1536, "unknown address"); 1681 | } 1682 | else 1683 | //add amount of bits 1684 | sprintf((char*)u16aBuf+1536+strlen((char*)u16aBuf+1536), "/%u", (unsigned int)g_u8aEcsOption[6]); 1685 | //add " forced" if g_bForceEcs 1686 | if(g_bForceEcs) 1687 | strcat((char*)u16aBuf+1536, " forced"); 1688 | } 1689 | else 1690 | strcpy((char*)u16aBuf+1536, "disabled"); 1691 | 1692 | //output configuration 1693 | OutputToLog(OUTPUT_LINE_BREAK|OUTPUT_CONSOLE, "%s %s port %s\n" 1694 | "DNS server %s port %s\n" 1695 | "listening on %s port %s\n" 1696 | "cache %s\n" 1697 | "authentication %s\n" 1698 | "EDNS client subnet %s\n", 1699 | g_iHttpProxyConnectLen?"HTTP proxy ":"SOCKS server", (char*)u16aBuf, (char*)u16aBuf+256, 1700 | (char*)u16aBuf+512, (char*)u16aBuf+768, 1701 | (char*)u16aBuf+1024, (char*)u16aBuf+1280, 1702 | g_bCacheEnabled?"enabled":"disabled", 1703 | szUser?"enabled":"disabled", 1704 | (char*)u16aBuf+1536); 1705 | 1706 | InitializeCriticalSection(&g_sCritSect); 1707 | 1708 | //log file was requested? 1709 | if(szLogFilePath) 1710 | OpenLogFile(szLogFilePath, bAppend); 1711 | 1712 | //create authentication package if user/password was specified 1713 | if(szUser) 1714 | { 1715 | g_iUsrPwdLen=(int)(uUserLen+uPasswordLen+3); 1716 | g_uaUsrPwd=(unsigned char*)malloc(g_iUsrPwdLen); 1717 | g_uaUsrPwd[0]=1; //version 1 1718 | g_uaUsrPwd[1]=(unsigned char)uUserLen; 1719 | memcpy(g_uaUsrPwd+2, szUser, uUserLen); 1720 | g_uaUsrPwd[uUserLen+2]=(unsigned char)uPasswordLen; 1721 | memcpy(g_uaUsrPwd+uUserLen+3, szPassword, uPasswordLen); 1722 | } 1723 | 1724 | //create thread for TCP connection 1725 | ThreadCreate(TcpThread, &sAddr); 1726 | 1727 | //endless loop 1728 | for(;;) 1729 | { 1730 | //receive DNS request 1731 | iAddrLen=sizeof(sAddr); 1732 | iLen=recvfrom(g_hSockUdp, (char*)u16aBuf, sizeof(u16aBuf), 0, (struct sockaddr*)&sAddr, &iAddrLen); 1733 | if(iLen>12) //12 bytes header plus at least one byte of data 1734 | HandleDnsRequest(u16aBuf, iLen, &sAddr, iAddrLen); 1735 | } 1736 | /*no cleanup code as we have an endless loop 1737 | we would need something like this: 1738 | terminate all threads and clear their resources 1739 | free(g_uaUsrPwd); 1740 | DeleteCriticalSection(&g_sCritSect); 1741 | closesocket(g_hSockUdp); 1742 | free all cache entries 1743 | close the console 1744 | close the log file 1745 | return 0;*/ 1746 | } 1747 | 1748 | #ifdef _WIN32 1749 | 1750 | //entry function for Windows applications - just forwards to "main" 1751 | int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) 1752 | { 1753 | WSADATA sData; 1754 | char* szErrMsg; 1755 | int iErrNo; 1756 | 1757 | hInstance; 1758 | hPrevInstance; 1759 | szCmdLine; 1760 | iCmdShow; 1761 | 1762 | iErrNo=WSAStartup(0x202, &sData); 1763 | if(iErrNo) 1764 | { 1765 | szErrMsg=GetSysError(iErrNo); 1766 | OutputFatal("\nWSAStartup has failed: %s\n", szErrMsg); 1767 | FreeSysError(szErrMsg); 1768 | return 1; 1769 | } 1770 | 1771 | //call "main" with the already parsed command line parameters stored in global variables by CRT 1772 | iErrNo=main(__argc, __argv); 1773 | 1774 | WSACleanup(); 1775 | return iErrNo; 1776 | } 1777 | 1778 | #endif //#ifdef _WIN32 1779 | -------------------------------------------------------------------------------- /DNS2SOCKS.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | true 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /DNS2SOCKS.rc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US 4 | #pragma code_page(1252) 5 | 6 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "DNS2SOCKS.manifest" 7 | 8 | VS_VERSION_INFO VERSIONINFO 9 | FILEVERSION 2,1,0,0 10 | PRODUCTVERSION 2,1,0,0 11 | FILEFLAGSMASK 0x3FL 12 | #ifdef _DEBUG 13 | FILEFLAGS 0x1L 14 | #else 15 | FILEFLAGS 0x0L 16 | #endif 17 | FILEOS 0x00040004L 18 | FILETYPE 0x1L 19 | FILESUBTYPE 0x0L 20 | BEGIN 21 | BLOCK "StringFileInfo" 22 | BEGIN 23 | BLOCK "040904B0" 24 | BEGIN 25 | VALUE "FileDescription", "Tunnels DNS requests via SOCKS or HTTP" 26 | VALUE "FileVersion", "2.1.0.0" 27 | VALUE "OriginalFilename", "DNS2SOCKS.exe" 28 | VALUE "ProductVersion", "2.1.0.0" 29 | END 30 | END 31 | BLOCK "VarFileInfo" 32 | BEGIN 33 | VALUE "Translation", 0x0409, 1200 34 | END 35 | END -------------------------------------------------------------------------------- /DNS2SOCKS.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {F19D3415-2E79-45EF-9893-4D9E2010B976} 15 | Win32Proj 16 | DNS2SOCKS 17 | 18 | 19 | 20 | Application 21 | true 22 | NotSet 23 | v140 24 | 25 | 26 | Application 27 | false 28 | true 29 | NotSet 30 | v140 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | false 45 | 46 | 47 | false 48 | false 49 | 50 | 51 | 52 | Use 53 | Level4 54 | Disabled 55 | WIN32;_DEBUG;%(PreprocessorDefinitions) 56 | true 57 | false 58 | 59 | 60 | Windows 61 | true 62 | ws2_32.lib 63 | 64 | 65 | 66 | 67 | Level4 68 | Use 69 | MaxSpeed 70 | true 71 | true 72 | WIN32;NDEBUG;%(PreprocessorDefinitions) 73 | true 74 | false 75 | MultiThreaded 76 | 77 | 78 | Windows 79 | false 80 | true 81 | true 82 | ws2_32.lib 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Create 92 | Create 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /DNS2SOCKS.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Header Files 16 | 17 | 18 | 19 | 20 | Source Files 21 | 22 | 23 | Source Files 24 | 25 | 26 | 27 | 28 | Source Files 29 | 30 | 31 | -------------------------------------------------------------------------------- /stdafx.c: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDAFX_H 2 | #define _STDAFX_H 3 | 4 | #ifdef _WIN32 5 | 6 | //Windows specific includes 7 | #define WINVER 0x501 8 | #define _CRT_SECURE_NO_WARNINGS 9 | #define _WINSOCK_DEPRECATED_NO_WARNINGS 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #else //#ifdef _WIN32 17 | 18 | //other OS includes and some tricks to fake Win32 API 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | typedef int SOCKET; 33 | #define SOCKET_ERROR (-1) 34 | #define closesocket(hSock) close(hSock) 35 | #define WSAGetLastError() errno 36 | #define CRITICAL_SECTION pthread_mutex_t 37 | #define InitializeCriticalSection(criticalSection) pthread_mutex_init(criticalSection, NULL) 38 | #define EnterCriticalSection(criticalSection) pthread_mutex_lock(criticalSection) 39 | #define LeaveCriticalSection(criticalSection) pthread_mutex_unlock(criticalSection) 40 | 41 | #endif //#ifdef _WIN32 42 | 43 | #endif //#ifndef _STDAFX_H 44 | --------------------------------------------------------------------------------