diff --git a/src/System.Net.IPNetwork/IPNetwork2Members.cs b/src/System.Net.IPNetwork/IPNetwork2Members.cs
index 0c9bcf5..a9418cf 100644
--- a/src/System.Net.IPNetwork/IPNetwork2Members.cs
+++ b/src/System.Net.IPNetwork/IPNetwork2Members.cs
@@ -93,7 +93,7 @@ public IPAddress Broadcast
return ToIPAddress(this.InternalBroadcast, this.family);
}
}
-
+
///
/// Gets first usable IPAddress in Network.
///
@@ -127,7 +127,31 @@ public IPAddress LastUsable
return ToIPAddress(last, this.family);
}
}
-
+
+ ///
+ /// Gets first IPAddress in Network.
+ ///
+ public IPAddress First
+ {
+ get
+ {
+ BigInteger first = this.InternalNetwork;
+ return ToIPAddress(first, this.family);
+ }
+ }
+
+ ///
+ /// Gets last IPAddress in Network.
+ ///
+ public IPAddress Last
+ {
+ get
+ {
+ BigInteger last = this.InternalBroadcast;
+ return ToIPAddress(last, this.family);
+ }
+ }
+
///
/// Gets number of usable IPAddress in Network.
///
diff --git a/src/System.Net.IPNetwork/IPNetwork2Operators.cs b/src/System.Net.IPNetwork/IPNetwork2Operators.cs
index 33d50e1..47e3723 100644
--- a/src/System.Net.IPNetwork/IPNetwork2Operators.cs
+++ b/src/System.Net.IPNetwork/IPNetwork2Operators.cs
@@ -103,4 +103,80 @@ public sealed partial class IPNetwork2
}
return [left, right];
}
+
+ ///
+ /// Behavior
+ /// The addition operator (+) performs the following operations:
+ /// Network Expansion: Adds the specified number of IP addresses to the network range
+ /// Optimal Grouping: Attempts to create the most efficient network representation
+ /// Multiple Networks: When a single contiguous network cannot represent the result, returns multiple networks
+ /// CIDR Optimization: Automatically calculates the appropriate subnet mask for the expanded range
+ ///
+ /// left instance.
+ /// number.
+ /// Adds the specified number of IP addresses to the network range.
+ public static IEnumerable operator +(IPNetwork2 left, int add)
+ {
+ if (add < 0)
+ {
+ return left - (add * -1);
+ }
+ if (add == 0)
+ {
+ return new[] { left };
+ }
+ var start = ToBigInteger(left.First);
+ var last = ToBigInteger(left.Last);
+ var end = last+ add;
+
+ if (end < start)
+ {
+ return [];
+ }
+
+ var startIp = ToIPAddress(start, left.AddressFamily);
+ var endIp = ToIPAddress(end, left.AddressFamily);
+
+ var uintStart = ToBigInteger(startIp);
+ var uintEnd = ToBigInteger(endIp);
+
+ if (uintEnd <= uintStart)
+ {
+ throw new OverflowException("IPNetwork overflow");
+ }
+ InternalParseRange(true, startIp, endIp, out IEnumerable networks);
+ return networks;
+ }
+
+ ///
+ /// Add IPNetwork.
+ ///
+ /// left instance.
+ /// number.
+ /// Try to supernet two consecutive cidr equal subnet into a single one, otherwise return both netowkrs.
+ public static IEnumerable operator -(IPNetwork2 left, int subtract)
+ {
+ if (subtract < 0)
+ {
+ return left + (subtract * -1);
+ }
+ if (subtract == 0)
+ {
+ return new[] { left };
+ }
+ var start = ToBigInteger(left.First);
+ var last = ToBigInteger(left.Last);
+ var end = last- subtract;
+
+ if (end < start)
+ {
+ return [];
+ }
+
+ var startIp = ToIPAddress(start, left.AddressFamily);
+ var endIp = ToIPAddress(end, left.AddressFamily);
+
+ InternalParseRange(true, startIp, endIp, out IEnumerable networks);
+ return networks;
+ }
}
\ No newline at end of file
diff --git a/src/TestProject/BigIntegerToUnitTest.cs b/src/TestProject/BigIntegerToUnitTest.cs
index db3c157..3927ea8 100644
--- a/src/TestProject/BigIntegerToUnitTest.cs
+++ b/src/TestProject/BigIntegerToUnitTest.cs
@@ -16,12 +16,12 @@ public class BigIntegerToUnitTest
[TestMethod]
public void TestToOctalString1()
{
- byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
- var convertme = new BigInteger(bytes);
- string result = convertme.ToOctalString();
+ byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
+ var convertme = new BigInteger(bytes);
+ string result = convertme.ToOctalString();
- Assert.AreEqual("037777777777", result);
- }
+ Assert.AreEqual("037777777777", result);
+ }
///
/// Test.
@@ -29,12 +29,12 @@ public void TestToOctalString1()
[TestMethod]
public void TestToOctalString3()
{
- var bigi = BigInteger.Parse("1048576");
- bigi++;
- string result = bigi.ToOctalString();
+ var bigi = BigInteger.Parse("1048576");
+ bigi++;
+ string result = bigi.ToOctalString();
- Assert.AreEqual("04000001", result);
- }
+ Assert.AreEqual("04000001", result);
+ }
///
/// Test.
@@ -42,12 +42,12 @@ public void TestToOctalString3()
[TestMethod]
public void TestToOctalString01()
{
- BigInteger bigi = BigInteger.Zero;
- bigi++;
- string result = bigi.ToOctalString();
+ BigInteger bigi = BigInteger.Zero;
+ bigi++;
+ string result = bigi.ToOctalString();
- Assert.AreEqual("01", result);
- }
+ Assert.AreEqual("01", result);
+ }
///
/// Test.
@@ -55,12 +55,12 @@ public void TestToOctalString01()
[TestMethod]
public void TestToOctalString02()
{
- BigInteger bigi = BigInteger.Zero;
- bigi--;
- string result = bigi.ToOctalString();
+ BigInteger bigi = BigInteger.Zero;
+ bigi--;
+ string result = bigi.ToOctalString();
- Assert.AreEqual("377", result);
- }
+ Assert.AreEqual("377", result);
+ }
///
/// Test.
@@ -68,18 +68,18 @@ public void TestToOctalString02()
[TestMethod]
public void TestToOctalString03()
{
- BigInteger bigi = BigInteger.Zero;
- bigi--;
- bigi--;
- bigi--;
- bigi--;
- bigi--;
- bigi--;
- bigi--;
- string result = bigi.ToOctalString();
-
- Assert.AreEqual("371", result);
- }
+ BigInteger bigi = BigInteger.Zero;
+ bigi--;
+ bigi--;
+ bigi--;
+ bigi--;
+ bigi--;
+ bigi--;
+ bigi--;
+ string result = bigi.ToOctalString();
+
+ Assert.AreEqual("371", result);
+ }
///
/// Test.
@@ -87,12 +87,12 @@ public void TestToOctalString03()
[TestMethod]
public void TestToHexadecimalString1()
{
- byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
- var convertme = new BigInteger(bytes);
- string result = convertme.ToHexadecimalString();
+ byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
+ var convertme = new BigInteger(bytes);
+ string result = convertme.ToHexadecimalString();
- Assert.AreEqual("0FFFFFFFF", result);
- }
+ Assert.AreEqual("0FFFFFFFF", result);
+ }
///
/// Test.
@@ -100,12 +100,12 @@ public void TestToHexadecimalString1()
[TestMethod]
public void TestToBinaryString1()
{
- byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
- var convertme = new BigInteger(bytes);
- string result = convertme.ToBinaryString();
+ byte[] bytes = [0xFF, 0xFF, 0xFF, 0xFF, 0x00];
+ var convertme = new BigInteger(bytes);
+ string result = convertme.ToBinaryString();
- Assert.AreEqual("011111111111111111111111111111111", result);
- }
+ Assert.AreEqual("011111111111111111111111111111111", result);
+ }
///
/// Test.
@@ -113,12 +113,12 @@ public void TestToBinaryString1()
[TestMethod]
public void TestToBinaryString01()
{
- BigInteger bigi = BigInteger.Zero;
- bigi++;
- string result = bigi.ToBinaryString();
+ BigInteger bigi = BigInteger.Zero;
+ bigi++;
+ string result = bigi.ToBinaryString();
- Assert.AreEqual("01", result);
- }
+ Assert.AreEqual("01", result);
+ }
///
/// Test.
@@ -126,11 +126,11 @@ public void TestToBinaryString01()
[TestMethod]
public void TestToBinaryString2()
{
- var convertme = new BigInteger(-1);
- string result = convertme.ToBinaryString();
+ var convertme = new BigInteger(-1);
+ string result = convertme.ToBinaryString();
- Assert.AreEqual("11111111", result);
- }
+ Assert.AreEqual("11111111", result);
+ }
///
/// Test.
@@ -138,14 +138,14 @@ public void TestToBinaryString2()
[TestMethod]
public void TestToBinaryString3()
{
- byte[] bytes =
- [
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
- ];
- var convertme = new BigInteger(bytes);
- string result = convertme.ToBinaryString();
-
- Assert.AreEqual("11111111", result);
- }
+ byte[] bytes =
+ [
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ ];
+ var convertme = new BigInteger(bytes);
+ string result = convertme.ToBinaryString();
+
+ Assert.AreEqual("11111111", result);
+ }
}
\ No newline at end of file
diff --git a/src/TestProject/IPAddressTest.cs b/src/TestProject/IPAddressTest.cs
new file mode 100644
index 0000000..51b15c9
--- /dev/null
+++ b/src/TestProject/IPAddressTest.cs
@@ -0,0 +1,25 @@
+namespace TestProject;
+
+///
+/// Test IPAddress Behaviour on MacOS
+///
+[TestClass]
+public class IPAddressTest
+{
+ ///
+ /// Mixed IPv6 / IPvç notation
+ /// Why This Happens
+ /// .NET automatically uses mixed notation for IPv6 addresses when:
+ /// The first 96 bits are zero (IPv4-compatible)
+ /// The first 80 bits are zero and bits 81-96 are either all zeros or all ones (IPv4-mapped)
+ /// The pattern suggests an embedded IPv4 address
+ /// Your bytes ::0.1.0.0 are being interpreted as an IPv4-compatible IPv6 address.
+ ///
+ [TestMethod]
+ public void TestIPAddress()
+ {
+ byte[] bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0];
+ var ip = new IPAddress(bytes);
+ Assert.AreEqual("::0.1.0.0", ip.ToString());
+ }
+}
\ No newline at end of file
diff --git a/src/TestProject/IPNetworkTest/IPNetworkOperatorTests.cs b/src/TestProject/IPNetworkTest/IPNetworkOperatorTests.cs
index 42c7e4f..7eb02cd 100644
--- a/src/TestProject/IPNetworkTest/IPNetworkOperatorTests.cs
+++ b/src/TestProject/IPNetworkTest/IPNetworkOperatorTests.cs
@@ -5,7 +5,7 @@
namespace TestProject.IPNetworkTest;
///
-/// Tests with operators.
+/// Tests with operators.
///
[TestClass]
public class IPNetworkOperatorTests
@@ -23,7 +23,7 @@ public void TestOperatorGreater1()
Assert.IsFalse(greater, "greater");
}
-
+
///
/// Tests Operator functionality with Operator Greater.
///
@@ -37,7 +37,7 @@ public void TestOperatorGreater2()
Assert.IsTrue(greater, "greater");
}
-
+
///
/// Tests Operator functionality with Operator Greater.
///
@@ -51,8 +51,8 @@ public void TestOperatorGreater3()
Assert.IsFalse(greater, "greater");
}
-
-
+
+
///
/// Tests Operator functionality with Operator Greater.
///
@@ -80,7 +80,7 @@ public void TestOperatorGreaterOrEqual1()
Assert.IsFalse(greater, "greater");
}
-
+
///
/// Tests Operator functionality with Operator Greater.
///
@@ -94,7 +94,7 @@ public void TestOperatorGreaterOrEqual2()
Assert.IsTrue(greater, "greater");
}
-
+
///
/// Tests Operator functionality with Operator Greater.
///
@@ -108,9 +108,9 @@ public void TestOperatorGreaterOrEqual3()
Assert.IsTrue(greater, "greater");
}
-
+
///
- /// Tests Operator functionality with Operator Greater.
+ /// Tests Operator functionality with Operator Greater.
///
[TestMethod]
public void TestOperatorGreaterOrEqual4()
@@ -122,9 +122,9 @@ public void TestOperatorGreaterOrEqual4()
Assert.IsFalse(greater, "greater");
}
-
+
///
- /// Tests Operator functionality with Operator Greater.
+ /// Tests Operator functionality with Operator Greater.
///
[TestMethod]
public void TestOperatorGreaterOrEqual5()
@@ -166,7 +166,7 @@ public void TestOperatorLower2()
}
///
- /// Tests Operator functionality with Operator Lower.
+ /// Tests Operator functionality with Operator Lower.
///
[TestMethod]
public void TestOperatorLower3()
@@ -208,7 +208,7 @@ public void TestOperatorLowerOrEqual2()
}
///
- /// Tests Operator functionality with Operator Lower.
+ /// Tests Operator functionality with Operator Lower.
///
[TestMethod]
public void TestOperatorLowerOrEqual3()
@@ -277,9 +277,9 @@ public void TestOperatorEqual2()
Assert.IsTrue(eq, "eq");
}
-
+
///
- /// Tests Operator functionality with Operator -.
+ /// Tests Operator functionality with Operator -.
///
[TestMethod]
[DataRow("10.0.0.1/32", "10.0.0.1/32", 0)]
@@ -297,14 +297,14 @@ public void TestOperatorSubtract(string left, string right, int count)
var ipn1 = IPNetwork2.Parse(left);
var ipn2 = IPNetwork2.Parse(right);
- var result = ipn1 - ipn2;
+ List result = ipn1 - ipn2;
Assert.HasCount(count, result, "subtract");
}
-
-
+
+
///
- /// Tests Operator functionality with Operator -.
+ /// Tests Operator functionality with Operator -.
///
[TestMethod]
[DataRow("10.0.0.0/32", "10.0.0.1/32", 1)]
@@ -327,8 +327,98 @@ public void TestOperatorAdd(string left, string right, int count)
var ipn1 = IPNetwork2.Parse(left);
var ipn2 = IPNetwork2.Parse(right);
- var result = ipn1 + ipn2;
+ List result = ipn1 + ipn2;
Assert.HasCount(count, result, "add");
}
+
+ ///
+ /// Tests Operator functionality with Operator +.
+ ///
+ [TestMethod]
+ [DataRow("10.0.0.0/32", 0, "10.0.0.0/32")]
+ [DataRow("10.0.0.0/32", 1, "10.0.0.0/31")]
+ [DataRow("10.0.0.0/32", 2, "10.0.0.0/31, 10.0.0.2/32")]
+ [DataRow("10.0.0.0/32", 3, "10.0.0.0/30")]
+ [DataRow("10.0.0.0/32", 4, "10.0.0.0/30, 10.0.0.4/32")]
+ [DataRow("10.0.0.0/32", 7, "10.0.0.0/29")]
+ [DataRow("10.0.0.0/32", 15, "10.0.0.0/28")]
+ [DataRow("10.0.0.0/32", 31, "10.0.0.0/27")]
+ [DataRow("10.0.0.0/32", 63, "10.0.0.0/26")]
+ [DataRow("10.0.0.0/32", 127, "10.0.0.0/25")]
+ [DataRow("10.0.0.0/32", 255, "10.0.0.0/24")]
+ [DataRow("10.0.0.0/32", 511, "10.0.0.0/23")]
+ [DataRow("10.0.0.0/32", 1023, "10.0.0.0/22")]
+ [DataRow("10.0.0.0/32", 2047, "10.0.0.0/21")]
+ [DataRow("10.0.0.0/32", 4095, "10.0.0.0/20")]
+ [DataRow("10.0.0.0/32", -1, "")]
+ [DataRow("10.0.0.0/32", -10, "")]
+ [DataRow("::/128", 1, "::/127")]
+ [DataRow("::/128", 3, "::/126")]
+ [DataRow("::f/128", 1, "::f/128, ::10/128")]
+ [DataRow("1::ffff/128", 1, "1::ffff/128, 1::1:0/128")]
+ public void TestOperatorAdd2(string left, int right, string expected)
+ {
+ var ipn1 = IPNetwork2.Parse(left);
+ IEnumerable result = ipn1 + right;
+ string sresult = string.Join(", ", result);
+
+ Assert.AreEqual(expected, sresult);
+ }
+
+ ///
+ /// Tests Operator functionality with Operator +.
+ ///
+ [TestMethod]
+ [DataRow("0.0.0.0/0", 1, "0.0.0.0/32")]
+ [DataRow("255.255.255.255/32", 1, "10.0.0.0/31")]
+ public void TestOperatorAddOverflow(string left, int right, string expected)
+ {
+ var ipn1 = IPNetwork2.Parse(left);
+ Assert.ThrowsExactly(() => ipn1 + right);
+ }
+
+ ///
+ /// Tests Operator functionality with Operator -.
+ ///
+ [TestMethod]
+ [DataRow("10.0.0.0/32", 0, "10.0.0.0/32")]
+ [DataRow("10.0.0.0/32", 1, "")]
+ [DataRow("10.0.0.0/32", 3, "")]
+ [DataRow("10.0.0.0/32", 7, "")]
+ [DataRow("10.0.0.0/32", 15, "")]
+ [DataRow("10.0.0.0/32", 31, "")]
+ [DataRow("10.0.0.0/32", 63, "")]
+ [DataRow("10.0.0.0/32", 4095, "")]
+ [DataRow("10.0.0.0/32", -1, "10.0.0.0/31")]
+ [DataRow("10.0.0.0/32", -10, "10.0.0.0/29, 10.0.0.8/31, 10.0.0.10/32")]
+ [DataRow("255.255.255.255/32", 1, "")]
+ [DataRow("::/128", 1, "")]
+ [DataRow("::/127", 1, "::/128")]
+ [DataRow("::/128", 3, "")]
+ [DataRow("::f/128", 1, "")]
+ public void TestOperatorsubtract2(string left, int right, string expected)
+ {
+ var ipn1 = IPNetwork2.Parse(left);
+ IEnumerable result = ipn1 - right;
+ string sresult = string.Join(", ", result);
+
+ Assert.AreEqual(expected, sresult);
+ }
+
+ ///
+ /// Tests Operator functionality with Operator -.
+ ///
+ [TestMethod]
+ [DataRow("0.0.0.0/0", -1)]
+ [DataRow("255.255.255.255/32", -1)]
+ public void TestOperatorsubtractOverflow(string left, int right)
+ {
+ var ipn1 = IPNetwork2.Parse(left);
+ Assert.ThrowsExactly(() =>
+ {
+ var result = ipn1 - right;
+ Assert.AreEqual("32", result.ToString());
+ });
+ }
}
\ No newline at end of file