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 Main(string [] args) { if (args.Length == 0) { return; } counter = args.Length; Stopwatch watch = new Stopwatch(); watch.Start(); SimpleResolver r = new SimpleResolver(); foreach (string s in args) { SimpleResolverEventArgs e = new SimpleResolverEventArgs(); e.Completed += OnCompleted; e.HostName = s; if (!r.GetHostEntryAsync(e)) { OnCompleted(e, e); } } exit_event.WaitOne(); watch.Stop(); Console.WriteLine(watch.Elapsed); }
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); }
static void OnCompleted (object sender, SimpleResolverEventArgs e) { IPHostEntry entry = e.HostEntry; if (entry == null) { Console.WriteLine ("HostName: {0} Error: {1} {2}", e.HostName, e.ResolverError, e.ErrorMessage); if (Interlocked.Decrement (ref counter) == 0) exit_event.Set (); return; } if (e.ResolverError != 0) Console.WriteLine ("HostName: {0} {1}", e.HostName, e.ResolverError); else Console.WriteLine ("HostName: {0}", e.HostName); if (entry.HostName != null) Console.WriteLine ("\tHostName: {0}", entry.HostName); foreach (string alias in entry.Aliases) { Console.WriteLine ("\tAlias: {0}", alias); } foreach (IPAddress addr in entry.AddressList) { Console.WriteLine ("\tAddress: {0}", addr); } if (Interlocked.Decrement (ref counter) == 0) exit_event.Set (); }
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 (); */ }
void OnTimeout(object obj) { SimpleResolverEventArgs args = (SimpleResolverEventArgs)obj; SimpleResolverEventArgs args2; lock (queries) { if (!queries.TryGetValue(args.QueryID, out args2)) { return; // Already processed. } if (args != args2) { throw new Exception("Should not happen: args != args2"); } args.Retries++; if (args.Retries > 1) { // Error timeout args.ResolverError = ResolverError.Timeout; args.OnCompleted(this); } else { SendAQuery(args, false); } } }
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); }
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); }
static void GetLocalHost(SimpleResolverEventArgs args) { //FIXME IPHostEntry entry = new IPHostEntry(); entry.HostName = "localhost"; entry.Aliases = EmptyStrings; args.ResolverError = 0; args.HostEntry = entry; #if NET_4_0 bool ipv4 = Socket.OSSupportsIPv4; #else bool ipv4 = Socket.SupportsIPv4; #endif bool ipv6 = Socket.OSSupportsIPv6; List <IPAddress> ips = new List <IPAddress> (); if (ipv4) { ips.Add(IPAddress.Loopback); } if (ipv6) { ips.Add(IPAddress.IPv6Loopback); } foreach (NetworkInterface iface in NetworkInterface.GetAllNetworkInterfaces()) { if (NetworkInterfaceType.Loopback == iface.NetworkInterfaceType) { continue; } foreach (UnicastIPAddressInformation info in iface.GetIPProperties().UnicastAddresses) { IPAddress addr = info.Address; AddressFamily family = addr.AddressFamily; if ((ipv6 && AddressFamily.InterNetworkV6 == family) || (ipv4 && AddressFamily.InterNetwork == family)) { ips.Add(addr); } } } entry.AddressList = ips.ToArray(); }
static void Main (string [] args) { if (args.Length == 0) return; counter = args.Length; Stopwatch watch = new Stopwatch (); watch.Start (); SimpleResolver r = new SimpleResolver (); foreach (string s in args) { SimpleResolverEventArgs e = new SimpleResolverEventArgs (); e.Completed += OnCompleted; e.HostName = s; if (!r.GetHostEntryAsync (e)) OnCompleted (e, e); } exit_event.WaitOne (); watch.Stop (); Console.WriteLine (watch.Elapsed); }
// 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); }
static void OnCompleted(object sender, SimpleResolverEventArgs e) { IPHostEntry entry = e.HostEntry; if (entry == null) { Console.WriteLine("HostName: {0} Error: {1} {2}", e.HostName, e.ResolverError, e.ErrorMessage); if (Interlocked.Decrement(ref counter) == 0) { exit_event.Set(); } return; } if (e.ResolverError != 0) { Console.WriteLine("HostName: {0} {1}", e.HostName, e.ResolverError); } else { Console.WriteLine("HostName: {0}", e.HostName); } if (entry.HostName != null) { Console.WriteLine("\tHostName: {0}", entry.HostName); } foreach (string alias in entry.Aliases) { Console.WriteLine("\tAlias: {0}", alias); } foreach (IPAddress addr in entry.AddressList) { Console.WriteLine("\tAddress: {0}", addr); } if (Interlocked.Decrement(ref counter) == 0) { exit_event.Set(); } }
static void GetLocalHost (SimpleResolverEventArgs args) { //FIXME IPHostEntry entry = new IPHostEntry (); entry.HostName = "localhost"; entry.Aliases = EmptyStrings; args.ResolverError = 0; args.HostEntry = entry; #if NET_4_0 bool ipv4 = Socket.OSSupportsIPv4; #else bool ipv4 = Socket.SupportsIPv4; #endif bool ipv6 = Socket.OSSupportsIPv6; List<IPAddress> ips = new List<IPAddress> (); if (ipv4) ips.Add (IPAddress.Loopback); if (ipv6) ips.Add (IPAddress.IPv6Loopback); foreach (NetworkInterface iface in NetworkInterface.GetAllNetworkInterfaces ()) { if (NetworkInterfaceType.Loopback == iface.NetworkInterfaceType) continue; foreach (UnicastIPAddressInformation info in iface.GetIPProperties ().UnicastAddresses) { IPAddress addr = info.Address; AddressFamily family = addr.AddressFamily; if ((ipv6 && AddressFamily.InterNetworkV6 == family) || (ipv4 && AddressFamily.InterNetwork == family)) { ips.Add (addr); } } } entry.AddressList = ips.ToArray (); }
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 SendPTRQuery (SimpleResolverEventArgs args, bool add_it) { DnsQuery query = GetQuery (GetPTRName (args.PTRAddress), DnsQType.PTR, DnsQClass.IN); SendQuery (args, query, add_it); }
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; }
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"; } }
static IAsyncResult BeginAsyncCallAddresses (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.GetHostAddressesAsync (e) == false) ares.SetCompleted (true, e.HostEntry); // Completed synchronously return ares; }
void SendAQuery(SimpleResolverEventArgs args, bool add_it) { SendAQuery(args, args.HostName, add_it); }
void SendAQuery(SimpleResolverEventArgs args, string host, bool add_it) { DnsQuery query = GetQuery(host, DnsQType.A, DnsQClass.IN); SendQuery(args, query, add_it); }
void SendPTRQuery(SimpleResolverEventArgs args, bool add_it) { DnsQuery query = GetQuery(GetPTRName(args.PTRAddress), DnsQType.PTR, DnsQClass.IN); SendQuery(args, query, add_it); }
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"; } }
// 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; }
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); }