Dns.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. // System.Net.Dns.cs
  2. //
  3. // Authors:
  4. // Mads Pultz ([email protected])
  5. // Lawrence Pit ([email protected])
  6. // Author: Mads Pultz ([email protected])
  7. // Lawrence Pit ([email protected])
  8. // Marek Safar ([email protected])
  9. // Gonzalo Paniagua Javier ([email protected])
  10. //
  11. // (C) Mads Pultz, 2001
  12. // Copyright (c) 2011 Novell, Inc.
  13. // Copyright (c) 2011 Xamarin, Inc.
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System;
  35. using System.Net.Sockets;
  36. using System.Text;
  37. using System.Collections;
  38. using System.Threading;
  39. using System.Runtime.CompilerServices;
  40. using System.Runtime.Remoting.Messaging;
  41. using System.Threading.Tasks;
  42. #if !MOBILE
  43. using Mono.Net.Dns;
  44. #endif
  45. namespace System.Net {
  46. public static class Dns {
  47. #if !MOBILE
  48. static bool use_mono_dns;
  49. static SimpleResolver resolver;
  50. #endif
  51. static Dns ()
  52. {
  53. #if !MOBILE
  54. if (Environment.GetEnvironmentVariable ("MONO_DNS") != null) {
  55. resolver = new SimpleResolver ();
  56. use_mono_dns = true;
  57. }
  58. #endif
  59. }
  60. #if !MOBILE
  61. internal static bool UseMonoDns {
  62. get { return use_mono_dns; }
  63. }
  64. #endif
  65. private delegate IPHostEntry GetHostByNameCallback (string hostName);
  66. private delegate IPHostEntry ResolveCallback (string hostName);
  67. private delegate IPHostEntry GetHostEntryNameCallback (string hostName);
  68. private delegate IPHostEntry GetHostEntryIPCallback (IPAddress hostAddress);
  69. private delegate IPAddress [] GetHostAddressesCallback (string hostName);
  70. #if !MOBILE
  71. static void OnCompleted (object sender, SimpleResolverEventArgs e)
  72. {
  73. DnsAsyncResult ares = (DnsAsyncResult) e.UserToken;
  74. IPHostEntry entry = e.HostEntry;
  75. if (entry == null || e.ResolverError != 0) {
  76. ares.SetCompleted (false, new Exception ("Error: " + e.ResolverError));
  77. return;
  78. }
  79. ares.SetCompleted (false, entry);
  80. }
  81. static IAsyncResult BeginAsyncCallAddresses (string host, AsyncCallback callback, object state)
  82. {
  83. SimpleResolverEventArgs e = new SimpleResolverEventArgs ();
  84. e.Completed += OnCompleted;
  85. e.HostName = host;
  86. DnsAsyncResult ares = new DnsAsyncResult (callback, state);
  87. e.UserToken = ares;
  88. if (resolver.GetHostAddressesAsync (e) == false)
  89. ares.SetCompleted (true, e.HostEntry); // Completed synchronously
  90. return ares;
  91. }
  92. static IAsyncResult BeginAsyncCall (string host, AsyncCallback callback, object state)
  93. {
  94. SimpleResolverEventArgs e = new SimpleResolverEventArgs ();
  95. e.Completed += OnCompleted;
  96. e.HostName = host;
  97. DnsAsyncResult ares = new DnsAsyncResult (callback, state);
  98. e.UserToken = ares;
  99. if (resolver.GetHostEntryAsync (e) == false)
  100. ares.SetCompleted (true, e.HostEntry); // Completed synchronously
  101. return ares;
  102. }
  103. static IPHostEntry EndAsyncCall (DnsAsyncResult ares)
  104. {
  105. if (ares == null)
  106. throw new ArgumentException ("Invalid asyncResult");
  107. if (!ares.IsCompleted)
  108. ares.AsyncWaitHandle.WaitOne ();
  109. if (ares.Exception != null)
  110. throw ares.Exception;
  111. IPHostEntry entry = ares.HostEntry;
  112. if (entry == null || entry.AddressList == null || entry.AddressList.Length == 0)
  113. Error_11001 (entry.HostName);
  114. return entry;
  115. }
  116. #endif
  117. [Obsolete ("Use BeginGetHostEntry instead")]
  118. public static IAsyncResult BeginGetHostByName (string hostName, AsyncCallback requestCallback, object stateObject)
  119. {
  120. #if FEATURE_NO_BSD_SOCKETS
  121. throw new PlatformNotSupportedException ("System.Net.Dns:BeginGetHostByName is not supported on this platform.");
  122. #else
  123. if (hostName == null)
  124. throw new ArgumentNullException ("hostName");
  125. #if !MOBILE
  126. if (use_mono_dns)
  127. return BeginAsyncCall (hostName, requestCallback, stateObject);
  128. #endif
  129. GetHostByNameCallback c = new GetHostByNameCallback (GetHostByName);
  130. return c.BeginInvoke (hostName, requestCallback, stateObject);
  131. #endif // FEATURE_NO_BSD_SOCKETS
  132. }
  133. [Obsolete ("Use BeginGetHostEntry instead")]
  134. public static IAsyncResult BeginResolve (string hostName, AsyncCallback requestCallback, object stateObject)
  135. {
  136. #if FEATURE_NO_BSD_SOCKETS
  137. throw new PlatformNotSupportedException ("System.Net.Dns:BeginResolve is not supported on this platform.");
  138. #else
  139. if (hostName == null)
  140. throw new ArgumentNullException ("hostName");
  141. #if !MOBILE
  142. if (use_mono_dns)
  143. return BeginAsyncCall (hostName, requestCallback, stateObject);
  144. #endif
  145. ResolveCallback c = new ResolveCallback (Resolve);
  146. return c.BeginInvoke (hostName, requestCallback, stateObject);
  147. #endif // FEATURE_NO_BSD_SOCKETS
  148. }
  149. public static IAsyncResult BeginGetHostAddresses (string hostNameOrAddress, AsyncCallback requestCallback, object state)
  150. {
  151. if (hostNameOrAddress == null)
  152. throw new ArgumentNullException ("hostName");
  153. if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
  154. throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
  155. "and ::0 (IPv6) are unspecified addresses. You " +
  156. "cannot use them as target address.",
  157. "hostNameOrAddress");
  158. #if !MOBILE
  159. if (use_mono_dns)
  160. return BeginAsyncCallAddresses (hostNameOrAddress, requestCallback, state);
  161. #endif
  162. GetHostAddressesCallback c = new GetHostAddressesCallback (GetHostAddresses);
  163. return c.BeginInvoke (hostNameOrAddress, requestCallback, state);
  164. }
  165. public static IAsyncResult BeginGetHostEntry (string hostNameOrAddress, AsyncCallback requestCallback, object stateObject)
  166. {
  167. #if FEATURE_NO_BSD_SOCKETS
  168. throw new PlatformNotSupportedException ("System.Net.Dns:GetHostEntry is not supported on this platform.");
  169. #else
  170. if (hostNameOrAddress == null)
  171. throw new ArgumentNullException ("hostName");
  172. if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
  173. throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
  174. "and ::0 (IPv6) are unspecified addresses. You " +
  175. "cannot use them as target address.",
  176. "hostNameOrAddress");
  177. #if !MOBILE
  178. if (use_mono_dns)
  179. return BeginAsyncCall (hostNameOrAddress, requestCallback, stateObject);
  180. #endif
  181. GetHostEntryNameCallback c = new GetHostEntryNameCallback (GetHostEntry);
  182. return c.BeginInvoke (hostNameOrAddress, requestCallback, stateObject);
  183. #endif // FEATURE_NO_BSD_SOCKETS
  184. }
  185. public static IAsyncResult BeginGetHostEntry (IPAddress address, AsyncCallback requestCallback, object stateObject)
  186. {
  187. #if FEATURE_NO_BSD_SOCKETS
  188. throw new PlatformNotSupportedException ("System.Net.Dns:BeginGetHostEntry is not supported on this platform.");
  189. #else
  190. if (address == null)
  191. throw new ArgumentNullException ("address");
  192. #if !MOBILE
  193. if (use_mono_dns)
  194. return BeginAsyncCall (address.ToString (), requestCallback, stateObject);
  195. #endif
  196. GetHostEntryIPCallback c = new GetHostEntryIPCallback (GetHostEntry);
  197. return c.BeginInvoke (address, requestCallback, stateObject);
  198. #endif // FEATURE_NO_BSD_SOCKETS
  199. }
  200. [Obsolete ("Use EndGetHostEntry instead")]
  201. public static IPHostEntry EndGetHostByName (IAsyncResult asyncResult)
  202. {
  203. if (asyncResult == null)
  204. throw new ArgumentNullException ("asyncResult");
  205. #if !MOBILE
  206. if (use_mono_dns)
  207. return EndAsyncCall (asyncResult as DnsAsyncResult);
  208. #endif
  209. AsyncResult async = (AsyncResult) asyncResult;
  210. GetHostByNameCallback cb = (GetHostByNameCallback) async.AsyncDelegate;
  211. return cb.EndInvoke(asyncResult);
  212. }
  213. [Obsolete ("Use EndGetHostEntry instead")]
  214. public static IPHostEntry EndResolve (IAsyncResult asyncResult)
  215. {
  216. if (asyncResult == null)
  217. throw new ArgumentNullException ("asyncResult");
  218. #if !MOBILE
  219. if (use_mono_dns)
  220. return EndAsyncCall (asyncResult as DnsAsyncResult);
  221. #endif
  222. AsyncResult async = (AsyncResult) asyncResult;
  223. ResolveCallback cb = (ResolveCallback) async.AsyncDelegate;
  224. return cb.EndInvoke(asyncResult);
  225. }
  226. public static IPAddress [] EndGetHostAddresses (IAsyncResult asyncResult)
  227. {
  228. if (asyncResult == null)
  229. throw new ArgumentNullException ("asyncResult");
  230. #if !MOBILE
  231. if (use_mono_dns) {
  232. IPHostEntry entry = EndAsyncCall (asyncResult as DnsAsyncResult);
  233. if (entry == null)
  234. return null;
  235. return entry.AddressList;
  236. }
  237. #endif
  238. AsyncResult async = (AsyncResult) asyncResult;
  239. GetHostAddressesCallback cb = (GetHostAddressesCallback) async.AsyncDelegate;
  240. return cb.EndInvoke(asyncResult);
  241. }
  242. public static IPHostEntry EndGetHostEntry (IAsyncResult asyncResult)
  243. {
  244. if (asyncResult == null)
  245. throw new ArgumentNullException ("asyncResult");
  246. #if !MOBILE
  247. if (use_mono_dns)
  248. return EndAsyncCall (asyncResult as DnsAsyncResult);
  249. #endif
  250. AsyncResult async = (AsyncResult) asyncResult;
  251. if (async.AsyncDelegate is GetHostEntryIPCallback)
  252. return ((GetHostEntryIPCallback) async.AsyncDelegate).EndInvoke (asyncResult);
  253. GetHostEntryNameCallback cb = (GetHostEntryNameCallback) async.AsyncDelegate;
  254. return cb.EndInvoke(asyncResult);
  255. }
  256. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  257. private extern static bool GetHostByName_internal(string host, out string h_name, out string[] h_aliases, out string[] h_addr_list, int hint);
  258. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  259. private extern static bool GetHostByAddr_internal(string addr, out string h_name, out string[] h_aliases, out string[] h_addr_list, int hint);
  260. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  261. private extern static bool GetHostName_internal(out string h_name);
  262. static void Error_11001 (string hostName)
  263. {
  264. throw new SocketException(11001, string.Format ("Could not resolve host '{0}'", hostName));
  265. }
  266. private static IPHostEntry hostent_to_IPHostEntry(string originalHostName, string h_name, string[] h_aliases, string[] h_addrlist)
  267. {
  268. IPHostEntry he = new IPHostEntry();
  269. ArrayList addrlist = new ArrayList();
  270. he.HostName = h_name;
  271. he.Aliases = h_aliases;
  272. for(int i=0; i<h_addrlist.Length; i++) {
  273. try {
  274. IPAddress newAddress = IPAddress.Parse(h_addrlist[i]);
  275. if( (Socket.SupportsIPv6 && newAddress.AddressFamily == AddressFamily.InterNetworkV6) ||
  276. (Socket.SupportsIPv4 && newAddress.AddressFamily == AddressFamily.InterNetwork) )
  277. addrlist.Add(newAddress);
  278. } catch (ArgumentNullException) {
  279. /* Ignore this, as the
  280. * internal call might have
  281. * left some blank entries at
  282. * the end of the array
  283. */
  284. }
  285. }
  286. if(addrlist.Count == 0)
  287. Error_11001 (originalHostName);
  288. he.AddressList = addrlist.ToArray(typeof(IPAddress)) as IPAddress[];
  289. return he;
  290. }
  291. [Obsolete ("Use GetHostEntry instead")]
  292. public static IPHostEntry GetHostByAddress(IPAddress address)
  293. {
  294. if (address == null)
  295. throw new ArgumentNullException ("address");
  296. return GetHostByAddressFromString (address.ToString (), false);
  297. }
  298. [Obsolete ("Use GetHostEntry instead")]
  299. public static IPHostEntry GetHostByAddress(string address)
  300. {
  301. if (address == null)
  302. throw new ArgumentNullException ("address");
  303. return GetHostByAddressFromString (address, true);
  304. }
  305. static IPHostEntry GetHostByAddressFromString (string address, bool parse)
  306. {
  307. // Undocumented MS behavior: when called with IF_ANY,
  308. // this should return the local host
  309. if (address.Equals ("0.0.0.0")) {
  310. address = "127.0.0.1";
  311. parse = false;
  312. }
  313. // Must check the IP format, might send an exception if invalid string.
  314. if (parse)
  315. IPAddress.Parse (address);
  316. string h_name;
  317. string[] h_aliases, h_addrlist;
  318. bool ret = GetHostByAddr_internal(address, out h_name, out h_aliases, out h_addrlist, Socket.FamilyHint);
  319. if (!ret)
  320. Error_11001 (address);
  321. return (hostent_to_IPHostEntry (address, h_name, h_aliases, h_addrlist));
  322. }
  323. public static IPHostEntry GetHostEntry (string hostNameOrAddress)
  324. {
  325. if (hostNameOrAddress == null)
  326. throw new ArgumentNullException ("hostNameOrAddress");
  327. if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
  328. throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
  329. "and ::0 (IPv6) are unspecified addresses. You " +
  330. "cannot use them as target address.",
  331. "hostNameOrAddress");
  332. IPAddress addr;
  333. if (hostNameOrAddress.Length > 0 && IPAddress.TryParse (hostNameOrAddress, out addr))
  334. return GetHostEntry (addr);
  335. return GetHostByName (hostNameOrAddress);
  336. }
  337. public static IPHostEntry GetHostEntry (IPAddress address)
  338. {
  339. if (address == null)
  340. throw new ArgumentNullException ("address");
  341. return GetHostByAddressFromString (address.ToString (), false);
  342. }
  343. public static IPAddress [] GetHostAddresses (string hostNameOrAddress)
  344. {
  345. if (hostNameOrAddress == null)
  346. throw new ArgumentNullException ("hostNameOrAddress");
  347. if (hostNameOrAddress == "0.0.0.0" || hostNameOrAddress == "::0")
  348. throw new ArgumentException ("Addresses 0.0.0.0 (IPv4) " +
  349. "and ::0 (IPv6) are unspecified addresses. You " +
  350. "cannot use them as target address.",
  351. "hostNameOrAddress");
  352. IPAddress addr;
  353. if (hostNameOrAddress.Length > 0 && IPAddress.TryParse (hostNameOrAddress, out addr))
  354. return new IPAddress[1] { addr };
  355. return GetHostEntry (hostNameOrAddress).AddressList;
  356. }
  357. [Obsolete ("Use GetHostEntry instead")]
  358. public static IPHostEntry GetHostByName (string hostName)
  359. {
  360. #if FEATURE_NO_BSD_SOCKETS
  361. if (!string.IsNullOrEmpty (hostName))
  362. throw new PlatformNotSupportedException ("System.Net.Dns:GetHostByName is not supported on this platform.");
  363. #endif // FEATURE_NO_BSD_SOCKETS
  364. if (hostName == null)
  365. throw new ArgumentNullException ("hostName");
  366. string h_name;
  367. string[] h_aliases, h_addrlist;
  368. bool ret = GetHostByName_internal(hostName, out h_name, out h_aliases, out h_addrlist, Socket.FamilyHint);
  369. if (ret == false)
  370. Error_11001 (hostName);
  371. return(hostent_to_IPHostEntry(hostName, h_name, h_aliases, h_addrlist));
  372. }
  373. public static string GetHostName ()
  374. {
  375. string hostName;
  376. bool ret = GetHostName_internal(out hostName);
  377. if (ret == false)
  378. Error_11001 (hostName);
  379. return hostName;
  380. }
  381. [Obsolete ("Use GetHostEntry instead")]
  382. public static IPHostEntry Resolve(string hostName)
  383. {
  384. #if FEATURE_NO_BSD_SOCKETS
  385. throw new PlatformNotSupportedException ("System.Net.Dns:Resolve is not supported on this platform.");
  386. #else
  387. if (hostName == null)
  388. throw new ArgumentNullException ("hostName");
  389. IPHostEntry ret = null;
  390. try {
  391. ret = GetHostByAddress(hostName);
  392. }
  393. catch{}
  394. if(ret == null)
  395. ret = GetHostByName(hostName);
  396. return ret;
  397. #endif // FEATURE_NO_BSD_SOCKETS
  398. }
  399. public static Task<IPAddress[]> GetHostAddressesAsync (string hostNameOrAddress)
  400. {
  401. return Task<IPAddress[]>.Factory.FromAsync (BeginGetHostAddresses, EndGetHostAddresses, hostNameOrAddress, null);
  402. }
  403. public static Task<IPHostEntry> GetHostEntryAsync (IPAddress address)
  404. {
  405. return Task<IPHostEntry>.Factory.FromAsync (BeginGetHostEntry, EndGetHostEntry, address, null);
  406. }
  407. public static Task<IPHostEntry> GetHostEntryAsync (string hostNameOrAddress)
  408. {
  409. return Task<IPHostEntry>.Factory.FromAsync (BeginGetHostEntry, EndGetHostEntry, hostNameOrAddress, null);
  410. }
  411. }
  412. }