void GetLocalHost (SimpleResolverEventArgs args) { //FIXME IPHostEntry entry = new IPHostEntry (); entry.HostName = "localhost"; entry.AddressList = new IPAddress [] { IPAddress.Loopback }; entry.Aliases = EmptyStrings; args.ResolverError = 0; args.HostEntry = entry; return; /* List<IPEndPoint> eps = new List<IPEndPoint> (); foreach (NetworkInterface iface in NetworkInterface.GetAllNetworkInterfaces ()) { if (NetworkInterfaceType.Loopback == iface.NetworkInterfaceType) continue; foreach (IPAddress addr in iface.GetIPProperties ().DnsAddresses) { if (AddressFamily.InterNetworkV6 == addr.AddressFamily) continue; IPEndPoint ep = new IPEndPoint (addr, 53); if (eps.Contains (ep)) continue; eps.Add (ep); } } endpoints = eps.ToArray (); */ }
static void OnCompleted (object sender, SimpleResolverEventArgs e) { DnsAsyncResult ares = (DnsAsyncResult) e.UserToken; IPHostEntry entry = e.HostEntry; if (entry == null || e.ResolverError != 0) { ares.SetCompleted (false, new Exception ("Error: " + e.ResolverError)); return; } ares.SetCompleted (false, entry); }
static IAsyncResult BeginAsyncCall (string host, AsyncCallback callback, object state) { SimpleResolverEventArgs e = new SimpleResolverEventArgs (); e.Completed += OnCompleted; e.HostName = host; DnsAsyncResult ares = new DnsAsyncResult (callback, state); e.UserToken = ares; if (resolver.GetHostEntryAsync (e) == false) ares.SetCompleted (true, e.HostEntry); // Completed synchronously return ares; }
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 SendPTRQuery (SimpleResolverEventArgs args, bool add_it) { DnsQuery query = GetQuery (GetPTRName (args.PTRAddress), DnsQType.PTR, DnsQClass.IN); SendQuery (args, query, add_it); }
void SendQuery (SimpleResolverEventArgs args, DnsQuery query, bool add_it) { // TODO: not sure about reusing IDs when add_it == false int count = 0; if (add_it) { do { query.Header.ID = (ushort)new Random().Next(1, 65534); if (count > 500) throw new InvalidOperationException ("Too many pending queries (or really bad luck)"); } while (AddQuery (query, args) == false); args.QueryID = query.Header.ID; } else { query.Header.ID = args.QueryID; } if (args.Timer == null) args.Timer = new Timer (timeout_cb, args, 5000, Timeout.Infinite); else args.Timer.Change (5000, Timeout.Infinite); client.BeginSend (query.Packet, 0, query.Length, SocketFlags.None, null, null); }
void SendAQuery (SimpleResolverEventArgs args, string host, bool add_it) { DnsQuery query = GetQuery (host, DnsQType.A, DnsQClass.IN); SendQuery (args, query, add_it); }
void SendAQuery (SimpleResolverEventArgs args, bool add_it) { SendAQuery (args, args.HostName, add_it); }
bool AddQuery (DnsQuery query, SimpleResolverEventArgs args) { lock (queries) { if (queries.ContainsKey (query.Header.ID)) return false; queries [query.Header.ID] = args; } return true; }
// For names -> type A Query // For IP addresses -> PTR + A -> will at least return itself // Careful: for IP addresses with PTR, the hostname might yield different IP addresses! public bool GetHostEntryAsync (SimpleResolverEventArgs args) { if (args == null) throw new ArgumentNullException ("args"); if (args.HostName == null) throw new ArgumentNullException ("args.HostName is null"); if (args.HostName.Length > 255) throw new ArgumentException ("args.HostName is too long"); args.Reset (ResolverAsyncOperation.GetHostEntry); string host = args.HostName; if (host == "") { GetLocalHost (args); return false; } IPAddress addr; if (IPAddress.TryParse (host, out addr)) { IPHostEntry entry = new IPHostEntry (); entry.HostName = host; entry.Aliases = EmptyStrings; entry.AddressList = new IPAddress [1] { addr }; args.HostEntry = entry; args.PTRAddress = addr; SendPTRQuery (args, true); return true; } // 3. For IP addresses: // 3.1 Parsing IP succeeds // 3.2 Reverse lookup of the IP fills in HostName -> fails? HostName = IP // 3.3 The hostname resulting from this is used to query DNS again to get the IP addresses // // Exclude IPv6 addresses if not supported by the system // .Aliases is always empty // Length > 255 SendAQuery (args, true); return true; }
// Type A query // Might fill in Aliases // -IPAddress -> return the same IPAddress // -"" -> Local host ip addresses (filter out IPv6 if needed) public bool GetHostAddressesAsync (SimpleResolverEventArgs args) { if (args == null) throw new ArgumentNullException ("args"); if (args.HostName == null) throw new ArgumentNullException ("args.HostName is null"); if (args.HostName.Length > 255) throw new ArgumentException ("args.HostName is too long"); args.Reset (ResolverAsyncOperation.GetHostAddresses); string host = args.HostName; if (host == "") { GetLocalHost (args); return false; } IPAddress addr; if (IPAddress.TryParse (host, out addr)) { IPHostEntry entry = new IPHostEntry (); entry.HostName = host; entry.Aliases = EmptyStrings; entry.AddressList = new IPAddress [1] { addr }; args.HostEntry = entry; return false; } SendAQuery (args, true); return true; }