protected virtual void CacheRecords(IReadOnlyList <DnsResourceRecord> resourceRecords) { if (resourceRecords.Count == 1) { DnsCacheEntry entry = _cache.GetOrAdd(resourceRecords[0].Name.ToLower(), delegate(string key) { return(new DnsCacheEntry()); }); entry.SetRecords(resourceRecords[0].Type, resourceRecords); } else { Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntries = DnsResourceRecord.GroupRecords(resourceRecords); //add grouped entries into cache foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntry in cacheEntries) { DnsCacheEntry entry = _cache.GetOrAdd(cacheEntry.Key.ToLower(), delegate(string key) { return(new DnsCacheEntry()); }); foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntry in cacheEntry.Value) { entry.SetRecords(cacheTypeEntry.Key, cacheTypeEntry.Value); } } } }
private void CacheEntry(string domain, DnsResourceRecordType type, DnsResourceRecord[] records) { domain = domain.ToLower(); DnsCacheEntry entry = _cache.GetOrAdd(domain, delegate(string key) { return(new DnsCacheEntry()); }); entry.Add(type, records); }
/// <inheritdoc/> public async Task <DnsAnswer> Query(DnsHeader query, CancellationToken token) { string cacheKey = GetCacheKey(query); DnsAnswer answer; var cacheEntry = (DnsCacheEntry)_objectCache.Get(cacheKey); if (cacheEntry != null) { _logger.LogTrace("Returned cached DNS result for {Domain} (expires in: {ExpiryTime})", query.Host, cacheEntry.Expires); answer = DnsByteExtensions.FromBytes <DnsAnswer>(cacheEntry.Data); // Replace the ID answer.Header.Id = query.Id; // Adjust the TTLs to be correct foreach (var record in answer.Answers) { record.TimeToLive -= cacheEntry.Age; } return(answer); } answer = await _dnsClient.Query(new DnsHeader { Id = query.Id, Host = query.Host, IsQueryResponse = false, RecusionDesired = query.RecusionDesired, QueryClass = query.QueryClass, QueryType = query.QueryType, QuestionCount = query.QuestionCount }, token); _logger.LogTrace("Returned fresh DNS result for {Domain}", query.Host); if (answer.Answers.Count > 0) { cacheEntry = new DnsCacheEntry(answer); _objectCache.Add(cacheKey, cacheEntry, new CacheItemPolicy { AbsoluteExpiration = cacheEntry.Expiry }); } return(answer); }
private List <DnsCacheEntry> ResolveRedir(DnsCacheEntry CurEntry, int Level = 0) { List <DnsCacheEntry> EntryList = new List <DnsCacheEntry>(); CloneableList <DnsCacheEntry> NameEntries; if (Level >= 4 || !cacheByStr.TryGetValue(CurEntry.HostName, out NameEntries)) // dont get trapped in an endles recursion { EntryList.Add(CurEntry); } else { foreach (DnsCacheEntry NameEntry in NameEntries) { EntryList.AddRange(ResolveRedir(NameEntry, Level + 1)); } } return(EntryList); }
public void CleanupCache() { DateTime ExpirationLimit = DateTime.Now.AddMinutes(App.GetConfigInt("DnsInspector", "CacheRetention", 15)); foreach (var Name in dnsCache.Keys.ToList()) { CloneableList <DnsCacheEntry> curEntries = dnsCache[Name]; for (int i = 0; i < curEntries.Count; i++) { DnsCacheEntry curEntry = curEntries[i]; if (curEntry.ExpirationTime < ExpirationLimit) { if (curEntry.RecordType == DnsApi.DnsRecordType.A || curEntry.RecordType == DnsApi.DnsRecordType.AAAA) { if (curEntry.Address != null) { cacheByIP.Remove(curEntry.Address, curEntry); } } else // CNAME, SRV, MX, DNAME { if (curEntry.ResolvedString != null) { cacheByStr.Remove(curEntry.ResolvedString, curEntry); } } curEntries.RemoveAt(i--); } } if (curEntries.Count == 0) { dnsCache.Remove(Name); } } }
private void AddCacheEntry(CloneableList <DnsCacheEntry> curEntries, DnsCacheEntry curEntry) { curEntries.Add(curEntry); if ((curEntry.RecordType == DnsApi.DnsRecordType.A || curEntry.RecordType == DnsApi.DnsRecordType.AAAA) && curEntry.Address != null) { if (curEntry.Address != null) { cacheByIP.Add(curEntry.Address, curEntry); } } else if (curEntry.ResolvedString != null) // CNAME, SRV, MX, DNAME { if (curEntry.ResolvedString != null) { cacheByStr.Add(curEntry.ResolvedString, curEntry); } } DnsCacheEvent?.Invoke(this, new DnsEvent() { Entry = curEntry }); }
public UInt32[] ResolveHostNameToIpAddresses(string name, out string canonicalName, Int64 timeoutInMachineTicks) { UInt32[] dnsServerAddresses = _ipv4Layer.DnsServerAddresses; if (dnsServerAddresses.Length < 1) { /* could not resolve DNS entry */ throw Utility.NewSocketException(SocketError.NoRecovery); /* no DNS server is configured */ } /* NOTE: this DNS resolver assumes that all names are Internet domains. */ // ensure that the domain is rooted. if (name.Substring(name.Length - 1) != ".") { name += "."; } /* first, return a response from our dns cache if a valid response is already cached */ lock (_dnsCacheLock) { DnsCacheEntry dnsEntry = (DnsCacheEntry)_dnsCache[name.ToLower()]; // if we retrieved an entry, make sure it has not timed out. if (dnsEntry != null) { Int64 nowTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks; if (dnsEntry.ExpirationTicks < nowTicks) { // if the entry has timed out, dispose of it; we will re-query the target _dnsCache.Remove(name.ToLower()); dnsEntry = null; } else { dnsEntry.LastUsedTicks = nowTicks; // update "last used" timestamp canonicalName = dnsEntry.CanonicalName; return(dnsEntry.IpAddresses); } } } // by default, set our canonicalName to the passed-in name canonicalName = name; Int64 expirationInMachineTicks = Int64.MaxValue; DnsResponse response = null; for (int iDnsServer = 0; iDnsServer < dnsServerAddresses.Length; iDnsServer++) { // set our query timeout to the maximum of DNS_QUERY_TIMEOUT_MS and the hard timeout passed into our function. Int64 queryTimeoutInMachineTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks + (DNS_QUERY_TIMEOUT_MS * TimeSpan.TicksPerMillisecond); if (queryTimeoutInMachineTicks > timeoutInMachineTicks) { queryTimeoutInMachineTicks = timeoutInMachineTicks; } // query this DNS server and wait for a response (until a maximum time of queryTimeoutInMachineTicks) bool success = SendDnsQueryAndWaitForResponse(dnsServerAddresses[iDnsServer], DnsRecordType.A, name, out response, queryTimeoutInMachineTicks); if (success) { break; } } if (response == null) { throw Utility.NewSocketException(SocketError.TryAgain); /* no response received from any dns server */ } switch (response.ResponseCode) { case DnsResponseCode.NoError: break; /* success */ case DnsResponseCode.NXDomain: throw Utility.NewSocketException(SocketError.HostNotFound); case DnsResponseCode.Refused: throw Utility.NewSocketException(SocketError.NoRecovery); case DnsResponseCode.ServFail: throw Utility.NewSocketException(SocketError.TryAgain); default: break; /* in theory, some errors could actually have valid data, so ignore other errors for now. */ } System.Collections.ArrayList ipAddressList = new System.Collections.ArrayList(); for (int iRecord = 0; iRecord < response.AnswerRecords.Length; iRecord++) { if (response.AnswerRecords[iRecord].RecordType == DnsRecordType.A) { canonicalName = response.AnswerRecords[iRecord].Name; Int64 currentTimeoutTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks + (response.AnswerRecords[iRecord].TimeToLive * TimeSpan.TicksPerSecond); if (currentTimeoutTicks < expirationInMachineTicks) { expirationInMachineTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks + (response.AnswerRecords[iRecord].TimeToLive * TimeSpan.TicksPerSecond); } ipAddressList.Add( ((UInt32)response.AnswerRecords[iRecord].Data[0] << 24) + ((UInt32)response.AnswerRecords[iRecord].Data[1] << 16) + ((UInt32)response.AnswerRecords[iRecord].Data[2] << 8) + ((UInt32)response.AnswerRecords[iRecord].Data[3]) ); } } if (ipAddressList.Count > 0) { // add the host to our DNS cache lock (_dnsCacheLock) { // first make sure that our cache table is not full; if it is full then remove the oldest entry (based on LastAccessedInMachineTicks) if (_dnsCache.Count >= DNS_CACHE_MAXIMUM_ENTRIES) { Int64 oldestLastUsedTicks = Int64.MaxValue; string oldestKey = string.Empty; foreach (string key in _dnsCache.Keys) { if (((DnsCacheEntry)_dnsCache[key]).LastUsedTicks < oldestLastUsedTicks) { oldestKey = key; oldestLastUsedTicks = ((DnsCacheEntry)_dnsCache[key]).LastUsedTicks; } } _dnsCache.Remove(oldestKey); } DnsCacheEntry dnsEntry = new DnsCacheEntry(name, canonicalName, (UInt32[])ipAddressList.ToArray(typeof(UInt32)), expirationInMachineTicks, Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks); _dnsCache.Add(name.ToLower(), dnsEntry); } } if (ipAddressList.Count == 0) { throw Utility.NewSocketException(SocketError.NoData); } UInt32[] addresses = (UInt32[])ipAddressList.ToArray(typeof(UInt32)); return(addresses); }
public void SyncCache() { var dnsCacheDataTable = IntPtr.Zero; if (DnsGetCacheDataTable_I == null || !DnsGetCacheDataTable_I(out dnsCacheDataTable)) { return; } DateTime CurrentTime = DateTime.Now; // cache domains //var oldCache = new HashSet<string>(dnsCache.Keys); foreach (DnsCacheEntry cacheEntry in dnsCache.GetAllValues()) { if (cacheEntry.ExpirationTime > CurrentTime) { cacheEntry.ExpirationTime = CurrentTime; } // will be reset in the loop, efectivly timeouting all flushed entries imminetly } for (var tablePtr = dnsCacheDataTable; tablePtr != IntPtr.Zero;) { var entry = (DnsApi.DnsCacheEntry)Marshal.PtrToStructure(tablePtr, typeof(DnsApi.DnsCacheEntry)); tablePtr = entry.Next; // Note: DnsGetCacheDataTable_I should only return one result per domain name in cache mo mater how many entries there are // DnsQuery wil retrive all entries of any type for a given domain name thanks to DNS_QUERY_UN_DOCUMENTED var resultPtr = IntPtr.Zero; uint ret = DnsApi.DnsQuery(entry.Name, entry.Type, DnsApi.DnsQueryType.DNS_QUERY_NO_WIRE_QUERY | DnsApi.DnsQueryType.DNS_QUERY_UN_DOCUMENTED, IntPtr.Zero, ref resultPtr, IntPtr.Zero); if (ret != DnsApi.ERROR_SUCCESS) { continue; } //AppLog.Debug("DnsEntries: " + entry.Name); // get all entries for thisdomain name /*CloneableList<DnsCacheEntry> curEntries = null; * if (!dnsCache.TryGetValue(entry.Name, out curEntries)) * { * curEntries = new CloneableList<DnsCacheEntry>(); * dnsCache.Add(entry.Name, curEntries); * } * else * oldCache.Remove(entry.Name);*/ for (var recordIndexPtr = resultPtr; recordIndexPtr != IntPtr.Zero;) { var record = (DnsApi.DnsRecord)Marshal.PtrToStructure(recordIndexPtr, typeof(DnsApi.DnsRecord)); int offset = Marshal.OffsetOf(typeof(DnsApi.DnsRecord), "Data").ToInt32(); IntPtr data = recordIndexPtr + offset; recordIndexPtr = record.Next; string HostName = record.Name; IPAddress Address = null; string ResolvedString = null; CloneableList <DnsCacheEntry> curEntries = GetEntriesFor(HostName); DnsCacheEntry curEntry = null; if (record.Type == DnsApi.DnsRecordType.A || record.Type == DnsApi.DnsRecordType.AAAA) { switch (record.Type) { case DnsApi.DnsRecordType.A: { var ptr = (DnsApi.DnsARecord)Marshal.PtrToStructure(data, typeof(DnsApi.DnsARecord)); Address = new IPAddress((UInt32)ptr.IpAddress); break; } case DnsApi.DnsRecordType.AAAA: { var ptr = (DnsApi.DnsAAAARecord)Marshal.PtrToStructure(data, typeof(DnsApi.DnsAAAARecord)); Address = new IPAddress(ptr.IpAddress); break; } } if (Address.Equals(IPAddress.Any) || Address.Equals(IPAddress.IPv6Any)) // thats wht we get from a pi hole dns proxy if the domain is blocked { Address = null; } curEntry = curEntries.FirstOrDefault(e => { return(e.RecordType == record.Type && MiscFunc.IsEqual(e.Address, Address)); }); } else // CNAME, SRV, MX, DNAME { switch (record.Type) { //case DnsApi.DnsRecordType.PTR: // Address = RevDnsHost2Address(HostName); // goto case DnsApi.DnsRecordType.CNAME; //case DnsApi.DnsRecordType.DNAME: // entire zone case DnsApi.DnsRecordType.CNAME: // one host { var ptr = (DnsApi.DnsPTRRecord)Marshal.PtrToStructure(data, typeof(DnsApi.DnsPTRRecord)); ResolvedString = ptr.NameHost; break; } /*case DnsApi.DnsRecordType.SRV: * { * var ptr = (DnsApi.DnsSRVRecord)Marshal.PtrToStructure(data, typeof(DnsApi.DnsSRVRecord)); * ResolvedString = ptr.NameTarget + ":" + ptr.Port; * break; * } * case DnsApi.DnsRecordType.MX: * { * var ptr = (DnsApi.DnsMXRecord)Marshal.PtrToStructure(data, typeof(DnsApi.DnsMXRecord)); * ResolvedString = ptr.NameExchange; * break; * }*/ default: continue; } if (ResolvedString.Equals("null.arpa")) // I invented that or the DnsProxyServer so probably no one else uses it { ResolvedString = null; } curEntry = curEntries.FirstOrDefault(e => { return(e.RecordType == record.Type && MiscFunc.IsEqual(e.ResolvedString, ResolvedString)); }); } if (curEntry == null) { curEntry = new DnsCacheEntry() { HostName = HostName, RecordType = record.Type }; curEntry.ExpirationTime = CurrentTime.AddSeconds(record.Ttl); if (Address == null && ResolvedString == null) { curEntry.State = DnsCacheEntry.States.Blocked; } else { curEntry.State = DnsCacheEntry.States.Resolved; } curEntry.Address = Address; curEntry.ResolvedString = ResolvedString; AddCacheEntry(curEntries, curEntry); } else // just update { curEntry.ExpirationTime = CurrentTime.AddSeconds(record.Ttl); } } if (resultPtr != IntPtr.Zero) { DnsApi.DnsRecordListFree(resultPtr, DnsApi.DnsFreeType.DnsFreeRecordList); } } /*DateTime ExpirationLimit = CurrentTime.AddMinutes(App.GetConfigInt("DnsInspector", "CacheRetention", 15)); * // remove old entries * foreach (var Name in oldCache) * { * CloneableList<DnsCacheEntry> curEntries = dnsCache[Name]; * for (int i = 0; i < curEntries.Count; i++) * { * DnsCacheEntry curEntry = curEntries[i]; * if (curEntry.ExpirationTime < ExpirationLimit) * { * if (curEntry.RecordType == DnsApi.DnsRecordType.A || curEntry.RecordType == DnsApi.DnsRecordType.AAAA) * cacheByIP.Remove(curEntry.Address, curEntry); * else // CNAME, SRV, MX, DNAME * cacheByStr.Remove(curEntry.ResolvedString, curEntry); * * curEntries.RemoveAt(i--); * } * } * if (curEntries.Count == 0) * dnsCache.Remove(Name); * }*/ DnsApi.DnsRecordListFree(dnsCacheDataTable, DnsApi.DnsFreeType.DnsFreeRecordList); }
private void OnDnsQueryEvent(Microsoft.O365.Security.ETW.IEventRecord record) { // WARNING: this function is called from the worker thread if (record.Id != 1001) { return; } if (record.GetUInt32("Status", 0) != 0) { return; } int ProcessId = (int)record.ProcessId; int ThreadId = (int)record.ThreadId; var HostName = record.GetUnicodeString("NodeName", null); var Results = record.GetUnicodeString("Result", null); if (ProcessId == ProcFunc.CurID) { return; // ignore these events as thay are the result of reverse dns querries.... } /* * "192.168.163.1" "192.168.163.1;" * "localhost" "[::1]:8307;127.0.0.1:8307;" <- wtf is this why is there a port?! * "DESKTOP" "fe80::189a:f1c3:3e87:be81%12;192.168.10.12;" * "telemetry.malwarebytes.com" "54.149.69.204;54.200.191.52;54.70.191.27;54.149.66.105;54.244.17.248;54.148.98.86;" * "web.whatsapp.com" "31.13.84.51;" */ App.engine?.RunInEngineThread(() => { // Note: this happens in the engine thread DnsQueryEvent?.Invoke(this, new DnsEvent() { ProcessId = ProcessId, HostName = HostName }); foreach (string Result in Results.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { IPAddress Address = null; if (!IPAddress.TryParse(Result, out Address) && !IPAddress.TryParse(TextHelpers.Split2(Result, ":", true).Item1, out Address)) { continue; } OnHostName(ProcessId, Address, HostName); Dictionary <IPAddress, Dictionary <string, DnsCacheEntry> > dnsCache = dnsQueryCache.GetOrCreate(ProcessId); Dictionary <string, DnsCacheEntry> cacheEntries = dnsCache.GetOrCreate(Address); DnsCacheEntry cacheEntry = cacheEntries.GetOrCreate(HostName); cacheEntry.Counter++; } }); }
public UInt32[] ResolveHostNameToIpAddresses(string name, out string canonicalName, Int64 timeoutInMachineTicks) { UInt32[] dnsServerAddresses = _ipv4Layer.DnsServerAddresses; if (dnsServerAddresses.Length < 1) { /* could not resolve DNS entry */ throw Utility.NewSocketException(SocketError.NoRecovery); /* no DNS server is configured */ } /* NOTE: this DNS resolver assumes that all names are Internet domains. */ // ensure that the domain is rooted. if (name.Substring(name.Length - 1) != ".") { name += "."; } /* first, return a response from our dns cache if a valid response is already cached */ lock (_dnsCacheLock) { DnsCacheEntry dnsEntry = (DnsCacheEntry)_dnsCache[name.ToLower()]; // if we retrieved an entry, make sure it has not timed out. if (dnsEntry != null) { Int64 nowTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks; if (dnsEntry.ExpirationTicks < nowTicks) { // if the entry has timed out, dispose of it; we will re-query the target _dnsCache.Remove(name.ToLower()); dnsEntry = null; } else { dnsEntry.LastUsedTicks = nowTicks; // update "last used" timestamp canonicalName = dnsEntry.CanonicalName; return dnsEntry.IpAddresses; } } } // by default, set our canonicalName to the passed-in name canonicalName = name; Int64 expirationInMachineTicks = Int64.MaxValue; double millisecondsWaitTimeBetweenDnsQueries = (4000.0 / Math.Max((double)(dnsServerAddresses.Length - 1), 1.0)); DnsResponse response = null; for (int iDnsServer = 0; iDnsServer < dnsServerAddresses.Length; iDnsServer++) { response = SendDnsQueryAndWaitForResponse(dnsServerAddresses[iDnsServer], DnsRecordType.A, name, timeoutInMachineTicks); if (response != null) break; Int32 waitTimeInMilliseconds = (Int32)System.Math.Min(((timeoutInMachineTicks - Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks) / TimeSpan.TicksPerMillisecond), millisecondsWaitTimeBetweenDnsQueries); if (waitTimeInMilliseconds > 0) Thread.Sleep(waitTimeInMilliseconds); } if (response == null) { throw Utility.NewSocketException(SocketError.TryAgain); /* no response received from any dns server */ } switch (response.ResponseCode) { case DnsResponseCode.NoError: break; /* success */ case DnsResponseCode.NXDomain: throw Utility.NewSocketException(SocketError.HostNotFound); case DnsResponseCode.Refused: throw Utility.NewSocketException(SocketError.NoRecovery); case DnsResponseCode.ServFail: throw Utility.NewSocketException(SocketError.TryAgain); default: break; /* in theory, some errors could actually have valid data, so ignore other errors for now. */ } System.Collections.ArrayList ipAddressList = new System.Collections.ArrayList(); for (int iRecord = 0; iRecord < response.AnswerRecords.Length; iRecord++) { if (response.AnswerRecords[iRecord].RecordType == DnsRecordType.A) { canonicalName = response.AnswerRecords[iRecord].Name; Int64 currentTimeoutTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks + (response.AnswerRecords[iRecord].TimeToLive * TimeSpan.TicksPerSecond); if (currentTimeoutTicks < expirationInMachineTicks) { expirationInMachineTicks = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks + (response.AnswerRecords[iRecord].TimeToLive * TimeSpan.TicksPerSecond); } ipAddressList.Add( ((UInt32)response.AnswerRecords[iRecord].Data[0] << 24) + ((UInt32)response.AnswerRecords[iRecord].Data[1] << 16) + ((UInt32)response.AnswerRecords[iRecord].Data[2] << 8) + ((UInt32)response.AnswerRecords[iRecord].Data[3]) ); } } if (ipAddressList.Count > 0) { // add the host to our DNS cache lock (_dnsCacheLock) { // first make sure that our cache table is not full; if it is full then remove the oldest entry (based on LastAccessedInMachineTicks) if (_dnsCache.Count >= DNS_CACHE_MAXIMUM_ENTRIES) { Int64 oldestLastUsedTicks = Int64.MaxValue; string oldestKey = string.Empty; foreach (string key in _dnsCache.Keys) { if (((DnsCacheEntry)_dnsCache[key]).LastUsedTicks < oldestLastUsedTicks) { oldestKey = key; oldestLastUsedTicks = ((DnsCacheEntry)_dnsCache[key]).LastUsedTicks; } } _dnsCache.Remove(oldestKey); } DnsCacheEntry dnsEntry = new DnsCacheEntry(name, canonicalName, (UInt32[])ipAddressList.ToArray(typeof(UInt32)), expirationInMachineTicks, Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks); _dnsCache.Add(name.ToLower(), dnsEntry); } } if (ipAddressList.Count == 0) throw Utility.NewSocketException(SocketError.NoData); UInt32[] addresses = (UInt32[])ipAddressList.ToArray(typeof(UInt32)); return addresses; }