public void Set(string domain, ref IpRecord val) { if (domain == null) { throw new ArgumentNullException(nameof(domain)); } mapLock.EnterWriteLock(); if (mapHostIp.TryGetValue(domain, out var old)) { if (val.ipLongs != null) { old.ipLongs = val.ipLongs; old.expire = val.expire; } if (val.ips6 != null) { old.ips6 = val.ips6; old.expire6 = val.expire6; } mapHostIp[domain] = old; } else { mapHostIp[domain] = val; } mapLock.ExitWriteLock(); SetReverseMap(ref val, domain); }
public bool QueryByName(string name, out IpRecord val) { if (name == null) { throw new ArgumentNullException(nameof(name)); } mapLock.EnterReadLock(); try { return(mapHostIp.TryGetValue(name, out val)); } finally { mapLock.ExitReadLock(); } }
public bool QueryByName(string domain, out IpRecord val) { Interlocked.Increment(ref queryByDomains); var begin = Logging.getRuntime(); try { var doc = FindDocByDomain(domain).SingleOrDefault(); if (doc != null) { var r = Record.FromDocument(doc); val = new IpRecord(); val.ipLongs = r.Ips; val.ips6 = r.Ips6; val.expire = r.Expire; val.expire6 = r.Expire6; return(true); } val = default(IpRecord); return(false); } finally { Interlocked.Add(ref queryByDomainTotalTime, (int)(Logging.getRuntime() - begin)); } }
void SetReverseMap(ref IpRecord r, string domain) { if (domain == null) { throw new ArgumentNullException(nameof(domain)); } mapLock2.EnterWriteLock(); if (r.ipLongs != null) { foreach (var item in r.ipLongs) { mapIpHost[item] = domain; } } if (r.ips6 != null) { foreach (var item in r.ips6) { mapIp6Host[item] = domain; } } mapLock2.ExitWriteLock(); }
private async Task <IResponse> HandleDnsRequest(IRequest request) { var q = request; var r = Response.FromRequest(request); r.ResponseCode = ResponseCode.ServerFailure; try { var questions = q.Questions; if (questions.Count == 0) { Logger.warning($"id {q.Id} does not contain any questions." + $"\nAdditionalRecords: {string.Join(", ", q.AdditionalRecords)}"); } // var queryNames = new Dictionary <Domain, DnsRequestType>(); foreach (var item in questions) { if (item.Type == RecordType.A || item.Type == RecordType.AAAA) { DnsRequestType type = item.Type == RecordType.A ? DnsRequestType.A : DnsRequestType.AAAA; if (verbose) { Logger.debugForce($"id {q.Id} query: {item}"); } if (!queryNames.ContainsKey(item.Name)) { queryNames.Add(item.Name, type); } else { queryNames[item.Name] |= type; } } else if (item.Type == RecordType.PTR) { } else { Logger.warning("Unsupported DNS record: " + item); } } foreach (var kv in queryNames) { DnsRequestType reqType = kv.Value; bool reqv4 = (reqType & DnsRequestType.A) != 0; bool reqv6 = (reqType & DnsRequestType.AAAA) != 0; var strName = kv.Key.ToString(); IEnumerable <IPAddress> ips = emptyIps; IpRecord val = new IpRecord(); bool exist = cacheDns?.QueryByName(strName, out val) ?? false; var now = DateTime.Now; if (val.expire < now) { val.ipLongs = null; } if (val.expire6 < now) { val.ips6 = null; } var ipLongs = val.ipLongs; var ips6 = val.ips6; if (!exist || (reqv4 && ipLongs == null) || (reqv6 && ips6 == null)) { var startTime = Logging.getRuntime(); var task = StartResolve(reqType, strName, out var newTask); try { try { var resp = await task; if (resp != null) { var iparr = resp.Addresses; ips = iparr; ipFilter(iparr, ref ipLongs, ref ips6); } } catch (Exception e) { if (newTask) { Logger.warning("resolving: " + strName + " (" + reqType + "): " + e.Message + " (" + (Logging.getRuntime() - startTime) + " ms)"); } continue; } if (newTask) { Logger.info("" + strName + " (" + reqType + ") -> " + string.Join("|", ips) + " (" + (Logging.getRuntime() - startTime) + " ms)"); var newExpire = DateTime.Now.AddSeconds(cache_ttl); // If we requested only A records (not AnAAAA) and an empty result returned, then there's // really no A records, so we can cache the empty result: if (reqType == DnsRequestType.A && ipLongs == null) { ipLongs = new uint[0]; } if (ipLongs != null) { val.ipLongs = ipLongs; val.expire = newExpire; } // The same reason: if (reqType == DnsRequestType.AAAA && ips6 == null) { ips6 = new Ip6[0]; } if (ips6 != null) { val.ips6 = ips6; val.expire6 = newExpire; } cacheDns?.Set(strName, ref val); } } finally { if (newTask) { EndResolve(strName, task); } } } if (reqv4 && ipLongs != null) { foreach (var item in ipLongs) { r.AnswerRecords.Add(new ResourceRecord(kv.Key, BitConverter.GetBytes(item), RecordType.A, ttl: TimeSpan.FromSeconds(ttl))); } } if (reqv6 && ips6 != null) { foreach (var item in ips6) { r.AnswerRecords.Add(new ResourceRecord(kv.Key, item.ToBytes(), RecordType.AAAA, ttl: TimeSpan.FromSeconds(ttl))); } } r.ResponseCode = ResponseCode.NoError; } } catch (Exception e) { Logger.exception(e, Logging.Level.Error, "server"); } return(r); }
public void Set(string domain, ref IpRecord val) { lock (syncRoot) { var begin = Logging.getRuntime(); inserts++; var doc = FindDocByDomain(domain).SingleOrDefault(); Record r = null; if (doc != null) { r = Record.FromDocument(doc); } else { r = new Record() { Domain = domain } }; // update IPv4/v6 records separately if (val.ipLongs != null) { if (r.Ips != null && r.Ips.Length > 0) { if (r.OldIps != null) { r.OldIps = r.OldIps.Union(r.Ips).Except(val.ipLongs).ToArray(); } else { r.OldIps = r.Ips.Except(val.ipLongs).ToArray(); if (r.OldIps.Length == 0) { r.OldIps = null; } } } r.Ips = val.ipLongs; r.Date = DateTime.Now; r.Expire = val.expire; } if (val.ips6 != null) { if (r.Ips6 != null && r.Ips6.Length > 0) { var ec = Ip6.EqualityComparer; if (r.OldIps6 != null) { r.OldIps6 = r.OldIps6.Union(r.Ips6, ec).Except(val.ips6, ec).ToArray(); } else { r.OldIps6 = r.Ips6.Except(val.ips6, ec).ToArray(); if (r.OldIps6.Length == 0) { r.OldIps6 = null; } } } r.Ips6 = val.ips6; r.Date6 = DateTime.Now; r.Expire6 = val.expire6; } engine.Upsert(ColRecords, r.ToDocument(), BsonType.Int32); insertTotalTime += (int)(Logging.getRuntime() - begin); } }