private Task <DnsResponse> StartResolve(DnsRequestType type, string strName, out bool newTask) { if (dnsProvider == null) { throw new Exception("no dns resolver"); } lock (resolvingNames) { newTask = false; if (resolvingNames.TryGetValue(strName, out var rt)) { // try to return a running task if (type == DnsRequestType.A && rt.A != null) { return(rt.A); } if (type == DnsRequestType.AAAA || rt.AAAA != null) { return(rt.AAAA); } if (type == DnsRequestType.AnAAAA) { if (rt.A == rt.AAAA) { return(rt.A); } if (rt.A != null && rt.AAAA != null) { return(UnionWarpper(rt)); } } } else { rt = new ResolveTask(); resolvingNames[strName] = rt; } var task = Controller.ResolveName(this, AdapterRef.FromAdapter(dnsProvider), new DnsRequest(strName, type)); if ((type & DnsRequestType.A) != 0 && rt.A == null) { rt.A = task; } if ((type & DnsRequestType.AAAA) != 0 && rt.AAAA == null) { rt.AAAA = task; } newTask = true; return(task); } }
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 DnsRequest(string name, DnsRequestType type) { Name = name; Type = type; }