//Check hosts from list size_t __fastcall CheckHostsProcess(PSTR OriginalRequest, const size_t Length, PSTR Result, const size_t ResultSize) { //Initilization std::string Domain; auto DNS_Header = (pdns_hdr)OriginalRequest; memset(Result, 0, ResultSize); //Request check if (DNS_Header->Questions == htons(U16_NUM_ONE) && CheckQueryNameLength(OriginalRequest + sizeof(dns_hdr)) + 1U < DOMAIN_MAXSIZE) { if (DNSQueryToChar(OriginalRequest + sizeof(dns_hdr), Result) > DOMAIN_MINSIZE) { //Domain Case Conversion CaseConvert(false, Result, strnlen_s(Result, ResultSize)); //Copy domain string. Domain = Result; memset(Result, 0, ResultSize); } else { return EXIT_FAILURE; } } else { return EXIT_FAILURE; } //Response memcpy_s(Result, ResultSize, OriginalRequest, Length); DNS_Header = (pdns_hdr)Result; auto DNS_Query = (pdns_qry)(Result + DNS_PACKET_QUERY_LOCATE(Result)); //Check Classes. if (DNS_Query->Classes != htons(DNS_CLASS_IN)) return EXIT_FAILURE; //Check Accept Types list. if (Parameter.AcceptType) //Permit { for (auto AcceptTypeTableIter = Parameter.AcceptTypeList->begin();AcceptTypeTableIter != Parameter.AcceptTypeList->end();++AcceptTypeTableIter) { if (AcceptTypeTableIter + 1U == Parameter.AcceptTypeList->end()) { if (*AcceptTypeTableIter != DNS_Query->Type) { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R_SNH); return Length; } } else if (*AcceptTypeTableIter == DNS_Query->Type) { break; } } } else { //Deny for (auto AcceptTypeTableIter:*Parameter.AcceptTypeList) { if (DNS_Query->Type == AcceptTypeTableIter) { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R_SNH); return Length; } } } size_t DataLength = 0; //PTR Records #if !defined(PLATFORM_MACX) if (DNS_Query->Type == htons(DNS_RECORD_PTR) && Parameter.LocalServer_Length + Length <= ResultSize) { auto IsSendPTR = false; //IPv6 check if (Domain == ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") || //Loopback address(::1, Section 2.5.3 in RFC 4291) //IPv4 check Domain.find(".127.in-addr.arpa") != std::string::npos || //Loopback address(127.0.0.0/8, Section 3.2.1.3 in RFC 1122) Domain.find(".254.169.in-addr.arpa") != std::string::npos) //Link-local address(169.254.0.0/16, RFC 3927) { IsSendPTR = true; } else { //IPv6 check std::unique_lock<std::mutex> LocalAddressMutexIPv6(LocalAddressLock[0]); for (auto StringIter:*Parameter.LocalAddress_ResponsePTR[0]) { if (Domain == StringIter) { IsSendPTR = true; break; } } LocalAddressMutexIPv6.unlock(); //IPv4 check if (!IsSendPTR) { std::unique_lock<std::mutex> LocalAddressMutexIPv4(LocalAddressLock[1U]); for (auto StringIter:*Parameter.LocalAddress_ResponsePTR[1U]) { if (Domain == StringIter) { IsSendPTR = true; break; } } } } //Send Localhost PTR. if (IsSendPTR) { //Set header flags and copy response to buffer. DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SER_RA); DNS_Header->Answer = htons(U16_NUM_ONE); memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), 0, ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry))); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry)), Parameter.LocalServer_Response, Parameter.LocalServer_Length); DataLength = DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + Parameter.LocalServer_Length; //EDNS Label if (Parameter.EDNS_Label || DNS_Header->Additional > 0) { DNS_Header->Additional = 0; DataLength = AddEDNSLabelToAdditionalRR(Result, DataLength, ResultSize, false); } return DataLength; } } #endif //LocalFQDN check if (Domain == *Parameter.LocalFQDN_String) { //IPv6 if (DNS_Query->Type == htons(DNS_RECORD_AAAA)) { std::unique_lock<std::mutex> LocalAddressMutexIPv6(LocalAddressLock[0]); if (Parameter.LocalAddress_Length[0] >= DNS_PACKET_MINSIZE) { memset(Result + sizeof(uint16_t), 0, ResultSize - sizeof(uint16_t)); memcpy_s(Result + sizeof(uint16_t), ResultSize - sizeof(uint16_t), Parameter.LocalAddress_Response[0] + sizeof(uint16_t), Parameter.LocalAddress_Length[0] - sizeof(uint16_t)); return Parameter.LocalAddress_Length[0]; } } //IPv4 else if (DNS_Query->Type == htons(DNS_RECORD_A)) { std::unique_lock<std::mutex> LocalAddressMutexIPv4(LocalAddressLock[1U]); if (Parameter.LocalAddress_Length[1U] >= DNS_PACKET_MINSIZE) { memset(Result + sizeof(uint16_t), 0, ResultSize - sizeof(uint16_t)); memcpy_s(Result + sizeof(uint16_t), ResultSize - sizeof(uint16_t), Parameter.LocalAddress_Response[1U] + sizeof(uint16_t), Parameter.LocalAddress_Length[1U] - sizeof(uint16_t)); return Parameter.LocalAddress_Length[1U]; } } } //Main check auto IsLocal = false; std::unique_lock<std::mutex> HostsFileMutex(HostsFileLock); for (auto HostsFileSetIter:*HostsFileSetUsing) { for (auto HostsTableIter:HostsFileSetIter.HostsList) { if (std::regex_match(Domain, HostsTableIter.Pattern)) { //Check white list. if (HostsTableIter.Type_Hosts == HOSTS_TYPE_WHITE) { break; } //Check local request. else if (HostsTableIter.Type_Hosts == HOSTS_TYPE_LOCAL) { IsLocal = true; break; } //Check banned list. else if (HostsTableIter.Type_Hosts == HOSTS_TYPE_BANNED) { if (HostsTableIter.Type_Record.empty()) //Block all types { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R_SNH); return Length; } else { //Permit or Deny if (HostsTableIter.Type_Operation) { //Only allow some types. for (auto RecordTypeIter = HostsTableIter.Type_Record.begin();RecordTypeIter != HostsTableIter.Type_Record.end();++RecordTypeIter) { if (DNS_Query->Type == *RecordTypeIter) { break; } else if (RecordTypeIter + 1U == HostsTableIter.Type_Record.end()) { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); return Length; } } } else { //Block some types. for (auto RecordTypeIter:HostsTableIter.Type_Record) { if (DNS_Query->Type == RecordTypeIter) { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); return Length; } } } } } //Check Hosts. else if (!HostsTableIter.Type_Record.empty()) { //IPv6 if (DNS_Query->Type == htons(DNS_RECORD_AAAA) && HostsTableIter.Type_Record.front() == htons(DNS_RECORD_AAAA)) { /* Old version(2015-07-19) //EDNS Label if (DNS_Header->Additional == htons(U16_NUM_ONE)) { memset(Result + Length - sizeof(dns_record_opt), 0, sizeof(dns_record_opt)); DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Answer = htons((uint16_t)(HostsTableIter.Length / sizeof(dns_record_aaaa))); memcpy_s(Result + Length - sizeof(dns_record_opt), Length, HostsTableIter.Response.get(), HostsTableIter.Length); //Hosts load balancing if (ntohs(DNS_Header->Answer) > U16_NUM_ONE) { std::shared_ptr<dns_record_aaaa> DNS_AAAA_Temp(new dns_record_aaaa()); memset(DNS_AAAA_Temp.get(), 0, sizeof(dns_record_aaaa)); //Select a ramdom preferred result. std::uniform_int_distribution<int> RamdomDistribution(0, ntohs(DNS_Header->Answer) - 1U); size_t RamdomIndex = RamdomDistribution(*Parameter.RamdomEngine); if (RamdomIndex > 0) { memcpy_s(DNS_AAAA_Temp.get(), sizeof(dns_record_aaaa), Result + Length - sizeof(dns_record_opt), sizeof(dns_record_aaaa)); memset(Result + Length - sizeof(dns_record_opt), 0, sizeof(dns_record_aaaa)); memcpy_s(Result + Length - sizeof(dns_record_opt), ResultSize, Result + Length - sizeof(dns_record_opt) + sizeof(dns_record_aaaa) * RamdomIndex, sizeof(dns_record_aaaa)); memset(Result + Length - sizeof(dns_record_opt) + sizeof(dns_record_aaaa) * RamdomIndex, 0, sizeof(dns_record_aaaa)); memcpy_s(Result + Length - sizeof(dns_record_opt) + sizeof(dns_record_aaaa) * RamdomIndex, ResultSize, DNS_AAAA_Temp.get(), sizeof(dns_record_aaaa)); } } //Different result if (!Parameter.EDNS_Label) { auto DNS_Record_OPT = (pdns_record_opt)(Result + Length - sizeof(dns_record_opt) + HostsTableIter.Length); DNS_Record_OPT->Type = htons(DNS_RECORD_OPT); DNS_Record_OPT->UDPPayloadSize = htons((uint16_t)Parameter.EDNSPayloadSize); //DNSSEC if (Parameter.DNSSEC_Request) DNS_Record_OPT->Z_Field = htons(ntohs(DNS_Record_OPT->Z_Field) | EDNS_GET_BIT_DO); //Set Accepts DNSSEC security Resource Records bit. return Length + HostsTableIter.Length; DNS_Header->Additional = 0; return AddEDNSLabelToAdditionalRR(Result, Length - sizeof(dns_record_opt) + HostsTableIter.Length, ResultSize, false); } else { return Length - sizeof(dns_record_opt) + HostsTableIter.Length; } } else { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Answer = htons((uint16_t)(HostsTableIter.Length / sizeof(dns_record_aaaa))); memcpy_s(Result + Length, ResultSize, HostsTableIter.Response.get(), HostsTableIter.Length); //Hosts load balancing if (ntohs(DNS_Header->Answer) > U16_NUM_ONE) { std::shared_ptr<dns_record_aaaa> DNS_AAAA_Temp(new dns_record_aaaa()); memset(DNS_AAAA_Temp.get(), 0, sizeof(dns_record_aaaa)); //Select a ramdom preferred result. std::uniform_int_distribution<int> RamdomDistribution(0, ntohs(DNS_Header->Answer) - 1U); size_t RamdomIndex = RamdomDistribution(*Parameter.RamdomEngine); if (RamdomIndex > 0) { memcpy_s(DNS_AAAA_Temp.get(), sizeof(dns_record_aaaa), Result + Length, sizeof(dns_record_aaaa)); memset(Result + Length, 0, sizeof(dns_record_aaaa)); memcpy_s(Result + Length, ResultSize, Result + Length + sizeof(dns_record_aaaa) * RamdomIndex, sizeof(dns_record_aaaa)); memset(Result + Length + sizeof(dns_record_aaaa) * RamdomIndex, 0, sizeof(dns_record_aaaa)); memcpy_s(Result + Length + sizeof(dns_record_aaaa) * RamdomIndex, ResultSize, DNS_AAAA_Temp.get(), sizeof(dns_record_aaaa)); } } return Length + HostsTableIter.Length; } */ //Set header flags. DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Answer = htons((uint16_t)(HostsTableIter.Length / sizeof(dns_record_aaaa))); //Hosts item length check DataLength = DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + HostsTableIter.Length; if (Parameter.EDNS_Label || DNS_Header->Additional > 0) { while (DataLength > PACKET_MAXSIZE - EDNS_ADDITIONAL_MAXSIZE) { DataLength -= sizeof(dns_record_aaaa); DNS_Header->Answer = htons(ntohs(DNS_Header->Answer) - 1U); } } else { while (DataLength > PACKET_MAXSIZE) { DataLength -= sizeof(dns_record_aaaa); DNS_Header->Answer = htons(ntohs(DNS_Header->Answer) - 1U); } } //Copy response to buffer. memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), 0, ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry))); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry)), HostsTableIter.Response.get(), DataLength - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry))); //Hosts load balancing if (ntohs(DNS_Header->Answer) > U16_NUM_ONE) { std::shared_ptr<dns_record_aaaa> DNS_AAAA_Temp(new dns_record_aaaa()); memset(DNS_AAAA_Temp.get(), 0, sizeof(dns_record_aaaa)); //Select a ramdom preferred result. std::uniform_int_distribution<int> RamdomDistribution(0, ntohs(DNS_Header->Answer) - 1U); size_t RamdomIndex = RamdomDistribution(*Parameter.RamdomEngine); if (RamdomIndex > 0) { memcpy_s(DNS_AAAA_Temp.get(), sizeof(dns_record_aaaa), Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), sizeof(dns_record_aaaa)); memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), 0, sizeof(dns_record_aaaa)); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry)), Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + sizeof(dns_record_aaaa) * RamdomIndex, sizeof(dns_record_aaaa)); memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + sizeof(dns_record_aaaa) * RamdomIndex, 0, sizeof(dns_record_aaaa)); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + sizeof(dns_record_aaaa) * RamdomIndex, sizeof(dns_record_aaaa), DNS_AAAA_Temp.get(), sizeof(dns_record_aaaa)); } } //EDNS Label if (Parameter.EDNS_Label || DNS_Header->Additional > 0) { DNS_Header->Additional = 0; DataLength = AddEDNSLabelToAdditionalRR(Result, DataLength, ResultSize, false); } return DataLength; } else if (DNS_Query->Type == htons(DNS_RECORD_A) && HostsTableIter.Type_Record.front() == htons(DNS_RECORD_A)) { /* Old version(2015-07-19) //EDNS Label if (DNS_Header->Additional == htons(U16_NUM_ONE)) { memset(Result + Length - sizeof(dns_record_opt), 0, sizeof(dns_record_opt)); DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Answer = htons((uint16_t)(HostsTableIter.Length / sizeof(dns_record_a))); memcpy_s(Result + Length - sizeof(dns_record_opt), ResultSize, HostsTableIter.Response.get(), HostsTableIter.Length); //Hosts load balancing if (ntohs(DNS_Header->Answer) > U16_NUM_ONE) { std::shared_ptr<dns_record_a> DNS_A_Temp(new dns_record_a()); memset(DNS_A_Temp.get(), 0, sizeof(dns_record_a)); //Select a ramdom preferred result. std::uniform_int_distribution<int> RamdomDistribution(0, ntohs(DNS_Header->Answer) - 1U); size_t RamdomIndex = RamdomDistribution(*Parameter.RamdomEngine); if (RamdomIndex > 0) { memcpy_s(DNS_A_Temp.get(), sizeof(dns_record_a), Result + Length - sizeof(dns_record_opt), sizeof(dns_record_a)); memset(Result + Length - sizeof(dns_record_opt), 0, sizeof(dns_record_a)); memcpy_s(Result + Length - sizeof(dns_record_opt), ResultSize, Result + Length - sizeof(dns_record_opt) + sizeof(dns_record_a) * RamdomIndex, sizeof(dns_record_a)); memset(Result + Length - sizeof(dns_record_opt) + sizeof(dns_record_a) * RamdomIndex, 0, sizeof(dns_record_a)); memcpy_s(Result + Length - sizeof(dns_record_opt) + sizeof(dns_record_a) * RamdomIndex, ResultSize, DNS_A_Temp.get(), sizeof(dns_record_a)); } } //Different result if (!Parameter.EDNS_Label) { auto DNS_Record_OPT = (pdns_record_opt)(Result + Length - sizeof(dns_record_opt) + HostsTableIter.Length); DNS_Record_OPT->Type = htons(DNS_RECORD_OPT); DNS_Record_OPT->UDPPayloadSize = htons((uint16_t)Parameter.EDNSPayloadSize); //DNSSEC if (Parameter.DNSSEC_Request) DNS_Record_OPT->Z_Field = htons(ntohs(DNS_Record_OPT->Z_Field) | EDNS_GET_BIT_DO); //Set Accepts DNSSEC security Resource Records bit. return Length + HostsTableIter.Length; DNS_Header->Additional = 0; return AddEDNSLabelToAdditionalRR(Result, Length - sizeof(dns_record_opt) + HostsTableIter.Length, ResultSize, false); } else { return Length - sizeof(dns_record_opt) + HostsTableIter.Length; } } else { DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Answer = htons((uint16_t)(HostsTableIter.Length / sizeof(dns_record_a))); memcpy_s(Result + Length, ResultSize, HostsTableIter.Response.get(), HostsTableIter.Length); //Hosts load balancing if (ntohs(DNS_Header->Answer) > U16_NUM_ONE) { std::shared_ptr<dns_record_a> DNS_A_Temp(new dns_record_a()); memset(DNS_A_Temp.get(), 0, sizeof(dns_record_a)); //Select a ramdom preferred result. std::uniform_int_distribution<int> RamdomDistribution(0, ntohs(DNS_Header->Answer) - 1U); size_t RamdomIndex = RamdomDistribution(*Parameter.RamdomEngine); if (RamdomIndex > 0) { memcpy_s(DNS_A_Temp.get(), sizeof(dns_record_a), Result + Length, sizeof(dns_record_a)); memset(Result + Length, 0, sizeof(dns_record_a)); memcpy_s(Result + Length, ResultSize, Result + Length + sizeof(dns_record_a) * RamdomIndex, sizeof(dns_record_a)); memset(Result + Length + sizeof(dns_record_a) * RamdomIndex, 0, sizeof(dns_record_a)); memcpy_s(Result + Length + sizeof(dns_record_a) * RamdomIndex, ResultSize, DNS_A_Temp.get(), sizeof(dns_record_a)); } } return Length + HostsTableIter.Length; } */ //Set header flags. DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Answer = htons((uint16_t)(HostsTableIter.Length / sizeof(dns_record_a))); //Hosts item length check DataLength = DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + HostsTableIter.Length; if (Parameter.EDNS_Label || DNS_Header->Additional > 0) { while (DataLength > PACKET_MAXSIZE - EDNS_ADDITIONAL_MAXSIZE) { DataLength -= sizeof(dns_record_a); DNS_Header->Answer = htons(ntohs(DNS_Header->Answer) - 1U); } } else { while (DataLength > PACKET_MAXSIZE) { DataLength -= sizeof(dns_record_a); DNS_Header->Answer = htons(ntohs(DNS_Header->Answer) - 1U); } } //Copy response to buffer. memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), 0, ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry))); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry)), HostsTableIter.Response.get(), DataLength - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry))); //Hosts load balancing if (ntohs(DNS_Header->Answer) > U16_NUM_ONE) { std::shared_ptr<dns_record_a> DNS_A_Temp(new dns_record_a()); memset(DNS_A_Temp.get(), 0, sizeof(dns_record_a)); //Select a ramdom preferred result. std::uniform_int_distribution<int> RamdomDistribution(0, ntohs(DNS_Header->Answer) - 1U); size_t RamdomIndex = RamdomDistribution(*Parameter.RamdomEngine); if (RamdomIndex > 0) { memcpy_s(DNS_A_Temp.get(), sizeof(dns_record_a), Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), sizeof(dns_record_a)); memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), 0, sizeof(dns_record_a)); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry), ResultSize - (DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry)), Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + sizeof(dns_record_a) * RamdomIndex, sizeof(dns_record_a)); memset(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + sizeof(dns_record_a) * RamdomIndex, 0, sizeof(dns_record_a)); memcpy_s(Result + DNS_PACKET_QUERY_LOCATE(Result) + sizeof(dns_qry) + sizeof(dns_record_a) * RamdomIndex, sizeof(dns_record_a), DNS_A_Temp.get(), sizeof(dns_record_a)); } } //EDNS Label if (Parameter.EDNS_Label || DNS_Header->Additional > 0) { DNS_Header->Additional = 0; DataLength = AddEDNSLabelToAdditionalRR(Result, DataLength, ResultSize, false); } return DataLength; } } } } } HostsFileMutex.unlock(); //Check DNS cache. std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock); for (auto DNSCacheDataIter:DNSCacheList) { if (Domain == DNSCacheDataIter.Domain && DNS_Query->Type == DNSCacheDataIter.RecordType) { memset(Result + sizeof(uint16_t), 0, ResultSize - sizeof(uint16_t)); memcpy_s(Result + sizeof(uint16_t), ResultSize - sizeof(uint16_t), DNSCacheDataIter.Response.get(), DNSCacheDataIter.Length); return DNSCacheDataIter.Length + sizeof(uint16_t); } } DNSCacheListMutex.unlock(); //Domain Case Conversion if (Parameter.DomainCaseConversion) MakeDomainCaseConversion(OriginalRequest + sizeof(dns_hdr)); if (IsLocal) return EXIT_CHECK_HOSTS_TYPE_LOCAL; return EXIT_SUCCESS; }
//Mark responses to domains Cache bool __fastcall MarkDomainCache(const char *Buffer, const size_t Length) { //Check conditions. auto DNS_Header = (pdns_hdr)Buffer; if ( //Not a response packet (ntohs(DNS_Header->Flags) & DNS_GET_BIT_RESPONSE) == 0 || //Question Resource Records must be one. DNS_Header->Questions != htons(U16_NUM_ONE) || //Not any Answer Resource Records DNS_Header->Answer == 0 /* && DNS_Header->Authority == 0 && DNS_Header->Additional == 0 */ || //OPCode must be set Query/0. (ntohs(DNS_Header->Flags) & DNS_GET_BIT_OPCODE) != DNS_OPCODE_QUERY || //Truncated bit must not be set. (ntohs(DNS_Header->Flags) & DNS_GET_BIT_TC) != 0 || //RCode must be set No Error or Non-Existent Domain. (ntohs(DNS_Header->Flags) & DNS_GET_BIT_RCODE) != DNS_RCODE_NOERROR && (ntohs(DNS_Header->Flags) & DNS_GET_BIT_RCODE) != DNS_RCODE_NXDOMAIN) return false; //Initialization(A part) DNSCACHE_DATA DNSCacheDataTemp; DNSCacheDataTemp.Length = 0; DNSCacheDataTemp.ClearCacheTime = 0; auto DNS_Query = (pdns_qry)(Buffer + DNS_PACKET_QUERY_LOCATE(Buffer)); DNSCacheDataTemp.RecordType = DNS_Query->Type; uint32_t ResponseTTL = 0; //Mark DNS A records and AAAA records only. if (DNSCacheDataTemp.RecordType == htons(DNS_RECORD_AAAA) || DNSCacheDataTemp.RecordType == htons(DNS_RECORD_A)) { size_t DataLength = DNS_PACKET_RR_LOCATE(Buffer), TTLCounts = 0; pdns_record_standard DNS_Record_Standard = nullptr; uint16_t DNS_Pointer = 0; //Scan all Answers Resource Records. for (size_t Index = 0;Index < (size_t)ntohs(DNS_Header->Answer);++Index) { //Pointer check if (DataLength + sizeof(uint16_t) < Length && (UCHAR)Buffer[DataLength] >= DNS_POINTER_BITS) { DNS_Pointer = ntohs(*(uint16_t *)(Buffer + DataLength)) & DNS_POINTER_BITS_GET_LOCATE; if (DNS_Pointer >= Length || DNS_Pointer < sizeof(dns_hdr) || DNS_Pointer == DataLength || DNS_Pointer == DataLength + 1U) return false; } //Resource Records Name(Domain Name) DataLength += CheckQueryNameLength(Buffer + DataLength) + 1U; if (DataLength + sizeof(dns_record_standard) > Length) break; //Standard Resource Records DNS_Record_Standard = (pdns_record_standard)(Buffer + DataLength); DataLength += sizeof(dns_record_standard); if (DataLength > Length || DNS_Record_Standard != nullptr && DataLength + ntohs(DNS_Record_Standard->Length) > Length) break; //Resource Records Data if (DNS_Record_Standard->Classes == htons(DNS_CLASS_IN) && DNS_Record_Standard->TTL > 0 && (DNS_Record_Standard->Type == htons(DNS_RECORD_AAAA) && DNS_Record_Standard->Length == htons(sizeof(in6_addr)) || DNS_Record_Standard->Type == htons(DNS_RECORD_A) && DNS_Record_Standard->Length == htons(sizeof(in_addr)))) { ResponseTTL += ntohl(DNS_Record_Standard->TTL); ++TTLCounts; } DataLength += ntohs(DNS_Record_Standard->Length); } //Calculate average TTL. if (TTLCounts > 0) ResponseTTL = ResponseTTL / (uint32_t)TTLCounts + ResponseTTL % (uint32_t)TTLCounts; } //Set cache TTL. if (ResponseTTL == 0) //Only mark A and AAAA records. { return false; } else { if (Parameter.CacheType == CACHE_TYPE_TIMER) { if (ResponseTTL * SECOND_TO_MILLISECOND < Parameter.CacheParameter) ResponseTTL = (uint32_t)(Parameter.CacheParameter / SECOND_TO_MILLISECOND - ResponseTTL + STANDARD_TIMEOUT / SECOND_TO_MILLISECOND); } else { //CACHE_TYPE_QUEUE if (ResponseTTL < Parameter.HostsDefaultTTL) ResponseTTL = Parameter.HostsDefaultTTL - ResponseTTL + STANDARD_TIMEOUT / SECOND_TO_MILLISECOND; } } //Initialization(B part) if (Length <= DOMAIN_MAXSIZE) { std::shared_ptr<char> DNSCacheDataBufferTemp(new char[DOMAIN_MAXSIZE]()); memset(DNSCacheDataBufferTemp.get(), 0, DOMAIN_MAXSIZE); DNSCacheDataTemp.Response.swap(DNSCacheDataBufferTemp); } else { std::shared_ptr<char> DNSCacheDataBufferTemp(new char[Length]()); memset(DNSCacheDataBufferTemp.get(), 0, Length); DNSCacheDataTemp.Response.swap(DNSCacheDataBufferTemp); } //Mark to global list. if (DNSQueryToChar(Buffer + sizeof(dns_hdr), DNSCacheDataTemp.Response.get()) > DOMAIN_MINSIZE) { //Domain Case Conversion CaseConvert(false, DNSCacheDataTemp.Response.get(), strnlen_s(DNSCacheDataTemp.Response.get(), DOMAIN_MAXSIZE)); DNSCacheDataTemp.Domain = DNSCacheDataTemp.Response.get(); memset(DNSCacheDataTemp.Response.get(), 0, DOMAIN_MAXSIZE); memcpy_s(DNSCacheDataTemp.Response.get(), PACKET_MAXSIZE, Buffer + sizeof(uint16_t), Length - sizeof(uint16_t)); DNSCacheDataTemp.Length = Length - sizeof(uint16_t); //Minimum supported system of GetTickCount64() is Windows Vista(Windows XP with SP3 support). #if (defined(PLATFORM_WIN32) && !defined(PLATFORM_WIN64)) if (Parameter.FunctionPTR_GetTickCount64 != nullptr) DNSCacheDataTemp.ClearCacheTime = (size_t)((*Parameter.FunctionPTR_GetTickCount64)() + ResponseTTL * SECOND_TO_MILLISECOND); else DNSCacheDataTemp.ClearCacheTime = GetTickCount() + ResponseTTL * SECOND_TO_MILLISECOND; #else DNSCacheDataTemp.ClearCacheTime = GetTickCount64() + ResponseTTL * SECOND_TO_MILLISECOND; #endif std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock); //Check repeating items, delete duque rear and add new item to deque front. for (auto DNSCacheDataIter = DNSCacheList.begin();DNSCacheDataIter != DNSCacheList.end();++DNSCacheDataIter) { if (DNSCacheDataTemp.Domain == DNSCacheDataIter->Domain && DNSCacheDataTemp.RecordType == DNSCacheDataIter->RecordType) { DNSCacheList.erase(DNSCacheDataIter); break; } } if (Parameter.CacheType == CACHE_TYPE_QUEUE) { while (DNSCacheList.size() > Parameter.CacheParameter) DNSCacheList.pop_front(); } else { //CACHE_TYPE_TIMER //Minimum supported system of GetTickCount64() is Windows Vista(Windows XP with SP3 support). #if (defined(PLATFORM_WIN32) && !defined(PLATFORM_WIN64)) while (!DNSCacheList.empty() && (Parameter.FunctionPTR_GetTickCount64 != nullptr && (*Parameter.FunctionPTR_GetTickCount64)() >= DNSCacheList.front().ClearCacheTime || GetTickCount() >= DNSCacheList.front().ClearCacheTime)) #else while (!DNSCacheList.empty() && GetTickCount64() >= DNSCacheList.front().ClearCacheTime) #endif DNSCacheList.pop_front(); } DNSCacheList.push_back(DNSCacheDataTemp); DNSCacheList.shrink_to_fit(); return true; } return false; }
//Check hosts from global list size_t __fastcall CheckHostsProcess( DNS_PACKET_DATA *Packet, char *Result, const size_t ResultSize) { //Initilization std::string Domain; size_t DataLength = 0; auto DNS_Header = (pdns_hdr)Packet->Buffer; //Request check if (DNS_Header->Question == htons(U16_NUM_ONE) && CheckQueryNameLength(Packet->Buffer + sizeof(dns_hdr)) + 1U < DOMAIN_MAXSIZE) { if (DNSQueryToChar(Packet->Buffer + sizeof(dns_hdr), Domain) <= DOMAIN_MINSIZE) return EXIT_SUCCESS; else CaseConvert(false, Domain); } else { return EXIT_FAILURE; } //Response setting memset(Result, 0, ResultSize); memcpy_s(Result, ResultSize, Packet->Buffer, Packet->Length); DNS_Header = (pdns_hdr)Result; auto DNS_Query = (pdns_qry)(Result + DNS_PACKET_QUERY_LOCATE(Result)); //Check Classes. if (DNS_Query->Classes != htons(DNS_CLASS_IN)) return EXIT_FAILURE; //Check Accept Types list. if (Parameter.AcceptTypeList != nullptr) { //Permit if (Parameter.AcceptType) { for (auto AcceptTypeTableIter = Parameter.AcceptTypeList->begin();AcceptTypeTableIter != Parameter.AcceptTypeList->end();++AcceptTypeTableIter) { if (AcceptTypeTableIter + 1U == Parameter.AcceptTypeList->end()) { if (*AcceptTypeTableIter != DNS_Query->Type) { // DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R_SNH); DNS_Header->Flags = htons(DNS_SET_R_SNH); return Packet->Length; } } else if (*AcceptTypeTableIter == DNS_Query->Type) { break; } } } //Deny else { for (auto AcceptTypeTableIter:*Parameter.AcceptTypeList) { if (DNS_Query->Type == AcceptTypeTableIter) { // DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R_SNH); DNS_Header->Flags = htons(DNS_SET_R_SNH); return Packet->Length; } } } } //PTR Records //LLMNR protocol of Mac OS X powered by mDNS with PTR records #if (defined(PLATFORM_WIN) || defined(PLATFORM_LINUX)) if (DNS_Query->Type == htons(DNS_RECORD_PTR) && Parameter.LocalServer_Length + Packet->Length <= ResultSize) { auto IsSendPTR = false; //IPv6 check if (Domain == ("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") || //Loopback address(::1, Section 2.5.3 in RFC 4291) //IPv4 check Domain.find(".127.in-addr.arpa") != std::string::npos || //Loopback address(127.0.0.0/8, Section 3.2.1.3 in RFC 1122) Domain.find(".254.169.in-addr.arpa") != std::string::npos) //Link-local address(169.254.0.0/16, RFC 3927) { IsSendPTR = true; } else { //IPv6 check std::unique_lock<std::mutex> LocalAddressMutexIPv6(LocalAddressLock[0]); for (auto StringIter:*GlobalRunningStatus.LocalAddress_ResponsePTR[0]) { if (Domain == StringIter) { IsSendPTR = true; break; } } LocalAddressMutexIPv6.unlock(); //IPv4 check if (!IsSendPTR) { std::lock_guard<std::mutex> LocalAddressMutexIPv4(LocalAddressLock[1U]); for (auto StringIter:*GlobalRunningStatus.LocalAddress_ResponsePTR[1U]) { if (Domain == StringIter) { IsSendPTR = true; break; } } } } //Send Localhost PTR. if (IsSendPTR) { //Set header flags and copy response to buffer. DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SER_RA); DNS_Header->Answer = htons(U16_NUM_ONE); DNS_Header->Authority = 0; DNS_Header->Additional = 0; memset(Result + sizeof(dns_hdr) + Packet->Question, 0, Packet->Length - (sizeof(dns_hdr) + Packet->Question)); memcpy_s(Result + sizeof(dns_hdr) + Packet->Question, ResultSize - (sizeof(dns_hdr) + Packet->Question), Parameter.LocalServer_Response, Parameter.LocalServer_Length); DataLength = sizeof(dns_hdr) + Packet->Question + Parameter.LocalServer_Length; //EDNS Label if (Parameter.EDNS_Label || Packet->EDNS_Record > 0) DataLength = AddEDNSLabelToAdditionalRR(Result, DataLength, ResultSize, nullptr); return DataLength; } } #endif //LocalFQDN check if (Parameter.LocalFQDN_String != nullptr && Domain == *Parameter.LocalFQDN_String) { //IPv6 if (DNS_Query->Type == htons(DNS_RECORD_AAAA)) { std::lock_guard<std::mutex> LocalAddressMutexIPv6(LocalAddressLock[0]); if (GlobalRunningStatus.LocalAddress_Length[0] >= DNS_PACKET_MINSIZE) { memset(Result + sizeof(uint16_t), 0, ResultSize - sizeof(uint16_t)); memcpy_s(Result + sizeof(uint16_t), ResultSize - sizeof(uint16_t), GlobalRunningStatus.LocalAddress_Response[0] + sizeof(uint16_t), GlobalRunningStatus.LocalAddress_Length[0] - sizeof(uint16_t)); return GlobalRunningStatus.LocalAddress_Length[0]; } } //IPv4 else if (DNS_Query->Type == htons(DNS_RECORD_A)) { std::lock_guard<std::mutex> LocalAddressMutexIPv4(LocalAddressLock[1U]); if (GlobalRunningStatus.LocalAddress_Length[1U] >= DNS_PACKET_MINSIZE) { memset(Result + sizeof(uint16_t), 0, ResultSize - sizeof(uint16_t)); memcpy_s(Result + sizeof(uint16_t), ResultSize - sizeof(uint16_t), GlobalRunningStatus.LocalAddress_Response[1U] + sizeof(uint16_t), GlobalRunningStatus.LocalAddress_Length[1U] - sizeof(uint16_t)); return GlobalRunningStatus.LocalAddress_Length[1U]; } } } //Check DNS cache. std::unique_lock<std::mutex> DNSCacheListMutex(DNSCacheListLock); for (auto DNSCacheDataIter:DNSCacheList) { if (Domain == DNSCacheDataIter.Domain && DNS_Query->Type == DNSCacheDataIter.RecordType) { memset(Result + sizeof(uint16_t), 0, ResultSize - sizeof(uint16_t)); memcpy_s(Result + sizeof(uint16_t), ResultSize - sizeof(uint16_t), DNSCacheDataIter.Response.get(), DNSCacheDataIter.Length); return DNSCacheDataIter.Length + sizeof(uint16_t); } } DNSCacheListMutex.unlock(); //Local Main check if (Parameter.LocalMain) Packet->IsLocal = true; //Main check std::unique_lock<std::mutex> HostsFileMutex(HostsFileLock); for (auto HostsFileSetIter:*HostsFileSetUsing) { //Normal Hosts for (auto HostsTableIter:HostsFileSetIter.HostsList_Normal) { if (std::regex_match(Domain, HostsTableIter.Pattern)) { //Check white and banned hosts list, empty record type list check DataLength = CheckWhiteBannedHostsProcess(Packet->Length, HostsTableIter, DNS_Header, DNS_Query, &Packet->IsLocal); if (DataLength >= DNS_PACKET_MINSIZE) return DataLength; else if (DataLength == EXIT_FAILURE) goto StopLoop; //Initialization void *DNS_Record = nullptr; size_t RamdomIndex = 0, Index = 0; //IPv6(AAAA records) if (DNS_Query->Type == htons(DNS_RECORD_AAAA) && HostsTableIter.RecordTypeList.front() == htons(DNS_RECORD_AAAA)) { //Set header flags and convert DNS query to DNS response packet. // DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Flags = htons(DNS_SQR_NE); DataLength = sizeof(dns_hdr) + Packet->Question; memset(Result + DataLength, 0, ResultSize - DataLength); //Hosts load balancing if (HostsTableIter.AddrList.size() > 1U) { std::uniform_int_distribution<size_t> RamdomDistribution(0, HostsTableIter.AddrList.size() - 1U); RamdomIndex = RamdomDistribution(*GlobalRunningStatus.RamdomEngine); } //Make response. for (Index = 0;Index < HostsTableIter.AddrList.size();++Index) { //Make resource records. DNS_Record = (pdns_record_aaaa)(Result + DataLength); DataLength += sizeof(dns_record_aaaa); ((pdns_record_aaaa)DNS_Record)->Name = htons(DNS_POINTER_QUERY); ((pdns_record_aaaa)DNS_Record)->Classes = htons(DNS_CLASS_IN); ((pdns_record_aaaa)DNS_Record)->TTL = htonl(Parameter.HostsDefaultTTL); ((pdns_record_aaaa)DNS_Record)->Type = htons(DNS_RECORD_AAAA); ((pdns_record_aaaa)DNS_Record)->Length = htons(sizeof(in6_addr)); if (Index == 0) ((pdns_record_aaaa)DNS_Record)->Addr = HostsTableIter.AddrList.at(RamdomIndex).IPv6.sin6_addr; else if (Index == RamdomIndex) ((pdns_record_aaaa)DNS_Record)->Addr = HostsTableIter.AddrList.at(0).IPv6.sin6_addr; else ((pdns_record_aaaa)DNS_Record)->Addr = HostsTableIter.AddrList.at(Index).IPv6.sin6_addr; //Hosts items length check if ((Parameter.EDNS_Label || Packet->EDNS_Record > 0) && DataLength + sizeof(dns_record_aaaa) + EDNS_ADDITIONAL_MAXSIZE >= ResultSize || //EDNS Label DataLength + sizeof(dns_record_aaaa) >= ResultSize) //Normal query { ++Index; break; } } //Set DNS counts and EDNS Label DNS_Header->Answer = htons((uint16_t)Index); DNS_Header->Authority = 0; DNS_Header->Additional = 0; if (Parameter.EDNS_Label || Packet->EDNS_Record > 0) DataLength = AddEDNSLabelToAdditionalRR(Result, DataLength, ResultSize, nullptr); return DataLength; } //IPv4(A records) else if (DNS_Query->Type == htons(DNS_RECORD_A) && HostsTableIter.RecordTypeList.front() == htons(DNS_RECORD_A)) { //Set header flags and convert DNS query to DNS response packet. // DNS_Header->Flags = htons(ntohs(DNS_Header->Flags) | DNS_SET_R); DNS_Header->Flags = htons(DNS_SQR_NE); DataLength = sizeof(dns_hdr) + Packet->Question; memset(Result + DataLength, 0, ResultSize - DataLength); //Hosts load balancing if (HostsTableIter.AddrList.size() > 1U) { std::uniform_int_distribution<size_t> RamdomDistribution(0, HostsTableIter.AddrList.size() - 1U); RamdomIndex = RamdomDistribution(*GlobalRunningStatus.RamdomEngine); } //Make response. for (Index = 0;Index < HostsTableIter.AddrList.size();++Index) { //Make resource records. DNS_Record = (pdns_record_a)(Result + DataLength); DataLength += sizeof(dns_record_a); ((pdns_record_a)DNS_Record)->Name = htons(DNS_POINTER_QUERY); ((pdns_record_a)DNS_Record)->Classes = htons(DNS_CLASS_IN); ((pdns_record_a)DNS_Record)->TTL = htonl(Parameter.HostsDefaultTTL); ((pdns_record_a)DNS_Record)->Type = htons(DNS_RECORD_A); ((pdns_record_a)DNS_Record)->Length = htons(sizeof(in_addr)); if (Index == 0) ((pdns_record_a)DNS_Record)->Addr = HostsTableIter.AddrList.at(RamdomIndex).IPv4.sin_addr; else if (Index == RamdomIndex) ((pdns_record_a)DNS_Record)->Addr = HostsTableIter.AddrList.at(0).IPv4.sin_addr; else ((pdns_record_a)DNS_Record)->Addr = HostsTableIter.AddrList.at(Index).IPv4.sin_addr; //Hosts items length check if ((Parameter.EDNS_Label || Packet->EDNS_Record > 0) && DataLength + sizeof(dns_record_a) + EDNS_ADDITIONAL_MAXSIZE >= ResultSize || //EDNS Label DataLength + sizeof(dns_record_a) >= ResultSize) //Normal query { ++Index; break; } } //Set DNS counts and EDNS Label DNS_Header->Answer = htons((uint16_t)Index); DNS_Header->Authority = 0; DNS_Header->Additional = 0; if (Parameter.EDNS_Label || Packet->EDNS_Record > 0) DataLength = AddEDNSLabelToAdditionalRR(Result, DataLength, ResultSize, nullptr); return DataLength; } } } //Local Hosts for (auto HostsTableIter:HostsFileSetIter.HostsList_Local) { if (std::regex_match(Domain, HostsTableIter.Pattern)) { //Check white and banned hosts list. DataLength = CheckWhiteBannedHostsProcess(Packet->Length, HostsTableIter, DNS_Header, DNS_Query, &Packet->IsLocal); if (DataLength >= DNS_PACKET_MINSIZE) return DataLength; else if (DataLength == EXIT_FAILURE) Packet->IsLocal = false; else //IsLocal flag setting Packet->IsLocal = true; goto StopLoop; } } } //Jump here to stop loop. StopLoop: HostsFileMutex.unlock(); //Domain Case Conversion if (Parameter.DomainCaseConversion) MakeDomainCaseConversion(Packet->Buffer + sizeof(dns_hdr)); return EXIT_SUCCESS; }