byte [] GetFreshBuffer() { #if !REUSE_RESPONSES return(new byte [512]); #else DnsResponse response = null; lock (responses_avail) { if (responses_avail.Count > 0) { response = responses_avail.Pop(); } } if (response == null) { response = new DnsResponse(); } else { response.Reset(); } return(response); #endif }
void ProcessResponse (SimpleResolverEventArgs args, DnsResponse response, EndPoint server_ep) { DnsRCode status = response.Header.RCode; if (status != 0) { if (args.PTRAddress != null) { // PTR query failed -> no error, we have the IP return; } args.ResolverError = (ResolverError) status; return; } // TODO: verify IP of the server is in our list and the same one that got the query IPEndPoint ep = (IPEndPoint) server_ep; if (ep.Port != 53) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "Port"; return; } DnsHeader header = response.Header; if (!header.IsQuery) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "IsQuery"; return; } // TODO: handle Truncation. Retry with bigger buffer? if (header.QuestionCount > 1) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QuestionCount"; return; } ReadOnlyCollection<DnsQuestion> q = response.GetQuestions (); if (q.Count != 1) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QuestionCount 2"; return; } DnsQuestion question = q [0]; /* The answer might have dot at the end, etc... if (String.Compare (question.Name, args.HostName) != 0) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "HostName - " + question.Name + " != " + args.HostName; return; } */ DnsQType t = question.Type; if (t != DnsQType.A && t != DnsQType.AAAA && t != DnsQType.PTR) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QType " + question.Type; return; } if (question.Class != DnsQClass.IN) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QClass " + question.Class; return; } ReadOnlyCollection<DnsResourceRecord> records = response.GetAnswers (); if (records.Count == 0) { if (args.PTRAddress != null) { // PTR query failed -> no error return; } args.ResolverError = ResolverError.NameError; // is this ok? args.ErrorMessage = "NoAnswers"; return; } List<string> aliases = null; List<IPAddress> addresses = null; foreach (DnsResourceRecord r in records) { if (r.Class != DnsClass.IN) continue; if (r.Type == DnsType.A || r.Type == DnsType.AAAA) { if (addresses == null) addresses = new List<IPAddress> (); addresses.Add (((DnsResourceRecordIPAddress) r).Address); } else if (r.Type == DnsType.CNAME) { if (aliases == null) aliases = new List<string> (); aliases.Add (((DnsResourceRecordCName) r).CName); } else if (r.Type == DnsType.PTR) { args.HostEntry.HostName = ((DnsResourceRecordPTR) r).DName; args.HostEntry.Aliases = aliases == null ? EmptyStrings : aliases.ToArray (); args.HostEntry.AddressList = EmptyAddresses; return; } } IPHostEntry entry = args.HostEntry ?? new IPHostEntry (); if (entry.HostName == null && aliases != null && aliases.Count > 0) { entry.HostName = aliases [0]; aliases.RemoveAt (0); } entry.Aliases = aliases == null ? EmptyStrings : aliases.ToArray (); entry.AddressList = addresses == null ? EmptyAddresses : addresses.ToArray (); args.HostEntry = entry; if ((question.Type == DnsQType.A || question.Type == DnsQType.AAAA) && entry.AddressList == EmptyAddresses) { args.ResolverError = ResolverError.NameError; args.ErrorMessage = "No addresses in response"; } else if (question.Type == DnsQType.PTR && entry.HostName == null) { args.ResolverError = ResolverError.NameError; args.ErrorMessage = "No PTR in response"; } }
void OnReceive (IAsyncResult ares) { if (disposed) return; int nread = 0; EndPoint remote_ep = client.RemoteEndPoint; try { nread = client.EndReceive (ares); } catch (Exception e) { Console.Error.WriteLine (e); } BeginReceive (); byte [] buffer = (byte []) ares.AsyncState; if (nread > 12) { DnsResponse response = new DnsResponse (buffer, nread); int id = response.Header.ID; SimpleResolverEventArgs args = null; lock (queries) { if (queries.TryGetValue (id, out args)) { queries.Remove (id); } } if (args != null) { Timer t = args.Timer; if (t != null) t.Change (Timeout.Infinite, Timeout.Infinite); try { ProcessResponse (args, response, remote_ep); } catch (Exception e) { args.ResolverError = (ResolverError) (-1); args.ErrorMessage = e.Message; } IPHostEntry entry = args.HostEntry; if (args.ResolverError != 0 && args.PTRAddress != null && entry != null && entry.HostName != null) { args.PTRAddress = null; SendAQuery (args, entry.HostName, true); args.Timer.Change (5000, Timeout.Infinite); } else { args.OnCompleted (this); } } } FreeBuffer (buffer); }
byte [] GetFreshBuffer () { #if !REUSE_RESPONSES return new byte [512]; #else DnsResponse response = null; lock (responses_avail) { if (responses_avail.Count > 0) { response = responses_avail.Pop (); } } if (response == null) { response = new DnsResponse (); } else { response.Reset (); } return response; #endif }
void ProcessResponse(SimpleResolverEventArgs args, DnsResponse response, EndPoint server_ep) { DnsRCode status = response.Header.RCode; if (status != 0) { if (args.PTRAddress != null) { // PTR query failed -> no error, we have the IP return; } args.ResolverError = (ResolverError)status; return; } // TODO: verify IP of the server is in our list and the same one that got the query IPEndPoint ep = (IPEndPoint)server_ep; if (ep.Port != 53) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "Port"; return; } DnsHeader header = response.Header; if (!header.IsQuery) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "IsQuery"; return; } // TODO: handle Truncation. Retry with bigger buffer? if (header.QuestionCount > 1) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QuestionCount"; return; } ReadOnlyCollection <DnsQuestion> q = response.GetQuestions(); if (q.Count != 1) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QuestionCount 2"; return; } DnsQuestion question = q [0]; /* The answer might have dot at the end, etc... * if (String.Compare (question.Name, args.HostName) != 0) { * args.ResolverError = ResolverError.ResponseHeaderError; * args.ErrorMessage = "HostName - " + question.Name + " != " + args.HostName; * return; * } */ DnsQType t = question.Type; if (t != DnsQType.A && t != DnsQType.AAAA && t != DnsQType.PTR) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QType " + question.Type; return; } if (question.Class != DnsQClass.IN) { args.ResolverError = ResolverError.ResponseHeaderError; args.ErrorMessage = "QClass " + question.Class; return; } ReadOnlyCollection <DnsResourceRecord> records = response.GetAnswers(); if (records.Count == 0) { if (args.PTRAddress != null) { // PTR query failed -> no error return; } args.ResolverError = ResolverError.NameError; // is this ok? args.ErrorMessage = "NoAnswers"; return; } List <string> aliases = null; List <IPAddress> addresses = null; foreach (DnsResourceRecord r in records) { if (r.Class != DnsClass.IN) { continue; } if (r.Type == DnsType.A || r.Type == DnsType.AAAA) { if (addresses == null) { addresses = new List <IPAddress> (); } addresses.Add(((DnsResourceRecordIPAddress)r).Address); } else if (r.Type == DnsType.CNAME) { if (aliases == null) { aliases = new List <string> (); } aliases.Add(((DnsResourceRecordCName)r).CName); } else if (r.Type == DnsType.PTR) { args.HostEntry.HostName = ((DnsResourceRecordPTR)r).DName; args.HostEntry.Aliases = aliases == null ? EmptyStrings : aliases.ToArray(); args.HostEntry.AddressList = EmptyAddresses; return; } } IPHostEntry entry = args.HostEntry ?? new IPHostEntry(); if (entry.HostName == null && aliases != null && aliases.Count > 0) { entry.HostName = aliases [0]; aliases.RemoveAt(0); } entry.Aliases = aliases == null ? EmptyStrings : aliases.ToArray(); entry.AddressList = addresses == null ? EmptyAddresses : addresses.ToArray(); args.HostEntry = entry; if ((question.Type == DnsQType.A || question.Type == DnsQType.AAAA) && entry.AddressList == EmptyAddresses) { args.ResolverError = ResolverError.NameError; args.ErrorMessage = "No addresses in response"; } else if (question.Type == DnsQType.PTR && entry.HostName == null) { args.ResolverError = ResolverError.NameError; args.ErrorMessage = "No PTR in response"; } }
void OnReceive(IAsyncResult ares) { if (disposed) { return; } int nread = 0; EndPoint remote_ep = client.RemoteEndPoint; try { nread = client.EndReceive(ares); } catch (Exception e) { Console.Error.WriteLine(e); } BeginReceive(); byte [] buffer = (byte [])ares.AsyncState; if (nread > 12) { DnsResponse response = new DnsResponse(buffer, nread); int id = response.Header.ID; SimpleResolverEventArgs args = null; lock (queries) { if (queries.TryGetValue(id, out args)) { queries.Remove(id); } } if (args != null) { Timer t = args.Timer; if (t != null) { t.Change(Timeout.Infinite, Timeout.Infinite); } try { ProcessResponse(args, response, remote_ep); } catch (Exception e) { args.ResolverError = (ResolverError)(-1); args.ErrorMessage = e.Message; } IPHostEntry entry = args.HostEntry; if (args.ResolverError != 0 && args.PTRAddress != null && entry != null && entry.HostName != null) { args.PTRAddress = null; SendAQuery(args, entry.HostName, true); args.Timer.Change(5000, Timeout.Infinite); } else { args.OnCompleted(this); } } } FreeBuffer(buffer); }