aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Networking
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations/Networking')
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs168
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs104
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetwork.cs2170
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs144
-rw-r--r--Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt24
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs166
6 files changed, 2736 insertions, 40 deletions
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs b/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
new file mode 100644
index 000000000..afb202fa3
--- /dev/null
+++ b/Emby.Server.Implementations/Networking/IPNetwork/BigIntegerExt.cs
@@ -0,0 +1,168 @@
+using System.Collections.Generic;
+
+namespace System.Net
+{
+ using System;
+ using System.Numerics;
+ using System.Text;
+
+ /// <summary>
+ /// Extension methods to convert <see cref="System.Numerics.BigInteger"/>
+ /// instances to hexadecimal, octal, and binary strings.
+ /// </summary>
+ public static class BigIntegerExtensions
+ {
+ /// <summary>
+ /// Converts a <see cref="BigInteger"/> to a binary string.
+ /// </summary>
+ /// <param name="bigint">A <see cref="BigInteger"/>.</param>
+ /// <returns>
+ /// A <see cref="System.String"/> containing a binary
+ /// representation of the supplied <see cref="BigInteger"/>.
+ /// </returns>
+ public static string ToBinaryString(this BigInteger bigint)
+ {
+ var bytes = bigint.ToByteArray();
+ var idx = bytes.Length - 1;
+
+ // Create a StringBuilder having appropriate capacity.
+ var base2 = new StringBuilder(bytes.Length * 8);
+
+ // Convert first byte to binary.
+ var binary = Convert.ToString(bytes[idx], 2);
+
+ // Ensure leading zero exists if value is positive.
+ if (binary[0] != '0' && bigint.Sign == 1)
+ {
+ base2.Append('0');
+ }
+
+ // Append binary string to StringBuilder.
+ base2.Append(binary);
+
+ // Convert remaining bytes adding leading zeros.
+ for (idx--; idx >= 0; idx--)
+ {
+ base2.Append(Convert.ToString(bytes[idx], 2).PadLeft(8, '0'));
+ }
+
+ return base2.ToString();
+ }
+
+ /// <summary>
+ /// Converts a <see cref="BigInteger"/> to a hexadecimal string.
+ /// </summary>
+ /// <param name="bigint">A <see cref="BigInteger"/>.</param>
+ /// <returns>
+ /// A <see cref="System.String"/> containing a hexadecimal
+ /// representation of the supplied <see cref="BigInteger"/>.
+ /// </returns>
+ public static string ToHexadecimalString(this BigInteger bigint)
+ {
+ return bigint.ToString("X");
+ }
+
+ /// <summary>
+ /// Converts a <see cref="BigInteger"/> to a octal string.
+ /// </summary>
+ /// <param name="bigint">A <see cref="BigInteger"/>.</param>
+ /// <returns>
+ /// A <see cref="System.String"/> containing an octal
+ /// representation of the supplied <see cref="BigInteger"/>.
+ /// </returns>
+ public static string ToOctalString(this BigInteger bigint)
+ {
+ var bytes = bigint.ToByteArray();
+ var idx = bytes.Length - 1;
+
+ // Create a StringBuilder having appropriate capacity.
+ var base8 = new StringBuilder(((bytes.Length / 3) + 1) * 8);
+
+ // Calculate how many bytes are extra when byte array is split
+ // into three-byte (24-bit) chunks.
+ var extra = bytes.Length % 3;
+
+ // If no bytes are extra, use three bytes for first chunk.
+ if (extra == 0)
+ {
+ extra = 3;
+ }
+
+ // Convert first chunk (24-bits) to integer value.
+ int int24 = 0;
+ for (; extra != 0; extra--)
+ {
+ int24 <<= 8;
+ int24 += bytes[idx--];
+ }
+
+ // Convert 24-bit integer to octal without adding leading zeros.
+ var octal = Convert.ToString(int24, 8);
+
+ // Ensure leading zero exists if value is positive.
+ if (octal[0] != '0')
+ {
+ if (bigint.Sign == 1)
+ {
+ base8.Append('0');
+ }
+ }
+
+ // Append first converted chunk to StringBuilder.
+ base8.Append(octal);
+
+ // Convert remaining 24-bit chunks, adding leading zeros.
+ for (; idx >= 0; idx -= 3)
+ {
+ int24 = (bytes[idx] << 16) + (bytes[idx - 1] << 8) + bytes[idx - 2];
+ base8.Append(Convert.ToString(int24, 8).PadLeft(8, '0'));
+ }
+
+ return base8.ToString();
+ }
+
+ /// <summary>
+ ///
+ /// Reverse a Positive BigInteger ONLY
+ /// Bitwise ~ operator
+ ///
+ /// Input : FF FF FF FF
+ /// Width : 4
+ /// Result : 00 00 00 00
+ ///
+ ///
+ /// Input : 00 00 00 00
+ /// Width : 4
+ /// Result : FF FF FF FF
+ ///
+ /// Input : FF FF FF FF
+ /// Width : 8
+ /// Result : FF FF FF FF 00 00 00 00
+ ///
+ ///
+ /// Input : 00 00 00 00
+ /// Width : 8
+ /// Result : FF FF FF FF FF FF FF FF
+ ///
+ /// </summary>
+ /// <param name="input"></param>
+ /// <param name="width"></param>
+ /// <returns></returns>
+ public static BigInteger PositiveReverse(this BigInteger input, int width)
+ {
+
+ var result = new List<byte>();
+ var bytes = input.ToByteArray();
+ var work = new byte[width];
+ Array.Copy(bytes, 0, work, 0, bytes.Length - 1); // Length -1 : positive BigInteger
+
+ for (int i = 0; i < work.Length; i++)
+ {
+ result.Add((byte)(~work[i]));
+ }
+ result.Add(0); // positive BigInteger
+ return new BigInteger(result.ToArray());
+
+ }
+ }
+} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
new file mode 100644
index 000000000..2b31a0a32
--- /dev/null
+++ b/Emby.Server.Implementations/Networking/IPNetwork/IPAddressCollection.cs
@@ -0,0 +1,104 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace System.Net
+{
+ public class IPAddressCollection : IEnumerable<IPAddress>, IEnumerator<IPAddress>
+ {
+
+ private IPNetwork _ipnetwork;
+ private BigInteger _enumerator;
+
+ internal IPAddressCollection(IPNetwork ipnetwork)
+ {
+ this._ipnetwork = ipnetwork;
+ this._enumerator = -1;
+ }
+
+
+ #region Count, Array, Enumerator
+
+ public BigInteger Count
+ {
+ get
+ {
+ return this._ipnetwork.Total;
+ }
+ }
+
+ public IPAddress this[BigInteger i]
+ {
+ get
+ {
+ if (i >= this.Count)
+ {
+ throw new ArgumentOutOfRangeException("i");
+ }
+ byte width = this._ipnetwork.AddressFamily == Sockets.AddressFamily.InterNetwork ? (byte)32 : (byte)128;
+ IPNetworkCollection ipn = this._ipnetwork.Subnet(width);
+ return ipn[i].Network;
+ }
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ IEnumerator<IPAddress> IEnumerable<IPAddress>.GetEnumerator()
+ {
+ return this;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this;
+ }
+
+ #region IEnumerator<IPNetwork> Members
+
+ public IPAddress Current
+ {
+ get { return this[this._enumerator]; }
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ // nothing to dispose
+ return;
+ }
+
+ #endregion
+
+ #region IEnumerator Members
+
+ object IEnumerator.Current
+ {
+ get { return this.Current; }
+ }
+
+ public bool MoveNext()
+ {
+ this._enumerator++;
+ if (this._enumerator >= this.Count)
+ {
+ return false;
+ }
+ return true;
+
+ }
+
+ public void Reset()
+ {
+ this._enumerator = -1;
+ }
+
+ #endregion
+
+ #endregion
+ }
+} \ No newline at end of file
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
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs b/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
new file mode 100644
index 000000000..35cff88dc
--- /dev/null
+++ b/Emby.Server.Implementations/Networking/IPNetwork/IPNetworkCollection.cs
@@ -0,0 +1,144 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Numerics;
+
+namespace System.Net
+{
+ public class IPNetworkCollection : IEnumerable<IPNetwork>, IEnumerator<IPNetwork>
+ {
+
+ private BigInteger _enumerator;
+ private byte _cidrSubnet;
+ private IPNetwork _ipnetwork;
+
+ private byte _cidr
+ {
+ get { return this._ipnetwork.Cidr; }
+ }
+ private BigInteger _broadcast
+ {
+ get { return IPNetwork.ToBigInteger(this._ipnetwork.Broadcast); }
+ }
+ private BigInteger _lastUsable
+ {
+ get { return IPNetwork.ToBigInteger(this._ipnetwork.LastUsable); }
+ }
+ private BigInteger _network
+ {
+ get { return IPNetwork.ToBigInteger(this._ipnetwork.Network); }
+ }
+#if TRAVISCI
+ public
+#else
+ internal
+#endif
+ IPNetworkCollection(IPNetwork ipnetwork, byte cidrSubnet)
+ {
+
+ int maxCidr = ipnetwork.AddressFamily == Sockets.AddressFamily.InterNetwork ? 32 : 128;
+ if (cidrSubnet > maxCidr)
+ {
+ throw new ArgumentOutOfRangeException("cidrSubnet");
+ }
+
+ if (cidrSubnet < ipnetwork.Cidr)
+ {
+ throw new ArgumentException("cidr");
+ }
+
+ this._cidrSubnet = cidrSubnet;
+ this._ipnetwork = ipnetwork;
+ this._enumerator = -1;
+ }
+
+ #region Count, Array, Enumerator
+
+ public BigInteger Count
+ {
+ get
+ {
+ BigInteger count = BigInteger.Pow(2, this._cidrSubnet - this._cidr);
+ return count;
+ }
+ }
+
+ public IPNetwork this[BigInteger i]
+ {
+ get
+ {
+ if (i >= this.Count)
+ {
+ throw new ArgumentOutOfRangeException("i");
+ }
+
+ BigInteger last = this._ipnetwork.AddressFamily == Sockets.AddressFamily.InterNetworkV6
+ ? this._lastUsable : this._broadcast;
+ BigInteger increment = (last - this._network) / this.Count;
+ BigInteger uintNetwork = this._network + ((increment + 1) * i);
+ IPNetwork ipn = new IPNetwork(uintNetwork, this._ipnetwork.AddressFamily, this._cidrSubnet);
+ return ipn;
+ }
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ IEnumerator<IPNetwork> IEnumerable<IPNetwork>.GetEnumerator()
+ {
+ return this;
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this;
+ }
+
+ #region IEnumerator<IPNetwork> Members
+
+ public IPNetwork Current
+ {
+ get { return this[this._enumerator]; }
+ }
+
+ #endregion
+
+ #region IDisposable Members
+
+ public void Dispose()
+ {
+ // nothing to dispose
+ return;
+ }
+
+ #endregion
+
+ #region IEnumerator Members
+
+ object IEnumerator.Current
+ {
+ get { return this.Current; }
+ }
+
+ public bool MoveNext()
+ {
+ this._enumerator++;
+ if (this._enumerator >= this.Count)
+ {
+ return false;
+ }
+ return true;
+
+ }
+
+ public void Reset()
+ {
+ this._enumerator = -1;
+ }
+
+ #endregion
+
+ #endregion
+
+ }
+} \ No newline at end of file
diff --git a/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt b/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
new file mode 100644
index 000000000..45d7392ac
--- /dev/null
+++ b/Emby.Server.Implementations/Networking/IPNetwork/LICENSE.txt
@@ -0,0 +1,24 @@
+Copyright (c) 2015, lduchosal
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 60da8a012..20abaf27c 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -11,6 +11,8 @@ using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Net;
+using MediaBrowser.Model.System;
+using System.Numerics;
namespace Emby.Server.Implementations.Networking
{
@@ -19,27 +21,32 @@ namespace Emby.Server.Implementations.Networking
protected ILogger Logger { get; private set; }
public event EventHandler NetworkChanged;
+ public Func<string[]> LocalSubnetsFn { get; set; }
- public NetworkManager(ILogger logger)
+ public NetworkManager(ILogger logger, IEnvironmentInfo environment)
{
Logger = logger;
- try
- {
- NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
- }
- catch (Exception ex)
+ // In FreeBSD these events cause a crash
+ if (environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.BSD)
{
- Logger.ErrorException("Error binding to NetworkAddressChanged event", ex);
- }
+ try
+ {
+ NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error binding to NetworkAddressChanged event", ex);
+ }
- try
- {
- NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
- }
- catch (Exception ex)
- {
- Logger.ErrorException("Error binding to NetworkChange_NetworkAvailabilityChanged event", ex);
+ try
+ {
+ NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error binding to NetworkChange_NetworkAvailabilityChanged event", ex);
+ }
}
}
@@ -60,6 +67,7 @@ namespace Emby.Server.Implementations.Networking
lock (_localIpAddressSyncLock)
{
_localIpAddresses = null;
+ _macAddresses = null;
}
if (NetworkChanged != null)
{
@@ -67,16 +75,16 @@ namespace Emby.Server.Implementations.Networking
}
}
- private List<IpAddressInfo> _localIpAddresses;
+ private IpAddressInfo[] _localIpAddresses;
private readonly object _localIpAddressSyncLock = new object();
- public List<IpAddressInfo> GetLocalIpAddresses()
+ public IpAddressInfo[] GetLocalIpAddresses()
{
lock (_localIpAddressSyncLock)
{
if (_localIpAddresses == null)
{
- var addresses = GetLocalIpAddressesInternal().Result.Select(ToIpAddressInfo).ToList();
+ var addresses = GetLocalIpAddressesInternal().Result.Select(ToIpAddressInfo).ToArray();
_localIpAddresses = addresses;
@@ -120,6 +128,11 @@ namespace Emby.Server.Implementations.Networking
public bool IsInPrivateAddressSpace(string endpoint)
{
+ return IsInPrivateAddressSpace(endpoint, true);
+ }
+
+ private bool IsInPrivateAddressSpace(string endpoint, bool checkSubnets)
+ {
if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase))
{
return true;
@@ -146,12 +159,24 @@ namespace Emby.Server.Implementations.Networking
return Is172AddressPrivate(endpoint);
}
- return endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
+ if (endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase) ||
- //endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
- IsInPrivateAddressSpaceAndLocalSubnet(endpoint);
+ endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ if (checkSubnets && endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ if (checkSubnets && IsInPrivateAddressSpaceAndLocalSubnet(endpoint))
+ {
+ return true;
+ }
+
+ return false;
}
public bool IsInPrivateAddressSpaceAndLocalSubnet(string endpoint)
@@ -238,9 +263,38 @@ namespace Emby.Server.Implementations.Networking
return IsInLocalNetworkInternal(endpoint, true);
}
- public bool IsInLocalNetworkInternal(string endpoint, bool resolveHost)
+ public bool IsAddressInSubnets(string addressString, string[] subnets)
{
- if (string.IsNullOrWhiteSpace(endpoint))
+ return IsAddressInSubnets(IPAddress.Parse(addressString), addressString, subnets);
+ }
+
+ private bool IsAddressInSubnets(IPAddress address, string addressString, string[] subnets)
+ {
+ foreach (var subnet in subnets)
+ {
+ var normalizedSubnet = subnet.Trim();
+
+ if (string.Equals(normalizedSubnet, addressString, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ if (normalizedSubnet.IndexOf('/') != -1)
+ {
+ var ipnetwork = IPNetwork.Parse(normalizedSubnet);
+ if (ipnetwork.Contains(address))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private bool IsInLocalNetworkInternal(string endpoint, bool resolveHost)
+ {
+ if (string.IsNullOrEmpty(endpoint))
{
throw new ArgumentNullException("endpoint");
}
@@ -250,11 +304,25 @@ namespace Emby.Server.Implementations.Networking
{
var addressString = address.ToString();
+ var localSubnetsFn = LocalSubnetsFn;
+ if (localSubnetsFn != null)
+ {
+ var localSubnets = localSubnetsFn();
+ foreach (var subnet in localSubnets)
+ {
+ // only validate if there's at least one valid entry
+ if (!string.IsNullOrWhiteSpace(subnet))
+ {
+ return IsAddressInSubnets(address, addressString, localSubnets) || IsInPrivateAddressSpace(addressString, false);
+ }
+ }
+ }
+
int lengthMatch = 100;
if (address.AddressFamily == AddressFamily.InterNetwork)
{
lengthMatch = 4;
- if (IsInPrivateAddressSpace(addressString))
+ if (IsInPrivateAddressSpace(addressString, true))
{
return true;
}
@@ -262,7 +330,7 @@ namespace Emby.Server.Implementations.Networking
else if (address.AddressFamily == AddressFamily.InterNetworkV6)
{
lengthMatch = 9;
- if (IsInPrivateAddressSpace(endpoint))
+ if (IsInPrivateAddressSpace(endpoint, true))
{
return true;
}
@@ -353,13 +421,7 @@ namespace Emby.Server.Implementations.Networking
return new List<IPAddress>();
}
- //if (!_validNetworkInterfaceTypes.Contains(network.NetworkInterfaceType))
- //{
- // return new List<IPAddress>();
- //}
-
return ipProperties.UnicastAddresses
- //.Where(i => i.IsDnsEligible)
.Select(i => i.Address)
.Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6)
.ToList();
@@ -408,16 +470,40 @@ namespace Emby.Server.Implementations.Networking
}
}
- /// <summary>
- /// Returns MAC Address from first Network Card in Computer
- /// </summary>
- /// <returns>[string] MAC Address</returns>
- public string GetMacAddress()
+ private List<string> _macAddresses;
+ public List<string> GetMacAddresses()
+ {
+ if (_macAddresses == null)
+ {
+ _macAddresses = GetMacAddressesInternal();
+ }
+ return _macAddresses;
+ }
+
+ private List<string> GetMacAddressesInternal()
{
return NetworkInterface.GetAllNetworkInterfaces()
.Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback)
- .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes()))
- .FirstOrDefault();
+ .Select(i =>
+ {
+ try
+ {
+ var physicalAddress = i.GetPhysicalAddress();
+
+ if (physicalAddress == null)
+ {
+ return null;
+ }
+
+ return physicalAddress.ToString();
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ })
+ .Where(i => i != null)
+ .ToList();
}
/// <summary>