public void Dispose() { if (dnsapiLibHandle != IntPtr.Zero) { DnsApi.FreeLibrary(dnsapiLibHandle); } }
public DnsCacheMonitor() { dnsapiLibHandle = DnsApi.LoadLibrary("dnsapi.dll"); if (dnsapiLibHandle != IntPtr.Zero) { var procAddress = DnsApi.GetProcAddress(dnsapiLibHandle, nameof(DnsApi.DnsGetCacheDataTable)); DnsGetCacheDataTable_I = (DnsApi.DnsGetCacheDataTable)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(DnsApi.DnsGetCacheDataTable)); } //else // throw new Win32Exception(Marshal.GetLastWin32Error()); }
public static void ApplyChanges(string AdapterName) { // this is how explorer suposedly does it DhcpNotifyConfigChange(null, AdapterName, false, 0, 0, 0, 0); DnsApi.DnsFlushResolverCache(); }
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); }
public List <HostNameEntry> ResolveHostNames(IPAddress remoteAddress) { if (remoteAddress.Equals(IPAddress.Any) || remoteAddress.Equals(IPAddress.IPv6Any)) { return(new List <HostNameEntry>()); } if (remoteAddress.Equals(IPAddress.Loopback) || remoteAddress.Equals(IPAddress.IPv6Loopback)) { return new List <HostNameEntry>() { new HostNameEntry() { HostName = "localhost", TimeStamp = DateTime.Now } } } ; ReverseDnsEntry Entry = null; if (ReverseDnsCache.TryGetValue(remoteAddress, out Entry)) { if (Entry.HostNames.Count > 0) { List <HostNameEntry> List = new List <HostNameEntry>(); foreach (string HostName in Entry.HostNames) { List.Add(new HostNameEntry() { HostName = HostName, TimeStamp = Entry.TimeStamp }); } return(List); } else if (Entry.Pending) { return(null); } else if ((Entry.TimeStamp.AddMinutes(1) > DateTime.Now)) { return(new List <HostNameEntry>()); // dont re query if teh last query failed } } if (Entry == null) { Entry = new ReverseDnsEntry(); Entry.Pending = true; ReverseDnsCache.Add(remoteAddress, Entry); } AppLog.Debug("reverse looking up : {0}", remoteAddress.ToString()); Thread task = new Thread(() => { // WARNING: this function is called from the worker thread string AddressReverse = Address2RevDnsHost(remoteAddress); List <string> HostNames = new List <string>(); try { var resultPtr = IntPtr.Zero; if (DnsApi.DnsQuery(AddressReverse, DnsApi.DnsRecordType.PTR, DnsApi.DnsQueryType.DNS_QUERY_NO_HOSTS_FILE, IntPtr.Zero, ref resultPtr, IntPtr.Zero) == DnsApi.ERROR_SUCCESS) { 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; if (record.Type != DnsApi.DnsRecordType.PTR) { continue; } var ptr = (DnsApi.DnsPTRRecord)Marshal.PtrToStructure(data, typeof(DnsApi.DnsPTRRecord)); HostNames.Add(ptr.NameHost); } if (resultPtr != IntPtr.Zero) { DnsApi.DnsRecordListFree(resultPtr, DnsApi.DnsFreeType.DnsFreeRecordList); } } } catch (Exception err) { AppLog.Exception(err); } App.engine?.RunInEngineThread(() => { // Note: this happens in the engine thread Entry.TimeStamp = DateTime.Now; Entry.HostNames = HostNames; Entry.Pending = false; HostNameResolved?.Invoke(this, new DnsEvent() { RemoteAddress = remoteAddress, HostNames = HostNames /*, TimeStamp = Entry.TimeStamp*/ }); }); }); task.Start(); return(null); }