aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs')
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs2170
1 files changed, 2170 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
new file mode 100644
index 000000000..6d7785b90
--- /dev/null
+++ b/Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs
@@ -0,0 +1,2170 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+using System.Numerics;
+using System.Text.RegularExpressions;
+
+namespace System.Net
+{
+ /// <summary>
+ /// IP Network utility class.
+ /// Use IPNetwork.Parse to create instances.
+ /// </summary>
+ public class IPNetwork : IComparable<IPNetwork>
+ {
+
+ #region properties
+
+ //private uint _network;
+ private BigInteger _ipaddress;
+ private AddressFamily _family;
+ //private uint _netmask;
+ //private uint _broadcast;
+ //private uint _firstUsable;
+ //private uint _lastUsable;
+ //private uint _usable;
+ private byte _cidr;
+
+ #endregion
+
+ #region accessors
+
+ private BigInteger _network
+ {
+ get
+ {
+ BigInteger uintNetwork = this._ipaddress & this._netmask;
+ return uintNetwork;
+ }
+ }
+
+ /// <summary>
+ /// Network address
+ /// </summary>
+ public IPAddress Network
+ {
+ get
+ {
+
+ return IPNetwork.ToIPAddress(this._network, this._family);
+ }
+ }
+
+ /// <summary>
+ /// Address Family
+ /// </summary>
+ public AddressFamily AddressFamily
+ {
+ get
+ {
+ return this._family;
+ }
+ }
+
+ private BigInteger _netmask
+ {
+ get
+ {
+ return IPNetwork.ToUint(this._cidr, this._family);
+ }
+ }
+
+ /// <summary>
+ /// Netmask
+ /// </summary>
+ public IPAddress Netmask
+ {
+ get
+ {
+ return IPNetwork.ToIPAddress(this._netmask, this._family);
+ }
+ }
+
+ private BigInteger _broadcast
+ {
+ get
+ {
+
+ int width = this._family == Sockets.AddressFamily.InterNetwork ? 4 : 16;
+ BigInteger uintBroadcast = this._network + this._netmask.PositiveReverse(width);
+ return uintBroadcast;
+ }
+ }
+
+ /// <summary>
+ /// Broadcast address
+ /// </summary>
+ public IPAddress Broadcast
+ {
+ get
+ {
+ if (this._family == Sockets.AddressFamily.InterNetworkV6)
+ {
+ return null;
+ }
+ return IPNetwork.ToIPAddress(this._broadcast, this._family);
+ }
+ }
+
+ /// <summary>
+ /// First usable IP adress in Network
+ /// </summary>
+ public IPAddress FirstUsable
+ {
+ get
+ {
+ BigInteger fisrt = this._family == Sockets.AddressFamily.InterNetworkV6
+ ? this._network
+ : (this.Usable <= 0) ? this._network : this._network + 1;
+ return IPNetwork.ToIPAddress(fisrt, this._family);
+ }
+ }
+
+ /// <summary>
+ /// Last usable IP adress in Network
+ /// </summary>
+ public IPAddress LastUsable
+ {
+ get
+ {
+ BigInteger last = this._family == Sockets.AddressFamily.InterNetworkV6
+ ? this._broadcast
+ : (this.Usable <= 0) ? this._network : this._broadcast - 1;
+ return IPNetwork.ToIPAddress(last, this._family);
+ }
+ }
+
+ /// <summary>
+ /// Number of usable IP adress in Network
+ /// </summary>
+ public BigInteger Usable
+ {
+ get
+ {
+
+ if (this._family == Sockets.AddressFamily.InterNetworkV6)
+ {
+ return this.Total;
+ }
+ byte[] mask = new byte[] { 0xff, 0xff, 0xff, 0xff, 0x00 };
+ BigInteger bmask = new BigInteger(mask);
+ BigInteger usableIps = (_cidr > 30) ? 0 : ((bmask >> _cidr) - 1);
+ return usableIps;
+ }
+ }
+
+ /// <summary>
+ /// Number of IP adress in Network
+ /// </summary>
+ public BigInteger Total
+ {
+ get
+ {
+
+ int max = this._family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ BigInteger count = BigInteger.Pow(2, (max - _cidr));
+ return count;
+ }
+ }
+
+
+ /// <summary>
+ /// The CIDR netmask notation
+ /// </summary>
+ public byte Cidr
+ {
+ get
+ {
+ return this._cidr;
+ }
+ }
+
+ #endregion
+
+ #region constructor
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+
+ IPNetwork(BigInteger ipaddress, AddressFamily family, byte cidr)
+ {
+
+ int maxCidr = family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ if (cidr > maxCidr)
+ {
+ throw new ArgumentOutOfRangeException("cidr");
+ }
+
+ this._ipaddress = ipaddress;
+ this._family = family;
+ this._cidr = cidr;
+
+ }
+
+ #endregion
+
+ #region parsers
+
+ /// <summary>
+ /// 192.168.168.100 - 255.255.255.0
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static IPNetwork Parse(string ipaddress, string netmask)
+ {
+
+ IPNetwork ipnetwork = null;
+ IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
+ return ipnetwork;
+ }
+
+ /// <summary>
+ /// 192.168.168.100/24
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static IPNetwork Parse(string ipaddress, byte cidr)
+ {
+
+ IPNetwork ipnetwork = null;
+ IPNetwork.InternalParse(false, ipaddress, cidr, out ipnetwork);
+ return ipnetwork;
+
+ }
+
+ /// <summary>
+ /// 192.168.168.100 255.255.255.0
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static IPNetwork Parse(IPAddress ipaddress, IPAddress netmask)
+ {
+
+ IPNetwork ipnetwork = null;
+ IPNetwork.InternalParse(false, ipaddress, netmask, out ipnetwork);
+ return ipnetwork;
+
+ }
+
+ /// <summary>
+ /// 192.168.0.1/24
+ /// 192.168.0.1 255.255.255.0
+ ///
+ /// Network : 192.168.0.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.0.1
+ /// End : 192.168.0.254
+ /// Broadcast : 192.168.0.255
+ /// </summary>
+ /// <param name="network"></param>
+ /// <returns></returns>
+ public static IPNetwork Parse(string network)
+ {
+
+ IPNetwork ipnetwork = null;
+ IPNetwork.InternalParse(false, network, out ipnetwork);
+ return ipnetwork;
+
+ }
+
+ #endregion
+
+ #region TryParse
+
+
+
+ /// <summary>
+ /// 192.168.168.100 - 255.255.255.0
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static bool TryParse(string ipaddress, string netmask, out IPNetwork ipnetwork)
+ {
+
+ IPNetwork ipnetwork2 = null;
+ IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
+ bool parsed = (ipnetwork2 != null);
+ ipnetwork = ipnetwork2;
+ return parsed;
+
+ }
+
+
+
+ /// <summary>
+ /// 192.168.168.100/24
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static bool TryParse(string ipaddress, byte cidr, out IPNetwork ipnetwork)
+ {
+
+ IPNetwork ipnetwork2 = null;
+ IPNetwork.InternalParse(true, ipaddress, cidr, out ipnetwork2);
+ bool parsed = (ipnetwork2 != null);
+ ipnetwork = ipnetwork2;
+ return parsed;
+
+ }
+
+ /// <summary>
+ /// 192.168.0.1/24
+ /// 192.168.0.1 255.255.255.0
+ ///
+ /// Network : 192.168.0.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.0.1
+ /// End : 192.168.0.254
+ /// Broadcast : 192.168.0.255
+ /// </summary>
+ /// <param name="network"></param>
+ /// <param name="ipnetwork"></param>
+ /// <returns></returns>
+ public static bool TryParse(string network, out IPNetwork ipnetwork)
+ {
+
+ IPNetwork ipnetwork2 = null;
+ IPNetwork.InternalParse(true, network, out ipnetwork2);
+ bool parsed = (ipnetwork2 != null);
+ ipnetwork = ipnetwork2;
+ return parsed;
+
+ }
+
+ /// <summary>
+ /// 192.168.0.1/24
+ /// 192.168.0.1 255.255.255.0
+ ///
+ /// Network : 192.168.0.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.0.1
+ /// End : 192.168.0.254
+ /// Broadcast : 192.168.0.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="netmask"></param>
+ /// <param name="ipnetwork"></param>
+ /// <returns></returns>
+ public static bool TryParse(IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
+ {
+
+ IPNetwork ipnetwork2 = null;
+ IPNetwork.InternalParse(true, ipaddress, netmask, out ipnetwork2);
+ bool parsed = (ipnetwork2 != null);
+ ipnetwork = ipnetwork2;
+ return parsed;
+
+ }
+
+
+ #endregion
+
+ #region InternalParse
+
+ /// <summary>
+ /// 192.168.168.100 - 255.255.255.0
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ private static void InternalParse(bool tryParse, string ipaddress, string netmask, out IPNetwork ipnetwork)
+ {
+
+ if (string.IsNullOrEmpty(ipaddress))
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("ipaddress");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ if (string.IsNullOrEmpty(netmask))
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("netmask");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ IPAddress ip = null;
+ bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
+ if (ipaddressParsed == false)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("ipaddress");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ IPAddress mask = null;
+ bool netmaskParsed = IPAddress.TryParse(netmask, out mask);
+ if (netmaskParsed == false)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("netmask");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
+ }
+
+ private static void InternalParse(bool tryParse, string network, out IPNetwork ipnetwork)
+ {
+
+ if (string.IsNullOrEmpty(network))
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("network");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ network = Regex.Replace(network, @"[^0-9a-fA-F\.\/\s\:]+", "");
+ network = Regex.Replace(network, @"\s{2,}", " ");
+ network = network.Trim();
+ string[] args = network.Split(new char[] { ' ', '/' });
+ byte cidr = 0;
+ if (args.Length == 1)
+ {
+
+ if (IPNetwork.TryGuessCidr(args[0], out cidr))
+ {
+ IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
+ return;
+ }
+
+ if (tryParse == false)
+ {
+ throw new ArgumentException("network");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ if (byte.TryParse(args[1], out cidr))
+ {
+ IPNetwork.InternalParse(tryParse, args[0], cidr, out ipnetwork);
+ return;
+ }
+
+ IPNetwork.InternalParse(tryParse, args[0], args[1], out ipnetwork);
+ return;
+
+ }
+
+
+
+ /// <summary>
+ /// 192.168.168.100 255.255.255.0
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ private static void InternalParse(bool tryParse, IPAddress ipaddress, IPAddress netmask, out IPNetwork ipnetwork)
+ {
+
+ if (ipaddress == null)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("ipaddress");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ if (netmask == null)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("netmask");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ BigInteger uintIpAddress = IPNetwork.ToBigInteger(ipaddress);
+ byte? cidr2 = null;
+ bool parsed = IPNetwork.TryToCidr(netmask, out cidr2);
+ if (parsed == false)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("netmask");
+ }
+ ipnetwork = null;
+ return;
+ }
+ byte cidr = (byte)cidr2;
+
+ IPNetwork ipnet = new IPNetwork(uintIpAddress, ipaddress.AddressFamily, cidr);
+ ipnetwork = ipnet;
+
+ return;
+ }
+
+
+
+ /// <summary>
+ /// 192.168.168.100/24
+ ///
+ /// Network : 192.168.168.0
+ /// Netmask : 255.255.255.0
+ /// Cidr : 24
+ /// Start : 192.168.168.1
+ /// End : 192.168.168.254
+ /// Broadcast : 192.168.168.255
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ private static void InternalParse(bool tryParse, string ipaddress, byte cidr, out IPNetwork ipnetwork)
+ {
+
+ if (string.IsNullOrEmpty(ipaddress))
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("ipaddress");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+
+ IPAddress ip = null;
+ bool ipaddressParsed = IPAddress.TryParse(ipaddress, out ip);
+ if (ipaddressParsed == false)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("ipaddress");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ IPAddress mask = null;
+ bool parsedNetmask = IPNetwork.TryToNetmask(cidr, ip.AddressFamily, out mask);
+ if (parsedNetmask == false)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("cidr");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+
+ IPNetwork.InternalParse(tryParse, ip, mask, out ipnetwork);
+ }
+
+ #endregion
+
+ #region converters
+
+ #region ToUint
+
+ /// <summary>
+ /// Convert an ipadress to decimal
+ /// 0.0.0.0 -> 0
+ /// 0.0.1.0 -> 256
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <returns></returns>
+ public static BigInteger ToBigInteger(IPAddress ipaddress)
+ {
+ BigInteger? uintIpAddress = null;
+ IPNetwork.InternalToBigInteger(false, ipaddress, out uintIpAddress);
+ return (BigInteger)uintIpAddress;
+
+ }
+
+ /// <summary>
+ /// Convert an ipadress to decimal
+ /// 0.0.0.0 -> 0
+ /// 0.0.1.0 -> 256
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <returns></returns>
+ public static bool TryToBigInteger(IPAddress ipaddress, out BigInteger? uintIpAddress)
+ {
+ BigInteger? uintIpAddress2 = null;
+ IPNetwork.InternalToBigInteger(true, ipaddress, out uintIpAddress2);
+ bool parsed = (uintIpAddress2 != null);
+ uintIpAddress = uintIpAddress2;
+ return parsed;
+ }
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static void InternalToBigInteger(bool tryParse, IPAddress ipaddress, out BigInteger? uintIpAddress)
+ {
+
+ if (ipaddress == null)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("ipaddress");
+ }
+ uintIpAddress = null;
+ return;
+ }
+
+ byte[] bytes = ipaddress.GetAddressBytes();
+ /// 20180217 lduchosal
+ /// code impossible to reach, GetAddressBytes returns either 4 or 16 bytes length addresses
+ /// if (bytes.Length != 4 && bytes.Length != 16) {
+ /// if (tryParse == false) {
+ /// throw new ArgumentException("bytes");
+ /// }
+ /// uintIpAddress = null;
+ /// return;
+ /// }
+
+ Array.Reverse(bytes);
+ var unsigned = new List<byte>(bytes);
+ unsigned.Add(0);
+ uintIpAddress = new BigInteger(unsigned.ToArray());
+ return;
+ }
+
+
+ /// <summary>
+ /// Convert a cidr to BigInteger netmask
+ /// </summary>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static BigInteger ToUint(byte cidr, AddressFamily family)
+ {
+
+ BigInteger? uintNetmask = null;
+ IPNetwork.InternalToBigInteger(false, cidr, family, out uintNetmask);
+ return (BigInteger)uintNetmask;
+ }
+
+
+ /// <summary>
+ /// Convert a cidr to uint netmask
+ /// </summary>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static bool TryToUint(byte cidr, AddressFamily family, out BigInteger? uintNetmask)
+ {
+
+ BigInteger? uintNetmask2 = null;
+ IPNetwork.InternalToBigInteger(true, cidr, family, out uintNetmask2);
+ bool parsed = (uintNetmask2 != null);
+ uintNetmask = uintNetmask2;
+ return parsed;
+ }
+
+ /// <summary>
+ /// Convert a cidr to uint netmask
+ /// </summary>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static void InternalToBigInteger(bool tryParse, byte cidr, AddressFamily family, out BigInteger? uintNetmask)
+ {
+
+ if (family == AddressFamily.InterNetwork && cidr > 32)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentOutOfRangeException("cidr");
+ }
+ uintNetmask = null;
+ return;
+ }
+
+ if (family == AddressFamily.InterNetworkV6 && cidr > 128)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentOutOfRangeException("cidr");
+ }
+ uintNetmask = null;
+ return;
+ }
+
+ if (family != AddressFamily.InterNetwork
+ && family != AddressFamily.InterNetworkV6)
+ {
+ if (tryParse == false)
+ {
+ throw new NotSupportedException(family.ToString());
+ }
+ uintNetmask = null;
+ return;
+ }
+
+ if (family == AddressFamily.InterNetwork)
+ {
+
+ uintNetmask = cidr == 0 ? 0 : 0xffffffff << (32 - cidr);
+ return;
+ }
+
+ BigInteger mask = new BigInteger(new byte[] {
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x00
+ });
+
+ BigInteger masked = cidr == 0 ? 0 : mask << (128 - cidr);
+ byte[] m = masked.ToByteArray();
+ byte[] bmask = new byte[17];
+ int copy = m.Length > 16 ? 16 : m.Length;
+ Array.Copy(m, 0, bmask, 0, copy);
+ uintNetmask = new BigInteger(bmask);
+
+
+ }
+
+ #endregion
+
+ #region ToCidr
+
+ /// <summary>
+ /// Convert netmask to CIDR
+ /// 255.255.255.0 -> 24
+ /// 255.255.0.0 -> 16
+ /// 255.0.0.0 -> 8
+ /// </summary>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ private static void InternalToCidr(bool tryParse, BigInteger netmask, AddressFamily family, out byte? cidr)
+ {
+
+ if (!IPNetwork.InternalValidNetmask(netmask, family))
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("netmask");
+ }
+ cidr = null;
+ return;
+ }
+
+ byte cidr2 = IPNetwork.BitsSet(netmask, family);
+ cidr = cidr2;
+ return;
+
+ }
+ /// <summary>
+ /// Convert netmask to CIDR
+ /// 255.255.255.0 -> 24
+ /// 255.255.0.0 -> 16
+ /// 255.0.0.0 -> 8
+ /// </summary>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static byte ToCidr(IPAddress netmask)
+ {
+ byte? cidr = null;
+ IPNetwork.InternalToCidr(false, netmask, out cidr);
+ return (byte)cidr;
+ }
+
+ /// <summary>
+ /// Convert netmask to CIDR
+ /// 255.255.255.0 -> 24
+ /// 255.255.0.0 -> 16
+ /// 255.0.0.0 -> 8
+ /// </summary>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static bool TryToCidr(IPAddress netmask, out byte? cidr)
+ {
+ byte? cidr2 = null;
+ IPNetwork.InternalToCidr(true, netmask, out cidr2);
+ bool parsed = (cidr2 != null);
+ cidr = cidr2;
+ return parsed;
+ }
+
+ private static void InternalToCidr(bool tryParse, IPAddress netmask, out byte? cidr)
+ {
+
+ if (netmask == null)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentNullException("netmask");
+ }
+ cidr = null;
+ return;
+ }
+ BigInteger? uintNetmask2 = null;
+ bool parsed = IPNetwork.TryToBigInteger(netmask, out uintNetmask2);
+
+ /// 20180217 lduchosal
+ /// impossible to reach code.
+ /// if (parsed == false) {
+ /// if (tryParse == false) {
+ /// throw new ArgumentException("netmask");
+ /// }
+ /// cidr = null;
+ /// return;
+ /// }
+ BigInteger uintNetmask = (BigInteger)uintNetmask2;
+
+ byte? cidr2 = null;
+ IPNetwork.InternalToCidr(tryParse, uintNetmask, netmask.AddressFamily, out cidr2);
+ cidr = cidr2;
+
+ return;
+
+ }
+
+
+ #endregion
+
+ #region ToNetmask
+
+ /// <summary>
+ /// Convert CIDR to netmask
+ /// 24 -> 255.255.255.0
+ /// 16 -> 255.255.0.0
+ /// 8 -> 255.0.0.0
+ /// </summary>
+ /// <see cref="http://snipplr.com/view/15557/cidr-class-for-ipv4/"/>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static IPAddress ToNetmask(byte cidr, AddressFamily family)
+ {
+
+ IPAddress netmask = null;
+ IPNetwork.InternalToNetmask(false, cidr, family, out netmask);
+ return netmask;
+ }
+
+ /// <summary>
+ /// Convert CIDR to netmask
+ /// 24 -> 255.255.255.0
+ /// 16 -> 255.255.0.0
+ /// 8 -> 255.0.0.0
+ /// </summary>
+ /// <see cref="http://snipplr.com/view/15557/cidr-class-for-ipv4/"/>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static bool TryToNetmask(byte cidr, AddressFamily family, out IPAddress netmask)
+ {
+
+ IPAddress netmask2 = null;
+ IPNetwork.InternalToNetmask(true, cidr, family, out netmask2);
+ bool parsed = (netmask2 != null);
+ netmask = netmask2;
+ return parsed;
+ }
+
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static void InternalToNetmask(bool tryParse, byte cidr, AddressFamily family, out IPAddress netmask)
+ {
+
+ if (family != AddressFamily.InterNetwork
+ && family != AddressFamily.InterNetworkV6)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentException("family");
+ }
+ netmask = null;
+ return;
+ }
+
+ /// 20180217 lduchosal
+ /// impossible to reach code, byte cannot be negative :
+ ///
+ /// if (cidr < 0) {
+ /// if (tryParse == false) {
+ /// throw new ArgumentOutOfRangeException("cidr");
+ /// }
+ /// netmask = null;
+ /// return;
+ /// }
+
+ int maxCidr = family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ if (cidr > maxCidr)
+ {
+ if (tryParse == false)
+ {
+ throw new ArgumentOutOfRangeException("cidr");
+ }
+ netmask = null;
+ return;
+ }
+
+ BigInteger mask = IPNetwork.ToUint(cidr, family);
+ IPAddress netmask2 = IPNetwork.ToIPAddress(mask, family);
+ netmask = netmask2;
+
+ return;
+ }
+
+ #endregion
+
+ #endregion
+
+ #region utils
+
+ #region BitsSet
+
+ /// <summary>
+ /// Count bits set to 1 in netmask
+ /// </summary>
+ /// <see cref="http://stackoverflow.com/questions/109023/best-algorithm-to-count-the-number-of-set-bits-in-a-32-bit-integer"/>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ private static byte BitsSet(BigInteger netmask, AddressFamily family)
+ {
+
+ string s = netmask.ToBinaryString();
+ return (byte)s.Replace("0", "")
+ .ToCharArray()
+ .Length;
+
+ }
+
+
+ /// <summary>
+ /// Count bits set to 1 in netmask
+ /// </summary>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static uint BitsSet(IPAddress netmask)
+ {
+ BigInteger uintNetmask = IPNetwork.ToBigInteger(netmask);
+ uint bits = IPNetwork.BitsSet(uintNetmask, netmask.AddressFamily);
+ return bits;
+ }
+
+ #endregion
+
+ #region ValidNetmask
+
+ /// <summary>
+ /// return true if netmask is a valid netmask
+ /// 255.255.255.0, 255.0.0.0, 255.255.240.0, ...
+ /// </summary>
+ /// <see cref="http://www.actionsnip.com/snippets/tomo_atlacatl/calculate-if-a-netmask-is-valid--as2-"/>
+ /// <param name="netmask"></param>
+ /// <returns></returns>
+ public static bool ValidNetmask(IPAddress netmask)
+ {
+
+ if (netmask == null)
+ {
+ throw new ArgumentNullException("netmask");
+ }
+ BigInteger uintNetmask = IPNetwork.ToBigInteger(netmask);
+ bool valid = IPNetwork.InternalValidNetmask(uintNetmask, netmask.AddressFamily);
+ return valid;
+ }
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static bool InternalValidNetmask(BigInteger netmask, AddressFamily family)
+ {
+
+ if (family != AddressFamily.InterNetwork
+ && family != AddressFamily.InterNetworkV6)
+ {
+ throw new ArgumentException("family");
+ }
+
+ var mask = family == AddressFamily.InterNetwork
+ ? new BigInteger(0x0ffffffff)
+ : new BigInteger(new byte[]{
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x00
+ });
+
+ BigInteger neg = ((~netmask) & (mask));
+ bool isNetmask = ((neg + 1) & neg) == 0;
+ return isNetmask;
+
+ }
+
+ #endregion
+
+ #region ToIPAddress
+
+ /// <summary>
+ /// Transform a uint ipaddress into IPAddress object
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <returns></returns>
+ public static IPAddress ToIPAddress(BigInteger ipaddress, AddressFamily family)
+ {
+
+ int width = family == AddressFamily.InterNetwork ? 4 : 16;
+ byte[] bytes = ipaddress.ToByteArray();
+ byte[] bytes2 = new byte[width];
+ int copy = bytes.Length > width ? width : bytes.Length;
+ Array.Copy(bytes, 0, bytes2, 0, copy);
+ Array.Reverse(bytes2);
+
+ byte[] sized = Resize(bytes2, family);
+ IPAddress ip = new IPAddress(sized);
+ return ip;
+ }
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static byte[] Resize(byte[] bytes, AddressFamily family)
+ {
+
+ if (family != AddressFamily.InterNetwork
+ && family != AddressFamily.InterNetworkV6)
+ {
+ throw new ArgumentException("family");
+ }
+
+ int width = family == AddressFamily.InterNetwork ? 4 : 16;
+
+ if (bytes.Length > width)
+ {
+ throw new ArgumentException("bytes");
+ }
+
+ byte[] result = new byte[width];
+ Array.Copy(bytes, 0, result, 0, bytes.Length);
+ return result;
+ }
+
+ #endregion
+
+ #endregion
+
+ #region contains
+
+ /// <summary>
+ /// return true if ipaddress is contained in network
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <returns></returns>
+ public bool Contains(IPAddress ipaddress)
+ {
+
+ if (ipaddress == null)
+ {
+ throw new ArgumentNullException("ipaddress");
+ }
+
+ if (AddressFamily != ipaddress.AddressFamily)
+ {
+ return false;
+ }
+
+ BigInteger uintNetwork = _network;
+ BigInteger uintBroadcast = _broadcast;
+ BigInteger uintAddress = IPNetwork.ToBigInteger(ipaddress);
+
+ bool contains = (uintAddress >= uintNetwork
+ && uintAddress <= uintBroadcast);
+
+ return contains;
+
+ }
+
+ [Obsolete("static Contains is deprecated, please use instance Contains.")]
+ public static bool Contains(IPNetwork network, IPAddress ipaddress)
+ {
+
+ if (network == null)
+ {
+ throw new ArgumentNullException("network");
+ }
+
+ return network.Contains(ipaddress);
+ }
+
+ /// <summary>
+ /// return true is network2 is fully contained in network
+ /// </summary>
+ /// <param name="network2"></param>
+ /// <returns></returns>
+ public bool Contains(IPNetwork network2)
+ {
+
+ if (network2 == null)
+ {
+ throw new ArgumentNullException("network2");
+ }
+
+ BigInteger uintNetwork = _network;
+ BigInteger uintBroadcast = _broadcast;
+
+ BigInteger uintFirst = network2._network;
+ BigInteger uintLast = network2._broadcast;
+
+ bool contains = (uintFirst >= uintNetwork
+ && uintLast <= uintBroadcast);
+
+ return contains;
+ }
+
+ [Obsolete("static Contains is deprecated, please use instance Contains.")]
+ public static bool Contains(IPNetwork network, IPNetwork network2)
+ {
+
+ if (network == null)
+ {
+ throw new ArgumentNullException("network");
+ }
+
+ return network.Contains(network2);
+ }
+
+ #endregion
+
+ #region overlap
+
+ /// <summary>
+ /// return true is network2 overlap network
+ /// </summary>
+ /// <param name="network2"></param>
+ /// <returns></returns>
+ public bool Overlap(IPNetwork network2)
+ {
+
+ if (network2 == null)
+ {
+ throw new ArgumentNullException("network2");
+ }
+
+ BigInteger uintNetwork = _network;
+ BigInteger uintBroadcast = _broadcast;
+
+ BigInteger uintFirst = network2._network;
+ BigInteger uintLast = network2._broadcast;
+
+ bool overlap =
+ (uintFirst >= uintNetwork && uintFirst <= uintBroadcast)
+ || (uintLast >= uintNetwork && uintLast <= uintBroadcast)
+ || (uintFirst <= uintNetwork && uintLast >= uintBroadcast)
+ || (uintFirst >= uintNetwork && uintLast <= uintBroadcast);
+
+ return overlap;
+ }
+
+ [Obsolete("static Overlap is deprecated, please use instance Overlap.")]
+ public static bool Overlap(IPNetwork network, IPNetwork network2)
+ {
+
+ if (network == null)
+ {
+ throw new ArgumentNullException("network");
+ }
+
+ return network.Overlap(network2);
+ }
+
+ #endregion
+
+ #region ToString
+
+ public override string ToString()
+ {
+ return string.Format("{0}/{1}", this.Network, this.Cidr);
+ }
+
+ #endregion
+
+ #region IANA block
+
+ private static readonly Lazy<IPNetwork> _iana_ablock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("10.0.0.0/8"));
+ private static readonly Lazy<IPNetwork> _iana_bblock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("172.16.0.0/12"));
+ private static readonly Lazy<IPNetwork> _iana_cblock_reserved = new Lazy<IPNetwork>(() => IPNetwork.Parse("192.168.0.0/16"));
+
+ /// <summary>
+ /// 10.0.0.0/8
+ /// </summary>
+ /// <returns></returns>
+ public static IPNetwork IANA_ABLK_RESERVED1
+ {
+ get
+ {
+ return _iana_ablock_reserved.Value;
+ }
+ }
+
+ /// <summary>
+ /// 172.12.0.0/12
+ /// </summary>
+ /// <returns></returns>
+ public static IPNetwork IANA_BBLK_RESERVED1
+ {
+ get
+ {
+ return _iana_bblock_reserved.Value;
+ }
+ }
+
+ /// <summary>
+ /// 192.168.0.0/16
+ /// </summary>
+ /// <returns></returns>
+ public static IPNetwork IANA_CBLK_RESERVED1
+ {
+ get
+ {
+ return _iana_cblock_reserved.Value;
+ }
+ }
+
+ /// <summary>
+ /// return true if ipaddress is contained in
+ /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
+ /// </summary>
+ /// <param name="ipaddress"></param>
+ /// <returns></returns>
+ public static bool IsIANAReserved(IPAddress ipaddress)
+ {
+
+ if (ipaddress == null)
+ {
+ throw new ArgumentNullException("ipaddress");
+ }
+
+ return IPNetwork.IANA_ABLK_RESERVED1.Contains(ipaddress)
+ || IPNetwork.IANA_BBLK_RESERVED1.Contains(ipaddress)
+ || IPNetwork.IANA_CBLK_RESERVED1.Contains(ipaddress);
+ }
+
+ /// <summary>
+ /// return true if ipnetwork is contained in
+ /// IANA_ABLK_RESERVED1, IANA_BBLK_RESERVED1, IANA_CBLK_RESERVED1
+ /// </summary>
+ /// <returns></returns>
+ public bool IsIANAReserved()
+ {
+ return IPNetwork.IANA_ABLK_RESERVED1.Contains(this)
+ || IPNetwork.IANA_BBLK_RESERVED1.Contains(this)
+ || IPNetwork.IANA_CBLK_RESERVED1.Contains(this);
+ }
+
+ [Obsolete("static IsIANAReserved is deprecated, please use instance IsIANAReserved.")]
+ public static bool IsIANAReserved(IPNetwork ipnetwork)
+ {
+
+ if (ipnetwork == null)
+ {
+ throw new ArgumentNullException("ipnetwork");
+ }
+
+ return ipnetwork.IsIANAReserved();
+ }
+
+ #endregion
+
+ #region Subnet
+
+ /// <summary>
+ /// Subnet a network into multiple nets of cidr mask
+ /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
+ /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
+ /// </summary>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public IPNetworkCollection Subnet(byte cidr)
+ {
+ IPNetworkCollection ipnetworkCollection = null;
+ IPNetwork.InternalSubnet(false, this, cidr, out ipnetworkCollection);
+ return ipnetworkCollection;
+ }
+
+ [Obsolete("static Subnet is deprecated, please use instance Subnet.")]
+ public static IPNetworkCollection Subnet(IPNetwork network, byte cidr)
+ {
+ if (network == null)
+ {
+ throw new ArgumentNullException("network");
+ }
+ return network.Subnet(cidr);
+ }
+
+ /// <summary>
+ /// Subnet a network into multiple nets of cidr mask
+ /// Subnet 192.168.0.0/24 into cidr 25 gives 192.168.0.0/25, 192.168.0.128/25
+ /// Subnet 10.0.0.0/8 into cidr 9 gives 10.0.0.0/9, 10.128.0.0/9
+ /// </summary>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public bool TrySubnet(byte cidr, out IPNetworkCollection ipnetworkCollection)
+ {
+ IPNetworkCollection inc = null;
+ IPNetwork.InternalSubnet(true, this, cidr, out inc);
+ if (inc == null)
+ {
+ ipnetworkCollection = null;
+ return false;
+ }
+
+ ipnetworkCollection = inc;
+ return true;
+ }
+
+ [Obsolete("static TrySubnet is deprecated, please use instance TrySubnet.")]
+ public static bool TrySubnet(IPNetwork network, byte cidr, out IPNetworkCollection ipnetworkCollection)
+ {
+ if (network == null)
+ {
+ throw new ArgumentNullException("network");
+ }
+ return network.TrySubnet(cidr, out ipnetworkCollection);
+ }
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static void InternalSubnet(bool trySubnet, IPNetwork network, byte cidr, out IPNetworkCollection ipnetworkCollection)
+ {
+
+ if (network == null)
+ {
+ if (trySubnet == false)
+ {
+ throw new ArgumentNullException("network");
+ }
+ ipnetworkCollection = null;
+ return;
+ }
+
+ int maxCidr = network._family == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ if (cidr > maxCidr)
+ {
+ if (trySubnet == false)
+ {
+ throw new ArgumentOutOfRangeException("cidr");
+ }
+ ipnetworkCollection = null;
+ return;
+ }
+
+ if (cidr < network.Cidr)
+ {
+ if (trySubnet == false)
+ {
+ throw new ArgumentException("cidr");
+ }
+ ipnetworkCollection = null;
+ return;
+ }
+
+ ipnetworkCollection = new IPNetworkCollection(network, cidr);
+ return;
+ }
+
+
+
+ #endregion
+
+ #region Supernet
+
+ /// <summary>
+ /// Supernet two consecutive cidr equal subnet into a single one
+ /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
+ /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
+ /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
+ /// </summary>
+ /// <param name="network2"></param>
+ /// <returns></returns>
+ public IPNetwork Supernet(IPNetwork network2)
+ {
+ IPNetwork supernet = null;
+ IPNetwork.InternalSupernet(false, this, network2, out supernet);
+ return supernet;
+ }
+
+ [Obsolete("static Supernet is deprecated, please use instance Supernet.")]
+ public static IPNetwork Supernet(IPNetwork network, IPNetwork network2)
+ {
+ return network.Supernet(network2);
+ }
+
+ /// <summary>
+ /// Try to supernet two consecutive cidr equal subnet into a single one
+ /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
+ /// 10.1.0.0/16 + 10.0.0.0/16 = 10.0.0.0/15
+ /// 192.168.0.0/24 + 192.168.0.0/25 = 192.168.0.0/24
+ /// </summary>
+ /// <param name="network2"></param>
+ /// <returns></returns>
+ public bool TrySupernet(IPNetwork network2, out IPNetwork supernet)
+ {
+
+ IPNetwork outSupernet = null;
+ IPNetwork.InternalSupernet(true, this, network2, out outSupernet);
+ bool parsed = (outSupernet != null);
+ supernet = outSupernet;
+ return parsed;
+ }
+
+ [Obsolete("static TrySupernet is deprecated, please use instance TrySupernet.")]
+ public static bool TrySupernet(IPNetwork network, IPNetwork network2, out IPNetwork supernet)
+ {
+ if (network == null)
+ {
+ throw new ArgumentNullException("network");
+ }
+ return network.TrySupernet(network2, out supernet);
+ }
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static void InternalSupernet(bool trySupernet, IPNetwork network1, IPNetwork network2, out IPNetwork supernet)
+ {
+
+ if (network1 == null)
+ {
+ if (trySupernet == false)
+ {
+ throw new ArgumentNullException("network1");
+ }
+ supernet = null;
+ return;
+ }
+
+ if (network2 == null)
+ {
+ if (trySupernet == false)
+ {
+ throw new ArgumentNullException("network2");
+ }
+ supernet = null;
+ return;
+ }
+
+
+ if (network1.Contains(network2))
+ {
+ supernet = new IPNetwork(network1._network, network1._family, network1.Cidr);
+ return;
+ }
+
+ if (network2.Contains(network1))
+ {
+ supernet = new IPNetwork(network2._network, network2._family, network2.Cidr);
+ return;
+ }
+
+ if (network1._cidr != network2._cidr)
+ {
+ if (trySupernet == false)
+ {
+ throw new ArgumentException("cidr");
+ }
+ supernet = null;
+ return;
+ }
+
+ IPNetwork first = (network1._network < network2._network) ? network1 : network2;
+ IPNetwork last = (network1._network > network2._network) ? network1 : network2;
+
+ /// Starting from here :
+ /// network1 and network2 have the same cidr,
+ /// network1 does not contain network2,
+ /// network2 does not contain network1,
+ /// first is the lower subnet
+ /// last is the higher subnet
+
+
+ if ((first._broadcast + 1) != last._network)
+ {
+ if (trySupernet == false)
+ {
+ throw new ArgumentOutOfRangeException("network");
+ }
+ supernet = null;
+ return;
+ }
+
+ BigInteger uintSupernet = first._network;
+ byte cidrSupernet = (byte)(first._cidr - 1);
+
+ IPNetwork networkSupernet = new IPNetwork(uintSupernet, first._family, cidrSupernet);
+ if (networkSupernet._network != first._network)
+ {
+ if (trySupernet == false)
+ {
+ throw new ArgumentException("network");
+ }
+ supernet = null;
+ return;
+ }
+ supernet = networkSupernet;
+ return;
+ }
+
+ #endregion
+
+ #region GetHashCode
+
+ public override int GetHashCode()
+ {
+ return string.Format("{0}|{1}|{2}",
+ this._ipaddress.GetHashCode(),
+ this._network.GetHashCode(),
+ this._cidr.GetHashCode()).GetHashCode();
+ }
+
+ #endregion
+
+ #region SupernetArray
+
+ /// <summary>
+ /// Supernet a list of subnet
+ /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
+ /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
+ /// </summary>
+ /// <param name="ipnetworks"></param>
+ /// <param name="supernet"></param>
+ /// <returns></returns>
+ public static IPNetwork[] Supernet(IPNetwork[] ipnetworks)
+ {
+ IPNetwork[] supernet;
+ InternalSupernet(false, ipnetworks, out supernet);
+ return supernet;
+ }
+
+ /// <summary>
+ /// Supernet a list of subnet
+ /// 192.168.0.0/24 + 192.168.1.0/24 = 192.168.0.0/23
+ /// 192.168.0.0/24 + 192.168.1.0/24 + 192.168.2.0/24 + 192.168.3.0/24 = 192.168.0.0/22
+ /// </summary>
+ /// <param name="ipnetworks"></param>
+ /// <param name="supernet"></param>
+ /// <returns></returns>
+ public static bool TrySupernet(IPNetwork[] ipnetworks, out IPNetwork[] supernet)
+ {
+ bool supernetted = InternalSupernet(true, ipnetworks, out supernet);
+ return supernetted;
+
+ }
+
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ static bool InternalSupernet(bool trySupernet, IPNetwork[] ipnetworks, out IPNetwork[] supernet)
+ {
+
+ if (ipnetworks == null)
+ {
+ if (trySupernet == false)
+ {
+ throw new ArgumentNullException("ipnetworks");
+ }
+ supernet = null;
+ return false;
+ }
+
+ if (ipnetworks.Length <= 0)
+ {
+ supernet = new IPNetwork[0];
+ return true;
+ }
+
+ List<IPNetwork> supernetted = new List<IPNetwork>();
+ List<IPNetwork> ipns = IPNetwork.Array2List(ipnetworks);
+ Stack<IPNetwork> current = IPNetwork.List2Stack(ipns);
+ int previousCount = 0;
+ int currentCount = current.Count;
+
+ while (previousCount != currentCount)
+ {
+
+ supernetted.Clear();
+ while (current.Count > 1)
+ {
+ IPNetwork ipn1 = current.Pop();
+ IPNetwork ipn2 = current.Peek();
+
+ IPNetwork outNetwork = null;
+ bool success = ipn1.TrySupernet(ipn2, out outNetwork);
+ if (success)
+ {
+ current.Pop();
+ current.Push(outNetwork);
+ }
+ else
+ {
+ supernetted.Add(ipn1);
+ }
+ }
+ if (current.Count == 1)
+ {
+ supernetted.Add(current.Pop());
+ }
+
+ previousCount = currentCount;
+ currentCount = supernetted.Count;
+ current = IPNetwork.List2Stack(supernetted);
+
+ }
+ supernet = supernetted.ToArray();
+ return true;
+ }
+
+ private static Stack<IPNetwork> List2Stack(List<IPNetwork> list)
+ {
+ Stack<IPNetwork> stack = new Stack<IPNetwork>();
+ list.ForEach(new Action<IPNetwork>(
+ delegate (IPNetwork ipn)
+ {
+ stack.Push(ipn);
+ }
+ ));
+ return stack;
+ }
+
+ private static List<IPNetwork> Array2List(IPNetwork[] array)
+ {
+ List<IPNetwork> ipns = new List<IPNetwork>();
+ ipns.AddRange(array);
+ IPNetwork.RemoveNull(ipns);
+ ipns.Sort(new Comparison<IPNetwork>(
+ delegate (IPNetwork ipn1, IPNetwork ipn2)
+ {
+ int networkCompare = ipn1._network.CompareTo(ipn2._network);
+ if (networkCompare == 0)
+ {
+ int cidrCompare = ipn1._cidr.CompareTo(ipn2._cidr);
+ return cidrCompare;
+ }
+ return networkCompare;
+ }
+ ));
+ ipns.Reverse();
+
+ return ipns;
+ }
+
+ private static void RemoveNull(List<IPNetwork> ipns)
+ {
+ ipns.RemoveAll(new Predicate<IPNetwork>(
+ delegate (IPNetwork ipn)
+ {
+ if (ipn == null)
+ {
+ return true;
+ }
+ return false;
+ }
+ ));
+
+ }
+
+ #endregion
+
+ #region WideSubnet
+
+ public static IPNetwork WideSubnet(string start, string end)
+ {
+
+ if (string.IsNullOrEmpty(start))
+ {
+ throw new ArgumentNullException("start");
+ }
+
+ if (string.IsNullOrEmpty(end))
+ {
+ throw new ArgumentNullException("end");
+ }
+
+ IPAddress startIP;
+ if (!IPAddress.TryParse(start, out startIP))
+ {
+ throw new ArgumentException("start");
+ }
+
+ IPAddress endIP;
+ if (!IPAddress.TryParse(end, out endIP))
+ {
+ throw new ArgumentException("end");
+ }
+
+ if (startIP.AddressFamily != endIP.AddressFamily)
+ {
+ throw new NotSupportedException("MixedAddressFamily");
+ }
+
+ IPNetwork ipnetwork = new IPNetwork(0, startIP.AddressFamily, 0);
+ for (byte cidr = 32; cidr >= 0; cidr--)
+ {
+ IPNetwork wideSubnet = IPNetwork.Parse(start, cidr);
+ if (wideSubnet.Contains(endIP))
+ {
+ ipnetwork = wideSubnet;
+ break;
+ }
+ }
+ return ipnetwork;
+
+ }
+
+ public static bool TryWideSubnet(IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
+ {
+ IPNetwork ipn = null;
+ IPNetwork.InternalWideSubnet(true, ipnetworks, out ipn);
+ if (ipn == null)
+ {
+ ipnetwork = null;
+ return false;
+ }
+ ipnetwork = ipn;
+ return true;
+ }
+
+ public static IPNetwork WideSubnet(IPNetwork[] ipnetworks)
+ {
+ IPNetwork ipn = null;
+ IPNetwork.InternalWideSubnet(false, ipnetworks, out ipn);
+ return ipn;
+ }
+
+ internal static void InternalWideSubnet(bool tryWide, IPNetwork[] ipnetworks, out IPNetwork ipnetwork)
+ {
+
+ if (ipnetworks == null)
+ {
+ if (tryWide == false)
+ {
+ throw new ArgumentNullException("ipnetworks");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+
+ IPNetwork[] nnin = Array.FindAll<IPNetwork>(ipnetworks, new Predicate<IPNetwork>(
+ delegate (IPNetwork ipnet) {
+ return ipnet != null;
+ }
+ ));
+
+ if (nnin.Length <= 0)
+ {
+ if (tryWide == false)
+ {
+ throw new ArgumentException("ipnetworks");
+ }
+ ipnetwork = null;
+ return;
+ }
+
+ if (nnin.Length == 1)
+ {
+ IPNetwork ipn0 = nnin[0];
+ ipnetwork = ipn0;
+ return;
+ }
+
+ Array.Sort<IPNetwork>(nnin);
+ IPNetwork nnin0 = nnin[0];
+ BigInteger uintNnin0 = nnin0._ipaddress;
+
+ IPNetwork nninX = nnin[nnin.Length - 1];
+ IPAddress ipaddressX = nninX.Broadcast;
+
+ AddressFamily family = ipnetworks[0]._family;
+ foreach (var ipnx in ipnetworks)
+ {
+ if (ipnx._family != family)
+ {
+ throw new ArgumentException("MixedAddressFamily");
+ }
+ }
+
+ IPNetwork ipn = new IPNetwork(0, family, 0);
+ for (byte cidr = nnin0._cidr; cidr >= 0; cidr--)
+ {
+ IPNetwork wideSubnet = new IPNetwork(uintNnin0, family, cidr);
+ if (wideSubnet.Contains(ipaddressX))
+ {
+ ipn = wideSubnet;
+ break;
+ }
+ }
+
+ ipnetwork = ipn;
+ return;
+ }
+
+ #endregion
+
+ #region Print
+
+ /// <summary>
+ /// Print an ipnetwork in a clear representation string
+ /// </summary>
+ /// <returns></returns>
+ public string Print()
+ {
+
+ StringWriter sw = new StringWriter();
+
+ sw.WriteLine("IPNetwork : {0}", ToString());
+ sw.WriteLine("Network : {0}", Network);
+ sw.WriteLine("Netmask : {0}", Netmask);
+ sw.WriteLine("Cidr : {0}", Cidr);
+ sw.WriteLine("Broadcast : {0}", Broadcast);
+ sw.WriteLine("FirstUsable : {0}", FirstUsable);
+ sw.WriteLine("LastUsable : {0}", LastUsable);
+ sw.WriteLine("Usable : {0}", Usable);
+
+ return sw.ToString();
+ }
+
+ [Obsolete("static Print is deprecated, please use instance Print.")]
+ public static string Print(IPNetwork ipnetwork)
+ {
+
+ if (ipnetwork == null)
+ {
+ throw new ArgumentNullException("ipnetwork");
+ }
+
+ return ipnetwork.Print();
+ }
+
+ #endregion
+
+ #region TryGuessCidr
+
+ /// <summary>
+ ///
+ /// Class Leading bits Default netmask
+ /// A (CIDR /8) 00 255.0.0.0
+ /// A (CIDR /8) 01 255.0.0.0
+ /// B (CIDR /16) 10 255.255.0.0
+ /// C (CIDR /24) 11 255.255.255.0
+ ///
+ /// </summary>
+ /// <param name="ip"></param>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static bool TryGuessCidr(string ip, out byte cidr)
+ {
+
+ IPAddress ipaddress = null;
+ bool parsed = IPAddress.TryParse(string.Format("{0}", ip), out ipaddress);
+ if (parsed == false)
+ {
+ cidr = 0;
+ return false;
+ }
+
+ if (ipaddress.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ cidr = 64;
+ return true;
+ }
+ BigInteger uintIPAddress = IPNetwork.ToBigInteger(ipaddress);
+ uintIPAddress = uintIPAddress >> 29;
+ if (uintIPAddress <= 3)
+ {
+ cidr = 8;
+ return true;
+ }
+ else if (uintIPAddress <= 5)
+ {
+ cidr = 16;
+ return true;
+ }
+ else if (uintIPAddress <= 6)
+ {
+ cidr = 24;
+ return true;
+ }
+
+ cidr = 0;
+ return false;
+
+ }
+
+ /// <summary>
+ /// Try to parse cidr. Have to be >= 0 and <= 32 or 128
+ /// </summary>
+ /// <param name="sidr"></param>
+ /// <param name="cidr"></param>
+ /// <returns></returns>
+ public static bool TryParseCidr(string sidr, AddressFamily family, out byte? cidr)
+ {
+
+ byte b = 0;
+ if (!byte.TryParse(sidr, out b))
+ {
+ cidr = null;
+ return false;
+ }
+
+ IPAddress netmask = null;
+ if (!IPNetwork.TryToNetmask(b, family, out netmask))
+ {
+ cidr = null;
+ return false;
+ }
+
+ cidr = b;
+ return true;
+ }
+
+ #endregion
+
+ #region ListIPAddress
+
+ [Obsolete("static ListIPAddress is deprecated, please use instance ListIPAddress.")]
+ public static IPAddressCollection ListIPAddress(IPNetwork ipnetwork)
+ {
+ return ipnetwork.ListIPAddress();
+ }
+
+ public IPAddressCollection ListIPAddress()
+ {
+ return new IPAddressCollection(this);
+ }
+
+ #endregion
+
+ /**
+ * Need a better way to do it
+ *
+#region TrySubstractNetwork
+
+ public static bool TrySubstractNetwork(IPNetwork[] ipnetworks, IPNetwork substract, out IEnumerable<IPNetwork> result) {
+
+ if (ipnetworks == null) {
+ result = null;
+ return false;
+ }
+ if (ipnetworks.Length <= 0) {
+ result = null;
+ return false;
+ }
+ if (substract == null) {
+ result = null;
+ return false;
+ }
+ var results = new List<IPNetwork>();
+ foreach (var ipn in ipnetworks) {
+ if (!Overlap(ipn, substract)) {
+ results.Add(ipn);
+ continue;
+ }
+
+ var collection = ipn.Subnet(substract.Cidr);
+ var rtemp = new List<IPNetwork>();
+ foreach(var subnet in collection) {
+ if (subnet != substract) {
+ rtemp.Add(subnet);
+ }
+ }
+ var supernets = Supernet(rtemp.ToArray());
+ results.AddRange(supernets);
+ }
+ result = results;
+ return true;
+ }
+#endregion
+ * **/
+
+ #region IComparable<IPNetwork> Members
+
+ public static Int32 Compare(IPNetwork left, IPNetwork right)
+ {
+ // two null IPNetworks are equal
+ if (ReferenceEquals(left, null) && ReferenceEquals(right, null)) return 0;
+
+ // two same IPNetworks are equal
+ if (ReferenceEquals(left, right)) return 0;
+
+ // null is always sorted first
+ if (ReferenceEquals(left, null)) return -1;
+ if (ReferenceEquals(right, null)) return 1;
+
+ // first test the network
+ var result = left._network.CompareTo(right._network);
+ if (result != 0) return result;
+
+ // then test the cidr
+ result = left._cidr.CompareTo(right._cidr);
+ return result;
+ }
+
+ public Int32 CompareTo(IPNetwork other)
+ {
+ return Compare(this, other);
+ }
+
+ public Int32 CompareTo(Object obj)
+ {
+ // null is at less
+ if (obj == null) return 1;
+
+ // convert to a proper Cidr object
+ var other = obj as IPNetwork;
+
+ // type problem if null
+ if (other == null)
+ {
+ throw new ArgumentException(
+ "The supplied parameter is an invalid type. Please supply an IPNetwork type.",
+ "obj");
+ }
+
+ // perform the comparision
+ return CompareTo(other);
+ }
+
+ #endregion
+
+ #region IEquatable<IPNetwork> Members
+
+ public static Boolean Equals(IPNetwork left, IPNetwork right)
+ {
+ return Compare(left, right) == 0;
+ }
+
+ public Boolean Equals(IPNetwork other)
+ {
+ return Equals(this, other);
+ }
+
+ public override Boolean Equals(Object obj)
+ {
+ return Equals(this, obj as IPNetwork);
+ }
+
+ #endregion
+
+ #region Operators
+
+ public static Boolean operator ==(IPNetwork left, IPNetwork right)
+ {
+ return Equals(left, right);
+ }
+
+ public static Boolean operator !=(IPNetwork left, IPNetwork right)
+ {
+ return !Equals(left, right);
+ }
+
+ public static Boolean operator <(IPNetwork left, IPNetwork right)
+ {
+ return Compare(left, right) < 0;
+ }
+
+ public static Boolean operator >(IPNetwork left, IPNetwork right)
+ {
+ return Compare(left, right) > 0;
+ }
+
+ #endregion
+
+ }
+} \ No newline at end of file