/Source/NETworkManager.Models/Network/HostRangeHelper.cs

https://github.com/BornToBeRoot/NETworkManager · C# · 218 lines · 164 code · 34 blank · 20 comment · 30 complexity · b61b192a382224cb35b4d1fe20001b43 MD5 · raw file

  1. using NETworkManager.Utilities;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using System.Text.RegularExpressions;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace NETworkManager.Models.Network
  12. {
  13. public static class HostRangeHelper
  14. {
  15. public static Task<IPAddress[]> CreateIPAddressesFromIPRangesAsync(string[] ipRanges, CancellationToken cancellationToken)
  16. {
  17. return Task.Run(() => CreateIPAddressesFromIPRanges(ipRanges, cancellationToken), cancellationToken);
  18. }
  19. public static IPAddress[] CreateIPAddressesFromIPRanges(string[] ipRanges, CancellationToken cancellationToken)
  20. {
  21. var bag = new ConcurrentBag<IPAddress>();
  22. var parallelOptions = new ParallelOptions
  23. {
  24. CancellationToken = cancellationToken
  25. };
  26. foreach (var ipOrRange in ipRanges)
  27. {
  28. // 192.168.0.1
  29. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressRegex))
  30. {
  31. bag.Add(IPAddress.Parse(ipOrRange));
  32. continue;
  33. }
  34. // 192.168.0.0/24 or 192.168.0.0/255.255.255.0
  35. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressCidrRegex) || Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressSubnetmaskRegex))
  36. {
  37. var network = IPNetwork.Parse(ipOrRange);
  38. Parallel.For(IPv4Address.ToInt32(network.Network), IPv4Address.ToInt32(network.Broadcast) + 1, parallelOptions, i =>
  39. {
  40. bag.Add(IPv4Address.FromInt32(i));
  41. parallelOptions.CancellationToken.ThrowIfCancellationRequested();
  42. });
  43. continue;
  44. }
  45. // 192.168.0.0 - 192.168.0.100
  46. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressRangeRegex))
  47. {
  48. var range = ipOrRange.Split('-');
  49. Parallel.For(IPv4Address.ToInt32(IPAddress.Parse(range[0])), IPv4Address.ToInt32(IPAddress.Parse(range[1])) + 1, parallelOptions, i =>
  50. {
  51. bag.Add(IPv4Address.FromInt32(i));
  52. parallelOptions.CancellationToken.ThrowIfCancellationRequested();
  53. });
  54. continue;
  55. }
  56. // 192.168.[50-100,200].1 --> 192.168.50.1, 192.168.51.1, 192.168.52.1, {..}, 192.168.200.1
  57. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressSpecialRangeRegex))
  58. {
  59. var octets = ipOrRange.Split('.');
  60. var list = new List<List<int>>();
  61. // Go through each octet...
  62. foreach (var octet in octets)
  63. {
  64. var innerList = new List<int>();
  65. // Create a range for each octet
  66. if (Regex.IsMatch(octet, RegexHelper.SpecialRangeRegex))
  67. {
  68. foreach (var numberOrRange in octet.Substring(1, octet.Length - 2).Split(','))
  69. {
  70. // 50-100
  71. if (numberOrRange.Contains("-"))
  72. {
  73. var rangeNumbers = numberOrRange.Split('-');
  74. for (var i = int.Parse(rangeNumbers[0]); i < (int.Parse(rangeNumbers[1]) + 1); i++)
  75. {
  76. innerList.Add(i);
  77. }
  78. } // 200
  79. else
  80. {
  81. innerList.Add(int.Parse(numberOrRange));
  82. }
  83. }
  84. }
  85. else
  86. {
  87. innerList.Add(int.Parse(octet));
  88. }
  89. list.Add(innerList);
  90. }
  91. // Build the new ipv4
  92. foreach (var i in list[0])
  93. {
  94. foreach (var j in list[1])
  95. {
  96. foreach (var k in list[2])
  97. {
  98. foreach (var h in list[3])
  99. {
  100. bag.Add(IPAddress.Parse($"{i}.{j}.{k}.{h}"));
  101. }
  102. }
  103. }
  104. }
  105. continue;
  106. }
  107. // 2001:db8:85a3::8a2e:370:7334
  108. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv6AddressRegex))
  109. {
  110. bag.Add(IPAddress.Parse(ipOrRange));
  111. }
  112. }
  113. return bag.ToArray();
  114. }
  115. public static Task<List<string>> ResolveHostnamesInIPRangesAsync(string[] ipRanges, CancellationToken cancellationToken)
  116. {
  117. return Task.Run(() => ResolveHostnamesInIPRanges(ipRanges, cancellationToken), cancellationToken);
  118. }
  119. public static List<string> ResolveHostnamesInIPRanges(string[] ipRanges, CancellationToken cancellationToken)
  120. {
  121. var bag = new ConcurrentBag<string>();
  122. var exceptions = new ConcurrentQueue<HostNotFoundException>();
  123. Parallel.ForEach(ipRanges, new ParallelOptions { CancellationToken = cancellationToken }, ipHostOrRange =>
  124. {
  125. // 192.168.0.1
  126. if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressRegex))
  127. {
  128. bag.Add(ipHostOrRange);
  129. }
  130. // 192.168.0.0/24
  131. else if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressCidrRegex))
  132. {
  133. bag.Add(ipHostOrRange);
  134. }
  135. // 192.168.0.0/255.255.255.0
  136. else if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressSubnetmaskRegex))
  137. {
  138. bag.Add(ipHostOrRange);
  139. }
  140. // 192.168.0.0 - 192.168.0.100
  141. else if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressRangeRegex))
  142. {
  143. bag.Add(ipHostOrRange);
  144. }
  145. // 192.168.[50-100].1
  146. else if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv4AddressSpecialRangeRegex))
  147. {
  148. bag.Add(ipHostOrRange);
  149. }
  150. // 2001:db8:85a3::8a2e:370:7334
  151. else if (Regex.IsMatch(ipHostOrRange, RegexHelper.IPv6AddressRegex))
  152. {
  153. bag.Add(ipHostOrRange);
  154. }
  155. // example.com
  156. else if(Regex.IsMatch(ipHostOrRange, RegexHelper.HostnameRegex))
  157. {
  158. // Wait for task inside a Parallel.Foreach
  159. var dnsResovlerTask = DnsLookupHelper.ResolveIPAddress(ipHostOrRange);
  160. Task.WaitAll(dnsResovlerTask);
  161. bag.Add($"{dnsResovlerTask.Result}");
  162. }
  163. // example.com/24 or example.com/255.255.255.128
  164. else if (Regex.IsMatch(ipHostOrRange, RegexHelper.HostnameCidrRegex) || Regex.IsMatch(ipHostOrRange, RegexHelper.HostnameSubnetmaskRegex))
  165. {
  166. var hostAndSubnet = ipHostOrRange.Split('/');
  167. // Wait for task inside a Parallel.Foreach
  168. var dnsResovlerTask = DnsLookupHelper.ResolveIPAddress(hostAndSubnet[0]);
  169. Task.WaitAll(dnsResovlerTask);
  170. // IPv6 is not supported for ranges
  171. if (dnsResovlerTask.Result == null || dnsResovlerTask.Result.AddressFamily != AddressFamily.InterNetwork)
  172. {
  173. exceptions.Enqueue(new HostNotFoundException(hostAndSubnet[0]));
  174. return;
  175. }
  176. bag.Add($"{dnsResovlerTask.Result}/{hostAndSubnet[1]}");
  177. }
  178. });
  179. if (exceptions.Count > 0)
  180. throw new AggregateException(exceptions);
  181. return bag.ToList();
  182. }
  183. }
  184. }